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