diff --git a/tests/core/nogo/coverage/BUILD.bazel b/tests/core/nogo/coverage/BUILD.bazel index 8eb40b7c5e..b14fcaf48e 100644 --- a/tests/core/nogo/coverage/BUILD.bazel +++ b/tests/core/nogo/coverage/BUILD.bazel @@ -4,3 +4,8 @@ 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 index d672e2c871..cd1fdbf3f2 100644 --- a/tests/core/nogo/coverage/README.rst +++ b/tests/core/nogo/coverage/README.rst @@ -16,3 +16,13 @@ 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`_ would interact with source code that was generated as part of +rules_go's coverage implementation. Currently `nogo`_ would be run over these +generated source code, which is not desirable as end-user have very little control +over how these code were generated. + +In a future version, we shall flip this behavior so that `nogo`_ would not run +over source files that users have no control over. 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 0000000000..2d394dc23a --- /dev/null +++ b/tests/core/nogo/coverage/gen_code_test.go @@ -0,0 +1,142 @@ +// 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 ( + "errors" + "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_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) { + out, err := bazel_testing.BazelOutput("coverage", "//:simple_test") + if err == nil { + t.Fatal("test should fail") + } + + var eErr *exec.ExitError + if errors.As(err, &eErr) && strings.Contains(string(eErr.Stderr), "was generated by rules_go (nocover)") { + // Expected failure + return + } + + println(string(out)) + t.Fatal(err) +}