1 // Copyright 2018 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
17 "internal/lazytemplate"
24 "cmd/go/internal/fsys"
26 "cmd/go/internal/trace"
29 var TestMainDeps = []string{
30 // Dependencies for testmain.
34 "testing/internal/testdeps",
37 type TestCover struct {
43 DeclVars func(*Package, ...string) map[string]*CoverVar
46 // TestPackagesFor is like TestPackagesAndErrors but it returns
47 // an error if the test packages or their dependencies have errors.
48 // Only test packages without errors are returned.
49 func TestPackagesFor(ctx context.Context, opts PackageOpts, p *Package, cover *TestCover) (pmain, ptest, pxtest *Package, err error) {
50 pmain, ptest, pxtest = TestPackagesAndErrors(ctx, opts, p, cover)
51 for _, p1 := range []*Package{ptest, pxtest, pmain} {
60 if len(p1.DepsErrors) > 0 {
61 perr := p1.DepsErrors[0]
66 if pmain.Error != nil || len(pmain.DepsErrors) > 0 {
69 if ptest.Error != nil || len(ptest.DepsErrors) > 0 {
72 if pxtest != nil && (pxtest.Error != nil || len(pxtest.DepsErrors) > 0) {
75 return pmain, ptest, pxtest, err
78 // TestPackagesAndErrors returns three packages:
79 // - pmain, the package main corresponding to the test binary (running tests in ptest and pxtest).
80 // - ptest, the package p compiled with added "package p" test files.
81 // - pxtest, the result of compiling any "package p_test" (external) test files.
83 // If the package has no "package p_test" test files, pxtest will be nil.
84 // If the non-test compilation of package p can be reused
85 // (for example, if there are no "package p" test files and
86 // package p need not be instrumented for coverage or any other reason),
87 // then the returned ptest == p.
89 // An error is returned if the testmain source cannot be completely generated
90 // (for example, due to a syntax error in a test file). No error will be
91 // returned for errors loading packages, but the Error or DepsError fields
92 // of the returned packages may be set.
94 // The caller is expected to have checked that len(p.TestGoFiles)+len(p.XTestGoFiles) > 0,
95 // or else there's no point in any of this.
96 func TestPackagesAndErrors(ctx context.Context, opts PackageOpts, p *Package, cover *TestCover) (pmain, ptest, pxtest *Package) {
97 ctx, span := trace.StartSpan(ctx, "load.TestPackagesAndErrors")
102 allImports := append([]string{}, p.TestImports...)
103 allImports = append(allImports, p.XTestImports...)
104 pre.preloadImports(ctx, opts, allImports, p.Internal.Build)
106 var ptestErr, pxtestErr *PackageError
107 var imports, ximports []*Package
109 var testEmbed, xtestEmbed map[string][]string
110 stk.Push(p.ImportPath + " (test)")
111 rawTestImports := str.StringList(p.TestImports)
112 for i, path := range p.TestImports {
113 p1 := loadImport(ctx, opts, pre, path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport)
114 if str.Contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
115 // Same error that loadPackage returns (via reusePackage) in pkg.go.
116 // Can't change that code, because that code is only for loading the
117 // non-test copy of a package.
118 ptestErr = &PackageError{
119 ImportStack: importCycleStack(p1, p.ImportPath),
120 Err: errors.New("import cycle not allowed in test"),
124 p.TestImports[i] = p1.ImportPath
125 imports = append(imports, p1)
128 p.TestEmbedFiles, testEmbed, err = resolveEmbed(p.Dir, p.TestEmbedPatterns)
129 if err != nil && ptestErr == nil {
130 ptestErr = &PackageError{
131 ImportStack: stk.Copy(),
134 embedErr := err.(*EmbedError)
135 ptestErr.setPos(p.Internal.Build.TestEmbedPatternPos[embedErr.Pattern])
139 stk.Push(p.ImportPath + "_test")
140 pxtestNeedsPtest := false
141 rawXTestImports := str.StringList(p.XTestImports)
142 for i, path := range p.XTestImports {
143 p1 := loadImport(ctx, opts, pre, path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], ResolveImport)
144 if p1.ImportPath == p.ImportPath {
145 pxtestNeedsPtest = true
147 ximports = append(ximports, p1)
149 p.XTestImports[i] = p1.ImportPath
151 p.XTestEmbedFiles, xtestEmbed, err = resolveEmbed(p.Dir, p.XTestEmbedPatterns)
152 if err != nil && pxtestErr == nil {
153 pxtestErr = &PackageError{
154 ImportStack: stk.Copy(),
157 embedErr := err.(*EmbedError)
158 pxtestErr.setPos(p.Internal.Build.XTestEmbedPatternPos[embedErr.Pattern])
163 if len(p.TestGoFiles) > 0 || p.Name == "main" || cover != nil && cover.Local {
166 ptest.Error = ptestErr
167 ptest.ForTest = p.ImportPath
169 ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
170 ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
172 // Note: The preparation of the vet config requires that common
173 // indexes in ptest.Imports and ptest.Internal.RawImports
174 // all line up (but RawImports can be shorter than the others).
175 // That is, for 0 ≤ i < len(RawImports),
176 // RawImports[i] is the import string in the program text, and
177 // Imports[i] is the expanded import string (vendoring applied or relative path expanded away).
178 // Any implicitly added imports appear in Imports and Internal.Imports
179 // but not RawImports (because they were not in the source code).
180 // We insert TestImports, imports, and rawTestImports at the start of
181 // these lists to preserve the alignment.
182 // Note that p.Internal.Imports may not be aligned with p.Imports/p.Internal.RawImports,
183 // but we insert at the beginning there too just for consistency.
184 ptest.Imports = str.StringList(p.TestImports, p.Imports)
185 ptest.Internal.Imports = append(imports, p.Internal.Imports...)
186 ptest.Internal.RawImports = str.StringList(rawTestImports, p.Internal.RawImports)
187 ptest.Internal.ForceLibrary = true
188 ptest.Internal.BuildInfo = ""
189 ptest.Internal.Build = new(build.Package)
190 *ptest.Internal.Build = *p.Internal.Build
191 m := map[string][]token.Position{}
192 for k, v := range p.Internal.Build.ImportPos {
193 m[k] = append(m[k], v...)
195 for k, v := range p.Internal.Build.TestImportPos {
196 m[k] = append(m[k], v...)
198 ptest.Internal.Build.ImportPos = m
199 if testEmbed == nil && len(p.Internal.Embed) > 0 {
200 testEmbed = map[string][]string{}
202 for k, v := range p.Internal.Embed {
205 ptest.Internal.Embed = testEmbed
206 ptest.EmbedFiles = str.StringList(p.EmbedFiles, p.TestEmbedFiles)
207 ptest.Internal.OrigImportPath = p.Internal.OrigImportPath
213 // External test package.
214 if len(p.XTestGoFiles) > 0 {
216 PackagePublic: PackagePublic{
217 Name: p.Name + "_test",
218 ImportPath: p.ImportPath + "_test",
222 GoFiles: p.XTestGoFiles,
223 Imports: p.XTestImports,
224 ForTest: p.ImportPath,
227 EmbedFiles: p.XTestEmbedFiles,
229 Internal: PackageInternal{
230 LocalPrefix: p.Internal.LocalPrefix,
231 Build: &build.Package{
232 ImportPos: p.Internal.Build.XTestImportPos,
235 RawImports: rawXTestImports,
237 Asmflags: p.Internal.Asmflags,
238 Gcflags: p.Internal.Gcflags,
239 Ldflags: p.Internal.Ldflags,
240 Gccgoflags: p.Internal.Gccgoflags,
242 OrigImportPath: p.Internal.OrigImportPath,
245 if pxtestNeedsPtest {
246 pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest)
251 // Build main package.
253 PackagePublic: PackagePublic{
256 GoFiles: []string{"_testmain.go"},
257 ImportPath: p.ImportPath + ".test",
259 Imports: str.StringList(TestMainDeps),
262 Internal: PackageInternal{
263 Build: &build.Package{Name: "main"},
264 BuildInfo: p.Internal.BuildInfo,
265 Asmflags: p.Internal.Asmflags,
266 Gcflags: p.Internal.Gcflags,
267 Ldflags: p.Internal.Ldflags,
268 Gccgoflags: p.Internal.Gccgoflags,
269 OrigImportPath: p.Internal.OrigImportPath,
273 // The generated main also imports testing, regexp, and os.
274 // Also the linker introduces implicit dependencies reported by LinkerDeps.
276 deps := TestMainDeps // cap==len, so safe for append
277 for _, d := range LinkerDeps(p) {
278 deps = append(deps, d)
280 for _, dep := range deps {
281 if dep == ptest.ImportPath {
282 pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
284 p1 := loadImport(ctx, opts, pre, dep, "", nil, &stk, nil, 0)
285 pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
290 if cover != nil && cover.Pkgs != nil {
291 // Add imports, but avoid duplicates.
292 seen := map[*Package]bool{p: true, ptest: true}
293 for _, p1 := range pmain.Internal.Imports {
296 for _, p1 := range cover.Pkgs {
298 // Don't add duplicate imports.
302 pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
306 allTestImports := make([]*Package, 0, len(pmain.Internal.Imports)+len(imports)+len(ximports))
307 allTestImports = append(allTestImports, pmain.Internal.Imports...)
308 allTestImports = append(allTestImports, imports...)
309 allTestImports = append(allTestImports, ximports...)
310 setToolFlags(allTestImports...)
312 // Do initial scan for metadata needed for writing _testmain.go
313 // Use that metadata to update the list of imports for package main.
314 // The list of imports is used by recompileForTest and by the loop
315 // afterward that gathers t.Cover information.
316 t, err := loadTestFuncs(ptest)
317 if err != nil && pmain.Error == nil {
318 pmain.setLoadPackageDataError(err, p.ImportPath, &stk, nil)
321 if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
322 pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
323 pmain.Imports = append(pmain.Imports, ptest.ImportPath)
327 pmain.Internal.Imports = append(pmain.Internal.Imports, pxtest)
328 pmain.Imports = append(pmain.Imports, pxtest.ImportPath)
333 // Sort and dedup pmain.Imports.
334 // Only matters for go list -test output.
335 sort.Strings(pmain.Imports)
337 for _, path := range pmain.Imports {
338 if w == 0 || path != pmain.Imports[w-1] {
339 pmain.Imports[w] = path
343 pmain.Imports = pmain.Imports[:w]
344 pmain.Internal.RawImports = str.StringList(pmain.Imports)
346 // Replace pmain's transitive dependencies with test copies, as necessary.
347 recompileForTest(pmain, p, ptest, pxtest)
349 // Should we apply coverage analysis locally,
350 // only for this package and only for this test?
351 // Yes, if -cover is on but -coverpkg has not specified
352 // a list of packages for global coverage.
353 if cover != nil && cover.Local {
354 ptest.Internal.CoverMode = cover.Mode
355 var coverFiles []string
356 coverFiles = append(coverFiles, ptest.GoFiles...)
357 coverFiles = append(coverFiles, ptest.CgoFiles...)
358 ptest.Internal.CoverVars = cover.DeclVars(ptest, coverFiles...)
361 for _, cp := range pmain.Internal.Imports {
362 if len(cp.Internal.CoverVars) > 0 {
363 t.Cover.Vars = append(t.Cover.Vars, coverInfo{cp, cp.Internal.CoverVars})
367 data, err := formatTestmain(t)
368 if err != nil && pmain.Error == nil {
369 pmain.Error = &PackageError{Err: err}
372 pmain.Internal.TestmainGo = &data
375 return pmain, ptest, pxtest
378 // importCycleStack returns an import stack from p to the package whose import
380 func importCycleStack(p *Package, target string) []string {
381 // importerOf maps each import path to its importer nearest to p.
382 importerOf := map[string]string{p.ImportPath: ""}
384 // q is a breadth-first queue of packages to search for target.
385 // Every package added to q has a corresponding entry in pathTo.
387 // We search breadth-first for two reasons:
389 // 1. We want to report the shortest cycle.
391 // 2. If p contains multiple cycles, the first cycle we encounter might not
392 // contain target. To ensure termination, we have to break all cycles
393 // other than the first.
399 if path := p.ImportPath; path == target {
402 stk = append(stk, path)
403 path = importerOf[path]
407 for _, dep := range p.Internal.Imports {
408 if _, ok := importerOf[dep.ImportPath]; !ok {
409 importerOf[dep.ImportPath] = p.ImportPath
415 panic("lost path to cycle")
418 // recompileForTest copies and replaces certain packages in pmain's dependency
419 // graph. This is necessary for two reasons. First, if ptest is different than
420 // preal, packages that import the package under test should get ptest instead
421 // of preal. This is particularly important if pxtest depends on functionality
422 // exposed in test sources in ptest. Second, if there is a main package
423 // (other than pmain) anywhere, we need to set p.Internal.ForceLibrary and
424 // clear p.Internal.BuildInfo in the test copy to prevent link conflicts.
425 // This may happen if both -coverpkg and the command line patterns include
426 // multiple main packages.
427 func recompileForTest(pmain, preal, ptest, pxtest *Package) {
428 // The "test copy" of preal is ptest.
429 // For each package that depends on preal, make a "test copy"
430 // that depends on ptest. And so on, up the dependency tree.
431 testCopy := map[*Package]*Package{preal: ptest}
432 for _, p := range PackageList([]*Package{pmain}) {
437 didSplit := p == pmain || p == pxtest
443 if testCopy[p] != nil {
444 panic("recompileForTest loop")
449 p1.ForTest = preal.ImportPath
450 p1.Internal.Imports = make([]*Package, len(p.Internal.Imports))
451 copy(p1.Internal.Imports, p.Internal.Imports)
452 p1.Imports = make([]string, len(p.Imports))
453 copy(p1.Imports, p.Imports)
456 p.Internal.BuildInfo = ""
457 p.Internal.ForceLibrary = true
460 // Update p.Internal.Imports to use test copies.
461 for i, imp := range p.Internal.Imports {
462 if p1 := testCopy[imp]; p1 != nil && p1 != imp {
464 p.Internal.Imports[i] = p1
468 // Force main packages the test imports to be built as libraries.
469 // Normal imports of main packages are forbidden by the package loader,
470 // but this can still happen if -coverpkg patterns include main packages:
471 // covered packages are imported by pmain. Linking multiple packages
472 // compiled with '-p main' causes duplicate symbol errors.
473 // See golang.org/issue/30907, golang.org/issue/34114.
474 if p.Name == "main" && p != pmain && p != ptest {
480 // isTestFunc tells whether fn has the type of a testing function. arg
481 // specifies the parameter type we look for: B, M or T.
482 func isTestFunc(fn *ast.FuncDecl, arg string) bool {
483 if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
484 fn.Type.Params.List == nil ||
485 len(fn.Type.Params.List) != 1 ||
486 len(fn.Type.Params.List[0].Names) > 1 {
489 ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr)
493 // We can't easily check that the type is *testing.M
494 // because we don't know how testing has been imported,
495 // but at least check that it's *M or *something.M.
496 // Same applies for B and T.
497 if name, ok := ptr.X.(*ast.Ident); ok && name.Name == arg {
500 if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == arg {
506 // isTest tells whether name looks like a test (or benchmark, according to prefix).
507 // It is a Test (say) if there is a character after Test that is not a lower-case letter.
508 // We don't want TesticularCancer.
509 func isTest(name, prefix string) bool {
510 if !strings.HasPrefix(name, prefix) {
513 if len(name) == len(prefix) { // "Test" is ok
516 rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
517 return !unicode.IsLower(rune)
520 type coverInfo struct {
522 Vars map[string]*CoverVar
525 // loadTestFuncs returns the testFuncs describing the tests that will be run.
526 // The returned testFuncs is always non-nil, even if an error occurred while
527 // processing test files.
528 func loadTestFuncs(ptest *Package) (*testFuncs, error) {
533 for _, file := range ptest.TestGoFiles {
534 if lerr := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); lerr != nil && err == nil {
538 for _, file := range ptest.XTestGoFiles {
539 if lerr := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); lerr != nil && err == nil {
546 // formatTestmain returns the content of the _testmain.go file for t.
547 func formatTestmain(t *testFuncs) ([]byte, error) {
549 if err := testmainTmpl.Execute(&buf, t); err != nil {
552 return buf.Bytes(), nil
555 type testFuncs struct {
557 Benchmarks []testFunc
558 FuzzTargets []testFunc
569 // ImportPath returns the import path of the package being tested, if it is within GOPATH.
570 // This is printed by the testing package when running benchmarks.
571 func (t *testFuncs) ImportPath() string {
572 pkg := t.Package.ImportPath
573 if strings.HasPrefix(pkg, "_/") {
576 if pkg == "command-line-arguments" {
582 // Covered returns a string describing which packages are being tested for coverage.
583 // If the covered package is the same as the tested package, it returns the empty string.
584 // Otherwise it is a comma-separated human-readable list of packages beginning with
585 // " in", ready for use in the coverage message.
586 func (t *testFuncs) Covered() string {
587 if t.Cover == nil || t.Cover.Paths == nil {
590 return " in " + strings.Join(t.Cover.Paths, ", ")
593 // Tested returns the name of the package being tested.
594 func (t *testFuncs) Tested() string {
595 return t.Package.Name
598 type testFunc struct {
599 Package string // imported package name (_test or _xtest)
600 Name string // function name
601 Output string // output, for examples
602 Unordered bool // output is allowed to be unordered.
605 var testFileSet = token.NewFileSet()
607 func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
608 // Pass in the overlaid source if we have an overlay for this file.
609 src, err := fsys.Open(filename)
614 f, err := parser.ParseFile(testFileSet, filename, src, parser.ParseComments)
618 for _, d := range f.Decls {
619 n, ok := d.(*ast.FuncDecl)
626 name := n.Name.String()
628 case name == "TestMain":
629 if isTestFunc(n, "T") {
630 t.Tests = append(t.Tests, testFunc{pkg, name, "", false})
631 *doImport, *seen = true, true
634 err := checkTestFunc(n, "M")
638 if t.TestMain != nil {
639 return errors.New("multiple definitions of TestMain")
641 t.TestMain = &testFunc{pkg, name, "", false}
642 *doImport, *seen = true, true
643 case isTest(name, "Test"):
644 err := checkTestFunc(n, "T")
648 t.Tests = append(t.Tests, testFunc{pkg, name, "", false})
649 *doImport, *seen = true, true
650 case isTest(name, "Benchmark"):
651 err := checkTestFunc(n, "B")
655 t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, "", false})
656 *doImport, *seen = true, true
657 case isTest(name, "Fuzz"):
658 err := checkTestFunc(n, "F")
662 t.FuzzTargets = append(t.FuzzTargets, testFunc{pkg, name, "", false})
663 *doImport, *seen = true, true
666 ex := doc.Examples(f)
667 sort.Slice(ex, func(i, j int) bool { return ex[i].Order < ex[j].Order })
668 for _, e := range ex {
669 *doImport = true // import test file whether executed or not
670 if e.Output == "" && !e.EmptyOutput {
671 // Don't run examples with no output.
674 t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output, e.Unordered})
680 func checkTestFunc(fn *ast.FuncDecl, arg string) error {
681 if !isTestFunc(fn, arg) {
682 name := fn.Name.String()
683 pos := testFileSet.Position(fn.Pos())
684 return fmt.Errorf("%s: wrong signature for %s, must be: func %s(%s *testing.%s)", pos, name, name, strings.ToLower(arg), arg)
689 var testmainTmpl = lazytemplate.New("main", `
690 // Code generated by 'go test'. DO NOT EDIT.
700 "testing/internal/testdeps"
703 {{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
706 {{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
709 {{range $i, $p := .Cover.Vars}}
710 _cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
715 var tests = []testing.InternalTest{
717 {"{{.Name}}", {{.Package}}.{{.Name}}},
721 var benchmarks = []testing.InternalBenchmark{
722 {{range .Benchmarks}}
723 {"{{.Name}}", {{.Package}}.{{.Name}}},
727 var fuzzTargets = []testing.InternalFuzzTarget{
728 {{range .FuzzTargets}}
729 {"{{.Name}}", {{.Package}}.{{.Name}}},
733 var examples = []testing.InternalExample{
735 {"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
740 testdeps.ImportPath = {{.ImportPath | printf "%q"}}
745 // Only updated by init functions, so no need for atomicity.
747 coverCounters = make(map[string][]uint32)
748 coverBlocks = make(map[string][]testing.CoverBlock)
752 {{range $i, $p := .Cover.Vars}}
753 {{range $file, $cover := $p.Vars}}
754 coverRegisterFile({{printf "%q" $cover.File}}, _cover{{$i}}.{{$cover.Var}}.Count[:], _cover{{$i}}.{{$cover.Var}}.Pos[:], _cover{{$i}}.{{$cover.Var}}.NumStmt[:])
759 func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts []uint16) {
760 if 3*len(counter) != len(pos) || len(counter) != len(numStmts) {
761 panic("coverage: mismatched sizes")
763 if coverCounters[fileName] != nil {
764 // Already registered.
767 coverCounters[fileName] = counter
768 block := make([]testing.CoverBlock, len(counter))
769 for i := range counter {
770 block[i] = testing.CoverBlock{
772 Col0: uint16(pos[3*i+2]),
774 Col1: uint16(pos[3*i+2]>>16),
778 coverBlocks[fileName] = block
784 testing.RegisterCover(testing.Cover{
785 Mode: {{printf "%q" .Cover.Mode}},
786 Counters: coverCounters,
788 CoveredPackages: {{printf "%q" .Covered}},
791 m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, fuzzTargets, examples)
793 {{.Package}}.{{.Name}}(m)
794 os.Exit(int(reflect.ValueOf(m).Elem().FieldByName("exitCode").Int()))