1
2
3
4
5 package load
6
7 import (
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
31 var TestMainDeps = []string{
32
33 "os",
34 "reflect",
35 "testing",
36 "testing/internal/testdeps",
37 }
38
39 type TestCover struct {
40 Mode string
41 Local bool
42 Pkgs []*Package
43 Paths []string
44 Vars []coverInfo
45 }
46
47
48
49
50 func 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
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 func 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
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
186
187
188
189
190
191
192
193
194
195
196
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
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
268 ldflags := append(p.Internal.Ldflags, "-X", "testing.testBinary=1")
269 gccgoflags := append(p.Internal.Gccgoflags, "-Wl,--defsym,testing.gccgoTestBinary=1")
270
271
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
298
299 stk.Push("testmain")
300 deps := TestMainDeps
301 ldDeps, err := LinkerDeps(p)
302 if err != nil && pmain.Error == nil {
303 pmain.Error = &PackageError{Err: err}
304 }
305 for _, d := range ldDeps {
306 deps = append(deps, d)
307 }
308 for _, dep := range deps {
309 if dep == ptest.ImportPath {
310 pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
311 } else {
312 p1, err := loadImport(ctx, opts, pre, dep, "", nil, &stk, nil, 0)
313 if err != nil && pmain.Error == nil {
314 pmain.Error = err
315 pmain.Incomplete = true
316 }
317 pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
318 }
319 }
320 stk.Pop()
321
322 parallelizablePart := func() {
323 if cover != nil && cover.Pkgs != nil && !cfg.Experiment.CoverageRedesign {
324
325 seen := map[*Package]bool{p: true, ptest: true}
326 for _, p1 := range pmain.Internal.Imports {
327 seen[p1] = true
328 }
329 for _, p1 := range cover.Pkgs {
330 if seen[p1] {
331
332 continue
333 }
334 seen[p1] = true
335 pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
336 }
337 }
338
339 allTestImports := make([]*Package, 0, len(pmain.Internal.Imports)+len(imports)+len(ximports))
340 allTestImports = append(allTestImports, pmain.Internal.Imports...)
341 allTestImports = append(allTestImports, imports...)
342 allTestImports = append(allTestImports, ximports...)
343 setToolFlags(allTestImports...)
344
345
346
347
348
349 t, err := loadTestFuncs(p)
350 if err != nil && pmain.Error == nil {
351 pmain.setLoadPackageDataError(err, p.ImportPath, &stk, nil)
352 }
353 t.Cover = cover
354 if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
355 pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
356 pmain.Imports = append(pmain.Imports, ptest.ImportPath)
357 t.ImportTest = true
358 }
359 if pxtest != nil {
360 pmain.Internal.Imports = append(pmain.Internal.Imports, pxtest)
361 pmain.Imports = append(pmain.Imports, pxtest.ImportPath)
362 t.ImportXtest = true
363 }
364
365
366
367 sort.Strings(pmain.Imports)
368 w := 0
369 for _, path := range pmain.Imports {
370 if w == 0 || path != pmain.Imports[w-1] {
371 pmain.Imports[w] = path
372 w++
373 }
374 }
375 pmain.Imports = pmain.Imports[:w]
376 pmain.Internal.RawImports = str.StringList(pmain.Imports)
377
378
379 cycleErr := recompileForTest(pmain, p, ptest, pxtest)
380 if cycleErr != nil {
381 ptest.Error = cycleErr
382 ptest.Incomplete = true
383 }
384
385 if cover != nil {
386 if cfg.Experiment.CoverageRedesign {
387
388
389
390
391 ptest.Internal.Cover.Mode = p.Internal.Cover.Mode
392 pmain.Internal.Cover.Mode = "testmain"
393 }
394
395
396
397
398 if cover.Local {
399 ptest.Internal.Cover.Mode = cover.Mode
400
401 if !cfg.Experiment.CoverageRedesign {
402 var coverFiles []string
403 coverFiles = append(coverFiles, ptest.GoFiles...)
404 coverFiles = append(coverFiles, ptest.CgoFiles...)
405 ptest.Internal.CoverVars = DeclareCoverVars(ptest, coverFiles...)
406 }
407 }
408
409 if !cfg.Experiment.CoverageRedesign {
410 for _, cp := range pmain.Internal.Imports {
411 if len(cp.Internal.CoverVars) > 0 {
412 t.Cover.Vars = append(t.Cover.Vars, coverInfo{cp, cp.Internal.CoverVars})
413 }
414 }
415 }
416 }
417
418 data, err := formatTestmain(t)
419 if err != nil && pmain.Error == nil {
420 pmain.Error = &PackageError{Err: err}
421 pmain.Incomplete = true
422 }
423
424
425 pmain.Internal.TestmainGo = &data
426 }
427
428 if done != nil {
429 go func() {
430 parallelizablePart()
431 done()
432 }()
433 } else {
434 parallelizablePart()
435 }
436
437 return pmain, ptest, pxtest
438 }
439
440
441
442
443
444
445
446
447
448
449 func recompileForTest(pmain, preal, ptest, pxtest *Package) *PackageError {
450
451
452
453 testCopy := map[*Package]*Package{preal: ptest}
454 for _, p := range PackageList([]*Package{pmain}) {
455 if p == preal {
456 continue
457 }
458
459 didSplit := p == pmain || p == pxtest || p == ptest
460 split := func() {
461 if didSplit {
462 return
463 }
464 didSplit = true
465 if testCopy[p] != nil {
466 panic("recompileForTest loop")
467 }
468 p1 := new(Package)
469 testCopy[p] = p1
470 *p1 = *p
471 p1.ForTest = preal.ImportPath
472 p1.Internal.Imports = make([]*Package, len(p.Internal.Imports))
473 copy(p1.Internal.Imports, p.Internal.Imports)
474 p1.Imports = make([]string, len(p.Imports))
475 copy(p1.Imports, p.Imports)
476 p = p1
477 p.Target = ""
478 p.Internal.BuildInfo = nil
479 p.Internal.ForceLibrary = true
480 p.Internal.PGOProfile = preal.Internal.PGOProfile
481 }
482
483
484 for i, imp := range p.Internal.Imports {
485 if p1 := testCopy[imp]; p1 != nil && p1 != imp {
486 split()
487
488
489
490
491 p.Internal.Imports[i] = p1
492 }
493 }
494
495
496
497
498
499
500
501 if p.Name == "main" && p != pmain && p != ptest {
502 split()
503 }
504
505
506 if preal.Internal.PGOProfile != "" && p.Internal.PGOProfile == "" {
507 split()
508 }
509 }
510
511
512
513 importerOf := map[*Package]*Package{}
514 for _, p := range ptest.Internal.Imports {
515 importerOf[p] = nil
516 }
517
518
519
520
521
522
523
524
525
526
527
528 q := slices.Clip(ptest.Internal.Imports)
529 for len(q) > 0 {
530 p := q[0]
531 q = q[1:]
532 if p == ptest {
533
534
535
536 var stk []string
537 for p != nil {
538 stk = append(stk, p.ImportPath)
539 p = importerOf[p]
540 }
541
542
543
544
545
546 stk = append(stk, ptest.ImportPath)
547 slices.Reverse(stk)
548
549 return &PackageError{
550 ImportStack: stk,
551 Err: errors.New("import cycle not allowed in test"),
552 IsImportCycle: true,
553 }
554 }
555 for _, dep := range p.Internal.Imports {
556 if _, ok := importerOf[dep]; !ok {
557 importerOf[dep] = p
558 q = append(q, dep)
559 }
560 }
561 }
562
563 return nil
564 }
565
566
567
568 func isTestFunc(fn *ast.FuncDecl, arg string) bool {
569 if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
570 fn.Type.Params.List == nil ||
571 len(fn.Type.Params.List) != 1 ||
572 len(fn.Type.Params.List[0].Names) > 1 {
573 return false
574 }
575 ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr)
576 if !ok {
577 return false
578 }
579
580
581
582
583 if name, ok := ptr.X.(*ast.Ident); ok && name.Name == arg {
584 return true
585 }
586 if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == arg {
587 return true
588 }
589 return false
590 }
591
592
593
594
595 func isTest(name, prefix string) bool {
596 if !strings.HasPrefix(name, prefix) {
597 return false
598 }
599 if len(name) == len(prefix) {
600 return true
601 }
602 rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
603 return !unicode.IsLower(rune)
604 }
605
606 type coverInfo struct {
607 Package *Package
608 Vars map[string]*CoverVar
609 }
610
611
612
613
614 func loadTestFuncs(ptest *Package) (*testFuncs, error) {
615 t := &testFuncs{
616 Package: ptest,
617 }
618 var err error
619 for _, file := range ptest.TestGoFiles {
620 if lerr := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); lerr != nil && err == nil {
621 err = lerr
622 }
623 }
624 for _, file := range ptest.XTestGoFiles {
625 if lerr := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); lerr != nil && err == nil {
626 err = lerr
627 }
628 }
629 return t, err
630 }
631
632
633 func formatTestmain(t *testFuncs) ([]byte, error) {
634 var buf bytes.Buffer
635 tmpl := testmainTmpl
636 if cfg.Experiment.CoverageRedesign {
637 tmpl = testmainTmplNewCoverage
638 }
639 if err := tmpl.Execute(&buf, t); err != nil {
640 return nil, err
641 }
642 return buf.Bytes(), nil
643 }
644
645 type testFuncs struct {
646 Tests []testFunc
647 Benchmarks []testFunc
648 FuzzTargets []testFunc
649 Examples []testFunc
650 TestMain *testFunc
651 Package *Package
652 ImportTest bool
653 NeedTest bool
654 ImportXtest bool
655 NeedXtest bool
656 Cover *TestCover
657 }
658
659
660
661 func (t *testFuncs) ImportPath() string {
662 pkg := t.Package.ImportPath
663 if strings.HasPrefix(pkg, "_/") {
664 return ""
665 }
666 if pkg == "command-line-arguments" {
667 return ""
668 }
669 return pkg
670 }
671
672
673
674
675
676 func (t *testFuncs) Covered() string {
677 if t.Cover == nil || t.Cover.Paths == nil {
678 return ""
679 }
680 return " in " + strings.Join(t.Cover.Paths, ", ")
681 }
682
683
684 func (t *testFuncs) Tested() string {
685 return t.Package.Name
686 }
687
688 type testFunc struct {
689 Package string
690 Name string
691 Output string
692 Unordered bool
693 }
694
695 var testFileSet = token.NewFileSet()
696
697 func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
698
699 src, err := fsys.Open(filename)
700 if err != nil {
701 return err
702 }
703 defer src.Close()
704 f, err := parser.ParseFile(testFileSet, filename, src, parser.ParseComments|parser.SkipObjectResolution)
705 if err != nil {
706 return err
707 }
708 for _, d := range f.Decls {
709 n, ok := d.(*ast.FuncDecl)
710 if !ok {
711 continue
712 }
713 if n.Recv != nil {
714 continue
715 }
716 name := n.Name.String()
717 switch {
718 case name == "TestMain":
719 if isTestFunc(n, "T") {
720 t.Tests = append(t.Tests, testFunc{pkg, name, "", false})
721 *doImport, *seen = true, true
722 continue
723 }
724 err := checkTestFunc(n, "M")
725 if err != nil {
726 return err
727 }
728 if t.TestMain != nil {
729 return errors.New("multiple definitions of TestMain")
730 }
731 t.TestMain = &testFunc{pkg, name, "", false}
732 *doImport, *seen = true, true
733 case isTest(name, "Test"):
734 err := checkTestFunc(n, "T")
735 if err != nil {
736 return err
737 }
738 t.Tests = append(t.Tests, testFunc{pkg, name, "", false})
739 *doImport, *seen = true, true
740 case isTest(name, "Benchmark"):
741 err := checkTestFunc(n, "B")
742 if err != nil {
743 return err
744 }
745 t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, "", false})
746 *doImport, *seen = true, true
747 case isTest(name, "Fuzz"):
748 err := checkTestFunc(n, "F")
749 if err != nil {
750 return err
751 }
752 t.FuzzTargets = append(t.FuzzTargets, testFunc{pkg, name, "", false})
753 *doImport, *seen = true, true
754 }
755 }
756 ex := doc.Examples(f)
757 sort.Slice(ex, func(i, j int) bool { return ex[i].Order < ex[j].Order })
758 for _, e := range ex {
759 *doImport = true
760 if e.Output == "" && !e.EmptyOutput {
761
762 continue
763 }
764 t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output, e.Unordered})
765 *seen = true
766 }
767 return nil
768 }
769
770 func checkTestFunc(fn *ast.FuncDecl, arg string) error {
771 var why string
772 if !isTestFunc(fn, arg) {
773 why = fmt.Sprintf("must be: func %s(%s *testing.%s)", fn.Name.String(), strings.ToLower(arg), arg)
774 }
775 if fn.Type.TypeParams.NumFields() > 0 {
776 why = "test functions cannot have type parameters"
777 }
778 if why != "" {
779 pos := testFileSet.Position(fn.Pos())
780 return fmt.Errorf("%s: wrong signature for %s, %s", pos, fn.Name.String(), why)
781 }
782 return nil
783 }
784
785 var testmainTmpl = lazytemplate.New("main", `
786 // Code generated by 'go test'. DO NOT EDIT.
787
788 package main
789
790 import (
791 "os"
792 {{if .TestMain}}
793 "reflect"
794 {{end}}
795 "testing"
796 "testing/internal/testdeps"
797
798 {{if .ImportTest}}
799 {{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
800 {{end}}
801 {{if .ImportXtest}}
802 {{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
803 {{end}}
804 {{if .Cover}}
805 {{range $i, $p := .Cover.Vars}}
806 _cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
807 {{end}}
808 {{end}}
809 )
810
811 var tests = []testing.InternalTest{
812 {{range .Tests}}
813 {"{{.Name}}", {{.Package}}.{{.Name}}},
814 {{end}}
815 }
816
817 var benchmarks = []testing.InternalBenchmark{
818 {{range .Benchmarks}}
819 {"{{.Name}}", {{.Package}}.{{.Name}}},
820 {{end}}
821 }
822
823 var fuzzTargets = []testing.InternalFuzzTarget{
824 {{range .FuzzTargets}}
825 {"{{.Name}}", {{.Package}}.{{.Name}}},
826 {{end}}
827 }
828
829 var examples = []testing.InternalExample{
830 {{range .Examples}}
831 {"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
832 {{end}}
833 }
834
835 func init() {
836 testdeps.ImportPath = {{.ImportPath | printf "%q"}}
837 }
838
839 {{if .Cover}}
840
841 // Only updated by init functions, so no need for atomicity.
842 var (
843 coverCounters = make(map[string][]uint32)
844 coverBlocks = make(map[string][]testing.CoverBlock)
845 )
846
847 func init() {
848 {{range $i, $p := .Cover.Vars}}
849 {{range $file, $cover := $p.Vars}}
850 coverRegisterFile({{printf "%q" $cover.File}}, _cover{{$i}}.{{$cover.Var}}.Count[:], _cover{{$i}}.{{$cover.Var}}.Pos[:], _cover{{$i}}.{{$cover.Var}}.NumStmt[:])
851 {{end}}
852 {{end}}
853 }
854
855 func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts []uint16) {
856 if 3*len(counter) != len(pos) || len(counter) != len(numStmts) {
857 panic("coverage: mismatched sizes")
858 }
859 if coverCounters[fileName] != nil {
860 // Already registered.
861 return
862 }
863 coverCounters[fileName] = counter
864 block := make([]testing.CoverBlock, len(counter))
865 for i := range counter {
866 block[i] = testing.CoverBlock{
867 Line0: pos[3*i+0],
868 Col0: uint16(pos[3*i+2]),
869 Line1: pos[3*i+1],
870 Col1: uint16(pos[3*i+2]>>16),
871 Stmts: numStmts[i],
872 }
873 }
874 coverBlocks[fileName] = block
875 }
876 {{end}}
877
878 func main() {
879 {{if .Cover}}
880 testing.RegisterCover(testing.Cover{
881 Mode: {{printf "%q" .Cover.Mode}},
882 Counters: coverCounters,
883 Blocks: coverBlocks,
884 CoveredPackages: {{printf "%q" .Covered}},
885 })
886 {{end}}
887 m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, fuzzTargets, examples)
888 {{with .TestMain}}
889 {{.Package}}.{{.Name}}(m)
890 os.Exit(int(reflect.ValueOf(m).Elem().FieldByName("exitCode").Int()))
891 {{else}}
892 os.Exit(m.Run())
893 {{end}}
894 }
895
896 `)
897
898 var testmainTmplNewCoverage = lazytemplate.New("main", `
899 // Code generated by 'go test'. DO NOT EDIT.
900
901 package main
902
903 import (
904 "os"
905 {{if .Cover}}
906 _ "unsafe"
907 {{end}}
908 {{if .TestMain}}
909 "reflect"
910 {{end}}
911 "testing"
912 "testing/internal/testdeps"
913
914 {{if .ImportTest}}
915 {{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
916 {{end}}
917 {{if .ImportXtest}}
918 {{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
919 {{end}}
920 )
921
922 var tests = []testing.InternalTest{
923 {{range .Tests}}
924 {"{{.Name}}", {{.Package}}.{{.Name}}},
925 {{end}}
926 }
927
928 var benchmarks = []testing.InternalBenchmark{
929 {{range .Benchmarks}}
930 {"{{.Name}}", {{.Package}}.{{.Name}}},
931 {{end}}
932 }
933
934 var fuzzTargets = []testing.InternalFuzzTarget{
935 {{range .FuzzTargets}}
936 {"{{.Name}}", {{.Package}}.{{.Name}}},
937 {{end}}
938 }
939
940 var examples = []testing.InternalExample{
941 {{range .Examples}}
942 {"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
943 {{end}}
944 }
945
946 func init() {
947 testdeps.ImportPath = {{.ImportPath | printf "%q"}}
948 }
949
950 {{if .Cover}}
951
952 //go:linkname runtime_coverage_processCoverTestDir runtime/coverage.processCoverTestDir
953 func runtime_coverage_processCoverTestDir(dir string, cfile string, cmode string, cpkgs string) error
954
955 //go:linkname testing_registerCover2 testing.registerCover2
956 func testing_registerCover2(mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64)
957
958 //go:linkname runtime_coverage_markProfileEmitted runtime/coverage.markProfileEmitted
959 func runtime_coverage_markProfileEmitted(val bool)
960
961 //go:linkname runtime_coverage_snapshot runtime/coverage.snapshot
962 func runtime_coverage_snapshot() float64
963
964 func coverTearDown(coverprofile string, gocoverdir string) (string, error) {
965 var err error
966 if gocoverdir == "" {
967 gocoverdir, err = os.MkdirTemp("", "gocoverdir")
968 if err != nil {
969 return "error setting GOCOVERDIR: bad os.MkdirTemp return", err
970 }
971 defer os.RemoveAll(gocoverdir)
972 }
973 runtime_coverage_markProfileEmitted(true)
974 cmode := {{printf "%q" .Cover.Mode}}
975 if err := runtime_coverage_processCoverTestDir(gocoverdir, coverprofile, cmode, {{printf "%q" .Covered}}); err != nil {
976 return "error generating coverage report", err
977 }
978 return "", nil
979 }
980 {{end}}
981
982 func main() {
983 {{if .Cover}}
984 testing_registerCover2({{printf "%q" .Cover.Mode}}, coverTearDown, runtime_coverage_snapshot)
985 {{end}}
986 m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, fuzzTargets, examples)
987 {{with .TestMain}}
988 {{.Package}}.{{.Name}}(m)
989 os.Exit(int(reflect.ValueOf(m).Elem().FieldByName("exitCode").Int()))
990 {{else}}
991 os.Exit(m.Run())
992 {{end}}
993 }
994
995 `)
996
View as plain text