github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/src/cmd/go/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 "cmd/go/internal/base" 10 "cmd/go/internal/str" 11 "errors" 12 "fmt" 13 "go/ast" 14 "go/build" 15 "go/doc" 16 "go/parser" 17 "go/token" 18 "path/filepath" 19 "sort" 20 "strings" 21 "text/template" 22 "unicode" 23 "unicode/utf8" 24 ) 25 26 var TestMainDeps = []string{ 27 // Dependencies for testmain. 28 "os", 29 "testing", 30 "testing/internal/testdeps", 31 } 32 33 type TestCover struct { 34 Mode string 35 Local bool 36 Pkgs []*Package 37 Paths []string 38 Vars []coverInfo 39 DeclVars func(*Package, ...string) map[string]*CoverVar 40 } 41 42 // TestPackagesFor returns three packages: 43 // - ptest, the package p compiled with added "package p" test files. 44 // - pxtest, the result of compiling any "package p_test" (external) test files. 45 // - pmain, the package main corresponding to the test binary (running tests in ptest and pxtest). 46 // 47 // If the package has no "package p_test" test files, pxtest will be nil. 48 // If the non-test compilation of package p can be reused 49 // (for example, if there are no "package p" test files and 50 // package p need not be instrumented for coverage or any other reason), 51 // then the returned ptest == p. 52 // 53 // The caller is expected to have checked that len(p.TestGoFiles)+len(p.XTestGoFiles) > 0, 54 // or else there's no point in any of this. 55 func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Package, err error) { 56 var imports, ximports []*Package 57 var stk ImportStack 58 stk.Push(p.ImportPath + " (test)") 59 rawTestImports := str.StringList(p.TestImports) 60 for i, path := range p.TestImports { 61 p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport) 62 if p1.Error != nil { 63 return nil, nil, nil, p1.Error 64 } 65 if len(p1.DepsErrors) > 0 { 66 err := p1.DepsErrors[0] 67 err.Pos = "" // show full import stack 68 return nil, nil, nil, err 69 } 70 if str.Contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath { 71 // Same error that loadPackage returns (via reusePackage) in pkg.go. 72 // Can't change that code, because that code is only for loading the 73 // non-test copy of a package. 74 err := &PackageError{ 75 ImportStack: testImportStack(stk[0], p1, p.ImportPath), 76 Err: "import cycle not allowed in test", 77 IsImportCycle: true, 78 } 79 return nil, nil, nil, err 80 } 81 p.TestImports[i] = p1.ImportPath 82 imports = append(imports, p1) 83 } 84 stk.Pop() 85 stk.Push(p.ImportPath + "_test") 86 pxtestNeedsPtest := false 87 rawXTestImports := str.StringList(p.XTestImports) 88 for i, path := range p.XTestImports { 89 p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], ResolveImport) 90 if p1.Error != nil { 91 return nil, nil, nil, p1.Error 92 } 93 if len(p1.DepsErrors) > 0 { 94 err := p1.DepsErrors[0] 95 err.Pos = "" // show full import stack 96 return nil, nil, nil, err 97 } 98 if p1.ImportPath == p.ImportPath { 99 pxtestNeedsPtest = true 100 } else { 101 ximports = append(ximports, p1) 102 } 103 p.XTestImports[i] = p1.ImportPath 104 } 105 stk.Pop() 106 107 // Test package. 108 if len(p.TestGoFiles) > 0 || p.Name == "main" || cover != nil && cover.Local { 109 ptest = new(Package) 110 *ptest = *p 111 ptest.ForTest = p.ImportPath 112 ptest.GoFiles = nil 113 ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...) 114 ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...) 115 ptest.Target = "" 116 // Note: The preparation of the vet config requires that common 117 // indexes in ptest.Imports and ptest.Internal.RawImports 118 // all line up (but RawImports can be shorter than the others). 119 // That is, for 0 ≤ i < len(RawImports), 120 // RawImports[i] is the import string in the program text, and 121 // Imports[i] is the expanded import string (vendoring applied or relative path expanded away). 122 // Any implicitly added imports appear in Imports and Internal.Imports 123 // but not RawImports (because they were not in the source code). 124 // We insert TestImports, imports, and rawTestImports at the start of 125 // these lists to preserve the alignment. 126 // Note that p.Internal.Imports may not be aligned with p.Imports/p.Internal.RawImports, 127 // but we insert at the beginning there too just for consistency. 128 ptest.Imports = str.StringList(p.TestImports, p.Imports) 129 ptest.Internal.Imports = append(imports, p.Internal.Imports...) 130 ptest.Internal.RawImports = str.StringList(rawTestImports, p.Internal.RawImports) 131 ptest.Internal.ForceLibrary = true 132 ptest.Internal.BuildInfo = "" 133 ptest.Internal.Build = new(build.Package) 134 *ptest.Internal.Build = *p.Internal.Build 135 m := map[string][]token.Position{} 136 for k, v := range p.Internal.Build.ImportPos { 137 m[k] = append(m[k], v...) 138 } 139 for k, v := range p.Internal.Build.TestImportPos { 140 m[k] = append(m[k], v...) 141 } 142 ptest.Internal.Build.ImportPos = m 143 } else { 144 ptest = p 145 } 146 147 // External test package. 148 if len(p.XTestGoFiles) > 0 { 149 pxtest = &Package{ 150 PackagePublic: PackagePublic{ 151 Name: p.Name + "_test", 152 ImportPath: p.ImportPath + "_test", 153 Root: p.Root, 154 Dir: p.Dir, 155 GoFiles: p.XTestGoFiles, 156 Imports: p.XTestImports, 157 ForTest: p.ImportPath, 158 }, 159 Internal: PackageInternal{ 160 LocalPrefix: p.Internal.LocalPrefix, 161 Build: &build.Package{ 162 ImportPos: p.Internal.Build.XTestImportPos, 163 }, 164 Imports: ximports, 165 RawImports: rawXTestImports, 166 167 Asmflags: p.Internal.Asmflags, 168 Gcflags: p.Internal.Gcflags, 169 Ldflags: p.Internal.Ldflags, 170 Gccgoflags: p.Internal.Gccgoflags, 171 }, 172 } 173 if pxtestNeedsPtest { 174 pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest) 175 } 176 } 177 178 // Build main package. 179 pmain = &Package{ 180 PackagePublic: PackagePublic{ 181 Name: "main", 182 Dir: p.Dir, 183 GoFiles: []string{"_testmain.go"}, 184 ImportPath: p.ImportPath + ".test", 185 Root: p.Root, 186 Imports: str.StringList(TestMainDeps), 187 }, 188 Internal: PackageInternal{ 189 Build: &build.Package{Name: "main"}, 190 BuildInfo: p.Internal.BuildInfo, 191 Asmflags: p.Internal.Asmflags, 192 Gcflags: p.Internal.Gcflags, 193 Ldflags: p.Internal.Ldflags, 194 Gccgoflags: p.Internal.Gccgoflags, 195 }, 196 } 197 198 // The generated main also imports testing, regexp, and os. 199 // Also the linker introduces implicit dependencies reported by LinkerDeps. 200 stk.Push("testmain") 201 deps := TestMainDeps // cap==len, so safe for append 202 for _, d := range LinkerDeps(p) { 203 deps = append(deps, d) 204 } 205 for _, dep := range deps { 206 if dep == ptest.ImportPath { 207 pmain.Internal.Imports = append(pmain.Internal.Imports, ptest) 208 } else { 209 p1 := LoadImport(dep, "", nil, &stk, nil, 0) 210 if p1.Error != nil { 211 return nil, nil, nil, p1.Error 212 } 213 pmain.Internal.Imports = append(pmain.Internal.Imports, p1) 214 } 215 } 216 stk.Pop() 217 218 if cover != nil && cover.Pkgs != nil { 219 // Add imports, but avoid duplicates. 220 seen := map[*Package]bool{p: true, ptest: true} 221 for _, p1 := range pmain.Internal.Imports { 222 seen[p1] = true 223 } 224 for _, p1 := range cover.Pkgs { 225 if !seen[p1] { 226 seen[p1] = true 227 pmain.Internal.Imports = append(pmain.Internal.Imports, p1) 228 } 229 } 230 } 231 232 allTestImports := make([]*Package, 0, len(pmain.Internal.Imports)+len(imports)+len(ximports)) 233 allTestImports = append(allTestImports, pmain.Internal.Imports...) 234 allTestImports = append(allTestImports, imports...) 235 allTestImports = append(allTestImports, ximports...) 236 setToolFlags(allTestImports...) 237 238 // Do initial scan for metadata needed for writing _testmain.go 239 // Use that metadata to update the list of imports for package main. 240 // The list of imports is used by recompileForTest and by the loop 241 // afterward that gathers t.Cover information. 242 t, err := loadTestFuncs(ptest) 243 if err != nil { 244 return nil, nil, nil, err 245 } 246 t.Cover = cover 247 if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 { 248 pmain.Internal.Imports = append(pmain.Internal.Imports, ptest) 249 pmain.Imports = append(pmain.Imports, ptest.ImportPath) 250 t.ImportTest = true 251 } 252 if pxtest != nil { 253 pmain.Internal.Imports = append(pmain.Internal.Imports, pxtest) 254 pmain.Imports = append(pmain.Imports, pxtest.ImportPath) 255 t.ImportXtest = true 256 } 257 258 // Sort and dedup pmain.Imports. 259 // Only matters for go list -test output. 260 sort.Strings(pmain.Imports) 261 w := 0 262 for _, path := range pmain.Imports { 263 if w == 0 || path != pmain.Imports[w-1] { 264 pmain.Imports[w] = path 265 w++ 266 } 267 } 268 pmain.Imports = pmain.Imports[:w] 269 pmain.Internal.RawImports = str.StringList(pmain.Imports) 270 271 // Replace pmain's transitive dependencies with test copies, as necessary. 272 recompileForTest(pmain, p, ptest, pxtest) 273 274 // Should we apply coverage analysis locally, 275 // only for this package and only for this test? 276 // Yes, if -cover is on but -coverpkg has not specified 277 // a list of packages for global coverage. 278 if cover != nil && cover.Local { 279 ptest.Internal.CoverMode = cover.Mode 280 var coverFiles []string 281 coverFiles = append(coverFiles, ptest.GoFiles...) 282 coverFiles = append(coverFiles, ptest.CgoFiles...) 283 ptest.Internal.CoverVars = cover.DeclVars(ptest, coverFiles...) 284 } 285 286 for _, cp := range pmain.Internal.Imports { 287 if len(cp.Internal.CoverVars) > 0 { 288 t.Cover.Vars = append(t.Cover.Vars, coverInfo{cp, cp.Internal.CoverVars}) 289 } 290 } 291 292 data, err := formatTestmain(t) 293 if err != nil { 294 return nil, nil, nil, err 295 } 296 pmain.Internal.TestmainGo = &data 297 298 return pmain, ptest, pxtest, nil 299 } 300 301 func testImportStack(top string, p *Package, target string) []string { 302 stk := []string{top, p.ImportPath} 303 Search: 304 for p.ImportPath != target { 305 for _, p1 := range p.Internal.Imports { 306 if p1.ImportPath == target || str.Contains(p1.Deps, target) { 307 stk = append(stk, p1.ImportPath) 308 p = p1 309 continue Search 310 } 311 } 312 // Can't happen, but in case it does... 313 stk = append(stk, "<lost path to cycle>") 314 break 315 } 316 return stk 317 } 318 319 // recompileForTest copies and replaces certain packages in pmain's dependency 320 // graph. This is necessary for two reasons. First, if ptest is different than 321 // preal, packages that import the package under test should get ptest instead 322 // of preal. This is particularly important if pxtest depends on functionality 323 // exposed in test sources in ptest. Second, if there is a main package 324 // (other than pmain) anywhere, we need to set p.Internal.ForceLibrary and 325 // clear p.Internal.BuildInfo in the test copy to prevent link conflicts. 326 // This may happen if both -coverpkg and the command line patterns include 327 // multiple main packages. 328 func recompileForTest(pmain, preal, ptest, pxtest *Package) { 329 // The "test copy" of preal is ptest. 330 // For each package that depends on preal, make a "test copy" 331 // that depends on ptest. And so on, up the dependency tree. 332 testCopy := map[*Package]*Package{preal: ptest} 333 for _, p := range PackageList([]*Package{pmain}) { 334 if p == preal { 335 continue 336 } 337 // Copy on write. 338 didSplit := p == pmain || p == pxtest 339 split := func() { 340 if didSplit { 341 return 342 } 343 didSplit = true 344 if testCopy[p] != nil { 345 panic("recompileForTest loop") 346 } 347 p1 := new(Package) 348 testCopy[p] = p1 349 *p1 = *p 350 p1.ForTest = preal.ImportPath 351 p1.Internal.Imports = make([]*Package, len(p.Internal.Imports)) 352 copy(p1.Internal.Imports, p.Internal.Imports) 353 p1.Imports = make([]string, len(p.Imports)) 354 copy(p1.Imports, p.Imports) 355 p = p1 356 p.Target = "" 357 p.Internal.BuildInfo = "" 358 p.Internal.ForceLibrary = true 359 } 360 361 // Update p.Internal.Imports to use test copies. 362 for i, imp := range p.Internal.Imports { 363 if p1 := testCopy[imp]; p1 != nil && p1 != imp { 364 split() 365 p.Internal.Imports[i] = p1 366 } 367 } 368 369 // Don't compile build info from a main package. This can happen 370 // if -coverpkg patterns include main packages, since those packages 371 // are imported by pmain. See golang.org/issue/30907. 372 if p.Internal.BuildInfo != "" && p != pmain { 373 split() 374 } 375 } 376 } 377 378 // isTestFunc tells whether fn has the type of a testing function. arg 379 // specifies the parameter type we look for: B, M or T. 380 func isTestFunc(fn *ast.FuncDecl, arg string) bool { 381 if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 || 382 fn.Type.Params.List == nil || 383 len(fn.Type.Params.List) != 1 || 384 len(fn.Type.Params.List[0].Names) > 1 { 385 return false 386 } 387 ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr) 388 if !ok { 389 return false 390 } 391 // We can't easily check that the type is *testing.M 392 // because we don't know how testing has been imported, 393 // but at least check that it's *M or *something.M. 394 // Same applies for B and T. 395 if name, ok := ptr.X.(*ast.Ident); ok && name.Name == arg { 396 return true 397 } 398 if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == arg { 399 return true 400 } 401 return false 402 } 403 404 // isTest tells whether name looks like a test (or benchmark, according to prefix). 405 // It is a Test (say) if there is a character after Test that is not a lower-case letter. 406 // We don't want TesticularCancer. 407 func isTest(name, prefix string) bool { 408 if !strings.HasPrefix(name, prefix) { 409 return false 410 } 411 if len(name) == len(prefix) { // "Test" is ok 412 return true 413 } 414 rune, _ := utf8.DecodeRuneInString(name[len(prefix):]) 415 return !unicode.IsLower(rune) 416 } 417 418 type coverInfo struct { 419 Package *Package 420 Vars map[string]*CoverVar 421 } 422 423 // loadTestFuncs returns the testFuncs describing the tests that will be run. 424 func loadTestFuncs(ptest *Package) (*testFuncs, error) { 425 t := &testFuncs{ 426 Package: ptest, 427 } 428 for _, file := range ptest.TestGoFiles { 429 if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); err != nil { 430 return nil, err 431 } 432 } 433 for _, file := range ptest.XTestGoFiles { 434 if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); err != nil { 435 return nil, err 436 } 437 } 438 return t, nil 439 } 440 441 // formatTestmain returns the content of the _testmain.go file for t. 442 func formatTestmain(t *testFuncs) ([]byte, error) { 443 var buf bytes.Buffer 444 if err := testmainTmpl.Execute(&buf, t); err != nil { 445 return nil, err 446 } 447 return buf.Bytes(), nil 448 } 449 450 type testFuncs struct { 451 Tests []testFunc 452 Benchmarks []testFunc 453 Examples []testFunc 454 TestMain *testFunc 455 Package *Package 456 ImportTest bool 457 NeedTest bool 458 ImportXtest bool 459 NeedXtest bool 460 Cover *TestCover 461 } 462 463 // ImportPath returns the import path of the package being tested, if it is within GOPATH. 464 // This is printed by the testing package when running benchmarks. 465 func (t *testFuncs) ImportPath() string { 466 pkg := t.Package.ImportPath 467 if strings.HasPrefix(pkg, "_/") { 468 return "" 469 } 470 if pkg == "command-line-arguments" { 471 return "" 472 } 473 return pkg 474 } 475 476 // Covered returns a string describing which packages are being tested for coverage. 477 // If the covered package is the same as the tested package, it returns the empty string. 478 // Otherwise it is a comma-separated human-readable list of packages beginning with 479 // " in", ready for use in the coverage message. 480 func (t *testFuncs) Covered() string { 481 if t.Cover == nil || t.Cover.Paths == nil { 482 return "" 483 } 484 return " in " + strings.Join(t.Cover.Paths, ", ") 485 } 486 487 // Tested returns the name of the package being tested. 488 func (t *testFuncs) Tested() string { 489 return t.Package.Name 490 } 491 492 type testFunc struct { 493 Package string // imported package name (_test or _xtest) 494 Name string // function name 495 Output string // output, for examples 496 Unordered bool // output is allowed to be unordered. 497 } 498 499 var testFileSet = token.NewFileSet() 500 501 func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error { 502 f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments) 503 if err != nil { 504 return base.ExpandScanner(err) 505 } 506 for _, d := range f.Decls { 507 n, ok := d.(*ast.FuncDecl) 508 if !ok { 509 continue 510 } 511 if n.Recv != nil { 512 continue 513 } 514 name := n.Name.String() 515 switch { 516 case name == "TestMain": 517 if isTestFunc(n, "T") { 518 t.Tests = append(t.Tests, testFunc{pkg, name, "", false}) 519 *doImport, *seen = true, true 520 continue 521 } 522 err := checkTestFunc(n, "M") 523 if err != nil { 524 return err 525 } 526 if t.TestMain != nil { 527 return errors.New("multiple definitions of TestMain") 528 } 529 t.TestMain = &testFunc{pkg, name, "", false} 530 *doImport, *seen = true, true 531 case isTest(name, "Test"): 532 err := checkTestFunc(n, "T") 533 if err != nil { 534 return err 535 } 536 t.Tests = append(t.Tests, testFunc{pkg, name, "", false}) 537 *doImport, *seen = true, true 538 case isTest(name, "Benchmark"): 539 err := checkTestFunc(n, "B") 540 if err != nil { 541 return err 542 } 543 t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, "", false}) 544 *doImport, *seen = true, true 545 } 546 } 547 ex := doc.Examples(f) 548 sort.Slice(ex, func(i, j int) bool { return ex[i].Order < ex[j].Order }) 549 for _, e := range ex { 550 *doImport = true // import test file whether executed or not 551 if e.Output == "" && !e.EmptyOutput { 552 // Don't run examples with no output. 553 continue 554 } 555 t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output, e.Unordered}) 556 *seen = true 557 } 558 return nil 559 } 560 561 func checkTestFunc(fn *ast.FuncDecl, arg string) error { 562 if !isTestFunc(fn, arg) { 563 name := fn.Name.String() 564 pos := testFileSet.Position(fn.Pos()) 565 return fmt.Errorf("%s: wrong signature for %s, must be: func %s(%s *testing.%s)", pos, name, name, strings.ToLower(arg), arg) 566 } 567 return nil 568 } 569 570 var testmainTmpl = template.Must(template.New("main").Parse(` 571 package main 572 573 import ( 574 {{if not .TestMain}} 575 "os" 576 {{end}} 577 "testing" 578 "testing/internal/testdeps" 579 580 {{if .ImportTest}} 581 {{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}} 582 {{end}} 583 {{if .ImportXtest}} 584 {{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}} 585 {{end}} 586 {{if .Cover}} 587 {{range $i, $p := .Cover.Vars}} 588 _cover{{$i}} {{$p.Package.ImportPath | printf "%q"}} 589 {{end}} 590 {{end}} 591 ) 592 593 var tests = []testing.InternalTest{ 594 {{range .Tests}} 595 {"{{.Name}}", {{.Package}}.{{.Name}}}, 596 {{end}} 597 } 598 599 var benchmarks = []testing.InternalBenchmark{ 600 {{range .Benchmarks}} 601 {"{{.Name}}", {{.Package}}.{{.Name}}}, 602 {{end}} 603 } 604 605 var examples = []testing.InternalExample{ 606 {{range .Examples}} 607 {"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}}, 608 {{end}} 609 } 610 611 func init() { 612 testdeps.ImportPath = {{.ImportPath | printf "%q"}} 613 } 614 615 {{if .Cover}} 616 617 // Only updated by init functions, so no need for atomicity. 618 var ( 619 coverCounters = make(map[string][]uint32) 620 coverBlocks = make(map[string][]testing.CoverBlock) 621 ) 622 623 func init() { 624 {{range $i, $p := .Cover.Vars}} 625 {{range $file, $cover := $p.Vars}} 626 coverRegisterFile({{printf "%q" $cover.File}}, _cover{{$i}}.{{$cover.Var}}.Count[:], _cover{{$i}}.{{$cover.Var}}.Pos[:], _cover{{$i}}.{{$cover.Var}}.NumStmt[:]) 627 {{end}} 628 {{end}} 629 } 630 631 func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts []uint16) { 632 if 3*len(counter) != len(pos) || len(counter) != len(numStmts) { 633 panic("coverage: mismatched sizes") 634 } 635 if coverCounters[fileName] != nil { 636 // Already registered. 637 return 638 } 639 coverCounters[fileName] = counter 640 block := make([]testing.CoverBlock, len(counter)) 641 for i := range counter { 642 block[i] = testing.CoverBlock{ 643 Line0: pos[3*i+0], 644 Col0: uint16(pos[3*i+2]), 645 Line1: pos[3*i+1], 646 Col1: uint16(pos[3*i+2]>>16), 647 Stmts: numStmts[i], 648 } 649 } 650 coverBlocks[fileName] = block 651 } 652 {{end}} 653 654 func main() { 655 {{if .Cover}} 656 testing.RegisterCover(testing.Cover{ 657 Mode: {{printf "%q" .Cover.Mode}}, 658 Counters: coverCounters, 659 Blocks: coverBlocks, 660 CoveredPackages: {{printf "%q" .Covered}}, 661 }) 662 {{end}} 663 m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, examples) 664 {{with .TestMain}} 665 {{.Package}}.{{.Name}}(m) 666 {{else}} 667 os.Exit(m.Run()) 668 {{end}} 669 } 670 671 `))