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