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 "maps"
19 "path/filepath"
20 "runtime"
21 "slices"
22 "sort"
23 "strings"
24 "sync"
25 "unicode"
26 "unicode/utf8"
27
28 "cmd/go/internal/fsys"
29 "cmd/go/internal/modload"
30 "cmd/go/internal/str"
31 "cmd/go/internal/trace"
32 "cmd/internal/par"
33 )
34
35 var TestMainDeps = []string{
36
37 "os",
38 "reflect",
39 "testing",
40 "testing/internal/testdeps",
41 }
42
43 var testFileQueue = par.NewQueue(runtime.GOMAXPROCS(0))
44
45 type TestCover struct {
46 Mode string
47 Local bool
48 Pkgs []*Package
49 Paths []string
50 }
51
52
53
54
55
56 func TestPackagesFor(ld *modload.Loader, ctx context.Context, opts PackageOpts, p *Package, cover *TestCover) (pmain, ptest, pxtest, perr *Package) {
57 pmain, ptest, pxtest = TestPackagesAndErrors(ld, ctx, nil, opts, p, cover)
58 for _, p1 := range []*Package{ptest, pxtest, pmain} {
59 if p1 == nil {
60
61 continue
62 }
63 if p1.Error != nil {
64 perr = p1
65 break
66 }
67 if p1.Incomplete {
68 ps := PackageList([]*Package{p1})
69 for _, p := range ps {
70 if p.Error != nil {
71 perr = p
72 break
73 }
74 }
75 break
76 }
77 }
78 if pmain.Error != nil || pmain.Incomplete {
79 pmain = nil
80 }
81 if ptest.Error != nil || ptest.Incomplete {
82 ptest = nil
83 }
84 if pxtest != nil && (pxtest.Error != nil || pxtest.Incomplete) {
85 pxtest = nil
86 }
87 return pmain, ptest, pxtest, perr
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107 func TestPackagesAndErrors(ld *modload.Loader, ctx context.Context, done func(), opts PackageOpts, p *Package, cover *TestCover) (pmain, ptest, pxtest *Package) {
108 ctx, span := trace.StartSpan(ctx, "load.TestPackagesAndErrors")
109 defer span.Done()
110
111 pre := newPreload()
112 defer pre.flush()
113 allImports := append([]string{}, p.TestImports...)
114 allImports = append(allImports, p.XTestImports...)
115 pre.preloadImports(ld, ctx, opts, allImports, p.Internal.Build)
116
117 var ptestErr, pxtestErr *PackageError
118 var imports, ximports []*Package
119 var stk ImportStack
120 var testEmbed, xtestEmbed map[string][]string
121 var incomplete bool
122 stk.Push(ImportInfo{Pkg: p.ImportPath + " (test)"})
123 rawTestImports := str.StringList(p.TestImports)
124
125 for i, path := range p.TestImports {
126 p1, err := loadImport(ld, ctx, opts, pre, path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport)
127 if err != nil && ptestErr == nil {
128 ptestErr = err
129 incomplete = true
130 }
131 if p1.Incomplete {
132 incomplete = true
133 }
134 p.TestImports[i] = p1.ImportPath
135 imports = append(imports, p1)
136 }
137
138 var ptestCompiledImports []string
139 if hasSimd := hasSimd(p.TestImports); hasSimd {
140 p1, err := loadImport(ld, ctx, opts, pre, SimdBridgePkg, p.Dir, p, &stk, nil, ResolveImport|allowSimdInternalBridge)
141 if err != nil && ptestErr == nil {
142 ptestErr = err
143 incomplete = true
144 }
145 if p1.Incomplete {
146 incomplete = true
147 }
148 imports = append(imports, p1)
149 ptestCompiledImports = append(ptestCompiledImports, p1.ImportPath)
150 }
151 var err error
152 p.TestEmbedFiles, testEmbed, err = resolveEmbed(p.Dir, p.TestEmbedPatterns)
153 if err != nil {
154 ptestErr = &PackageError{
155 ImportStack: stk.Copy(),
156 Err: err,
157 }
158 incomplete = true
159 embedErr := err.(*EmbedError)
160 ptestErr.setPos(p.Internal.Build.TestEmbedPatternPos[embedErr.Pattern])
161 }
162 stk.Pop()
163
164 stk.Push(ImportInfo{Pkg: p.ImportPath + "_test"})
165 pxtestNeedsPtest := false
166 var pxtestIncomplete bool
167 rawXTestImports := str.StringList(p.XTestImports)
168
169 for i, path := range p.XTestImports {
170 p1, err := loadImport(ld, ctx, opts, pre, path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], ResolveImport)
171 if err != nil && pxtestErr == nil {
172 pxtestErr = err
173 }
174 if p1.Incomplete {
175 pxtestIncomplete = true
176 }
177 if p1.ImportPath == p.ImportPath {
178 pxtestNeedsPtest = true
179 } else {
180 ximports = append(ximports, p1)
181 }
182 p.XTestImports[i] = p1.ImportPath
183 }
184
185 var pxtestCompiledImports []string
186 if hasSimd := hasSimd(p.XTestImports); hasSimd {
187 p1, err := loadImport(ld, ctx, opts, pre, SimdBridgePkg, p.Dir, p, &stk, nil, ResolveImport|allowSimdInternalBridge)
188 if err != nil && pxtestErr == nil {
189 pxtestErr = err
190 }
191 if p1.Incomplete {
192 pxtestIncomplete = true
193 }
194 ximports = append(ximports, p1)
195 pxtestCompiledImports = append(pxtestCompiledImports, p1.ImportPath)
196 }
197 p.XTestEmbedFiles, xtestEmbed, err = resolveEmbed(p.Dir, p.XTestEmbedPatterns)
198 if err != nil && pxtestErr == nil {
199 pxtestErr = &PackageError{
200 ImportStack: stk.Copy(),
201 Err: err,
202 }
203 embedErr := err.(*EmbedError)
204 pxtestErr.setPos(p.Internal.Build.XTestEmbedPatternPos[embedErr.Pattern])
205 }
206 pxtestIncomplete = pxtestIncomplete || pxtestErr != nil
207 stk.Pop()
208
209
210 if len(p.TestGoFiles) > 0 || p.Name == "main" || cover != nil && cover.Local {
211 ptest = new(Package)
212 *ptest = *p
213 if ptest.Error == nil {
214 ptest.Error = ptestErr
215 }
216 ptest.Incomplete = ptest.Incomplete || incomplete
217 ptest.ForTest = p.ImportPath
218 ptest.GoFiles = nil
219 ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
220 ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
221 ptest.Target = ""
222
223
224
225
226
227
228
229
230
231
232
233
234 ptest.Imports = str.StringList(p.TestImports, p.Imports)
235 ptest.Internal.Imports = append(imports, p.Internal.Imports...)
236 ptest.Internal.RawImports = str.StringList(rawTestImports, p.Internal.RawImports)
237 ptest.Internal.CompiledImports = slices.Clone(p.Internal.CompiledImports)
238 for _, path := range ptestCompiledImports {
239 if !slices.Contains(ptest.Internal.CompiledImports, path) {
240 ptest.Internal.CompiledImports = append(ptest.Internal.CompiledImports, path)
241 }
242 }
243 ptest.Internal.ForceLibrary = true
244 ptest.Internal.BuildInfo = nil
245 ptest.Internal.Build = new(build.Package)
246 *ptest.Internal.Build = *p.Internal.Build
247 m := map[string][]token.Position{}
248 for k, v := range p.Internal.Build.ImportPos {
249 m[k] = append(m[k], v...)
250 }
251 for k, v := range p.Internal.Build.TestImportPos {
252 m[k] = append(m[k], v...)
253 }
254 ptest.Internal.Build.ImportPos = m
255 if testEmbed == nil && len(p.Internal.Embed) > 0 {
256 testEmbed = map[string][]string{}
257 }
258 maps.Copy(testEmbed, p.Internal.Embed)
259 ptest.Internal.Embed = testEmbed
260 ptest.EmbedFiles = str.StringList(p.EmbedFiles, p.TestEmbedFiles)
261 ptest.Internal.OrigImportPath = p.Internal.OrigImportPath
262 ptest.Internal.PGOProfile = p.Internal.PGOProfile
263 ptest.Internal.Build.Directives = append(slices.Clip(p.Internal.Build.Directives), p.Internal.Build.TestDirectives...)
264 } else {
265 ptest = p
266 }
267
268
269 if len(p.XTestGoFiles) > 0 {
270 pxtest = &Package{
271 PackagePublic: PackagePublic{
272 Name: p.Name + "_test",
273 ImportPath: p.ImportPath + "_test",
274 Root: p.Root,
275 Dir: p.Dir,
276 Goroot: p.Goroot,
277 GoFiles: p.XTestGoFiles,
278 Imports: p.XTestImports,
279 ForTest: p.ImportPath,
280 Module: p.Module,
281 Error: pxtestErr,
282 Incomplete: pxtestIncomplete,
283 EmbedFiles: p.XTestEmbedFiles,
284 },
285 Internal: PackageInternal{
286 LocalPrefix: p.Internal.LocalPrefix,
287 Build: &build.Package{
288 ImportPos: p.Internal.Build.XTestImportPos,
289 Directives: p.Internal.Build.XTestDirectives,
290 },
291 Imports: ximports,
292 RawImports: rawXTestImports,
293 CompiledImports: pxtestCompiledImports,
294
295 Asmflags: p.Internal.Asmflags,
296 Gcflags: p.Internal.Gcflags,
297 Ldflags: p.Internal.Ldflags,
298 Gccgoflags: p.Internal.Gccgoflags,
299 Embed: xtestEmbed,
300 OrigImportPath: p.Internal.OrigImportPath,
301 PGOProfile: p.Internal.PGOProfile,
302 },
303 }
304 if pxtestNeedsPtest {
305 pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest)
306 }
307 }
308
309
310 ldflags := append(p.Internal.Ldflags, "-X", "testing.testBinary=1")
311 gccgoflags := append(p.Internal.Gccgoflags, "-Wl,--defsym,testing.gccgoTestBinary=1")
312
313
314 pmain = &Package{
315 PackagePublic: PackagePublic{
316 Name: "main",
317 Dir: p.Dir,
318 GoFiles: []string{"_testmain.go"},
319 ImportPath: p.ImportPath + ".test",
320 Root: p.Root,
321 Imports: str.StringList(TestMainDeps),
322 Module: p.Module,
323 },
324 Internal: PackageInternal{
325 Build: &build.Package{Name: "main"},
326 BuildInfo: p.Internal.BuildInfo,
327 Asmflags: p.Internal.Asmflags,
328 Gcflags: p.Internal.Gcflags,
329 Ldflags: ldflags,
330 Gccgoflags: gccgoflags,
331 OrigImportPath: p.Internal.OrigImportPath,
332 PGOProfile: p.Internal.PGOProfile,
333 },
334 }
335
336 pb := p.Internal.Build
337 pmain.DefaultGODEBUG = defaultGODEBUG(ld, pmain, pb.Directives, pb.TestDirectives, pb.XTestDirectives)
338
339
340
341 stk.Push(ImportInfo{Pkg: "testmain"})
342 deps := TestMainDeps
343 if cover != nil {
344 deps = append(deps, "internal/coverage/cfile")
345 }
346 ldDeps, err := LinkerDeps(ld, p)
347 if err != nil && pmain.Error == nil {
348 pmain.Error = &PackageError{Err: err}
349 }
350 for _, d := range ldDeps {
351 deps = append(deps, d)
352 }
353 for _, dep := range deps {
354 if dep == ptest.ImportPath {
355 pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
356 } else {
357 p1, err := loadImport(ld, ctx, opts, pre, dep, "", nil, &stk, nil, 0)
358 if err != nil && pmain.Error == nil {
359 pmain.Error = err
360 pmain.Incomplete = true
361 }
362 pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
363 }
364 }
365 stk.Pop()
366
367 parallelizablePart := func() {
368
369
370
371
372 t, err := loadTestFuncs(p)
373 if err != nil && pmain.Error == nil {
374 pmain.setLoadPackageDataError(err, p.ImportPath, &stk, nil)
375 }
376 t.Cover = cover
377 if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
378 pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
379 pmain.Imports = append(pmain.Imports, ptest.ImportPath)
380 t.ImportTest = true
381 }
382 if pxtest != nil {
383 pmain.Internal.Imports = append(pmain.Internal.Imports, pxtest)
384 pmain.Imports = append(pmain.Imports, pxtest.ImportPath)
385 t.ImportXtest = true
386 }
387
388
389
390 sort.Strings(pmain.Imports)
391 w := 0
392 for _, path := range pmain.Imports {
393 if w == 0 || path != pmain.Imports[w-1] {
394 pmain.Imports[w] = path
395 w++
396 }
397 }
398 pmain.Imports = pmain.Imports[:w]
399 pmain.Internal.RawImports = str.StringList(pmain.Imports)
400
401
402 cycleErr := recompileForTest(pmain, p, ptest, pxtest)
403 if cycleErr != nil {
404 ptest.Error = cycleErr
405 ptest.Incomplete = true
406 }
407
408 if !opts.SuppressBuildInfo {
409
410
411
412
413
414 pmain.setBuildInfo(ctx, ld.Fetcher(), opts.AutoVCS)
415 }
416
417 if cover != nil {
418
419
420
421
422 ptest.Internal.Cover.Mode = p.Internal.Cover.Mode
423 pmain.Internal.Cover.Mode = "testmain"
424
425
426
427
428
429 if cover.Local {
430 ptest.Internal.Cover.Mode = cover.Mode
431 }
432 }
433
434 data, err := formatTestmain(t)
435 if err != nil && pmain.Error == nil {
436 pmain.Error = &PackageError{Err: err}
437 pmain.Incomplete = true
438 }
439
440
441 pmain.Internal.TestmainGo = &data
442 }
443
444 if done != nil {
445 go func() {
446 parallelizablePart()
447 done()
448 }()
449 } else {
450 parallelizablePart()
451 }
452
453 return pmain, ptest, pxtest
454 }
455
456
457
458
459
460
461
462
463
464
465 func recompileForTest(pmain, preal, ptest, pxtest *Package) *PackageError {
466
467
468
469 testCopy := map[*Package]*Package{preal: ptest}
470 for _, p := range PackageList([]*Package{pmain}) {
471 if p == preal {
472 continue
473 }
474
475 didSplit := p == pmain || p == pxtest || p == ptest
476 split := func() {
477 if didSplit {
478 return
479 }
480 didSplit = true
481 if testCopy[p] != nil {
482 panic("recompileForTest loop")
483 }
484 p1 := new(Package)
485 testCopy[p] = p1
486 *p1 = *p
487 p1.ForTest = preal.ImportPath
488 p1.Internal.Imports = make([]*Package, len(p.Internal.Imports))
489 copy(p1.Internal.Imports, p.Internal.Imports)
490 p1.Imports = make([]string, len(p.Imports))
491 copy(p1.Imports, p.Imports)
492 p = p1
493 p.Target = ""
494 p.Internal.BuildInfo = nil
495 p.Internal.ForceLibrary = true
496 p.Internal.PGOProfile = preal.Internal.PGOProfile
497 }
498
499
500 for i, imp := range p.Internal.Imports {
501 if p1 := testCopy[imp]; p1 != nil && p1 != imp {
502 split()
503
504
505
506
507 p.Internal.Imports[i] = p1
508 }
509 }
510
511
512
513
514
515
516
517 if p.Name == "main" && p != pmain && p != ptest {
518 split()
519 }
520
521
522 if preal.Internal.PGOProfile != "" && p.Internal.PGOProfile == "" {
523 split()
524 }
525 }
526
527
528
529 importerOf := map[*Package]*Package{}
530 for _, p := range ptest.Internal.Imports {
531 importerOf[p] = nil
532 }
533
534
535
536
537
538
539
540
541
542
543
544 q := slices.Clip(ptest.Internal.Imports)
545 for len(q) > 0 {
546 p := q[0]
547 q = q[1:]
548 if p == ptest {
549
550
551
552 var stk ImportStack
553 for p != nil {
554 importer, ok := importerOf[p]
555 if importer == nil && ok {
556 importer = ptest
557 }
558 stk = append(stk, ImportInfo{
559 Pkg: p.ImportPath,
560 Pos: extractFirstImport(importer.Internal.Build.ImportPos[p.ImportPath]),
561 })
562 p = importerOf[p]
563 }
564
565
566
567
568
569 stk = append(stk, ImportInfo{
570 Pkg: ptest.ImportPath,
571 })
572 slices.Reverse(stk)
573 return &PackageError{
574 ImportStack: stk,
575 Err: errors.New("import cycle not allowed in test"),
576 IsImportCycle: true,
577 }
578 }
579 for _, dep := range p.Internal.Imports {
580 if _, ok := importerOf[dep]; !ok {
581 importerOf[dep] = p
582 q = append(q, dep)
583 }
584 }
585 }
586
587 return nil
588 }
589
590
591
592 func isTestFunc(fn *ast.FuncDecl, arg string) bool {
593 if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
594 fn.Type.Params.List == nil ||
595 len(fn.Type.Params.List) != 1 ||
596 len(fn.Type.Params.List[0].Names) > 1 {
597 return false
598 }
599 ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr)
600 if !ok {
601 return false
602 }
603
604
605
606
607 if name, ok := ptr.X.(*ast.Ident); ok && name.Name == arg {
608 return true
609 }
610 if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == arg {
611 return true
612 }
613 return false
614 }
615
616
617
618
619 func isTest(name, prefix string) bool {
620 if !strings.HasPrefix(name, prefix) {
621 return false
622 }
623 if len(name) == len(prefix) {
624 return true
625 }
626 rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
627 return !unicode.IsLower(rune)
628 }
629
630
631
632
633 func loadTestFuncs(ptest *Package) (*testFuncs, error) {
634 t := &testFuncs{
635 Package: ptest,
636 }
637
638 nTest := len(ptest.TestGoFiles)
639 results := make([]testFileResult, nTest+len(ptest.XTestGoFiles))
640 var wg sync.WaitGroup
641 queueFile := func(i int, filename, pkg string) {
642 wg.Add(1)
643 testFileQueue.Add(func() {
644 defer wg.Done()
645 results[i] = loadTestFuncFile(ptest, filename, pkg)
646 })
647 }
648 for i, file := range ptest.TestGoFiles {
649 queueFile(i, filepath.Join(ptest.Dir, file), "_test")
650 }
651 for i, file := range ptest.XTestGoFiles {
652 queueFile(nTest+i, filepath.Join(ptest.Dir, file), "_xtest")
653 }
654 wg.Wait()
655
656 var err error
657 for i := range results {
658 r := &results[i]
659 if r.err != nil && err == nil {
660 err = r.err
661 }
662 t.Tests = append(t.Tests, r.funcs.Tests...)
663 t.Benchmarks = append(t.Benchmarks, r.funcs.Benchmarks...)
664 t.FuzzTargets = append(t.FuzzTargets, r.funcs.FuzzTargets...)
665 t.Examples = append(t.Examples, r.funcs.Examples...)
666 if r.funcs.TestMain != nil {
667 if t.TestMain != nil && err == nil {
668 err = errors.New("multiple definitions of TestMain")
669 } else if t.TestMain == nil {
670 t.TestMain = r.funcs.TestMain
671 }
672 }
673 t.ImportTest = t.ImportTest || r.funcs.ImportTest
674 t.NeedTest = t.NeedTest || r.funcs.NeedTest
675 t.ImportXtest = t.ImportXtest || r.funcs.ImportXtest
676 t.NeedXtest = t.NeedXtest || r.funcs.NeedXtest
677 }
678 return t, err
679 }
680
681 type testFileResult struct {
682 funcs testFuncs
683 err error
684 }
685
686 func loadTestFuncFile(ptest *Package, filename, pkg string) testFileResult {
687 tf := &testFuncs{Package: ptest}
688 var err error
689 if pkg == "_test" {
690 err = tf.load(token.NewFileSet(), filename, pkg, &tf.ImportTest, &tf.NeedTest)
691 } else {
692 err = tf.load(token.NewFileSet(), filename, pkg, &tf.ImportXtest, &tf.NeedXtest)
693 }
694 return testFileResult{*tf, err}
695 }
696
697
698 func formatTestmain(t *testFuncs) ([]byte, error) {
699 var buf bytes.Buffer
700 tmpl := testmainTmpl
701 if err := tmpl.Execute(&buf, t); err != nil {
702 return nil, err
703 }
704 return buf.Bytes(), nil
705 }
706
707 type testFuncs struct {
708 Tests []testFunc
709 Benchmarks []testFunc
710 FuzzTargets []testFunc
711 Examples []testFunc
712 TestMain *testFunc
713 Package *Package
714 ImportTest bool
715 NeedTest bool
716 ImportXtest bool
717 NeedXtest bool
718 Cover *TestCover
719 }
720
721
722
723 func (t *testFuncs) ImportPath() string {
724 pkg := t.Package.ImportPath
725 if strings.HasPrefix(pkg, "_/") {
726 return ""
727 }
728 if pkg == "command-line-arguments" {
729 return ""
730 }
731 return pkg
732 }
733
734 func (t *testFuncs) ModulePath() string {
735 m := t.Package.Module
736 if m == nil {
737 return ""
738 }
739 return m.Path
740 }
741
742
743
744
745
746 func (t *testFuncs) Covered() string {
747 if t.Cover == nil || t.Cover.Paths == nil {
748 return ""
749 }
750 return " in " + strings.Join(t.Cover.Paths, ", ")
751 }
752
753 func (t *testFuncs) CoverSelectedPackages() string {
754 if t.Cover == nil || t.Cover.Paths == nil {
755 return `[]string{"` + t.Package.ImportPath + `"}`
756 }
757 var sb strings.Builder
758 fmt.Fprintf(&sb, "[]string{")
759 for k, p := range t.Cover.Pkgs {
760 if k != 0 {
761 sb.WriteString(", ")
762 }
763 fmt.Fprintf(&sb, `"%s"`, p.ImportPath)
764 }
765 sb.WriteString("}")
766 return sb.String()
767 }
768
769
770 func (t *testFuncs) Tested() string {
771 return t.Package.Name
772 }
773
774 type testFunc struct {
775 Package string
776 Name string
777 Output string
778 Unordered bool
779 }
780
781 func (t *testFuncs) load(fset *token.FileSet, filename, pkg string, doImport, seen *bool) error {
782
783 src, err := fsys.Open(filename)
784 if err != nil {
785 return err
786 }
787 defer src.Close()
788 f, err := parser.ParseFile(fset, filename, src, parser.ParseComments|parser.SkipObjectResolution)
789 if err != nil {
790 return err
791 }
792 for _, d := range f.Decls {
793 n, ok := d.(*ast.FuncDecl)
794 if !ok {
795 continue
796 }
797 if n.Recv != nil {
798 continue
799 }
800 name := n.Name.String()
801 switch {
802 case name == "TestMain":
803 if isTestFunc(n, "T") {
804 t.Tests = append(t.Tests, testFunc{pkg, name, "", false})
805 *doImport, *seen = true, true
806 continue
807 }
808 err := checkTestFunc(fset, n, "M")
809 if err != nil {
810 return err
811 }
812 if t.TestMain != nil {
813 return errors.New("multiple definitions of TestMain")
814 }
815 t.TestMain = &testFunc{pkg, name, "", false}
816 *doImport, *seen = true, true
817 case isTest(name, "Test"):
818 err := checkTestFunc(fset, n, "T")
819 if err != nil {
820 return err
821 }
822 t.Tests = append(t.Tests, testFunc{pkg, name, "", false})
823 *doImport, *seen = true, true
824 case isTest(name, "Benchmark"):
825 err := checkTestFunc(fset, n, "B")
826 if err != nil {
827 return err
828 }
829 t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, "", false})
830 *doImport, *seen = true, true
831 case isTest(name, "Fuzz"):
832 err := checkTestFunc(fset, n, "F")
833 if err != nil {
834 return err
835 }
836 t.FuzzTargets = append(t.FuzzTargets, testFunc{pkg, name, "", false})
837 *doImport, *seen = true, true
838 }
839 }
840 ex := doc.Examples(f)
841 sort.Slice(ex, func(i, j int) bool { return ex[i].Order < ex[j].Order })
842 for _, e := range ex {
843 *doImport = true
844 if e.Output == "" && !e.EmptyOutput {
845
846 continue
847 }
848 t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output, e.Unordered})
849 *seen = true
850 }
851 return nil
852 }
853
854 func checkTestFunc(fset *token.FileSet, fn *ast.FuncDecl, arg string) error {
855 var why string
856 if !isTestFunc(fn, arg) {
857 why = fmt.Sprintf("must be: func %s(%s *testing.%s)", fn.Name.String(), strings.ToLower(arg), arg)
858 }
859 if fn.Type.TypeParams.NumFields() > 0 {
860 why = "test functions cannot have type parameters"
861 }
862 if why != "" {
863 pos := fset.Position(fn.Pos())
864 return fmt.Errorf("%s: wrong signature for %s, %s", pos, fn.Name.String(), why)
865 }
866 return nil
867 }
868
869 var testmainTmpl = lazytemplate.New("main", `
870 // Code generated by 'go test'. DO NOT EDIT.
871
872 package main
873
874 import (
875 "os"
876 {{if .TestMain}}
877 "reflect"
878 {{end}}
879 "testing"
880 "testing/internal/testdeps"
881 {{if .Cover}}
882 "internal/coverage/cfile"
883 {{end}}
884
885 {{if .ImportTest}}
886 {{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
887 {{end}}
888 {{if .ImportXtest}}
889 {{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
890 {{end}}
891 )
892
893 var tests = []testing.InternalTest{
894 {{range .Tests}}
895 {"{{.Name}}", {{.Package}}.{{.Name}}},
896 {{end}}
897 }
898
899 var benchmarks = []testing.InternalBenchmark{
900 {{range .Benchmarks}}
901 {"{{.Name}}", {{.Package}}.{{.Name}}},
902 {{end}}
903 }
904
905 var fuzzTargets = []testing.InternalFuzzTarget{
906 {{range .FuzzTargets}}
907 {"{{.Name}}", {{.Package}}.{{.Name}}},
908 {{end}}
909 }
910
911 var examples = []testing.InternalExample{
912 {{range .Examples}}
913 {"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
914 {{end}}
915 }
916
917 func init() {
918 {{if .Cover}}
919 testdeps.CoverMode = {{printf "%q" .Cover.Mode}}
920 testdeps.Covered = {{printf "%q" .Covered}}
921 testdeps.CoverSelectedPackages = {{printf "%s" .CoverSelectedPackages}}
922 testdeps.CoverSnapshotFunc = cfile.Snapshot
923 testdeps.CoverProcessTestDirFunc = cfile.ProcessCoverTestDir
924 testdeps.CoverMarkProfileEmittedFunc = cfile.MarkProfileEmitted
925
926 {{end}}
927 testdeps.ModulePath = {{.ModulePath | printf "%q"}}
928 testdeps.ImportPath = {{.ImportPath | printf "%q"}}
929 }
930
931 func main() {
932 m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, fuzzTargets, examples)
933 {{with .TestMain}}
934 {{.Package}}.{{.Name}}(m)
935 os.Exit(int(reflect.ValueOf(m).Elem().FieldByName("exitCode").Int()))
936 {{else}}
937 os.Exit(m.Run())
938 {{end}}
939 }
940
941 `)
942
View as plain text