...

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

View as plain text