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