Source file src/cmd/go/internal/load/test.go

     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  	"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  	// Dependencies for testmain.
    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  // TestPackagesFor is like TestPackagesAndErrors but it returns
    48  // an error if the test packages or their dependencies have errors.
    49  // Only test packages without errors are returned.
    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  			// pxtest may be nil
    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  // TestPackagesAndErrors returns three packages:
    85  //   - pmain, the package main corresponding to the test binary (running tests in ptest and pxtest).
    86  //   - ptest, the package p compiled with added "package p" test files.
    87  //   - pxtest, the result of compiling any "package p_test" (external) test files.
    88  //
    89  // If the package has no "package p_test" test files, pxtest will be nil.
    90  // If the non-test compilation of package p can be reused
    91  // (for example, if there are no "package p" test files and
    92  // package p need not be instrumented for coverage or any other reason),
    93  // then the returned ptest == p.
    94  //
    95  // If done is non-nil, TestPackagesAndErrors will finish filling out the returned
    96  // package structs in a goroutine and call done once finished. The members of the
    97  // returned packages should not be accessed until done is called.
    98  //
    99  // The caller is expected to have checked that len(p.TestGoFiles)+len(p.XTestGoFiles) > 0,
   100  // or else there's no point in any of this.
   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  	// Test package.
   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  		// Note: The preparation of the vet config requires that common
   186  		// indexes in ptest.Imports and ptest.Internal.RawImports
   187  		// all line up (but RawImports can be shorter than the others).
   188  		// That is, for 0 ≤ i < len(RawImports),
   189  		// RawImports[i] is the import string in the program text, and
   190  		// Imports[i] is the expanded import string (vendoring applied or relative path expanded away).
   191  		// Any implicitly added imports appear in Imports and Internal.Imports
   192  		// but not RawImports (because they were not in the source code).
   193  		// We insert TestImports, imports, and rawTestImports at the start of
   194  		// these lists to preserve the alignment.
   195  		// Note that p.Internal.Imports may not be aligned with p.Imports/p.Internal.RawImports,
   196  		// but we insert at the beginning there too just for consistency.
   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  	// External test package.
   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  	// Arrange for testing.Testing to report true.
   268  	ldflags := append(p.Internal.Ldflags, "-X", "testing.testBinary=1")
   269  	gccgoflags := append(p.Internal.Gccgoflags, "-Wl,--defsym,testing.gccgoTestBinary=1")
   270  
   271  	// Build main package.
   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  	// The generated main also imports testing, regexp, and os.
   298  	// Also the linker introduces implicit dependencies reported by LinkerDeps.
   299  	stk.Push("testmain")
   300  	deps := TestMainDeps // cap==len, so safe for append
   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  			// Add imports, but avoid duplicates.
   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  					// Don't add duplicate imports.
   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  		// Do initial scan for metadata needed for writing _testmain.go
   346  		// Use that metadata to update the list of imports for package main.
   347  		// The list of imports is used by recompileForTest and by the loop
   348  		// afterward that gathers t.Cover information.
   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  		// Sort and dedup pmain.Imports.
   366  		// Only matters for go list -test output.
   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  		// Replace pmain's transitive dependencies with test copies, as necessary.
   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  				// Here ptest needs to inherit the proper coverage mode (since
   388  				// it contains p's Go files), whereas pmain contains only
   389  				// test harness code (don't want to instrument it, and
   390  				// we don't want coverage hooks in the pkg init).
   391  				ptest.Internal.Cover.Mode = p.Internal.Cover.Mode
   392  				pmain.Internal.Cover.Mode = "testmain"
   393  			}
   394  			// Should we apply coverage analysis locally, only for this
   395  			// package and only for this test? Yes, if -cover is on but
   396  			// -coverpkg has not specified a list of packages for global
   397  			// coverage.
   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  		// Set TestmainGo even if it is empty: the presence of a TestmainGo
   424  		// indicates that this package is, in fact, a test main.
   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  // recompileForTest copies and replaces certain packages in pmain's dependency
   441  // graph. This is necessary for two reasons. First, if ptest is different than
   442  // preal, packages that import the package under test should get ptest instead
   443  // of preal. This is particularly important if pxtest depends on functionality
   444  // exposed in test sources in ptest. Second, if there is a main package
   445  // (other than pmain) anywhere, we need to set p.Internal.ForceLibrary and
   446  // clear p.Internal.BuildInfo in the test copy to prevent link conflicts.
   447  // This may happen if both -coverpkg and the command line patterns include
   448  // multiple main packages.
   449  func recompileForTest(pmain, preal, ptest, pxtest *Package) *PackageError {
   450  	// The "test copy" of preal is ptest.
   451  	// For each package that depends on preal, make a "test copy"
   452  	// that depends on ptest. And so on, up the dependency tree.
   453  	testCopy := map[*Package]*Package{preal: ptest}
   454  	for _, p := range PackageList([]*Package{pmain}) {
   455  		if p == preal {
   456  			continue
   457  		}
   458  		// Copy on write.
   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  		// Update p.Internal.Imports to use test copies.
   484  		for i, imp := range p.Internal.Imports {
   485  			if p1 := testCopy[imp]; p1 != nil && p1 != imp {
   486  				split()
   487  
   488  				// If the test dependencies cause a cycle with pmain, this is
   489  				// where it is introduced.
   490  				// (There are no cycles in the graph until this assignment occurs.)
   491  				p.Internal.Imports[i] = p1
   492  			}
   493  		}
   494  
   495  		// Force main packages the test imports to be built as libraries.
   496  		// Normal imports of main packages are forbidden by the package loader,
   497  		// but this can still happen if -coverpkg patterns include main packages:
   498  		// covered packages are imported by pmain. Linking multiple packages
   499  		// compiled with '-p main' causes duplicate symbol errors.
   500  		// See golang.org/issue/30907, golang.org/issue/34114.
   501  		if p.Name == "main" && p != pmain && p != ptest {
   502  			split()
   503  		}
   504  		// Split and attach PGO information to test dependencies if preal
   505  		// is built with PGO.
   506  		if preal.Internal.PGOProfile != "" && p.Internal.PGOProfile == "" {
   507  			split()
   508  		}
   509  	}
   510  
   511  	// Do search to find cycle.
   512  	// importerOf maps each import path to its importer nearest to p.
   513  	importerOf := map[*Package]*Package{}
   514  	for _, p := range ptest.Internal.Imports {
   515  		importerOf[p] = nil
   516  	}
   517  
   518  	// q is a breadth-first queue of packages to search for target.
   519  	// Every package added to q has a corresponding entry in pathTo.
   520  	//
   521  	// We search breadth-first for two reasons:
   522  	//
   523  	// 	1. We want to report the shortest cycle.
   524  	//
   525  	// 	2. If p contains multiple cycles, the first cycle we encounter might not
   526  	// 	   contain target. To ensure termination, we have to break all cycles
   527  	// 	   other than the first.
   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  			// The stack is supposed to be in the order x imports y imports z.
   534  			// We collect in the reverse order: z is imported by y is imported
   535  			// by x, and then we reverse it.
   536  			var stk []string
   537  			for p != nil {
   538  				stk = append(stk, p.ImportPath)
   539  				p = importerOf[p]
   540  			}
   541  			// complete the cycle: we set importer[p] = nil to break the cycle
   542  			// in importerOf, it's an implicit importerOf[p] == pTest. Add it
   543  			// back here since we reached nil in the loop above to demonstrate
   544  			// the cycle as (for example) package p imports package q imports package r
   545  			// imports package p.
   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  // isTestFunc tells whether fn has the type of a testing function. arg
   567  // specifies the parameter type we look for: B, M or T.
   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  	// We can't easily check that the type is *testing.M
   580  	// because we don't know how testing has been imported,
   581  	// but at least check that it's *M or *something.M.
   582  	// Same applies for B and T.
   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  // isTest tells whether name looks like a test (or benchmark, according to prefix).
   593  // It is a Test (say) if there is a character after Test that is not a lower-case letter.
   594  // We don't want TesticularCancer.
   595  func isTest(name, prefix string) bool {
   596  	if !strings.HasPrefix(name, prefix) {
   597  		return false
   598  	}
   599  	if len(name) == len(prefix) { // "Test" is ok
   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  // loadTestFuncs returns the testFuncs describing the tests that will be run.
   612  // The returned testFuncs is always non-nil, even if an error occurred while
   613  // processing test files.
   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  // formatTestmain returns the content of the _testmain.go file for t.
   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  // ImportPath returns the import path of the package being tested, if it is within GOPATH.
   660  // This is printed by the testing package when running benchmarks.
   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  // Covered returns a string describing which packages are being tested for coverage.
   673  // If the covered package is the same as the tested package, it returns the empty string.
   674  // Otherwise it is a comma-separated human-readable list of packages beginning with
   675  // " in", ready for use in the coverage message.
   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  // Tested returns the name of the package being tested.
   684  func (t *testFuncs) Tested() string {
   685  	return t.Package.Name
   686  }
   687  
   688  type testFunc struct {
   689  	Package   string // imported package name (_test or _xtest)
   690  	Name      string // function name
   691  	Output    string // output, for examples
   692  	Unordered bool   // output is allowed to be unordered.
   693  }
   694  
   695  var testFileSet = token.NewFileSet()
   696  
   697  func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
   698  	// Pass in the overlaid source if we have an overlay for this file.
   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 // import test file whether executed or not
   760  		if e.Output == "" && !e.EmptyOutput {
   761  			// Don't run examples with no output.
   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