cmd/go: search test imports when matching -coverpkg

Fixes #25093

Change-Id: If283275e2b73621ade56d014e60c2d18199b366c
Reviewed-on: https://go-review.googlesource.com/122555
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go
index 4bf1792..6df70a2 100644
--- a/src/cmd/go/go_test.go
+++ b/src/cmd/go/go_test.go
@@ -6210,3 +6210,23 @@
 	tg.mustNotExist("hello")
 	tg.mustNotExist("hello.exe")
 }
+
+// Issue 25093.
+func TestCoverpkgTestOnly(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempFile("src/a/a.go", `package a
+		func F(i int) int {
+			return i*i
+		}`)
+	tg.tempFile("src/atest/a_test.go", `
+		package a_test
+		import ( "a"; "testing" )
+		func TestF(t *testing.T) { a.F(2) }
+	`)
+	tg.setenv("GOPATH", tg.path("."))
+	tg.run("test", "-coverpkg=a", "atest")
+	tg.grepStderrNot("no packages being tested depend on matches", "bad match message")
+	tg.grepStdout("coverage: 100", "no coverage")
+}
diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go
index 198fef3..50cd01f 100644
--- a/src/cmd/go/internal/load/pkg.go
+++ b/src/cmd/go/internal/load/pkg.go
@@ -1596,7 +1596,7 @@
 	return len(p.CgoFiles) > 0
 }
 
-// packageList returns the list of packages in the dag rooted at roots
+// PackageList returns the list of packages in the dag rooted at roots
 // as visited in a depth-first post-order traversal.
 func PackageList(roots []*Package) []*Package {
 	seen := map[*Package]bool{}
@@ -1618,6 +1618,42 @@
 	return all
 }
 
+// TestPackageList returns the list of packages in the dag rooted at roots
+// as visited in a depth-first post-order traversal, including the test
+// imports of the roots. This ignores errors in test packages.
+func TestPackageList(roots []*Package) []*Package {
+	seen := map[*Package]bool{}
+	all := []*Package{}
+	var walk func(*Package)
+	walk = func(p *Package) {
+		if seen[p] {
+			return
+		}
+		seen[p] = true
+		for _, p1 := range p.Internal.Imports {
+			walk(p1)
+		}
+		all = append(all, p)
+	}
+	walkTest := func(root *Package, path string) {
+		var stk ImportStack
+		p1 := LoadImport(path, root.Dir, root, &stk, root.Internal.Build.TestImportPos[path], ResolveImport)
+		if p1.Error == nil {
+			walk(p1)
+		}
+	}
+	for _, root := range roots {
+		walk(root)
+		for _, path := range root.TestImports {
+			walkTest(root, path)
+		}
+		for _, path := range root.XTestImports {
+			walkTest(root, path)
+		}
+	}
+	return all
+}
+
 var cmdCache = map[string]*Package{}
 
 func ClearCmdCache() {
diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go
index 7c5c779..80c99b7 100644
--- a/src/cmd/go/internal/test/test.go
+++ b/src/cmd/go/internal/test/test.go
@@ -650,7 +650,7 @@
 		}
 
 		// Select for coverage all dependencies matching the testCoverPaths patterns.
-		for _, p := range load.PackageList(pkgs) {
+		for _, p := range load.TestPackageList(pkgs) {
 			haveMatch := false
 			for i := range testCoverPaths {
 				if match[i](p) {