Black Lives Matter. Support the Equal Justice Initiative.

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

Documentation: cmd/go/internal/load

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

View as plain text