blob: 2cbfc444c03c5787ea2489c3ba2f0391ecaa9d7a [file] [log] [blame]
# Copyright 2014 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
load(
"@io_bazel_rules_go//go/private:context.bzl",
"go_context",
)
load(
"@io_bazel_rules_go//go/private:common.bzl",
"asm_exts",
"go_exts",
"pkg_dir",
"split_srcs",
)
load(
"@io_bazel_rules_go//go/private:rules/binary.bzl",
"gc_linkopts",
)
load(
"@io_bazel_rules_go//go/private:providers.bzl",
"GoLibrary",
"INFERRED_PATH",
"get_archive",
)
load(
"@io_bazel_rules_go//go/private:rules/aspect.bzl",
"go_archive_aspect",
)
load(
"@io_bazel_rules_go//go/private:rules/rule.bzl",
"go_rule",
)
load(
"@io_bazel_rules_go//go/platform:list.bzl",
"GOARCH",
"GOOS",
)
load(
"@io_bazel_rules_go//go/private:mode.bzl",
"LINKMODE_NORMAL",
)
def _testmain_library_to_source(go, attr, source, merge):
source["deps"] = source["deps"] + [attr.library]
def _go_test_impl(ctx):
"""go_test_impl implements go testing.
It emits an action to run the test generator, and then compiles the
test into a binary."""
go = go_context(ctx)
# Compile the library to test with internal white box tests
internal_library = go.new_library(go, testfilter = "exclude")
internal_source = go.library_to_source(go, ctx.attr, internal_library, ctx.coverage_instrumented())
internal_archive = go.archive(go, internal_source)
go_srcs = split_srcs(internal_source.srcs).go
# Compile the library with the external black box tests
external_library = go.new_library(
go,
name = internal_library.name + "_test",
importpath = internal_library.importpath + "_test",
testfilter = "only",
)
external_source = go.library_to_source(go, struct(
srcs = [struct(files = go_srcs)],
deps = internal_archive.direct + [internal_archive],
x_defs = ctx.attr.x_defs,
), external_library, ctx.coverage_instrumented())
external_archive = go.archive(go, external_source)
external_srcs = split_srcs(external_source.srcs).go
# now generate the main function
if ctx.attr.rundir:
if ctx.attr.rundir.startswith("/"):
run_dir = ctx.attr.rundir
else:
run_dir = pkg_dir(ctx.label.workspace_root, ctx.attr.rundir)
else:
run_dir = pkg_dir(ctx.label.workspace_root, ctx.label.package)
main_go = go.declare_file(go, "testmain.go")
arguments = go.builder_args(go)
arguments.add_all(["-rundir", run_dir, "-output", main_go])
if ctx.configuration.coverage_enabled:
arguments.add("-coverage")
arguments.add_all([
# the l is the alias for the package under test, the l_test must be the
# same with the test suffix
"-import",
"l=" + internal_source.library.importpath,
"-import",
"l_test=" + external_source.library.importpath,
])
arguments.add_all(go_srcs, before_each = "-src", format_each = "l=%s")
ctx.actions.run(
inputs = go_srcs,
outputs = [main_go],
mnemonic = "GoTestGenTest",
executable = go.builders.test_generator,
arguments = [arguments],
env = {
"RUNDIR": ctx.label.package,
},
)
# Now compile the test binary itself
test_library = GoLibrary(
name = go._ctx.label.name + "~testmain",
label = go._ctx.label,
importpath = "testmain",
importmap = "testmain",
pathtype = INFERRED_PATH,
resolve = None,
)
test_deps = external_archive.direct + [external_archive]
if ctx.configuration.coverage_enabled:
test_deps.append(go.coverdata)
test_source = go.library_to_source(go, struct(
srcs = [struct(files = [main_go])],
deps = test_deps,
), test_library, False)
test_archive, executable, runfiles = go.binary(
go,
name = ctx.label.name,
source = test_source,
test_archives = [internal_archive.data],
gc_linkopts = gc_linkopts(ctx),
version_file = ctx.version_file,
info_file = ctx.info_file,
)
# Bazel only looks for coverage data if the test target has an
# InstrumentedFilesProvider, but this provider can currently only be
# created using "legacy" provider syntax. Old and new provider syntaxes
# can be combined by putting new-style providers in a providers field
# of the old-style struct.
# If the provider is found and at least one source file is present, Bazel
# will set the COVERAGE_OUTPUT_FILE environment variable during tests
# and will save that file to the build events + test outputs.
return struct(
providers = [
test_archive,
DefaultInfo(
files = depset([executable]),
runfiles = runfiles,
executable = executable,
),
],
instrumented_files = struct(
extensions = ["go"],
source_attributes = ["srcs"],
dependency_attributes = ["deps", "embed"],
),
)
go_test = go_rule(
_go_test_impl,
attrs = {
"data": attr.label_list(allow_files = True),
"srcs": attr.label_list(allow_files = go_exts + asm_exts),
"deps": attr.label_list(
providers = [GoLibrary],
aspects = [go_archive_aspect],
),
"embed": attr.label_list(
providers = [GoLibrary],
aspects = [go_archive_aspect],
),
"importpath": attr.string(),
"pure": attr.string(
values = [
"on",
"off",
"auto",
],
default = "auto",
),
"static": attr.string(
values = [
"on",
"off",
"auto",
],
default = "auto",
),
"race": attr.string(
values = [
"on",
"off",
"auto",
],
default = "auto",
),
"msan": attr.string(
values = [
"on",
"off",
"auto",
],
default = "auto",
),
"goos": attr.string(
values = GOOS.keys() + ["auto"],
default = "auto",
),
"goarch": attr.string(
values = GOARCH.keys() + ["auto"],
default = "auto",
),
"gc_goopts": attr.string_list(),
"gc_linkopts": attr.string_list(),
"rundir": attr.string(),
"x_defs": attr.string_dict(),
"linkmode": attr.string(default = LINKMODE_NORMAL),
},
executable = True,
test = True,
)
"""See go/core.rst#go_test for full documentation."""