github.com/bir3/gocompiler@v0.3.205/src/cmd/gocmd/internal/load/test.go (about) 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. 4 5 package load 6 7 import ( 8 "bytes" 9 "context" 10 "errors" 11 "fmt" 12 "github.com/bir3/gocompiler/src/go/ast" 13 "github.com/bir3/gocompiler/src/go/build" 14 "github.com/bir3/gocompiler/src/go/doc" 15 "github.com/bir3/gocompiler/src/go/parser" 16 "github.com/bir3/gocompiler/src/go/token" 17 "github.com/bir3/gocompiler/src/internal/lazytemplate" 18 "path/filepath" 19 "sort" 20 "strings" 21 "unicode" 22 "unicode/utf8" 23 24 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/cfg" 25 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/fsys" 26 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/str" 27 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/trace" 28 ) 29 30 var TestMainDeps = []string{ 31 // Dependencies for testmain. 32 "os", 33 "reflect", 34 "testing", 35 "testing/internal/testdeps", 36 } 37 38 type TestCover struct { 39 Mode string 40 Local bool 41 Pkgs []*Package 42 Paths []string 43 Vars []coverInfo 44 } 45 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} { 52 if p1 == nil { 53 // pxtest may be nil 54 continue 55 } 56 if p1.Error != nil { 57 err = p1.Error 58 break 59 } 60 if len(p1.DepsErrors) > 0 { 61 perr := p1.DepsErrors[0] 62 err = perr 63 break 64 } 65 } 66 if pmain.Error != nil || len(pmain.DepsErrors) > 0 { 67 pmain = nil 68 } 69 if ptest.Error != nil || len(ptest.DepsErrors) > 0 { 70 ptest = nil 71 } 72 if pxtest != nil && (pxtest.Error != nil || len(pxtest.DepsErrors) > 0) { 73 pxtest = nil 74 } 75 return pmain, ptest, pxtest, err 76 } 77 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. 82 // 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. 88 // 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. 93 // 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") 98 defer span.Done() 99 100 pre := newPreload() 101 defer pre.flush() 102 allImports := append([]string{}, p.TestImports...) 103 allImports = append(allImports, p.XTestImports...) 104 pre.preloadImports(ctx, opts, allImports, p.Internal.Build) 105 106 var ptestErr, pxtestErr *PackageError 107 var imports, ximports []*Package 108 var stk ImportStack 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"), 121 IsImportCycle: true, 122 } 123 } 124 p.TestImports[i] = p1.ImportPath 125 imports = append(imports, p1) 126 } 127 var err error 128 p.TestEmbedFiles, testEmbed, err = resolveEmbed(p.Dir, p.TestEmbedPatterns) 129 if err != nil && ptestErr == nil { 130 ptestErr = &PackageError{ 131 ImportStack: stk.Copy(), 132 Err: err, 133 } 134 embedErr := err.(*EmbedError) 135 ptestErr.setPos(p.Internal.Build.TestEmbedPatternPos[embedErr.Pattern]) 136 } 137 stk.Pop() 138 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 146 } else { 147 ximports = append(ximports, p1) 148 } 149 p.XTestImports[i] = p1.ImportPath 150 } 151 p.XTestEmbedFiles, xtestEmbed, err = resolveEmbed(p.Dir, p.XTestEmbedPatterns) 152 if err != nil && pxtestErr == nil { 153 pxtestErr = &PackageError{ 154 ImportStack: stk.Copy(), 155 Err: err, 156 } 157 embedErr := err.(*EmbedError) 158 pxtestErr.setPos(p.Internal.Build.XTestEmbedPatternPos[embedErr.Pattern]) 159 } 160 stk.Pop() 161 162 // Test package. 163 if len(p.TestGoFiles) > 0 || p.Name == "main" || cover != nil && cover.Local { 164 ptest = new(Package) 165 *ptest = *p 166 ptest.Error = ptestErr 167 ptest.ForTest = p.ImportPath 168 ptest.GoFiles = nil 169 ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...) 170 ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...) 171 ptest.Target = "" 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...) 194 } 195 for k, v := range p.Internal.Build.TestImportPos { 196 m[k] = append(m[k], v...) 197 } 198 ptest.Internal.Build.ImportPos = m 199 if testEmbed == nil && len(p.Internal.Embed) > 0 { 200 testEmbed = map[string][]string{} 201 } 202 for k, v := range p.Internal.Embed { 203 testEmbed[k] = v 204 } 205 ptest.Internal.Embed = testEmbed 206 ptest.EmbedFiles = str.StringList(p.EmbedFiles, p.TestEmbedFiles) 207 ptest.Internal.OrigImportPath = p.Internal.OrigImportPath 208 ptest.collectDeps() 209 } else { 210 ptest = p 211 } 212 213 // External test package. 214 if len(p.XTestGoFiles) > 0 { 215 pxtest = &Package{ 216 PackagePublic: PackagePublic{ 217 Name: p.Name + "_test", 218 ImportPath: p.ImportPath + "_test", 219 Root: p.Root, 220 Dir: p.Dir, 221 Goroot: p.Goroot, 222 GoFiles: p.XTestGoFiles, 223 Imports: p.XTestImports, 224 ForTest: p.ImportPath, 225 Module: p.Module, 226 Error: pxtestErr, 227 EmbedFiles: p.XTestEmbedFiles, 228 }, 229 Internal: PackageInternal{ 230 LocalPrefix: p.Internal.LocalPrefix, 231 Build: &build.Package{ 232 ImportPos: p.Internal.Build.XTestImportPos, 233 }, 234 Imports: ximports, 235 RawImports: rawXTestImports, 236 237 Asmflags: p.Internal.Asmflags, 238 Gcflags: p.Internal.Gcflags, 239 Ldflags: p.Internal.Ldflags, 240 Gccgoflags: p.Internal.Gccgoflags, 241 Embed: xtestEmbed, 242 OrigImportPath: p.Internal.OrigImportPath, 243 }, 244 } 245 if pxtestNeedsPtest { 246 pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest) 247 } 248 pxtest.collectDeps() 249 } 250 251 // Build main package. 252 pmain = &Package{ 253 PackagePublic: PackagePublic{ 254 Name: "main", 255 Dir: p.Dir, 256 GoFiles: []string{"_testmain.go"}, 257 ImportPath: p.ImportPath + ".test", 258 Root: p.Root, 259 Imports: str.StringList(TestMainDeps), 260 Module: p.Module, 261 }, 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, 270 }, 271 } 272 273 // The generated main also imports testing, regexp, and os. 274 // Also the linker introduces implicit dependencies reported by LinkerDeps. 275 stk.Push("testmain") 276 deps := TestMainDeps // cap==len, so safe for append 277 for _, d := range LinkerDeps(p) { 278 deps = append(deps, d) 279 } 280 for _, dep := range deps { 281 if dep == ptest.ImportPath { 282 pmain.Internal.Imports = append(pmain.Internal.Imports, ptest) 283 } else { 284 p1 := loadImport(ctx, opts, pre, dep, "", nil, &stk, nil, 0) 285 pmain.Internal.Imports = append(pmain.Internal.Imports, p1) 286 } 287 } 288 stk.Pop() 289 290 if cover != nil && cover.Pkgs != nil && !cfg.Experiment.CoverageRedesign { 291 // Add imports, but avoid duplicates. 292 seen := map[*Package]bool{p: true, ptest: true} 293 for _, p1 := range pmain.Internal.Imports { 294 seen[p1] = true 295 } 296 for _, p1 := range cover.Pkgs { 297 if seen[p1] { 298 // Don't add duplicate imports. 299 continue 300 } 301 seen[p1] = true 302 pmain.Internal.Imports = append(pmain.Internal.Imports, p1) 303 } 304 } 305 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...) 311 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) 319 } 320 t.Cover = cover 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) 324 t.ImportTest = true 325 } 326 if pxtest != nil { 327 pmain.Internal.Imports = append(pmain.Internal.Imports, pxtest) 328 pmain.Imports = append(pmain.Imports, pxtest.ImportPath) 329 t.ImportXtest = true 330 } 331 pmain.collectDeps() 332 333 // Sort and dedup pmain.Imports. 334 // Only matters for go list -test output. 335 sort.Strings(pmain.Imports) 336 w := 0 337 for _, path := range pmain.Imports { 338 if w == 0 || path != pmain.Imports[w-1] { 339 pmain.Imports[w] = path 340 w++ 341 } 342 } 343 pmain.Imports = pmain.Imports[:w] 344 pmain.Internal.RawImports = str.StringList(pmain.Imports) 345 346 // Replace pmain's transitive dependencies with test copies, as necessary. 347 recompileForTest(pmain, p, ptest, pxtest) 348 349 if cover != nil { 350 if cfg.Experiment.CoverageRedesign { 351 // Here ptest needs to inherit the proper coverage mode (since 352 // it contains p's Go files), whereas pmain contains only 353 // test harness code (don't want to instrument it, and 354 // we don't want coverage hooks in the pkg init). 355 ptest.Internal.CoverMode = p.Internal.CoverMode 356 pmain.Internal.CoverMode = "testmain" 357 } 358 // Should we apply coverage analysis locally, only for this 359 // package and only for this test? Yes, if -cover is on but 360 // -coverpkg has not specified a list of packages for global 361 // coverage. 362 if cover.Local { 363 ptest.Internal.CoverMode = cover.Mode 364 365 if !cfg.Experiment.CoverageRedesign { 366 var coverFiles []string 367 coverFiles = append(coverFiles, ptest.GoFiles...) 368 coverFiles = append(coverFiles, ptest.CgoFiles...) 369 ptest.Internal.CoverVars = DeclareCoverVars(ptest, coverFiles...) 370 } 371 } 372 373 if !cfg.Experiment.CoverageRedesign { 374 for _, cp := range pmain.Internal.Imports { 375 if len(cp.Internal.CoverVars) > 0 { 376 t.Cover.Vars = append(t.Cover.Vars, coverInfo{cp, cp.Internal.CoverVars}) 377 } 378 } 379 } 380 } 381 382 data, err := formatTestmain(t) 383 if err != nil && pmain.Error == nil { 384 pmain.Error = &PackageError{Err: err} 385 } 386 // Set TestmainGo even if it is empty: the presence of a TestmainGo 387 // indicates that this package is, in fact, a test main. 388 pmain.Internal.TestmainGo = &data 389 390 return pmain, ptest, pxtest 391 } 392 393 // importCycleStack returns an import stack from p to the package whose import 394 // path is target. 395 func importCycleStack(p *Package, target string) []string { 396 // importerOf maps each import path to its importer nearest to p. 397 importerOf := map[string]string{p.ImportPath: ""} 398 399 // q is a breadth-first queue of packages to search for target. 400 // Every package added to q has a corresponding entry in pathTo. 401 // 402 // We search breadth-first for two reasons: 403 // 404 // 1. We want to report the shortest cycle. 405 // 406 // 2. If p contains multiple cycles, the first cycle we encounter might not 407 // contain target. To ensure termination, we have to break all cycles 408 // other than the first. 409 q := []*Package{p} 410 411 for len(q) > 0 { 412 p := q[0] 413 q = q[1:] 414 if path := p.ImportPath; path == target { 415 var stk []string 416 for path != "" { 417 stk = append(stk, path) 418 path = importerOf[path] 419 } 420 return stk 421 } 422 for _, dep := range p.Internal.Imports { 423 if _, ok := importerOf[dep.ImportPath]; !ok { 424 importerOf[dep.ImportPath] = p.ImportPath 425 q = append(q, dep) 426 } 427 } 428 } 429 430 panic("lost path to cycle") 431 } 432 433 // recompileForTest copies and replaces certain packages in pmain's dependency 434 // graph. This is necessary for two reasons. First, if ptest is different than 435 // preal, packages that import the package under test should get ptest instead 436 // of preal. This is particularly important if pxtest depends on functionality 437 // exposed in test sources in ptest. Second, if there is a main package 438 // (other than pmain) anywhere, we need to set p.Internal.ForceLibrary and 439 // clear p.Internal.BuildInfo in the test copy to prevent link conflicts. 440 // This may happen if both -coverpkg and the command line patterns include 441 // multiple main packages. 442 func recompileForTest(pmain, preal, ptest, pxtest *Package) { 443 // The "test copy" of preal is ptest. 444 // For each package that depends on preal, make a "test copy" 445 // that depends on ptest. And so on, up the dependency tree. 446 testCopy := map[*Package]*Package{preal: ptest} 447 for _, p := range PackageList([]*Package{pmain}) { 448 if p == preal { 449 continue 450 } 451 // Copy on write. 452 didSplit := p == pmain || p == pxtest 453 split := func() { 454 if didSplit { 455 return 456 } 457 didSplit = true 458 if testCopy[p] != nil { 459 panic("recompileForTest loop") 460 } 461 p1 := new(Package) 462 testCopy[p] = p1 463 *p1 = *p 464 p1.ForTest = preal.ImportPath 465 p1.Internal.Imports = make([]*Package, len(p.Internal.Imports)) 466 copy(p1.Internal.Imports, p.Internal.Imports) 467 p1.Imports = make([]string, len(p.Imports)) 468 copy(p1.Imports, p.Imports) 469 p = p1 470 p.Target = "" 471 p.Internal.BuildInfo = "" 472 p.Internal.ForceLibrary = true 473 } 474 475 // Update p.Internal.Imports to use test copies. 476 for i, imp := range p.Internal.Imports { 477 if p1 := testCopy[imp]; p1 != nil && p1 != imp { 478 split() 479 p.Internal.Imports[i] = p1 480 } 481 } 482 483 // Force main packages the test imports to be built as libraries. 484 // Normal imports of main packages are forbidden by the package loader, 485 // but this can still happen if -coverpkg patterns include main packages: 486 // covered packages are imported by pmain. Linking multiple packages 487 // compiled with '-p main' causes duplicate symbol errors. 488 // See golang.org/issue/30907, golang.org/issue/34114. 489 if p.Name == "main" && p != pmain && p != ptest { 490 split() 491 } 492 } 493 } 494 495 // isTestFunc tells whether fn has the type of a testing function. arg 496 // specifies the parameter type we look for: B, M or T. 497 func isTestFunc(fn *ast.FuncDecl, arg string) bool { 498 if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 || 499 fn.Type.Params.List == nil || 500 len(fn.Type.Params.List) != 1 || 501 len(fn.Type.Params.List[0].Names) > 1 { 502 return false 503 } 504 ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr) 505 if !ok { 506 return false 507 } 508 // We can't easily check that the type is *testing.M 509 // because we don't know how testing has been imported, 510 // but at least check that it's *M or *something.M. 511 // Same applies for B and T. 512 if name, ok := ptr.X.(*ast.Ident); ok && name.Name == arg { 513 return true 514 } 515 if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == arg { 516 return true 517 } 518 return false 519 } 520 521 // isTest tells whether name looks like a test (or benchmark, according to prefix). 522 // It is a Test (say) if there is a character after Test that is not a lower-case letter. 523 // We don't want TesticularCancer. 524 func isTest(name, prefix string) bool { 525 if !strings.HasPrefix(name, prefix) { 526 return false 527 } 528 if len(name) == len(prefix) { // "Test" is ok 529 return true 530 } 531 rune, _ := utf8.DecodeRuneInString(name[len(prefix):]) 532 return !unicode.IsLower(rune) 533 } 534 535 type coverInfo struct { 536 Package *Package 537 Vars map[string]*CoverVar 538 } 539 540 // loadTestFuncs returns the testFuncs describing the tests that will be run. 541 // The returned testFuncs is always non-nil, even if an error occurred while 542 // processing test files. 543 func loadTestFuncs(ptest *Package) (*testFuncs, error) { 544 t := &testFuncs{ 545 Package: ptest, 546 } 547 var err error 548 for _, file := range ptest.TestGoFiles { 549 if lerr := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); lerr != nil && err == nil { 550 err = lerr 551 } 552 } 553 for _, file := range ptest.XTestGoFiles { 554 if lerr := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); lerr != nil && err == nil { 555 err = lerr 556 } 557 } 558 return t, err 559 } 560 561 // formatTestmain returns the content of the _testmain.go file for t. 562 func formatTestmain(t *testFuncs) ([]byte, error) { 563 var buf bytes.Buffer 564 tmpl := testmainTmpl 565 if cfg.Experiment.CoverageRedesign { 566 tmpl = testmainTmplNewCoverage 567 } 568 if err := tmpl.Execute(&buf, t); err != nil { 569 return nil, err 570 } 571 return buf.Bytes(), nil 572 } 573 574 type testFuncs struct { 575 Tests []testFunc 576 Benchmarks []testFunc 577 FuzzTargets []testFunc 578 Examples []testFunc 579 TestMain *testFunc 580 Package *Package 581 ImportTest bool 582 NeedTest bool 583 ImportXtest bool 584 NeedXtest bool 585 Cover *TestCover 586 } 587 588 // ImportPath returns the import path of the package being tested, if it is within GOPATH. 589 // This is printed by the testing package when running benchmarks. 590 func (t *testFuncs) ImportPath() string { 591 pkg := t.Package.ImportPath 592 if strings.HasPrefix(pkg, "_/") { 593 return "" 594 } 595 if pkg == "command-line-arguments" { 596 return "" 597 } 598 return pkg 599 } 600 601 // Covered returns a string describing which packages are being tested for coverage. 602 // If the covered package is the same as the tested package, it returns the empty string. 603 // Otherwise it is a comma-separated human-readable list of packages beginning with 604 // " in", ready for use in the coverage message. 605 func (t *testFuncs) Covered() string { 606 if t.Cover == nil || t.Cover.Paths == nil { 607 return "" 608 } 609 return " in " + strings.Join(t.Cover.Paths, ", ") 610 } 611 612 // Tested returns the name of the package being tested. 613 func (t *testFuncs) Tested() string { 614 return t.Package.Name 615 } 616 617 type testFunc struct { 618 Package string // imported package name (_test or _xtest) 619 Name string // function name 620 Output string // output, for examples 621 Unordered bool // output is allowed to be unordered. 622 } 623 624 var testFileSet = token.NewFileSet() 625 626 func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error { 627 // Pass in the overlaid source if we have an overlay for this file. 628 src, err := fsys.Open(filename) 629 if err != nil { 630 return err 631 } 632 defer src.Close() 633 f, err := parser.ParseFile(testFileSet, filename, src, parser.ParseComments|parser.SkipObjectResolution) 634 if err != nil { 635 return err 636 } 637 for _, d := range f.Decls { 638 n, ok := d.(*ast.FuncDecl) 639 if !ok { 640 continue 641 } 642 if n.Recv != nil { 643 continue 644 } 645 name := n.Name.String() 646 switch { 647 case name == "TestMain": 648 if isTestFunc(n, "T") { 649 t.Tests = append(t.Tests, testFunc{pkg, name, "", false}) 650 *doImport, *seen = true, true 651 continue 652 } 653 err := checkTestFunc(n, "M") 654 if err != nil { 655 return err 656 } 657 if t.TestMain != nil { 658 return errors.New("multiple definitions of TestMain") 659 } 660 t.TestMain = &testFunc{pkg, name, "", false} 661 *doImport, *seen = true, true 662 case isTest(name, "Test"): 663 err := checkTestFunc(n, "T") 664 if err != nil { 665 return err 666 } 667 t.Tests = append(t.Tests, testFunc{pkg, name, "", false}) 668 *doImport, *seen = true, true 669 case isTest(name, "Benchmark"): 670 err := checkTestFunc(n, "B") 671 if err != nil { 672 return err 673 } 674 t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, "", false}) 675 *doImport, *seen = true, true 676 case isTest(name, "Fuzz"): 677 err := checkTestFunc(n, "F") 678 if err != nil { 679 return err 680 } 681 t.FuzzTargets = append(t.FuzzTargets, testFunc{pkg, name, "", false}) 682 *doImport, *seen = true, true 683 } 684 } 685 ex := doc.Examples(f) 686 sort.Slice(ex, func(i, j int) bool { return ex[i].Order < ex[j].Order }) 687 for _, e := range ex { 688 *doImport = true // import test file whether executed or not 689 if e.Output == "" && !e.EmptyOutput { 690 // Don't run examples with no output. 691 continue 692 } 693 t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output, e.Unordered}) 694 *seen = true 695 } 696 return nil 697 } 698 699 func checkTestFunc(fn *ast.FuncDecl, arg string) error { 700 var why string 701 if !isTestFunc(fn, arg) { 702 why = fmt.Sprintf("must be: func %s(%s *testing.%s)", fn.Name.String(), strings.ToLower(arg), arg) 703 } 704 if fn.Type.TypeParams.NumFields() > 0 { 705 why = "test functions cannot have type parameters" 706 } 707 if why != "" { 708 pos := testFileSet.Position(fn.Pos()) 709 return fmt.Errorf("%s: wrong signature for %s, %s", pos, fn.Name.String(), why) 710 } 711 return nil 712 } 713 714 var testmainTmpl = lazytemplate.New("main", ` 715 // Code generated by 'go test'. DO NOT EDIT. 716 717 package main 718 719 import ( 720 "os" 721 {{if .TestMain}} 722 "reflect" 723 {{end}} 724 "testing" 725 "testing/internal/testdeps" 726 727 {{if .ImportTest}} 728 {{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}} 729 {{end}} 730 {{if .ImportXtest}} 731 {{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}} 732 {{end}} 733 {{if .Cover}} 734 {{range $i, $p := .Cover.Vars}} 735 _cover{{$i}} {{$p.Package.ImportPath | printf "%q"}} 736 {{end}} 737 {{end}} 738 ) 739 740 var tests = []testing.InternalTest{ 741 {{range .Tests}} 742 {"{{.Name}}", {{.Package}}.{{.Name}}}, 743 {{end}} 744 } 745 746 var benchmarks = []testing.InternalBenchmark{ 747 {{range .Benchmarks}} 748 {"{{.Name}}", {{.Package}}.{{.Name}}}, 749 {{end}} 750 } 751 752 var fuzzTargets = []testing.InternalFuzzTarget{ 753 {{range .FuzzTargets}} 754 {"{{.Name}}", {{.Package}}.{{.Name}}}, 755 {{end}} 756 } 757 758 var examples = []testing.InternalExample{ 759 {{range .Examples}} 760 {"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}}, 761 {{end}} 762 } 763 764 func init() { 765 testdeps.ImportPath = {{.ImportPath | printf "%q"}} 766 } 767 768 {{if .Cover}} 769 770 // Only updated by init functions, so no need for atomicity. 771 var ( 772 coverCounters = make(map[string][]uint32) 773 coverBlocks = make(map[string][]testing.CoverBlock) 774 ) 775 776 func init() { 777 {{range $i, $p := .Cover.Vars}} 778 {{range $file, $cover := $p.Vars}} 779 coverRegisterFile({{printf "%q" $cover.File}}, _cover{{$i}}.{{$cover.Var}}.Count[:], _cover{{$i}}.{{$cover.Var}}.Pos[:], _cover{{$i}}.{{$cover.Var}}.NumStmt[:]) 780 {{end}} 781 {{end}} 782 } 783 784 func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts []uint16) { 785 if 3*len(counter) != len(pos) || len(counter) != len(numStmts) { 786 panic("coverage: mismatched sizes") 787 } 788 if coverCounters[fileName] != nil { 789 // Already registered. 790 return 791 } 792 coverCounters[fileName] = counter 793 block := make([]testing.CoverBlock, len(counter)) 794 for i := range counter { 795 block[i] = testing.CoverBlock{ 796 Line0: pos[3*i+0], 797 Col0: uint16(pos[3*i+2]), 798 Line1: pos[3*i+1], 799 Col1: uint16(pos[3*i+2]>>16), 800 Stmts: numStmts[i], 801 } 802 } 803 coverBlocks[fileName] = block 804 } 805 {{end}} 806 807 func main() { 808 {{if .Cover}} 809 testing.RegisterCover(testing.Cover{ 810 Mode: {{printf "%q" .Cover.Mode}}, 811 Counters: coverCounters, 812 Blocks: coverBlocks, 813 CoveredPackages: {{printf "%q" .Covered}}, 814 }) 815 {{end}} 816 m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, fuzzTargets, examples) 817 {{with .TestMain}} 818 {{.Package}}.{{.Name}}(m) 819 os.Exit(int(reflect.ValueOf(m).Elem().FieldByName("exitCode").Int())) 820 {{else}} 821 os.Exit(m.Run()) 822 {{end}} 823 } 824 825 `) 826 827 var testmainTmplNewCoverage = lazytemplate.New("main", ` 828 // Code generated by 'go test'. DO NOT EDIT. 829 830 package main 831 832 import ( 833 "os" 834 {{if .Cover}} 835 _ "unsafe" 836 {{end}} 837 {{if .TestMain}} 838 "reflect" 839 {{end}} 840 "testing" 841 "testing/internal/testdeps" 842 843 {{if .ImportTest}} 844 {{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}} 845 {{end}} 846 {{if .ImportXtest}} 847 {{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}} 848 {{end}} 849 ) 850 851 var tests = []testing.InternalTest{ 852 {{range .Tests}} 853 {"{{.Name}}", {{.Package}}.{{.Name}}}, 854 {{end}} 855 } 856 857 var benchmarks = []testing.InternalBenchmark{ 858 {{range .Benchmarks}} 859 {"{{.Name}}", {{.Package}}.{{.Name}}}, 860 {{end}} 861 } 862 863 var fuzzTargets = []testing.InternalFuzzTarget{ 864 {{range .FuzzTargets}} 865 {"{{.Name}}", {{.Package}}.{{.Name}}}, 866 {{end}} 867 } 868 869 var examples = []testing.InternalExample{ 870 {{range .Examples}} 871 {"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}}, 872 {{end}} 873 } 874 875 func init() { 876 testdeps.ImportPath = {{.ImportPath | printf "%q"}} 877 } 878 879 {{if .Cover}} 880 881 //go:linkname runtime_coverage_processCoverTestDir runtime/coverage.processCoverTestDir 882 func runtime_coverage_processCoverTestDir(dir string, cfile string, cmode string, cpkgs string) error 883 884 //go:linkname testing_registerCover2 testing.registerCover2 885 func testing_registerCover2(mode string, tearDown func(coverprofile string, gocoverdir string) (string, error)) 886 887 //go:linkname runtime_coverage_markProfileEmitted runtime/coverage.markProfileEmitted 888 func runtime_coverage_markProfileEmitted(val bool) 889 890 func coverTearDown(coverprofile string, gocoverdir string) (string, error) { 891 var err error 892 if gocoverdir == "" { 893 gocoverdir, err = os.MkdirTemp("", "gocoverdir") 894 if err != nil { 895 return "error setting GOCOVERDIR: bad os.MkdirTemp return", err 896 } 897 defer os.RemoveAll(gocoverdir) 898 } 899 runtime_coverage_markProfileEmitted(true) 900 cmode := {{printf "%q" .Cover.Mode}} 901 if err := runtime_coverage_processCoverTestDir(gocoverdir, coverprofile, cmode, {{printf "%q" .Covered}}); err != nil { 902 return "error generating coverage report", err 903 } 904 return "", nil 905 } 906 {{end}} 907 908 func main() { 909 {{if .Cover}} 910 testing_registerCover2({{printf "%q" .Cover.Mode}}, coverTearDown) 911 {{end}} 912 m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, fuzzTargets, examples) 913 {{with .TestMain}} 914 {{.Package}}.{{.Name}}(m) 915 os.Exit(int(reflect.ValueOf(m).Elem().FieldByName("exitCode").Int())) 916 {{else}} 917 os.Exit(m.Run()) 918 {{end}} 919 } 920 921 `)