aboutsummaryrefslogtreecommitdiff
path: root/tests/core
diff options
context:
space:
mode:
Diffstat (limited to 'tests/core')
-rw-r--r--tests/core/README.rst35
-rw-r--r--tests/core/boringcrypto/BUILD.bazel6
-rw-r--r--tests/core/boringcrypto/README.rst11
-rw-r--r--tests/core/boringcrypto/boringcrypto_test.go115
-rw-r--r--tests/core/build_stdlib/BUILD.bazel6
-rw-r--r--tests/core/build_stdlib/README.rst11
-rw-r--r--tests/core/build_stdlib/build_stdlib_test.go97
-rw-r--r--tests/core/c_linkmodes/BUILD.bazel139
-rw-r--r--tests/core/c_linkmodes/README.rst35
-rw-r--r--tests/core/c_linkmodes/add.go11
-rw-r--r--tests/core/c_linkmodes/add_sandwich.c5
-rw-r--r--tests/core/c_linkmodes/add_sandwich.go14
-rw-r--r--tests/core/c_linkmodes/add_sandwich.h1
-rw-r--r--tests/core/c_linkmodes/add_test_archive.c11
-rw-r--r--tests/core/c_linkmodes/add_test_sandwich.c11
-rw-r--r--tests/core/c_linkmodes/add_test_shared.c11
-rw-r--r--tests/core/c_linkmodes/c-archive_empty_hdr_test.c17
-rw-r--r--tests/core/c_linkmodes/crypto.go18
-rw-r--r--tests/core/c_linkmodes/crypto_test_dl.c30
-rw-r--r--tests/core/c_linkmodes/empty.go3
-rw-r--r--tests/core/c_linkmodes/go_with_cgo_dep.go29
-rw-r--r--tests/core/c_linkmodes/go_with_cgo_dep_caller.cc20
-rw-r--r--tests/core/c_linkmodes/skip.c3
-rw-r--r--tests/core/cgo/BUILD.bazel474
-rw-r--r--tests/core/cgo/README.rst67
-rw-r--r--tests/core/cgo/add.c19
-rw-r--r--tests/core/cgo/add.cpp19
-rw-r--r--tests/core/cgo/add.h10
-rw-r--r--tests/core/cgo/add.m11
-rw-r--r--tests/core/cgo/add.mm11
-rw-r--r--tests/core/cgo/adder.go14
-rw-r--r--tests/core/cgo/adder_test.go19
-rw-r--r--tests/core/cgo/bar.cc9
-rw-r--r--tests/core/cgo/bar.go8
-rw-r--r--tests/core/cgo/cc_libs_common.go34
-rw-r--r--tests/core/cgo/cc_libs_darwin_test.go96
-rw-r--r--tests/core/cgo/cc_libs_linux_test.go93
-rw-r--r--tests/core/cgo/cgo_link_dep.c15
-rw-r--r--tests/core/cgo/cgo_link_test.go24
-rw-r--r--tests/core/cgo/cgo_ref.go20
-rw-r--r--tests/core/cgo/direct_dep.go9
-rw-r--r--tests/core/cgo/dylib_client.go10
-rw-r--r--tests/core/cgo/dylib_test.go10
-rw-r--r--tests/core/cgo/external_includes_test.go85
-rw-r--r--tests/core/cgo/foo.c7
-rw-r--r--tests/core/cgo/foo.go8
-rwxr-xr-xtests/core/cgo/generate_imported_dylib.sh26
-rw-r--r--tests/core/cgo/imported.c1
-rw-r--r--tests/core/cgo/native_dep.c5
-rw-r--r--tests/core/cgo/native_dep.h1
-rw-r--r--tests/core/cgo/objc/BUILD.bazel32
-rw-r--r--tests/core/cgo/objc/README.rst8
-rw-r--r--tests/core/cgo/objc/add_darwin.go10
-rw-r--r--tests/core/cgo/objc/add_darwin.h1
-rw-r--r--tests/core/cgo/objc/add_darwin.m22
-rw-r--r--tests/core/cgo/objc/objc_darwin_test.go16
-rw-r--r--tests/core/cgo/objc/sub.m20
-rw-r--r--tests/core/cgo/objc/sub_darwin.go10
-rw-r--r--tests/core/cgo/provide_external_symbol.go12
-rw-r--r--tests/core/cgo/pure.go3
-rw-r--r--tests/core/cgo/race_off.c3
-rw-r--r--tests/core/cgo/race_off.go5
-rw-r--r--tests/core/cgo/race_on.c3
-rw-r--r--tests/core/cgo/race_on.go5
-rw-r--r--tests/core/cgo/race_test.go31
-rw-r--r--tests/core/cgo/split_import_a.go3
-rw-r--r--tests/core/cgo/split_import_b.go10
-rw-r--r--tests/core/cgo/split_import_c.c2
-rw-r--r--tests/core/cgo/split_import_c.h6
-rw-r--r--tests/core/cgo/split_import_cgo.go10
-rw-r--r--tests/core/cgo/split_import_i_test.go9
-rw-r--r--tests/core/cgo/split_import_x_test.go13
-rw-r--r--tests/core/cgo/tag_cgo.go10
-rw-r--r--tests/core/cgo/tag_cgo_err.go6
-rw-r--r--tests/core/cgo/tag_pure.go9
-rw-r--r--tests/core/cgo/tag_pure_err.c1
-rw-r--r--tests/core/cgo/tag_pure_err.go6
-rw-r--r--tests/core/cgo/tag_test.go38
-rw-r--r--tests/core/cgo/transitive_dep.go10
-rw-r--r--tests/core/cgo/use_c_symbol_through_go.c5
-rw-r--r--tests/core/cgo/use_external_symbol.go10
-rw-r--r--tests/core/cgo/use_transitive_symbol.go14
-rw-r--r--tests/core/coverage/BUILD.bazel34
-rw-r--r--tests/core/coverage/README.rst23
-rw-r--r--tests/core/coverage/binary_coverage_test.go75
-rw-r--r--tests/core/coverage/coverage_test.go265
-rw-r--r--tests/core/coverage/issue3017_test.go80
-rw-r--r--tests/core/coverage/lcov_coverage_test.go290
-rw-r--r--tests/core/coverage/lcov_test_main_coverage_test.go122
-rw-r--r--tests/core/cross/BUILD.bazel143
-rw-r--r--tests/core/cross/README.rst62
-rw-r--r--tests/core/cross/asm.s15
-rw-r--r--tests/core/cross/cross_test.go91
-rw-r--r--tests/core/cross/def.bzl24
-rw-r--r--tests/core/cross/ios_select_test.go66
-rw-r--r--tests/core/cross/lib_darwin.go3
-rw-r--r--tests/core/cross/lib_linux.go3
-rw-r--r--tests/core/cross/lib_windows.go3
-rw-r--r--tests/core/cross/main.go26
-rw-r--r--tests/core/cross/non_executable_test.go106
-rw-r--r--tests/core/cross/proto_test.go126
-rw-r--r--tests/core/cross/sdk_version_test.go135
-rw-r--r--tests/core/go_bazel_test/BUILD.bazel9
-rw-r--r--tests/core/go_bazel_test/README.rst10
-rw-r--r--tests/core/go_bazel_test/dataargtest_test.go69
-rw-r--r--tests/core/go_binary/BUILD.bazel193
-rw-r--r--tests/core/go_binary/README.rst70
-rw-r--r--tests/core/go_binary/broken_cgo.go7
-rw-r--r--tests/core/go_binary/configurable_attribute_bad_test.go69
-rw-r--r--tests/core/go_binary/configurable_attribute_good_test.go92
-rw-r--r--tests/core/go_binary/custom_bin.go4
-rw-r--r--tests/core/go_binary/hello.go7
-rw-r--r--tests/core/go_binary/many_deps.bzl92
-rw-r--r--tests/core/go_binary/non_executable_test.go87
-rw-r--r--tests/core/go_binary/out_test.go13
-rw-r--r--tests/core/go_binary/package_conflict_test.go120
-rw-r--r--tests/core/go_binary/pie_darwin_amd64_test.go31
-rw-r--r--tests/core/go_binary/pie_darwin_test.go35
-rw-r--r--tests/core/go_binary/pie_linux_test.go48
-rw-r--r--tests/core/go_binary/prefix/BUILD.bazel8
-rw-r--r--tests/core/go_binary/prefix/prefix.go3
-rw-r--r--tests/core/go_binary/stamp_bin.go16
-rw-r--r--tests/core/go_binary/stamp_dep.go6
-rw-r--r--tests/core/go_binary/stamp_embed.go3
-rw-r--r--tests/core/go_binary/stamp_test.go29
-rw-r--r--tests/core/go_binary/static_bin.go7
-rw-r--r--tests/core/go_binary/static_cgo_bin.go14
-rw-r--r--tests/core/go_binary/static_pure_bin.go8
-rw-r--r--tests/core/go_binary/static_test.go45
-rw-r--r--tests/core/go_binary/tags_lib_bad.go5
-rw-r--r--tests/core/go_binary/tags_lib_good.go1
-rw-r--r--tests/core/go_binary/tags_main_bad.go5
-rw-r--r--tests/core/go_binary/tags_main_good.go8
-rw-r--r--tests/core/go_download_sdk/BUILD.bazel6
-rw-r--r--tests/core/go_download_sdk/README.rst7
-rw-r--r--tests/core/go_download_sdk/go_download_sdk_test.go187
-rw-r--r--tests/core/go_library/BUILD.bazel168
-rw-r--r--tests/core/go_library/README.rst57
-rw-r--r--tests/core/go_library/def.bzl22
-rw-r--r--tests/core/go_library/embedsrcs_error_test.go138
-rw-r--r--tests/core/go_library/embedsrcs_gen_test.go.in20
-rw-r--r--tests/core/go_library/embedsrcs_simple_test.go6
-rw-r--r--tests/core/go_library/embedsrcs_static/contains_hidden/.hidden0
-rw-r--r--tests/core/go_library/embedsrcs_static/contains_hidden/.hidden_dir/.env0
-rw-r--r--tests/core/go_library/embedsrcs_static/contains_hidden/.hidden_dir/visible_file0
-rw-r--r--tests/core/go_library/embedsrcs_static/contains_hidden/_hidden_dir/.bashrc0
-rw-r--r--tests/core/go_library/embedsrcs_static/contains_hidden/_hidden_dir/_hidden_file0
-rw-r--r--tests/core/go_library/embedsrcs_static/contains_hidden/_hidden_dir/visible_file0
-rw-r--r--tests/core/go_library/embedsrcs_static/contains_hidden/visible/.bzr/file-under-version-control0
-rw-r--r--tests/core/go_library/embedsrcs_static/contains_hidden/visible/visible_file0
-rw-r--r--tests/core/go_library/embedsrcs_static/dir/_no0
-rw-r--r--tests/core/go_library/embedsrcs_static/dir/f0
-rw-r--r--tests/core/go_library/embedsrcs_static/file0
-rw-r--r--tests/core/go_library/embedsrcs_static/glob/_hidden0
-rw-r--r--tests/core/go_library/embedsrcs_static/glob/f0
-rw-r--r--tests/core/go_library/embedsrcs_static/no0
-rw-r--r--tests/core/go_library/embedsrcs_test.go199
-rw-r--r--tests/core/go_library/empty_bar.go3
-rw-r--r--tests/core/go_library/empty_baz.s1
-rw-r--r--tests/core/go_library/empty_foo.go3
-rw-r--r--tests/core/go_library/empty_main.go3
-rw-r--r--tests/core/go_library/gen_embedsrcs_files.go51
-rw-r--r--tests/core/go_library/import_alias_a_v2.go17
-rw-r--r--tests/core/go_library/import_alias_b.go17
-rw-r--r--tests/core/go_library/import_alias_test.go33
-rw-r--r--tests/core/go_library/inc.go1
-rw-r--r--tests/core/go_library/inc_asmhdr.s1
-rw-r--r--tests/core/go_library/inc_bar.s1
-rw-r--r--tests/core/go_library/inc_foo.s0
-rw-r--r--tests/core/go_library/no_srcs_test.go78
-rw-r--r--tests/core/go_library/package_height.go6
-rw-r--r--tests/core/go_library/package_height_dep_deep.go7
-rw-r--r--tests/core/go_library/package_height_dep_shallow.go3
-rw-r--r--tests/core/go_library/package_height_embeddee.go7
-rw-r--r--tests/core/go_library/package_height_embedder.go3
-rw-r--r--tests/core/go_path/BUILD.bazel81
-rw-r--r--tests/core/go_path/README.rst12
-rw-r--r--tests/core/go_path/cmd/bin/BUILD.bazel30
-rw-r--r--tests/core/go_path/cmd/bin/bin.go4
-rw-r--r--tests/core/go_path/extra.txt0
-rw-r--r--tests/core/go_path/go_path_test.go205
-rw-r--r--tests/core/go_path/pkg/lib/BUILD.bazel80
-rw-r--r--tests/core/go_path/pkg/lib/data.txt0
-rw-r--r--tests/core/go_path/pkg/lib/embed_test.go1
-rw-r--r--tests/core/go_path/pkg/lib/embedded_src.txt1
-rw-r--r--tests/core/go_path/pkg/lib/external_test.go1
-rw-r--r--tests/core/go_path/pkg/lib/generated_embeded.bzl71
-rw-r--r--tests/core/go_path/pkg/lib/internal_test.go1
-rw-r--r--tests/core/go_path/pkg/lib/lib.go15
-rw-r--r--tests/core/go_path/pkg/lib/template/index.html.tmpl1
-rw-r--r--tests/core/go_path/pkg/lib/testdata/testdata.txt0
-rw-r--r--tests/core/go_path/pkg/lib/transitive.go5
-rw-r--r--tests/core/go_path/pkg/lib/vendored.go1
-rw-r--r--tests/core/go_plugin/BUILD.bazel16
-rw-r--r--tests/core/go_plugin/README.rst16
-rw-r--r--tests/core/go_plugin/all_test.go33
-rw-r--r--tests/core/go_plugin/plugin.go7
-rw-r--r--tests/core/go_plugin_with_proto_library/BUILD.bazel31
-rw-r--r--tests/core/go_plugin_with_proto_library/README.rst16
-rw-r--r--tests/core/go_plugin_with_proto_library/all_test.go36
-rw-r--r--tests/core/go_plugin_with_proto_library/plugin.go7
-rw-r--r--tests/core/go_plugin_with_proto_library/validate.proto6
-rw-r--r--tests/core/go_proto_library/BUILD.bazel314
-rw-r--r--tests/core/go_proto_library/README.rst65
-rw-r--r--tests/core/go_proto_library/adjusted_a.proto11
-rw-r--r--tests/core/go_proto_library/adjusted_b.proto9
-rw-r--r--tests/core/go_proto_library/adjusted_c.proto7
-rw-r--r--tests/core/go_proto_library/adjusted_import_test.go31
-rw-r--r--tests/core/go_proto_library/bar.proto10
-rw-r--r--tests/core/go_proto_library/embed_test.go45
-rw-r--r--tests/core/go_proto_library/extra.go5
-rw-r--r--tests/core/go_proto_library/foo.proto8
-rw-r--r--tests/core/go_proto_library/gofast_grpc_test.go32
-rw-r--r--tests/core/go_proto_library/gofast_test.go30
-rw-r--r--tests/core/go_proto_library/gogofast_grpc_test.go32
-rw-r--r--tests/core/go_proto_library/gogofast_test.go30
-rw-r--r--tests/core/go_proto_library/grpc.proto14
-rw-r--r--tests/core/go_proto_library/no_go_package.proto7
-rw-r--r--tests/core/go_proto_library/proto_package_test.go28
-rw-r--r--tests/core/go_proto_library/protos_a.proto7
-rw-r--r--tests/core/go_proto_library/protos_alias_test.go29
-rw-r--r--tests/core/go_proto_library/protos_b.proto7
-rw-r--r--tests/core/go_proto_library/protos_test.go30
-rw-r--r--tests/core/go_proto_library/proxy_a.proto7
-rw-r--r--tests/core/go_proto_library/proxy_b.proto7
-rw-r--r--tests/core/go_proto_library/proxy_test.go30
-rw-r--r--tests/core/go_proto_library/transitive_test.go30
-rw-r--r--tests/core/go_proto_library/wkt_wrapper_test.go67
-rw-r--r--tests/core/go_proto_library_importmap/BUILD.bazel21
-rw-r--r--tests/core/go_proto_library_importmap/README.rst8
-rw-r--r--tests/core/go_proto_library_importmap/foo.proto6
-rw-r--r--tests/core/go_proto_library_importmap/importmap_test.go16
-rw-r--r--tests/core/go_test/BUILD.bazel261
-rw-r--r--tests/core/go_test/README.rst126
-rw-r--r--tests/core/go_test/binary_env_test.go55
-rw-r--r--tests/core/go_test/data_test.go45
-rw-r--r--tests/core/go_test/data_test_dep.go15
-rw-r--r--tests/core/go_test/data_test_embed.go15
-rw-r--r--tests/core/go_test/env_inherit_test.go61
-rw-r--r--tests/core/go_test/env_test.go39
-rw-r--r--tests/core/go_test/example_test.go32
-rw-r--r--tests/core/go_test/external_importmap_dep.go11
-rw-r--r--tests/core/go_test/external_importmap_lib.go5
-rw-r--r--tests/core/go_test/external_importmap_test.go10
-rw-r--r--tests/core/go_test/external_test.go29
-rw-r--r--tests/core/go_test/flag_test.go30
-rw-r--r--tests/core/go_test/fuzz_test.go29
-rw-r--r--tests/core/go_test/indirect_import_dep.go7
-rw-r--r--tests/core/go_test/indirect_import_i_test.go7
-rw-r--r--tests/core/go_test/indirect_import_lib.go3
-rw-r--r--tests/core/go_test/indirect_import_x_test.go15
-rw-r--r--tests/core/go_test/internal_test.go28
-rw-r--r--tests/core/go_test/lib.go20
-rw-r--r--tests/core/go_test/only_testmain_test.go10
-rw-r--r--tests/core/go_test/pwd_test.go16
-rw-r--r--tests/core/go_test/same_package_test.go7
-rw-r--r--tests/core/go_test/sharding_test.go13
-rw-r--r--tests/core/go_test/tags_bad_test.go9
-rw-r--r--tests/core/go_test/tags_good_test.go7
-rw-r--r--tests/core/go_test/test_fail_fast_test.go75
-rw-r--r--tests/core/go_test/test_filter_test.go54
-rw-r--r--tests/core/go_test/testmain_import_indirect_test.go7
-rw-r--r--tests/core/go_test/testmain_import_main_test.go11
-rw-r--r--tests/core/go_test/testmain_without_exit_test.go59
-rw-r--r--tests/core/go_test/wrapped_test.go19
-rw-r--r--tests/core/go_test/wrapper_test.go46
-rw-r--r--tests/core/go_test/x0
-rw-r--r--tests/core/go_test/x_defs/BUILD.bazel73
-rw-r--r--tests/core/go_test/x_defs/bar.go10
-rw-r--r--tests/core/go_test/x_defs/baz.go6
-rw-r--r--tests/core/go_test/x_defs/foo.go1
-rw-r--r--tests/core/go_test/x_defs/foo_test.go28
-rw-r--r--tests/core/go_test/x_defs/qux.go3
-rw-r--r--tests/core/go_test/x_defs/x_defs_lib.go3
-rw-r--r--tests/core/go_test/x_defs/x_defs_test.go34
-rw-r--r--tests/core/go_test/xmlreport_test.go163
-rw-r--r--tests/core/go_test/y0
-rw-r--r--tests/core/go_test/z0
-rw-r--r--tests/core/importmap/BUILD.bazel45
-rw-r--r--tests/core/importmap/README.rst16
-rw-r--r--tests/core/importmap/import.go24
-rw-r--r--tests/core/importmap/importmap_test.go31
-rw-r--r--tests/core/importmap/lib.go18
-rw-r--r--tests/core/nogo/BUILD.bazel5
-rw-r--r--tests/core/nogo/README.rst18
-rw-r--r--tests/core/nogo/common.bzl38
-rw-r--r--tests/core/nogo/config/BUILD.bazel6
-rw-r--r--tests/core/nogo/config/README.rst17
-rw-r--r--tests/core/nogo/config/config_test.go62
-rw-r--r--tests/core/nogo/coverage/BUILD.bazel11
-rw-r--r--tests/core/nogo/coverage/README.rst23
-rw-r--r--tests/core/nogo/coverage/coverage_test.go65
-rw-r--r--tests/core/nogo/coverage/gen_code_test.go130
-rw-r--r--tests/core/nogo/custom/BUILD.bazel6
-rw-r--r--tests/core/nogo/custom/README.rst16
-rw-r--r--tests/core/nogo/custom/custom_test.go510
-rw-r--r--tests/core/nogo/custom/flags/BUILD.bazel6
-rw-r--r--tests/core/nogo/custom/flags/README.rst19
-rw-r--r--tests/core/nogo/custom/flags/flags_test.go262
-rw-r--r--tests/core/nogo/deps/BUILD.bazel6
-rw-r--r--tests/core/nogo/deps/README.rst26
-rw-r--r--tests/core/nogo/deps/deps_test.go211
-rw-r--r--tests/core/nogo/generate/BUILD.bazel6
-rw-r--r--tests/core/nogo/generate/README.rst12
-rw-r--r--tests/core/nogo/generate/empty_test.go102
-rw-r--r--tests/core/nogo/generics/BUILD.bazel6
-rw-r--r--tests/core/nogo/generics/README.rst18
-rw-r--r--tests/core/nogo/generics/generics_test.go85
-rw-r--r--tests/core/nogo/nolint/BUILD.bazel6
-rw-r--r--tests/core/nogo/nolint/README.rst14
-rw-r--r--tests/core/nogo/nolint/nolint_test.go227
-rw-r--r--tests/core/nogo/vet/BUILD.bazel6
-rw-r--r--tests/core/nogo/vet/README.rst14
-rw-r--r--tests/core/nogo/vet/vet_test.go179
-rw-r--r--tests/core/output_groups/BUILD.bazel36
-rw-r--r--tests/core/output_groups/README.rst10
-rw-r--r--tests/core/output_groups/bin.go3
-rw-r--r--tests/core/output_groups/compilation_outputs_test.go59
-rw-r--r--tests/core/output_groups/lib.go1
-rw-r--r--tests/core/output_groups/lib_test.go1
-rw-r--r--tests/core/race/BUILD.bazel6
-rw-r--r--tests/core/race/README.rst10
-rw-r--r--tests/core/race/race_test.go302
-rw-r--r--tests/core/runfiles/BUILD.bazel48
-rw-r--r--tests/core/runfiles/README.rst23
-rw-r--r--tests/core/runfiles/bin.go17
-rw-r--r--tests/core/runfiles/check_runfiles.go121
-rw-r--r--tests/core/runfiles/empty_bin.go3
-rw-r--r--tests/core/runfiles/local_file.txt0
-rw-r--r--tests/core/runfiles/local_group.txt0
-rw-r--r--tests/core/runfiles/runfiles_cmd.go28
-rw-r--r--tests/core/runfiles/runfiles_remote_test/BUILD.bazel27
-rw-r--r--tests/core/runfiles/runfiles_remote_test/WORKSPACE1
-rw-r--r--tests/core/runfiles/runfiles_remote_test/remote_file.txt0
-rw-r--r--tests/core/runfiles/runfiles_remote_test/remote_group.txt0
-rw-r--r--tests/core/runfiles/runfiles_test.go27
-rw-r--r--tests/core/starlark/BUILD.bazel6
-rw-r--r--tests/core/starlark/README.rst9
-rw-r--r--tests/core/starlark/common_tests.bzl53
-rw-r--r--tests/core/starlark/packagedriver/BUILD.bazel5
-rw-r--r--tests/core/starlark/packagedriver/fixtures/a/BUILD.bazel8
-rw-r--r--tests/core/starlark/packagedriver/fixtures/a/a.go5
-rw-r--r--tests/core/starlark/packagedriver/fixtures/b/BUILD.bazel8
-rw-r--r--tests/core/starlark/packagedriver/fixtures/b/b.go5
-rw-r--r--tests/core/starlark/packagedriver/fixtures/c/BUILD.bazel20
-rw-r--r--tests/core/starlark/packagedriver/fixtures/c/c.go11
-rw-r--r--tests/core/starlark/packagedriver/fixtures/c/c_test.go9
-rw-r--r--tests/core/starlark/packagedriver/go_pkg_info_aspect_test.bzl32
-rw-r--r--tests/core/starlark/sdk_tests.bzl86
-rw-r--r--tests/core/stdlib/BUILD.bazel11
-rw-r--r--tests/core/stdlib/README.rst13
-rw-r--r--tests/core/stdlib/buildid_test.go93
-rwxr-xr-xtests/core/stdlib/reproduce_test.sh23
-rw-r--r--tests/core/stdlib/stdlib_files.bzl49
-rw-r--r--tests/core/strip/BUILD.bazel6
-rw-r--r--tests/core/strip/README.rst13
-rw-r--r--tests/core/strip/strip_test.go270
-rw-r--r--tests/core/transition/BUILD.bazel13
-rw-r--r--tests/core/transition/README.rst18
-rw-r--r--tests/core/transition/cmdline_test.go84
-rw-r--r--tests/core/transition/hermeticity_test.go289
361 files changed, 13163 insertions, 0 deletions
diff --git a/tests/core/README.rst b/tests/core/README.rst
new file mode 100644
index 00000000..835b9ba7
--- /dev/null
+++ b/tests/core/README.rst
@@ -0,0 +1,35 @@
+Core Go rules tests
+===================
+
+This contains tests of the core go rules.
+
+Contents
+--------
+
+.. Child list start
+
+* `Misc configuration transition tests <transition/README.rst>`_
+* `Basic go_library functionality <go_library/README.rst>`_
+* `output_groups functionality <output_groups/README.rst>`_
+* `Basic -buildmode=plugin functionality <go_plugin/README.rst>`_
+* `go_bazel_test macro functionality <go_bazel_test/README.rst>`_
+* `Core Go rules tests <nogo/README.rst>`_
+* `go_proto_library importmap <go_proto_library_importmap/README.rst>`_
+* `Cross compilation <cross/README.rst>`_
+* `Basic go_proto_library functionality <go_proto_library/README.rst>`_
+* `c-archive / c-shared linkmodes <c_linkmodes/README.rst>`_
+* `Basic go_test functionality <go_test/README.rst>`_
+* `.. _#2067: https://github.com/bazelbuild/rules_go/issues/2067 <cgo/README.rst>`_
+* `Runfiles functionality <runfiles/README.rst>`_
+* `go_download_sdk <go_download_sdk/README.rst>`_
+* `go_embed_data <go_embed_data/README.rst>`_
+* `race instrumentation <race/README.rst>`_
+* `stdlib functionality <stdlib/README.rst>`_
+* `Basic go_binary functionality <go_binary/README.rst>`_
+* `Starlark unit tests <starlark/README.rst>`_
+* `.. _#2127: https://github.com/bazelbuild/rules_go/issues/2127 <coverage/README.rst>`_
+* `Import maps <importmap/README.rst>`_
+* `Basic go_path functionality <go_path/README.rst>`_
+
+.. Child list end
+
diff --git a/tests/core/boringcrypto/BUILD.bazel b/tests/core/boringcrypto/BUILD.bazel
new file mode 100644
index 00000000..9de03bb0
--- /dev/null
+++ b/tests/core/boringcrypto/BUILD.bazel
@@ -0,0 +1,6 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "boringcrypto_test",
+ srcs = ["boringcrypto_test.go"],
+)
diff --git a/tests/core/boringcrypto/README.rst b/tests/core/boringcrypto/README.rst
new file mode 100644
index 00000000..cd084f33
--- /dev/null
+++ b/tests/core/boringcrypto/README.rst
@@ -0,0 +1,11 @@
+Boringcrypto
+===========
+
+Tests to ensure that support for building with boringcrypto is working as expected.
+
+boringcrypto_test
+--------------
+
+Test that the build is failed if a non-local Go version less than 1.19 is requested to be built with
+boringcrypto. Test that binaries built with boringcrypto stdlib have X:boringcrypto in version
+information. \ No newline at end of file
diff --git a/tests/core/boringcrypto/boringcrypto_test.go b/tests/core/boringcrypto/boringcrypto_test.go
new file mode 100644
index 00000000..ec7bebfd
--- /dev/null
+++ b/tests/core/boringcrypto/boringcrypto_test.go
@@ -0,0 +1,115 @@
+// Copyright 2022 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.
+
+package boringcrypto_test
+
+import (
+ "bytes"
+ "os"
+ "os/exec"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
+
+go_binary(
+ name = "program",
+ srcs = ["main.go"],
+ deps = [":library"],
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "library",
+ srcs = ["library.go"],
+ importpath = "example.com/library"
+)
+-- main.go --
+//go:build goexperiment.boringcrypto
+
+package main
+
+import "example.com/library"
+
+func main() {
+ library.F()
+}
+-- library.go --
+package library
+
+func F() {}
+`,
+ })
+}
+
+const origWrapSDK = `go_wrap_sdk(
+ name = "go_sdk",
+ root_file = "@local_go_sdk//:ROOT",
+)`
+
+const wrapSDKBoringcrypto = `go_wrap_sdk(
+ name = "go_sdk",
+ root_file = "@local_go_sdk//:ROOT",
+ experiments = ["boringcrypto"],
+)`
+
+func TestBoringcryptoExperimentPresent(t *testing.T) {
+ mustReplaceInFile(t, "WORKSPACE", origWrapSDK, wrapSDKBoringcrypto)
+ defer mustReplaceInFile(t, "WORKSPACE", wrapSDKBoringcrypto, origWrapSDK)
+
+ if _, err := exec.LookPath("go"); err != nil {
+ t.Skip("go command is necessary to evaluate if boringcrypto experiment is present")
+ }
+
+ cmd := bazel_testing.BazelCmd("build", "//:program")
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stdout
+ if err := cmd.Run(); err != nil {
+ t.Fatal("failed to run bazel build: ", err)
+ }
+
+ out, err := exec.Command("go", "version", "bazel-bin/program_/program").CombinedOutput()
+ if err != nil {
+ t.Fatalf("failed to run go version command: %v\noutput was:\n%v", err, string(out))
+ }
+
+ if !strings.Contains(string(out), "X:boringcrypto") {
+ t.Fatalf(`version of binary: got %q, want string containing "X:boringcrypto"`, string(out))
+ }
+}
+
+func mustReplaceInFile(t *testing.T, path, old, new string) {
+ t.Helper()
+ if old == new {
+ return
+ }
+ data, err := os.ReadFile(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Contains(data, []byte(old)) {
+ t.Fatalf("bytes to replace %q not found in file %q with contents, %q", old, path, data)
+ }
+ data = bytes.ReplaceAll(data, []byte(old), []byte(new))
+ if err := os.WriteFile(path, data, 0666); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/tests/core/build_stdlib/BUILD.bazel b/tests/core/build_stdlib/BUILD.bazel
new file mode 100644
index 00000000..2d619fc3
--- /dev/null
+++ b/tests/core/build_stdlib/BUILD.bazel
@@ -0,0 +1,6 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "build_stdlib_test",
+ srcs = ["build_stdlib_test.go"],
+)
diff --git a/tests/core/build_stdlib/README.rst b/tests/core/build_stdlib/README.rst
new file mode 100644
index 00000000..38a0f100
--- /dev/null
+++ b/tests/core/build_stdlib/README.rst
@@ -0,0 +1,11 @@
+Building with standard libraries with missing .a files
+===========
+
+Tests to ensure that building with Go 1.20 and later versions of Go, which no longer
+include precompiled standard library .a files, continues to work
+
+build_stdlib_test
+--------------
+
+Test that a simple binary depending on a simple library can build when the WORKSPACE's
+go version is set to 1.20rc1. \ No newline at end of file
diff --git a/tests/core/build_stdlib/build_stdlib_test.go b/tests/core/build_stdlib/build_stdlib_test.go
new file mode 100644
index 00000000..31851b3a
--- /dev/null
+++ b/tests/core/build_stdlib/build_stdlib_test.go
@@ -0,0 +1,97 @@
+// Copyright 2022 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.
+
+package build_stdlib_test
+
+import (
+ "bytes"
+ "os"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
+
+go_binary(
+ name = "program",
+ srcs = ["main.go"],
+ deps = [":library"],
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "library",
+ srcs = ["library.go"],
+ importpath = "example.com/library"
+)
+-- main.go --
+package main
+
+import "example.com/library"
+
+func main() {
+ library.F()
+}
+-- library.go --
+package library
+
+func F() {}
+`,
+ })
+}
+
+const origWrapSDK = `go_wrap_sdk(
+ name = "go_sdk",
+ root_file = "@local_go_sdk//:ROOT",
+)
+
+go_register_toolchains()`
+
+const toolchain120 = `go_register_toolchains(version = "1.20rc1")`
+
+func TestBoringcryptoExperimentPresent(t *testing.T) {
+ mustReplaceInFile(t, "WORKSPACE", origWrapSDK, toolchain120)
+ defer mustReplaceInFile(t, "WORKSPACE", toolchain120, origWrapSDK)
+
+ cmd := bazel_testing.BazelCmd("build", "//:program")
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stdout
+ if err := cmd.Run(); err != nil {
+ t.Fatal("failed to run bazel build: ", err)
+ }
+
+}
+
+func mustReplaceInFile(t *testing.T, path, old, new string) {
+ t.Helper()
+ if old == new {
+ return
+ }
+ data, err := os.ReadFile(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Contains(data, []byte(old)) {
+ t.Fatalf("bytes to replace %q not found in file %q with contents, %q", old, path, data)
+ }
+ data = bytes.ReplaceAll(data, []byte(old), []byte(new))
+ if err := os.WriteFile(path, data, 0666); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/tests/core/c_linkmodes/BUILD.bazel b/tests/core/c_linkmodes/BUILD.bazel
new file mode 100644
index 00000000..ee7f68e6
--- /dev/null
+++ b/tests/core/c_linkmodes/BUILD.bazel
@@ -0,0 +1,139 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary")
+
+go_binary(
+ name = "adder_archive",
+ srcs = ["add.go"],
+ cgo = True,
+ linkmode = "c-archive",
+ tags = ["manual"],
+)
+
+cc_test(
+ name = "c-archive_test",
+ srcs = select({
+ "@io_bazel_rules_go//go/platform:windows": ["skip.c"],
+ "//conditions:default": ["add_test_archive.c"],
+ }),
+ deps = select({
+ "@io_bazel_rules_go//go/platform:windows": [],
+ "//conditions:default": [":adder_archive"],
+ }),
+)
+
+go_binary(
+ name = "c-archive_empty_hdr",
+ srcs = ["empty.go"],
+ cgo = True,
+ linkmode = "c-archive",
+ tags = ["manual"],
+)
+
+cc_test(
+ name = "c-archive_empty_hdr_test",
+ srcs = select({
+ "@io_bazel_rules_go//go/platform:windows": ["skip.c"],
+ "//conditions:default": ["c-archive_empty_hdr_test.c"],
+ }),
+ deps = select({
+ "@io_bazel_rules_go//go/platform:windows": [],
+ "//conditions:default": [":c-archive_empty_hdr"],
+ }),
+)
+
+go_binary(
+ name = "adder_shared",
+ srcs = ["add.go"],
+ cgo = True,
+ linkmode = "c-shared",
+ tags = ["manual"],
+)
+
+cc_test(
+ name = "c-shared_test",
+ srcs = select({
+ "@io_bazel_rules_go//go/platform:windows": ["skip.c"],
+ "//conditions:default": ["add_test_shared.c"],
+ }),
+ deps = select({
+ "@io_bazel_rules_go//go/platform:windows": [],
+ "//conditions:default": [":adder_shared"],
+ }),
+)
+
+go_binary(
+ name = "crypto",
+ srcs = [":crypto.go"],
+ cgo = True,
+ linkmode = "c-shared",
+ tags = ["manual"],
+ deps = ["@org_golang_x_crypto//nacl/box:go_default_library"],
+)
+
+cc_test(
+ name = "c-shared_dl_test",
+ srcs = select({
+ "@io_bazel_rules_go//go/platform:windows": ["skip.c"],
+ "//conditions:default": ["crypto_test_dl.c"],
+ }),
+ copts = select({
+ "@io_bazel_rules_go//go/platform:windows": [],
+ "//conditions:default": ['-DSO=\\"$(rootpath :crypto)\\"'],
+ }),
+ data = select({
+ "@io_bazel_rules_go//go/platform:windows": [],
+ "//conditions:default": [":crypto"],
+ }),
+ linkopts = select({
+ "@io_bazel_rules_go//go/platform:windows": [],
+ "//conditions:default": ["-ldl"],
+ }),
+)
+
+cc_library(
+ name = "adder_sandwich_cc",
+ srcs = ["add_sandwich.c"],
+ hdrs = ["add_sandwich.h"],
+ linkstatic = True,
+ alwayslink = True,
+)
+
+go_binary(
+ name = "adder_sandwich_archive",
+ srcs = ["add_sandwich.go"],
+ cdeps = [":adder_sandwich_cc"],
+ cgo = True,
+ linkmode = "c-archive",
+ tags = ["manual"],
+)
+
+cc_test(
+ name = "c-archive_sandwich_test",
+ srcs = select({
+ "@io_bazel_rules_go//go/platform:windows": ["skip.c"],
+ "//conditions:default": ["add_test_sandwich.c"],
+ }),
+ deps = select({
+ "@io_bazel_rules_go//go/platform:windows": [],
+ "//conditions:default": [":adder_sandwich_archive"],
+ }),
+)
+
+go_binary(
+ name = "go_with_cgo_dep",
+ srcs = select({
+ "@io_bazel_rules_go//go/platform:windows": ["empty.go"],
+ "//conditions:default": ["go_with_cgo_dep.go"],
+ }),
+ cgo = True,
+ linkmode = "c-archive",
+ deps = ["@org_golang_x_sys//unix"],
+)
+
+cc_binary(
+ name = "go_with_cgo_dep_caller",
+ srcs = select({
+ "@io_bazel_rules_go//go/platform:windows": ["skip.c"],
+ "//conditions:default": ["go_with_cgo_dep_caller.cc"],
+ }),
+ deps = [":go_with_cgo_dep"],
+)
diff --git a/tests/core/c_linkmodes/README.rst b/tests/core/c_linkmodes/README.rst
new file mode 100644
index 00000000..dd517725
--- /dev/null
+++ b/tests/core/c_linkmodes/README.rst
@@ -0,0 +1,35 @@
+c-archive / c-shared linkmodes
+==============================
+
+.. _go_binary: /docs/go/core/rules.md#go_binary
+.. _#2132: https://github.com/bazelbuild/rules_go/issues/2132
+.. _#2138: https://github.com/bazelbuild/rules_go/issues/2138
+
+Tests to ensure that c-archive link mode is working as expected.
+
+.. contents::
+
+c-archive_test
+--------------
+
+Checks that a ``go_binary`` can be built in ``c-archive`` mode and linked into
+a C/C++ binary as a dependency.
+
+c-archive_empty_hdr_test
+------------------------
+
+Checks that a ``go_binary`` built with in ``c-archive`` mode without cgo code
+still produces an empty header file. Verifies `#2132`_.
+
+c-shared_test
+-------------
+
+Checks that a ``go_binary`` can be built in ``c-shared`` mode and linked into
+a C/C++ binary as a dependency.
+
+c-shared_dl_test
+----------------
+
+Checks that a ``go_binary`` can be built in ``c-shared`` mode and loaded
+dynamically from a C/C++ binary. The binary depends on a package in
+``org_golang_x_crypto`` with a fair amount of assembly code. Verifies `#2138`_.
diff --git a/tests/core/c_linkmodes/add.go b/tests/core/c_linkmodes/add.go
new file mode 100644
index 00000000..35084fea
--- /dev/null
+++ b/tests/core/c_linkmodes/add.go
@@ -0,0 +1,11 @@
+package main
+
+// #define CGO_EXPORT_H_EXISTS
+import "C"
+
+//export GoAdd
+func GoAdd(a, b int) int {
+ return a + b
+}
+
+func main() {}
diff --git a/tests/core/c_linkmodes/add_sandwich.c b/tests/core/c_linkmodes/add_sandwich.c
new file mode 100644
index 00000000..dcf6150f
--- /dev/null
+++ b/tests/core/c_linkmodes/add_sandwich.c
@@ -0,0 +1,5 @@
+#include "add_sandwich.h"
+
+int add(int a, int b) {
+ return a + b;
+}
diff --git a/tests/core/c_linkmodes/add_sandwich.go b/tests/core/c_linkmodes/add_sandwich.go
new file mode 100644
index 00000000..0073638f
--- /dev/null
+++ b/tests/core/c_linkmodes/add_sandwich.go
@@ -0,0 +1,14 @@
+package main
+
+/*
+#define CGO_EXPORT_H_EXISTS
+#include "tests/core/c_linkmodes/add_sandwich.h"
+*/
+import "C"
+
+//export GoAdd
+func GoAdd(a, b int) int {
+ return int(C.add(C.int(a), C.int(b)))
+}
+
+func main() {}
diff --git a/tests/core/c_linkmodes/add_sandwich.h b/tests/core/c_linkmodes/add_sandwich.h
new file mode 100644
index 00000000..6295ab95
--- /dev/null
+++ b/tests/core/c_linkmodes/add_sandwich.h
@@ -0,0 +1 @@
+int add(int a, int b);
diff --git a/tests/core/c_linkmodes/add_test_archive.c b/tests/core/c_linkmodes/add_test_archive.c
new file mode 100644
index 00000000..1e585a42
--- /dev/null
+++ b/tests/core/c_linkmodes/add_test_archive.c
@@ -0,0 +1,11 @@
+#include <assert.h>
+#include "tests/core/c_linkmodes/adder_archive.h"
+
+#ifndef CGO_EXPORT_H_EXISTS
+#error cgo header did not include define
+#endif
+
+int main(int argc, char** argv) {
+ assert(GoAdd(42, 42) == 84);
+ return 0;
+}
diff --git a/tests/core/c_linkmodes/add_test_sandwich.c b/tests/core/c_linkmodes/add_test_sandwich.c
new file mode 100644
index 00000000..26efff70
--- /dev/null
+++ b/tests/core/c_linkmodes/add_test_sandwich.c
@@ -0,0 +1,11 @@
+#include <assert.h>
+#include "tests/core/c_linkmodes/adder_sandwich_archive.h"
+
+#ifndef CGO_EXPORT_H_EXISTS
+#error cgo header did not include define
+#endif
+
+int main(int argc, char** argv) {
+ assert(GoAdd(42, 42) == 84);
+ return 0;
+}
diff --git a/tests/core/c_linkmodes/add_test_shared.c b/tests/core/c_linkmodes/add_test_shared.c
new file mode 100644
index 00000000..2f57712e
--- /dev/null
+++ b/tests/core/c_linkmodes/add_test_shared.c
@@ -0,0 +1,11 @@
+#include <assert.h>
+#include "tests/core/c_linkmodes/adder_shared.h"
+
+#ifndef CGO_EXPORT_H_EXISTS
+#error cgo header did not include define
+#endif
+
+int main(int argc, char** argv) {
+ assert(GoAdd(42, 42) == 84);
+ return 0;
+}
diff --git a/tests/core/c_linkmodes/c-archive_empty_hdr_test.c b/tests/core/c_linkmodes/c-archive_empty_hdr_test.c
new file mode 100644
index 00000000..63ff5dfc
--- /dev/null
+++ b/tests/core/c_linkmodes/c-archive_empty_hdr_test.c
@@ -0,0 +1,17 @@
+// Copyright 2019 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.
+
+#include "tests/core/c_linkmodes/c-archive_empty_hdr.h"
+
+int main() { return 0; }
diff --git a/tests/core/c_linkmodes/crypto.go b/tests/core/c_linkmodes/crypto.go
new file mode 100644
index 00000000..a362c7ee
--- /dev/null
+++ b/tests/core/c_linkmodes/crypto.go
@@ -0,0 +1,18 @@
+package main
+
+import "C"
+
+import (
+ "crypto/rand"
+
+ "golang.org/x/crypto/nacl/box"
+)
+
+//export GoFn
+func GoFn() {
+ box.GenerateKey(rand.Reader)
+ return
+}
+
+func main() {
+}
diff --git a/tests/core/c_linkmodes/crypto_test_dl.c b/tests/core/c_linkmodes/crypto_test_dl.c
new file mode 100644
index 00000000..36e21495
--- /dev/null
+++ b/tests/core/c_linkmodes/crypto_test_dl.c
@@ -0,0 +1,30 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+#ifndef SO
+#error No SO path defined
+#endif
+
+int main() {
+ void* handle = dlopen(SO, RTLD_NOW);
+ if (!handle) {
+ printf("dlopen: %s\n", dlerror());
+ return 1;
+ }
+
+ typedef void (*gofn_t)();
+ gofn_t gofn = (gofn_t)dlsym(handle, "GoFn");
+ const char* dlsym_error = dlerror();
+ if (dlsym_error) {
+ printf("dlsym: %s\n", dlerror());
+ dlclose(handle);
+ return 1;
+ }
+
+ gofn();
+
+ if (dlclose(handle)) {
+ printf("dlclose: %s\n", dlerror());
+ }
+ return 0;
+}
diff --git a/tests/core/c_linkmodes/empty.go b/tests/core/c_linkmodes/empty.go
new file mode 100644
index 00000000..38dd16da
--- /dev/null
+++ b/tests/core/c_linkmodes/empty.go
@@ -0,0 +1,3 @@
+package main
+
+func main() {}
diff --git a/tests/core/c_linkmodes/go_with_cgo_dep.go b/tests/core/c_linkmodes/go_with_cgo_dep.go
new file mode 100644
index 00000000..cfaeb31f
--- /dev/null
+++ b/tests/core/c_linkmodes/go_with_cgo_dep.go
@@ -0,0 +1,29 @@
+// Copyright 2021 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.
+
+package main
+
+import "C"
+import (
+ "fmt"
+
+ "golang.org/x/sys/unix"
+)
+
+//export UnixHello
+func UnixHello() {
+ fmt.Printf("Hello, %d\n", unix.Getuid())
+}
+
+func main() {}
diff --git a/tests/core/c_linkmodes/go_with_cgo_dep_caller.cc b/tests/core/c_linkmodes/go_with_cgo_dep_caller.cc
new file mode 100644
index 00000000..cc771076
--- /dev/null
+++ b/tests/core/c_linkmodes/go_with_cgo_dep_caller.cc
@@ -0,0 +1,20 @@
+// Copyright 2021 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.
+
+#include "tests/core/c_linkmodes/go_with_cgo_dep.h"
+
+int main() {
+ UnixHello();
+ return 0;
+}
diff --git a/tests/core/c_linkmodes/skip.c b/tests/core/c_linkmodes/skip.c
new file mode 100644
index 00000000..33c14ce1
--- /dev/null
+++ b/tests/core/c_linkmodes/skip.c
@@ -0,0 +1,3 @@
+int main() {
+ return 0;
+}
diff --git a/tests/core/cgo/BUILD.bazel b/tests/core/cgo/BUILD.bazel
new file mode 100644
index 00000000..cc12203f
--- /dev/null
+++ b/tests/core/cgo/BUILD.bazel
@@ -0,0 +1,474 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_test(
+ name = "opts_test",
+ srcs = ["adder_test.go"],
+ embed = [":opts"],
+)
+
+genrule(
+ name = "generate_header_copts",
+ outs = ["generated_copts/generated_copts.h"],
+ cmd = "echo '#define GENERATED_COPTS 1' >$@",
+)
+
+genrule(
+ name = "generate_header_cppopts",
+ outs = ["generated_cppopts/generated_cppopts.h"],
+ cmd = "echo '#define GENERATED_CPPOPTS 1' >$@",
+)
+
+genrule(
+ name = "generate_header_cxxopts",
+ outs = ["generated_cxxopts/generated_cxxopts.h"],
+ cmd = "echo '#define GENERATED_CXXOPTS 1' >$@",
+)
+
+cc_library(
+ name = "generated_headers",
+ hdrs = [
+ "generated_copts/generated_copts.h",
+ "generated_cppopts/generated_cppopts.h",
+ "generated_cxxopts/generated_cxxopts.h",
+ ],
+)
+
+COPTS_INCLUDE_PREFIX = (package_name() if repository_name() == "@" else "external/%s/%s" % (
+ repository_name()[1:],
+ package_name(),
+))
+
+go_library(
+ name = "opts",
+ srcs = [
+ "add.c",
+ "add.cpp",
+ "add.h",
+ "adder.go",
+ ] + select({
+ "@io_bazel_rules_go//go/platform:darwin": [
+ "add.m",
+ "add.mm",
+ ],
+ "//conditions:default": [],
+ }),
+ cdeps = [":generated_headers"],
+ cgo = True,
+ copts = [
+ "-DRULES_GO_C",
+ "-I$(GENDIR)/%s/generated_copts" % COPTS_INCLUDE_PREFIX,
+ "-DDOLLAR_SIGN_C=$$", # the dollar sign should be escaped
+ ],
+ cppopts = [
+ "-DRULES_GO_CPP",
+ "-I$(GENDIR)/%s/generated_cppopts" % COPTS_INCLUDE_PREFIX,
+ "-DDOLLAR_SIGN_CPP=$$", # the dollar sign should be escaped
+ ],
+ cxxopts = [
+ "-DRULES_GO_CXX",
+ "-I$(GENDIR)/%s/generated_cxxopts" % COPTS_INCLUDE_PREFIX,
+ "-DDOLLAR_SIGN_CXX=$$", # the dollar sign should be escaped
+ ],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cxx",
+)
+
+go_test(
+ name = "dylib_test",
+ srcs = ["dylib_test.go"],
+ embed = [":dylib_client"],
+ rundir = ".",
+ tags = ["manual"], # //tests/core/cgo:generate_imported_dylib.sh must be run first
+)
+
+go_library(
+ name = "dylib_client",
+ srcs = ["dylib_client.go"],
+ cdeps = select({
+ "@io_bazel_rules_go//go/platform:darwin": [":darwin_imported_dylib"],
+ "//conditions:default": [":linux_imported_dylib"],
+ # TODO(jayconrod): Support windows, skip others.
+ }),
+ cgo = True,
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cgo/dylib",
+ tags = ["manual"],
+)
+
+cc_import(
+ name = "darwin_imported_dylib",
+ shared_library = "libimported.dylib",
+ tags = ["manual"],
+)
+
+cc_import(
+ name = "linux_imported_dylib",
+ shared_library = ":libimported.so",
+ tags = ["manual"],
+)
+
+go_test(
+ name = "generated_dylib_test",
+ srcs = ["dylib_test.go"],
+ embed = [":generated_dylib_client"],
+ rundir = ".",
+)
+
+go_library(
+ name = "generated_dylib_client",
+ srcs = ["dylib_client.go"],
+ cdeps = select({
+ "@io_bazel_rules_go//go/platform:darwin": [":darwin_imported_generated_dylib"],
+ "//conditions:default": [":linux_imported_generated_dylib"],
+ # TODO(jayconrod): Support windows, skip others.
+ }),
+ cgo = True,
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cgo/dylib",
+)
+
+cc_import(
+ name = "darwin_imported_generated_dylib",
+ shared_library = ":libimported_generated.dylib",
+ tags = ["manual"],
+)
+
+cc_binary(
+ name = "libimported_generated.dylib",
+ srcs = ["imported.c"],
+ linkopts = ["-Wl,-install_name,@rpath/libimported_generated.dylib"],
+ linkshared = True,
+ tags = ["manual"],
+)
+
+cc_import(
+ name = "linux_imported_generated_dylib",
+ shared_library = ":libimported_generated.so",
+ tags = ["manual"],
+)
+
+cc_binary(
+ name = "libimported_generated.so",
+ srcs = ["imported.c"],
+ linkshared = True,
+ tags = ["manual"],
+)
+
+# //tests/core/cgo:generate_imported_dylib.sh must be run first
+go_test(
+ name = "versioned_dylib_test",
+ srcs = ["dylib_test.go"],
+ embed = [":versioned_dylib_client"],
+ rundir = ".",
+ target_compatible_with = select({
+ "@platforms//os:osx": [],
+ "@platforms//os:linux": [],
+ "//conditions:default": ["@platforms//:incompatible"],
+ }),
+)
+
+go_library(
+ name = "versioned_dylib_client",
+ srcs = ["dylib_client.go"],
+ cdeps = select({
+ "@io_bazel_rules_go//go/platform:darwin": [":darwin_imported_versioned_dylib"],
+ "//conditions:default": [":linux_imported_versioned_dylib"],
+ # TODO(jayconrod): Support windows, skip others.
+ }),
+ cgo = True,
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cgo/dylib",
+ tags = ["manual"],
+)
+
+cc_import(
+ name = "linux_imported_versioned_dylib",
+ shared_library = "libversioned.so.2",
+ tags = ["manual"],
+)
+
+cc_import(
+ name = "darwin_imported_versioned_dylib",
+ shared_library = "libversioned.2.dylib",
+ tags = ["manual"],
+)
+
+go_test(
+ name = "oracle_convention_darwin_dylib_test",
+ srcs = ["dylib_test.go"],
+ embed = [":oracle_convention_darwin_dylib_client"],
+ rundir = ".",
+ target_compatible_with = ["@platforms//os:macos"],
+)
+
+go_library(
+ name = "oracle_convention_darwin_dylib_client",
+ srcs = ["dylib_client.go"],
+ cdeps = [":oracle_convention_darwin_dylib"],
+ cgo = True,
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cgo/dylib",
+ target_compatible_with = ["@platforms//os:macos"],
+)
+
+# //tests/core/cgo:generate_imported_dylib.sh must be run first
+cc_library(
+ name = "oracle_convention_darwin_dylib",
+ srcs = [
+ "libversioned.dylib",
+ "libversioned.dylib.2",
+ ],
+ target_compatible_with = ["@platforms//os:macos"],
+)
+
+go_test(
+ name = "generated_versioned_dylib_test",
+ srcs = ["dylib_test.go"],
+ embed = [":generated_versioned_dylib_client"],
+ rundir = ".",
+)
+
+go_library(
+ name = "generated_versioned_dylib_client",
+ srcs = ["dylib_client.go"],
+ cdeps = select({
+ # This test exists just for versioned `.so`s on Linux,
+ # but we can reuse the above test's dylib so it passes on darwin,
+ # where filename suffixes are not used for library version.
+ "@io_bazel_rules_go//go/platform:darwin": [":darwin_imported_generated_dylib"],
+ "//conditions:default": [":linux_imported_generated_versioned_dylib"],
+ # TODO(jayconrod): Support windows, skip others.
+ }),
+ cgo = True,
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cgo/dylib",
+)
+
+cc_library(
+ name = "linux_imported_generated_versioned_dylib",
+ srcs = [":libimported_generated.so.2"],
+ linkstatic = False,
+ tags = ["manual"],
+)
+
+cc_binary(
+ name = "libimported_generated.so.2",
+ srcs = ["imported.c"],
+ linkshared = True,
+ tags = ["manual"],
+)
+
+go_test(
+ name = "cc_libs_test",
+ srcs = [
+ "cc_libs_common.go",
+ "cc_libs_darwin_test.go",
+ "cc_libs_linux_test.go",
+ ],
+ data = [
+ ":c_srcs",
+ ":cc_deps",
+ ":cc_srcs",
+ ":pure",
+ ],
+ deps = ["//go/tools/bazel:go_default_library"],
+)
+
+go_binary(
+ name = "pure",
+ srcs = ["pure.go"],
+ out = "pure_bin",
+ cgo = True,
+ pure = "on",
+)
+
+go_binary(
+ name = "c_srcs",
+ srcs = [
+ "foo.c",
+ "foo.go",
+ ],
+ out = "c_srcs_bin",
+ cgo = True,
+)
+
+go_binary(
+ name = "cc_srcs",
+ srcs = [
+ "bar.cc",
+ "bar.go",
+ ],
+ out = "cc_srcs_bin",
+ cgo = True,
+)
+
+go_binary(
+ name = "cc_deps",
+ srcs = ["bar.go"],
+ out = "cc_deps_bin",
+ cdeps = [":bar_dep"],
+ cgo = True,
+)
+
+cc_library(
+ name = "bar_dep",
+ srcs = ["bar.cc"],
+)
+
+go_test(
+ name = "race_test",
+ srcs = [
+ "race_off.c",
+ "race_off.go",
+ "race_on.c",
+ "race_on.go",
+ "race_test.go",
+ ],
+ cgo = True,
+ race = "on",
+)
+
+go_test(
+ name = "tag_test",
+ srcs = ["tag_test.go"],
+ data = [
+ ":tag_cgo_bin",
+ ":tag_pure_bin",
+ ],
+ rundir = ".",
+ deps = ["//go/tools/bazel:go_default_library"],
+)
+
+go_binary(
+ name = "tag_pure_bin",
+ srcs = [
+ "tag_pure.go",
+ "tag_pure_err.c",
+ "tag_pure_err.go",
+ ],
+ cgo = True,
+ pure = "on",
+)
+
+go_binary(
+ name = "tag_cgo_bin",
+ srcs = [
+ "tag_cgo.go",
+ "tag_cgo_err.go",
+ ],
+ cgo = True,
+ pure = "off",
+)
+
+go_test(
+ name = "cgo_link_test",
+ srcs = [
+ "cgo_link_test.go",
+ "cgo_ref.go",
+ ],
+ cdeps = [":cgo_link_dep"],
+ cgo = True,
+)
+
+cc_library(
+ name = "cgo_link_dep",
+ srcs = ["cgo_link_dep.c"],
+)
+
+go_test(
+ name = "split_import_test",
+ srcs = [
+ "split_import_i_test.go",
+ "split_import_x_test.go",
+ ],
+ embed = [":split_import_a"],
+ deps = [":split_import_b"],
+)
+
+go_library(
+ name = "split_import_a",
+ srcs = ["split_import_a.go"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cgo/split_import/a",
+)
+
+go_library(
+ name = "split_import_b",
+ srcs = ["split_import_b.go"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cgo/split_import/b",
+ deps = [
+ ":split_import_a",
+ ":split_import_cgo",
+ ],
+)
+
+go_library(
+ name = "split_import_cgo",
+ srcs = ["split_import_cgo.go"],
+ cdeps = [":split_import_c"],
+ cgo = True,
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cgo/split_import/cgo",
+)
+
+cc_library(
+ name = "split_import_c",
+ srcs = ["split_import_c.c"],
+ hdrs = ["split_import_c.h"],
+)
+
+go_bazel_test(
+ name = "external_includes_test",
+ srcs = ["external_includes_test.go"],
+)
+
+go_library(
+ name = "use_external_symbol",
+ srcs = ["use_external_symbol.go"],
+ cgo = True,
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cgo/use_external_symbol",
+ tags = ["manual"],
+)
+
+go_binary(
+ name = "provide_external_symbol",
+ srcs = ["provide_external_symbol.go"],
+ cgo = True,
+ target_compatible_with = select({
+ "@platforms//os:osx": [],
+ "@platforms//os:linux": [],
+ "//conditions:default": ["@platforms//:incompatible"],
+ }),
+ deps = [":use_external_symbol"],
+)
+
+cc_library(
+ name = "native_dep",
+ srcs = ["native_dep.c"],
+ hdrs = ["native_dep.h"],
+ # Force static linking to ensure that the build doesn't succeed by
+ # accidentally picking up the shared library in the search path.
+ linkstatic = True,
+)
+
+go_library(
+ name = "transitive_dep",
+ srcs = ["transitive_dep.go"],
+ cdeps = [":native_dep"],
+ cgo = True,
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cgo/transitive_dep",
+)
+
+go_library(
+ name = "direct_dep",
+ srcs = ["direct_dep.go"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cgo/direct_dep",
+ deps = [":transitive_dep"],
+)
+
+go_binary(
+ name = "use_transitive_symbol",
+ srcs = ["use_transitive_symbol.go"],
+ cgo = True,
+ linkmode = "c-archive",
+ deps = [":direct_dep"],
+)
+
+cc_binary(
+ name = "use_c_symbol_through_go",
+ srcs = ["use_c_symbol_through_go.c"],
+ deps = [":use_transitive_symbol"],
+)
diff --git a/tests/core/cgo/README.rst b/tests/core/cgo/README.rst
new file mode 100644
index 00000000..a385cab3
--- /dev/null
+++ b/tests/core/cgo/README.rst
@@ -0,0 +1,67 @@
+.. _#2067: https://github.com/bazelbuild/rules_go/issues/2067
+.. _#2622: https://github.com/bazelbuild/rules_go/issues/2622
+
+Basic cgo functionality
+=======================
+
+opts_test
+---------
+
+Checks that different sets of options are passed to C and C++ sources in a
+``go_library`` with ``cgo = True``.
+
+(generated_)?(versioned_)?dylib_test
+------------------------------------
+
+Checks that Go binaries can link against dynamic C libraries. Some libraries
+(especially those provided with ``cc_import``) may only have dynamic versions,
+and we should be able to link against them and find them at run-time.
+
+The non ``generated_`` tests are manual. The ``generate_imported_dylib.sh``
+script must be run before running the tests themselves.
+
+The ``generated_`` variants check that Go binaries can link against dynamic C
+libraries that are generated by another rule, rather than being included in the
+source tree.
+
+The ``versioned_`` variants check that Go binaries can link against dynamic C
+libraries that are only available as a versioned shared library, like
+``libfoo.so.1``, as used on Linux.
+
+cc_libs_test
+------------
+
+Checks that Go binaries that include cgo code may or may not link against
+libstdc++, depending on how they're linked. This tests several binaries:
+
+* ``pure_bin`` - built in ``"pure"`` mode, should not depend on libstdc++.
+* ``c_srcs`` - has no C++ code in sources, should not depend on libstdc++.
+* ``cc_srcs`` - has some C++ code in sources, should depend on libstdc++.
+* ``cc_deps`` - depends on a ``cc_library``, should depend on libstdc++
+ because we don't know what's in it.
+
+race_test
+---------
+
+Checks that cgo code in a binary with ``race = "on"`` is compiled in race mode.
+Verifies #1592.
+
+tag_test
+--------
+
+Checks that sources with ``// +build cgo`` are built when cgo is enabled
+(whether or not ``cgo = True`` is set), and sources with ``// +build !cgo``
+are only built in pure mode.
+
+cdeps_link_test
+---------------
+
+Checks that libraries in ``cdeps`` are linked into the generated ``_cgo_.o``
+executable used to produce ``_cgo_imports.go``. Verifies `#2067`_.
+
+split_import_test
+-----------------
+
+Checks that when a package with ``cdeps`` is recompiled due to a split test,
+the input files from ``cdeps`` are included in the recompilation and are passed
+to the linker. Verifies `#2622`_.
diff --git a/tests/core/cgo/add.c b/tests/core/cgo/add.c
new file mode 100644
index 00000000..fba09af2
--- /dev/null
+++ b/tests/core/cgo/add.c
@@ -0,0 +1,19 @@
+#include <add.h>
+#include <generated_cppopts.h>
+#include <generated_copts.h>
+
+#if !defined(RULES_GO_C) || !defined(RULES_GO_CPP) || defined(RULES_GO_CXX)
+#error This is a C file, only RULES_GO_C and RULES_GO_CPP should be defined.
+#endif
+
+#if !defined(GENERATED_COPTS) || !defined(GENERATED_CPPOPTS) || defined(GENERATED_CXXOPTS)
+#error Generated headers should be correctly included
+#endif
+
+int add_c(int a, int b) {
+ int $ = 0;
+ int sum = a + b;
+ sum += DOLLAR_SIGN_C;
+ sum += DOLLAR_SIGN_CPP;
+ return sum;
+}
diff --git a/tests/core/cgo/add.cpp b/tests/core/cgo/add.cpp
new file mode 100644
index 00000000..e5dbc0a9
--- /dev/null
+++ b/tests/core/cgo/add.cpp
@@ -0,0 +1,19 @@
+#include "add.h"
+#include <generated_cppopts.h>
+#include <generated_cxxopts.h>
+
+#if !defined(RULES_GO_CPP) || !defined(RULES_GO_CXX) || defined(RULES_GO_C)
+#error This is a C++ file, only RULES_GO_CXX and RULES_GO_CPP should be defined.
+#endif
+
+#if !defined(GENERATED_CPPOPTS) || !defined(GENERATED_CXXOPTS) || defined(GENERATED_COPTS)
+#error Generated headers should be correctly included
+#endif
+
+int add_cpp(int a, int b) {
+ int $ = 0;
+ int sum = a + b;
+ sum += DOLLAR_SIGN_CXX;
+ sum += DOLLAR_SIGN_CPP;
+ return sum;
+}
diff --git a/tests/core/cgo/add.h b/tests/core/cgo/add.h
new file mode 100644
index 00000000..eb2c7c77
--- /dev/null
+++ b/tests/core/cgo/add.h
@@ -0,0 +1,10 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int add_c(int a, int b);
+int add_cpp(int a, int b);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/tests/core/cgo/add.m b/tests/core/cgo/add.m
new file mode 100644
index 00000000..5a321b29
--- /dev/null
+++ b/tests/core/cgo/add.m
@@ -0,0 +1,11 @@
+#include "add.h"
+#include <generated_cppopts.h>
+#include <generated_copts.h>
+
+#if !defined(RULES_GO_C) || !defined(RULES_GO_CPP) || defined(RULES_GO_CXX)
+#error This is an Objective-C file, only RULES_GO_C and RULES_GO_CPP should be defined.
+#endif
+
+#if !defined(GENERATED_COPTS) || !defined(GENERATED_CPPOPTS) || defined(GENERATED_CXXOPTS)
+#error Generated headers should be correctly included
+#endif
diff --git a/tests/core/cgo/add.mm b/tests/core/cgo/add.mm
new file mode 100644
index 00000000..aed54ab5
--- /dev/null
+++ b/tests/core/cgo/add.mm
@@ -0,0 +1,11 @@
+#include "add.h"
+#include <generated_cppopts.h>
+#include <generated_cxxopts.h>
+
+#if !defined(RULES_GO_CPP) || !defined(RULES_GO_CXX) || defined(RULES_GO_C)
+#error This is an Objective-C++ file, only RULES_GO_CXX and RULES_GO_CPP should be defined.
+#endif
+
+#if !defined(GENERATED_CPPOPTS) || !defined(GENERATED_CXXOPTS) || defined(GENERATED_COPTS)
+#error Generated headers should be correctly included
+#endif
diff --git a/tests/core/cgo/adder.go b/tests/core/cgo/adder.go
new file mode 100644
index 00000000..e8e2f403
--- /dev/null
+++ b/tests/core/cgo/adder.go
@@ -0,0 +1,14 @@
+package objc
+
+/*
+#include "add.h"
+*/
+import "C"
+
+func AddC(a, b int32) int32 {
+ return int32(C.add_c(C.int(a), C.int(b)))
+}
+
+func AddCPP(a, b int32) int32 {
+ return int32(C.add_cpp(C.int(a), C.int(b)))
+}
diff --git a/tests/core/cgo/adder_test.go b/tests/core/cgo/adder_test.go
new file mode 100644
index 00000000..fc9bf451
--- /dev/null
+++ b/tests/core/cgo/adder_test.go
@@ -0,0 +1,19 @@
+package objc
+
+import (
+ "fmt"
+ "math/rand"
+ "testing"
+)
+
+func TestCPPAdder(t *testing.T) {
+ a := rand.Int31()
+ b := rand.Int31()
+ expected := a + b
+ if result := AddC(a, b); result != expected {
+ t.Error(fmt.Errorf("wrong result: got %d, expected %d", result, expected))
+ }
+ if result := AddCPP(a, b); result != expected {
+ t.Error(fmt.Errorf("wrong result: got %d, expected %d", result, expected))
+ }
+}
diff --git a/tests/core/cgo/bar.cc b/tests/core/cgo/bar.cc
new file mode 100644
index 00000000..d72f5123
--- /dev/null
+++ b/tests/core/cgo/bar.cc
@@ -0,0 +1,9 @@
+#include <iostream>
+
+extern "C" {
+
+void bar() {
+ std::cout << "bar" << std::endl;
+}
+
+}
diff --git a/tests/core/cgo/bar.go b/tests/core/cgo/bar.go
new file mode 100644
index 00000000..92562dd4
--- /dev/null
+++ b/tests/core/cgo/bar.go
@@ -0,0 +1,8 @@
+package main
+
+// void bar();
+import "C"
+
+func main() {
+ C.bar()
+}
diff --git a/tests/core/cgo/cc_libs_common.go b/tests/core/cgo/cc_libs_common.go
new file mode 100644
index 00000000..40a04ed5
--- /dev/null
+++ b/tests/core/cgo/cc_libs_common.go
@@ -0,0 +1,34 @@
+package cc_libs_test
+
+import (
+ "bytes"
+ "github.com/bazelbuild/rules_go/go/tools/bazel"
+ "io/ioutil"
+ "testing"
+)
+
+// A distinctive substring contained in every absolute path pointing into the
+// Bazel cache.
+const execPathIndicator = "/execroot/io_bazel_rules_go"
+
+func verifyNoCachePaths(t *testing.T, shortPath string) {
+ binPath, err := bazel.Runfile(shortPath)
+ if err != nil {
+ t.Error(err)
+ }
+ binBytes, err := ioutil.ReadFile(binPath)
+ if err != nil {
+ t.Error(err)
+ }
+ if pos := bytes.Index(binBytes, []byte(execPathIndicator)); pos != -1 {
+ begin := pos - 150
+ if begin < 0 {
+ begin = 0
+ }
+ end := pos + 150
+ if end > len(binBytes) {
+ end = len(binBytes)
+ }
+ t.Errorf("%s leaks an absolute path:\n%q", shortPath, binBytes[begin:end])
+ }
+}
diff --git a/tests/core/cgo/cc_libs_darwin_test.go b/tests/core/cgo/cc_libs_darwin_test.go
new file mode 100644
index 00000000..4201dbf2
--- /dev/null
+++ b/tests/core/cgo/cc_libs_darwin_test.go
@@ -0,0 +1,96 @@
+// Copyright 2018 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.
+
+package cc_libs_test
+
+import (
+ "debug/macho"
+ "path"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel"
+)
+
+func TestBinaries(t *testing.T) {
+ for _, test := range []struct {
+ shortPath string
+ wantLibs map[string]bool
+ }{
+ {
+ shortPath: "tests/core/cgo/pure_bin",
+ // Since go1.11, pure binaries have a dependency on libSystem.
+ // This is true with go tool link -linkmode=internal
+ // and with CGO_ENABLED=0 go build ...
+ wantLibs: map[string]bool{"libc++": false},
+ }, {
+ shortPath: "tests/core/cgo/c_srcs_bin",
+ wantLibs: map[string]bool{"libSystem": true, "libc++": false},
+ }, {
+ shortPath: "tests/core/cgo/cc_srcs_bin",
+ wantLibs: map[string]bool{"libSystem": true, "libc++": true},
+ }, {
+ shortPath: "tests/core/cgo/cc_deps_bin",
+ wantLibs: map[string]bool{"libSystem": true, "libc++": true},
+ },
+ } {
+ t.Run(path.Base(test.shortPath), func(t *testing.T) {
+ libs, err := listLibs(test.shortPath)
+ if err != nil {
+ t.Fatal(err)
+ }
+ haveLibs := make(map[string]bool)
+ for _, lib := range libs {
+ haveLibs[lib] = true
+ }
+ for haveLib := range haveLibs {
+ if wantLib, ok := test.wantLibs[haveLib]; ok && !wantLib {
+ t.Errorf("unexpected dependency on library %q", haveLib)
+ }
+ }
+ for wantLib, want := range test.wantLibs {
+ if want && !haveLibs[wantLib] {
+ t.Errorf("wanted dependency on library %q", wantLib)
+ }
+ }
+
+ verifyNoCachePaths(t, test.shortPath)
+ })
+ }
+}
+
+func listLibs(shortPath string) ([]string, error) {
+ binPath, err := bazel.Runfile(shortPath)
+ if err != nil {
+ return nil, err
+ }
+ f, err := macho.Open(binPath)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ libs, err := f.ImportedLibraries()
+ if err != nil {
+ return nil, err
+ }
+ for i := range libs {
+ if pos := strings.LastIndexByte(libs[i], '/'); pos >= 0 {
+ libs[i] = libs[i][pos+1:]
+ }
+ if pos := strings.IndexByte(libs[i], '.'); pos >= 0 {
+ libs[i] = libs[i][:pos]
+ }
+ }
+ return libs, nil
+}
diff --git a/tests/core/cgo/cc_libs_linux_test.go b/tests/core/cgo/cc_libs_linux_test.go
new file mode 100644
index 00000000..204a8fcf
--- /dev/null
+++ b/tests/core/cgo/cc_libs_linux_test.go
@@ -0,0 +1,93 @@
+// Copyright 2018 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.
+
+package cc_libs_test
+
+import (
+ "debug/elf"
+ "path"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel"
+)
+
+func TestBinaries(t *testing.T) {
+ for _, test := range []struct {
+ shortPath string
+ wantLibs map[string]bool
+ }{
+ {
+ shortPath: "tests/core/cgo/pure_bin",
+ wantLibs: map[string]bool{"libc": false, "libstdc++": false},
+ }, {
+ shortPath: "tests/core/cgo/c_srcs_bin",
+ wantLibs: map[string]bool{"libc": true, "libstdc++": false},
+ }, {
+ shortPath: "tests/core/cgo/cc_srcs_bin",
+ wantLibs: map[string]bool{"libc": true, "libstdc++": true},
+ }, {
+ shortPath: "tests/core/cgo/cc_deps_bin",
+ wantLibs: map[string]bool{"libc": true, "libstdc++": true},
+ },
+ } {
+ t.Run(path.Base(test.shortPath), func(t *testing.T) {
+ libs, err := listLibs(test.shortPath)
+ if err != nil {
+ t.Fatal(err)
+ }
+ haveLibs := make(map[string]bool)
+ for _, lib := range libs {
+ haveLibs[lib] = true
+ }
+ for haveLib := range haveLibs {
+ if wantLib, ok := test.wantLibs[haveLib]; ok && !wantLib {
+ t.Errorf("unexpected dependency on library %q", haveLib)
+ }
+ }
+ for wantLib, want := range test.wantLibs {
+ if want && !haveLibs[wantLib] {
+ t.Errorf("wanted dependency on library %q", wantLib)
+ }
+ }
+
+ verifyNoCachePaths(t, test.shortPath)
+ })
+ }
+}
+
+func listLibs(shortPath string) ([]string, error) {
+ binPath, err := bazel.Runfile(shortPath)
+ if err != nil {
+ return nil, err
+ }
+ f, err := elf.Open(binPath)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ libs, err := f.ImportedLibraries()
+ if err != nil {
+ return nil, err
+ }
+ for i := range libs {
+ if pos := strings.LastIndexByte(libs[i], '/'); pos >= 0 {
+ libs[i] = libs[i][pos+1:]
+ }
+ if pos := strings.IndexByte(libs[i], '.'); pos >= 0 {
+ libs[i] = libs[i][:pos]
+ }
+ }
+ return libs, nil
+}
diff --git a/tests/core/cgo/cgo_link_dep.c b/tests/core/cgo/cgo_link_dep.c
new file mode 100644
index 00000000..c102d587
--- /dev/null
+++ b/tests/core/cgo/cgo_link_dep.c
@@ -0,0 +1,15 @@
+// Copyright 2019 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.
+
+int f() { return 42; }
diff --git a/tests/core/cgo/cgo_link_test.go b/tests/core/cgo/cgo_link_test.go
new file mode 100644
index 00000000..fcd3d00f
--- /dev/null
+++ b/tests/core/cgo/cgo_link_test.go
@@ -0,0 +1,24 @@
+// Copyright 2019 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.
+
+package cgo_link
+
+import "testing"
+
+func Test(t *testing.T) {
+ want := 42
+ if got := F(); got != want {
+ t.Errorf("got %d; want %d", got, want)
+ }
+}
diff --git a/tests/core/cgo/cgo_ref.go b/tests/core/cgo/cgo_ref.go
new file mode 100644
index 00000000..f425e188
--- /dev/null
+++ b/tests/core/cgo/cgo_ref.go
@@ -0,0 +1,20 @@
+// Copyright 2019 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.
+
+package cgo_link
+
+// int f();
+import "C"
+
+func F() int { return int(C.f()) }
diff --git a/tests/core/cgo/direct_dep.go b/tests/core/cgo/direct_dep.go
new file mode 100644
index 00000000..6f717863
--- /dev/null
+++ b/tests/core/cgo/direct_dep.go
@@ -0,0 +1,9 @@
+package direct_dep
+
+import (
+ "github.com/bazelbuild/rules_go/tests/core/cgo/transitive_dep"
+)
+
+func PrintGreeting() {
+ transitive_dep.PrintGreeting()
+}
diff --git a/tests/core/cgo/dylib_client.go b/tests/core/cgo/dylib_client.go
new file mode 100644
index 00000000..7356d127
--- /dev/null
+++ b/tests/core/cgo/dylib_client.go
@@ -0,0 +1,10 @@
+package dylib
+
+/*
+extern int foo();
+*/
+import "C"
+
+func Foo() int {
+ return int(C.foo())
+}
diff --git a/tests/core/cgo/dylib_test.go b/tests/core/cgo/dylib_test.go
new file mode 100644
index 00000000..03aa1f36
--- /dev/null
+++ b/tests/core/cgo/dylib_test.go
@@ -0,0 +1,10 @@
+package dylib
+
+import "testing"
+
+func TestFoo(t *testing.T) {
+ want := 42
+ if got := Foo(); got != want {
+ t.Errorf("got %d ; want %d", got, want)
+ }
+}
diff --git a/tests/core/cgo/external_includes_test.go b/tests/core/cgo/external_includes_test.go
new file mode 100644
index 00000000..0e1ba06a
--- /dev/null
+++ b/tests/core/cgo/external_includes_test.go
@@ -0,0 +1,85 @@
+// Copyright 2020 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.
+
+package external_includes_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- other_repo/WORKSPACE --
+-- other_repo/cc/BUILD.bazel --
+cc_binary(
+ name = "main",
+ srcs = ["main.c"],
+ deps = ["//cgo"],
+)
+-- other_repo/cc/main.c --
+#include "cgo/cgo.h"
+
+int main() {}
+-- other_repo/cgo/BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
+
+go_binary(
+ name = "cgo",
+ embed = [":cgo_lib"],
+ importpath = "example.com/rules_go/cgo",
+ linkmode = "c-archive",
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "cgo_lib",
+ srcs = ["cgo.go"],
+ cgo = True,
+ importpath = "example.com/rules_go/cgo",
+ visibility = ["//visibility:private"],
+)
+-- other_repo/cgo/cgo.go --
+package main
+
+import "C"
+
+//export HelloCgo
+func HelloCgo() {}
+
+func main() {}
+`,
+ WorkspaceSuffix: `
+local_repository(
+ name = "other_repo",
+ path = "other_repo",
+)
+`,
+ })
+}
+
+func TestExternalIncludes(t *testing.T) {
+ t.Run("default", func(t *testing.T) {
+ if err := bazel_testing.RunBazel("build", "@other_repo//cc:main"); err != nil {
+ t.Fatalf("Did not expect error:\n%+v", err)
+ }
+ })
+ t.Run("experimental_sibling_repository_layout", func(t *testing.T) {
+ if err := bazel_testing.RunBazel("build", "--experimental_sibling_repository_layout", "@other_repo//cc:main"); err != nil {
+ t.Fatalf("Did not expect error:\n%+v", err)
+ }
+ })
+}
diff --git a/tests/core/cgo/foo.c b/tests/core/cgo/foo.c
new file mode 100644
index 00000000..0992a7d1
--- /dev/null
+++ b/tests/core/cgo/foo.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void foo() {
+ printf("foo\n");
+}
+
+
diff --git a/tests/core/cgo/foo.go b/tests/core/cgo/foo.go
new file mode 100644
index 00000000..4403a51c
--- /dev/null
+++ b/tests/core/cgo/foo.go
@@ -0,0 +1,8 @@
+package main
+
+// void foo();
+import "C"
+
+func main() {
+ C.foo()
+}
diff --git a/tests/core/cgo/generate_imported_dylib.sh b/tests/core/cgo/generate_imported_dylib.sh
new file mode 100755
index 00000000..41227b77
--- /dev/null
+++ b/tests/core/cgo/generate_imported_dylib.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+set -exo pipefail
+
+cd "$(dirname "$0")"
+
+case "$(uname -s)" in
+ Linux*)
+ cc -shared -o libimported.so imported.c
+ cc -shared -o libversioned.so.2 imported.c
+ ;;
+ Darwin*)
+ cc -shared -Wl,-install_name,@rpath/libimported.dylib -o libimported.dylib imported.c
+ # According to "Mac OS X For Unix Geeks", 4th Edition, Chapter 11, versioned dylib for macOS
+ # should be libversioned.2.dylib.
+ cc -shared -Wl,-install_name,@rpath/libversioned.2.dylib -o libversioned.2.dylib imported.c
+ # However, Oracle Instant Client was distributed as libclntsh.dylib.12.1 with a unversioed
+ # symlink (https://www.oracle.com/database/technologies/instant-client/macos-intel-x86-downloads.html).
+ # Let's cover this non-standard case as well.
+ cc -shared -Wl,-install_name,@rpath/libversioned.dylib.2 -o libversioned.dylib.2 imported.c
+ ln -fs libversioned.dylib.2 libversioned.dylib
+ ;;
+ *)
+ echo "Unsupported OS: $(uname -s)" >&2
+ exit 1
+esac
diff --git a/tests/core/cgo/imported.c b/tests/core/cgo/imported.c
new file mode 100644
index 00000000..bf7759e1
--- /dev/null
+++ b/tests/core/cgo/imported.c
@@ -0,0 +1 @@
+int foo() { return 42; }
diff --git a/tests/core/cgo/native_dep.c b/tests/core/cgo/native_dep.c
new file mode 100644
index 00000000..f6504a85
--- /dev/null
+++ b/tests/core/cgo/native_dep.c
@@ -0,0 +1,5 @@
+#include <stdio.h>
+
+void native_greeting(void) {
+ printf("Hello, world!\n");
+}
diff --git a/tests/core/cgo/native_dep.h b/tests/core/cgo/native_dep.h
new file mode 100644
index 00000000..5d750beb
--- /dev/null
+++ b/tests/core/cgo/native_dep.h
@@ -0,0 +1 @@
+extern void native_greeting(void);
diff --git a/tests/core/cgo/objc/BUILD.bazel b/tests/core/cgo/objc/BUILD.bazel
new file mode 100644
index 00000000..030408f1
--- /dev/null
+++ b/tests/core/cgo/objc/BUILD.bazel
@@ -0,0 +1,32 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_test(
+ name = "objc_test",
+ srcs = ["objc_darwin_test.go"],
+ embed = select({
+ "@io_bazel_rules_go//go/platform:darwin": [":objc_lib"],
+ "//conditions:default": [],
+ }),
+)
+
+go_library(
+ name = "objc_lib",
+ srcs = [
+ "add_darwin.go",
+ "add_darwin.h",
+ "add_darwin.m",
+ "sub_darwin.go",
+ ],
+ cdeps = [":sub"],
+ cgo = True,
+ copts = ["-fmodules"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cgo/objc",
+ tags = ["manual"],
+)
+
+objc_library(
+ name = "sub",
+ srcs = ["sub.m"],
+ enable_modules = True,
+ tags = ["manual"],
+)
diff --git a/tests/core/cgo/objc/README.rst b/tests/core/cgo/objc/README.rst
new file mode 100644
index 00000000..86faa182
--- /dev/null
+++ b/tests/core/cgo/objc/README.rst
@@ -0,0 +1,8 @@
+Objective C / cgo functionality
+===============================
+
+objc_test
+---------
+
+Checks that a Go target with Objective C code (both embedded and in an
+``objc_library`` ``cdeps`` dependency) compiles, links, and executes.
diff --git a/tests/core/cgo/objc/add_darwin.go b/tests/core/cgo/objc/add_darwin.go
new file mode 100644
index 00000000..76bdaf97
--- /dev/null
+++ b/tests/core/cgo/objc/add_darwin.go
@@ -0,0 +1,10 @@
+package objc
+
+/*
+#include "add_darwin.h"
+*/
+import "C"
+
+func Add(a, b int32) int32 {
+ return int32(C.add(C.int(a), C.int(b)))
+}
diff --git a/tests/core/cgo/objc/add_darwin.h b/tests/core/cgo/objc/add_darwin.h
new file mode 100644
index 00000000..6295ab95
--- /dev/null
+++ b/tests/core/cgo/objc/add_darwin.h
@@ -0,0 +1 @@
+int add(int a, int b);
diff --git a/tests/core/cgo/objc/add_darwin.m b/tests/core/cgo/objc/add_darwin.m
new file mode 100644
index 00000000..ffd02430
--- /dev/null
+++ b/tests/core/cgo/objc/add_darwin.m
@@ -0,0 +1,22 @@
+@import Foundation;
+
+#include "add_darwin.h"
+
+@interface Adder : NSObject
+
+- (int)add:(int)num1 andNum2:(int)num2;
+
+@end
+
+@implementation Adder
+
+- (int)add:(int)num1 andNum2:(int)num2{
+ return num1 + num2;
+}
+
+@end
+
+int add(int a, int b) {
+ Adder* adder = [[Adder alloc] init];
+ return [adder add:a andNum2:b];
+}
diff --git a/tests/core/cgo/objc/objc_darwin_test.go b/tests/core/cgo/objc/objc_darwin_test.go
new file mode 100644
index 00000000..5d475b4d
--- /dev/null
+++ b/tests/core/cgo/objc/objc_darwin_test.go
@@ -0,0 +1,16 @@
+package objc
+
+import (
+ "fmt"
+ "math/rand"
+ "testing"
+)
+
+func TestObjcMethod(t *testing.T) {
+ a := rand.Int31()
+ b := rand.Int31()
+ expected := a + b
+ if result := Add(a, b); result != expected {
+ t.Error(fmt.Errorf("wrong result: expected %d, got %d", expected, result))
+ }
+}
diff --git a/tests/core/cgo/objc/sub.m b/tests/core/cgo/objc/sub.m
new file mode 100644
index 00000000..3b408ea8
--- /dev/null
+++ b/tests/core/cgo/objc/sub.m
@@ -0,0 +1,20 @@
+@import Foundation;
+
+@interface Subber : NSObject
+
+- (int)sub:(int)num1 andNum2:(int)num2;
+
+@end
+
+@implementation Subber
+
+- (int)sub:(int)num1 andNum2:(int)num2{
+ return num1 - num2;
+}
+
+@end
+
+int sub(int a, int b) {
+ Subber* subber = [[Subber alloc] init];
+ return [subber sub:a andNum2:b];
+}
diff --git a/tests/core/cgo/objc/sub_darwin.go b/tests/core/cgo/objc/sub_darwin.go
new file mode 100644
index 00000000..5b780307
--- /dev/null
+++ b/tests/core/cgo/objc/sub_darwin.go
@@ -0,0 +1,10 @@
+package objc
+
+/*
+int sub(int a, int b);
+*/
+import "C"
+
+func Sub(a, b int32) int32 {
+ return int32(C.sub(C.int(a), C.int(b)))
+}
diff --git a/tests/core/cgo/provide_external_symbol.go b/tests/core/cgo/provide_external_symbol.go
new file mode 100644
index 00000000..68d9fce1
--- /dev/null
+++ b/tests/core/cgo/provide_external_symbol.go
@@ -0,0 +1,12 @@
+package main
+
+import "C"
+
+import "github.com/bazelbuild/rules_go/tests/core/cgo/use_external_symbol"
+
+//export external_symbol
+func external_symbol() {}
+
+func main() {
+ use_external_symbol.UseExternalSymbol()
+}
diff --git a/tests/core/cgo/pure.go b/tests/core/cgo/pure.go
new file mode 100644
index 00000000..38dd16da
--- /dev/null
+++ b/tests/core/cgo/pure.go
@@ -0,0 +1,3 @@
+package main
+
+func main() {}
diff --git a/tests/core/cgo/race_off.c b/tests/core/cgo/race_off.c
new file mode 100644
index 00000000..f752c63c
--- /dev/null
+++ b/tests/core/cgo/race_off.c
@@ -0,0 +1,3 @@
+// +build !race
+
+int race_enabled = 0;
diff --git a/tests/core/cgo/race_off.go b/tests/core/cgo/race_off.go
new file mode 100644
index 00000000..b572268e
--- /dev/null
+++ b/tests/core/cgo/race_off.go
@@ -0,0 +1,5 @@
+// +build !race
+
+package race
+
+const goRaceEnabled = false
diff --git a/tests/core/cgo/race_on.c b/tests/core/cgo/race_on.c
new file mode 100644
index 00000000..9b79ea31
--- /dev/null
+++ b/tests/core/cgo/race_on.c
@@ -0,0 +1,3 @@
+// +build race
+
+int race_enabled = 1;
diff --git a/tests/core/cgo/race_on.go b/tests/core/cgo/race_on.go
new file mode 100644
index 00000000..7f172dc5
--- /dev/null
+++ b/tests/core/cgo/race_on.go
@@ -0,0 +1,5 @@
+// +build race
+
+package race
+
+const goRaceEnabled = true
diff --git a/tests/core/cgo/race_test.go b/tests/core/cgo/race_test.go
new file mode 100644
index 00000000..c9344bac
--- /dev/null
+++ b/tests/core/cgo/race_test.go
@@ -0,0 +1,31 @@
+// Copyright 2018 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.
+
+package race
+
+// extern int race_enabled;
+import "C"
+import "testing"
+
+func TestGo(t *testing.T) {
+ if !goRaceEnabled {
+ t.Error("goRaceEnabled is false")
+ }
+}
+
+func TestC(t *testing.T) {
+ if C.race_enabled == 0 {
+ t.Error("C.race_enabled is false")
+ }
+}
diff --git a/tests/core/cgo/split_import_a.go b/tests/core/cgo/split_import_a.go
new file mode 100644
index 00000000..4b0e38a1
--- /dev/null
+++ b/tests/core/cgo/split_import_a.go
@@ -0,0 +1,3 @@
+package a
+
+func Answer() int { return 42 }
diff --git a/tests/core/cgo/split_import_b.go b/tests/core/cgo/split_import_b.go
new file mode 100644
index 00000000..2d8410fa
--- /dev/null
+++ b/tests/core/cgo/split_import_b.go
@@ -0,0 +1,10 @@
+package b
+
+import (
+ "github.com/bazelbuild/rules_go/tests/core/cgo/split_import/a"
+ "github.com/bazelbuild/rules_go/tests/core/cgo/split_import/cgo"
+)
+
+func HalfAnswer() int {
+ return cgo.Half(a.Answer())
+}
diff --git a/tests/core/cgo/split_import_c.c b/tests/core/cgo/split_import_c.c
new file mode 100644
index 00000000..b20e936e
--- /dev/null
+++ b/tests/core/cgo/split_import_c.c
@@ -0,0 +1,2 @@
+int half(int x) { return x/2; }
+
diff --git a/tests/core/cgo/split_import_c.h b/tests/core/cgo/split_import_c.h
new file mode 100644
index 00000000..35731ef1
--- /dev/null
+++ b/tests/core/cgo/split_import_c.h
@@ -0,0 +1,6 @@
+#ifndef split_import_c
+#define split_import_c
+
+int half(int);
+
+#endif
diff --git a/tests/core/cgo/split_import_cgo.go b/tests/core/cgo/split_import_cgo.go
new file mode 100644
index 00000000..b15bc16f
--- /dev/null
+++ b/tests/core/cgo/split_import_cgo.go
@@ -0,0 +1,10 @@
+package cgo
+
+/*
+#include "tests/core/cgo/split_import_c.h"
+*/
+import "C"
+
+func Half(x int) int {
+ return int(C.half(C.int(x)))
+}
diff --git a/tests/core/cgo/split_import_i_test.go b/tests/core/cgo/split_import_i_test.go
new file mode 100644
index 00000000..77429eff
--- /dev/null
+++ b/tests/core/cgo/split_import_i_test.go
@@ -0,0 +1,9 @@
+package a
+
+import "testing"
+
+func TestInternal(t *testing.T) {
+ if Answer() != 42 {
+ t.Error("wrong answer")
+ }
+}
diff --git a/tests/core/cgo/split_import_x_test.go b/tests/core/cgo/split_import_x_test.go
new file mode 100644
index 00000000..9202eaad
--- /dev/null
+++ b/tests/core/cgo/split_import_x_test.go
@@ -0,0 +1,13 @@
+package a_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/tests/core/cgo/split_import/b"
+)
+
+func TestExternal(t *testing.T) {
+ if b.HalfAnswer() != 21 {
+ t.Error("wrong answer")
+ }
+}
diff --git a/tests/core/cgo/tag_cgo.go b/tests/core/cgo/tag_cgo.go
new file mode 100644
index 00000000..e8185f85
--- /dev/null
+++ b/tests/core/cgo/tag_cgo.go
@@ -0,0 +1,10 @@
+package main
+
+// const char *msg = "cgo";
+import "C"
+
+import "fmt"
+
+func main() {
+ fmt.Println(C.GoString(C.msg))
+}
diff --git a/tests/core/cgo/tag_cgo_err.go b/tests/core/cgo/tag_cgo_err.go
new file mode 100644
index 00000000..4e3a9fa4
--- /dev/null
+++ b/tests/core/cgo/tag_cgo_err.go
@@ -0,0 +1,6 @@
+// +build !cgo
+
+package main
+
+// this file should not be compiled
+!!!
diff --git a/tests/core/cgo/tag_pure.go b/tests/core/cgo/tag_pure.go
new file mode 100644
index 00000000..eca8e6fd
--- /dev/null
+++ b/tests/core/cgo/tag_pure.go
@@ -0,0 +1,9 @@
+// +build !cgo
+
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("pure")
+}
diff --git a/tests/core/cgo/tag_pure_err.c b/tests/core/cgo/tag_pure_err.c
new file mode 100644
index 00000000..c92fa97c
--- /dev/null
+++ b/tests/core/cgo/tag_pure_err.c
@@ -0,0 +1 @@
+#error should not be compiled
diff --git a/tests/core/cgo/tag_pure_err.go b/tests/core/cgo/tag_pure_err.go
new file mode 100644
index 00000000..32b6e953
--- /dev/null
+++ b/tests/core/cgo/tag_pure_err.go
@@ -0,0 +1,6 @@
+// +build cgo
+
+package main
+
+// this file should not be compiled
+!!!
diff --git a/tests/core/cgo/tag_test.go b/tests/core/cgo/tag_test.go
new file mode 100644
index 00000000..b1ad4c99
--- /dev/null
+++ b/tests/core/cgo/tag_test.go
@@ -0,0 +1,38 @@
+package tag
+
+import (
+ "os/exec"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel"
+)
+
+func Test(t *testing.T) {
+ for _, tc := range []struct {
+ name, path, want string
+ }{
+ {
+ name: "tag_pure_bin",
+ want: "pure",
+ }, {
+ name: "tag_cgo_bin",
+ want: "cgo",
+ },
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ path, ok := bazel.FindBinary("tests/core/cgo", tc.name)
+ if !ok {
+ t.Fatalf("could not find binary: %s", tc.name)
+ }
+ out, err := exec.Command(path).Output()
+ if err != nil {
+ t.Fatal(err)
+ }
+ got := strings.TrimSpace(string(out))
+ if got != tc.want {
+ t.Errorf("got %s; want %s", got, tc.want)
+ }
+ })
+ }
+}
diff --git a/tests/core/cgo/transitive_dep.go b/tests/core/cgo/transitive_dep.go
new file mode 100644
index 00000000..40632f50
--- /dev/null
+++ b/tests/core/cgo/transitive_dep.go
@@ -0,0 +1,10 @@
+package transitive_dep
+
+/*
+#include "tests/core/cgo/native_dep.h"
+ */
+import "C"
+
+func PrintGreeting() {
+ C.native_greeting();
+}
diff --git a/tests/core/cgo/use_c_symbol_through_go.c b/tests/core/cgo/use_c_symbol_through_go.c
new file mode 100644
index 00000000..bd5b7fec
--- /dev/null
+++ b/tests/core/cgo/use_c_symbol_through_go.c
@@ -0,0 +1,5 @@
+#include "tests/core/cgo/use_transitive_symbol.h"
+
+int main() {
+ PrintGreeting();
+}
diff --git a/tests/core/cgo/use_external_symbol.go b/tests/core/cgo/use_external_symbol.go
new file mode 100644
index 00000000..70980ea7
--- /dev/null
+++ b/tests/core/cgo/use_external_symbol.go
@@ -0,0 +1,10 @@
+package use_external_symbol
+
+/*
+void external_symbol();
+*/
+import "C"
+
+func UseExternalSymbol() {
+ C.external_symbol()
+}
diff --git a/tests/core/cgo/use_transitive_symbol.go b/tests/core/cgo/use_transitive_symbol.go
new file mode 100644
index 00000000..c229311e
--- /dev/null
+++ b/tests/core/cgo/use_transitive_symbol.go
@@ -0,0 +1,14 @@
+package main
+
+import "C"
+
+import (
+ "github.com/bazelbuild/rules_go/tests/core/cgo/direct_dep"
+)
+
+//export PrintGreeting
+func PrintGreeting() {
+ direct_dep.PrintGreeting()
+}
+
+func main() {}
diff --git a/tests/core/coverage/BUILD.bazel b/tests/core/coverage/BUILD.bazel
new file mode 100644
index 00000000..9a20440f
--- /dev/null
+++ b/tests/core/coverage/BUILD.bazel
@@ -0,0 +1,34 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "coverage_test",
+ srcs = ["coverage_test.go"],
+)
+
+go_bazel_test(
+ name = "binary_coverage_test",
+ srcs = ["binary_coverage_test.go"],
+)
+
+go_bazel_test(
+ name = "lcov_coverage_test",
+ srcs = ["lcov_coverage_test.go"],
+ target_compatible_with = select({
+ "@platforms//os:windows": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ }),
+)
+
+go_bazel_test(
+ name = "lcov_test_main_coverage_test",
+ srcs = ["lcov_test_main_coverage_test.go"],
+ target_compatible_with = select({
+ "@platforms//os:windows": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ }),
+)
+
+go_bazel_test(
+ name = "issue3017_test",
+ srcs = ["issue3017_test.go"],
+)
diff --git a/tests/core/coverage/README.rst b/tests/core/coverage/README.rst
new file mode 100644
index 00000000..aadc5fa9
--- /dev/null
+++ b/tests/core/coverage/README.rst
@@ -0,0 +1,23 @@
+.. _#2127: https://github.com/bazelbuild/rules_go/issues/2127
+
+coverage functionality
+======================
+
+coverage_test
+-------------
+
+Checks that ``bazel coverage`` on a ``go_test`` produces reasonable output.
+Libraries referenced by the test that pass ``--instrumentation_filter`` should
+have coverage data. Library excluded with ``--instrumentatiuon_filter`` should
+not have coverage data.
+
+binary_coverage_test
+--------------------
+
+Checks that ``bazel build --collect_code_coverage`` can instrument a
+``go_binary``. ``bazel coverage`` should also work, though it should fail
+with status 4 since the binary is not a test.
+
+This functionality isn't really complete. The generate test main package
+gathers and writes coverage data, and that's not present. This is just
+a regression test for a link error (`#2127`_).
diff --git a/tests/core/coverage/binary_coverage_test.go b/tests/core/coverage/binary_coverage_test.go
new file mode 100644
index 00000000..724528be
--- /dev/null
+++ b/tests/core/coverage/binary_coverage_test.go
@@ -0,0 +1,75 @@
+// Copyright 2019 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.
+
+package binary_coverage_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary")
+
+go_binary(
+ name = "hello",
+ srcs = ["hello.go"],
+ out = "hello",
+)
+-- hello.go --
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Println(A())
+}
+
+func A() int { return 12 }
+
+func B() int { return 34 }
+`,
+ })
+}
+
+func Test(t *testing.T) {
+ // Check that we can build a binary with coverage instrumentation enabled.
+ args := []string{
+ "build",
+ "--collect_code_coverage",
+ "--instrumentation_filter=.*",
+ "//:hello",
+ }
+ if err := bazel_testing.RunBazel(args...); err != nil {
+ t.Fatal(err)
+ }
+
+ // Check that we can build with `bazel coverage`. It will fail because
+ // there are no tests.
+ args = []string{
+ "coverage",
+ "//:hello",
+ }
+ if err := bazel_testing.RunBazel(args...); err == nil {
+ t.Fatal("got success; want failure")
+ } else if bErr, ok := err.(*bazel_testing.StderrExitError); !ok {
+ t.Fatalf("got %v; want StderrExitError", err)
+ } else if code := bErr.Err.ExitCode(); code != 4 {
+ t.Fatalf("got code %d; want code 4 (no tests found)", code)
+ }
+}
diff --git a/tests/core/coverage/coverage_test.go b/tests/core/coverage/coverage_test.go
new file mode 100644
index 00000000..52bda780
--- /dev/null
+++ b/tests/core/coverage/coverage_test.go
@@ -0,0 +1,265 @@
+// Copyright 2019 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.
+
+package coverage_test
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "path/filepath"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_test(
+ name = "a_test",
+ srcs = ["a_test.go"],
+ embed = [":a"],
+)
+
+go_test(
+ name = "a_test_cross",
+ srcs = ["a_test.go"],
+ embed = [":a"],
+ goarch = "386",
+ goos = "linux",
+ pure = "on",
+ tags = ["manual"],
+)
+
+go_library(
+ name = "a",
+ srcs = ["a.go"],
+ importpath = "example.com/coverage/a",
+ deps = [":b"],
+)
+
+go_library(
+ name = "b",
+ srcs = ["b.go"],
+ importpath = "example.com/coverage/b",
+ deps = [":c"],
+)
+
+go_library(
+ name = "c",
+ srcs = ["c.go"],
+ importpath = "example.com/coverage/c",
+)
+
+go_library(
+ name = "d",
+ srcs = ["d.go"],
+ importpath = "example.com/coverage/d",
+)
+
+go_test(
+ name = "d_test",
+ embed = [":d"],
+)
+
+go_library(
+ name = "panicking",
+ srcs = ["panicking.go"],
+ importpath = "example.com/coverage/panicking",
+)
+
+go_test(
+ name = "panicking_test",
+ srcs = ["panicking_test.go"],
+ embed = [":panicking"],
+)
+-- a_test.go --
+package a
+
+import "testing"
+
+func TestA(t *testing.T) {
+ ALive()
+}
+-- a.go --
+package a
+
+import "example.com/coverage/b"
+
+func ALive() int {
+ return b.BLive()
+}
+
+func ADead() int {
+ return b.BDead()
+}
+
+-- b.go --
+package b
+
+import "example.com/coverage/c"
+
+func BLive() int {
+ return c.CLive()
+}
+
+func BDead() int {
+ return c.CDead()
+}
+
+-- c.go --
+package c
+
+func CLive() int {
+ return 12
+}
+
+func CDead() int {
+ return 34
+}
+
+-- d.go --
+package lzma
+
+/* Naming conventions follows the CodeReviewComments in the Go Wiki. */
+
+// ntz32Const is used by the functions NTZ and NLZ.
+const ntz32Const = 0x04d7651f
+-- panicking.go --
+package panicking
+
+func Panic() {
+ panic("from line 4")
+}
+-- panicking_test.go --
+package panicking
+
+import (
+ "regexp"
+ "runtime/debug"
+ "testing"
+)
+
+func TestPanic(t *testing.T) {
+ defer func() {
+ if err := recover(); err != nil {
+ got := regexp.MustCompile("panicking.go:[0-9]+").
+ FindString(string(debug.Stack()))
+ if want := "panicking.go:4"; want != got {
+ t.Errorf("want %q; got %q", want, got)
+ }
+ }
+ }()
+ Panic()
+}
+`,
+ })
+}
+
+func TestCoverage(t *testing.T) {
+ t.Run("without-race", func(t *testing.T) {
+ testCoverage(t, "set")
+ })
+
+ t.Run("with-race", func(t *testing.T) {
+ testCoverage(t, "atomic", "--@io_bazel_rules_go//go/config:race")
+ })
+}
+
+func testCoverage(t *testing.T, expectedCoverMode string, extraArgs ...string) {
+ args := append([]string{"coverage"}, append(
+ extraArgs,
+ "--instrumentation_filter=-//:b",
+ "--@io_bazel_rules_go//go/config:cover_format=go_cover",
+ ":a_test",
+ )...)
+
+ if err := bazel_testing.RunBazel(args...); err != nil {
+ t.Fatal(err)
+ }
+
+ coveragePath := filepath.FromSlash("bazel-testlogs/a_test/coverage.dat")
+ coverageData, err := ioutil.ReadFile(coveragePath)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, include := range []string{
+ fmt.Sprintf("mode: %s", expectedCoverMode),
+ "example.com/coverage/a/a.go:",
+ "example.com/coverage/c/c.go:",
+ } {
+ if !bytes.Contains(coverageData, []byte(include)) {
+ t.Errorf("%s: does not contain %q\n", coveragePath, include)
+ }
+ }
+ for _, exclude := range []string{
+ "example.com/coverage/b/b.go:",
+ } {
+ if bytes.Contains(coverageData, []byte(exclude)) {
+ t.Errorf("%s: contains %q\n", coveragePath, exclude)
+ }
+ }
+}
+
+func TestCrossBuild(t *testing.T) {
+ t.Run("lcov", func(t *testing.T) {
+ testCrossBuild(t)
+ })
+ t.Run("cover", func(t *testing.T) {
+ testCrossBuild(t, "--@io_bazel_rules_go//go/config:cover_format=go_cover")
+ })
+}
+
+func testCrossBuild(t *testing.T, extraArgs ...string) {
+ if err := bazel_testing.RunBazel(append(
+ []string{"build", "--collect_code_coverage", "--instrumentation_filter=-//:b", "//:a_test_cross"},
+ extraArgs...,
+ )...); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestCoverageWithComments(t *testing.T) {
+ t.Run("lcov", func(t *testing.T) {
+ testCoverageWithComments(t)
+ })
+ t.Run("go_cover", func(t *testing.T) {
+ testCoverageWithComments(t, "--@io_bazel_rules_go//go/config:cover_format=go_cover")
+ })
+}
+
+func testCoverageWithComments(t *testing.T, extraArgs ...string) {
+ if err := bazel_testing.RunBazel(append([]string{"coverage", ":d_test"}, extraArgs...)...); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestCoverageWithCorrectLineNumbers(t *testing.T) {
+ t.Run("lcov", func(t *testing.T) {
+ testCoverageWithCorrectLineNumbers(t)
+ })
+ t.Run("go_cover", func(t *testing.T) {
+ testCoverageWithCorrectLineNumbers(t, "--@io_bazel_rules_go//go/config:cover_format=go_cover")
+ })
+}
+
+func testCoverageWithCorrectLineNumbers(t *testing.T, extraArgs ...string) {
+ if err := bazel_testing.RunBazel(append([]string{"coverage", ":panicking_test"}, extraArgs...)...); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/tests/core/coverage/issue3017_test.go b/tests/core/coverage/issue3017_test.go
new file mode 100644
index 00000000..e2786e1f
--- /dev/null
+++ b/tests/core/coverage/issue3017_test.go
@@ -0,0 +1,80 @@
+// Copyright 2019 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.
+
+package coverage_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- fx.go --
+package fx
+
+import (
+ _ "uber.com/internal"
+)
+-- fx_test.go --
+package fx
+-- internal/BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["lib.go"],
+ importpath = "uber.com/internal",
+ visibility = ["//visibility:public"],
+ deps = ["@io_bazel_rules_go//go/tools/coverdata"],
+)
+
+go_test(
+ name = "go_default_test",
+ srcs = ["lib_test.go"],
+ embed = [":go_default_library"],
+)
+-- internal/lib.go --
+package internal
+
+import _ "github.com/bazelbuild/rules_go/go/tools/coverdata"
+-- internal/lib_test.go --
+package internal
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["fx.go"],
+ importpath = "code.uber.internal/devexp/code-coverage/cmd/fx",
+ visibility = ["//visibility:private"],
+ deps = ["//internal:go_default_library"],
+)
+
+go_test(
+ name = "go_default_test",
+ srcs = ["fx_test.go"],
+ embed = [":go_default_library"],
+)
+`,
+ })
+}
+
+func TestIssue3017(t *testing.T) {
+ if err := bazel_testing.RunBazel("coverage", "//:go_default_test"); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/tests/core/coverage/lcov_coverage_test.go b/tests/core/coverage/lcov_coverage_test.go
new file mode 100644
index 00000000..a46567cc
--- /dev/null
+++ b/tests/core/coverage/lcov_coverage_test.go
@@ -0,0 +1,290 @@
+// Copyright 2022 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.
+
+package lcov_coverage_test
+
+import (
+ "io/ioutil"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- src/BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_library(
+ name = "lib",
+ srcs = ["lib.go"],
+ importpath = "example.com/lib",
+ deps = [":other_lib"],
+)
+
+go_library(
+ name = "other_lib",
+ srcs = ["other_lib.go"],
+ importpath = "example.com/other_lib",
+)
+
+go_test(
+ name = "lib_test",
+ srcs = ["lib_test.go"],
+ deps = [":lib"],
+)
+
+java_binary(
+ name = "Tool",
+ srcs = ["Tool.java"],
+)
+
+go_test(
+ name = "lib_with_tool_test",
+ srcs = ["lib_with_tool_test.go"],
+ data = [":Tool"],
+ deps = [":lib"],
+)
+-- src/lib.go --
+package lib
+
+import (
+ "strings"
+
+ "example.com/other_lib"
+)
+
+func HelloFromLib(informal bool) string {
+ var greetings []string
+ if informal {
+ greetings = []string{"Hey there, other_lib!"}
+ } else {
+ greetings = []string{"Good morning, other_lib!"}
+ }
+ greetings = append(greetings, other_lib.HelloOtherLib(informal))
+ return strings.Join(greetings, "\n")
+}
+-- src/other_lib.go --
+package other_lib
+
+func HelloOtherLib(informal bool) string {
+ if informal {
+ return "Hey there, other_lib!"
+ }
+ return "Good morning, other_lib!"
+}
+-- src/lib_test.go --
+package lib_test
+
+import (
+ "strings"
+ "testing"
+
+ "example.com/lib"
+)
+
+func TestLib(t *testing.T) {
+ if !strings.Contains(lib.HelloFromLib(false), "\n") {
+ t.Error("Expected a newline in the output")
+ }
+}
+-- src/Tool.java --
+public class Tool {
+ public static void main(String[] args) {
+ if (args.length != 0) {
+ System.err.println("Expected no arguments");
+ System.exit(1);
+ }
+ System.err.println("Hello, world!");
+ }
+}
+-- src/lib_with_tool_test.go --
+package lib_test
+
+import (
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "example.com/lib"
+)
+
+func TestLib(t *testing.T) {
+ if !strings.Contains(lib.HelloFromLib(false), "\n") {
+ t.Error("Expected a newline in the output")
+ }
+}
+
+func TestTool(t *testing.T) {
+ err := exec.Command("." + string(filepath.Separator) + "Tool").Run()
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+`,
+ })
+}
+
+func TestLcovCoverage(t *testing.T) {
+ t.Run("without-race", func(t *testing.T) {
+ testLcovCoverage(t)
+ })
+
+ t.Run("with-race", func(t *testing.T) {
+ testLcovCoverage(t, "--@io_bazel_rules_go//go/config:race")
+ })
+}
+
+func testLcovCoverage(t *testing.T, extraArgs ...string) {
+ args := append([]string{
+ "coverage",
+ "--combined_report=lcov",
+ "//src:lib_test",
+ }, extraArgs...)
+
+ if err := bazel_testing.RunBazel(args...); err != nil {
+ t.Fatal(err)
+ }
+
+ individualCoveragePath := filepath.FromSlash("bazel-testlogs/src/lib_test/coverage.dat")
+ individualCoverageData, err := ioutil.ReadFile(individualCoveragePath)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, expectedIndividualCoverage := range expectedGoCoverage {
+ if !strings.Contains(string(individualCoverageData), expectedIndividualCoverage) {
+ t.Errorf(
+ "%s: does not contain:\n\n%s\nactual content:\n\n%s",
+ individualCoveragePath,
+ expectedIndividualCoverage,
+ string(individualCoverageData),
+ )
+ }
+ }
+
+ combinedCoveragePath := filepath.FromSlash("bazel-out/_coverage/_coverage_report.dat")
+ combinedCoverageData, err := ioutil.ReadFile(combinedCoveragePath)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, include := range []string{
+ "SF:src/lib.go\n",
+ "SF:src/other_lib.go\n",
+ } {
+ if !strings.Contains(string(combinedCoverageData), include) {
+ t.Errorf("%s: does not contain %q\n", combinedCoverageData, include)
+ }
+ }
+}
+
+func TestLcovCoverageWithTool(t *testing.T) {
+ args := append([]string{
+ "coverage",
+ "--combined_report=lcov",
+ "//src:lib_with_tool_test",
+ })
+
+ if err := bazel_testing.RunBazel(args...); err != nil {
+ t.Fatal(err)
+ }
+
+ individualCoveragePath := filepath.FromSlash("bazel-testlogs/src/lib_with_tool_test/coverage.dat")
+ individualCoverageData, err := ioutil.ReadFile(individualCoveragePath)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expectedCoverage := append(expectedGoCoverage, expectedToolCoverage)
+ for _, expected := range expectedCoverage {
+ if !strings.Contains(string(individualCoverageData), expected) {
+ t.Errorf(
+ "%s: does not contain:\n\n%s\nactual content:\n\n%s",
+ individualCoveragePath,
+ expected,
+ string(individualCoverageData),
+ )
+ }
+ }
+
+ combinedCoveragePath := filepath.FromSlash("bazel-out/_coverage/_coverage_report.dat")
+ combinedCoverageData, err := ioutil.ReadFile(combinedCoveragePath)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, include := range []string{
+ "SF:src/lib.go\n",
+ "SF:src/other_lib.go\n",
+ "SF:src/Tool.java\n",
+ } {
+ if !strings.Contains(string(combinedCoverageData), include) {
+ t.Errorf("%s: does not contain %q\n", combinedCoverageData, include)
+ }
+ }
+}
+
+var expectedGoCoverage = []string{
+ `SF:src/other_lib.go
+FNF:0
+FNH:0
+DA:3,1
+DA:4,1
+DA:5,0
+DA:6,0
+DA:7,1
+LH:3
+LF:5
+end_of_record
+`,
+ `SF:src/lib.go
+FNF:0
+FNH:0
+DA:9,1
+DA:10,1
+DA:11,1
+DA:12,0
+DA:13,1
+DA:14,1
+DA:15,1
+DA:16,1
+DA:17,1
+LH:8
+LF:9
+end_of_record
+`}
+
+const expectedToolCoverage = `SF:src/Tool.java
+FN:1,Tool::<init> ()V
+FN:3,Tool::main ([Ljava/lang/String;)V
+FNDA:0,Tool::<init> ()V
+FNDA:1,Tool::main ([Ljava/lang/String;)V
+FNF:2
+FNH:1
+BRDA:3,0,0,1
+BRDA:3,0,1,0
+BRF:2
+BRH:1
+DA:1,0
+DA:3,1
+DA:4,0
+DA:5,0
+DA:7,1
+DA:8,1
+LH:3
+LF:6
+end_of_record
+`
diff --git a/tests/core/coverage/lcov_test_main_coverage_test.go b/tests/core/coverage/lcov_test_main_coverage_test.go
new file mode 100644
index 00000000..57aafd28
--- /dev/null
+++ b/tests/core/coverage/lcov_test_main_coverage_test.go
@@ -0,0 +1,122 @@
+// Copyright 2022 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.
+
+package lcov_test_main_coverage_test
+
+import (
+ "io/ioutil"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- src/BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_library(
+ name = "lib",
+ srcs = ["lib.go"],
+ importpath = "example.com/lib",
+)
+
+go_test(
+ name = "lib_test",
+ srcs = ["lib_test.go"],
+ deps = [":lib"],
+)
+-- src/lib.go --
+package lib
+
+func HelloFromLib(informal bool) string {
+ if informal {
+ return "Hey there, lib!"
+ } else {
+ return "Good morning, lib!"
+ }
+}
+-- src/lib_test.go --
+package lib_test
+
+import (
+ "strings"
+ "testing"
+ "os"
+
+ "example.com/lib"
+)
+
+func TestMain(m *testing.M) {
+ os.Exit(m.Run())
+}
+
+func TestLib(t *testing.T) {
+ if !strings.Contains(lib.HelloFromLib(false), "lib!") {
+ t.Error("Expected 'lib!' in the output")
+ }
+}
+`,
+ })
+}
+
+func TestLcovCoverageWithTestMain(t *testing.T) {
+ if err := bazel_testing.RunBazel("coverage", "--combined_report=lcov", "//src:lib_test"); err != nil {
+ t.Fatal(err)
+ }
+
+ individualCoveragePath := filepath.FromSlash("bazel-testlogs/src/lib_test/coverage.dat")
+ individualCoverageData, err := ioutil.ReadFile(individualCoveragePath)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(individualCoverageData) != string(expectedIndividualCoverage) {
+ t.Errorf(
+ "%s: expected content:\n\n%s\nactual content:\n\n%s",
+ individualCoveragePath,
+ expectedIndividualCoverage,
+ string(individualCoverageData),
+ )
+ }
+
+ combinedCoveragePath := filepath.FromSlash("bazel-out/_coverage/_coverage_report.dat")
+ combinedCoverageData, err := ioutil.ReadFile(combinedCoveragePath)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, include := range []string{
+ "SF:src/lib.go\n",
+ } {
+ if !strings.Contains(string(combinedCoverageData), include) {
+ t.Errorf("%s: does not contain %q\n", combinedCoverageData, include)
+ }
+ }
+}
+
+const expectedIndividualCoverage = `SF:src/lib.go
+FNF:0
+FNH:0
+DA:3,1
+DA:4,1
+DA:5,0
+DA:6,1
+DA:7,1
+DA:8,1
+LH:5
+LF:6
+end_of_record
+`
diff --git a/tests/core/cross/BUILD.bazel b/tests/core/cross/BUILD.bazel
new file mode 100644
index 00000000..ec179984
--- /dev/null
+++ b/tests/core/cross/BUILD.bazel
@@ -0,0 +1,143 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_cross_binary", "go_library", "go_test")
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+load(":def.bzl", "no_context_info")
+
+test_suite(
+ name = "cross",
+)
+
+go_binary(
+ name = "windows_cross",
+ srcs = ["main.go"],
+ goarch = "amd64",
+ goos = "windows",
+ pure = "on",
+ deps = [":platform_lib"],
+)
+
+go_binary(
+ name = "linux_cross",
+ srcs = ["main.go"],
+ goarch = "amd64",
+ goos = "linux",
+ pure = "on",
+ deps = [":platform_lib"],
+)
+
+go_binary(
+ name = "darwin_cross",
+ srcs = ["main.go"],
+ goarch = "amd64",
+ goos = "darwin",
+ pure = "on",
+ deps = [":platform_lib"],
+)
+
+go_binary(
+ name = "asm_cross",
+ srcs = ["asm.s", "main.go"],
+ goarch = "386",
+ goos = "linux",
+ deps = [":platform_lib"],
+)
+
+go_binary(
+ name = "native_bin",
+ srcs = ["main.go"],
+ pure = "on",
+ deps = [":platform_lib"],
+)
+
+go_cross_binary(
+ name = "windows_go_cross",
+ platform = "@io_bazel_rules_go//go/toolchain:windows_amd64",
+ target = ":native_bin",
+)
+
+go_cross_binary(
+ name = "linux_go_cross",
+ platform = "@io_bazel_rules_go//go/toolchain:linux_amd64",
+ target = ":native_bin",
+)
+
+go_cross_binary(
+ name = "darwin_go_cross",
+ platform = "@io_bazel_rules_go//go/toolchain:darwin_amd64",
+ target = ":native_bin",
+)
+
+go_library(
+ name = "platform_lib",
+ srcs = select({
+ "//go/platform:darwin": ["lib_darwin.go"],
+ "//go/platform:linux": ["lib_linux.go"],
+ "//go/platform:windows": ["lib_windows.go"],
+ }),
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cross/platform_lib",
+)
+
+go_test(
+ name = "cross_test",
+ size = "small",
+ srcs = ["cross_test.go"],
+ args = [
+ "-darwin",
+ "$(location :darwin_cross)",
+ "-linux",
+ "$(location :linux_cross)",
+ "-windows",
+ "$(location :windows_cross)",
+ ],
+ data = [
+ ":darwin_cross",
+ ":linux_cross",
+ ":windows_cross",
+ ],
+ rundir = ".",
+ deps = ["//go/tools/bazel:go_default_library"],
+)
+
+go_test(
+ name = "go_cross_binary_test",
+ size = "small",
+ srcs = ["cross_test.go"],
+ args = [
+ "-darwin",
+ "$(location :darwin_go_cross)",
+ "-linux",
+ "$(location :linux_go_cross)",
+ "-windows",
+ "$(location :windows_go_cross)",
+ ],
+ data = [
+ ":darwin_go_cross",
+ ":linux_go_cross",
+ ":windows_go_cross",
+ ],
+ rundir = ".",
+ deps = ["//go/tools/bazel:go_default_library"],
+)
+
+go_bazel_test(
+ name = "ios_select_test",
+ srcs = ["ios_select_test.go"],
+)
+
+go_bazel_test(
+ name = "proto_test",
+ srcs = ["proto_test.go"],
+)
+
+go_bazel_test(
+ name = "sdk_version_test",
+ srcs = ["sdk_version_test.go"],
+)
+
+go_bazel_test(
+ name = "non_executable_test",
+ srcs = ["non_executable_test.go"],
+)
+
+no_context_info(
+ name = "no_context_info",
+)
diff --git a/tests/core/cross/README.rst b/tests/core/cross/README.rst
new file mode 100644
index 00000000..283eb264
--- /dev/null
+++ b/tests/core/cross/README.rst
@@ -0,0 +1,62 @@
+Cross compilation
+=================
+
+.. _go_binary: /docs/go/core/rules.md#go_binary
+.. _go_library: /docs/go/core/rules.md#go_library
+.. _go_cross_binary: /docs/go/core/rules.md#go_cross_binary
+.. _#2523: https://github.com/bazelbuild/rules_go/issues/2523
+
+Tests to ensure that cross compilation is working as expected.
+
+.. contents::
+
+cross_test
+----------
+
+
+Tests that cross compilation controlled by the ``goos`` and ``goarch``
+attributes on a `go_binary`_ produces executables for the correct platform.
+
+This builds binaries using `main.go <main.go>`_ in multiple configurations, and
+then passes them as data to a test `written in go <cross_test.go>`_.
+
+The test executes the unix command "file" on the binaries to determine their
+type, and checks they were built for the expected architecture.
+
+The test also checks that `go_library`_ packages imoprted by `go_binary`_ with
+``goos`` set are built in the correct configuration, and ``select`` is applied
+in that configuration. Each binary depends on ``platform_lib``, which has a
+different source file (determined by ``select``) for each platform. The source
+files have a ``goos`` suffix, so they will only be built on the right platform.
+If the wrong source file is used or if all files are filtered out, the
+`go_binary`_ will not build.
+
+go_cross_test
+-------------
+
+Indentical test to ``cross_test`` except tests using a `go_cross_binary`_ rule wrapping a `go_binary`_ instead of the ``goos`` and ``goarch`` attributes on a `go_binary`_.
+
+sdk_version_test
+----------------
+Tests that a `go_binary`_ wrapped in a `go_cross_binary`_ rule, with the ``sdk_version`` attribute set, produces an executable built with the correct Go SDK version.
+
+ios_select_test
+---------------
+
+Tests that we can cross-compile a library for iOS. We should be able to select
+a dependency using ``@io_bazel_rules_go//go/platform:darwin``, which is true
+when building for iOS (tested by ``ios_select_test``) and macOS
+(tested by ``use_ios_lib``).
+
+proto_test
+----------
+
+Tests that a ``go_proto_library`` can be cross-compiled, both with
+``--platforms`` and with mode attributes.
+
+no_context_info
+---------------
+
+Tests that a rule that uses ``@io_bazel_rules_go//go:toolchain`` but does not
+depend on any other target can call ``go_context`` without error. Verifies
+`#2523`_.
diff --git a/tests/core/cross/asm.s b/tests/core/cross/asm.s
new file mode 100644
index 00000000..7a5d5219
--- /dev/null
+++ b/tests/core/cross/asm.s
@@ -0,0 +1,15 @@
+// Example assembly copied from https://github.com/rpccloud/goid
+
+#include "go_asm.h"
+#include "textflag.h"
+
+#ifdef GOARCH_386
+#define get_tls(r) MOVL TLS, r
+#define g(r) 0(r)(TLS*1)
+#endif
+
+TEXT ·getg(SB), NOSPLIT, $0-4
+ get_tls(CX)
+ MOVL g(CX), AX
+ MOVL AX, ret+0(FP)
+ RET
diff --git a/tests/core/cross/cross_test.go b/tests/core/cross/cross_test.go
new file mode 100644
index 00000000..c8ff3b72
--- /dev/null
+++ b/tests/core/cross/cross_test.go
@@ -0,0 +1,91 @@
+/* Copyright 2017 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.
+*/
+
+package cross_test
+
+import (
+ "flag"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel"
+)
+
+type check struct {
+ file *string
+ info []string
+}
+
+var darwin = flag.String("darwin", "", "The darwin binary")
+var linux = flag.String("linux", "", "The linux binary")
+var windows = flag.String("windows", "", "The windows binary")
+
+var checks = []check{
+ {darwin, []string{
+ "Mach-O",
+ "64-bit",
+ "executable",
+ "x86_64",
+ }},
+ {linux, []string{
+ "ELF",
+ "64-bit",
+ "executable",
+ "x86-64",
+ }},
+ {windows, []string{
+ "PE32+",
+ "Windows",
+ "executable",
+ "console",
+ "x86-64",
+ }},
+}
+
+func TestCross(t *testing.T) {
+ for _, c := range checks {
+ path, err := bazel.Runfile(*c.file)
+ if err != nil {
+ t.Fatalf("Could not find runfile %s: %q", *c.file, err)
+ }
+
+ if _, err := os.Stat(path); os.IsNotExist(err) {
+ t.Fatalf("Missing binary %v", path)
+ }
+ file, err := filepath.EvalSymlinks(path)
+ if err != nil {
+ t.Fatalf("Invalid filename %v", path)
+ }
+ cmd := exec.Command("file", file)
+ cmd.Stderr = os.Stderr
+ res, err := cmd.Output()
+ if err != nil {
+ t.Fatalf("failed running 'file': %v", err)
+ }
+ output := string(res)
+ if index := strings.Index(output, ":"); index >= 0 {
+ output = output[index+1:]
+ }
+ output = strings.TrimSpace(output)
+ for _, info := range c.info {
+ if !strings.Contains(output, info) {
+ t.Errorf("incorrect type for %v\nExpected %v\nGot %v", file, info, output)
+ }
+ }
+ }
+}
diff --git a/tests/core/cross/def.bzl b/tests/core/cross/def.bzl
new file mode 100644
index 00000000..99ef7c40
--- /dev/null
+++ b/tests/core/cross/def.bzl
@@ -0,0 +1,24 @@
+# Copyright 2020 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("//go:def.bzl", "go_context")
+
+def _no_context_info_impl(ctx):
+ go_context(ctx)
+ # do nothing and pass if that succeeds
+
+no_context_info = rule(
+ implementation = _no_context_info_impl,
+ toolchains = ["@io_bazel_rules_go//go:toolchain"],
+)
diff --git a/tests/core/cross/ios_select_test.go b/tests/core/cross/ios_select_test.go
new file mode 100644
index 00000000..00bf0032
--- /dev/null
+++ b/tests/core/cross/ios_select_test.go
@@ -0,0 +1,66 @@
+// Copyright 2019 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.
+
+package ios_select_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "use_ios_lib",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cross/use_ios_lib",
+ deps = select({
+ ":is_osx": [":ios_lib"],
+ "//conditions:default": [],
+ }),
+)
+
+config_setting(
+ name = "is_osx",
+ constraint_values = ["@platforms//os:osx"],
+)
+
+go_library(
+ name = "ios_lib",
+ srcs = select({
+ "@io_bazel_rules_go//go/platform:darwin": ["ios_good.go"],
+ "@io_bazel_rules_go//go/platform:ios": ["ios_good.go"],
+ "//conditions:default": ["ios_bad.go"],
+ }),
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cross/ios_lib",
+)
+
+-- ios_good.go --
+package ios_lib
+
+-- ios_bad.go --
+donotbuild
+`,
+ })
+}
+
+func Test(t *testing.T) {
+ if err := bazel_testing.RunBazel("build", "--platforms=@io_bazel_rules_go//go/toolchain:ios_amd64", ":ios_lib"); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/tests/core/cross/lib_darwin.go b/tests/core/cross/lib_darwin.go
new file mode 100644
index 00000000..dfdc059f
--- /dev/null
+++ b/tests/core/cross/lib_darwin.go
@@ -0,0 +1,3 @@
+package platform_lib
+
+const Platform = "darwin"
diff --git a/tests/core/cross/lib_linux.go b/tests/core/cross/lib_linux.go
new file mode 100644
index 00000000..0759c9b5
--- /dev/null
+++ b/tests/core/cross/lib_linux.go
@@ -0,0 +1,3 @@
+package platform_lib
+
+const Platform = "linux"
diff --git a/tests/core/cross/lib_windows.go b/tests/core/cross/lib_windows.go
new file mode 100644
index 00000000..6ed0f7ab
--- /dev/null
+++ b/tests/core/cross/lib_windows.go
@@ -0,0 +1,3 @@
+package platform_lib
+
+const Platform = "windows"
diff --git a/tests/core/cross/main.go b/tests/core/cross/main.go
new file mode 100644
index 00000000..0d0c6794
--- /dev/null
+++ b/tests/core/cross/main.go
@@ -0,0 +1,26 @@
+/* Copyright 2016 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.
+*/
+
+package main
+
+import (
+ "fmt"
+
+ "github.com/bazelbuild/rules_go/tests/core/cross/platform_lib"
+)
+
+func main() {
+ fmt.Println(platform_lib.Platform)
+}
diff --git a/tests/core/cross/non_executable_test.go b/tests/core/cross/non_executable_test.go
new file mode 100644
index 00000000..ed9521c3
--- /dev/null
+++ b/tests/core/cross/non_executable_test.go
@@ -0,0 +1,106 @@
+// Copyright 2022 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.
+
+package non_executable_test
+
+import (
+ "regexp"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+var errorRegexp = regexp.MustCompile(`cannot run go_cross target "host_archive": underlying target "@{0,2}//src:archive" is not executable`);
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- src/BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_cross_binary")
+load(":rules.bzl", "no_runfiles_check")
+
+go_binary(
+ name = "archive",
+ srcs = ["archive.go"],
+ cgo = True,
+ linkmode = "c-archive",
+)
+
+# We make a new platform here so that we can exercise the go_cross_binary rule.
+# However, the test needs to run on all hosts, so the platform needs
+# to inherit from the host platform.
+platform(
+ name = "host_cgo",
+ parents = ["@local_config_platform//:host"],
+ constraint_values = [
+ "@io_bazel_rules_go//go/toolchain:cgo_on",
+ ],
+)
+
+go_cross_binary(
+ name = "host_archive",
+ target = ":archive",
+ platform = ":host_cgo",
+)
+
+cc_binary(
+ name = "main",
+ srcs = ["main.c"],
+ deps = [":host_archive"],
+)
+
+no_runfiles_check(
+ name = "no_runfiles",
+ target = ":main",
+)
+-- src/archive.go --
+package main
+
+import "C"
+
+func main() {}
+-- src/main.c --
+int main() {}
+-- src/rules.bzl --
+def _no_runfiles_check_impl(ctx):
+ runfiles = ctx.attr.target[DefaultInfo].default_runfiles.files.to_list()
+ for runfile in runfiles:
+ if runfile.short_path not in ["src/main", "src/main.exe"]:
+ fail("Unexpected runfile: %s" % runfile.short_path)
+
+no_runfiles_check = rule(
+ implementation = _no_runfiles_check_impl,
+ attrs = {
+ "target": attr.label(),
+ }
+)
+`,
+ })
+}
+
+func TestNonExecutableGoBinaryCantBeRun(t *testing.T) {
+ if err := bazel_testing.RunBazel("build", "//src:host_archive"); err != nil {
+ t.Fatal(err)
+ }
+ err := bazel_testing.RunBazel("run", "//src:host_archive")
+ if err == nil || !errorRegexp.MatchString(err.Error()) {
+ t.Errorf("Expected bazel run to fail due to //src:host_archive not being executable")
+ }
+}
+
+func TestNonExecutableGoBinaryNotInRunfiles(t *testing.T) {
+ if err := bazel_testing.RunBazel("build", "//src:no_runfiles"); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/tests/core/cross/proto_test.go b/tests/core/cross/proto_test.go
new file mode 100644
index 00000000..cd9e6c60
--- /dev/null
+++ b/tests/core/cross/proto_test.go
@@ -0,0 +1,126 @@
+// Copyright 2019 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.
+
+package proto_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+var testArgs = bazel_testing.Args{
+ WorkspaceSuffix: `
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+http_archive(
+ name = "com_google_protobuf",
+ sha256 = "75be42bd736f4df6d702a0e4e4d30de9ee40eac024c4b845d17ae4cc831fe4ae",
+ strip_prefix = "protobuf-21.7",
+ # latest available in BCR, as of 2022-09-30
+ urls = [
+ "https://github.com/protocolbuffers/protobuf/archive/v21.7.tar.gz",
+ "https://mirror.bazel.build/github.com/protocolbuffers/protobuf/archive/v21.7.tar.gz",
+ ],
+)
+
+load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
+
+protobuf_deps()
+
+http_archive(
+ name = "rules_proto",
+ sha256 = "4d421d51f9ecfe9bf96ab23b55c6f2b809cbaf0eea24952683e397decfbd0dd0",
+ strip_prefix = "rules_proto-f6b8d89b90a7956f6782a4a3609b2f0eee3ce965",
+ # master, as of 2020-01-06
+ urls = [
+ "https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/f6b8d89b90a7956f6782a4a3609b2f0eee3ce965.tar.gz",
+ "https://github.com/bazelbuild/rules_proto/archive/f6b8d89b90a7956f6782a4a3609b2f0eee3ce965.tar.gz",
+ ],
+)
+`,
+ Main: `
+-- BUILD.bazel --
+load("@rules_proto//proto:defs.bzl", "proto_library")
+load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
+load("@io_bazel_rules_go//go:def.bzl", "go_binary")
+
+proto_library(
+ name = "cross_proto",
+ srcs = ["cross.proto"],
+)
+
+go_proto_library(
+ name = "cross_go_proto",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/cross",
+ protos = [":cross_proto"],
+)
+
+go_binary(
+ name = "use_bin",
+ srcs = ["use.go"],
+ deps = [":cross_go_proto"],
+ goos = "linux",
+ goarch = "386",
+)
+
+go_binary(
+ name = "use_shared",
+ srcs = ["use.go"],
+ deps = [":cross_go_proto"],
+ linkmode = "c-shared",
+)
+
+-- cross.proto --
+syntax = "proto3";
+
+package cross;
+
+option go_package = "github.com/bazelbuild/rules_go/tests/core/cross";
+
+message Foo {
+ int64 x = 1;
+}
+
+-- use.go --
+package main
+
+import _ "github.com/bazelbuild/rules_go/tests/core/cross"
+
+func main() {}
+`,
+}
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, testArgs)
+}
+
+func TestCmdLine(t *testing.T) {
+ args := []string{
+ "build",
+ "--platforms=@io_bazel_rules_go//go/toolchain:linux_386",
+ ":cross_go_proto",
+ }
+ if err := bazel_testing.RunBazel(args...); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestTargets(t *testing.T) {
+ for _, target := range []string{"//:use_bin", "//:use_shared"} {
+ if err := bazel_testing.RunBazel("build", target); err != nil {
+ t.Errorf("building target %s: %v", target, err)
+ }
+ }
+}
diff --git a/tests/core/cross/sdk_version_test.go b/tests/core/cross/sdk_version_test.go
new file mode 100644
index 00000000..9cb7ad51
--- /dev/null
+++ b/tests/core/cross/sdk_version_test.go
@@ -0,0 +1,135 @@
+// Copyright 2022 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.
+
+package go_download_sdk_test
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+ "text/template"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+type testcase struct {
+ Name, SDKVersion, expectedVersion string
+}
+
+var testCases = []testcase{
+ {
+ Name: "major_version",
+ SDKVersion: "1",
+ expectedVersion: "go1.16",
+ },
+ {
+ Name: "minor_version",
+ SDKVersion: "1.16",
+ expectedVersion: "go1.16",
+ },
+ {
+ Name: "patch_version",
+ SDKVersion: "1.16.0",
+ expectedVersion: "go1.16",
+ },
+ {
+ Name: "1_17_minor_version",
+ SDKVersion: "1.17",
+ expectedVersion: "go1.17",
+ },
+ {
+ Name: "1_17_patch_version",
+ SDKVersion: "1.17.1",
+ expectedVersion: "go1.17.1",
+ },
+}
+
+func TestMain(m *testing.M) {
+ mainFilesTmpl := template.Must(template.New("").Parse(`
+-- WORKSPACE --
+local_repository(
+ name = "io_bazel_rules_go",
+ path = "../io_bazel_rules_go",
+)
+
+load("@io_bazel_rules_go//go:deps.bzl", "go_download_sdk", "go_rules_dependencies", "go_register_toolchains")
+
+go_rules_dependencies()
+
+go_download_sdk(
+ name = "go_sdk",
+ version = "1.16",
+)
+go_download_sdk(
+ name = "go_sdk_1_17",
+ version = "1.17",
+)
+go_download_sdk(
+ name = "go_sdk_1_17_1",
+ version = "1.17.1",
+)
+go_register_toolchains()
+-- main.go --
+package main
+
+import (
+ "fmt"
+ "runtime"
+)
+
+func main() {
+ fmt.Print(runtime.Version())
+}
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_cross_binary")
+
+go_binary(
+ name = "print_version",
+ srcs = ["main.go"],
+)
+{{range .TestCases}}
+go_cross_binary(
+ name = "{{.Name}}",
+ target = ":print_version",
+ sdk_version = "{{.SDKVersion}}",
+)
+{{end}}
+`))
+ tmplValues := struct{
+ TestCases []testcase
+ }{
+ TestCases: testCases,
+ }
+ mainFilesBuilder := &strings.Builder{}
+ if err := mainFilesTmpl.Execute(mainFilesBuilder, tmplValues); err != nil {
+ panic(err)
+ }
+
+ bazel_testing.TestMain(m, bazel_testing.Args{Main: mainFilesBuilder.String()})
+}
+
+func Test(t *testing.T) {
+ for _, test := range testCases {
+ t.Run(test.Name, func(t *testing.T) {
+ output, err := bazel_testing.BazelOutput("run", fmt.Sprintf("//:%s", test.Name))
+ if err != nil {
+ t.Fatal(err)
+ }
+ actualVersion := string(output)
+ if actualVersion != test.expectedVersion {
+ t.Fatal("actual", actualVersion, "vs expected", test.expectedVersion)
+ }
+ })
+ }
+}
diff --git a/tests/core/go_bazel_test/BUILD.bazel b/tests/core/go_bazel_test/BUILD.bazel
new file mode 100644
index 00000000..5a32ad75
--- /dev/null
+++ b/tests/core/go_bazel_test/BUILD.bazel
@@ -0,0 +1,9 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "dataargtest_test",
+ srcs = ["dataargtest_test.go"],
+ args = ["-binaryPath=$(location //tests/core/go_binary:hello)"],
+ data = ["//tests/core/go_binary:hello"],
+ deps = ["//go/tools/bazel:go_default_library"],
+)
diff --git a/tests/core/go_bazel_test/README.rst b/tests/core/go_bazel_test/README.rst
new file mode 100644
index 00000000..073f955f
--- /dev/null
+++ b/tests/core/go_bazel_test/README.rst
@@ -0,0 +1,10 @@
+go_bazel_test macro functionality
+=================================
+
+Tests to ensure the go_bazel_test is functioning correctly.
+
+dataargtest_test
+----------------
+
+Tests that `data` and `args` provided to `go_bazel_test` are provided to the go
+test framework correctly.
diff --git a/tests/core/go_bazel_test/dataargtest_test.go b/tests/core/go_bazel_test/dataargtest_test.go
new file mode 100644
index 00000000..9859fe84
--- /dev/null
+++ b/tests/core/go_bazel_test/dataargtest_test.go
@@ -0,0 +1,69 @@
+// Copyright 2019 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.
+
+package main
+
+import (
+ "flag"
+ "os"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel"
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+var (
+ binaryPath = flag.String("binaryPath", "", "")
+ setUpRan = false
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- root.txt --
+Hello world!
+-- nested/file.txt --
+Hello world!`,
+ SetUp: func() error {
+ setUpRan = true
+ return nil
+ },
+ })
+}
+
+// Tests that go_bazel_test keeps includes data files correctly and doesn't mess
+// up on `args` that include `$(location ...)` calls.
+func TestGoldenPath(t *testing.T) {
+ bp, err := bazel.Runfile(*binaryPath)
+ if err != nil {
+ t.Fatalf("unable to get the runfile path %#v: %s", *binaryPath, err)
+ }
+
+ tests := map[string]string{
+ "Go binary file": bp,
+ "Text file in root": "root.txt",
+ "Text file in nested dir": "nested/file.txt",
+ }
+
+ for name, f := range tests {
+ _, err = os.Stat(f)
+ if err != nil {
+ t.Fatalf("unable to stat %s file (%q): %s", name, f, err)
+ }
+ }
+
+ if setUpRan == false {
+ t.Fatal("setUp should have been executed but was not")
+ }
+}
diff --git a/tests/core/go_binary/BUILD.bazel b/tests/core/go_binary/BUILD.bazel
new file mode 100644
index 00000000..99a2d784
--- /dev/null
+++ b/tests/core/go_binary/BUILD.bazel
@@ -0,0 +1,193 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+load(":many_deps.bzl", "many_deps")
+
+test_suite(name = "go_binary")
+
+go_bazel_test(
+ name = "configurable_attribute_bad_test",
+ srcs = ["configurable_attribute_bad_test.go"],
+)
+
+go_bazel_test(
+ name = "configurable_attribute_good_test",
+ srcs = ["configurable_attribute_good_test.go"],
+)
+
+go_binary(
+ name = "hello",
+ srcs = ["hello.go"],
+ visibility = ["//visibility:public"],
+)
+
+go_test(
+ name = "go_default_test",
+ srcs = ["out_test.go"],
+ data = [":custom_bin"],
+)
+
+go_bazel_test(
+ name = "package_conflict_test",
+ srcs = ["package_conflict_test.go"],
+)
+
+go_binary(
+ name = "custom_bin",
+ srcs = ["custom_bin.go"],
+ out = "alt_bin",
+)
+
+go_binary(
+ name = "goos_pure_bin",
+ srcs = [
+ "broken_cgo.go",
+ "hello.go",
+ ],
+ goarch = "amd64",
+ goos = "plan9",
+)
+
+many_deps(name = "many_deps")
+
+go_test(
+ name = "stamp_test",
+ srcs = ["stamp_test.go"],
+ data = [":stamp_bin"],
+ rundir = ".",
+ deps = ["@io_bazel_rules_go//go/tools/bazel:go_default_library"],
+)
+
+go_binary(
+ name = "stamp_bin",
+ srcs = ["stamp_bin.go"],
+ embed = [":stamp_embed"],
+ x_defs = {
+ "Bin": "Bin",
+ "example.com/stamp_dep.DepBin": "DepBin",
+ },
+ deps = [":stamp_dep"],
+)
+
+go_library(
+ name = "stamp_embed",
+ srcs = ["stamp_embed.go"],
+ importpath = "example.com/stamp_embed",
+ x_defs = {
+ "Embed": "Embed",
+ },
+)
+
+go_library(
+ name = "stamp_dep",
+ srcs = ["stamp_dep.go"],
+ importpath = "example.com/stamp_dep",
+ x_defs = {
+ "DepSelf": "DepSelf",
+ },
+)
+
+go_binary(
+ name = "hello_pie_bin",
+ srcs = ["hello.go"],
+ cgo = True,
+ linkmode = "pie",
+ tags = ["manual"],
+)
+
+go_binary(
+ name = "hello_nopie_bin",
+ srcs = ["hello.go"],
+ cgo = True,
+ tags = ["manual"],
+)
+
+go_test(
+ name = "pie_test",
+ srcs = [
+ "pie_darwin_amd64_test.go",
+ "pie_darwin_test.go",
+ "pie_linux_test.go",
+ ],
+ data = select({
+ "@io_bazel_rules_go//go/platform:darwin": [
+ ":hello_nopie_bin",
+ ":hello_pie_bin",
+ ],
+ "@io_bazel_rules_go//go/platform:linux": [
+ ":hello_nopie_bin",
+ ":hello_pie_bin",
+ ],
+ "//conditions:default": [],
+ }),
+ rundir = ".",
+ deps = ["@io_bazel_rules_go//go/tools/bazel:go_default_library"],
+)
+
+go_test(
+ name = "static_test",
+ srcs = ["static_test.go"],
+ data = select({
+ "@io_bazel_rules_go//go/platform:linux": [
+ ":static_bin",
+ ":static_cgo_bin",
+ ":static_pure_bin",
+ ],
+ "//conditions:default": [],
+ }),
+ rundir = ".",
+ deps = ["//go/tools/bazel:go_default_library"],
+)
+
+go_binary(
+ name = "static_bin",
+ srcs = ["static_bin.go"],
+ static = "on",
+ tags = ["manual"],
+ deps = ["@org_golang_x_sys//unix:go_default_library"],
+)
+
+go_binary(
+ name = "static_cgo_bin",
+ srcs = ["static_cgo_bin.go"],
+ cgo = True,
+ static = "on",
+ tags = ["manual"],
+)
+
+go_binary(
+ name = "static_pure_bin",
+ srcs = ["static_pure_bin.go"],
+ pure = "on",
+ static = "on",
+ tags = ["manual"],
+)
+
+go_binary(
+ name = "tags_bin",
+ srcs = [
+ "tags_main_bad.go",
+ "tags_main_good.go",
+ ],
+ gotags = ["good"],
+ deps = [":tags_lib"],
+)
+
+go_library(
+ name = "tags_lib",
+ srcs = [
+ "tags_lib_bad.go",
+ "tags_lib_good.go",
+ ],
+ importpath = "tags_lib",
+ tags = ["manual"],
+)
+
+go_binary(
+ name = "prefix",
+ embed = ["//tests/core/go_binary/prefix"],
+)
+
+go_bazel_test(
+ name = "non_executable_test",
+ srcs = ["non_executable_test.go"],
+)
diff --git a/tests/core/go_binary/README.rst b/tests/core/go_binary/README.rst
new file mode 100644
index 00000000..a01bdf60
--- /dev/null
+++ b/tests/core/go_binary/README.rst
@@ -0,0 +1,70 @@
+Basic go_binary functionality
+=============================
+
+.. _go_binary: /docs/go/core/rules.md#_go_binary
+.. _#2168: https://github.com/bazelbuild/rules_go/issues/2168
+.. _#2463: https://github.com/bazelbuild/rules_go/issues/2463
+
+Tests to ensure the basic features of go_binary are working as expected.
+
+hello
+-----
+
+Hello is a basic "hello world" program that doesn't do anything interesting.
+Useful as a primitive smoke test -- if this doesn't build, nothing will.
+
+out_test
+--------
+
+Tests that a `go_binary`_ rule can write its executable file with a custom name
+in the package directory (not the mode directory).
+
+package_conflict_test
+---------------------
+
+Tests that linking multiple packages with the same path (`importmap`) is an
+error.
+
+goos_pure_bin
+-------------
+
+Tests that specifying the `goos` attribute on a `go_binary`_ target to be
+different than the host os forces the pure mode to be on. This is achieved
+by including a broken cgo file in the sources for the build.
+
+many_deps
+---------
+
+Test that a `go_binary`_ with many imports with long names can be linked. This
+makes sure we don't exceed command-line length limits with -I and -L flags.
+Verifies #1637.
+
+stamp_test
+----------
+Test that the `go_binary`_ ``x_defs`` attribute works correctly, both in a
+binary and in an embedded library. Tests regular stamps and stamps that
+depend on values from the workspace status script. Verifies #2000.
+
+pie_test
+--------
+Tests that specifying the ``linkmode`` attribute on a `go_binary`_ target to be
+pie produces a position-independent executable and that no specifying it produces
+a position-dependent binary.
+
+static_test
+-----------
+Test that `go_binary`_ rules with ``static = "on"`` with and without cgo
+produce static binaries. Verifies `#2168`_.
+
+This test only runs on Linux. The darwin external linker cannot produce
+static binaries since there is no static version of C runtime libraries.
+
+tags_bin
+--------
+Checks that setting ``gotags`` affects source filtering. This binary won't build
+without a specific tag being set.
+
+prefix
+------
+This binary has a name that conflicts with a subdirectory. Its output file
+name should not have this conflict. Verifies `#2463`_.
diff --git a/tests/core/go_binary/broken_cgo.go b/tests/core/go_binary/broken_cgo.go
new file mode 100644
index 00000000..0f0b6051
--- /dev/null
+++ b/tests/core/go_binary/broken_cgo.go
@@ -0,0 +1,7 @@
+// +build cgo
+
+// This file will not compile and its inclusion in a build is used to ensure
+// that a binary was built in pure mode.
+package main
+
+import "non/existent/pkg"
diff --git a/tests/core/go_binary/configurable_attribute_bad_test.go b/tests/core/go_binary/configurable_attribute_bad_test.go
new file mode 100644
index 00000000..abd35ba2
--- /dev/null
+++ b/tests/core/go_binary/configurable_attribute_bad_test.go
@@ -0,0 +1,69 @@
+// Copyright 2022 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.
+
+package configurable_attribute_bad_test
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary")
+
+go_binary(
+ name = "main",
+ srcs = [
+ "main.go",
+ ],
+ goos = "darwin",
+ goarch = "amd64",
+ gotags = select({
+ "@io_bazel_rules_go//go/platform:linux": ["penguins"],
+ "//conditions:default": ["nopenguins"],
+ }),
+)
+
+-- main.go --
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("Howdy")
+}
+`,
+ })
+}
+
+func TestConfigurableGotagsAttribute(t *testing.T) {
+ _, err := bazel_testing.BazelOutput("build", "//:main")
+ if err == nil {
+ t.Fatal("Want error")
+ }
+ eErr, ok := err.(*bazel_testing.StderrExitError)
+ if !ok {
+ t.Fatalf("Want StderrExitError but got %v", err)
+ }
+ stderr := eErr.Error()
+ want := "Cannot use select for go_binary with goos/goarch set, but gotags was a select"
+ if !strings.Contains(stderr, want) {
+ t.Fatalf("Want error message containing %q but got %v", want, stderr)
+ }
+}
diff --git a/tests/core/go_binary/configurable_attribute_good_test.go b/tests/core/go_binary/configurable_attribute_good_test.go
new file mode 100644
index 00000000..a1fe1954
--- /dev/null
+++ b/tests/core/go_binary/configurable_attribute_good_test.go
@@ -0,0 +1,92 @@
+// Copyright 2022 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.
+
+package configurable_attribute_good_test
+
+import (
+ "runtime"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary")
+
+go_binary(
+ name = "main",
+ srcs = [
+ "main.go",
+ "lib_nopenguins.go",
+ "lib_penguins.go",
+ ],
+ gotags = select({
+ "@io_bazel_rules_go//go/platform:linux": ["penguins"],
+ "//conditions:default": ["nopenguins"],
+ }),
+)
+
+-- main.go --
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Println(message())
+}
+
+-- lib_penguins.go --
+// +build penguins
+
+package main
+
+func message() string {
+ return "Penguins are great"
+}
+
+
+-- lib_nopenguins.go --
+// +build !penguins
+
+package main
+
+func message() string {
+ return "Penguins smell fishy'"
+}
+`,
+ })
+}
+
+func TestConfigurableGotagsAttribute(t *testing.T) {
+ outBytes, err := bazel_testing.BazelOutput("run", "//:main")
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ out := string(outBytes)
+ os := runtime.GOOS
+ switch os {
+ case "linux":
+ if !strings.Contains(out, "Penguins are great") {
+ t.Fatalf("Wanted penguin executable, but output was: %s", out)
+ }
+ default:
+ if !strings.Contains(out, "Penguins smell fishy") {
+ t.Fatalf("Wanted nopenguin executable, but output was: %s", out)
+ }
+ }
+}
diff --git a/tests/core/go_binary/custom_bin.go b/tests/core/go_binary/custom_bin.go
new file mode 100644
index 00000000..da29a2ca
--- /dev/null
+++ b/tests/core/go_binary/custom_bin.go
@@ -0,0 +1,4 @@
+package main
+
+func main() {
+}
diff --git a/tests/core/go_binary/hello.go b/tests/core/go_binary/hello.go
new file mode 100644
index 00000000..f7b60bde
--- /dev/null
+++ b/tests/core/go_binary/hello.go
@@ -0,0 +1,7 @@
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("Hello, world!")
+}
diff --git a/tests/core/go_binary/many_deps.bzl b/tests/core/go_binary/many_deps.bzl
new file mode 100644
index 00000000..621e286d
--- /dev/null
+++ b/tests/core/go_binary/many_deps.bzl
@@ -0,0 +1,92 @@
+# Copyright 2018 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:def.bzl",
+ "go_binary",
+ "go_context",
+)
+
+_PREFIX = "/".join(["abcdefgh"[i] * 100 for i in range(7)]) + "/"
+
+def _gen_library_impl(ctx):
+ go = go_context(ctx)
+ src = go.actions.declare_file(ctx.label.name + ".go")
+ go.actions.write(src, "package " + ctx.label.name + "\n")
+ library = go.new_library(go, srcs = [src])
+ source = go.library_to_source(go, ctx.attr, library, ctx.coverage_instrumented())
+ archive = go.archive(go, source)
+ return [
+ library,
+ source,
+ archive,
+ DefaultInfo(files = depset([archive.data.file])),
+ ]
+
+_gen_library = rule(
+ _gen_library_impl,
+ attrs = {
+ "importpath": attr.string(mandatory = True),
+ "_go_context_data": attr.label(
+ default = "//:go_context_data",
+ ),
+ },
+ toolchains = ["@io_bazel_rules_go//go:toolchain"],
+)
+
+def _gen_main_src_impl(ctx):
+ src = ctx.actions.declare_file(ctx.label.name + ".go")
+ lines = [
+ "package main",
+ "",
+ "import (",
+ ]
+ for i in range(ctx.attr.n):
+ lines.append('\t_ "{}many_deps{}"'.format(_PREFIX, i))
+ lines.extend([
+ ")",
+ "",
+ "func main() {}",
+ ])
+ ctx.actions.write(src, "\n".join(lines))
+ return [DefaultInfo(files = depset([src]))]
+
+_gen_main_src = rule(
+ _gen_main_src_impl,
+ attrs = {
+ "n": attr.int(mandatory = True),
+ },
+)
+
+def many_deps(name, **kwargs):
+ deps = []
+ n = 200
+ for i in range(n):
+ lib_name = "many_deps" + str(i)
+ _gen_library(
+ name = lib_name,
+ importpath = _PREFIX + lib_name,
+ visibility = ["//visibility:private"],
+ )
+ deps.append(lib_name)
+ _gen_main_src(
+ name = "many_deps_src",
+ n = n,
+ )
+ go_binary(
+ name = name,
+ srcs = [":many_deps_src"],
+ deps = deps,
+ **kwargs
+ )
diff --git a/tests/core/go_binary/non_executable_test.go b/tests/core/go_binary/non_executable_test.go
new file mode 100644
index 00000000..b2eb987c
--- /dev/null
+++ b/tests/core/go_binary/non_executable_test.go
@@ -0,0 +1,87 @@
+// Copyright 2022 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.
+
+package non_executable_test
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- src/BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary")
+load(":rules.bzl", "no_runfiles_check")
+
+go_binary(
+ name = "archive",
+ srcs = ["archive.go"],
+ cgo = True,
+ linkmode = "c-archive",
+)
+
+cc_binary(
+ name = "main",
+ srcs = ["main.c"],
+ deps = [":archive"],
+)
+
+no_runfiles_check(
+ name = "no_runfiles",
+ target = ":main",
+)
+-- src/archive.go --
+package main
+
+import "C"
+
+func main() {}
+-- src/main.c --
+int main() {}
+-- src/rules.bzl --
+def _no_runfiles_check_impl(ctx):
+ runfiles = ctx.attr.target[DefaultInfo].default_runfiles.files.to_list()
+ for runfile in runfiles:
+ if runfile.short_path not in ["src/main", "src/main.exe"]:
+ fail("Unexpected runfile: %s" % runfile.short_path)
+
+no_runfiles_check = rule(
+ implementation = _no_runfiles_check_impl,
+ attrs = {
+ "target": attr.label(),
+ }
+)
+`,
+ })
+}
+
+func TestNonExecutableGoBinaryCantBeRun(t *testing.T) {
+ if err := bazel_testing.RunBazel("build", "//src:archive"); err != nil {
+ t.Fatal(err)
+ }
+ err := bazel_testing.RunBazel("run", "//src:archive")
+ if err == nil || !strings.Contains(err.Error(), "ERROR: Cannot run target //src:archive: Not executable") {
+ t.Errorf("Expected bazel run to fail due to //src:archive not being executable")
+ }
+}
+
+func TestNonExecutableGoBinaryNotInRunfiles(t *testing.T) {
+ if err := bazel_testing.RunBazel("build", "//src:no_runfiles"); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/tests/core/go_binary/out_test.go b/tests/core/go_binary/out_test.go
new file mode 100644
index 00000000..7c6ba7f3
--- /dev/null
+++ b/tests/core/go_binary/out_test.go
@@ -0,0 +1,13 @@
+package main
+
+import (
+ "os"
+ "testing"
+)
+
+func TestCustomBinaryName(t *testing.T) {
+ _, err := os.Stat("alt_bin")
+ if err != nil {
+ t.Error(err)
+ }
+}
diff --git a/tests/core/go_binary/package_conflict_test.go b/tests/core/go_binary/package_conflict_test.go
new file mode 100644
index 00000000..9ec6340a
--- /dev/null
+++ b/tests/core/go_binary/package_conflict_test.go
@@ -0,0 +1,120 @@
+// Copyright 2020 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.
+
+package package_conflict_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
+
+go_library(
+ name = "foo_de",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/package_conflict/foo",
+ srcs = ["foo_de.go"],
+)
+
+go_library(
+ name = "de",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/package_conflict/de",
+ srcs = ["de.go"],
+ deps = [":foo_de"],
+)
+
+go_library(
+ name = "foo_en",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/package_conflict/foo",
+ srcs = ["foo_en.go"],
+)
+
+go_library(
+ name = "en",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/package_conflict/en",
+ srcs = ["en.go"],
+ deps = [":foo_en"],
+)
+
+go_binary(
+ name = "main",
+ srcs = ["main.go"],
+ deps = [
+ ":de",
+ ":en",
+ ],
+)
+
+-- foo_en.go --
+package foo
+
+import "fmt"
+
+func SayHello() {
+ fmt.Println("Hello, World!")
+}
+
+-- en.go --
+package en
+
+import "github.com/bazelbuild/rules_go/tests/core/package_conflict/foo"
+
+func SayHello() {
+ foo.SayHello()
+}
+
+-- foo_de.go --
+package foo
+
+import "fmt"
+
+func SayHello() {
+ fmt.Println("Hallo, Welt!")
+}
+
+-- de.go --
+package de
+
+import "github.com/bazelbuild/rules_go/tests/core/package_conflict/foo"
+
+func SayHello() {
+ foo.SayHello()
+}
+
+-- main.go --
+package main
+
+import (
+ "github.com/bazelbuild/rules_go/tests/core/package_conflict/de"
+ "github.com/bazelbuild/rules_go/tests/core/package_conflict/en"
+)
+
+func main() {
+ de.SayHello()
+ en.SayHello()
+}
+`,
+ })
+}
+
+func TestPackageConflict(t *testing.T) {
+ if err := bazel_testing.RunBazel("build", "//:main"); err == nil {
+ t.Fatal("Expected error")
+ }
+}
diff --git a/tests/core/go_binary/pie_darwin_amd64_test.go b/tests/core/go_binary/pie_darwin_amd64_test.go
new file mode 100644
index 00000000..9a07f955
--- /dev/null
+++ b/tests/core/go_binary/pie_darwin_amd64_test.go
@@ -0,0 +1,31 @@
+// Copyright 2021 Google LLC
+//
+// 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
+//
+// https://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.
+
+package test
+
+import (
+ "debug/macho"
+ "testing"
+)
+
+func TestNoPIE(t *testing.T) {
+ m, err := openMachO("tests/core/go_binary", "hello_nopie_bin")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if m.Flags&macho.FlagPIE != 0 {
+ t.Error("ELF binary is not position-dependent.")
+ }
+}
diff --git a/tests/core/go_binary/pie_darwin_test.go b/tests/core/go_binary/pie_darwin_test.go
new file mode 100644
index 00000000..2f45b878
--- /dev/null
+++ b/tests/core/go_binary/pie_darwin_test.go
@@ -0,0 +1,35 @@
+package test
+
+import (
+ "debug/macho"
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel"
+)
+
+func openMachO(dir, bin string) (*macho.File, error) {
+ bin, ok := bazel.FindBinary(dir, bin)
+ if !ok {
+ return nil, fmt.Errorf("could not find binary: %s", bin)
+ }
+
+ f, err := os.Open(bin)
+ if err != nil {
+ return nil, err
+ }
+
+ return macho.NewFile(f)
+}
+
+func TestPIE(t *testing.T) {
+ m, err := openMachO("tests/core/go_binary", "hello_pie_bin")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if m.Flags&macho.FlagPIE == 0 {
+ t.Error("ELF binary is not position-independent.")
+ }
+}
diff --git a/tests/core/go_binary/pie_linux_test.go b/tests/core/go_binary/pie_linux_test.go
new file mode 100644
index 00000000..8b135500
--- /dev/null
+++ b/tests/core/go_binary/pie_linux_test.go
@@ -0,0 +1,48 @@
+package test
+
+import (
+ "debug/elf"
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel"
+)
+
+func openELF(dir, bin string) (*elf.File, error) {
+ bin, ok := bazel.FindBinary(dir, bin)
+ if !ok {
+ return nil, fmt.Errorf("could not find binary: %s", bin)
+ }
+
+ f, err := os.Open(bin)
+ if err != nil {
+ return nil, err
+ }
+
+ return elf.NewFile(f)
+}
+
+func TestPIE(t *testing.T) {
+ e, err := openELF("tests/core/go_binary", "hello_pie_bin")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // PIE binaries are implemented as shared libraries.
+ if e.Type != elf.ET_DYN {
+ t.Error("ELF binary is not position-independent.")
+ }
+}
+
+func TestNoPIE(t *testing.T) {
+ e, err := openELF("tests/core/go_binary", "hello_nopie_bin")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // PIE binaries are implemented as shared libraries.
+ if e.Type != elf.ET_EXEC {
+ t.Error("ELF binary is not position-dependent.")
+ }
+}
diff --git a/tests/core/go_binary/prefix/BUILD.bazel b/tests/core/go_binary/prefix/BUILD.bazel
new file mode 100644
index 00000000..aff7406b
--- /dev/null
+++ b/tests/core/go_binary/prefix/BUILD.bazel
@@ -0,0 +1,8 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "prefix",
+ srcs = ["prefix.go"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_binary/prefix",
+ visibility = ["//tests/core/go_binary:__pkg__"],
+)
diff --git a/tests/core/go_binary/prefix/prefix.go b/tests/core/go_binary/prefix/prefix.go
new file mode 100644
index 00000000..38dd16da
--- /dev/null
+++ b/tests/core/go_binary/prefix/prefix.go
@@ -0,0 +1,3 @@
+package main
+
+func main() {}
diff --git a/tests/core/go_binary/stamp_bin.go b/tests/core/go_binary/stamp_bin.go
new file mode 100644
index 00000000..e227be4c
--- /dev/null
+++ b/tests/core/go_binary/stamp_bin.go
@@ -0,0 +1,16 @@
+package main
+
+import (
+ "fmt"
+
+ "example.com/stamp_dep"
+)
+
+var Bin = "redacted"
+
+func main() {
+ fmt.Printf("Bin=%s\n", Bin)
+ fmt.Printf("Embed=%s\n", Embed)
+ fmt.Printf("DepSelf=%s\n", stamp_dep.DepSelf)
+ fmt.Printf("DepBin=%s\n", stamp_dep.DepBin)
+}
diff --git a/tests/core/go_binary/stamp_dep.go b/tests/core/go_binary/stamp_dep.go
new file mode 100644
index 00000000..37aa4635
--- /dev/null
+++ b/tests/core/go_binary/stamp_dep.go
@@ -0,0 +1,6 @@
+package stamp_dep
+
+var (
+ DepSelf = "redacted"
+ DepBin = "redacted"
+)
diff --git a/tests/core/go_binary/stamp_embed.go b/tests/core/go_binary/stamp_embed.go
new file mode 100644
index 00000000..8989e914
--- /dev/null
+++ b/tests/core/go_binary/stamp_embed.go
@@ -0,0 +1,3 @@
+package main
+
+var Embed = "redacted"
diff --git a/tests/core/go_binary/stamp_test.go b/tests/core/go_binary/stamp_test.go
new file mode 100644
index 00000000..506cce5c
--- /dev/null
+++ b/tests/core/go_binary/stamp_test.go
@@ -0,0 +1,29 @@
+package main
+
+import (
+ "os/exec"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel"
+)
+
+func TestStamp(t *testing.T) {
+ bin, ok := bazel.FindBinary("tests/core/go_binary", "stamp_bin")
+ if !ok {
+ t.Error("could not find stamp_bin")
+ }
+ out, err := exec.Command(bin).Output()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got := strings.TrimSpace(string(out))
+ want := `Bin=Bin
+Embed=Embed
+DepSelf=DepSelf
+DepBin=DepBin`
+ if got != want {
+ t.Errorf("got:\n%s\nwant:\n%s", got, want)
+ }
+}
diff --git a/tests/core/go_binary/static_bin.go b/tests/core/go_binary/static_bin.go
new file mode 100644
index 00000000..7e0ab83b
--- /dev/null
+++ b/tests/core/go_binary/static_bin.go
@@ -0,0 +1,7 @@
+package main
+
+import (
+ _ "golang.org/x/sys/unix" // See https://github.com/bazelbuild/rules_go/issues/2168
+)
+
+func main() {}
diff --git a/tests/core/go_binary/static_cgo_bin.go b/tests/core/go_binary/static_cgo_bin.go
new file mode 100644
index 00000000..65676fd9
--- /dev/null
+++ b/tests/core/go_binary/static_cgo_bin.go
@@ -0,0 +1,14 @@
+package main
+
+/*
+#include <stdio.h>
+
+void say_hello() {
+ printf("hello\n");
+}
+*/
+import "C"
+
+func main() {
+ C.say_hello()
+}
diff --git a/tests/core/go_binary/static_pure_bin.go b/tests/core/go_binary/static_pure_bin.go
new file mode 100644
index 00000000..1dbaa12e
--- /dev/null
+++ b/tests/core/go_binary/static_pure_bin.go
@@ -0,0 +1,8 @@
+package main
+
+import (
+ _ "net"
+ _ "os"
+)
+
+func main() {}
diff --git a/tests/core/go_binary/static_test.go b/tests/core/go_binary/static_test.go
new file mode 100644
index 00000000..7c23cdae
--- /dev/null
+++ b/tests/core/go_binary/static_test.go
@@ -0,0 +1,45 @@
+// Copyright 2019 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.
+
+// +build linux
+
+package static_cgo_test
+
+import (
+ "debug/elf"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel"
+)
+
+func TestStatic(t *testing.T) {
+ for _, name := range []string{"static_bin", "static_cgo_bin", "static_pure_bin"} {
+ t.Run(name, func(t *testing.T) {
+ path, ok := bazel.FindBinary("tests/core/go_binary", name)
+ if !ok {
+ t.Fatal("could not find static_cgo_bin")
+ }
+ f, err := elf.Open(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+ for _, prog := range f.Progs {
+ if prog.Type == elf.PT_INTERP {
+ t.Fatalf("binary %s has PT_INTERP segment, indicating dynamic linkage", path)
+ }
+ }
+ })
+ }
+}
diff --git a/tests/core/go_binary/tags_lib_bad.go b/tests/core/go_binary/tags_lib_bad.go
new file mode 100644
index 00000000..30deb5ed
--- /dev/null
+++ b/tests/core/go_binary/tags_lib_bad.go
@@ -0,0 +1,5 @@
+// +build !good
+
+package lib
+
+var Does Not = Compile
diff --git a/tests/core/go_binary/tags_lib_good.go b/tests/core/go_binary/tags_lib_good.go
new file mode 100644
index 00000000..55c21f80
--- /dev/null
+++ b/tests/core/go_binary/tags_lib_good.go
@@ -0,0 +1 @@
+package lib
diff --git a/tests/core/go_binary/tags_main_bad.go b/tests/core/go_binary/tags_main_bad.go
new file mode 100644
index 00000000..444667ba
--- /dev/null
+++ b/tests/core/go_binary/tags_main_bad.go
@@ -0,0 +1,5 @@
+// +build !good
+
+package main
+
+var Does Not = Compile
diff --git a/tests/core/go_binary/tags_main_good.go b/tests/core/go_binary/tags_main_good.go
new file mode 100644
index 00000000..ee15bee7
--- /dev/null
+++ b/tests/core/go_binary/tags_main_good.go
@@ -0,0 +1,8 @@
+// +build good
+
+package main
+
+import _ "tags_lib"
+
+func main() {
+}
diff --git a/tests/core/go_download_sdk/BUILD.bazel b/tests/core/go_download_sdk/BUILD.bazel
new file mode 100644
index 00000000..f294f987
--- /dev/null
+++ b/tests/core/go_download_sdk/BUILD.bazel
@@ -0,0 +1,6 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "go_download_sdk_test",
+ srcs = ["go_download_sdk_test.go"],
+)
diff --git a/tests/core/go_download_sdk/README.rst b/tests/core/go_download_sdk/README.rst
new file mode 100644
index 00000000..78e93118
--- /dev/null
+++ b/tests/core/go_download_sdk/README.rst
@@ -0,0 +1,7 @@
+go_download_sdk
+===============
+
+go_download_sdk_test
+--------------------
+Verifies that ``go_downlaod_sdk`` can be used to download a specific version
+or a set of archives for various platforms.
diff --git a/tests/core/go_download_sdk/go_download_sdk_test.go b/tests/core/go_download_sdk/go_download_sdk_test.go
new file mode 100644
index 00000000..61bd05b8
--- /dev/null
+++ b/tests/core/go_download_sdk/go_download_sdk_test.go
@@ -0,0 +1,187 @@
+// Copyright 2019 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.
+
+package go_download_sdk_test
+
+import (
+ "bytes"
+ "io/ioutil"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_test")
+
+go_test(
+ name = "version_test",
+ srcs = ["version_test.go"],
+)
+
+-- version_test.go --
+package version_test
+
+import (
+ "flag"
+ "runtime"
+ "testing"
+)
+
+var want = flag.String("version", "", "")
+
+func Test(t *testing.T) {
+ if v := runtime.Version(); v != *want {
+ t.Errorf("got version %q; want %q", v, *want)
+ }
+}
+`,
+ })
+}
+
+func Test(t *testing.T) {
+ for _, test := range []struct {
+ desc, rule string
+ optToWantVersion map[string]string
+ fetchOnly string
+ }{
+ {
+ desc: "version",
+ rule: `
+load("@io_bazel_rules_go//go:deps.bzl", "go_download_sdk")
+
+go_download_sdk(
+ name = "go_sdk",
+ version = "1.16",
+)
+
+`,
+ optToWantVersion: map[string]string{"": "go1.16"},
+ },
+ {
+ desc: "custom_archives",
+ rule: `
+load("@io_bazel_rules_go//go:deps.bzl", "go_download_sdk")
+
+go_download_sdk(
+ name = "go_sdk",
+ sdks = {
+ "darwin_amd64": ("go1.16.darwin-amd64.tar.gz", "6000a9522975d116bf76044967d7e69e04e982e9625330d9a539a8b45395f9a8"),
+ "darwin_arm64": ("go1.16.darwin-arm64.tar.gz", "4dac57c00168d30bbd02d95131d5de9ca88e04f2c5a29a404576f30ae9b54810"),
+ "linux_amd64": ("go1.16.linux-amd64.tar.gz", "013a489ebb3e24ef3d915abe5b94c3286c070dfe0818d5bca8108f1d6e8440d2"),
+ "windows_amd64": ("go1.16.windows-amd64.zip", "5cc88fa506b3d5c453c54c3ea218fc8dd05d7362ae1de15bb67986b72089ce93"),
+ },
+)
+`,
+ optToWantVersion: map[string]string{"": "go1.16"},
+ },
+ {
+ desc: "multiple_sdks",
+ rule: `
+load("@io_bazel_rules_go//go:deps.bzl", "go_download_sdk", "go_host_sdk")
+
+go_download_sdk(
+ name = "go_sdk",
+ version = "1.16",
+)
+go_download_sdk(
+ name = "go_sdk_1_17",
+ version = "1.17",
+)
+go_download_sdk(
+ name = "go_sdk_1_17_1",
+ version = "1.17.1",
+)
+`,
+ optToWantVersion: map[string]string{
+ "": "go1.16",
+ "--@io_bazel_rules_go//go/toolchain:sdk_version=remote": "go1.16",
+ "--@io_bazel_rules_go//go/toolchain:sdk_version=1": "go1.16",
+ "--@io_bazel_rules_go//go/toolchain:sdk_version=1.17": "go1.17",
+ "--@io_bazel_rules_go//go/toolchain:sdk_version=1.17.0": "go1.17",
+ "--@io_bazel_rules_go//go/toolchain:sdk_version=1.17.1": "go1.17.1",
+ },
+ },
+ {
+ // Cover workaround for #2771.
+ desc: "windows_zip",
+ rule: `
+load("@io_bazel_rules_go//go:deps.bzl", "go_download_sdk")
+
+go_download_sdk(
+ name = "go_sdk",
+ goarch = "amd64",
+ goos = "windows",
+ version = "1.20.4",
+)
+`,
+ fetchOnly: "@go_sdk//:BUILD.bazel",
+ },
+ } {
+ t.Run(test.desc, func(t *testing.T) {
+ origWorkspaceData, err := ioutil.ReadFile("WORKSPACE")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ i := bytes.Index(origWorkspaceData, []byte("go_rules_dependencies()"))
+ if i < 0 {
+ t.Fatal("could not find call to go_rules_dependencies()")
+ }
+
+ buf := &bytes.Buffer{}
+ buf.Write(origWorkspaceData[:i])
+ buf.WriteString(test.rule)
+ buf.WriteString(`
+go_rules_dependencies()
+
+go_register_toolchains()
+`)
+ if err := ioutil.WriteFile("WORKSPACE", buf.Bytes(), 0666); err != nil {
+ t.Fatal(err)
+ }
+ defer func() {
+ if err := ioutil.WriteFile("WORKSPACE", origWorkspaceData, 0666); err != nil {
+ t.Errorf("error restoring WORKSPACE: %v", err)
+ }
+ }()
+
+ if test.fetchOnly != "" {
+ if err := bazel_testing.RunBazel("fetch", test.fetchOnly); err != nil {
+ t.Fatal(err)
+ }
+ return
+ }
+
+ for opt, wantVersion := range test.optToWantVersion {
+ t.Run(wantVersion, func(t *testing.T) {
+ args := []string{
+ "test",
+ "//:version_test",
+ "--test_arg=-version=" + wantVersion,
+ }
+ if opt != "" {
+ args = append(args, opt)
+ }
+ if err := bazel_testing.RunBazel(args...); err != nil {
+ t.Fatal(err)
+ }
+ })
+ }
+ })
+ }
+}
diff --git a/tests/core/go_library/BUILD.bazel b/tests/core/go_library/BUILD.bazel
new file mode 100644
index 00000000..25293cbe
--- /dev/null
+++ b/tests/core/go_library/BUILD.bazel
@@ -0,0 +1,168 @@
+load("//go:def.bzl", "go_binary", "go_library", "go_test")
+load("//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+load(":def.bzl", "embedsrcs_files")
+
+go_library(
+ name = "empty",
+ srcs = [
+ # foo and bar have different package names
+ "empty_foo.go",
+ "empty_bar.go",
+ "empty_baz.s",
+ ],
+ importpath = "empty",
+)
+
+go_library(
+ name = "asm_include",
+ srcs = [
+ "inc.go",
+ "inc_bar.s",
+ "inc_foo.s",
+ ],
+ importpath = "asm_include",
+)
+
+go_library(
+ name = "asm_header",
+ srcs = [
+ "inc.go",
+ "inc_asmhdr.s",
+ ],
+ importpath = "asm_header",
+)
+
+go_library(
+ name = "package_height",
+ srcs = ["package_height.go"],
+ importpath = "package_height",
+ deps = [
+ ":package_height_dep_deep",
+ ":package_height_embedder",
+ ],
+)
+
+go_library(
+ name = "package_height_embedder",
+ srcs = ["package_height_embedder.go"],
+ embed = [":package_height_embeddee"],
+ importpath = "package_height/embed",
+ deps = [":package_height_dep_deep"],
+)
+
+go_library(
+ name = "package_height_embeddee",
+ srcs = ["package_height_embeddee.go"],
+ importpath = "package_height/embed",
+ deps = [":package_height_dep_shallow"],
+)
+
+go_library(
+ name = "package_height_dep_deep",
+ srcs = ["package_height_dep_deep.go"],
+ importpath = "package_height/dep",
+)
+
+go_library(
+ name = "package_height_dep_shallow",
+ srcs = ["package_height_dep_shallow.go"],
+ importpath = "package_height/dep",
+)
+
+go_test(
+ name = "import_alias_test",
+ srcs = ["import_alias_test.go"],
+ deps = [
+ ":import_alias_a_v2",
+ ":import_alias_b",
+ ":import_alias_b_v2",
+ ],
+)
+
+go_library(
+ name = "import_alias_a_v2",
+ srcs = ["import_alias_a_v2.go"],
+ importpath = "import_alias/a/v2",
+ importpath_aliases = ["import_alias/a"],
+)
+
+go_library(
+ name = "import_alias_b",
+ srcs = ["import_alias_b.go"],
+ importpath = "import_alias/b",
+)
+
+go_library(
+ name = "import_alias_b_v2",
+ importpath = "import_alias/b/v2",
+ importpath_aliases = ["import_alias/b"],
+)
+
+go_test(
+ name = "embedsrcs_test",
+ srcs = [
+ "embedsrcs_gen_test.go",
+ "embedsrcs_test.go",
+ ],
+ embedsrcs = [
+ ":embedsrcs_transitioned",
+ ":embedsrcs_dynamic",
+ "embedsrcs_test.go",
+ ] + glob(["embedsrcs_static/**"]),
+)
+
+genrule(
+ name = "embedsrcs_gen",
+ srcs = ["embedsrcs_gen_test.go.in"],
+ outs = ["embedsrcs_gen_test.go"],
+ cmd = "cp $< $@",
+)
+
+embedsrcs_files(
+ name = "embedsrcs_dynamic",
+ files = [
+ "dir/_no",
+ "dir/f",
+ "empty/",
+ "file",
+ "glob/_hidden",
+ "glob/f",
+ "no",
+ ],
+)
+
+go_binary(
+ name = "embedsrcs_transitioned",
+ srcs = ["empty_main.go"],
+ out = "embedsrcs_transitioned",
+ # Causes a transition on the incoming dependency edge.
+ race = "on",
+)
+
+go_binary(
+ name = "gen_embedsrcs_files",
+ srcs = ["gen_embedsrcs_files.go"],
+)
+
+go_bazel_test(
+ name = "embedsrcs_error_test",
+ size = "medium",
+ srcs = ["embedsrcs_error_test.go"],
+)
+
+go_test(
+ name = "embedsrcs_simple_test",
+ srcs = ["embedsrcs_simple_test.go"],
+ embedsrcs = ["embedsrcs_static/no"],
+)
+
+go_bazel_test(
+ name = "no_srcs_test",
+ size = "medium",
+ srcs = ["no_srcs_test.go"],
+)
+
+go_library(
+ name = "no_srcs_lib",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/no_srcs_lib",
+)
diff --git a/tests/core/go_library/README.rst b/tests/core/go_library/README.rst
new file mode 100644
index 00000000..4410902f
--- /dev/null
+++ b/tests/core/go_library/README.rst
@@ -0,0 +1,57 @@
+Basic go_library functionality
+==============================
+
+.. _go_library: /docs/go/core/rules.md#_go_library
+.. _#1262: https://github.com/bazelbuild/rules_go/issues/1262
+.. _#1520: https://github.com/bazelbuild/rules_go/issues/1520
+.. _#1772: https://github.com/bazelbuild/rules_go/issues/1772
+.. _#2058: https://github.com/bazelbuild/rules_go/issues/2058
+.. _#3558: https://github.com/bazelbuild/rules_go/issues/3558
+
+empty
+-----
+
+Checks that a `go_library`_ will compile and link even if all the sources
+(including assembly sources) are filtered out by build constraints.
+
+asm_include
+-----------
+
+Checks that assembly files in a `go_library`_ may include other assembly
+files in the same library. Verifies `#1520`_.
+
+asm_header
+----------
+
+Checks that assembly files in a `go_library`_ may include ``"go_asm.h"``,
+generated by the compiler. Verifies `#1262`_.
+
+package_height
+--------------
+
+Checks that when a library embeds another library, the embedder's dependencies
+may override the embeddee's dependencies. Verifies `#1772`_.
+
+import_alias_test
+-----------------
+
+Checks that a library may import another library using one of the strings
+listed in ``importpath_aliases``. This is the basic mechanism for minimal
+module compatibility. Verifies `#2058`_.
+
+embedsrcs_test
+--------------
+
+Checks that `go_library`_ can match ``//go:embed`` directives to files listed
+in the ``embedsrcs`` attribute and can pass those files to the compiler.
+
+embedsrcs_error_test
+--------------------
+
+Verifies common errors with ``//go:embed`` directives are correctly reported.
+
+no_srcs_test
+------------
+
+Verifies that `go_library`_ targets without Go source files build concurrently,
+even unsandboxed, and reproducibly. Verifies `#3558`_. \ No newline at end of file
diff --git a/tests/core/go_library/def.bzl b/tests/core/go_library/def.bzl
new file mode 100644
index 00000000..613ea84d
--- /dev/null
+++ b/tests/core/go_library/def.bzl
@@ -0,0 +1,22 @@
+def _embedsrcs_files_impl(ctx):
+ name = ctx.attr.name
+ dir = ctx.actions.declare_directory(name)
+ args = [dir.path] + ctx.attr.files
+ ctx.actions.run(
+ outputs = [dir],
+ executable = ctx.executable._gen,
+ arguments = args,
+ )
+ return [DefaultInfo(files = depset([dir]))]
+
+embedsrcs_files = rule(
+ implementation = _embedsrcs_files_impl,
+ attrs = {
+ "files": attr.string_list(),
+ "_gen": attr.label(
+ default = ":gen_embedsrcs_files",
+ executable = True,
+ cfg = "exec",
+ ),
+ },
+)
diff --git a/tests/core/go_library/embedsrcs_error_test.go b/tests/core/go_library/embedsrcs_error_test.go
new file mode 100644
index 00000000..73629ddf
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_error_test.go
@@ -0,0 +1,138 @@
+// Copyright 2021 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.
+
+package embedsrcs_errors
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "invalid",
+ srcs = ["invalid.go"],
+ importpath = "invalid",
+)
+
+go_library(
+ name = "none",
+ srcs = ["none.go"],
+ importpath = "none",
+)
+
+go_library(
+ name = "multi_dir",
+ srcs = [
+ "a.go",
+ "b/b.go",
+ ],
+ embedsrcs = [
+ "a.txt",
+ "b/b.txt",
+ ],
+ importpath = "multi_dir",
+)
+
+go_library(
+ name = "embeds_vcs_dir",
+ srcs = ["c/c.go"],
+ embedsrcs = ["c/.bzr/c.txt"],
+ importpath = "embeds_vcs_dir",
+)
+-- invalid.go --
+package invalid
+
+import _ "embed"
+
+//go:embed ..
+var x string
+-- none.go --
+package none
+
+import _ "embed"
+
+//go:embed none
+var x string
+-- a.go --
+package a
+
+import _ "embed"
+
+//go:embed a.txt
+var x string
+-- a.txt --
+-- b/b.go --
+package a
+
+import _ "embed"
+
+//go:embed b.txt
+var y string
+-- b/b.txt --
+-- c/c.go --
+package a
+
+import _ "embed"
+
+//go:embed .bzr
+var z string
+-- c/.bzr/c.txt --
+`,
+ })
+}
+
+func Test(t *testing.T) {
+ for _, test := range []struct {
+ desc, target, want string
+ }{
+ {
+ desc: "invalid",
+ target: "//:invalid",
+ want: "invalid pattern syntax",
+ },
+ {
+ desc: "none",
+ target: "//:none",
+ want: "could not embed none: no matching files found",
+ },
+ {
+ desc: "multi_dir",
+ target: "//:multi_dir",
+ want: "source files with //go:embed should be in same directory",
+ },
+ {
+ desc: "embeds_vcs_dir",
+ target: "//:embeds_vcs_dir",
+ want: "could not embed .bzr: cannot embed directory .bzr: invalid name .bzr",
+ },
+ } {
+ t.Run(test.desc, func(t *testing.T) {
+ err := bazel_testing.RunBazel("build", test.target)
+ if err == nil {
+ t.Fatalf("expected error matching %q", test.want)
+ }
+ if errMsg := err.Error(); !strings.Contains(errMsg, test.want) {
+ t.Fatalf("expected error matching %q; got %v", test.want, errMsg)
+ }
+ })
+ }
+}
diff --git a/tests/core/go_library/embedsrcs_gen_test.go.in b/tests/core/go_library/embedsrcs_gen_test.go.in
new file mode 100644
index 00000000..a845b48e
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_gen_test.go.in
@@ -0,0 +1,20 @@
+// Copyright 2021 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.
+
+package embedsrcs
+
+import "embed"
+
+//go:embed embedsrcs_test.go
+var gen embed.FS
diff --git a/tests/core/go_library/embedsrcs_simple_test.go b/tests/core/go_library/embedsrcs_simple_test.go
new file mode 100644
index 00000000..32b3fdee
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_simple_test.go
@@ -0,0 +1,6 @@
+package embedsrcs_simple_test
+
+import _ "embed"
+
+//go:embed embedsrcs_static/no
+var no []byte
diff --git a/tests/core/go_library/embedsrcs_static/contains_hidden/.hidden b/tests/core/go_library/embedsrcs_static/contains_hidden/.hidden
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_static/contains_hidden/.hidden
diff --git a/tests/core/go_library/embedsrcs_static/contains_hidden/.hidden_dir/.env b/tests/core/go_library/embedsrcs_static/contains_hidden/.hidden_dir/.env
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_static/contains_hidden/.hidden_dir/.env
diff --git a/tests/core/go_library/embedsrcs_static/contains_hidden/.hidden_dir/visible_file b/tests/core/go_library/embedsrcs_static/contains_hidden/.hidden_dir/visible_file
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_static/contains_hidden/.hidden_dir/visible_file
diff --git a/tests/core/go_library/embedsrcs_static/contains_hidden/_hidden_dir/.bashrc b/tests/core/go_library/embedsrcs_static/contains_hidden/_hidden_dir/.bashrc
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_static/contains_hidden/_hidden_dir/.bashrc
diff --git a/tests/core/go_library/embedsrcs_static/contains_hidden/_hidden_dir/_hidden_file b/tests/core/go_library/embedsrcs_static/contains_hidden/_hidden_dir/_hidden_file
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_static/contains_hidden/_hidden_dir/_hidden_file
diff --git a/tests/core/go_library/embedsrcs_static/contains_hidden/_hidden_dir/visible_file b/tests/core/go_library/embedsrcs_static/contains_hidden/_hidden_dir/visible_file
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_static/contains_hidden/_hidden_dir/visible_file
diff --git a/tests/core/go_library/embedsrcs_static/contains_hidden/visible/.bzr/file-under-version-control b/tests/core/go_library/embedsrcs_static/contains_hidden/visible/.bzr/file-under-version-control
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_static/contains_hidden/visible/.bzr/file-under-version-control
diff --git a/tests/core/go_library/embedsrcs_static/contains_hidden/visible/visible_file b/tests/core/go_library/embedsrcs_static/contains_hidden/visible/visible_file
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_static/contains_hidden/visible/visible_file
diff --git a/tests/core/go_library/embedsrcs_static/dir/_no b/tests/core/go_library/embedsrcs_static/dir/_no
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_static/dir/_no
diff --git a/tests/core/go_library/embedsrcs_static/dir/f b/tests/core/go_library/embedsrcs_static/dir/f
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_static/dir/f
diff --git a/tests/core/go_library/embedsrcs_static/file b/tests/core/go_library/embedsrcs_static/file
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_static/file
diff --git a/tests/core/go_library/embedsrcs_static/glob/_hidden b/tests/core/go_library/embedsrcs_static/glob/_hidden
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_static/glob/_hidden
diff --git a/tests/core/go_library/embedsrcs_static/glob/f b/tests/core/go_library/embedsrcs_static/glob/f
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_static/glob/f
diff --git a/tests/core/go_library/embedsrcs_static/no b/tests/core/go_library/embedsrcs_static/no
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_static/no
diff --git a/tests/core/go_library/embedsrcs_test.go b/tests/core/go_library/embedsrcs_test.go
new file mode 100644
index 00000000..0a4506e6
--- /dev/null
+++ b/tests/core/go_library/embedsrcs_test.go
@@ -0,0 +1,199 @@
+// Copyright 2021 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.
+
+package embedsrcs
+
+import (
+ "bytes"
+ "embed"
+ "io/fs"
+ "strings"
+ "testing"
+)
+
+//go:embed embedsrcs_test.go
+var self embed.FS
+
+//go:embed embedsrcs_static/file embedsrcs_static/dir embedsrcs_static/glob/*
+var static embed.FS
+
+//go:embed embedsrcs_dynamic/file embedsrcs_dynamic/dir embedsrcs_dynamic/glob/*
+var dynamic embed.FS
+
+//go:embed embedsrcs_transitioned
+var transitioned embed.FS
+
+//go:embed *
+var star embed.FS
+
+//go:embed all:embedsrcs_static/contains_hidden
+var all embed.FS
+
+//go:embed embedsrcs_static/contains_hidden
+var allButHidden embed.FS
+
+func TestFiles(t *testing.T) {
+ for _, test := range []struct {
+ desc string
+ fsys fs.FS
+ want []string
+ }{
+ {
+ desc: "self",
+ fsys: self,
+ want: []string{
+ ".",
+ "embedsrcs_test.go",
+ },
+ },
+ {
+ desc: "gen",
+ fsys: gen,
+ want: []string{
+ ".",
+ "embedsrcs_test.go",
+ },
+ },
+ {
+ desc: "static",
+ fsys: static,
+ want: []string{
+ ".",
+ "embedsrcs_static",
+ "embedsrcs_static/dir",
+ "embedsrcs_static/dir/f",
+ "embedsrcs_static/file",
+ "embedsrcs_static/glob",
+ "embedsrcs_static/glob/_hidden",
+ "embedsrcs_static/glob/f",
+ },
+ },
+ {
+ desc: "dynamic",
+ fsys: dynamic,
+ want: []string{
+ ".",
+ "embedsrcs_dynamic",
+ "embedsrcs_dynamic/dir",
+ "embedsrcs_dynamic/dir/f",
+ "embedsrcs_dynamic/file",
+ "embedsrcs_dynamic/glob",
+ "embedsrcs_dynamic/glob/_hidden",
+ "embedsrcs_dynamic/glob/f",
+ },
+ },
+ {
+ desc: "transitioned",
+ fsys: transitioned,
+ want: []string{
+ ".",
+ "embedsrcs_transitioned",
+ },
+ },
+ {
+ desc: "star",
+ fsys: star,
+ want: []string{
+ ".",
+ "embedsrcs_dynamic",
+ "embedsrcs_dynamic/dir",
+ "embedsrcs_dynamic/dir/f",
+ "embedsrcs_dynamic/empty",
+ "embedsrcs_dynamic/file",
+ "embedsrcs_dynamic/glob",
+ "embedsrcs_dynamic/glob/f",
+ "embedsrcs_dynamic/no",
+ "embedsrcs_static",
+ "embedsrcs_static/contains_hidden",
+ "embedsrcs_static/contains_hidden/visible",
+ "embedsrcs_static/contains_hidden/visible/visible_file",
+ "embedsrcs_static/dir",
+ "embedsrcs_static/dir/f",
+ "embedsrcs_static/file",
+ "embedsrcs_static/glob",
+ "embedsrcs_static/glob/f",
+ "embedsrcs_static/no",
+ "embedsrcs_test.go",
+ "embedsrcs_transitioned",
+ },
+ },
+ {
+ desc: "all",
+ fsys: all,
+ want: []string{
+ ".",
+ "embedsrcs_static",
+ "embedsrcs_static/contains_hidden",
+ "embedsrcs_static/contains_hidden/.hidden",
+ "embedsrcs_static/contains_hidden/.hidden_dir",
+ "embedsrcs_static/contains_hidden/.hidden_dir/.env",
+ "embedsrcs_static/contains_hidden/.hidden_dir/visible_file",
+ "embedsrcs_static/contains_hidden/_hidden_dir",
+ "embedsrcs_static/contains_hidden/_hidden_dir/.bashrc",
+ "embedsrcs_static/contains_hidden/_hidden_dir/_hidden_file",
+ "embedsrcs_static/contains_hidden/_hidden_dir/visible_file",
+ "embedsrcs_static/contains_hidden/visible",
+ "embedsrcs_static/contains_hidden/visible/visible_file",
+ },
+ },
+ {
+ desc: "allButHidden",
+ fsys: allButHidden,
+ want: []string{
+ ".",
+ "embedsrcs_static",
+ "embedsrcs_static/contains_hidden",
+ "embedsrcs_static/contains_hidden/visible",
+ "embedsrcs_static/contains_hidden/visible/visible_file",
+ },
+ },
+ } {
+ t.Run(test.desc, func(t *testing.T) {
+ got, err := listFiles(test.fsys)
+ if err != nil {
+ t.Fatal(err)
+ }
+ gotStr := strings.Join(got, "\n")
+ wantStr := strings.Join(test.want, "\n")
+ if gotStr != wantStr {
+ t.Errorf("got:\n%s\nwant:\n%s", gotStr, wantStr)
+ }
+ })
+ }
+}
+
+func listFiles(fsys fs.FS) ([]string, error) {
+ var files []string
+ err := fs.WalkDir(fsys, ".", func(path string, _ fs.DirEntry, err error) error {
+ if err != nil {
+ return err
+ }
+ files = append(files, path)
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ return files, nil
+}
+
+func TestContent(t *testing.T) {
+ data, err := fs.ReadFile(self, "embedsrcs_test.go")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Contains(data, []byte("package embedsrcs")) {
+ t.Error("embedded content did not contain package declaration")
+ }
+}
diff --git a/tests/core/go_library/empty_bar.go b/tests/core/go_library/empty_bar.go
new file mode 100644
index 00000000..d73206c4
--- /dev/null
+++ b/tests/core/go_library/empty_bar.go
@@ -0,0 +1,3 @@
+// +build ignore
+
+package bar
diff --git a/tests/core/go_library/empty_baz.s b/tests/core/go_library/empty_baz.s
new file mode 100644
index 00000000..15934b3b
--- /dev/null
+++ b/tests/core/go_library/empty_baz.s
@@ -0,0 +1 @@
+// +build ignore
diff --git a/tests/core/go_library/empty_foo.go b/tests/core/go_library/empty_foo.go
new file mode 100644
index 00000000..ce414ed6
--- /dev/null
+++ b/tests/core/go_library/empty_foo.go
@@ -0,0 +1,3 @@
+// +build ignore
+
+package foo
diff --git a/tests/core/go_library/empty_main.go b/tests/core/go_library/empty_main.go
new file mode 100644
index 00000000..38dd16da
--- /dev/null
+++ b/tests/core/go_library/empty_main.go
@@ -0,0 +1,3 @@
+package main
+
+func main() {}
diff --git a/tests/core/go_library/gen_embedsrcs_files.go b/tests/core/go_library/gen_embedsrcs_files.go
new file mode 100644
index 00000000..68ff2fef
--- /dev/null
+++ b/tests/core/go_library/gen_embedsrcs_files.go
@@ -0,0 +1,51 @@
+// Copyright 2021 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.
+
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+func main() {
+ dir := os.Args[1]
+ files := os.Args[2:]
+ if err := run(dir, files); err != nil {
+ fmt.Fprintf(os.Stderr, "%v\n", err)
+ os.Exit(1)
+ }
+}
+
+func run(dir string, files []string) error {
+ for _, file := range files {
+ path := filepath.Join(dir, file)
+ if strings.HasSuffix(path, "/") {
+ if err := os.MkdirAll(path, 0777); err != nil {
+ return err
+ }
+ } else {
+ if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil {
+ return err
+ }
+ if err := ioutil.WriteFile(path, nil, 0666); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
diff --git a/tests/core/go_library/import_alias_a_v2.go b/tests/core/go_library/import_alias_a_v2.go
new file mode 100644
index 00000000..66326f94
--- /dev/null
+++ b/tests/core/go_library/import_alias_a_v2.go
@@ -0,0 +1,17 @@
+// Copyright 2019 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.
+
+package a
+
+const A = "import_alias/a/v2"
diff --git a/tests/core/go_library/import_alias_b.go b/tests/core/go_library/import_alias_b.go
new file mode 100644
index 00000000..1fa79977
--- /dev/null
+++ b/tests/core/go_library/import_alias_b.go
@@ -0,0 +1,17 @@
+// Copyright 2019 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.
+
+package b
+
+const B = "import_alias/b"
diff --git a/tests/core/go_library/import_alias_test.go b/tests/core/go_library/import_alias_test.go
new file mode 100644
index 00000000..aabec973
--- /dev/null
+++ b/tests/core/go_library/import_alias_test.go
@@ -0,0 +1,33 @@
+// Copyright 2019 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.
+
+package import_alias
+
+import (
+ "import_alias/a"
+ "import_alias/b"
+ "testing"
+)
+
+func TestA(t *testing.T) {
+ if a.A != "import_alias/a/v2" {
+ t.Errorf("got %q; want %q", a.A, "import_alias/a/v2")
+ }
+}
+
+func TestB(t *testing.T) {
+ if b.B != "import_alias/b" {
+ t.Errorf("got %q; want %q", b.B, "import_alias/b")
+ }
+}
diff --git a/tests/core/go_library/inc.go b/tests/core/go_library/inc.go
new file mode 100644
index 00000000..bb5e9272
--- /dev/null
+++ b/tests/core/go_library/inc.go
@@ -0,0 +1 @@
+package inc
diff --git a/tests/core/go_library/inc_asmhdr.s b/tests/core/go_library/inc_asmhdr.s
new file mode 100644
index 00000000..230bbe2f
--- /dev/null
+++ b/tests/core/go_library/inc_asmhdr.s
@@ -0,0 +1 @@
+#include "go_asm.h"
diff --git a/tests/core/go_library/inc_bar.s b/tests/core/go_library/inc_bar.s
new file mode 100644
index 00000000..47eaec6b
--- /dev/null
+++ b/tests/core/go_library/inc_bar.s
@@ -0,0 +1 @@
+#include "inc_foo.s"
diff --git a/tests/core/go_library/inc_foo.s b/tests/core/go_library/inc_foo.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_library/inc_foo.s
diff --git a/tests/core/go_library/no_srcs_test.go b/tests/core/go_library/no_srcs_test.go
new file mode 100644
index 00000000..8e6bebc0
--- /dev/null
+++ b/tests/core/go_library/no_srcs_test.go
@@ -0,0 +1,78 @@
+// Copyright 2021 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.
+
+package no_srcs
+
+import (
+ "bytes"
+ "os"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+[
+ go_library(
+ name = "lib_" + str(i),
+ srcs = [],
+ importpath = "example.com/some/path",
+ )
+ for i in range(1000)
+]
+`,
+ })
+}
+
+func Test(t *testing.T) {
+ commonArgs := []string{
+ "--spawn_strategy=local",
+ "--compilation_mode=dbg",
+ }
+
+ if err := bazel_testing.RunBazel(append([]string{"build", "//..."}, commonArgs...)...); err != nil {
+ t.Fatal(err)
+ }
+
+ out, err := bazel_testing.BazelOutput(append([]string{"cquery", "--output=files", "//..."}, commonArgs...)...)
+ if err != nil {
+ t.Fatal(err)
+ }
+ archives := strings.Split(strings.TrimSpace(string(out)), "\n")
+
+ if len(archives) != 1000 {
+ t.Fatalf("expected 1000 archives, got %d", len(archives))
+ }
+
+ referenceContent, err := os.ReadFile(archives[0])
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ for _, archive := range archives {
+ content, err := os.ReadFile(archive)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(content, referenceContent) {
+ t.Fatalf("expected all archives to be identical, got:\n\n%s\n\n%s\n", string(content), string(referenceContent))
+ }
+ }
+}
diff --git a/tests/core/go_library/package_height.go b/tests/core/go_library/package_height.go
new file mode 100644
index 00000000..cafb5faf
--- /dev/null
+++ b/tests/core/go_library/package_height.go
@@ -0,0 +1,6 @@
+package height
+
+import "package_height/embed"
+import "package_height/dep"
+
+var X = embed.T{F: dep.T{}}
diff --git a/tests/core/go_library/package_height_dep_deep.go b/tests/core/go_library/package_height_dep_deep.go
new file mode 100644
index 00000000..139a805d
--- /dev/null
+++ b/tests/core/go_library/package_height_dep_deep.go
@@ -0,0 +1,7 @@
+package dep
+
+import "os"
+
+type T struct {
+ F *os.File
+}
diff --git a/tests/core/go_library/package_height_dep_shallow.go b/tests/core/go_library/package_height_dep_shallow.go
new file mode 100644
index 00000000..1902c035
--- /dev/null
+++ b/tests/core/go_library/package_height_dep_shallow.go
@@ -0,0 +1,3 @@
+package dep
+
+type T struct{}
diff --git a/tests/core/go_library/package_height_embeddee.go b/tests/core/go_library/package_height_embeddee.go
new file mode 100644
index 00000000..0c36a32a
--- /dev/null
+++ b/tests/core/go_library/package_height_embeddee.go
@@ -0,0 +1,7 @@
+package embed
+
+import "package_height/dep"
+
+type T struct {
+ F dep.T
+}
diff --git a/tests/core/go_library/package_height_embedder.go b/tests/core/go_library/package_height_embedder.go
new file mode 100644
index 00000000..81a00369
--- /dev/null
+++ b/tests/core/go_library/package_height_embedder.go
@@ -0,0 +1,3 @@
+package embed
+
+var X = T{}
diff --git a/tests/core/go_path/BUILD.bazel b/tests/core/go_path/BUILD.bazel
new file mode 100644
index 00000000..59aea97c
--- /dev/null
+++ b/tests/core/go_path/BUILD.bazel
@@ -0,0 +1,81 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_path", "go_test")
+
+test_suite(name = "go_path")
+
+[go_path(
+ name = mode + "_path",
+ testonly = True,
+ data = ["extra.txt"],
+ include_pkg = True,
+ mode = mode,
+ deps = [
+ "//tests/core/go_path/cmd/bin",
+ "//tests/core/go_path/cmd/bin:cross",
+ "//tests/core/go_path/pkg/lib:embed_test",
+ "//tests/core/go_path/pkg/lib:go_default_library",
+ "//tests/core/go_path/pkg/lib:go_default_test",
+ "//tests/core/go_path/pkg/lib:vendored",
+ ],
+) for mode in ("archive", "copy")]
+
+go_path(
+ name = "transition_path",
+ testonly = True,
+ data = ["extra.txt"],
+ include_pkg = True,
+ mode = "copy",
+ deps = ["//tests/core/go_path/cmd/bin:pie"],
+)
+
+go_path(
+ name = "nodata_path",
+ testonly = True,
+ data = ["extra.txt"],
+ include_data = False,
+ mode = "copy",
+ deps = ["//tests/core/go_path/pkg/lib:go_default_library"],
+)
+
+go_path(
+ name = "notransitive_path",
+ testonly = True,
+ include_transitive = False,
+ mode = "copy",
+ deps = ["//tests/core/go_path/pkg/lib:go_default_library"],
+)
+
+go_path(
+ name = "embed_path",
+ mode = "copy",
+ deps = ["//tests/core/go_path/pkg/lib:generated_embeded"],
+)
+
+go_path(
+ name = "embed_no_srcs_path",
+ mode = "copy",
+ deps = ["//tests/core/go_path/pkg/lib:generated_embeded_no_srcs"],
+)
+
+go_test(
+ name = "go_path_test",
+ srcs = ["go_path_test.go"],
+ args = [
+ "-archive_path=$(location :archive_path)",
+ "-copy_path=$(location :copy_path)",
+ "-nodata_path=$(location :nodata_path)",
+ "-embed_path=$(location :embed_path)",
+ "-embed_no_srcs_path=$(location :embed_no_srcs_path)",
+ "-notransitive_path=$(location :notransitive_path)",
+ ],
+ data = [
+ ":archive_path",
+ ":copy_path",
+ ":embed_no_srcs_path",
+ ":embed_path",
+ ":nodata_path",
+ ":notransitive_path",
+ ":transition_path",
+ ],
+ rundir = ".",
+ deps = ["//go/tools/bazel:go_default_library"],
+)
diff --git a/tests/core/go_path/README.rst b/tests/core/go_path/README.rst
new file mode 100644
index 00000000..6d086086
--- /dev/null
+++ b/tests/core/go_path/README.rst
@@ -0,0 +1,12 @@
+Basic go_path functionality
+===========================
+
+.. _go_path: /docs/go/core/rules.md#_go_path
+
+Tests to ensure the basic features of `go_path`_ are working as expected.
+
+go_path_test
+------------
+
+Consumes `go_path`_ rules built for the same set of packages in archive, copy,
+and link modes and verifies that expected files are present in each mode.
diff --git a/tests/core/go_path/cmd/bin/BUILD.bazel b/tests/core/go_path/cmd/bin/BUILD.bazel
new file mode 100644
index 00000000..08f4e6dd
--- /dev/null
+++ b/tests/core/go_path/cmd/bin/BUILD.bazel
@@ -0,0 +1,30 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary")
+
+go_binary(
+ name = "bin",
+ srcs = ["bin.go"],
+ data = ["bin.go"], # test duplicate
+ importpath = "example.com/repo/cmd/bin",
+ visibility = ["//visibility:public"],
+)
+
+go_binary(
+ name = "pie",
+ srcs = ["bin.go"],
+ importpath = "example.com/repo/cmd/bin",
+ linkmode = "pie",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//tests/core/go_path/pkg/lib:go_default_library",
+ ],
+)
+
+go_binary(
+ name = "cross",
+ srcs = ["bin.go"],
+ goarch = "arm",
+ goos = "plan9",
+ importpath = "example.com/repo/cmd/bin",
+ pure = "on",
+ visibility = ["//visibility:public"],
+)
diff --git a/tests/core/go_path/cmd/bin/bin.go b/tests/core/go_path/cmd/bin/bin.go
new file mode 100644
index 00000000..da29a2ca
--- /dev/null
+++ b/tests/core/go_path/cmd/bin/bin.go
@@ -0,0 +1,4 @@
+package main
+
+func main() {
+}
diff --git a/tests/core/go_path/extra.txt b/tests/core/go_path/extra.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_path/extra.txt
diff --git a/tests/core/go_path/go_path_test.go b/tests/core/go_path/go_path_test.go
new file mode 100644
index 00000000..23e27cb8
--- /dev/null
+++ b/tests/core/go_path/go_path_test.go
@@ -0,0 +1,205 @@
+/* Copyright 2018 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.
+*/
+
+package go_path
+
+import (
+ "archive/zip"
+ "flag"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel"
+)
+
+var copyPath, embedPath, embedNoSrcsPath, archivePath, nodataPath, notransitivePath string
+
+var defaultMode = runtime.GOOS + "_" + runtime.GOARCH
+
+var files = []string{
+ "extra.txt",
+ "src/",
+ "-src/example.com/repo/cmd/bin/bin",
+ "-src/testmain/testmain.go",
+ "src/example.com/repo/cmd/bin/bin.go",
+ "src/example.com/repo/pkg/lib/lib.go",
+ "src/example.com/repo/pkg/lib/embedded_src.txt",
+ "src/example.com/repo/pkg/lib/template/index.html.tmpl",
+ "src/example.com/repo/pkg/lib/embed_test.go",
+ "src/example.com/repo/pkg/lib/internal_test.go",
+ "src/example.com/repo/pkg/lib/external_test.go",
+ "-src/example.com/repo/pkg/lib_test/embed_test.go",
+ "src/example.com/repo/pkg/lib/data.txt",
+ "src/example.com/repo/pkg/lib/testdata/testdata.txt",
+ "src/example.com/repo/vendor/example.com/repo2/vendored.go",
+ "pkg/" + defaultMode + "/example.com/repo/cmd/bin.a",
+ "pkg/" + defaultMode + "/example.com/repo/pkg/lib.a",
+ "pkg/" + defaultMode + "/example.com/repo/vendor/example.com/repo2.a",
+ "pkg/plan9_arm/example.com/repo/cmd/bin.a",
+}
+
+func TestMain(m *testing.M) {
+ flag.StringVar(&copyPath, "copy_path", "", "path to copied go_path")
+ flag.StringVar(&archivePath, "archive_path", "", "path to archive go_path")
+ flag.StringVar(&nodataPath, "nodata_path", "", "path to go_path without data")
+ flag.StringVar(&embedPath, "embed_path", "", "path to go_path with embedsrcs")
+ flag.StringVar(&embedNoSrcsPath, "embed_no_srcs_path", "", "path to go_path with embedsrcs")
+ flag.StringVar(&notransitivePath, "notransitive_path", "", "path to go_path without transitive dependencies")
+ flag.Parse()
+ os.Exit(m.Run())
+}
+
+func TestCopyPath(t *testing.T) {
+ if copyPath == "" {
+ t.Fatal("-copy_path not set")
+ }
+ checkPath(t, copyPath, files)
+}
+
+func TestEmbedPath(t *testing.T) {
+ if embedPath == "" {
+ t.Fatal("-embed_path not set")
+ }
+ files := []string{
+ "src/lib/embed_test.go",
+ "src/lib/embedded_src.txt",
+ "src/lib/generated_embeded.go",
+ }
+ checkPath(t, embedPath, files)
+}
+
+func TestEmbedNoSrcsPath(t *testing.T) {
+ if embedNoSrcsPath == "" {
+ t.Fatal("-embed_no_srcs_path not set")
+ }
+ files := []string{
+ "src/lib/embedded_src.txt",
+ "src/lib/generated_embeded_no_srcs.go",
+ }
+ checkPath(t, embedNoSrcsPath, files)
+}
+
+func TestArchivePath(t *testing.T) {
+ if archivePath == "" {
+ t.Fatal("-archive_path not set")
+ }
+ dir, err := ioutil.TempDir(os.Getenv("TEST_TEMPDIR"), "TestArchivePath")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ path, err := bazel.Runfile(archivePath)
+ if err != nil {
+ t.Fatalf("Could not find runfile %s: %q", archivePath, err)
+ }
+
+ z, err := zip.OpenReader(path)
+ if err != nil {
+ t.Fatalf("error opening zip: %v", err)
+ }
+ defer z.Close()
+ for _, f := range z.File {
+ r, err := f.Open()
+ if err != nil {
+ t.Fatalf("error reading file %s: %v", f.Name, err)
+ }
+ dstPath := filepath.Join(dir, filepath.FromSlash(f.Name))
+ if err := os.MkdirAll(filepath.Dir(dstPath), 0777); err != nil {
+ t.Fatalf("error creating directory %s: %v", filepath.Dir(dstPath), err)
+ }
+ w, err := os.Create(dstPath)
+ if err != nil {
+ t.Fatalf("error creating file %s: %v", dstPath, err)
+ }
+ if _, err := io.Copy(w, r); err != nil {
+ w.Close()
+ t.Fatalf("error writing file %s: %v", dstPath, err)
+ }
+ if err := w.Close(); err != nil {
+ t.Fatalf("error closing file %s: %v", dstPath, err)
+ }
+ }
+
+ checkPath(t, dir, files)
+}
+
+func TestNoDataPath(t *testing.T) {
+ if nodataPath == "" {
+ t.Fatal("-nodata_path not set")
+ }
+ files := []string{
+ "extra.txt",
+ "src/example.com/repo/pkg/lib/lib.go",
+ "-src/example.com/repo/pkg/lib/data.txt",
+ }
+ checkPath(t, nodataPath, files)
+}
+
+func TestNoTransitivePath(t *testing.T) {
+ if notransitivePath == "" {
+ t.Fatal("-notransitive_path not set")
+ }
+ files := []string{
+ "-src/example.com/repo/pkg/lib/transitive/transitive.go",
+ }
+ checkPath(t, notransitivePath, files)
+}
+
+// checkPath checks that dir contains a list of files. files is a list of
+// slash-separated paths relative to dir. Files that start with "-" should be
+// absent. Files that end with "/" should be directories.
+func checkPath(t *testing.T, dir string, files []string) {
+ if strings.HasPrefix(dir, "external") {
+ dir = filepath.Join(os.Getenv("TEST_SRCDIR"), strings.TrimPrefix(dir, "external/"))
+ }
+
+ for _, f := range files {
+ wantDir := strings.HasSuffix(f, "/")
+ wantAbsent := false
+ if strings.HasPrefix(f, "-") {
+ f = f[1:]
+ wantAbsent = true
+ }
+ path := filepath.Join(dir, filepath.FromSlash(f))
+ st, err := os.Stat(path)
+ if wantAbsent {
+ if err == nil {
+ t.Errorf("found %s: should not be present", path)
+ } else if !os.IsNotExist(err) {
+ t.Error(err)
+ }
+ } else {
+ if err != nil {
+ if os.IsNotExist(err) {
+ t.Errorf("%s is missing", path)
+ } else {
+ t.Error(err)
+ }
+ continue
+ }
+ if st.IsDir() && !wantDir {
+ t.Errorf("%s: got directory; wanted file", path)
+ } else if !st.IsDir() && wantDir {
+ t.Errorf("%s: got file; wanted directory", path)
+ }
+ }
+ }
+}
diff --git a/tests/core/go_path/pkg/lib/BUILD.bazel b/tests/core/go_path/pkg/lib/BUILD.bazel
new file mode 100644
index 00000000..68f7c0b4
--- /dev/null
+++ b/tests/core/go_path/pkg/lib/BUILD.bazel
@@ -0,0 +1,80 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
+load(":generated_embeded.bzl", "generated_embeded")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["lib.go"],
+ cgo = True,
+ data = [
+ "data.txt",
+ "testdata/testdata.txt",
+ ],
+ embedsrcs = [
+ "embedded_src.txt",
+ "renamed_embedded_src.txt",
+ "template/index.html.tmpl",
+ ],
+ importpath = "example.com/repo/pkg/lib",
+ visibility = ["//visibility:public"],
+ deps = [":transitive_lib"],
+)
+
+copy_file(
+ name = "rename_embedded_src.txt",
+ src = ":embedded_src.txt",
+ out = "renamed_embedded_src.txt",
+)
+
+generated_embeded(
+ name = "generated_embeded",
+ srcs = ["embed_test.go"],
+ embedsrcs = ["embedded_src.txt"],
+ importpath = "lib",
+ visibility = ["//visibility:public"],
+)
+
+generated_embeded(
+ name = "generated_embeded_no_srcs",
+ embedsrcs = ["embedded_src.txt"],
+ importpath = "lib",
+ visibility = ["//visibility:public"],
+)
+
+go_test(
+ name = "go_default_test",
+ srcs = [
+ "external_test.go",
+ "internal_test.go",
+ ],
+ importpath = "example.com/repo/pkg/lib",
+ visibility = ["//visibility:public"],
+)
+
+go_test(
+ name = "embed_test",
+ embed = [":embed_lib"],
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "embed_lib",
+ srcs = ["embed_test.go"],
+ importpath = "example.com/repo/pkg/lib",
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "vendored",
+ srcs = ["vendored.go"],
+ importmap = "example.com/repo/vendor/example.com/repo2",
+ importpath = "example.com/repo2",
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "transitive_lib",
+ srcs = ["transitive.go"],
+ importpath = "example.com/repo/pkg/lib/transitive",
+ visibility = ["//visibility:public"],
+)
diff --git a/tests/core/go_path/pkg/lib/data.txt b/tests/core/go_path/pkg/lib/data.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_path/pkg/lib/data.txt
diff --git a/tests/core/go_path/pkg/lib/embed_test.go b/tests/core/go_path/pkg/lib/embed_test.go
new file mode 100644
index 00000000..55c21f80
--- /dev/null
+++ b/tests/core/go_path/pkg/lib/embed_test.go
@@ -0,0 +1 @@
+package lib
diff --git a/tests/core/go_path/pkg/lib/embedded_src.txt b/tests/core/go_path/pkg/lib/embedded_src.txt
new file mode 100644
index 00000000..257cc564
--- /dev/null
+++ b/tests/core/go_path/pkg/lib/embedded_src.txt
@@ -0,0 +1 @@
+foo
diff --git a/tests/core/go_path/pkg/lib/external_test.go b/tests/core/go_path/pkg/lib/external_test.go
new file mode 100644
index 00000000..df64f213
--- /dev/null
+++ b/tests/core/go_path/pkg/lib/external_test.go
@@ -0,0 +1 @@
+package lib_test
diff --git a/tests/core/go_path/pkg/lib/generated_embeded.bzl b/tests/core/go_path/pkg/lib/generated_embeded.bzl
new file mode 100644
index 00000000..42bcf595
--- /dev/null
+++ b/tests/core/go_path/pkg/lib/generated_embeded.bzl
@@ -0,0 +1,71 @@
+# Copyright 2018 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:def.bzl",
+ "go_context",
+)
+
+def _gen_library_impl(ctx):
+ go = go_context(ctx)
+ libname = getattr(ctx.attr, "libname")
+ src = go.actions.declare_file(ctx.label.name + ".go")
+
+ embedsrcs = getattr(ctx.attr, "embedsrcs", [])
+
+ lines = [
+ "package " + libname,
+ "",
+ 'import _ "embed"',
+ "",
+ ]
+
+ i = 0
+ for e in embedsrcs:
+ for f in e.files.to_list():
+ lines.extend([
+ "//go:embed {}".format(f.basename),
+ "var embeddedSource{} string".format(i),
+ ])
+ i += 1
+
+ ctx.actions.write(src, "\n".join(lines))
+
+ library = go.new_library(go, srcs = [src])
+ source = go.library_to_source(go, ctx.attr, library, ctx.coverage_instrumented())
+ archive = go.archive(go, source)
+ return [
+ library,
+ source,
+ archive,
+ DefaultInfo(files = depset([archive.data.file])),
+ ]
+
+generated_embeded = rule(
+ _gen_library_impl,
+ attrs = {
+ "importpath": attr.string(mandatory = True),
+ "_go_context_data": attr.label(
+ default = "//:go_context_data",
+ ),
+ "srcs": attr.label_list(
+ allow_files = True,
+ ),
+ "embedsrcs": attr.label_list(
+ allow_files = True,
+ ),
+ "libname": attr.string(default = "lib"),
+ },
+ toolchains = ["@io_bazel_rules_go//go:toolchain"],
+)
diff --git a/tests/core/go_path/pkg/lib/internal_test.go b/tests/core/go_path/pkg/lib/internal_test.go
new file mode 100644
index 00000000..55c21f80
--- /dev/null
+++ b/tests/core/go_path/pkg/lib/internal_test.go
@@ -0,0 +1 @@
+package lib
diff --git a/tests/core/go_path/pkg/lib/lib.go b/tests/core/go_path/pkg/lib/lib.go
new file mode 100644
index 00000000..1434db9f
--- /dev/null
+++ b/tests/core/go_path/pkg/lib/lib.go
@@ -0,0 +1,15 @@
+package lib
+
+import (
+ "C"
+ _ "embed" // for go:embed
+)
+
+//go:embed embedded_src.txt
+var embeddedSource string
+
+//go:embed renamed_embedded_src.txt
+var renamedEmbeddedSource string
+
+//go:embed template/index.html.tmpl
+var indexTmpl string
diff --git a/tests/core/go_path/pkg/lib/template/index.html.tmpl b/tests/core/go_path/pkg/lib/template/index.html.tmpl
new file mode 100644
index 00000000..68a09ae6
--- /dev/null
+++ b/tests/core/go_path/pkg/lib/template/index.html.tmpl
@@ -0,0 +1 @@
+{{ .Content }}
diff --git a/tests/core/go_path/pkg/lib/testdata/testdata.txt b/tests/core/go_path/pkg/lib/testdata/testdata.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_path/pkg/lib/testdata/testdata.txt
diff --git a/tests/core/go_path/pkg/lib/transitive.go b/tests/core/go_path/pkg/lib/transitive.go
new file mode 100644
index 00000000..a505a296
--- /dev/null
+++ b/tests/core/go_path/pkg/lib/transitive.go
@@ -0,0 +1,5 @@
+package transitive
+
+var (
+ _ = ""
+)
diff --git a/tests/core/go_path/pkg/lib/vendored.go b/tests/core/go_path/pkg/lib/vendored.go
new file mode 100644
index 00000000..2355022f
--- /dev/null
+++ b/tests/core/go_path/pkg/lib/vendored.go
@@ -0,0 +1 @@
+package vendored
diff --git a/tests/core/go_plugin/BUILD.bazel b/tests/core/go_plugin/BUILD.bazel
new file mode 100644
index 00000000..ce07189d
--- /dev/null
+++ b/tests/core/go_plugin/BUILD.bazel
@@ -0,0 +1,16 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_test")
+
+test_suite(name = "go_plugin")
+
+go_test(
+ name = "go_default_test",
+ srcs = ["all_test.go"],
+ data = [":plugin"],
+)
+
+go_binary(
+ name = "plugin",
+ srcs = ["plugin.go"],
+ out = "plugin.so",
+ linkmode = "plugin",
+)
diff --git a/tests/core/go_plugin/README.rst b/tests/core/go_plugin/README.rst
new file mode 100644
index 00000000..55b0e295
--- /dev/null
+++ b/tests/core/go_plugin/README.rst
@@ -0,0 +1,16 @@
+Basic -buildmode=plugin functionality
+=====================================
+
+.. _go_binary: /docs/go/core/rules.md#_go_binary
+
+Tests to ensure the basic features of go_binary with linkmode="plugin" are
+working as expected.
+
+all_test
+--------
+
+1. Test that a go_binary_ rule can write its shared object file with a custom
+ name in the package directory (not the mode directory).
+
+2. Test that a plugin built using a go_binary_ rule can be loaded by a Go
+ program and that its symbols are working as expected.
diff --git a/tests/core/go_plugin/all_test.go b/tests/core/go_plugin/all_test.go
new file mode 100644
index 00000000..d74738b5
--- /dev/null
+++ b/tests/core/go_plugin/all_test.go
@@ -0,0 +1,33 @@
+package main_test
+
+import (
+ "os"
+ "plugin"
+ "testing"
+)
+
+const HelloWorld = "Hello, world!"
+
+func TestPluginCreated(t *testing.T) {
+ _, err := os.Stat("plugin.so")
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestPluginWorks(t *testing.T) {
+ p, err := plugin.Open("plugin.so")
+ if err != nil {
+ t.Error(err)
+ }
+
+ f, err := p.Lookup("Hi")
+ if err != nil {
+ t.Error(err)
+ }
+
+ helloWorld := f.(func() string)()
+ if helloWorld != HelloWorld {
+ t.Errorf("expected %#v, got %#v", HelloWorld, helloWorld)
+ }
+}
diff --git a/tests/core/go_plugin/plugin.go b/tests/core/go_plugin/plugin.go
new file mode 100644
index 00000000..b7db8d2a
--- /dev/null
+++ b/tests/core/go_plugin/plugin.go
@@ -0,0 +1,7 @@
+package main
+
+const HelloWorld = "Hello, world!"
+
+func Hi() string { return HelloWorld }
+
+func main() {}
diff --git a/tests/core/go_plugin_with_proto_library/BUILD.bazel b/tests/core/go_plugin_with_proto_library/BUILD.bazel
new file mode 100644
index 00000000..468d8b35
--- /dev/null
+++ b/tests/core/go_plugin_with_proto_library/BUILD.bazel
@@ -0,0 +1,31 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_test")
+load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
+
+test_suite(name = "go_plugin_with_proto_library")
+
+go_test(
+ name = "go_default_test",
+ srcs = ["all_test.go"],
+ data = [":plugin"],
+ deps = [":validate"],
+)
+
+go_binary(
+ name = "plugin",
+ srcs = ["plugin.go"],
+ out = "plugin.so",
+ linkmode = "plugin",
+ deps = [":validate"],
+)
+
+proto_library(
+ name = "validate_proto",
+ srcs = ["validate.proto"],
+)
+
+go_proto_library(
+ name = "validate",
+ gc_goopts = ["-trimpath=$(BINDIR)=>."],
+ importpath = "go_plugin_with_proto_library/validate",
+ proto = ":validate_proto",
+)
diff --git a/tests/core/go_plugin_with_proto_library/README.rst b/tests/core/go_plugin_with_proto_library/README.rst
new file mode 100644
index 00000000..437a2cd9
--- /dev/null
+++ b/tests/core/go_plugin_with_proto_library/README.rst
@@ -0,0 +1,16 @@
+Go Plugin supporting protobufs
+==============================
+
+.. _go_binary: /go/core.rst#_go_binary
+
+Tests to ensure a protobuf can be included into a plugin and host.
+
+all_test
+--------
+
+1. Test that a go_binary_ rule can write its shared object file with a custom
+ name in the package directory (not the mode directory) when the plugin
+ depends on a protobuf.
+
+2. Test that a plugin with a protobuf dependency built using a go_binary_ rule
+ can be loaded by a Go program and that its symbols are working as expected.
diff --git a/tests/core/go_plugin_with_proto_library/all_test.go b/tests/core/go_plugin_with_proto_library/all_test.go
new file mode 100644
index 00000000..c09c6ef7
--- /dev/null
+++ b/tests/core/go_plugin_with_proto_library/all_test.go
@@ -0,0 +1,36 @@
+package main_test
+
+import (
+ "go_plugin_with_proto_library/validate"
+ "os"
+ "plugin"
+ "testing"
+)
+
+const RuleName = "test"
+
+func TestPluginCreated(t *testing.T) {
+ _, err := os.Stat("plugin.so")
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestPluginWorks(t *testing.T) {
+ p, err := plugin.Open("plugin.so")
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ symProto, err := p.Lookup("SomeProto")
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ proto := symProto.(*validate.MessageRules)
+ if *proto.Name != RuleName {
+ t.Errorf("expected %#v, got %#v", RuleName, proto.Name)
+ }
+}
diff --git a/tests/core/go_plugin_with_proto_library/plugin.go b/tests/core/go_plugin_with_proto_library/plugin.go
new file mode 100644
index 00000000..7197a140
--- /dev/null
+++ b/tests/core/go_plugin_with_proto_library/plugin.go
@@ -0,0 +1,7 @@
+package main
+
+import "go_plugin_with_proto_library/validate"
+
+var testValue = "test"
+
+var SomeProto = validate.MessageRules{Name: &testValue}
diff --git a/tests/core/go_plugin_with_proto_library/validate.proto b/tests/core/go_plugin_with_proto_library/validate.proto
new file mode 100644
index 00000000..759e8726
--- /dev/null
+++ b/tests/core/go_plugin_with_proto_library/validate.proto
@@ -0,0 +1,6 @@
+syntax = "proto2";
+package validate;
+
+message MessageRules {
+ required string name = 1;
+}
diff --git a/tests/core/go_proto_library/BUILD.bazel b/tests/core/go_proto_library/BUILD.bazel
new file mode 100644
index 00000000..0c1f8e23
--- /dev/null
+++ b/tests/core/go_proto_library/BUILD.bazel
@@ -0,0 +1,314 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
+load("@rules_proto//proto:defs.bzl", "proto_library")
+
+# Common rules
+proto_library(
+ name = "foo_proto",
+ srcs = ["foo.proto"],
+)
+
+go_proto_library(
+ name = "foo_go_proto",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/foo",
+ proto = ":foo_proto",
+)
+
+proto_library(
+ name = "bar_proto",
+ srcs = ["bar.proto"],
+ deps = [":foo_proto"],
+)
+
+go_proto_library(
+ name = "bar_go_proto",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/bar",
+ proto = ":bar_proto",
+ deps = [":foo_go_proto"],
+)
+
+proto_library(
+ name = "grpc_proto",
+ srcs = ["grpc.proto"],
+)
+
+# embed_test
+go_proto_library(
+ name = "embed_go_proto",
+ embed = [":extra_lib"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/foo",
+ proto = ":foo_proto",
+)
+
+go_library(
+ name = "extra_lib",
+ srcs = ["extra.go"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/foo",
+)
+
+go_test(
+ name = "embed_test",
+ srcs = ["embed_test.go"],
+ deps = [
+ ":embed_go_proto",
+ "@com_github_golang_protobuf//proto:go_default_library",
+ ],
+)
+
+# transitive_test
+go_proto_library(
+ name = "transitive_go_proto",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/bar",
+ proto = ":bar_proto",
+ deps = [":wrap_lib"],
+)
+
+go_library(
+ name = "wrap_lib",
+ srcs = ["extra.go"],
+ embed = [":foo_go_proto"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/foo",
+)
+
+go_test(
+ name = "transitive_test",
+ srcs = ["transitive_test.go"],
+ deps = [
+ ":transitive_go_proto",
+ ":wrap_lib",
+ ],
+)
+
+# proxy_test
+go_test(
+ name = "proxy_test",
+ srcs = ["proxy_test.go"],
+ deps = [":proxy_go_proto"],
+)
+
+go_proto_library(
+ name = "proxy_go_proto",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/proxy",
+ proto = ":proxy_proto",
+)
+
+proto_library(
+ name = "proxy_proto",
+ deps = [
+ ":proxy_a_proto",
+ ":proxy_b_proto",
+ ],
+)
+
+proto_library(
+ name = "proxy_a_proto",
+ srcs = ["proxy_a.proto"],
+)
+
+proto_library(
+ name = "proxy_b_proto",
+ srcs = ["proxy_b.proto"],
+)
+
+# protos_test (multiple entries in protos argument)
+go_test(
+ name = "protos_test",
+ srcs = ["protos_test.go"],
+ deps = [":protos_go_proto"],
+)
+
+go_test(
+ name = "protos_alias_test",
+ srcs = ["protos_alias_test.go"],
+ deps = [":protos_go_proto"],
+)
+
+go_proto_library(
+ name = "protos_go_proto",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/protos",
+ importpath_aliases = ["myalias/protos"],
+ protos = [
+ ":protos_a_proto",
+ ":protos_b_proto",
+ ],
+)
+
+proto_library(
+ name = "protos_a_proto",
+ srcs = ["protos_a.proto"],
+)
+
+proto_library(
+ name = "protos_b_proto",
+ srcs = ["protos_b.proto"],
+)
+
+# gofast test
+go_test(
+ name = "gofast_test",
+ srcs = ["gofast_test.go"],
+ deps = [":gofast_proto"],
+)
+
+go_proto_library(
+ name = "gofast_proto",
+ compilers = ["@io_bazel_rules_go//proto:gofast_proto"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/foo",
+ protos = [":foo_proto"],
+)
+
+# gofast gRPC test
+go_test(
+ name = "gofast_grpc_test",
+ srcs = ["gofast_grpc_test.go"],
+ deps = [":gofast_grpc"],
+)
+
+go_proto_library(
+ name = "gofast_grpc",
+ compilers = ["@io_bazel_rules_go//proto:gofast_grpc"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/grpc",
+ protos = [":grpc_proto"],
+)
+
+# gogofast test
+go_test(
+ name = "gogofast_test",
+ srcs = ["gogofast_test.go"],
+ deps = [":gogofast_proto"],
+)
+
+go_proto_library(
+ name = "gogofast_proto",
+ compilers = ["@io_bazel_rules_go//proto:gogofast_proto"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/foo",
+ protos = [":foo_proto"],
+)
+
+# gogofast gRPC test
+go_test(
+ name = "gogofast_grpc_test",
+ srcs = ["gogofast_grpc_test.go"],
+ deps = [":gogofast_grpc"],
+)
+
+go_proto_library(
+ name = "gogofast_grpc",
+ compilers = ["@io_bazel_rules_go//proto:gogofast_grpc"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/grpc",
+ protos = [":grpc_proto"],
+)
+
+# adjusted_import_test
+# TODO(#1851): uncomment when Bazel 0.22.0 is the minimum version.
+# go_test(
+# name = "adjusted_import_test",
+# srcs = ["adjusted_import_test.go"],
+# deps = [
+# ":adjusted_a_go_proto",
+# ":adjusted_b_go_library",
+# ":adjusted_c_go_proto",
+# ],
+# )
+
+# go_proto_library(
+# name = "adjusted_a_go_proto",
+# importpath = "adjusted/a",
+# proto = "adjusted_a_proto",
+# deps = [
+# ":adjusted_b_go_library",
+# ":adjusted_c_go_proto",
+# ],
+# )
+
+# proto_library(
+# name = "adjusted_a_proto",
+# srcs = ["adjusted_a.proto"],
+# import_prefix = "adjusted",
+# strip_import_prefix = "",
+# deps = [
+# ":adjusted_b_proto",
+# ":adjusted_c_proto",
+# ],
+# )
+
+# go_library(
+# name = "adjusted_b_go_library",
+# embed = [":adjusted_b_go_proto"],
+# importpath = "adjusted/b",
+# )
+
+# go_proto_library(
+# name = "adjusted_b_go_proto",
+# importpath = "adjusted/b",
+# proto = "adjusted_b_proto",
+# deps = [":adjusted_c_go_proto"],
+# )
+
+# proto_library(
+# name = "adjusted_b_proto",
+# srcs = ["adjusted_b.proto"],
+# import_prefix = "adjusted",
+# strip_import_prefix = "",
+# deps = [":adjusted_c_proto"],
+# )
+
+# go_proto_library(
+# name = "adjusted_c_go_proto",
+# importpath = "adjusted/c",
+# proto = ":adjusted_c_proto",
+# )
+
+# proto_library(
+# name = "adjusted_c_proto",
+# srcs = ["adjusted_c.proto"],
+# import_prefix = "adjusted",
+# strip_import_prefix = "",
+# )
+
+# proto_package_test
+proto_library(
+ name = "no_go_package_proto",
+ srcs = ["no_go_package.proto"],
+)
+
+go_proto_library(
+ name = "no_go_package_go_proto",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/package_name_derived_from_importpath",
+ protos = [":no_go_package_proto"],
+)
+
+go_test(
+ name = "proto_package_test",
+ srcs = ["proto_package_test.go"],
+ deps = [":no_go_package_go_proto"],
+)
+
+go_test(
+ name = "wkt_wrapper_test",
+ srcs = ["wkt_wrapper_test.go"],
+ deps = [
+ "//proto/wkt:any_go_proto",
+ "//proto/wkt:compiler_plugin_go_proto",
+ "//proto/wkt:descriptor_go_proto",
+ "//proto/wkt:duration_go_proto",
+ "//proto/wkt:empty_go_proto",
+ "//proto/wkt:field_mask_go_proto",
+ "//proto/wkt:source_context_go_proto",
+ "//proto/wkt:struct_go_proto",
+ "//proto/wkt:timestamp_go_proto",
+ "//proto/wkt:type_go_proto",
+ "//proto/wkt:wrappers_go_proto",
+ "@org_golang_google_protobuf//types/descriptorpb:go_default_library",
+ "@org_golang_google_protobuf//types/known/anypb:go_default_library",
+ "@org_golang_google_protobuf//types/known/durationpb:go_default_library",
+ "@org_golang_google_protobuf//types/known/emptypb:go_default_library",
+ "@org_golang_google_protobuf//types/known/fieldmaskpb:go_default_library",
+ "@org_golang_google_protobuf//types/known/sourcecontextpb:go_default_library",
+ "@org_golang_google_protobuf//types/known/structpb:go_default_library",
+ "@org_golang_google_protobuf//types/known/timestamppb:go_default_library",
+ "@org_golang_google_protobuf//types/known/typepb:go_default_library",
+ "@org_golang_google_protobuf//types/known/wrapperspb:go_default_library",
+ "@org_golang_google_protobuf//types/pluginpb:go_default_library",
+ ],
+)
diff --git a/tests/core/go_proto_library/README.rst b/tests/core/go_proto_library/README.rst
new file mode 100644
index 00000000..7696102a
--- /dev/null
+++ b/tests/core/go_proto_library/README.rst
@@ -0,0 +1,65 @@
+Basic go_proto_library functionality
+====================================
+
+.. _go_proto_library: /proto/core.rst#_go_proto_library
+.. _go_library: /docs/go/core/rules.md#_go_library
+.. _protobuf v1.26.0: https://github.com/protocolbuffers/protobuf-go/releases/tag/v1.26.0
+.. _#1422: https://github.com/bazelbuild/rules_go/issues/1422
+.. _#1596: https://github.com/bazelbuild/rules_go/issues/1596
+
+Tests to ensure the basic features of `go_proto_library`_ are working.
+
+.. contents::
+
+embed_test
+----------
+
+Checks that `go_proto_library`_ can embed rules that provide `GoLibrary`_.
+
+transitive_test
+---------------
+
+Checks that `go_proto_library`_ can import a proto dependency that is
+embedded in a `go_library`_. Verifies `#1422`_.
+
+adjusted_import_test
+--------------------
+
+Checks that `go_proto_library`_ can build ``proto_library`` with
+``import_prefix`` and ``strip_import_prefix``.
+
+gofast_test and gofast_grpc_test
+--------------------------------
+
+Checks that the gogo `gofast` compiler plugins build and link. In
+particular, these plugins only depoend on `github.com/golang/protobuf`.
+
+gogofast_test and gogofast_grpc_test
+------------------------------------
+
+Checks that the `gogofast` compiler plugins build and link. In
+particular, these plugins depend on both `github.com/gogo/protobuf`
+and `github.com/golang/protobuf`.
+
+proto_package_test
+------------------
+
+Checks that `go_proto_library`_ generates files with a package name based on
+``importpath``, not the proto package, when ``option go_package`` is not given.
+This changed in `protobuf v1.26.0`_: the import path must either be specified
+with an ``option go_package`` in each proto file or with an ``M`` flag passed
+in from ``go_proto_library``. Previously, the Go package name was derived from
+the proto package name. Previously verified `#1596`_.
+
+wkt_wrapper_test
+----------------
+
+Checks that most of the well known types in ``//proto/wkt`` are wrappers
+for packages in ``@org_golang_google_protobuf``. The proto types should be
+type aliases.
+
+protos_alias_test
+-----------------
+
+Checks that packages generated by `go_proto_library` can be imported using one of the strings
+listed in ``importpath_aliases``.
diff --git a/tests/core/go_proto_library/adjusted_a.proto b/tests/core/go_proto_library/adjusted_a.proto
new file mode 100644
index 00000000..d5538346
--- /dev/null
+++ b/tests/core/go_proto_library/adjusted_a.proto
@@ -0,0 +1,11 @@
+syntax = "proto3";
+
+import "adjusted/adjusted_b.proto";
+import "adjusted/adjusted_c.proto";
+
+package adjusted.a;
+
+message A {
+ adjusted.b.B x = 1;
+ adjusted.c.C y = 2;
+}
diff --git a/tests/core/go_proto_library/adjusted_b.proto b/tests/core/go_proto_library/adjusted_b.proto
new file mode 100644
index 00000000..e7828b84
--- /dev/null
+++ b/tests/core/go_proto_library/adjusted_b.proto
@@ -0,0 +1,9 @@
+syntax = "proto3";
+
+import "adjusted/adjusted_c.proto";
+
+package adjusted.b;
+
+message B {
+ adjusted.c.C b = 1;
+}
diff --git a/tests/core/go_proto_library/adjusted_c.proto b/tests/core/go_proto_library/adjusted_c.proto
new file mode 100644
index 00000000..500144c1
--- /dev/null
+++ b/tests/core/go_proto_library/adjusted_c.proto
@@ -0,0 +1,7 @@
+syntax = "proto3";
+
+package adjusted.c;
+
+message C {
+ int64 c = 1;
+}
diff --git a/tests/core/go_proto_library/adjusted_import_test.go b/tests/core/go_proto_library/adjusted_import_test.go
new file mode 100644
index 00000000..6c2856c5
--- /dev/null
+++ b/tests/core/go_proto_library/adjusted_import_test.go
@@ -0,0 +1,31 @@
+/* Copyright 2018 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.
+*/
+
+package adjusted_import_test
+
+import (
+ "testing"
+
+ a "adjusted/a"
+ b "adjusted/b"
+ c "adjusted/c"
+)
+
+func use(interface{}) {}
+
+func TestAdjusted(t *testing.T) {
+ // just make sure types exist
+ use(a.A{X: &b.B{B: &c.C{C: 1}}, Y: &c.C{C: 1}})
+}
diff --git a/tests/core/go_proto_library/bar.proto b/tests/core/go_proto_library/bar.proto
new file mode 100644
index 00000000..6d945edf
--- /dev/null
+++ b/tests/core/go_proto_library/bar.proto
@@ -0,0 +1,10 @@
+syntax = "proto3";
+
+package tests.core.go_proto_library.bar;
+option go_package = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/bar";
+
+import "tests/core/go_proto_library/foo.proto";
+
+message Bar {
+ tests.core.go_proto_library.foo.Foo value = 1;
+}
diff --git a/tests/core/go_proto_library/embed_test.go b/tests/core/go_proto_library/embed_test.go
new file mode 100644
index 00000000..2ba1dad4
--- /dev/null
+++ b/tests/core/go_proto_library/embed_test.go
@@ -0,0 +1,45 @@
+/* Copyright 2018 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.
+*/
+
+package embed_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/tests/core/go_proto_library/foo"
+ "github.com/golang/protobuf/proto"
+)
+
+func TestProto(t *testing.T) {
+ x := foo.Foo{Value: 42}
+ data, err := proto.Marshal(&x)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var y foo.Foo
+ err = proto.Unmarshal(data, &y)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if y.Value != x.Value {
+ t.Errorf("got {x = %d}; want {x = %d}", y.Value, x.Value)
+ }
+}
+
+func TestExtra(t *testing.T) {
+ if got, want := foo.Extra(), 42; got != want {
+ t.Errorf("got %d; want %d", got, want)
+ }
+}
diff --git a/tests/core/go_proto_library/extra.go b/tests/core/go_proto_library/extra.go
new file mode 100644
index 00000000..d27cddc8
--- /dev/null
+++ b/tests/core/go_proto_library/extra.go
@@ -0,0 +1,5 @@
+package foo
+
+func Extra() int {
+ return 42
+}
diff --git a/tests/core/go_proto_library/foo.proto b/tests/core/go_proto_library/foo.proto
new file mode 100644
index 00000000..1f164661
--- /dev/null
+++ b/tests/core/go_proto_library/foo.proto
@@ -0,0 +1,8 @@
+syntax = "proto3";
+
+package tests.core.go_proto_library.foo;
+option go_package = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/foo";
+
+message Foo {
+ int64 value = 1;
+}
diff --git a/tests/core/go_proto_library/gofast_grpc_test.go b/tests/core/go_proto_library/gofast_grpc_test.go
new file mode 100644
index 00000000..aeb4d5e7
--- /dev/null
+++ b/tests/core/go_proto_library/gofast_grpc_test.go
@@ -0,0 +1,32 @@
+/* Copyright 2019 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.
+*/
+
+package gofast_grpc_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/tests/core/go_proto_library/grpc"
+)
+
+func use(interface{}) {}
+
+func TestGoFastGrpc(t *testing.T) {
+ // just make sure types and generated functions exist
+ use(grpc.RPCServer(nil))
+ use(grpc.RPCClient(nil))
+ (&grpc.HelloRequest{}).Marshal()
+ (&grpc.HelloReply{}).Marshal()
+}
diff --git a/tests/core/go_proto_library/gofast_test.go b/tests/core/go_proto_library/gofast_test.go
new file mode 100644
index 00000000..3fbfc54b
--- /dev/null
+++ b/tests/core/go_proto_library/gofast_test.go
@@ -0,0 +1,30 @@
+/* Copyright 2019 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.
+*/
+
+package gofast_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/tests/core/go_proto_library/foo"
+)
+
+func use(interface{}) {}
+
+func TestGoFast(t *testing.T) {
+ // just make sure types and generated functions exist
+ use(foo.Foo{Value: 42})
+ (&foo.Foo{}).Marshal()
+}
diff --git a/tests/core/go_proto_library/gogofast_grpc_test.go b/tests/core/go_proto_library/gogofast_grpc_test.go
new file mode 100644
index 00000000..0cf08e44
--- /dev/null
+++ b/tests/core/go_proto_library/gogofast_grpc_test.go
@@ -0,0 +1,32 @@
+/* Copyright 2019 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.
+*/
+
+package gogofast_grpc_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/tests/core/go_proto_library/grpc"
+)
+
+func use(interface{}) {}
+
+func TestGoGoFastGrpc(t *testing.T) {
+ // just make sure types and generated functions exist
+ use(grpc.RPCServer(nil))
+ use(grpc.RPCClient(nil))
+ (&grpc.HelloRequest{}).Marshal()
+ (&grpc.HelloReply{}).Marshal()
+}
diff --git a/tests/core/go_proto_library/gogofast_test.go b/tests/core/go_proto_library/gogofast_test.go
new file mode 100644
index 00000000..ee1d9fdf
--- /dev/null
+++ b/tests/core/go_proto_library/gogofast_test.go
@@ -0,0 +1,30 @@
+/* Copyright 2019 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.
+*/
+
+package gogofast_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/tests/core/go_proto_library/foo"
+)
+
+func use(interface{}) {}
+
+func TestGoGoFast(t *testing.T) {
+ // just make sure types and generated functions exist
+ use(foo.Foo{Value: 42})
+ (&foo.Foo{}).Marshal()
+}
diff --git a/tests/core/go_proto_library/grpc.proto b/tests/core/go_proto_library/grpc.proto
new file mode 100644
index 00000000..fd50d217
--- /dev/null
+++ b/tests/core/go_proto_library/grpc.proto
@@ -0,0 +1,14 @@
+syntax = "proto3";
+
+package tests.core.go_proto_library.grpc;
+option go_package = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/grpc";
+
+message HelloRequest {
+}
+
+message HelloReply {
+}
+
+service RPC {
+ rpc Hello (HelloRequest) returns (HelloReply) {}
+}
diff --git a/tests/core/go_proto_library/no_go_package.proto b/tests/core/go_proto_library/no_go_package.proto
new file mode 100644
index 00000000..e3112c56
--- /dev/null
+++ b/tests/core/go_proto_library/no_go_package.proto
@@ -0,0 +1,7 @@
+syntax = "proto3";
+
+package protopkg;
+
+message Foo {
+ int64 x = 1;
+}
diff --git a/tests/core/go_proto_library/proto_package_test.go b/tests/core/go_proto_library/proto_package_test.go
new file mode 100644
index 00000000..81d66174
--- /dev/null
+++ b/tests/core/go_proto_library/proto_package_test.go
@@ -0,0 +1,28 @@
+/* Copyright 2019 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.
+*/
+
+package proto_package_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/tests/core/go_proto_library/package_name_derived_from_importpath"
+)
+
+func use(interface{}) {}
+
+func TestNoGoPackage(t *testing.T) {
+ use(&package_name_derived_from_importpath.Foo{})
+}
diff --git a/tests/core/go_proto_library/protos_a.proto b/tests/core/go_proto_library/protos_a.proto
new file mode 100644
index 00000000..7b64d52b
--- /dev/null
+++ b/tests/core/go_proto_library/protos_a.proto
@@ -0,0 +1,7 @@
+syntax = "proto3";
+
+option go_package = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/protos";
+
+message A {
+ int64 a = 1;
+}
diff --git a/tests/core/go_proto_library/protos_alias_test.go b/tests/core/go_proto_library/protos_alias_test.go
new file mode 100644
index 00000000..17612765
--- /dev/null
+++ b/tests/core/go_proto_library/protos_alias_test.go
@@ -0,0 +1,29 @@
+/* Copyright 2020 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.
+*/
+
+package protos_alias_test
+
+import (
+ "myalias/protos" // importing based on the alias import path
+ "testing"
+)
+
+func use(interface{}) {}
+
+func TestProtos(t *testing.T) {
+ // just make sure both types exist
+ use(protos.A{})
+ use(protos.B{})
+}
diff --git a/tests/core/go_proto_library/protos_b.proto b/tests/core/go_proto_library/protos_b.proto
new file mode 100644
index 00000000..21f81711
--- /dev/null
+++ b/tests/core/go_proto_library/protos_b.proto
@@ -0,0 +1,7 @@
+syntax = "proto3";
+
+option go_package = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/protos";
+
+message B {
+ int64 b = 1;
+}
diff --git a/tests/core/go_proto_library/protos_test.go b/tests/core/go_proto_library/protos_test.go
new file mode 100644
index 00000000..68083c27
--- /dev/null
+++ b/tests/core/go_proto_library/protos_test.go
@@ -0,0 +1,30 @@
+/* Copyright 2018 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.
+*/
+
+package protos_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/tests/core/go_proto_library/protos"
+)
+
+func use(interface{}) {}
+
+func TestProtos(t *testing.T) {
+ // just make sure both types exist
+ use(protos.A{})
+ use(protos.B{})
+}
diff --git a/tests/core/go_proto_library/proxy_a.proto b/tests/core/go_proto_library/proxy_a.proto
new file mode 100644
index 00000000..a3c88444
--- /dev/null
+++ b/tests/core/go_proto_library/proxy_a.proto
@@ -0,0 +1,7 @@
+syntax = "proto3";
+
+option go_package = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/proxy";
+
+message A {
+ int64 a = 1;
+}
diff --git a/tests/core/go_proto_library/proxy_b.proto b/tests/core/go_proto_library/proxy_b.proto
new file mode 100644
index 00000000..d65a239f
--- /dev/null
+++ b/tests/core/go_proto_library/proxy_b.proto
@@ -0,0 +1,7 @@
+syntax = "proto3";
+
+option go_package = "github.com/bazelbuild/rules_go/tests/core/go_proto_library/proxy";
+
+message B {
+ int64 b = 1;
+}
diff --git a/tests/core/go_proto_library/proxy_test.go b/tests/core/go_proto_library/proxy_test.go
new file mode 100644
index 00000000..2209462f
--- /dev/null
+++ b/tests/core/go_proto_library/proxy_test.go
@@ -0,0 +1,30 @@
+/* Copyright 2018 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.
+*/
+
+package proxy_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/tests/core/go_proto_library/proxy"
+)
+
+func use(interface{}) {}
+
+func TestProxy(t *testing.T) {
+ // just make sure both types exist
+ use(proxy.A{})
+ use(proxy.B{})
+}
diff --git a/tests/core/go_proto_library/transitive_test.go b/tests/core/go_proto_library/transitive_test.go
new file mode 100644
index 00000000..1b733afe
--- /dev/null
+++ b/tests/core/go_proto_library/transitive_test.go
@@ -0,0 +1,30 @@
+/* Copyright 2018 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.
+*/
+
+package transitive_compiler_test
+
+import (
+ "testing"
+
+ bar "github.com/bazelbuild/rules_go/tests/core/go_proto_library/bar"
+ foo "github.com/bazelbuild/rules_go/tests/core/go_proto_library/foo"
+)
+
+func use(interface{}) {}
+
+func TestServices(t *testing.T) {
+ // just make sure both types exist
+ use(bar.Bar{Value: &foo.Foo{Value: 42}})
+}
diff --git a/tests/core/go_proto_library/wkt_wrapper_test.go b/tests/core/go_proto_library/wkt_wrapper_test.go
new file mode 100644
index 00000000..16228b04
--- /dev/null
+++ b/tests/core/go_proto_library/wkt_wrapper_test.go
@@ -0,0 +1,67 @@
+// Copyright 2020 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.
+
+package wkt_wrapper_test
+
+import (
+ "testing"
+
+ descriptorpb1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
+ pluginpb1 "github.com/golang/protobuf/protoc-gen-go/plugin"
+ anypb1 "github.com/golang/protobuf/ptypes/any"
+ durationpb1 "github.com/golang/protobuf/ptypes/duration"
+ emptypb1 "github.com/golang/protobuf/ptypes/empty"
+ structpb1 "github.com/golang/protobuf/ptypes/struct"
+ timestamppb1 "github.com/golang/protobuf/ptypes/timestamp"
+ wrapperspb1 "github.com/golang/protobuf/ptypes/wrappers"
+ field_mask1 "google.golang.org/genproto/protobuf/field_mask"
+ type1 "google.golang.org/genproto/protobuf/ptype"
+ source_context1 "google.golang.org/genproto/protobuf/source_context"
+ descriptorpb2 "google.golang.org/protobuf/types/descriptorpb"
+ anypb2 "google.golang.org/protobuf/types/known/anypb"
+ durationpb2 "google.golang.org/protobuf/types/known/durationpb"
+ emptypb2 "google.golang.org/protobuf/types/known/emptypb"
+ field_mask2 "google.golang.org/protobuf/types/known/fieldmaskpb"
+ source_context2 "google.golang.org/protobuf/types/known/sourcecontextpb"
+ structpb2 "google.golang.org/protobuf/types/known/structpb"
+ timestamppb2 "google.golang.org/protobuf/types/known/timestamppb"
+ type2 "google.golang.org/protobuf/types/known/typepb"
+ wrapperspb2 "google.golang.org/protobuf/types/known/wrapperspb"
+ pluginpb2 "google.golang.org/protobuf/types/pluginpb"
+)
+
+func Test(t *testing.T) {
+ var _ *anypb2.Any = (*anypb1.Any)(nil)
+ var _ *anypb1.Any = (*anypb2.Any)(nil)
+ var _ *pluginpb2.Version = (*pluginpb1.Version)(nil)
+ var _ *pluginpb1.Version = (*pluginpb2.Version)(nil)
+ var _ *descriptorpb2.DescriptorProto = (*descriptorpb1.DescriptorProto)(nil)
+ var _ *descriptorpb1.DescriptorProto = (*descriptorpb2.DescriptorProto)(nil)
+ var _ *durationpb2.Duration = (*durationpb1.Duration)(nil)
+ var _ *durationpb1.Duration = (*durationpb2.Duration)(nil)
+ var _ *emptypb2.Empty = (*emptypb1.Empty)(nil)
+ var _ *emptypb1.Empty = (*emptypb2.Empty)(nil)
+ var _ *field_mask1.FieldMask = (*field_mask2.FieldMask)(nil)
+ var _ *field_mask2.FieldMask = (*field_mask1.FieldMask)(nil)
+ var _ *source_context1.SourceContext = (*source_context2.SourceContext)(nil)
+ var _ *source_context2.SourceContext = (*source_context1.SourceContext)(nil)
+ var _ *structpb2.Struct = (*structpb1.Struct)(nil)
+ var _ *structpb1.Struct = (*structpb2.Struct)(nil)
+ var _ *timestamppb2.Timestamp = (*timestamppb1.Timestamp)(nil)
+ var _ *timestamppb1.Timestamp = (*timestamppb2.Timestamp)(nil)
+ var _ *type1.Type = (*type2.Type)(nil)
+ var _ *type2.Type = (*type1.Type)(nil)
+ var _ *wrapperspb2.BoolValue = (*wrapperspb1.BoolValue)(nil)
+ var _ *wrapperspb1.BoolValue = (*wrapperspb2.BoolValue)(nil)
+}
diff --git a/tests/core/go_proto_library_importmap/BUILD.bazel b/tests/core/go_proto_library_importmap/BUILD.bazel
new file mode 100644
index 00000000..e1695b9f
--- /dev/null
+++ b/tests/core/go_proto_library_importmap/BUILD.bazel
@@ -0,0 +1,21 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_test")
+load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
+load("@rules_proto//proto:defs.bzl", "proto_library")
+
+proto_library(
+ name = "foo_proto",
+ srcs = ["foo.proto"],
+)
+
+go_proto_library(
+ name = "foo_go_proto",
+ importmap = "never/gonna/give/you/up",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_proto_library_importmap",
+ proto = ":foo_proto",
+)
+
+go_test(
+ name = "importmap_test",
+ srcs = ["importmap_test.go"],
+ deps = [":foo_go_proto"],
+)
diff --git a/tests/core/go_proto_library_importmap/README.rst b/tests/core/go_proto_library_importmap/README.rst
new file mode 100644
index 00000000..991f52f8
--- /dev/null
+++ b/tests/core/go_proto_library_importmap/README.rst
@@ -0,0 +1,8 @@
+go_proto_library importmap
+==========================
+
+importmap_test
+--------------
+
+Checks that the ``importmap`` attribute of ``go_proto_library`` works correctly.
+The test uses reflection information for a type in the generated file.
diff --git a/tests/core/go_proto_library_importmap/foo.proto b/tests/core/go_proto_library_importmap/foo.proto
new file mode 100644
index 00000000..b2bbe414
--- /dev/null
+++ b/tests/core/go_proto_library_importmap/foo.proto
@@ -0,0 +1,6 @@
+syntax = "proto3";
+
+option go_package = "github.com/bazelbuild/rules_go/tests/core/go_proto_library_importmap;foo";
+
+message Foo {
+};
diff --git a/tests/core/go_proto_library_importmap/importmap_test.go b/tests/core/go_proto_library_importmap/importmap_test.go
new file mode 100644
index 00000000..2ebbd815
--- /dev/null
+++ b/tests/core/go_proto_library_importmap/importmap_test.go
@@ -0,0 +1,16 @@
+package importmap_test
+
+import (
+ "reflect"
+ "testing"
+
+ foo "github.com/bazelbuild/rules_go/tests/core/go_proto_library_importmap"
+)
+
+func TestImportMap(t *testing.T) {
+ got := reflect.TypeOf(foo.Foo{}).PkgPath()
+ want := "never/gonna/give/you/up"
+ if got != want {
+ t.Errorf("got %q; want %q", got, want)
+ }
+}
diff --git a/tests/core/go_test/BUILD.bazel b/tests/core/go_test/BUILD.bazel
new file mode 100644
index 00000000..b77c851b
--- /dev/null
+++ b/tests/core/go_test/BUILD.bazel
@@ -0,0 +1,261 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+test_suite(
+ name = "go_test",
+)
+
+go_library(
+ name = "lib",
+ srcs = ["lib.go"],
+ cgo = True,
+ importpath = "lib",
+)
+
+go_test(
+ name = "internal_test",
+ size = "small",
+ srcs = ["internal_test.go"],
+ embed = [":lib"],
+ x_defs = {
+ "Got": "Internal",
+ "Expect": "Internal",
+ },
+)
+
+go_test(
+ name = "external_test",
+ size = "small",
+ srcs = ["external_test.go"],
+ embed = [":lib"],
+ x_defs = {
+ "Got": "External",
+ "Expect": "External",
+ },
+)
+
+go_test(
+ name = "combined_test",
+ size = "small",
+ srcs = [
+ "external_test.go",
+ "internal_test.go",
+ ],
+ embed = [":lib"],
+ x_defs = {
+ "Got": "Combined",
+ "Expect": "Combined",
+ },
+)
+
+go_test(
+ name = "flag_test",
+ size = "small",
+ srcs = [
+ "flag_test.go",
+ ],
+ args = [
+ "-aflag",
+ "somevalue",
+ ],
+)
+
+go_test(
+ name = "example_test",
+ size = "small",
+ srcs = ["example_test.go"],
+ embed = [":lib"],
+ x_defs = {
+ "Got": "Example",
+ "Expected": "Example",
+ },
+)
+
+go_test(
+ name = "only_testmain_test",
+ size = "small",
+ srcs = ["only_testmain_test.go"],
+)
+
+go_test(
+ name = "external_importmap_test",
+ size = "small",
+ srcs = ["external_importmap_test.go"],
+ embed = [":external_importmap_lib"],
+ deps = [":external_importmap_dep"],
+)
+
+go_library(
+ name = "external_importmap_lib",
+ srcs = ["external_importmap_lib.go"],
+ importmap = "x/github.com/bazelbuild/rules_go/tests/core/go_test/external_importmap",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_test/external_importmap",
+)
+
+go_library(
+ name = "external_importmap_dep",
+ srcs = ["external_importmap_dep.go"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_test/external_importmap_dep",
+ deps = [":external_importmap_lib"],
+)
+
+go_test(
+ name = "pwd_test",
+ size = "small",
+ srcs = ["pwd_test.go"],
+)
+
+go_test(
+ name = "data_test",
+ size = "small",
+ embed = [":data_test_lib"],
+)
+
+go_library(
+ name = "data_test_lib",
+ srcs = [":data_test_srcs"],
+ data = ["x"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_test/data_test",
+ deps = [":data_test_dep"],
+)
+
+filegroup(
+ name = "data_test_srcs",
+ srcs = ["data_test.go"],
+)
+
+go_library(
+ name = "data_test_dep",
+ srcs = ["data_test_dep.go"],
+ data = ["y"],
+ embed = [":data_test_embed"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_test/data_test_dep",
+)
+
+go_library(
+ name = "data_test_embed",
+ srcs = ["data_test_embed.go"],
+ data = ["z"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_test/data_test_dep",
+)
+
+go_bazel_test(
+ name = "test_fail_fast_test",
+ srcs = ["test_fail_fast_test.go"],
+)
+
+go_bazel_test(
+ name = "test_filter_test",
+ srcs = ["test_filter_test.go"],
+)
+
+go_bazel_test(
+ name = "xmlreport_test",
+ srcs = ["xmlreport_test.go"],
+)
+
+go_test(
+ name = "testmain_import_test",
+ srcs = [
+ "testmain_import_indirect_test.go",
+ "testmain_import_main_test.go",
+ ],
+ importpath = "example.com/imports/test_main",
+)
+
+go_test(
+ name = "tags_test",
+ srcs = [
+ "tags_bad_test.go",
+ "tags_good_test.go",
+ ],
+ gotags = ["good"],
+)
+
+go_test(
+ name = "indirect_import_test",
+ srcs = [
+ "indirect_import_i_test.go",
+ "indirect_import_x_test.go",
+ ],
+ embed = [":indirect_import_lib"],
+ deps = [":indirect_import_dep"],
+)
+
+go_library(
+ name = "indirect_import_lib",
+ srcs = ["indirect_import_lib.go"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_test/indirect_import",
+)
+
+go_library(
+ name = "indirect_import_dep",
+ srcs = ["indirect_import_dep.go"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_test/indirect_import_dep",
+ deps = [":indirect_import_lib"],
+)
+
+[
+ go_test(
+ name = "same_package_{}_test".format(i),
+ srcs = ["same_package_test.go"],
+ )
+ for i in range(1, 80)
+]
+
+test_suite(
+ name = "same_package_test",
+ tests = ["same_package_{}_test".format(i) for i in range(1, 80)],
+)
+
+go_bazel_test(
+ name = "testmain_without_exit_test",
+ srcs = ["testmain_without_exit_test.go"],
+)
+
+go_test(
+ name = "wrapper_test",
+ srcs = ["wrapper_test.go"],
+ args = ["$(location :wrapped_test)"],
+ data = [":wrapped_test"],
+ rundir = ".",
+)
+
+go_test(
+ name = "wrapped_test",
+ srcs = ["wrapped_test.go"],
+ tags = ["manual"],
+)
+
+go_test(
+ name = "fuzz_test",
+ srcs = ["fuzz_test.go"],
+)
+
+go_test(
+ name = "env_test",
+ srcs = ["env_test.go"],
+ data = ["@go_sdk//:lib/time/zoneinfo.zip"],
+ env = {
+ "ZONEINFO": "$(execpath @go_sdk//:lib/time/zoneinfo.zip)",
+ },
+ deps = [
+ "@io_bazel_rules_go//go/tools/bazel",
+ ],
+)
+
+go_test(
+ name = "sharding_test",
+ srcs = ["sharding_test.go"],
+ shard_count = 2,
+)
+
+go_bazel_test(
+ name = "env_inherit_test",
+ srcs = ["env_inherit_test.go"],
+)
+
+go_bazel_test(
+ name = "binary_env_test",
+ srcs = ["binary_env_test.go"],
+)
diff --git a/tests/core/go_test/README.rst b/tests/core/go_test/README.rst
new file mode 100644
index 00000000..176cf196
--- /dev/null
+++ b/tests/core/go_test/README.rst
@@ -0,0 +1,126 @@
+Basic go_test functionality
+===========================
+
+.. _go_test: /docs/go/core/rules.md#_go_test
+.. _#1877: https://github.com/bazelbuild/rules_go/issues/1877
+.. _#34129: https:////github.com/golang/go/issues/34129
+.. _#2749: https://github.com/bazelbuild/rules_go/issues/2749
+
+Tests to ensure that basic features of `go_test`_ are working as expected.
+
+.. contents::
+
+internal_test
+-------------
+
+Test that a `go_test`_ rule that adds white box tests to an embedded package works.
+This builds a library with `lib.go <lib.go>`_ and then a package with an
+`internal test <internal_test.go>`_ that contains the test case.
+It uses x_def stamped values to verify the library names are correct.
+
+external_test
+-------------
+
+Test that a `go_test`_ rule that adds black box tests for a dependant package works.
+This builds a library with `lib.go <lib.go>`_ and then a package with an
+`external test <external_test.go>`_ that contains the test case.
+It uses x_def stamped values to verify the library names are correct.
+
+combined_test
+-------------
+Test that a `go_test`_ rule that adds both white and black box tests for a
+package works.
+This builds a library with `lib.go <lib.go>`_ and then a one merged with the
+`internal test <internal_test.go>`_, and then another one that depends on it
+with the `external test <external_test.go>`_.
+It uses x_def stamped values to verify that all library names are correct.
+Verifies #413
+
+flag_test
+---------
+Test that a `go_test`_ rule that adds flags, even in the main package, can read
+the flag.
+This does not even build a library, it's a test in the main package with no
+dependancies that checks it can declare and then read a flag.
+Verifies #838
+
+only_testmain_test
+------------------
+Test that an `go_test`_ that contains a ``TestMain`` function but no tests
+still builds and passes.
+
+external_importmap_test
+----------------------
+
+Test that an external test package in `go_test`_ is compiled with the correct
+``importmap`` for the library under test. This is verified by defining an
+interface in the library under test and implementing it in a separate
+dependency.
+
+Verifies #1538.
+
+pwd_test
+--------
+
+Checks that the ``PWD`` environment variable is set to the current directory
+in the generated test main before running a test. This matches functionality
+in ``go test``.
+
+Verifies #1561.
+
+data_test
+---------
+
+Checks that data dependencies, including those inherited from ``deps`` and
+``embed``, are visible to tests at run-time. Source files should not be
+visible at run-time.
+
+test_fail_fast_test
+----------------
+
+Checks that ``--test_runner_fail_fast`` actually enables stopping test execution after
+the first failure.
+
+Verifies #3055.
+
+test_filter_test
+----------------
+
+Checks that ``--test_filter`` actually filters out test cases.
+
+testmain_import_test
+----------------
+
+Check if all packages in all source files are imported to test main, to ensure
+a consistent test behaviour. This ensures a consistent behaviour when thinking
+about global indirect depencencies.
+
+tags_test
+---------
+
+Checks that setting ``gotags`` affects source filtering. The test will fail
+unless a specific tag is set.
+
+indirect_import_test
+--------------------
+
+Checks that an external test can import another package that imports the library
+under test. The other package should be compiled against the internal test
+package, not the library under test. Verifies `#1877`_.
+
+testmain_without_exit
+---------------------
+
+Checks that TestMain without calling os.Exit directly works.
+Verifies `#34129`_ from Go 1.15.
+
+wrapper_test
+------------
+
+Checks that a ``go_test`` can be executed by another test in a subdirectory.
+Verifies `#2749`_.
+
+fuzz_test
+---------
+
+Checks that a ``go_test`` with a fuzz target builds correctly.
diff --git a/tests/core/go_test/binary_env_test.go b/tests/core/go_test/binary_env_test.go
new file mode 100644
index 00000000..25089034
--- /dev/null
+++ b/tests/core/go_test/binary_env_test.go
@@ -0,0 +1,55 @@
+// Copyright 2023 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.
+
+package binary_env_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- src/BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary")
+go_binary(
+ name = "main",
+ srcs = ["env.go"],
+ env = {"FOO": "bar"},
+)
+-- src/env.go --
+package main
+
+import (
+ "log"
+ "os"
+)
+
+func main() {
+ v := os.Getenv("FOO")
+ if v != "bar" {
+ log.Fatalf("FOO was not equal to bar")
+ }
+}
+`,
+ })
+}
+
+func TestBinaryEnv(t *testing.T) {
+ if err := bazel_testing.RunBazel("run", "//src:main"); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/tests/core/go_test/data_test.go b/tests/core/go_test/data_test.go
new file mode 100644
index 00000000..fd8a3930
--- /dev/null
+++ b/tests/core/go_test/data_test.go
@@ -0,0 +1,45 @@
+// Copyright 2018 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.
+
+package data_test
+
+import (
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+func TestVisibleRunfiles(t *testing.T) {
+ var got []string
+ err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if base := filepath.Base(path); info.IsDir() || base == "data_test" || base == "data_test.exe" {
+ return nil
+ }
+ got = append(got, filepath.ToSlash(path))
+ return nil
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ gotStr := strings.Join(got, "\n")
+ wantStr := "x\ny\nz"
+ if gotStr != wantStr {
+ t.Errorf("got:\n%s\nwant:\n%s\n", gotStr, wantStr)
+ }
+}
diff --git a/tests/core/go_test/data_test_dep.go b/tests/core/go_test/data_test_dep.go
new file mode 100644
index 00000000..d8eb2672
--- /dev/null
+++ b/tests/core/go_test/data_test_dep.go
@@ -0,0 +1,15 @@
+// Copyright 2018 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.
+
+package data_test_dep
diff --git a/tests/core/go_test/data_test_embed.go b/tests/core/go_test/data_test_embed.go
new file mode 100644
index 00000000..d8eb2672
--- /dev/null
+++ b/tests/core/go_test/data_test_embed.go
@@ -0,0 +1,15 @@
+// Copyright 2018 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.
+
+package data_test_dep
diff --git a/tests/core/go_test/env_inherit_test.go b/tests/core/go_test/env_inherit_test.go
new file mode 100644
index 00000000..b425abe2
--- /dev/null
+++ b/tests/core/go_test/env_inherit_test.go
@@ -0,0 +1,61 @@
+// Copyright 2021 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.
+
+package env_inherit_test
+
+import (
+ "os"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- src/BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_test")
+go_test(
+ name = "main",
+ srcs = ["env_inherit.go"],
+ env_inherit = ["INHERITEDVAR"],
+)
+-- src/env_inherit.go --
+package env_inherit_test
+
+import (
+ "os"
+ "testing"
+)
+
+func TestInherit(t *testing.T) {
+ v := os.Getenv("INHERITEDVAR")
+ if v != "b" {
+ t.Fatalf("INHERITEDVAR was not equal to b")
+ }
+}
+`,
+
+ SetUp: func() error {
+ os.Setenv("INHERITEDVAR", "b")
+ return nil
+ },
+ })
+}
+
+func TestInheritedEnvVar(t *testing.T) {
+ if err := bazel_testing.RunBazel("test", "//src:main"); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/tests/core/go_test/env_test.go b/tests/core/go_test/env_test.go
new file mode 100644
index 00000000..89dae3ca
--- /dev/null
+++ b/tests/core/go_test/env_test.go
@@ -0,0 +1,39 @@
+// Copyright 2021 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.
+
+package env_test
+
+import (
+ "os"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel"
+)
+
+func TestEnv(t *testing.T) {
+ v := os.Getenv("ZONEINFO")
+ if v == "" {
+ t.Fatalf("ZONEINFO env var was empty")
+ }
+
+ path, err := bazel.Runfile(v)
+ if err != nil {
+ t.Fatalf("Could not find runfile %v: %v", v, err)
+ }
+
+ if _, err := os.Stat(path); err != nil {
+ t.Fatalf("Could not find file at env var $ZONEINFO (value: %v) at path %v: %v", v, path, err)
+ }
+}
+
diff --git a/tests/core/go_test/example_test.go b/tests/core/go_test/example_test.go
new file mode 100644
index 00000000..6314e69c
--- /dev/null
+++ b/tests/core/go_test/example_test.go
@@ -0,0 +1,32 @@
+package lib
+
+import "fmt"
+
+var Expected = "Expected"
+
+func ExampleHelloWorld() {
+ fmt.Println("Hello Example!")
+ fmt.Println("expected: " + Expected)
+ fmt.Println("got: " + Got)
+ // Output:
+ // Hello Example!
+ // expected: Example
+ // got: Example
+}
+
+func ExampleDontTestMe() {
+ panic("Dont Test Me!")
+}
+
+func ExampleTestEmptyOutput() {
+ if false {
+ fmt.Println("Say something!")
+ }
+ // Output:
+}
+
+func ExampleTestQuoting() {
+ fmt.Printf(`"quotes are handled"`)
+ // Output:
+ // "quotes are handled"
+}
diff --git a/tests/core/go_test/external_importmap_dep.go b/tests/core/go_test/external_importmap_dep.go
new file mode 100644
index 00000000..c9990774
--- /dev/null
+++ b/tests/core/go_test/external_importmap_dep.go
@@ -0,0 +1,11 @@
+package external_importmap_dep
+
+import (
+ "github.com/bazelbuild/rules_go/tests/core/go_test/external_importmap"
+)
+
+type Impl struct{}
+
+func (_ *Impl) DeepCopyObject() external_importmap.Object {
+ return nil
+}
diff --git a/tests/core/go_test/external_importmap_lib.go b/tests/core/go_test/external_importmap_lib.go
new file mode 100644
index 00000000..e9800a1c
--- /dev/null
+++ b/tests/core/go_test/external_importmap_lib.go
@@ -0,0 +1,5 @@
+package external_importmap
+
+type Object interface {
+ DeepCopyObject() Object
+}
diff --git a/tests/core/go_test/external_importmap_test.go b/tests/core/go_test/external_importmap_test.go
new file mode 100644
index 00000000..fbcc55ef
--- /dev/null
+++ b/tests/core/go_test/external_importmap_test.go
@@ -0,0 +1,10 @@
+package external_importmap_test
+
+import (
+ "github.com/bazelbuild/rules_go/tests/core/go_test/external_importmap"
+ "github.com/bazelbuild/rules_go/tests/core/go_test/external_importmap_dep"
+)
+
+var _ external_importmap.Object = &external_importmap_dep.Impl{}
+
+// Test passes if it compiles.
diff --git a/tests/core/go_test/external_test.go b/tests/core/go_test/external_test.go
new file mode 100644
index 00000000..957cce9e
--- /dev/null
+++ b/tests/core/go_test/external_test.go
@@ -0,0 +1,29 @@
+/* Copyright 2017 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.
+*/
+
+package lib_test
+
+import (
+ "lib"
+ "testing"
+)
+
+var Expect = "Expect"
+
+func TestExternal(t *testing.T) {
+ if lib.Got != Expect {
+ t.Errorf("Got %q expected %q", lib.Got, Expect)
+ }
+}
diff --git a/tests/core/go_test/flag_test.go b/tests/core/go_test/flag_test.go
new file mode 100644
index 00000000..ec7c3576
--- /dev/null
+++ b/tests/core/go_test/flag_test.go
@@ -0,0 +1,30 @@
+/* Copyright 2018 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.
+*/
+package main
+
+import (
+ "flag"
+ "testing"
+)
+
+const flagDefault = "flag default"
+
+var aflag = flag.String("aflag", flagDefault, "A test flag")
+
+func TestAFlag(t *testing.T) {
+ if *aflag == flagDefault {
+ t.Error("aflag is still the default")
+ }
+}
diff --git a/tests/core/go_test/fuzz_test.go b/tests/core/go_test/fuzz_test.go
new file mode 100644
index 00000000..48c88194
--- /dev/null
+++ b/tests/core/go_test/fuzz_test.go
@@ -0,0 +1,29 @@
+// Copyright 2019 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.
+
+//go:build go1.18
+// +build go1.18
+
+package fuzz_test
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+ f.Add("seed")
+ f.Fuzz(func(t *testing.T, s string) {
+ if s != "seed" {
+ t.Fail()
+ }
+ })
+}
diff --git a/tests/core/go_test/indirect_import_dep.go b/tests/core/go_test/indirect_import_dep.go
new file mode 100644
index 00000000..c47d28b5
--- /dev/null
+++ b/tests/core/go_test/indirect_import_dep.go
@@ -0,0 +1,7 @@
+package indirect_import_dep
+
+import "github.com/bazelbuild/rules_go/tests/core/go_test/indirect_import"
+
+func GetX() string {
+ return indirect_import.X
+}
diff --git a/tests/core/go_test/indirect_import_i_test.go b/tests/core/go_test/indirect_import_i_test.go
new file mode 100644
index 00000000..e6814143
--- /dev/null
+++ b/tests/core/go_test/indirect_import_i_test.go
@@ -0,0 +1,7 @@
+package indirect_import
+
+import "testing"
+
+func TestMain(m *testing.M) {
+ X = "set by TestMain"
+}
diff --git a/tests/core/go_test/indirect_import_lib.go b/tests/core/go_test/indirect_import_lib.go
new file mode 100644
index 00000000..915c0dfe
--- /dev/null
+++ b/tests/core/go_test/indirect_import_lib.go
@@ -0,0 +1,3 @@
+package indirect_import
+
+var X string = "not set"
diff --git a/tests/core/go_test/indirect_import_x_test.go b/tests/core/go_test/indirect_import_x_test.go
new file mode 100644
index 00000000..008063ce
--- /dev/null
+++ b/tests/core/go_test/indirect_import_x_test.go
@@ -0,0 +1,15 @@
+package indirect_import_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/tests/core/go_test/indirect_import_dep"
+)
+
+func Test(t *testing.T) {
+ got := indirect_import_dep.GetX()
+ want := "set by TestMain"
+ if got != want {
+ t.Errorf("got %q; want %q", got, want)
+ }
+}
diff --git a/tests/core/go_test/internal_test.go b/tests/core/go_test/internal_test.go
new file mode 100644
index 00000000..fdb112e6
--- /dev/null
+++ b/tests/core/go_test/internal_test.go
@@ -0,0 +1,28 @@
+/* Copyright 2017 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.
+*/
+
+package lib
+
+import (
+ "testing"
+)
+
+var Expect = "Expect"
+
+func TestInternal(t *testing.T) {
+ if Got != Expect {
+ t.Errorf("Got %q expected %q", Got, Expect)
+ }
+}
diff --git a/tests/core/go_test/lib.go b/tests/core/go_test/lib.go
new file mode 100644
index 00000000..f34c854f
--- /dev/null
+++ b/tests/core/go_test/lib.go
@@ -0,0 +1,20 @@
+/* Copyright 2017 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.
+*/
+
+package lib
+
+import "C"
+
+var Got = "Got"
diff --git a/tests/core/go_test/only_testmain_test.go b/tests/core/go_test/only_testmain_test.go
new file mode 100644
index 00000000..474a3d6c
--- /dev/null
+++ b/tests/core/go_test/only_testmain_test.go
@@ -0,0 +1,10 @@
+package only_testmain
+
+import (
+ "os"
+ "testing"
+)
+
+func TestMain(m *testing.M) {
+ os.Exit(m.Run())
+}
diff --git a/tests/core/go_test/pwd_test.go b/tests/core/go_test/pwd_test.go
new file mode 100644
index 00000000..9de4abf0
--- /dev/null
+++ b/tests/core/go_test/pwd_test.go
@@ -0,0 +1,16 @@
+package pwd
+
+import (
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+func TestPwd(t *testing.T) {
+ pwd := os.Getenv("PWD")
+ suffix := filepath.FromSlash("tests/core/go_test")
+ if !strings.HasSuffix(pwd, filepath.FromSlash(suffix)) {
+ t.Errorf("PWD not set. got %q; want something ending with %q", pwd, suffix)
+ }
+}
diff --git a/tests/core/go_test/same_package_test.go b/tests/core/go_test/same_package_test.go
new file mode 100644
index 00000000..cf991492
--- /dev/null
+++ b/tests/core/go_test/same_package_test.go
@@ -0,0 +1,7 @@
+package same_package
+
+import (
+ "testing"
+)
+
+func OkTest(t *testing.T) {}
diff --git a/tests/core/go_test/sharding_test.go b/tests/core/go_test/sharding_test.go
new file mode 100644
index 00000000..a83bb85c
--- /dev/null
+++ b/tests/core/go_test/sharding_test.go
@@ -0,0 +1,13 @@
+package sharding_test
+
+import (
+ "log"
+ "os"
+ "testing"
+)
+
+func TestShardStatusFile(t *testing.T) {
+ if _, err := os.Stat(os.Getenv("TEST_SHARD_STATUS_FILE")); err != nil {
+ log.Fatalf("Expected Go test runner to create TEST_SHARD_STATUS_FILE: %v", err)
+ }
+}
diff --git a/tests/core/go_test/tags_bad_test.go b/tests/core/go_test/tags_bad_test.go
new file mode 100644
index 00000000..76d32cd5
--- /dev/null
+++ b/tests/core/go_test/tags_bad_test.go
@@ -0,0 +1,9 @@
+// +build !good
+
+package tags_test
+
+import "testing"
+
+func Test(t *testing.T) {
+ t.Fail()
+}
diff --git a/tests/core/go_test/tags_good_test.go b/tests/core/go_test/tags_good_test.go
new file mode 100644
index 00000000..60071805
--- /dev/null
+++ b/tests/core/go_test/tags_good_test.go
@@ -0,0 +1,7 @@
+// +build good
+
+package tags_test
+
+import "testing"
+
+func Test(t *testing.T) {}
diff --git a/tests/core/go_test/test_fail_fast_test.go b/tests/core/go_test/test_fail_fast_test.go
new file mode 100644
index 00000000..b949b489
--- /dev/null
+++ b/tests/core/go_test/test_fail_fast_test.go
@@ -0,0 +1,75 @@
+// Copyright 2022 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.
+
+package test_fail_fast_test
+
+import (
+ "bytes"
+ "io/ioutil"
+ "path/filepath"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_test")
+
+go_test(
+ name = "fail_fast_test",
+ srcs = ["fail_fast_test.go"],
+)
+
+-- fail_fast_test.go --
+package test_fail_fast
+
+import "testing"
+
+func TestShouldFail(t *testing.T) {
+ t.Fail()
+}
+
+func TestShouldNotRun(t *testing.T) {
+ t.Fail()
+}
+`,
+ })
+}
+
+func Test(t *testing.T) {
+ if err := bazel_testing.RunBazel("test", "//:fail_fast_test", "--test_runner_fail_fast"); err == nil {
+ t.Fatal("got success; want failure")
+ } else if bErr, ok := err.(*bazel_testing.StderrExitError); !ok {
+ t.Fatalf("got %v; want StderrExitError", err)
+ } else if code := bErr.Err.ExitCode(); code != 3 {
+ t.Fatalf("got code %d; want code 3", code)
+ }
+
+ logPath := filepath.FromSlash("bazel-testlogs/fail_fast_test/test.log")
+ logData, err := ioutil.ReadFile(logPath)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !bytes.Contains(logData, []byte("TestShouldFail")) {
+ t.Fatalf("test log does not contain 'TestShouldFail': %q", logData)
+ }
+
+ if bytes.Contains(logData, []byte("TestShouldNotRun")) {
+ t.Fatalf("test log contains 'TestShouldNotRun' but should not: %q", logData)
+ }
+}
diff --git a/tests/core/go_test/test_filter_test.go b/tests/core/go_test/test_filter_test.go
new file mode 100644
index 00000000..49b1ce73
--- /dev/null
+++ b/tests/core/go_test/test_filter_test.go
@@ -0,0 +1,54 @@
+// Copyright 2019 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.
+
+package test_filter_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_test")
+
+go_test(
+ name = "filter_test",
+ srcs = ["filter_test.go"],
+)
+
+-- filter_test.go --
+package test_filter
+
+import "testing"
+
+func TestShouldPass(t *testing.T) {
+}
+
+func TestShouldFail(t *testing.T) {
+ t.Fail()
+}
+
+`,
+ })
+}
+
+func Test(t *testing.T) {
+ if err := bazel_testing.RunBazel("test", "//:filter_test", "--test_filter=Pass"); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/tests/core/go_test/testmain_import_indirect_test.go b/tests/core/go_test/testmain_import_indirect_test.go
new file mode 100644
index 00000000..bcb6fac8
--- /dev/null
+++ b/tests/core/go_test/testmain_import_indirect_test.go
@@ -0,0 +1,7 @@
+package test_main_test
+
+import "example.com/imports/test_main"
+
+func init() {
+ test_main.Updated = true
+}
diff --git a/tests/core/go_test/testmain_import_main_test.go b/tests/core/go_test/testmain_import_main_test.go
new file mode 100644
index 00000000..b723bf06
--- /dev/null
+++ b/tests/core/go_test/testmain_import_main_test.go
@@ -0,0 +1,11 @@
+package test_main
+
+import "testing"
+
+var Updated bool
+
+func TestShouldPass(t *testing.T) {
+ if !Updated {
+ t.Fail()
+ }
+}
diff --git a/tests/core/go_test/testmain_without_exit_test.go b/tests/core/go_test/testmain_without_exit_test.go
new file mode 100644
index 00000000..6944747d
--- /dev/null
+++ b/tests/core/go_test/testmain_without_exit_test.go
@@ -0,0 +1,59 @@
+// Copyright 2020 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.
+
+package testmain_without_exit
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_test")
+
+go_test(
+ name = "main_without_exit_test",
+ srcs = ["main_without_exit_test.go"],
+)
+
+-- main_without_exit_test.go --
+package test_main_without_exit
+
+import "testing"
+
+func TestMain(m *testing.M) {
+ m.Run()
+}
+
+func TestShouldFail(t *testing.T) {
+ t.Fail()
+}
+`,
+ })
+}
+
+func Test(t *testing.T) {
+ err := bazel_testing.RunBazel("test", "//:main_without_exit_test")
+ if err == nil {
+ t.Fatal("expected bazel test to have failed")
+ }
+
+ if xerr, ok := err.(*bazel_testing.StderrExitError); !ok || xerr.Err.ExitCode() != 3 {
+ t.Fatalf("expected bazel tests to fail with exit code 3 (TESTS_FAILED), got: %s", err)
+ }
+}
diff --git a/tests/core/go_test/wrapped_test.go b/tests/core/go_test/wrapped_test.go
new file mode 100644
index 00000000..ce8c1933
--- /dev/null
+++ b/tests/core/go_test/wrapped_test.go
@@ -0,0 +1,19 @@
+// Copyright 2020 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.
+
+package wrapped_test
+
+import "testing"
+
+func Test(t *testing.T) {}
diff --git a/tests/core/go_test/wrapper_test.go b/tests/core/go_test/wrapper_test.go
new file mode 100644
index 00000000..c889ccac
--- /dev/null
+++ b/tests/core/go_test/wrapper_test.go
@@ -0,0 +1,46 @@
+// Copyright 2020 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.
+
+package wrapper_test
+
+import (
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "testing"
+)
+
+func Test(t *testing.T) {
+ if _, ok := os.LookupEnv("RUNFILES_MANIFEST_FILE"); ok {
+ t.Skipf("test only applicable with a runfiles directory")
+ }
+
+ tmpLog, err := ioutil.TempFile("", "tmp.xml")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer func() {
+ tmpLog.Close()
+ os.Remove(tmpLog.Name())
+ }()
+
+ arg := os.Args[1]
+ cmd := exec.Command(arg)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ cmd.Env = append(os.Environ(), "GO_TEST_WRAP=1", "XML_OUTPUT_FILE="+tmpLog.Name())
+ if err := cmd.Run(); err != nil {
+ t.Fatalf("running wrapped_test: %v", err)
+ }
+}
diff --git a/tests/core/go_test/x b/tests/core/go_test/x
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_test/x
diff --git a/tests/core/go_test/x_defs/BUILD.bazel b/tests/core/go_test/x_defs/BUILD.bazel
new file mode 100644
index 00000000..7edc4885
--- /dev/null
+++ b/tests/core/go_test/x_defs/BUILD.bazel
@@ -0,0 +1,73 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+test_suite(
+ name = "x_defs",
+)
+
+go_test(
+ name = "foo_test",
+ srcs = ["foo_test.go"],
+ embed = [":foo"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_test/x_defs/foo",
+ pure = "on",
+ deps = [":bar"],
+)
+
+go_library(
+ name = "bar",
+ srcs = ["bar.go"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_test/x_defs/bar",
+ visibility = ["//visibility:public"],
+ x_defs = {"Bar": "Bar"},
+ deps = [
+ ":baz",
+ ":foo",
+ ],
+)
+
+go_library(
+ name = "baz",
+ srcs = ["baz.go"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_test/x_defs/baz",
+ visibility = ["//visibility:public"],
+ x_defs = {"Baz": "Baz"},
+ deps = [":qux"],
+)
+
+go_library(
+ name = "foo",
+ srcs = ["foo.go"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_test/x_defs/foo",
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "qux",
+ srcs = ["qux.go"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_test/x_defs/qux",
+ visibility = ["//visibility:public"],
+ x_defs = {"Qux": "Qux"},
+)
+
+go_library(
+ name = "x_defs_lib",
+ srcs = ["x_defs_lib.go"],
+ data = ["x_defs_lib.go"],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_test/x_defs/x_defs_lib",
+ x_defs = {
+ "LibGo": "$(rlocationpath x_defs_lib.go)",
+ },
+)
+
+go_test(
+ name = "x_defs_test",
+ srcs = ["x_defs_test.go"],
+ data = ["x_defs_test.go"],
+ x_defs = {
+ "BinGo": "$(rlocationpath x_defs_test.go)",
+ },
+ deps = [
+ ":x_defs_lib",
+ "//go/runfiles",
+ ],
+)
diff --git a/tests/core/go_test/x_defs/bar.go b/tests/core/go_test/x_defs/bar.go
new file mode 100644
index 00000000..1d0081a4
--- /dev/null
+++ b/tests/core/go_test/x_defs/bar.go
@@ -0,0 +1,10 @@
+package bar
+
+import (
+ "github.com/bazelbuild/rules_go/tests/core/go_test/x_defs/baz"
+ _ "github.com/bazelbuild/rules_go/tests/core/go_test/x_defs/foo"
+)
+
+var Bar string
+var Qux = baz.Qux
+var Baz = baz.Baz
diff --git a/tests/core/go_test/x_defs/baz.go b/tests/core/go_test/x_defs/baz.go
new file mode 100644
index 00000000..9d4334f7
--- /dev/null
+++ b/tests/core/go_test/x_defs/baz.go
@@ -0,0 +1,6 @@
+package baz
+
+import "github.com/bazelbuild/rules_go/tests/core/go_test/x_defs/qux"
+
+var Baz string
+var Qux = qux.Qux
diff --git a/tests/core/go_test/x_defs/foo.go b/tests/core/go_test/x_defs/foo.go
new file mode 100644
index 00000000..f52652b1
--- /dev/null
+++ b/tests/core/go_test/x_defs/foo.go
@@ -0,0 +1 @@
+package foo
diff --git a/tests/core/go_test/x_defs/foo_test.go b/tests/core/go_test/x_defs/foo_test.go
new file mode 100644
index 00000000..dc940509
--- /dev/null
+++ b/tests/core/go_test/x_defs/foo_test.go
@@ -0,0 +1,28 @@
+package foo_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/tests/core/go_test/x_defs/bar"
+)
+
+func TestBar(t *testing.T) {
+ Equal(t, "Bar", bar.Bar)
+}
+
+func TestBaz(t *testing.T) {
+ Equal(t, "Baz", bar.Baz)
+}
+
+func TestQux(t *testing.T) {
+ Equal(t, "Qux", bar.Qux)
+}
+
+func Equal(t *testing.T, expected string, actual string) bool {
+ if expected != actual {
+ t.Errorf("Not equal: \n"+
+ "expected: %s\n"+
+ "actual : %s", expected, actual)
+ }
+ return true
+}
diff --git a/tests/core/go_test/x_defs/qux.go b/tests/core/go_test/x_defs/qux.go
new file mode 100644
index 00000000..4983170c
--- /dev/null
+++ b/tests/core/go_test/x_defs/qux.go
@@ -0,0 +1,3 @@
+package qux
+
+var Qux string
diff --git a/tests/core/go_test/x_defs/x_defs_lib.go b/tests/core/go_test/x_defs/x_defs_lib.go
new file mode 100644
index 00000000..e7794b33
--- /dev/null
+++ b/tests/core/go_test/x_defs/x_defs_lib.go
@@ -0,0 +1,3 @@
+package x_defs_lib
+
+var LibGo = "not set"
diff --git a/tests/core/go_test/x_defs/x_defs_test.go b/tests/core/go_test/x_defs/x_defs_test.go
new file mode 100644
index 00000000..0832c247
--- /dev/null
+++ b/tests/core/go_test/x_defs/x_defs_test.go
@@ -0,0 +1,34 @@
+package x_defs_lib_test
+
+import (
+ "os"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/runfiles"
+
+ "github.com/bazelbuild/rules_go/tests/core/go_test/x_defs/x_defs_lib"
+)
+
+var BinGo = "not set"
+
+func TestLibGoPath(t *testing.T) {
+ libGoPath, err := runfiles.Rlocation(x_defs_lib.LibGo)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = os.Stat(libGoPath)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestBinGoPath(t *testing.T) {
+ binGoPath, err := runfiles.Rlocation(BinGo)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = os.Stat(binGoPath)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/tests/core/go_test/xmlreport_test.go b/tests/core/go_test/xmlreport_test.go
new file mode 100644
index 00000000..09198356
--- /dev/null
+++ b/tests/core/go_test/xmlreport_test.go
@@ -0,0 +1,163 @@
+// Copyright 2020 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.
+
+package test_filter_test
+
+import (
+ "encoding/xml"
+ "io/ioutil"
+ "path/filepath"
+ "reflect"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_test")
+
+go_test(
+ name = "xml_test",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/go_test/xml_test",
+ srcs = ["xml_test.go"],
+)
+
+-- xml_test.go --
+package test
+
+import (
+ "math/rand"
+ "testing"
+ "time"
+)
+
+func TestPass(t *testing.T) {
+ t.Parallel()
+}
+
+func TestPassLog(t *testing.T) {
+ t.Parallel()
+ t.Log("pass")
+}
+
+func TestFail(t *testing.T) {
+ t.Error("Not working")
+}
+
+func TestSubtests(t *testing.T) {
+ for i, subtest := range []string{"subtest a", "testB", "another subtest"} {
+ t.Run(subtest, func(t *testing.T) {
+ t.Logf("from subtest %s", subtest)
+ time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond)
+ t.Logf("from subtest %s", subtest)
+ if i%3 == 0 {
+ t.Skip("skipping this test")
+ }
+ if i%2 == 0 {
+ t.Fail()
+ }
+ })
+ }
+}
+`,
+ })
+}
+
+// test execution time attributes will vary per testrun, so we must parse the
+// xml to inspect a subset of testresults
+type xmlTestSuite struct {
+ XMLName xml.Name `xml:"testsuite"`
+ Errors int `xml:"errors,attr"`
+ Failures int `xml:"failures,attr"`
+ Skipped int `xml:"skipped,attr"`
+ Tests int `xml:"tests,attr"`
+ Name string `xml:"name,attr"`
+}
+type xmlTestSuites struct {
+ XMLName xml.Name `xml:"testsuites"`
+ Suites []xmlTestSuite `xml:"testsuite"`
+}
+
+func Test(t *testing.T) {
+ tests := []struct {
+ name string
+ args []string
+ expected xmlTestSuites
+ }{
+ {
+ name: "default",
+ args: []string{"test", "//:xml_test"},
+ expected: xmlTestSuites{
+ XMLName: xml.Name{Local: "testsuites"},
+ Suites: []xmlTestSuite{{
+ XMLName: xml.Name{Local: "testsuite"},
+ Name: "github.com/bazelbuild/rules_go/tests/core/go_test/xml_test",
+ Errors: 0,
+ Failures: 3,
+ Tests: 3,
+ }},
+ },
+ },
+ {
+ name: "verbose",
+ args: []string{"test", "--test_env=GO_TEST_WRAP_TESTV=1", "//:xml_test"},
+ expected: xmlTestSuites{
+ XMLName: xml.Name{Local: "testsuites"},
+ Suites: []xmlTestSuite{{
+ XMLName: xml.Name{Local: "testsuite"},
+ Name: "github.com/bazelbuild/rules_go/tests/core/go_test/xml_test",
+ Errors: 0,
+ Failures: 3,
+ Skipped: 1,
+ Tests: 7,
+ }},
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ err := bazel_testing.RunBazel(tt.args...)
+ if err == nil {
+ t.Fatal("expected bazel test to have failed")
+ }
+ if xerr, ok := err.(*bazel_testing.StderrExitError); !ok || xerr.Err.ExitCode() != 3 {
+ t.Fatalf("expected bazel tests to fail with exit code 3 (TESTS_FAILED), got: %s", err)
+ }
+
+ p, err := bazel_testing.BazelOutput("info", "bazel-testlogs")
+ if err != nil {
+ t.Fatal("could not find testlog root: %s", err)
+ }
+ path := filepath.Join(strings.TrimSpace(string(p)), "xml_test/test.xml")
+ b, err := ioutil.ReadFile(path)
+ if err != nil {
+ t.Fatalf("could not read generated xml file: %s", err)
+ }
+
+ var suites xmlTestSuites
+ if err := xml.Unmarshal(b, &suites); err != nil {
+ t.Fatalf("could not unmarshall generated xml: %s", err)
+ }
+
+ if !reflect.DeepEqual(suites, tt.expected) {
+ t.Fatalf("expected %#v, got: %#v", tt.expected, suites)
+ }
+ })
+ }
+}
diff --git a/tests/core/go_test/y b/tests/core/go_test/y
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_test/y
diff --git a/tests/core/go_test/z b/tests/core/go_test/z
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/go_test/z
diff --git a/tests/core/importmap/BUILD.bazel b/tests/core/importmap/BUILD.bazel
new file mode 100644
index 00000000..115ab878
--- /dev/null
+++ b/tests/core/importmap/BUILD.bazel
@@ -0,0 +1,45 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+test_suite(
+ name = "importmap",
+)
+
+go_library(
+ name = "lib_a",
+ srcs = ["lib.go"],
+ importmap = "a/lib",
+ importpath = "lib",
+ x_defs = {"Value": "ValueA"},
+)
+
+go_library(
+ name = "lib_b",
+ srcs = ["lib.go"],
+ importmap = "b/lib",
+ importpath = "lib",
+ x_defs = {"Value": "ValueB"},
+)
+
+go_library(
+ name = "a",
+ srcs = ["import.go"],
+ importpath = "a",
+ deps = [":lib_a"],
+)
+
+go_library(
+ name = "b",
+ srcs = ["import.go"],
+ importpath = "b",
+ deps = [":lib_b"],
+)
+
+go_test(
+ name = "importmap_test",
+ size = "small",
+ srcs = ["importmap_test.go"],
+ deps = [
+ ":a",
+ ":b",
+ ],
+)
diff --git a/tests/core/importmap/README.rst b/tests/core/importmap/README.rst
new file mode 100644
index 00000000..7abf58d5
--- /dev/null
+++ b/tests/core/importmap/README.rst
@@ -0,0 +1,16 @@
+Import maps
+===========
+
+.. _go_library: /docs/go/core/rules.md#_go_library
+
+Tests to ensure that importmap is working as expected.
+
+.. contents::
+
+importmap_test
+--------------
+
+Test that importmap declarations on go_library_ are propagated and obeyed.
+This builds libraries using `src.go <src.go>`_ as multiple outputs with the differing importpaths,
+adds identical importmap declarations and then checks that the libraries can be correctly imported
+without colliding through differing intermediate libraries into `the main test <importmap_test.go>`_.
diff --git a/tests/core/importmap/import.go b/tests/core/importmap/import.go
new file mode 100644
index 00000000..6d70cbfc
--- /dev/null
+++ b/tests/core/importmap/import.go
@@ -0,0 +1,24 @@
+/* Copyright 2017 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.
+*/
+
+package importmap
+
+import (
+ "lib"
+)
+
+func Get() string {
+ return lib.Value
+}
diff --git a/tests/core/importmap/importmap_test.go b/tests/core/importmap/importmap_test.go
new file mode 100644
index 00000000..dc1d18b0
--- /dev/null
+++ b/tests/core/importmap/importmap_test.go
@@ -0,0 +1,31 @@
+/* Copyright 2017 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.
+*/
+
+package importmap_test
+
+import (
+ a "a"
+ b "b"
+ "testing"
+)
+
+func TestImportmap(t *testing.T) {
+ if a.Get() != "ValueA" {
+ t.Errorf("Got %v from a instead of ValueA", a.Get())
+ }
+ if b.Get() != "ValueB" {
+ t.Errorf("Got %v from b instead of ValueB", b.Get())
+ }
+}
diff --git a/tests/core/importmap/lib.go b/tests/core/importmap/lib.go
new file mode 100644
index 00000000..a4ad9c47
--- /dev/null
+++ b/tests/core/importmap/lib.go
@@ -0,0 +1,18 @@
+/* Copyright 2017 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.
+*/
+
+package lib
+
+var Value = "Unstamped"
diff --git a/tests/core/nogo/BUILD.bazel b/tests/core/nogo/BUILD.bazel
new file mode 100644
index 00000000..46c7ee89
--- /dev/null
+++ b/tests/core/nogo/BUILD.bazel
@@ -0,0 +1,5 @@
+filegroup(
+ name = "rules_go_deps",
+ srcs = [":common.bzl"],
+ visibility = ["//visibility:public"],
+)
diff --git a/tests/core/nogo/README.rst b/tests/core/nogo/README.rst
new file mode 100644
index 00000000..06b4e12a
--- /dev/null
+++ b/tests/core/nogo/README.rst
@@ -0,0 +1,18 @@
+Core Go rules tests
+===================
+
+This contains tests of the nogo build-time code analysis tool.
+
+Contents
+--------
+
+.. Child list start
+
+* `Vet check <vet/README.rst>`_
+* `Nogo configuration <config/README.rst>`_
+* `nogo analyzers with dependencies <deps/README.rst>`_
+* `Custom nogo analyzers <custom/README.rst>`_
+* `nogo test with coverage <coverage/README.rst>`_
+
+.. Child list end
+
diff --git a/tests/core/nogo/common.bzl b/tests/core/nogo/common.bzl
new file mode 100644
index 00000000..14089ce2
--- /dev/null
+++ b/tests/core/nogo/common.bzl
@@ -0,0 +1,38 @@
+# Macros used by all nogo integration tests.
+
+BUILD_FAILED_TMPL = """
+if [[ result -eq 0 ]]; then
+ echo "TEST FAILED: expected build error" >&2
+ result=1
+else
+ result=0
+ {check_err}
+fi
+"""
+
+BUILD_PASSED_TMPL = """
+if [[ result -ne 0 ]]; then
+ echo "TEST FAILED: unexpected build error" >&2
+ result=1
+else
+ {check_err}
+fi
+"""
+
+CONTAINS_ERR_TMPL = """
+ lines=$(grep '{err}' bazel-output.txt | wc -l)
+ if [ $lines -eq 0 ]; then
+ echo "TEST FAILED: expected error message containing: '{err}'" >&2
+ result=1
+ elif [ $lines -ne 1 ]; then
+ echo "TEST FAILED: expected error message '{err}' appears more than once" >&2
+ result=1
+ fi
+"""
+
+DOES_NOT_CONTAIN_ERR_TMPL = """
+ if grep -q '{err}' bazel-output.txt; then
+ echo "TEST FAILED: received error message containing: '{err}'" >&2
+ result=1
+ fi
+"""
diff --git a/tests/core/nogo/config/BUILD.bazel b/tests/core/nogo/config/BUILD.bazel
new file mode 100644
index 00000000..ce5ad406
--- /dev/null
+++ b/tests/core/nogo/config/BUILD.bazel
@@ -0,0 +1,6 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "config_test",
+ srcs = ["config_test.go"],
+)
diff --git a/tests/core/nogo/config/README.rst b/tests/core/nogo/config/README.rst
new file mode 100644
index 00000000..bcd4b730
--- /dev/null
+++ b/tests/core/nogo/config/README.rst
@@ -0,0 +1,17 @@
+Nogo configuration
+==================
+
+.. _nogo: /go/nogo.rst
+.. _go_binary: /docs/go/core/rules.md#_go_binary
+.. _#1850: https://github.com/bazelbuild/rules_go/issues/1850
+.. _#2470: https://github.com/bazelbuild/rules_go/issues/2470
+
+Tests that verify nogo_ works on targets compiled in non-default configurations.
+
+.. contents::
+
+config_test
+-----------
+
+Verifies that a `go_binary`_ can be built in non-default configurations with
+nogo. Verifies `#1850`_, `#2470`_.
diff --git a/tests/core/nogo/config/config_test.go b/tests/core/nogo/config/config_test.go
new file mode 100644
index 00000000..3758d438
--- /dev/null
+++ b/tests/core/nogo/config/config_test.go
@@ -0,0 +1,62 @@
+// Copyright 2019 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.
+
+package config_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Nogo: "@io_bazel_rules_go//:tools_nogo",
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
+
+go_binary(
+ name = "shared_bin",
+ srcs = ["shared_bin.go"],
+ linkmode = "c-shared",
+ deps = [":shared_lib"],
+)
+
+go_library(
+ name = "shared_lib",
+ srcs = ["shared_lib.go"],
+ importpath = "example.com/nogo/config/shared_lib",
+)
+
+-- shared_bin.go --
+package main
+
+import _ "example.com/nogo/config/shared_lib"
+
+func main() {
+}
+
+-- shared_lib.go --
+package shared_lib
+
+`,
+ })
+}
+
+func TestShared(t *testing.T) {
+ if err := bazel_testing.RunBazel("build", "//:shared_bin"); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/tests/core/nogo/coverage/BUILD.bazel b/tests/core/nogo/coverage/BUILD.bazel
new file mode 100644
index 00000000..b14fcaf4
--- /dev/null
+++ b/tests/core/nogo/coverage/BUILD.bazel
@@ -0,0 +1,11 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "coverage_test",
+ srcs = ["coverage_test.go"],
+)
+
+go_bazel_test(
+ name = "gen_code_test",
+ srcs = ["gen_code_test.go"],
+)
diff --git a/tests/core/nogo/coverage/README.rst b/tests/core/nogo/coverage/README.rst
new file mode 100644
index 00000000..2bb6de95
--- /dev/null
+++ b/tests/core/nogo/coverage/README.rst
@@ -0,0 +1,23 @@
+nogo test with coverage
+=======================
+
+.. _nogo: /go/nogo.rst
+.. _#1940: https://github.com/bazelbuild/rules_go/issues/1940
+.. _#2146: https://github.com/bazelbuild/rules_go/issues/2146
+
+Tests to ensure that `nogo`_ works with coverage.
+
+coverage_test
+-------------
+Checks that `nogo`_ works when coverage is enabled. All covered libraries gain
+an implicit dependencies on ``//go/tools/coverdata``, which is a
+`go_tool_library`_, which isn't built with `nogo`_. We should be able to
+handle libraries like this that do not have serialized facts. Verifies `#1940`_.
+
+Also checks that `nogo`_ itself can be built with coverage enabled.
+Verifies `#2146`_.
+
+gen_code_test
+-------------
+Checks how `nogo`_ should not run on source code that was generated as part of
+rules_go's coverage implementation.
diff --git a/tests/core/nogo/coverage/coverage_test.go b/tests/core/nogo/coverage/coverage_test.go
new file mode 100644
index 00000000..97dc63dc
--- /dev/null
+++ b/tests/core/nogo/coverage/coverage_test.go
@@ -0,0 +1,65 @@
+// Copyright 2019 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.
+
+package coverage_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_test", "go_tool_library", "nogo")
+
+go_test(
+ name = "coverage_target",
+ srcs = ["coverage_target_test.go"],
+ deps = [":coverage_target_dep"],
+)
+
+go_tool_library(
+ name = "coverage_target_dep",
+ importmap = "mapped/coverage_target/dep",
+ importpath = "coverage_target/dep",
+)
+
+nogo(
+ name = "nogo",
+ vet = True,
+ visibility = ["//visibility:public"],
+)
+-- coverage_target_test.go --
+package coverage_target_test
+`,
+ Nogo: `@//:nogo`,
+ })
+}
+
+func TestCoverageWithNogo(t *testing.T) {
+ if out, err := bazel_testing.BazelOutput("coverage", "//:coverage_target"); err != nil {
+ println(string(out))
+ t.Fatal(err)
+ }
+}
+
+func TestCoverageOfNogo(t *testing.T) {
+ if out, err := bazel_testing.BazelOutput("build", "--instrumentation_filter=.*", "--collect_code_coverage", "//:nogo"); err != nil {
+ println(string(out))
+ t.Fatal(err)
+ }
+}
diff --git a/tests/core/nogo/coverage/gen_code_test.go b/tests/core/nogo/coverage/gen_code_test.go
new file mode 100644
index 00000000..6f2c55b6
--- /dev/null
+++ b/tests/core/nogo/coverage/gen_code_test.go
@@ -0,0 +1,130 @@
+// Copyright 2019 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.
+
+package gen_code_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test", "nogo")
+
+go_library(
+ name = "simple",
+ srcs = ["simple.go"],
+ importpath = "simple"
+)
+
+go_test(
+ name = "simple_test",
+ srcs = ["simple_test.go"],
+ embed = [":simple"]
+)
+
+nogo(
+ name = "nogo",
+ deps = ["//nocover"],
+ visibility = ["//visibility:public"],
+)
+-- simple.go --
+package simple
+
+func Foo() string {
+ return "foo"
+}
+-- simple_test.go --
+package simple
+
+import "testing"
+
+func TestFoo(t *testing.T) {
+ if actual, expected := Foo(), "foo"; actual != expected {
+ t.Errorf("Foo() should return foo")
+ }
+}
+-- nocover/BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "nocover",
+ srcs = ["analyzer.go"],
+ importpath = "nocover",
+ visibility = ["//visibility:public"],
+ deps = [
+ "@org_golang_x_tools//go/analysis",
+ "@org_golang_x_tools//go/analysis/passes/inspect",
+ "@org_golang_x_tools//go/ast/inspector",
+ ],
+)
+-- nocover/analyzer.go --
+package nocover
+
+import (
+ "fmt"
+ "go/ast"
+ "strings"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/analysis/passes/inspect"
+ "golang.org/x/tools/go/ast/inspector"
+)
+
+var Analyzer = &analysis.Analyzer{
+ Name: "nocover",
+ Doc: "nocover ensure that source code was not a generated file created by rules_go's coverage implementation",
+ Run: run,
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ inspector := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+
+ inspector.Preorder([]ast.Node{(*ast.ValueSpec)(nil)}, func(node ast.Node) {
+ valueSpec := node.(*ast.ValueSpec)
+ if len(valueSpec.Names) != 1 {
+ return
+ }
+
+ varName := valueSpec.Names[0].Name
+
+ // check for coverage variable name that matches this pattern: CoverZ%sZ%dZ%s
+ // see go/tools/builders/compilepkg.go -> coverVar for more information
+ if strings.HasPrefix(varName, "CoverZ") && strings.Count(varName, "Z") >= 3 {
+ pass.Report(analysis.Diagnostic{
+ Pos: valueSpec.Pos(),
+ End: valueSpec.End(),
+ Message: fmt.Sprintf("variable %s was generated by rules_go", varName),
+ })
+ }
+ })
+
+ return nil, nil
+}
+`,
+ Nogo: `@//:nogo`,
+ })
+}
+
+func TestNogoCoverGenCode(t *testing.T) {
+ if out, err := bazel_testing.BazelOutput("coverage", "//:simple_test"); err != nil {
+ println(string(out))
+ t.Fatal(err)
+ }
+}
diff --git a/tests/core/nogo/custom/BUILD.bazel b/tests/core/nogo/custom/BUILD.bazel
new file mode 100644
index 00000000..06317a0b
--- /dev/null
+++ b/tests/core/nogo/custom/BUILD.bazel
@@ -0,0 +1,6 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "custom_test",
+ srcs = ["custom_test.go"],
+)
diff --git a/tests/core/nogo/custom/README.rst b/tests/core/nogo/custom/README.rst
new file mode 100644
index 00000000..285c8ff6
--- /dev/null
+++ b/tests/core/nogo/custom/README.rst
@@ -0,0 +1,16 @@
+Custom nogo analyzers
+=====================
+
+.. _nogo: /go/nogo.rst
+.. _go_library: /docs/go/core/rules.md#_go_library
+
+Tests to ensure that custom `nogo`_ analyzers run and detect errors.
+
+.. contents::
+
+custom_test
+-----------
+Verifies that custom analyzers print errors and fail a `go_library`_ build when
+a configuration file is not provided, and that analyzers with the same package
+name do not conflict. Also checks that custom analyzers can be configured to
+apply only to certain file paths using a custom configuration file.
diff --git a/tests/core/nogo/custom/custom_test.go b/tests/core/nogo/custom/custom_test.go
new file mode 100644
index 00000000..27624431
--- /dev/null
+++ b/tests/core/nogo/custom/custom_test.go
@@ -0,0 +1,510 @@
+// Copyright 2019 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.
+
+package custom_test
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "regexp"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+const origConfig = `# config = "",`
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Nogo: "@//:nogo",
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "nogo")
+
+nogo(
+ name = "nogo",
+ deps = [
+ ":foofuncname",
+ ":importfmt",
+ ":visibility",
+ ],
+ # config = "",
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "importfmt",
+ srcs = ["importfmt.go"],
+ importpath = "importfmtanalyzer",
+ deps = ["@org_golang_x_tools//go/analysis"],
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "foofuncname",
+ srcs = ["foofuncname.go"],
+ importpath = "foofuncanalyzer",
+ deps = ["@org_golang_x_tools//go/analysis"],
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "visibility",
+ srcs = ["visibility.go"],
+ importpath = "visibilityanalyzer",
+ deps = [
+ "@org_golang_x_tools//go/analysis",
+ "@org_golang_x_tools//go/ast/inspector",
+ ],
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "has_errors",
+ srcs = ["has_errors.go"],
+ importpath = "haserrors",
+ deps = [":dep"],
+)
+
+go_library(
+ name = "has_errors_linedirective",
+ srcs = ["has_errors_linedirective.go"],
+ importpath = "haserrors_linedirective",
+ deps = [":dep"],
+)
+
+go_library(
+ name = "uses_cgo_with_errors",
+ srcs = [
+ "examplepkg/uses_cgo_clean.go",
+ "examplepkg/pure_src_with_err_calling_native.go",
+ ],
+ importpath = "examplepkg",
+ cgo = True,
+)
+
+go_library(
+ name = "no_errors",
+ srcs = ["no_errors.go"],
+ importpath = "noerrors",
+ deps = [":dep"],
+)
+
+go_library(
+ name = "dep",
+ srcs = ["dep.go"],
+ importpath = "dep",
+)
+
+-- foofuncname.go --
+// importfmt checks for functions named "Foo".
+// It has the same package name as another check to test the checks with
+// the same package name do not conflict.
+package importfmt
+
+import (
+ "go/ast"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+const doc = "report calls of functions named \"Foo\"\n\nThe foofuncname analyzer reports calls to functions that are\nnamed \"Foo\"."
+
+var Analyzer = &analysis.Analyzer{
+ Name: "foofuncname",
+ Run: run,
+ Doc: doc,
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ for _, f := range pass.Files {
+ // TODO(samueltan): use package inspector once the latest golang.org/x/tools
+ // changes are pulled into this branch (see #1755).
+ ast.Inspect(f, func(n ast.Node) bool {
+ switch n := n.(type) {
+ case *ast.FuncDecl:
+ if n.Name.Name == "Foo" {
+ pass.Reportf(n.Pos(), "function must not be named Foo")
+ }
+ return true
+ }
+ return true
+ })
+ }
+ return nil, nil
+}
+
+-- importfmt.go --
+// importfmt checks for the import of package fmt.
+package importfmt
+
+import (
+ "go/ast"
+ "strconv"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+const doc = "report imports of package fmt\n\nThe importfmt analyzer reports imports of package fmt."
+
+var Analyzer = &analysis.Analyzer{
+ Name: "importfmt",
+ Run: run,
+ Doc: doc,
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ for _, f := range pass.Files {
+ // TODO(samueltan): use package inspector once the latest golang.org/x/tools
+ // changes are pulled into this branch (see #1755).
+ ast.Inspect(f, func(n ast.Node) bool {
+ switch n := n.(type) {
+ case *ast.ImportSpec:
+ if path, _ := strconv.Unquote(n.Path.Value); path == "fmt" {
+ pass.Reportf(n.Pos(), "package fmt must not be imported")
+ }
+ return true
+ }
+ return true
+ })
+ }
+ return nil, nil
+}
+
+-- visibility.go --
+// visibility looks for visibility annotations on functions and
+// checks they are only called from packages allowed to call them.
+package visibility
+
+import (
+ "encoding/gob"
+ "go/ast"
+ "regexp"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/ast/inspector"
+)
+
+var Analyzer = &analysis.Analyzer{
+ Name: "visibility",
+ Run: run,
+ Doc: "enforce visibility requirements for functions\n\nThe visibility analyzer reads visibility annotations on functions and\nchecks that packages that call those functions are allowed to do so.",
+ FactTypes: []analysis.Fact{(*VisibilityFact)(nil)},
+}
+
+type VisibilityFact struct {
+ Paths []string
+}
+
+func (_ *VisibilityFact) AFact() {} // dummy method to satisfy interface
+
+func init() { gob.Register((*VisibilityFact)(nil)) }
+
+var visibilityRegexp = regexp.MustCompile("visibility:([^\\s]+)")
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ in := inspector.New(pass.Files)
+
+ // Find visibility annotations on function declarations.
+ in.Nodes([]ast.Node{(*ast.FuncDecl)(nil)}, func(n ast.Node, push bool) (prune bool) {
+ if !push {
+ return false
+ }
+
+ fn := n.(*ast.FuncDecl)
+
+ if fn.Doc == nil {
+ return true
+ }
+ obj := pass.TypesInfo.ObjectOf(fn.Name)
+ if obj == nil {
+ return true
+ }
+ doc := fn.Doc.Text()
+
+ if matches := visibilityRegexp.FindAllStringSubmatch(doc, -1); matches != nil {
+ fact := &VisibilityFact{Paths: make([]string, len(matches))}
+ for i, m := range matches {
+ fact.Paths[i] = m[1]
+ }
+ pass.ExportObjectFact(obj, fact)
+ }
+
+ return true
+ })
+
+ // Find calls that may be affected by visibility declarations.
+ in.Nodes([]ast.Node{(*ast.CallExpr)(nil)}, func(n ast.Node, push bool) (prune bool) {
+ if !push {
+ return false
+ }
+
+ callee, ok := n.(*ast.CallExpr).Fun.(*ast.SelectorExpr)
+ if !ok {
+ return false
+ }
+ obj := pass.TypesInfo.ObjectOf(callee.Sel)
+ if obj == nil {
+ return false
+ }
+ var fact VisibilityFact
+ if ok := pass.ImportObjectFact(obj, &fact); !ok {
+ return false
+ }
+ visible := false
+ for _, path := range fact.Paths {
+ if path == pass.Pkg.Path() {
+ visible = true
+ break
+ }
+ }
+ if !visible {
+ pass.Reportf(callee.Pos(), "function %s is not visible in this package", callee.Sel.Name)
+ }
+
+ return false
+ })
+
+ return nil, nil
+}
+
+-- config.json --
+{
+ "importfmt": {
+ "only_files": {
+ "has_errors\\.go": ""
+ }
+ },
+ "foofuncname": {
+ "description": "no exemptions since we know this check is 100% accurate"
+ },
+ "visibility": {
+ "exclude_files": {
+ "has_.*\\.go": "special exception to visibility rules"
+ }
+ }
+}
+
+-- baseconfig.json --
+{
+ "_base": {
+ "exclude_files": {
+ "has_.*\\.go": "Visibility analyzer not specified. Still inherits this special exception."
+ }
+ },
+ "importfmt": {
+ "only_files": {
+ "has_errors\\.go": ""
+ }
+ },
+ "foofuncname": {
+ "description": "no exemptions since we know this check is 100% accurate, so override base config",
+ "exclude_files": {}
+ }
+}
+
+-- has_errors.go --
+package haserrors
+
+import (
+ _ "fmt" // This should fail importfmt
+
+ "dep"
+)
+
+func Foo() bool { // This should fail foofuncname
+ dep.D() // This should fail visibility
+ return true
+}
+
+-- has_errors_linedirective.go --
+//line linedirective.go:1
+package haserrors_linedirective
+
+import (
+ /*line linedirective_importfmt.go:4*/ _ "fmt" // This should fail importfmt
+
+ "dep"
+)
+
+//line linedirective_foofuncname.go:9
+func Foo() bool { // This should fail foofuncname
+//line linedirective_visibility.go:10
+ dep.D() // This should fail visibility
+ return true
+}
+
+-- no_errors.go --
+// package noerrors contains no analyzer errors.
+package noerrors
+
+import "dep"
+
+func Baz() int {
+ dep.D()
+ return 1
+}
+
+-- dep.go --
+package dep
+
+// visibility:noerrors
+func D() {
+}
+
+-- examplepkg/uses_cgo_clean.go --
+package examplepkg
+
+// #include <stdlib.h>
+import "C"
+
+func Bar() bool {
+ if C.rand() > 10 {
+ return true
+ }
+ return false
+}
+
+-- examplepkg/pure_src_with_err_calling_native.go --
+package examplepkg
+
+func Foo() bool { // This should fail foofuncname
+ return Bar()
+}
+
+`,
+ })
+}
+
+func Test(t *testing.T) {
+ for _, test := range []struct {
+ desc, config, target string
+ wantSuccess bool
+ includes, excludes []string
+ }{
+ {
+ desc: "default_config",
+ target: "//:has_errors",
+ wantSuccess: false,
+ includes: []string{
+ `has_errors.go:.*package fmt must not be imported \(importfmt\)`,
+ `has_errors.go:.*function must not be named Foo \(foofuncname\)`,
+ `has_errors.go:.*function D is not visible in this package \(visibility\)`,
+ },
+ }, {
+ desc: "default_config_linedirective",
+ target: "//:has_errors_linedirective",
+ wantSuccess: false,
+ includes: []string{
+ `linedirective_importfmt.go:.*package fmt must not be imported \(importfmt\)`,
+ `linedirective_foofuncname.go:.*function must not be named Foo \(foofuncname\)`,
+ `linedirective_visibility.go:.*function D is not visible in this package \(visibility\)`,
+ },
+ }, {
+ desc: "custom_config",
+ config: "config.json",
+ target: "//:has_errors",
+ wantSuccess: false,
+ includes: []string{
+ `has_errors.go:.*package fmt must not be imported \(importfmt\)`,
+ `has_errors.go:.*function must not be named Foo \(foofuncname\)`,
+ },
+ excludes: []string{
+ `visib`,
+ },
+ }, {
+ desc: "custom_config_linedirective",
+ config: "config.json",
+ target: "//:has_errors_linedirective",
+ wantSuccess: false,
+ includes: []string{
+ `linedirective_foofuncname.go:.*function must not be named Foo \(foofuncname\)`,
+ `linedirective_visibility.go:.*function D is not visible in this package \(visibility\)`,
+ },
+ excludes: []string{
+ `importfmt`,
+ },
+ }, {
+ desc: "custom_config_with_base_linedirective",
+ config: "baseconfig.json",
+ target: "//:has_errors_linedirective",
+ wantSuccess: false,
+ includes: []string{
+ `linedirective_foofuncname.go:.*function must not be named Foo \(foofuncname\)`,
+ `linedirective_visibility.go:.*function D is not visible in this package \(visibility\)`,
+ },
+ excludes: []string{
+ `importfmt`,
+ },
+ }, {
+ desc: "uses_cgo_with_errors",
+ config: "config.json",
+ target: "//:uses_cgo_with_errors",
+ wantSuccess: false,
+ includes: []string{
+ // note the cross platform regex :)
+ `.*[\\/]cgo[\\/]examplepkg[\\/]pure_src_with_err_calling_native.go:.*function must not be named Foo \(foofuncname\)`,
+ },
+ }, {
+ desc: "no_errors",
+ target: "//:no_errors",
+ wantSuccess: true,
+ excludes: []string{"no_errors.go"},
+ },
+ } {
+ t.Run(test.desc, func(t *testing.T) {
+ if test.config != "" {
+ customConfig := fmt.Sprintf("config = %q,", test.config)
+ if err := replaceInFile("BUILD.bazel", origConfig, customConfig); err != nil {
+ t.Fatal(err)
+ }
+ defer replaceInFile("BUILD.bazel", customConfig, origConfig)
+ }
+
+ cmd := bazel_testing.BazelCmd("build", test.target)
+ stderr := &bytes.Buffer{}
+ cmd.Stderr = stderr
+ if err := cmd.Run(); err == nil && !test.wantSuccess {
+ t.Fatal("unexpected success")
+ } else if err != nil && test.wantSuccess {
+ t.Fatalf("unexpected error: %v", err)
+ }
+
+ for _, pattern := range test.includes {
+ if matched, err := regexp.Match(pattern, stderr.Bytes()); err != nil {
+ t.Fatal(err)
+ } else if !matched {
+ t.Errorf("got output:\n %s\n which does not contain pattern: %s", string(stderr.Bytes()), pattern)
+ }
+ }
+ for _, pattern := range test.excludes {
+ if matched, err := regexp.Match(pattern, stderr.Bytes()); err != nil {
+ t.Fatal(err)
+ } else if matched {
+ t.Errorf("output contained pattern: %s", pattern)
+ }
+ }
+ })
+ }
+}
+
+func replaceInFile(path, old, new string) error {
+ data, err := ioutil.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ data = bytes.ReplaceAll(data, []byte(old), []byte(new))
+ return ioutil.WriteFile(path, data, 0666)
+}
diff --git a/tests/core/nogo/custom/flags/BUILD.bazel b/tests/core/nogo/custom/flags/BUILD.bazel
new file mode 100644
index 00000000..cdf4c76a
--- /dev/null
+++ b/tests/core/nogo/custom/flags/BUILD.bazel
@@ -0,0 +1,6 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "flags_test",
+ srcs = ["flags_test.go"],
+)
diff --git a/tests/core/nogo/custom/flags/README.rst b/tests/core/nogo/custom/flags/README.rst
new file mode 100644
index 00000000..e525250b
--- /dev/null
+++ b/tests/core/nogo/custom/flags/README.rst
@@ -0,0 +1,19 @@
+Custom nogo analyzer flags
+=====================
+
+.. _nogo: /go/nogo.rst
+.. _go_library: /docs/go/core/rules.md#_go_library
+
+Tests to ensure that custom `nogo`_ analyzers that consume flags can be
+supplied those flags via nono config.
+
+.. contents::
+
+flags_test
+-----------
+Verifies that a simple custom analyzer's behavior can be modified by setting
+its analyzer flags in the nogo driver, and that these flags can be provided to
+the driver via the nogo config `analyzer_flags` field. Also checks that
+invalid flags as defined by the `flag` package cause the driver to immediately
+return an error.
+
diff --git a/tests/core/nogo/custom/flags/flags_test.go b/tests/core/nogo/custom/flags/flags_test.go
new file mode 100644
index 00000000..7381a3f0
--- /dev/null
+++ b/tests/core/nogo/custom/flags/flags_test.go
@@ -0,0 +1,262 @@
+// Copyright 2019 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.
+
+package flags_test
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "regexp"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+const origConfig = `# config = "",`
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Nogo: "@//:nogo",
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "nogo")
+
+nogo(
+ name = "nogo",
+ deps = [
+ ":flagger",
+ ],
+ # config = "",
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "flagger",
+ srcs = ["flagger.go"],
+ importpath = "flaggeranalyzer",
+ deps = [
+ "@org_golang_x_tools//go/analysis",
+ ],
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "some_file",
+ srcs = ["some_file.go"],
+ importpath = "somefile",
+ deps = [":dep"],
+)
+
+go_library(
+ name = "dep",
+ srcs = ["dep.go"],
+ importpath = "dep",
+)
+
+-- flagger.go --
+// flagger crashes when three flags are set in the config or else it no-ops
+package flagger
+
+import (
+ "errors"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+var (
+ boolSwitch bool
+ stringSwitch string
+ intSwitch int
+)
+
+var Analyzer = &analysis.Analyzer{
+ Name: "flagger",
+ Run: run,
+ Doc: "Dummy analyzer that crashes when all its flags are set correctly",
+}
+
+func init() {
+ Analyzer.Flags.BoolVar(&boolSwitch, "bool-switch", false, "Bool must be set to true to run")
+ Analyzer.Flags.StringVar(&stringSwitch, "string-switch", "no", "String must be set to \"yes\" to run")
+ Analyzer.Flags.IntVar(&intSwitch, "int-switch", 0, "Int must be set to 1 to run")
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ if !boolSwitch {
+ return nil, nil
+ }
+ if stringSwitch != "yes" {
+ return nil, nil
+ }
+ if intSwitch != 1 {
+ return nil, nil
+ }
+ return nil, errors.New("all switches were set -> fail")
+}
+
+-- all_flags_set.json --
+{
+ "flagger": {
+ "description": "this will crash on every file",
+ "analyzer_flags": {
+ "bool-switch": "true",
+ "int-switch": "1",
+ "string-switch": "yes"
+ }
+ }
+}
+
+-- two_flags_set.json --
+{
+ "flagger": {
+ "description": "this will succeed on every file",
+ "analyzer_flags": {
+ "bool-switch": "true",
+ "int-switch": "1"
+ }
+ }
+}
+
+-- invalid_int.json --
+{
+ "flagger": {
+ "description": "this will crash immediately due to an invalid int flag",
+ "analyzer_flags": {
+ "int-switch": "one",
+ "string-switch": "yes"
+ }
+ }
+}
+
+-- nonexistent_flag.json --
+{
+ "flagger": {
+ "description": "this will crash immediately due to a nonexistent flag",
+ "analyzer_flags": {
+ "int-switch": "1",
+ "bool-switch": "true",
+ "string-switch": "yes",
+ "description": "This is a good analyzer"
+ }
+ }
+}
+
+-- hyphenated_flag.json --
+{
+ "flagger": {
+ "description": "this will crash immediately due to a hyphenated flag",
+ "analyzer_flags": {
+ "-int-switch": "1"
+ }
+ }
+}
+
+-- some_file.go --
+// package somefile contains a file and has a dep
+package somefile
+
+import "dep"
+
+func Baz() int {
+ dep.D()
+ return 1
+}
+
+-- dep.go --
+package dep
+
+func D() {
+}
+
+`,
+ })
+}
+
+func Test(t *testing.T) {
+ for _, test := range []struct {
+ desc, config string
+ wantSuccess bool
+ includes, excludes []string
+ }{
+ {
+ desc: "config_flags_triggering_error",
+ wantSuccess: false,
+ config: "all_flags_set.json",
+ includes: []string{"all switches were set -> fail"},
+ }, {
+ desc: "config_flags_triggering_success",
+ wantSuccess: true,
+ config: "two_flags_set.json",
+ }, {
+ desc: "invalid_int_triggering_error",
+ wantSuccess: false,
+ config: "invalid_int.json",
+ includes: []string{"flagger: invalid value for flag: int-switch=one"},
+ }, {
+ desc: "nonexistent_flag_triggering_error",
+ wantSuccess: false,
+ config: "nonexistent_flag.json",
+ includes: []string{"flagger: unrecognized flag: description"},
+ }, {
+ desc: "hyphenated_flag_triggering_error",
+ wantSuccess: false,
+ config: "hyphenated_flag.json",
+ includes: []string{"flagger: flag should not begin with '-': -int-switch"},
+ },
+ } {
+ t.Run(test.desc, func(t *testing.T) {
+ if test.config != "" {
+ customConfig := fmt.Sprintf("config = %q,", test.config)
+ if err := replaceInFile("BUILD.bazel", origConfig, customConfig); err != nil {
+ t.Fatal(err)
+ }
+ defer replaceInFile("BUILD.bazel", customConfig, origConfig)
+ }
+
+ cmd := bazel_testing.BazelCmd("build", "//:some_file")
+ stderr := &bytes.Buffer{}
+ cmd.Stderr = stderr
+ if err := cmd.Run(); err == nil && !test.wantSuccess {
+ t.Fatal("unexpected success")
+ } else if err != nil && test.wantSuccess {
+ t.Fatalf("unexpected error: %v", err)
+ }
+
+ for _, pattern := range test.includes {
+ if matched, err := regexp.Match(pattern, stderr.Bytes()); err != nil {
+ t.Fatal(err)
+ } else if !matched {
+ t.Errorf("got output:\n %s\n which does not contain pattern: %s", string(stderr.Bytes()), pattern)
+ }
+ }
+ for _, pattern := range test.excludes {
+ if matched, err := regexp.Match(pattern, stderr.Bytes()); err != nil {
+ t.Fatal(err)
+ } else if matched {
+ t.Errorf("output contained pattern: %s", pattern)
+ }
+ }
+ })
+ }
+}
+
+func replaceInFile(path, old, new string) error {
+ data, err := ioutil.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ data = bytes.ReplaceAll(data, []byte(old), []byte(new))
+ return ioutil.WriteFile(path, data, 0666)
+}
diff --git a/tests/core/nogo/deps/BUILD.bazel b/tests/core/nogo/deps/BUILD.bazel
new file mode 100644
index 00000000..a1d998fd
--- /dev/null
+++ b/tests/core/nogo/deps/BUILD.bazel
@@ -0,0 +1,6 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "deps_test",
+ srcs = ["deps_test.go"],
+)
diff --git a/tests/core/nogo/deps/README.rst b/tests/core/nogo/deps/README.rst
new file mode 100644
index 00000000..93affd23
--- /dev/null
+++ b/tests/core/nogo/deps/README.rst
@@ -0,0 +1,26 @@
+nogo analyzers with dependencies
+=============================
+
+.. _nogo: /go/nogo.rst
+.. _go_library: /docs/go/core/rules.md#_go_library
+
+Tests to ensure that custom `nogo`_ analyzers that depend on each other are
+run in the correct order.
+
+.. contents::
+
+deps_test
+---------
+Given the following dependency graph of analyzers:
+
+ a ----+
+ |
+ v
+ b --> c --> d
+
+Where analyzers a, b, c are explicitly depended on by the `nogo`_ rule and d
+isn't, verifies that a `go_library`_ build causes both paths in the graph
+(a->c->d and b->c->d) to be executed, and that each analyzer runs exactly once.
+
+Also verify that the diagnostics reported by d are not printed to the build log
+since d was not explicitly depended on by the declared `nogo`_ rule.
diff --git a/tests/core/nogo/deps/deps_test.go b/tests/core/nogo/deps/deps_test.go
new file mode 100644
index 00000000..f527effd
--- /dev/null
+++ b/tests/core/nogo/deps/deps_test.go
@@ -0,0 +1,211 @@
+// Copyright 2019 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.
+
+package deps_test
+
+import (
+ "bytes"
+ "regexp"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Nogo: "@//:nogo",
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "nogo")
+
+nogo(
+ name = "nogo",
+ deps = [
+ ":a",
+ ":b",
+ ":c",
+ ],
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "a",
+ srcs = ["a.go"],
+ importpath = "a",
+ deps = [
+ ":c",
+ "@org_golang_x_tools//go/analysis"
+ ],
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "b",
+ srcs = ["b.go"],
+ importpath = "b",
+ deps = [
+ ":c",
+ "@org_golang_x_tools//go/analysis"
+ ],
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "c",
+ srcs = ["c.go"],
+ importpath = "c",
+ deps = [
+ ":d",
+ "@org_golang_x_tools//go/analysis"
+ ],
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "d",
+ srcs = ["d.go"],
+ importpath = "d",
+ deps = ["@org_golang_x_tools//go/analysis"],
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "src",
+ srcs = ["src.go"],
+ importpath = "src",
+)
+
+-- a.go --
+package a
+
+import (
+ "c"
+ "go/token"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+var Analyzer = &analysis.Analyzer{
+ Name: "a",
+ Doc: "an analyzer that depends on c.Analyzer",
+ Run: run,
+ Requires: []*analysis.Analyzer{c.Analyzer},
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ pass.Reportf(token.NoPos, "a %s", pass.ResultOf[c.Analyzer])
+ return nil, nil
+}
+
+-- b.go --
+package b
+
+import (
+ "c"
+ "go/token"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+var Analyzer = &analysis.Analyzer{
+ Name: "b",
+ Doc: "an analyzer that depends on c.Analyzer",
+ Run: run,
+ Requires: []*analysis.Analyzer{c.Analyzer},
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ pass.Reportf(token.NoPos, "b %s", pass.ResultOf[c.Analyzer])
+ return nil, nil
+}
+
+-- c.go --
+package c
+
+import (
+ "d"
+ "fmt"
+ "go/token"
+ "reflect"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+var Analyzer = &analysis.Analyzer{
+ Name: "c",
+ Doc: "an analyzer that depends on d.Analyzer",
+ Run: run,
+ Requires: []*analysis.Analyzer{d.Analyzer},
+ ResultType: reflect.TypeOf(""),
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ pass.Reportf(token.NoPos, "only printed once")
+ return fmt.Sprintf("c %s", pass.ResultOf[d.Analyzer]), nil
+}
+
+-- d.go --
+package d
+
+import (
+ "go/token"
+ "reflect"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+var Analyzer = &analysis.Analyzer{
+ Name: "d",
+ Doc: "an analyzer that does not depend on other analyzers",
+ Run: run,
+ ResultType: reflect.TypeOf(""),
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ pass.Reportf(token.NoPos, "this should not be printed")
+ return "d", nil
+}
+
+-- src.go --
+package src
+
+func Foo() int {
+ return 1
+}
+
+`,
+ })
+}
+
+func Test(t *testing.T) {
+ cmd := bazel_testing.BazelCmd("build", "//:src")
+ stderr := &bytes.Buffer{}
+ cmd.Stderr = stderr
+ if err := cmd.Run(); err == nil {
+ t.Fatal("unexpected success")
+ }
+
+ for _, pattern := range []string{
+ "a c d",
+ "b c d",
+ "only printed once",
+ } {
+ if matched, _ := regexp.Match(pattern, stderr.Bytes()); !matched {
+ t.Errorf("output does not contain pattern: %s", pattern)
+ }
+ }
+ if bytes.Contains(stderr.Bytes(), []byte("this should not be printed")) {
+ t.Errorf("%q was printed", "this should not be printed")
+ }
+}
diff --git a/tests/core/nogo/generate/BUILD.bazel b/tests/core/nogo/generate/BUILD.bazel
new file mode 100644
index 00000000..52567b61
--- /dev/null
+++ b/tests/core/nogo/generate/BUILD.bazel
@@ -0,0 +1,6 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "empty_test",
+ srcs = ["empty_test.go"],
+)
diff --git a/tests/core/nogo/generate/README.rst b/tests/core/nogo/generate/README.rst
new file mode 100644
index 00000000..d9604fab
--- /dev/null
+++ b/tests/core/nogo/generate/README.rst
@@ -0,0 +1,12 @@
+nogo test with generated code
+=======================
+
+.. _nogo: /go/nogo.rst
+
+Tests to ensure `nogo`_ interaction with generated code.
+
+empty_test
+-------------
+Checks that `nogo`_ is not running over the `_empty.go` file that was
+generated as part of GoCompilePkg.
+
diff --git a/tests/core/nogo/generate/empty_test.go b/tests/core/nogo/generate/empty_test.go
new file mode 100644
index 00000000..a4f8de12
--- /dev/null
+++ b/tests/core/nogo/generate/empty_test.go
@@ -0,0 +1,102 @@
+// Copyright 2019 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.
+
+package empty_test
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test", "nogo")
+
+go_test(
+ name = "simple_test",
+ size = "small",
+ srcs = ["simple_test.go"],
+)
+
+nogo(
+ name = "nogo",
+ deps = ["//noempty"],
+ visibility = ["//visibility:public"],
+)
+-- simple_test.go --
+package simple
+
+import (
+ "testing"
+)
+
+func TestFoo(t *testing.T) {
+}
+-- noempty/BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "noempty",
+ srcs = ["analyzer.go"],
+ importpath = "noempty",
+ visibility = ["//visibility:public"],
+ deps = [
+ "@org_golang_x_tools//go/analysis",
+ ],
+)
+-- noempty/analyzer.go --
+package noempty
+
+import (
+ "fmt"
+ "path/filepath"
+ "strings"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+var Analyzer = &analysis.Analyzer{
+ Name: "noempty",
+ Doc: "noempty ensure that source code was not a generated file created by rules_go test rewrite",
+ Run: run,
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ for _, f := range pass.Files {
+ pos := pass.Fset.PositionFor(f.Pos(), false)
+
+ if strings.HasSuffix(pos.Filename, filepath.Join(".", "_empty.go")) {
+ pass.Report(analysis.Diagnostic{
+ Pos: 0,
+ Message: fmt.Sprintf("Detected generated source code from rules_go: %s", pos.Filename),
+ })
+ }
+ }
+
+ return nil, nil
+}
+`,
+ Nogo: `@//:nogo`,
+ })
+}
+
+func TestNogoGenEmptyCode(t *testing.T) {
+ if out, err := bazel_testing.BazelOutput("build", "-k", "//:simple_test"); err != nil {
+ println(string(out))
+ t.Fatal(err)
+ }
+}
diff --git a/tests/core/nogo/generics/BUILD.bazel b/tests/core/nogo/generics/BUILD.bazel
new file mode 100644
index 00000000..a40df345
--- /dev/null
+++ b/tests/core/nogo/generics/BUILD.bazel
@@ -0,0 +1,6 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "generics_test",
+ srcs = ["generics_test.go"],
+)
diff --git a/tests/core/nogo/generics/README.rst b/tests/core/nogo/generics/README.rst
new file mode 100644
index 00000000..c348a992
--- /dev/null
+++ b/tests/core/nogo/generics/README.rst
@@ -0,0 +1,18 @@
+nogo analyzers run against code using generics
+==============================================
+
+.. _nogo: /go/nogo.rst
+.. _buildssa: https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/buildssa
+.. _nilness: https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/nilness
+
+Tests to ensure that `nogo`_ analyzers that run on code using generics get correct
+type instantiation information.
+
+.. contents::
+
+generics_test
+-------------
+
+Verifies that code using generic types gets loaded including all type instantiation
+information, so that analyzers based on the `buildssa`_ analyzer (such as `nilness`_) get
+a complete picture of all types in the code.
diff --git a/tests/core/nogo/generics/generics_test.go b/tests/core/nogo/generics/generics_test.go
new file mode 100644
index 00000000..562d52ed
--- /dev/null
+++ b/tests/core/nogo/generics/generics_test.go
@@ -0,0 +1,85 @@
+// Copyright 2022 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.
+
+package generics_test
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Nogo: "@//:nogo",
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "nogo")
+
+nogo(
+ name = "nogo",
+ visibility = ["//visibility:public"],
+ deps = ["@org_golang_x_tools//go/analysis/passes/buildssa"],
+)
+
+go_library(
+ name = "src",
+ srcs = ["src.go"],
+ importpath = "src",
+)
+
+-- src.go --
+package src
+
+type Set[T comparable] struct {
+ m map[T]struct{}
+}
+
+func New[T comparable](s ...T) *Set[T] {
+ set := &Set[T]{}
+ set.Add(s...)
+ return set
+}
+
+func (set *Set[T]) Add(s ...T) {
+ if set.m == nil {
+ set.m = make(map[T]struct{})
+ }
+ for _, s := range s {
+ set.m[s] = struct{}{}
+ }
+}
+
+func S(x ...string) *Set[string] {
+ return New[string](x...)
+}
+`,
+ })
+}
+
+func Test(t *testing.T) {
+ cmd := bazel_testing.BazelCmd("build", "//:src")
+ var stderr bytes.Buffer
+ cmd.Stderr = &stderr
+
+ if err := cmd.Run(); err != nil {
+ t.Log("output:", stderr.String())
+ t.Fatal("unexpected error:", err)
+ }
+
+ if bytes.Contains(stderr.Bytes(), []byte("panic")) {
+ t.Errorf("found panic in Bazel output: \n%s", stderr.String())
+ }
+}
diff --git a/tests/core/nogo/nolint/BUILD.bazel b/tests/core/nogo/nolint/BUILD.bazel
new file mode 100644
index 00000000..c828045c
--- /dev/null
+++ b/tests/core/nogo/nolint/BUILD.bazel
@@ -0,0 +1,6 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "nolint_test",
+ srcs = ["nolint_test.go"],
+)
diff --git a/tests/core/nogo/nolint/README.rst b/tests/core/nogo/nolint/README.rst
new file mode 100644
index 00000000..83436898
--- /dev/null
+++ b/tests/core/nogo/nolint/README.rst
@@ -0,0 +1,14 @@
+Nolint check
+=========
+
+.. _go_library: /docs/go/core/rules.md#_go_library
+
+Tests to ensure that errors found by nogo and annotated with //nolint are
+ignored.
+
+.. contents::
+
+nolint_test
+--------
+Verified that errors emitted by ``nogo`` are ignored when `//nolint` appears as
+a comment.
diff --git a/tests/core/nogo/nolint/nolint_test.go b/tests/core/nogo/nolint/nolint_test.go
new file mode 100644
index 00000000..78ecbbcf
--- /dev/null
+++ b/tests/core/nogo/nolint/nolint_test.go
@@ -0,0 +1,227 @@
+// Copyright 2019 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.
+
+package nolint_test
+
+import (
+ "bytes"
+ "io/ioutil"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_tool_library", "nogo")
+
+nogo(
+ name = "nogo",
+ vet = True,
+ deps = ["@org_golang_x_tools//go/analysis/passes/nilness"],
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "inline",
+ srcs = ["inline.go"],
+ importpath = "test",
+)
+
+go_library(
+ name = "inline_filter",
+ srcs = ["inline_filter.go"],
+ importpath = "test",
+)
+
+go_library(
+ name = "block",
+ srcs = ["block.go"],
+ importpath = "test",
+)
+
+go_library(
+ name = "block_multiline",
+ srcs = ["block_multiline.go"],
+ importpath = "test",
+)
+
+go_library(
+ name = "inline_errors",
+ srcs = ["inline_errors.go"],
+ importpath = "test",
+)
+
+go_library(
+ name = "inline_column",
+ srcs = ["inline_column.go"],
+ importpath = "test",
+)
+
+go_library(
+ name = "large_block",
+ srcs = ["large_block.go"],
+ importpath = "test",
+)
+-- inline.go --
+package test
+
+import "fmt"
+
+func F() {
+ s := "hello"
+ fmt.Printf("%d", s) //nolint
+}
+
+-- inline_filter.go --
+package test
+
+func F() bool {
+ return true || true //nolint:bools
+}
+
+-- block.go --
+package test
+
+import "fmt"
+
+func F() {
+ //nolint
+ fmt.Printf("%d", "hello")
+}
+
+-- block_multiline.go --
+package test
+
+func F() bool {
+ var i *int
+ //nolint
+ return true &&
+ i != nil
+}
+
+-- inline_errors.go --
+package test
+
+import "fmt"
+
+func F() {
+ var i *int
+ if i == nil {
+ fmt.Printf("%d", "hello") //nolint
+ fmt.Println(*i) // Keep nil deref error
+ }
+}
+
+-- inline_column.go --
+package test
+
+import "fmt"
+
+func F() {
+ // Purposely used 'helo' to align the column
+ fmt.Printf("%d", "helo") //nolint
+ superLongVariableName := true || true
+ var _ = superLongVariableName
+}
+
+-- large_block.go --
+package test
+
+import "fmt"
+
+var V = struct {
+ S string
+ B bool
+} {
+ S: fmt.Sprintf("%d", "hello"), //nolint
+ B: true || true,
+}
+`,
+ })
+}
+
+func Test(t *testing.T) {
+ customRegister := `go_register_toolchains(nogo = "@//:nogo")`
+ if err := replaceInFile("WORKSPACE", "go_register_toolchains()", customRegister); err != nil {
+ t.Fatal(err)
+ }
+
+ tests := []struct {
+ Name string
+ Target string
+ Expected string
+ }{
+ {
+ Name: "Inline comment",
+ Target: "//:inline",
+ },
+ {
+ Name: "Inline with lint filter",
+ Target: "//:inline_filter",
+ },
+ {
+ Name: "Block comment",
+ Target: "//:block",
+ },
+ {
+ Name: "Multiline block comment",
+ Target: "//:block_multiline",
+ },
+ {
+ Name: "Inline with errors",
+ Target: "//:inline_errors",
+ Expected: "inline_errors.go:9:15: nil dereference in load (nilness)",
+ },
+ {
+ Name: "Inline comment on same column does not apply",
+ Target: "//:inline_column",
+ Expected: "inline_column.go:8:27: redundant or: true || true (bools)",
+ },
+ {
+ Name: "Inline comment does not apply to larger block",
+ Target: "//:large_block",
+ Expected: "large_block.go:10:5: redundant or: true || true (bools)",
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.Name, func(t *testing.T) {
+ cmd := bazel_testing.BazelCmd("build", tc.Target)
+ b, err := cmd.CombinedOutput()
+ output := string(b)
+ if tc.Expected != "" && err == nil {
+ t.Fatal("unexpected success", output)
+ }
+ if tc.Expected == "" && err != nil {
+ t.Fatal("unexpected failure", output)
+ }
+ if !strings.Contains(output, tc.Expected) {
+ t.Errorf("output did not contain expected: %s\n%s", tc.Expected, output)
+ }
+ })
+ }
+}
+
+func replaceInFile(path, old, new string) error {
+ data, err := ioutil.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ data = bytes.ReplaceAll(data, []byte(old), []byte(new))
+ return ioutil.WriteFile(path, data, 0666)
+}
diff --git a/tests/core/nogo/vet/BUILD.bazel b/tests/core/nogo/vet/BUILD.bazel
new file mode 100644
index 00000000..b01e0482
--- /dev/null
+++ b/tests/core/nogo/vet/BUILD.bazel
@@ -0,0 +1,6 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "vet_test",
+ srcs = ["vet_test.go"],
+)
diff --git a/tests/core/nogo/vet/README.rst b/tests/core/nogo/vet/README.rst
new file mode 100644
index 00000000..28f95c0e
--- /dev/null
+++ b/tests/core/nogo/vet/README.rst
@@ -0,0 +1,14 @@
+Vet check
+=========
+
+.. _go_library: /docs/go/core/rules.md#_go_library
+
+Tests to ensure that vet runs and detects errors.
+
+.. contents::
+
+vet_test
+--------
+Verifies that vet errors are emitted on a `go_library`_ with problems when built
+with a ``nogo`` binary with ``vet = True``. No errors should be emitted when
+analyzing error-free source code. Vet should not be enabled by default.
diff --git a/tests/core/nogo/vet/vet_test.go b/tests/core/nogo/vet/vet_test.go
new file mode 100644
index 00000000..4bc2163f
--- /dev/null
+++ b/tests/core/nogo/vet/vet_test.go
@@ -0,0 +1,179 @@
+// Copyright 2019 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.
+
+package vet_test
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "regexp"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_tool_library", "nogo")
+
+nogo(
+ name = "nogo",
+ vet = True,
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "has_errors",
+ srcs = ["has_errors.go"],
+ importpath = "haserrors",
+ deps = [":fmtwrap"],
+)
+
+go_library(
+ name = "no_errors",
+ srcs = ["no_errors.go"],
+ cgo = True,
+ importpath = "noerrors",
+)
+
+go_library(
+ name = "fmtwrap",
+ srcs = ["fmtwrap.go"],
+ importpath = "fmtwrap",
+)
+
+-- has_errors.go --
+package haserrors
+
+// +build build_tags_error
+
+import (
+ "fmtwrap"
+ "sync/atomic"
+)
+
+func F() {}
+
+func Foo() bool {
+ x := uint64(1)
+ _ = atomic.AddUint64(&x, 1)
+ if F == nil { // nilfunc error.
+ return false
+ }
+ fmtwrap.Printf("%b", "hi") // printf error.
+ return true || true // redundant boolean error.
+}
+
+-- no_errors.go --
+package noerrors
+
+// const int x = 1;
+import "C"
+
+func Foo() bool {
+ return bool(C.x == 1)
+}
+
+-- fmtwrap.go --
+package fmtwrap
+
+import "fmt"
+
+func Printf(format string, args ...interface{}) {
+ fmt.Printf(format, args...)
+}
+`,
+ })
+}
+
+func Test(t *testing.T) {
+ for _, test := range []struct {
+ desc, nogo, target string
+ wantSuccess bool
+ includes, excludes []string
+ }{
+ {
+ desc: "default",
+ target: "//:has_errors",
+ wantSuccess: true,
+ excludes: []string{
+ "\\+build comment must appear before package clause and be followed by a blank line",
+ "comparison of function F == nil is always false",
+ "Printf format %b has arg \"hi\" of wrong type string",
+ "redundant or: true \\|\\| true",
+ },
+ }, {
+ desc: "enabled_no_errors",
+ target: "//:no_errors",
+ wantSuccess: true,
+ }, {
+ desc: "enabled_has_errors",
+ nogo: "@//:nogo",
+ target: "//:has_errors",
+ includes: []string{
+ "misplaced \\+build comment",
+ "comparison of function F == nil is always false",
+ "Printf format %b has arg \"hi\" of wrong type string",
+ "redundant or: true \\|\\| true",
+ },
+ },
+ } {
+ t.Run(test.desc, func(t *testing.T) {
+ if test.nogo != "" {
+ origRegister := "go_register_toolchains()"
+ customRegister := fmt.Sprintf("go_register_toolchains(nogo = %q)", test.nogo)
+ if err := replaceInFile("WORKSPACE", origRegister, customRegister); err != nil {
+ t.Fatal(err)
+ }
+ defer replaceInFile("WORKSPACE", customRegister, origRegister)
+ }
+
+ cmd := bazel_testing.BazelCmd("build", test.target)
+ stderr := &bytes.Buffer{}
+ cmd.Stderr = stderr
+ if err := cmd.Run(); err == nil && !test.wantSuccess {
+ t.Fatal("unexpected success")
+ } else if err != nil && test.wantSuccess {
+ t.Fatalf("unexpected error: %v", err)
+ }
+
+ for _, pattern := range test.includes {
+ if matched, err := regexp.Match(pattern, stderr.Bytes()); err != nil {
+ t.Fatal(err)
+ } else if !matched {
+ t.Errorf("output did not contain pattern: %s", pattern)
+ }
+ }
+ for _, pattern := range test.excludes {
+ if matched, err := regexp.Match(pattern, stderr.Bytes()); err != nil {
+ t.Fatal(err)
+ } else if matched {
+ t.Errorf("output contained pattern: %s", pattern)
+ }
+ }
+ })
+ }
+}
+
+func replaceInFile(path, old, new string) error {
+ data, err := ioutil.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ data = bytes.ReplaceAll(data, []byte(old), []byte(new))
+ return ioutil.WriteFile(path, data, 0666)
+}
diff --git a/tests/core/output_groups/BUILD.bazel b/tests/core/output_groups/BUILD.bazel
new file mode 100644
index 00000000..ec8b86c9
--- /dev/null
+++ b/tests/core/output_groups/BUILD.bazel
@@ -0,0 +1,36 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
+
+go_library(
+ name = "lib",
+ srcs = ["lib.go"],
+ importpath = "lib",
+)
+
+go_test(
+ name = "lib_test",
+ srcs = ["lib_test.go"],
+ embed = [":lib"],
+)
+
+go_binary(
+ name = "bin",
+ srcs = ["bin.go"],
+)
+
+filegroup(
+ name = "compilation_outputs",
+ testonly = True,
+ srcs = [
+ ":bin",
+ ":lib",
+ ":lib_test",
+ ],
+ output_group = "compilation_outputs",
+)
+
+go_test(
+ name = "compilation_outputs_test",
+ srcs = ["compilation_outputs_test.go"],
+ data = [":compilation_outputs"],
+ deps = ["//go/tools/bazel:go_default_library"],
+)
diff --git a/tests/core/output_groups/README.rst b/tests/core/output_groups/README.rst
new file mode 100644
index 00000000..5d3d4e41
--- /dev/null
+++ b/tests/core/output_groups/README.rst
@@ -0,0 +1,10 @@
+output_groups functionality
+===========================
+
+Tests to ensure the supported `output_groups` are working as expected.
+
+compilation_outputs_test
+------------------------
+
+Checks that the `compilation_outputs` output group is populated with the
+compiled archives from `go_library`, `go_test`, and `go_binary` targets.
diff --git a/tests/core/output_groups/bin.go b/tests/core/output_groups/bin.go
new file mode 100644
index 00000000..38dd16da
--- /dev/null
+++ b/tests/core/output_groups/bin.go
@@ -0,0 +1,3 @@
+package main
+
+func main() {}
diff --git a/tests/core/output_groups/compilation_outputs_test.go b/tests/core/output_groups/compilation_outputs_test.go
new file mode 100644
index 00000000..25daced7
--- /dev/null
+++ b/tests/core/output_groups/compilation_outputs_test.go
@@ -0,0 +1,59 @@
+package output_groups
+
+import (
+ "os"
+ "path/filepath"
+ "runtime"
+ "sort"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel"
+)
+
+func TestCompilationOutputs(t *testing.T) {
+ runfiles, err := bazel.ListRunfiles()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ exe := ""
+ if runtime.GOOS == "windows" {
+ exe = ".exe"
+ }
+ expectedFiles := map[string]bool{
+ "compilation_outputs_test" + exe: true, // test binary; not relevant
+
+ "lib.a": false, // :lib archive
+ "lib_test.internal.a": false, // :lib_test archive
+ "bin.a": false, // :bin archive
+ }
+ for _, rf := range runfiles {
+ info, err := os.Stat(rf.Path)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if info.IsDir() {
+ continue
+ }
+
+ base := filepath.Base(rf.Path)
+ if seen, ok := expectedFiles[base]; !ok {
+ t.Errorf("unexpected runfile: %s %s", rf.Path, base)
+ } else if !seen {
+ expectedFiles[base] = true
+ }
+ }
+
+ missingFiles := make([]string, 0, len(expectedFiles))
+ for path, seen := range expectedFiles {
+ if !seen {
+ missingFiles = append(missingFiles, path)
+ }
+ }
+ sort.Strings(missingFiles)
+ if len(missingFiles) > 0 {
+ t.Errorf("did not find expected files: %s", strings.Join(missingFiles, " "))
+ }
+}
diff --git a/tests/core/output_groups/lib.go b/tests/core/output_groups/lib.go
new file mode 100644
index 00000000..55c21f80
--- /dev/null
+++ b/tests/core/output_groups/lib.go
@@ -0,0 +1 @@
+package lib
diff --git a/tests/core/output_groups/lib_test.go b/tests/core/output_groups/lib_test.go
new file mode 100644
index 00000000..55c21f80
--- /dev/null
+++ b/tests/core/output_groups/lib_test.go
@@ -0,0 +1 @@
+package lib
diff --git a/tests/core/race/BUILD.bazel b/tests/core/race/BUILD.bazel
new file mode 100644
index 00000000..842dff95
--- /dev/null
+++ b/tests/core/race/BUILD.bazel
@@ -0,0 +1,6 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "race_test",
+ srcs = ["race_test.go"],
+)
diff --git a/tests/core/race/README.rst b/tests/core/race/README.rst
new file mode 100644
index 00000000..a5152211
--- /dev/null
+++ b/tests/core/race/README.rst
@@ -0,0 +1,10 @@
+race instrumentation
+====================
+
+race_test
+---------
+
+Embeds a library that triggers a data race inside a binary and a test.
+Verifies that no race is reported by default and a race is reported when either
+target is build with the ``race = "on"`` attribute or the ``--features=race``
+flag.
diff --git a/tests/core/race/race_test.go b/tests/core/race/race_test.go
new file mode 100644
index 00000000..815b2b18
--- /dev/null
+++ b/tests/core/race/race_test.go
@@ -0,0 +1,302 @@
+// Copyright 2019 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.
+
+package race_test
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "os/exec"
+ "runtime"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
+
+go_library(
+ name = "racy",
+ srcs = [
+ "race_off.go",
+ "race_on.go",
+ "racy.go",
+ "empty.s", # verify #2143
+ ],
+ importpath = "example.com/racy",
+)
+
+go_binary(
+ name = "racy_cmd",
+ srcs = ["main.go"],
+ embed = [":racy"],
+)
+
+go_binary(
+ name = "racy_cmd_race_mode",
+ srcs = ["main.go"],
+ embed = [":racy"],
+ race = "on",
+)
+
+go_test(
+ name = "racy_test",
+ srcs = ["racy_test.go"],
+ embed = [":racy"],
+)
+
+go_test(
+ name = "racy_test_race_mode",
+ srcs = ["racy_test.go"],
+ embed = [":racy"],
+ race = "on",
+)
+
+go_binary(
+ name = "pure_bin",
+ srcs = ["pure_bin.go"],
+ pure = "on",
+)
+
+go_binary(
+ name = "pure_race_bin",
+ srcs = ["pure_bin.go"],
+ pure = "on",
+ race = "on",
+)
+
+go_library(
+ name = "coverrace",
+ srcs = ["coverrace.go"],
+ importpath = "example.com/coverrace",
+)
+
+go_test(
+ name = "coverrace_test",
+ srcs = ["coverrace_test.go"],
+ embed = [":coverrace"],
+ race = "on",
+)
+-- race_off.go --
+// +build !race
+
+package main
+
+const RaceEnabled = false
+
+-- race_on.go --
+// +build race
+
+package main
+
+const RaceEnabled = true
+
+-- racy.go --
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+)
+
+var wantRace = flag.Bool("wantrace", false, "")
+
+func Race() {
+ if *wantRace != RaceEnabled {
+ fmt.Fprintf(os.Stderr, "!!! -wantrace is %v, but RaceEnabled is %v\n", *wantRace, RaceEnabled)
+ os.Exit(1)
+ }
+
+ done := make(chan bool)
+ m := make(map[string]string)
+ m["name"] = "world"
+ go func() {
+ m["name"] = "data race"
+ done <- true
+ }()
+ fmt.Println("Hello,", m["name"])
+ <-done
+}
+
+-- main.go --
+package main
+
+import "flag"
+
+func main() {
+ flag.Parse()
+ Race()
+}
+
+-- racy_test.go --
+package main
+
+import "testing"
+
+func TestRace(t *testing.T) {
+ Race()
+}
+
+-- empty.s --
+-- pure_bin.go --
+// +build !race
+
+// pure_bin will not build in race mode, since its sources will be excluded.
+package main
+
+func main() {}
+
+-- coverrace.go --
+package coverrace
+// copied from https://hermanschaaf.com/running-the-go-race-detector-with-cover/
+func add100() int {
+ total := 0
+ c := make(chan int, 1)
+ for i := 0; i < 100; i++ {
+ go func(chan int) {
+ c <- 1
+ }(c)
+ }
+ for u := 0; u < 100; u++ {
+ total += <-c
+ }
+ return total
+}
+
+-- coverrace_test.go --
+package coverrace
+// copied from https://hermanschaaf.com/running-the-go-race-detector-with-cover/
+
+import "testing"
+
+func TestCoverRace(t *testing.T) {
+ got := add100()
+ if got != 100 {
+ t.Errorf("got %d, want %d", got, 100)
+ }
+}
+`,
+ })
+}
+
+func Test(t *testing.T) {
+ for _, test := range []struct {
+ desc, cmd, target string
+ featureFlag, wantRace, wantBuildFail bool
+ }{
+ {
+ desc: "cmd_auto",
+ cmd: "run",
+ target: "//:racy_cmd",
+ }, {
+ desc: "cmd_attr",
+ cmd: "run",
+ target: "//:racy_cmd_race_mode",
+ wantRace: true,
+ }, {
+ desc: "cmd_feature",
+ cmd: "run",
+ target: "//:racy_cmd",
+ featureFlag: true,
+ wantRace: true,
+ }, {
+ desc: "test_auto",
+ cmd: "test",
+ target: "//:racy_test",
+ }, {
+ desc: "test_attr",
+ cmd: "test",
+ target: "//:racy_test_race_mode",
+ wantRace: true,
+ }, {
+ desc: "test_feature",
+ cmd: "test",
+ target: "//:racy_test",
+ featureFlag: true,
+ wantRace: true,
+ }, {
+ desc: "pure_bin",
+ cmd: "build",
+ target: "//:pure_bin",
+ featureFlag: true,
+ }, {
+ desc: "pure_race_bin",
+ cmd: "build",
+ target: "//:pure_race_bin",
+ wantBuildFail: true,
+ }, {
+ desc: "cover_race",
+ cmd: "coverage",
+ target: "//:coverrace_test",
+ featureFlag: true,
+ },
+ } {
+ t.Run(test.desc, func(t *testing.T) {
+ // TODO(#2518): fix coverage tests on Windows
+ if test.cmd == "coverage" && runtime.GOOS == "windows" {
+ t.Skip("TODO(#2518): fix and enable coverage tests on Windows")
+ }
+ args := []string{test.cmd}
+ if test.featureFlag {
+ args = append(args, "--@io_bazel_rules_go//go/config:race")
+ }
+ args = append(args, test.target)
+ if test.cmd == "test" {
+ args = append(args, fmt.Sprintf("--test_arg=-wantrace=%v", test.wantRace))
+ } else if test.cmd == "run" {
+ args = append(args, "--", fmt.Sprintf("-wantrace=%v", test.wantRace))
+ }
+ cmd := bazel_testing.BazelCmd(args...)
+ stderr := &bytes.Buffer{}
+ cmd.Stderr = stderr
+ t.Logf("running: bazel %s", strings.Join(args, " "))
+ if err := cmd.Run(); err != nil {
+ var xerr *exec.ExitError
+ if !errors.As(err, &xerr) {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if xerr.ExitCode() == bazel_testing.BUILD_FAILURE {
+ if !test.wantBuildFail {
+ t.Fatalf("unexpected build failure: %v\nstderr:\n%s", err, stderr.Bytes())
+ }
+ return
+ } else if xerr.ExitCode() == bazel_testing.TESTS_FAILED {
+ if bytes.Contains(stderr.Bytes(), []byte("!!!")) {
+ t.Fatalf("error running %s:\n%s", strings.Join(cmd.Args, " "), stderr.Bytes())
+ } else if !test.wantRace {
+ t.Fatalf("error running %s without race enabled\n%s", strings.Join(cmd.Args, " "), stderr.Bytes())
+ }
+ } else if test.wantRace {
+ if !bytes.Contains(stderr.Bytes(), []byte("WARNING: DATA RACE")) {
+ t.Fatalf("wanted data race; command failed with: %v\nstderr:\n%s", err, stderr.Bytes())
+ }
+ return
+ } else {
+ t.Fatalf("unexpected error: %v\nstderr:\n%s", err, stderr.Bytes())
+ }
+ } else if test.wantRace {
+ t.Fatalf("command %s with race enabled did not fail", strings.Join(cmd.Args, " "))
+ } else if test.wantBuildFail {
+ t.Fatalf("target %s did not fail to build", test.target)
+ }
+ })
+ }
+}
diff --git a/tests/core/runfiles/BUILD.bazel b/tests/core/runfiles/BUILD.bazel
new file mode 100644
index 00000000..c7db6d3d
--- /dev/null
+++ b/tests/core/runfiles/BUILD.bazel
@@ -0,0 +1,48 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
+
+package(default_visibility = ["//visibility:public"])
+
+test_suite(
+ name = "runfiles_tests",
+ tests = [
+ ":local_test",
+ "@runfiles_remote_test//:remote_test",
+ ],
+)
+
+go_test(
+ name = "local_test",
+ srcs = ["runfiles_test.go"],
+ deps = [":check_runfiles"],
+)
+
+go_binary(
+ name = "local_cmd",
+ srcs = ["runfiles_cmd.go"],
+ deps = [":check_runfiles"],
+)
+
+go_binary(
+ name = "local_bin",
+ srcs = ["empty_bin.go"],
+)
+
+go_library(
+ name = "check_runfiles",
+ srcs = ["check_runfiles.go"],
+ data = [
+ "local_file.txt",
+ ":local_bin",
+ ":local_group",
+ "@runfiles_remote_test//:remote_bin",
+ "@runfiles_remote_test//:remote_file.txt",
+ "@runfiles_remote_test//:remote_group",
+ ],
+ importpath = "github.com/bazelbuild/rules_go/tests/core/runfiles/check",
+ deps = ["//go/tools/bazel:go_default_library"],
+)
+
+filegroup(
+ name = "local_group",
+ srcs = ["local_group.txt"],
+)
diff --git a/tests/core/runfiles/README.rst b/tests/core/runfiles/README.rst
new file mode 100644
index 00000000..ec357826
--- /dev/null
+++ b/tests/core/runfiles/README.rst
@@ -0,0 +1,23 @@
+Runfiles functionality
+=====================
+
+runfiles_tests
+--------------
+
+Checks that functions in ``//go/tools/bazel:go_default_library`` that
+provide access to runfiles behave correctly. In particular, this checks:
+
+* ``Runfile`` works for regular files.
+* ``FindBinary`` works for binaries.
+* ``ListRunfiles`` lists all expected files.
+* These functions work for runfiles in the local workspace and for files in
+ external repositories (``@runfiles_remote_test`` is a ``local_repository``
+ that points to a subdirectory here).
+* These functions work in tests invoked with ``bazel test`` and
+ binaries invoked with ``bazel run``.
+* These functions work on Windows and other platforms. Bazel doesn't
+ create a symlink tree for runfiles on Windows since symbolic links
+ can't be created without administrative privilege by default.
+
+TODO: Verify binary behavior in CI. The ``local_bin`` and ``remote_bin``
+targets verify behavior for binaries, but they are not tests.
diff --git a/tests/core/runfiles/bin.go b/tests/core/runfiles/bin.go
new file mode 100644
index 00000000..0ced7a9e
--- /dev/null
+++ b/tests/core/runfiles/bin.go
@@ -0,0 +1,17 @@
+// Copyright 2019 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.
+
+package main
+
+func main() {}
diff --git a/tests/core/runfiles/check_runfiles.go b/tests/core/runfiles/check_runfiles.go
new file mode 100644
index 00000000..8858a573
--- /dev/null
+++ b/tests/core/runfiles/check_runfiles.go
@@ -0,0 +1,121 @@
+// Copyright 2019 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.
+
+package check
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "runtime"
+ "sort"
+ "strings"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel"
+)
+
+type TestFile struct {
+ Workspace, ShortPath, Path string
+ Binary bool
+}
+
+var DefaultTestFiles = []TestFile{
+ {Workspace: "io_bazel_rules_go", Path: "tests/core/runfiles/local_file.txt"},
+ {Workspace: "io_bazel_rules_go", Path: "tests/core/runfiles/local_group.txt"},
+ {Workspace: "io_bazel_rules_go", Path: "tests/core/runfiles/local_bin", Binary: true},
+ {Workspace: "runfiles_remote_test", Path: "remote_file.txt"},
+ {Workspace: "runfiles_remote_test", Path: "remote_group.txt"},
+ {Workspace: "runfiles_remote_test", Path: "remote_bin", Binary: true},
+}
+
+func CheckRunfiles(files []TestFile) error {
+ // Check that the runfiles directory matches the current workspace.
+ // There is no runfiles directory on Windows.
+ if runtime.GOOS != "windows" {
+ dir, err := bazel.RunfilesPath()
+ if err != nil {
+ return err
+ }
+ root, base := filepath.Dir(dir), filepath.Base(dir)
+ if !strings.HasSuffix(root, ".runfiles") {
+ return fmt.Errorf("RunfilesPath: %q is not a .runfiles directory", dir)
+ }
+ workspace := os.Getenv("TEST_WORKSPACE")
+ if workspace != "" && workspace != base {
+ return fmt.Errorf("RunfilesPath: %q does not match test workspace %s", dir, workspace)
+ }
+ if srcDir := os.Getenv("TEST_SRCDIR"); srcDir != "" && filepath.Join(srcDir, workspace) != dir {
+ return fmt.Errorf("RunfilesPath: %q does not match TEST_SRCDIR %q", dir, srcDir)
+ }
+ }
+
+ // Check that files can be found with Runfile or FindBinary.
+ // Make sure the paths returned are absolute paths to actual files.
+ seen := make(map[string]string)
+ for _, f := range files {
+ var got string
+ var err error
+ if !f.Binary {
+ if got, err = bazel.Runfile(f.Path); err != nil {
+ return err
+ }
+ if !filepath.IsAbs(got) {
+ return fmt.Errorf("Runfile %s: got a relative path %q; want absolute", f.Path, got)
+ }
+ seen[f.Path] = got
+ } else {
+ var pkg, name string
+ if i := strings.LastIndex(f.Path, "/"); i < 0 {
+ name = f.Path
+ } else {
+ pkg = f.Path[:i]
+ name = f.Path[i+1:]
+ }
+ var ok bool
+ if got, ok = bazel.FindBinary(pkg, name); !ok {
+ return fmt.Errorf("FindBinary %s %s: could not find binary", pkg, name)
+ }
+ if !filepath.IsAbs(got) {
+ return fmt.Errorf("FindBinary %s %s: got a relative path %q; want absolute", pkg, name, got)
+ }
+ }
+
+ if _, err := os.Stat(got); err != nil {
+ return fmt.Errorf("%s: could not stat: %v", f.Path, err)
+ }
+ }
+
+ // Check that the files can be listed.
+ entries, err := bazel.ListRunfiles()
+ if err != nil {
+ return err
+ }
+ for _, e := range entries {
+ if want, ok := seen[e.ShortPath]; ok && want != e.Path {
+ return err
+ }
+ delete(seen, e.ShortPath)
+ }
+
+ if len(seen) > 0 {
+ unseen := make([]string, 0, len(seen))
+ for short := range seen {
+ unseen = append(unseen, short)
+ }
+ sort.Strings(unseen)
+ return fmt.Errorf("ListRunfiles did not include files:\n\t%s", strings.Join(unseen, "\n\t"))
+ }
+
+ return nil
+}
diff --git a/tests/core/runfiles/empty_bin.go b/tests/core/runfiles/empty_bin.go
new file mode 100644
index 00000000..38dd16da
--- /dev/null
+++ b/tests/core/runfiles/empty_bin.go
@@ -0,0 +1,3 @@
+package main
+
+func main() {}
diff --git a/tests/core/runfiles/local_file.txt b/tests/core/runfiles/local_file.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/runfiles/local_file.txt
diff --git a/tests/core/runfiles/local_group.txt b/tests/core/runfiles/local_group.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/runfiles/local_group.txt
diff --git a/tests/core/runfiles/runfiles_cmd.go b/tests/core/runfiles/runfiles_cmd.go
new file mode 100644
index 00000000..0ab124b5
--- /dev/null
+++ b/tests/core/runfiles/runfiles_cmd.go
@@ -0,0 +1,28 @@
+// Copyright 2019 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.
+
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/bazelbuild/rules_go/tests/core/runfiles/check"
+)
+
+func main() {
+ if err := check.CheckRunfiles(check.DefaultTestFiles); err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ }
+}
diff --git a/tests/core/runfiles/runfiles_remote_test/BUILD.bazel b/tests/core/runfiles/runfiles_remote_test/BUILD.bazel
new file mode 100644
index 00000000..112dcd35
--- /dev/null
+++ b/tests/core/runfiles/runfiles_remote_test/BUILD.bazel
@@ -0,0 +1,27 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_test")
+
+package(default_visibility = ["//visibility:public"])
+
+go_test(
+ name = "remote_test",
+ srcs = ["@io_bazel_rules_go//tests/core/runfiles:runfiles_test.go"],
+ deps = ["@io_bazel_rules_go//tests/core/runfiles:check_runfiles"],
+)
+
+go_binary(
+ name = "remote_cmd",
+ srcs = ["@io_bazel_rules_go//tests/core/runfiles:runfiles_cmd.go"],
+ deps = ["@io_bazel_rules_go//tests/core/runfiles:check_runfiles"],
+)
+
+go_binary(
+ name = "remote_bin",
+ srcs = ["@io_bazel_rules_go//tests/core/runfiles:empty_bin.go"],
+)
+
+filegroup(
+ name = "remote_group",
+ srcs = ["remote_group.txt"],
+)
+
+exports_files(["remote_file.txt"])
diff --git a/tests/core/runfiles/runfiles_remote_test/WORKSPACE b/tests/core/runfiles/runfiles_remote_test/WORKSPACE
new file mode 100644
index 00000000..c9af3f85
--- /dev/null
+++ b/tests/core/runfiles/runfiles_remote_test/WORKSPACE
@@ -0,0 +1 @@
+workspace(name = "runfiles_remote_test")
diff --git a/tests/core/runfiles/runfiles_remote_test/remote_file.txt b/tests/core/runfiles/runfiles_remote_test/remote_file.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/runfiles/runfiles_remote_test/remote_file.txt
diff --git a/tests/core/runfiles/runfiles_remote_test/remote_group.txt b/tests/core/runfiles/runfiles_remote_test/remote_group.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/runfiles/runfiles_remote_test/remote_group.txt
diff --git a/tests/core/runfiles/runfiles_test.go b/tests/core/runfiles/runfiles_test.go
new file mode 100644
index 00000000..62aab3af
--- /dev/null
+++ b/tests/core/runfiles/runfiles_test.go
@@ -0,0 +1,27 @@
+// Copyright 2019 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.
+
+package main
+
+import (
+ "testing"
+
+ "github.com/bazelbuild/rules_go/tests/core/runfiles/check"
+)
+
+func Test(t *testing.T) {
+ if err := check.CheckRunfiles(check.DefaultTestFiles); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/tests/core/starlark/BUILD.bazel b/tests/core/starlark/BUILD.bazel
new file mode 100644
index 00000000..c26a6bea
--- /dev/null
+++ b/tests/core/starlark/BUILD.bazel
@@ -0,0 +1,6 @@
+load(":common_tests.bzl", "common_test_suite")
+load(":sdk_tests.bzl", "sdk_test_suite")
+
+common_test_suite()
+
+sdk_test_suite()
diff --git a/tests/core/starlark/README.rst b/tests/core/starlark/README.rst
new file mode 100644
index 00000000..e1f8df76
--- /dev/null
+++ b/tests/core/starlark/README.rst
@@ -0,0 +1,9 @@
+Starlark unit tests
+=======================
+
+common_test_suite
+---------
+
+Checks that ``has_shared_lib_extension`` from ``//go/private:common.bzl``
+correctly matches shared library filenames, which may optionally have a version
+number at the end.
diff --git a/tests/core/starlark/common_tests.bzl b/tests/core/starlark/common_tests.bzl
new file mode 100644
index 00000000..e83d65f3
--- /dev/null
+++ b/tests/core/starlark/common_tests.bzl
@@ -0,0 +1,53 @@
+load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest")
+load("//go/private:common.bzl", "count_group_matches", "has_shared_lib_extension")
+
+def _versioned_shared_libraries_test(ctx):
+ env = unittest.begin(ctx)
+
+ # See //src/test/java/com/google/devtools/build/lib/rules/cpp:CppFileTypesTest.java
+ # for the corresponding native C++ rules tests.
+ asserts.true(env, has_shared_lib_extension("somelibrary.so"))
+ asserts.true(env, has_shared_lib_extension("somelibrary.so.2"))
+ asserts.true(env, has_shared_lib_extension("somelibrary.so.20"))
+ asserts.true(env, has_shared_lib_extension("somelibrary.so.20.2"))
+ asserts.true(env, has_shared_lib_extension("a/somelibrary.so.2"))
+ asserts.true(env, has_shared_lib_extension("somelibrary✅.so.2"))
+ asserts.true(env, has_shared_lib_extension("somelibrary✅.so.2.1"))
+ asserts.false(env, has_shared_lib_extension("somelibrary.so.e"))
+ asserts.false(env, has_shared_lib_extension("xx.1"))
+ asserts.false(env, has_shared_lib_extension("somelibrary.so.2e"))
+ asserts.false(env, has_shared_lib_extension("somelibrary.so.e2"))
+ asserts.false(env, has_shared_lib_extension("somelibrary.so.20.e2"))
+ asserts.false(env, has_shared_lib_extension("somelibrary.a.2"))
+ asserts.false(env, has_shared_lib_extension("somelibrary.a..2"))
+ asserts.false(env, has_shared_lib_extension("somelibrary.so.2."))
+ asserts.false(env, has_shared_lib_extension("somelibrary.so."))
+ asserts.false(env, has_shared_lib_extension("somelibrary.so.2🚫"))
+ asserts.false(env, has_shared_lib_extension("somelibrary.so.🚫2"))
+ asserts.false(env, has_shared_lib_extension("somelibrary.so🚫.2.0"))
+
+ return unittest.end(env)
+
+versioned_shared_libraries_test = unittest.make(_versioned_shared_libraries_test)
+
+def _count_group_matches_test(ctx):
+ env = unittest.begin(ctx)
+
+ asserts.equals(env, 1, count_group_matches("{foo_status}", "{foo_", "}"))
+ asserts.equals(env, 1, count_group_matches("{foo_status} {status}", "{foo_", "}"))
+ asserts.equals(env, 0, count_group_matches("{foo_status}", "{bar_", "}"))
+ asserts.equals(env, 1, count_group_matches("{foo_status}", "{", "}"))
+ asserts.equals(env, 2, count_group_matches("{foo} {bar}", "{", "}"))
+ asserts.equals(env, 2, count_group_matches("{foo{bar} {baz}", "{", "}"))
+
+ return unittest.end(env)
+
+count_group_matches_test = unittest.make(_count_group_matches_test)
+
+def common_test_suite():
+ """Creates the test targets and test suite for common.bzl tests."""
+ unittest.suite(
+ "common_tests",
+ versioned_shared_libraries_test,
+ count_group_matches_test,
+ )
diff --git a/tests/core/starlark/packagedriver/BUILD.bazel b/tests/core/starlark/packagedriver/BUILD.bazel
new file mode 100644
index 00000000..45dd6aba
--- /dev/null
+++ b/tests/core/starlark/packagedriver/BUILD.bazel
@@ -0,0 +1,5 @@
+load(":go_pkg_info_aspect_test.bzl", "package_driver_suite")
+
+package_driver_suite(
+ name = "package_driver_test",
+)
diff --git a/tests/core/starlark/packagedriver/fixtures/a/BUILD.bazel b/tests/core/starlark/packagedriver/fixtures/a/BUILD.bazel
new file mode 100644
index 00000000..0dad32d9
--- /dev/null
+++ b/tests/core/starlark/packagedriver/fixtures/a/BUILD.bazel
@@ -0,0 +1,8 @@
+load("//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["a.go"],
+ importpath = "example.com/a",
+ visibility = ["//tests/core/starlark/packagedriver:__subpackages__"],
+)
diff --git a/tests/core/starlark/packagedriver/fixtures/a/a.go b/tests/core/starlark/packagedriver/fixtures/a/a.go
new file mode 100644
index 00000000..af058f6d
--- /dev/null
+++ b/tests/core/starlark/packagedriver/fixtures/a/a.go
@@ -0,0 +1,5 @@
+package a
+
+func A() {
+ return
+}
diff --git a/tests/core/starlark/packagedriver/fixtures/b/BUILD.bazel b/tests/core/starlark/packagedriver/fixtures/b/BUILD.bazel
new file mode 100644
index 00000000..cdf5fd41
--- /dev/null
+++ b/tests/core/starlark/packagedriver/fixtures/b/BUILD.bazel
@@ -0,0 +1,8 @@
+load("//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["b.go"],
+ importpath = "example.com/b",
+ visibility = ["//tests/core/starlark/packagedriver:__subpackages__"],
+)
diff --git a/tests/core/starlark/packagedriver/fixtures/b/b.go b/tests/core/starlark/packagedriver/fixtures/b/b.go
new file mode 100644
index 00000000..869da65a
--- /dev/null
+++ b/tests/core/starlark/packagedriver/fixtures/b/b.go
@@ -0,0 +1,5 @@
+package b
+
+func B() {
+ return
+}
diff --git a/tests/core/starlark/packagedriver/fixtures/c/BUILD.bazel b/tests/core/starlark/packagedriver/fixtures/c/BUILD.bazel
new file mode 100644
index 00000000..28e8ef92
--- /dev/null
+++ b/tests/core/starlark/packagedriver/fixtures/c/BUILD.bazel
@@ -0,0 +1,20 @@
+load("//go:def.bzl", "go_library", "go_test")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["c.go"],
+ importpath = "example.com/c",
+ visibility = ["//tests/core/starlark/packagedriver:__subpackages__"],
+ deps = [
+ "//tests/core/starlark/packagedriver/fixtures/a:go_default_library",
+ "//tests/core/starlark/packagedriver/fixtures/b:go_default_library",
+ ],
+)
+
+go_test(
+ name = "go_default_test",
+ srcs = ["c_test.go"],
+ embed = [":go_default_library"],
+ tags = ["manual"],
+ visibility = ["//tests/core/starlark/packagedriver:__subpackages__"],
+)
diff --git a/tests/core/starlark/packagedriver/fixtures/c/c.go b/tests/core/starlark/packagedriver/fixtures/c/c.go
new file mode 100644
index 00000000..f8a8dd3b
--- /dev/null
+++ b/tests/core/starlark/packagedriver/fixtures/c/c.go
@@ -0,0 +1,11 @@
+package c
+
+import (
+ "example.com/a"
+ "example.com/b"
+)
+
+func C() {
+ a.A()
+ b.B()
+}
diff --git a/tests/core/starlark/packagedriver/fixtures/c/c_test.go b/tests/core/starlark/packagedriver/fixtures/c/c_test.go
new file mode 100644
index 00000000..4b25df88
--- /dev/null
+++ b/tests/core/starlark/packagedriver/fixtures/c/c_test.go
@@ -0,0 +1,9 @@
+package c
+
+import (
+ "testing"
+)
+
+func TestC(t *testing.T) {
+ C()
+}
diff --git a/tests/core/starlark/packagedriver/go_pkg_info_aspect_test.bzl b/tests/core/starlark/packagedriver/go_pkg_info_aspect_test.bzl
new file mode 100644
index 00000000..80b8d8b6
--- /dev/null
+++ b/tests/core/starlark/packagedriver/go_pkg_info_aspect_test.bzl
@@ -0,0 +1,32 @@
+load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
+load("//go/tools/gopackagesdriver:aspect.bzl", "go_pkg_info_aspect")
+
+def _package_driver_pkg_json_test_impl(ctx):
+ env = analysistest.begin(ctx)
+
+ target_under_test = analysistest.target_under_test(env)
+ json_files = [f.basename for f in target_under_test[OutputGroupInfo].go_pkg_driver_json_file.to_list()]
+ asserts.true(env, "go_default_test.pkg.json" in json_files, "{} does not contain go_default_test.pkg.json".format(json_files))
+
+ return analysistest.end(env)
+
+package_driver_pkg_json_test = analysistest.make(
+ _package_driver_pkg_json_test_impl,
+ extra_target_under_test_aspects = [go_pkg_info_aspect],
+)
+
+def _test_package_driver():
+ package_driver_pkg_json_test(
+ name = "package_driver_should_return_pkg_json_for_go_test",
+ target_under_test = "//tests/core/starlark/packagedriver/fixtures/c:go_default_test",
+ )
+
+def package_driver_suite(name):
+ _test_package_driver()
+
+ native.test_suite(
+ name = name,
+ tests = [
+ ":package_driver_should_return_pkg_json_for_go_test",
+ ],
+ )
diff --git a/tests/core/starlark/sdk_tests.bzl b/tests/core/starlark/sdk_tests.bzl
new file mode 100644
index 00000000..5339aec6
--- /dev/null
+++ b/tests/core/starlark/sdk_tests.bzl
@@ -0,0 +1,86 @@
+load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest")
+load("//go/private:sdk.bzl", "go_toolchains_single_definition")
+
+def _go_toolchains_single_definition_with_version_test(ctx):
+ env = unittest.begin(ctx)
+
+ result = go_toolchains_single_definition(
+ ctx = None,
+ prefix = "123_prefix_",
+ goos = "linux",
+ goarch = "amd64",
+ sdk_repo = "sdk_repo",
+ sdk_type = "download",
+ sdk_version = "1.20.2rc1",
+ )
+ asserts.equals(env, [], result.loads)
+ asserts.equals(env, [
+ """
+_123_PREFIX_MAJOR_VERSION = "1"
+_123_PREFIX_MINOR_VERSION = "20"
+_123_PREFIX_PATCH_VERSION = "2"
+_123_PREFIX_PRERELEASE_SUFFIX = "rc1"
+""",
+ """declare_bazel_toolchains(
+ prefix = "123_prefix_",
+ go_toolchain_repo = "@sdk_repo",
+ host_goarch = "amd64",
+ host_goos = "linux",
+ major = _123_PREFIX_MAJOR_VERSION,
+ minor = _123_PREFIX_MINOR_VERSION,
+ patch = _123_PREFIX_PATCH_VERSION,
+ prerelease = _123_PREFIX_PRERELEASE_SUFFIX,
+ sdk_type = "download",
+)
+""",
+ ], result.chunks)
+
+ return unittest.end(env)
+
+go_toolchains_single_definition_with_version_test = unittest.make(_go_toolchains_single_definition_with_version_test)
+
+def _go_toolchains_single_definition_without_version_test(ctx):
+ env = unittest.begin(ctx)
+
+ result = go_toolchains_single_definition(
+ ctx = None,
+ prefix = "123_prefix_",
+ goos = "linux",
+ goarch = "amd64",
+ sdk_repo = "sdk_repo",
+ sdk_type = "download",
+ sdk_version = None,
+ )
+ asserts.equals(env, ["""load(
+ "@sdk_repo//:version.bzl",
+ _123_PREFIX_MAJOR_VERSION = "MAJOR_VERSION",
+ _123_PREFIX_MINOR_VERSION = "MINOR_VERSION",
+ _123_PREFIX_PATCH_VERSION = "PATCH_VERSION",
+ _123_PREFIX_PRERELEASE_SUFFIX = "PRERELEASE_SUFFIX",
+)
+"""], result.loads)
+ asserts.equals(env, [
+ """declare_bazel_toolchains(
+ prefix = "123_prefix_",
+ go_toolchain_repo = "@sdk_repo",
+ host_goarch = "amd64",
+ host_goos = "linux",
+ major = _123_PREFIX_MAJOR_VERSION,
+ minor = _123_PREFIX_MINOR_VERSION,
+ patch = _123_PREFIX_PATCH_VERSION,
+ prerelease = _123_PREFIX_PRERELEASE_SUFFIX,
+ sdk_type = "download",
+)
+""",
+ ], result.chunks)
+
+ return unittest.end(env)
+
+go_toolchains_single_definition_without_version_test = unittest.make(_go_toolchains_single_definition_without_version_test)
+
+def sdk_test_suite():
+ unittest.suite(
+ "sdk_tests",
+ go_toolchains_single_definition_with_version_test,
+ go_toolchains_single_definition_without_version_test,
+ )
diff --git a/tests/core/stdlib/BUILD.bazel b/tests/core/stdlib/BUILD.bazel
new file mode 100644
index 00000000..eed94654
--- /dev/null
+++ b/tests/core/stdlib/BUILD.bazel
@@ -0,0 +1,11 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_test")
+load(":stdlib_files.bzl", "stdlib_files")
+
+go_test(
+ name = "buildid_test",
+ srcs = ["buildid_test.go"],
+ data = [":stdlib_files"],
+ deps = ["//go/runfiles"],
+)
+
+stdlib_files(name = "stdlib_files")
diff --git a/tests/core/stdlib/README.rst b/tests/core/stdlib/README.rst
new file mode 100644
index 00000000..4a942953
--- /dev/null
+++ b/tests/core/stdlib/README.rst
@@ -0,0 +1,13 @@
+stdlib functionality
+====================
+
+buildid_test
+------------
+
+Checks that the ``stdlib`` rule builds archives without Go build ids.
+
+Go build ids are used for caching within ``go build``; they are not needed by
+Bazel, which has its own caching mechanism. The build id is influenced by
+all inputs to the build, including cgo environment variables. Since these
+variables may include sandbox paths, they can make the build id
+non-reproducible, even though they don't affect the final binary.
diff --git a/tests/core/stdlib/buildid_test.go b/tests/core/stdlib/buildid_test.go
new file mode 100644
index 00000000..d95ba903
--- /dev/null
+++ b/tests/core/stdlib/buildid_test.go
@@ -0,0 +1,93 @@
+//go:build go1.10
+// +build go1.10
+
+/* Copyright 2018 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.
+*/
+
+package buildid_test
+
+import (
+ "bytes"
+ "errors"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/runfiles"
+)
+
+func TestEmptyBuildID(t *testing.T) {
+ // Locate the buildid tool and several archive files to check.
+ // fmt.a - pure go
+ // crypto/aes.a - contains assembly
+ // runtime/cgo.a - contains cgo
+ // The path may vary depending on platform and architecture, so just
+ // do a search.
+ var buildidPath string
+ pkgPaths := map[string]string{
+ "fmt.a": "",
+ "aes.a": "",
+ "cgo.a": "",
+ }
+ stdlibPkgDir, err := runfiles.Rlocation("io_bazel_rules_go/stdlib_/pkg")
+ if err != nil {
+ t.Fatal(err)
+ }
+ n := len(pkgPaths)
+ done := errors.New("done")
+ var visit filepath.WalkFunc
+ visit = func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if filepath.Base(path) == "buildid" && (info.Mode()&0111) != 0 {
+ buildidPath = path
+ }
+ for pkg := range pkgPaths {
+ if filepath.Base(path) == pkg {
+ pkgPaths[pkg] = path
+ n--
+ }
+ }
+ if buildidPath != "" && n == 0 {
+ return done
+ }
+ return nil
+ }
+ if err = filepath.Walk(stdlibPkgDir, visit); err != nil && err != done {
+ t.Fatal(err)
+ }
+ if buildidPath == "" {
+ t.Fatal("buildid not found")
+ }
+
+ for pkg, path := range pkgPaths {
+ if path == "" {
+ t.Errorf("could not locate %s", pkg)
+ continue
+ }
+ // Equivalent to: go tool buildid pkg.a
+ // It's an error if this produces any output.
+ cmd := exec.Command(buildidPath, path)
+ out, err := cmd.Output()
+ if err != nil {
+ t.Error(err)
+ }
+ if len(bytes.TrimSpace(out)) > 0 {
+ t.Errorf("%s: unexpected buildid: %s", path, out)
+ }
+ }
+}
diff --git a/tests/core/stdlib/reproduce_test.sh b/tests/core/stdlib/reproduce_test.sh
new file mode 100755
index 00000000..b709ab56
--- /dev/null
+++ b/tests/core/stdlib/reproduce_test.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+set -eux -o pipefail
+
+function run_bazel() {
+ bazel clean --expunge
+ bazel test //tests/core/go_binary:all
+ find bazel-out/ -name '*.a' | sort | uniq | grep stdlib | xargs shasum > $1
+}
+
+FILE1=$(mktemp)
+FILE2=$(mktemp)
+
+echo First run
+run_bazel ${FILE1}
+
+echo Second run
+run_bazel ${FILE2}
+
+echo Diffing runs
+diff ${FILE1} ${FILE2}
+
+echo Removing files
+rm ${FILE1} ${FILE2}
diff --git a/tests/core/stdlib/stdlib_files.bzl b/tests/core/stdlib/stdlib_files.bzl
new file mode 100644
index 00000000..35d48f33
--- /dev/null
+++ b/tests/core/stdlib/stdlib_files.bzl
@@ -0,0 +1,49 @@
+# Copyright 2018 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("//go/private:providers.bzl", "GoStdLib")
+
+def _force_rebuild_transition_impl(settings, attr):
+ return {"//go/config:race": True}
+
+force_rebuild_transition = transition(
+ implementation = _force_rebuild_transition_impl,
+ inputs = ["//go/config:race"],
+ outputs = ["//go/config:race"],
+)
+
+def _stdlib_files_impl(ctx):
+ # When an outgoing transition (aka split transition) is used,
+ # ctx.attr._stdlib is a list of Target.
+ stdlib = ctx.attr._stdlib[0][GoStdLib]
+ libs = stdlib.libs
+ runfiles = ctx.runfiles(files = libs)
+ return [DefaultInfo(
+ files = depset(libs + [stdlib._list_json]),
+ runfiles = runfiles,
+ )]
+
+stdlib_files = rule(
+ implementation = _stdlib_files_impl,
+ attrs = {
+ "_stdlib": attr.label(
+ default = "@io_bazel_rules_go//:stdlib",
+ providers = [GoStdLib],
+ cfg = force_rebuild_transition,
+ ),
+ "_allowlist_function_transition": attr.label(
+ default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
+ ),
+ },
+)
diff --git a/tests/core/strip/BUILD.bazel b/tests/core/strip/BUILD.bazel
new file mode 100644
index 00000000..bc2f6bd8
--- /dev/null
+++ b/tests/core/strip/BUILD.bazel
@@ -0,0 +1,6 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "strip_test",
+ srcs = ["strip_test.go"],
+)
diff --git a/tests/core/strip/README.rst b/tests/core/strip/README.rst
new file mode 100644
index 00000000..1b5c1f96
--- /dev/null
+++ b/tests/core/strip/README.rst
@@ -0,0 +1,13 @@
+symbol stripping
+====================
+
+strip_test
+---------
+
+Tests that the global Bazel configuration for stripping are applied to go_binary
+targets.
+In particular, it tests that stripping is performed iff the bazel flag ``--strip``
+is set to ``always`` or ``--strip`` is set to ``sometimes`` and ``--compilation_mode``
+is ``fastbuild``.
+Additionally, it tests that stack traces still contain the same information when stripping
+is enabled.
diff --git a/tests/core/strip/strip_test.go b/tests/core/strip/strip_test.go
new file mode 100644
index 00000000..b7183033
--- /dev/null
+++ b/tests/core/strip/strip_test.go
@@ -0,0 +1,270 @@
+// Copyright 2019 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.
+
+package strip_test
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "os/exec"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary")
+
+go_binary(
+ name = "strip",
+ srcs = ["strip.go"],
+)
+-- strip.go --
+package main
+
+import (
+ "debug/elf"
+ "debug/macho"
+ "debug/pe"
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "os"
+ "regexp"
+ "runtime"
+ "runtime/debug"
+ "strings"
+)
+
+var wantStrip = flag.Bool("wantstrip", false, "")
+
+func main() {
+ flag.Parse()
+ stackTrace, err := panicAndRecover()
+ if err != nil {
+ panic(err)
+ }
+ gotStackTrace := strings.Split(stackTrace, "\n")
+ if len(gotStackTrace) != len(wantStackTrace) {
+ panic(fmt.Sprintf("got %d lines of stack trace, want %d", len(gotStackTrace), len(wantStackTrace)))
+ }
+ for i := range gotStackTrace {
+ expectedLine := regexp.MustCompile(wantStackTrace[i])
+ if !expectedLine.MatchString(gotStackTrace[i]) {
+ panic(fmt.Sprintf("got unexpected stack trace line %q at index %d", gotStackTrace[i], i))
+ }
+ }
+ stripped, err := isStripped()
+ if err != nil {
+ panic(err)
+ }
+ if stripped != *wantStrip {
+ panic(fmt.Sprintf("got stripped=%t, want stripped=%t", stripped, *wantStrip))
+ }
+}
+
+func panicAndRecover() (stackTrace string, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ stackTrace = string(debug.Stack())
+ }
+ }()
+ panic("test")
+ return "", errors.New("should not reach here")
+}
+
+func isStripped() (bool, error) {
+ ownLocation, err := os.Executable()
+ if err != nil {
+ return false, err
+ }
+ ownBinary, err := os.Open(ownLocation)
+ if err != nil {
+ return false, err
+ }
+ defer ownBinary.Close()
+ switch runtime.GOOS {
+ case "darwin":
+ return isStrippedMachO(ownBinary)
+ case "linux":
+ return isStrippedElf(ownBinary)
+ case "windows":
+ return isStrippedPE(ownBinary)
+ default:
+ return false, fmt.Errorf("unsupported OS: %s", runtime.GOOS)
+ }
+}
+
+func isStrippedMachO(f io.ReaderAt) (bool, error) {
+ macho, err := macho.NewFile(f)
+ if err != nil {
+ return false, err
+ }
+ gotDwarf := macho.Segment("__DWARF") != nil
+ gotDebugInfo := macho.Section("__zdebug_info") != nil
+ if gotDwarf != gotDebugInfo {
+ return false, fmt.Errorf("inconsistent stripping: gotDwarf=%v, gotDebugInfo=%v", gotDwarf, gotDebugInfo)
+ }
+ return !gotDwarf, nil
+}
+
+func isStrippedElf(f io.ReaderAt) (bool, error) {
+ elf, err := elf.NewFile(f)
+ if err != nil {
+ return false, err
+ }
+ var gotSymtab bool
+ for _, section := range elf.Sections {
+ if section.Name == ".symtab" {
+ gotSymtab = true
+ break
+ }
+ }
+ return !gotSymtab, nil
+}
+
+
+func isStrippedPE(f io.ReaderAt) (bool, error) {
+ pe, err := pe.NewFile(f)
+ if err != nil {
+ return false, err
+ }
+ symtab := pe.Section(".symtab")
+ if symtab == nil {
+ return false, fmt.Errorf("no .symtab section")
+ }
+ emptySymtab := (symtab.VirtualSize <= 4) && (symtab.Size <= 512)
+ return emptySymtab, nil
+}
+
+
+` + embedWantedStackTraces(),
+ })
+}
+
+func Test(t *testing.T) {
+ for _, test := range []struct {
+ desc, stripFlag, compilationMode string
+ wantStrip bool
+ }{
+ {
+ desc: "run_auto",
+ wantStrip: true,
+ },
+ {
+ desc: "run_fastbuild",
+ compilationMode: "fastbuild",
+ wantStrip: true,
+ },
+ {
+ desc: "run_dbg",
+ compilationMode: "dbg",
+ },
+ {
+ desc: "run_opt",
+ compilationMode: "opt",
+ },
+ {
+ desc: "run_always",
+ stripFlag: "always",
+ wantStrip: true,
+ },
+ {
+ desc: "run_always_opt",
+ stripFlag: "always",
+ compilationMode: "opt",
+ wantStrip: true,
+ },
+ {
+ desc: "run_never",
+ stripFlag: "never",
+ },
+ {
+ desc: "run_sometimes_fastbuild",
+ stripFlag: "sometimes",
+ compilationMode: "fastbuild",
+ wantStrip: true,
+ },
+ {
+ desc: "run_sometimes_dbg",
+ stripFlag: "sometimes",
+ compilationMode: "dbg",
+ },
+ {
+ desc: "run_sometimes_opt",
+ stripFlag: "sometimes",
+ compilationMode: "opt",
+ },
+ } {
+ t.Run(test.desc, func(t *testing.T) {
+ args := []string{"run"}
+ if len(test.stripFlag) > 0 {
+ args = append(args, "--strip", test.stripFlag)
+ }
+ if len(test.compilationMode) > 0 {
+ args = append(args, "--compilation_mode", test.compilationMode)
+ }
+ args = append(args, "//:strip", "--", fmt.Sprintf("-wantstrip=%v", test.wantStrip))
+ cmd := bazel_testing.BazelCmd(args...)
+ stderr := &bytes.Buffer{}
+ cmd.Stderr = stderr
+ t.Logf("running: bazel %s", strings.Join(args, " "))
+ if err := cmd.Run(); err != nil {
+ var xerr *exec.ExitError
+ if !errors.As(err, &xerr) {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if xerr.ExitCode() == bazel_testing.BUILD_FAILURE {
+ t.Fatalf("unexpected build failure: %v\nstderr:\n%s", err, stderr.Bytes())
+ return
+ } else if xerr.ExitCode() == bazel_testing.TESTS_FAILED {
+ t.Fatalf("error running %s:\n%s", strings.Join(cmd.Args, " "), stderr.Bytes())
+ } else {
+ t.Fatalf("unexpected error: %v\nstderr:\n%s", err, stderr.Bytes())
+ }
+ }
+ })
+ }
+}
+
+var wantStackTrace = []string{
+ `^goroutine \d+ \[running\]:$`,
+ `^runtime/debug\.Stack\(\)$`,
+ `^ GOROOT/src/runtime/debug/stack\.go:\d+ \+0x[0-9a-f]+$`,
+ `^main\.panicAndRecover\.func1\(\)$`,
+ `^ strip\.go:\d+ \+0x[0-9a-f]+$`,
+ `^panic\({0x[0-9a-f]+, 0x[0-9a-f]+}\)$`,
+ `^ GOROOT/src/runtime/panic\.go:\d+ \+0x[0-9a-f]+$`,
+ `^main\.panicAndRecover\(\)$`,
+ `^ strip\.go:\d+ \+0x[0-9a-f]+$`,
+ `^main\.main\(\)$`,
+ `^ strip\.go:\d+ \+0x[0-9a-f]+$`,
+ `^$`,
+}
+
+func embedWantedStackTraces() string {
+ buf := &bytes.Buffer{}
+ fmt.Fprintln(buf, "var wantStackTrace = []string{")
+ for _, s := range wantStackTrace {
+ fmt.Fprintf(buf, "`%s`,\n", s)
+ }
+ fmt.Fprintln(buf, "}")
+ return buf.String()
+}
diff --git a/tests/core/transition/BUILD.bazel b/tests/core/transition/BUILD.bazel
new file mode 100644
index 00000000..12fe1504
--- /dev/null
+++ b/tests/core/transition/BUILD.bazel
@@ -0,0 +1,13 @@
+load("//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "cmdline_test",
+ size = "medium",
+ srcs = ["cmdline_test.go"],
+)
+
+go_bazel_test(
+ name = "hermeticity_test",
+ size = "medium",
+ srcs = ["hermeticity_test.go"],
+)
diff --git a/tests/core/transition/README.rst b/tests/core/transition/README.rst
new file mode 100644
index 00000000..5033f7b3
--- /dev/null
+++ b/tests/core/transition/README.rst
@@ -0,0 +1,18 @@
+Misc configuration transition tests
+===================================
+
+.. _go_binary: /docs/go/core/rules.md#_go_binary
+.. _go_test: /docs/go/core/rules.md#_go_test
+
+Tests that check that configuration transitions for `go_binary`_ and `go_test`_
+are working correctly.
+
+Most tests for specific attributes are in other directories, for example,
+``c_linkmodes``, ``cross``, ``nogo``, ``race``. This directory covers
+transition-related stuff that doesn't fit anywhere else.
+
+cmdline_test
+------------
+Tests that build settings can be set with flags on the command line. The test
+builds a target with and without a command line flag and verifies the output
+is different.
diff --git a/tests/core/transition/cmdline_test.go b/tests/core/transition/cmdline_test.go
new file mode 100644
index 00000000..1de0b3f5
--- /dev/null
+++ b/tests/core/transition/cmdline_test.go
@@ -0,0 +1,84 @@
+// Copyright 2020 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.
+
+package cmdline_test
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary")
+
+go_binary(
+ name = "maybe_pure",
+ srcs = [
+ "not_pure.go",
+ "pure.go",
+ ],
+)
+
+-- not_pure.go --
+// +build cgo
+
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("not pure")
+}
+
+-- pure.go --
+// +build !cgo
+
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("pure")
+}
+`,
+ })
+}
+
+// TestPure checks that the --@io_bazel_rules_go//go/config:pure flag controls
+// whether a target is built in pure mode. It doesn't actually require cgo,
+// since that doesn't work within go_bazel_test on Windows.
+func TestPure(t *testing.T) {
+ out, err := bazel_testing.BazelOutput("run", "//:maybe_pure")
+ if err != nil {
+ t.Fatalf("running //:maybe_pure without flag: %v", err)
+ }
+ got := string(bytes.TrimSpace(out))
+ if want := "not pure"; got != want {
+ t.Fatalf("got %q; want %q", got, want)
+ }
+
+ out, err = bazel_testing.BazelOutput("run", "--@io_bazel_rules_go//go/config:pure", "//:maybe_pure")
+ if err != nil {
+ t.Fatalf("running //:maybe_pure with flag: %v", err)
+ }
+ got = string(bytes.TrimSpace(out))
+ if want := "pure"; got != want {
+ t.Fatalf("got %q; want %q", got, want)
+ }
+}
diff --git a/tests/core/transition/hermeticity_test.go b/tests/core/transition/hermeticity_test.go
new file mode 100644
index 00000000..08eda7d6
--- /dev/null
+++ b/tests/core/transition/hermeticity_test.go
@@ -0,0 +1,289 @@
+// Copyright 2021 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.
+
+package hermeticity_test
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
+load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
+load("@rules_proto//proto:defs.bzl", "proto_library")
+
+go_binary(
+ name = "main",
+ srcs = [
+ "main.go",
+ ":gen_go",
+ ],
+ data = [":helper"],
+ embedsrcs = [":helper"],
+ cdeps = [":helper"],
+ cgo = True,
+ linkmode = "c-archive",
+ gotags = ["foo"],
+ deps = [":lib"],
+)
+
+go_library(
+ name = "lib",
+ srcs = [
+ "lib.go",
+ ":gen_indirect_go",
+ ],
+ importpath = "example.com/lib",
+ data = [":indirect_helper"],
+ embedsrcs = [":indirect_helper"],
+ cdeps = [":indirect_helper"],
+ cgo = True,
+)
+
+go_test(
+ name = "main_test",
+ srcs = [
+ "main.go",
+ ":gen_go",
+ ],
+ data = [":helper"],
+ embedsrcs = [":helper"],
+ cdeps = [":helper"],
+ cgo = True,
+ linkmode = "c-archive",
+ gotags = ["foo"],
+)
+
+cc_library(
+ name = "helper",
+)
+
+cc_library(
+ name = "indirect_helper",
+)
+
+genrule(
+ name = "gen_go",
+ outs = ["gen.go"],
+ exec_tools = [":helper"],
+ cmd = "# Not needed for bazel cquery",
+)
+
+genrule(
+ name = "gen_indirect_go",
+ outs = ["gen_indirect.go"],
+ exec_tools = [":indirect_helper"],
+ cmd = "# Not needed for bazel cquery",
+)
+
+proto_library(
+ name = "foo_proto",
+ srcs = ["foo.proto"],
+)
+
+go_proto_library(
+ name = "foo_go_proto",
+ importpath = "github.com/bazelbuild/rules_go/tests/core/transition/foo",
+ proto = ":foo_proto",
+)
+-- main.go --
+package main
+
+func main() {}
+-- lib.go --
+-- foo.proto --
+syntax = "proto3";
+
+package tests.core.transition.foo;
+option go_package = "github.com/bazelbuild/rules_go/tests/core/transition/foo";
+
+message Foo {
+ int64 value = 1;
+}
+`,
+ WorkspaceSuffix: `
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+http_archive(
+ name = "com_google_protobuf",
+ sha256 = "75be42bd736f4df6d702a0e4e4d30de9ee40eac024c4b845d17ae4cc831fe4ae",
+ strip_prefix = "protobuf-21.7",
+ # latest available in BCR, as of 2022-09-30
+ urls = [
+ "https://github.com/protocolbuffers/protobuf/archive/v21.7.tar.gz",
+ "https://mirror.bazel.build/github.com/protocolbuffers/protobuf/archive/v21.7.tar.gz",
+ ],
+)
+
+load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
+
+protobuf_deps()
+
+http_archive(
+ name = "rules_proto",
+ sha256 = "4d421d51f9ecfe9bf96ab23b55c6f2b809cbaf0eea24952683e397decfbd0dd0",
+ strip_prefix = "rules_proto-f6b8d89b90a7956f6782a4a3609b2f0eee3ce965",
+ # master, as of 2020-01-06
+ urls = [
+ "https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/f6b8d89b90a7956f6782a4a3609b2f0eee3ce965.tar.gz",
+ "https://github.com/bazelbuild/rules_proto/archive/f6b8d89b90a7956f6782a4a3609b2f0eee3ce965.tar.gz",
+ ],
+)
+`,
+ })
+}
+
+func TestGoBinaryNonGoAttrsAreReset(t *testing.T) {
+ assertDependsCleanlyOnWithFlags(
+ t,
+ "//:main",
+ "//:helper")
+}
+
+func TestGoLibraryNonGoAttrsAreReset(t *testing.T) {
+ assertDependsCleanlyOnWithFlags(
+ t,
+ "//:main",
+ "//:indirect_helper")
+}
+
+func TestGoTestNonGoAttrsAreReset(t *testing.T) {
+ assertDependsCleanlyOnWithFlags(
+ t,
+ "//:main_test",
+ "//:helper")
+}
+
+func TestGoProtoLibraryToolAttrsAreReset(t *testing.T) {
+ assertDependsCleanlyOnWithFlags(
+ t,
+ "//:foo_go_proto",
+ "@com_google_protobuf//:protoc",
+ "--@io_bazel_rules_go//go/config:static",
+ "--@io_bazel_rules_go//go/config:msan",
+ "--@io_bazel_rules_go//go/config:race",
+ "--@io_bazel_rules_go//go/config:debug",
+ "--@io_bazel_rules_go//go/config:linkmode=c-archive",
+ "--@io_bazel_rules_go//go/config:tags=fake_tag",
+ )
+ assertDependsCleanlyOnWithFlags(
+ t,
+ "//:foo_go_proto",
+ "@com_google_protobuf//:protoc",
+ "--@io_bazel_rules_go//go/config:pure",
+ )
+}
+
+func assertDependsCleanlyOnWithFlags(t *testing.T, targetA, targetB string, flags ...string) {
+ query := fmt.Sprintf("deps(%s) intersect %s", targetA, targetB)
+ out, err := bazel_testing.BazelOutput(append(
+ []string{
+ "cquery",
+ "--transitions=full",
+ "--output=jsonproto",
+ query,
+ },
+ flags...,
+ )...,
+ )
+ if err != nil {
+ t.Fatalf("bazel cquery '%s': %v", query, err)
+ }
+ cqueryOut := bytes.TrimSpace(out)
+ configHashes := extractConfigHashes(t, cqueryOut)
+ if len(configHashes) != 1 {
+ differingGoOptions := getGoOptions(t, configHashes...)
+ if len(differingGoOptions) != 0 {
+ t.Fatalf(
+ "%s depends on %s in multiple configs with these differences in rules_go options: %s",
+ targetA,
+ targetB,
+ strings.Join(differingGoOptions, "\n"),
+ )
+ }
+ }
+ goOptions := getGoOptions(t, configHashes[0])
+ if len(goOptions) != 0 {
+ t.Fatalf(
+ "%s depends on %s in a config with rules_go options: %s",
+ targetA,
+ targetB,
+ strings.Join(goOptions, "\n"),
+ )
+ }
+}
+
+func extractConfigHashes(t *testing.T, rawJsonOut []byte) []string {
+ var jsonOut bazelCqueryOutput
+ err := json.Unmarshal(rawJsonOut, &jsonOut)
+ if err != nil {
+ t.Fatalf("Failed to decode bazel config JSON output %v: %q", err, string(rawJsonOut))
+ }
+ var hashes []string
+ for _, result := range jsonOut.Results {
+ hashes = append(hashes, result.Configuration.Checksum)
+ }
+ return hashes
+}
+
+func getGoOptions(t *testing.T, hashes ...string) []string {
+ out, err := bazel_testing.BazelOutput(append([]string{"config", "--output=json"}, hashes...)...)
+ if err != nil {
+ t.Fatalf("bazel config %s: %v", strings.Join(hashes, " "), err)
+ }
+ rawJsonOut := bytes.TrimSpace(out)
+ var jsonOut bazelConfigOutput
+ err = json.Unmarshal(rawJsonOut, &jsonOut)
+ if err != nil {
+ t.Fatalf("Failed to decode bazel config JSON output %v: %q", err, string(rawJsonOut))
+ }
+ var differingGoOptions []string
+ for _, fragment := range jsonOut.Fragments {
+ if fragment.Name != starlarkOptionsFragment {
+ continue
+ }
+ for key, value := range fragment.Options {
+ if strings.HasPrefix(key, "@io_bazel_rules_go//") {
+ differingGoOptions = append(differingGoOptions, fmt.Sprintf("%s=%s", key, value))
+ }
+ }
+ }
+ return differingGoOptions
+}
+
+const starlarkOptionsFragment = "user-defined"
+
+type bazelConfigOutput struct {
+ Fragments []struct {
+ Name string `json:"name"`
+ Options map[string]string `json:"options"`
+ } `json:"fragmentOptions"`
+}
+
+type bazelCqueryOutput struct {
+ Results []struct {
+ Configuration struct {
+ Checksum string `json:"checksum"`
+ } `json:"configuration"`
+ } `json:"results"`
+}