diff options
Diffstat (limited to 'src/cmd/go/test.go')
-rw-r--r-- | src/cmd/go/test.go | 142 |
1 files changed, 103 insertions, 39 deletions
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go index 06ac9d206..5935c98db 100644 --- a/src/cmd/go/test.go +++ b/src/cmd/go/test.go @@ -72,6 +72,10 @@ In addition to the build flags, the flags handled by 'go test' itself are: Install packages that are dependencies of the test. Do not run the test. + -exec xprog + Run the test binary using xprog. The behavior is the same as + in 'go run'. See 'go help run' for details. + The test binary also accepts flags that control execution of the test; these flags are also accessible by 'go test'. See 'go help testflag' for details. @@ -133,7 +137,8 @@ control the execution of any test: -covermode set,count,atomic Set the mode for coverage analysis for the package[s] - being tested. The default is "set". + being tested. The default is "set" unless -race is enabled, + in which case it is "atomic". The values: set: bool: does this statement run? count: int: how many times does this statement run? @@ -168,9 +173,7 @@ control the execution of any test: Enable more precise (and expensive) memory profiles by setting runtime.MemProfileRate. See 'godoc runtime MemProfileRate'. To profile all memory allocations, use -test.memprofilerate=1 - and set the environment variable GOGC=off to disable the - garbage collector, provided the test can run in the available - memory without garbage collection. + and pass --alloc_space flag to the pprof tool. -outputdir directory Place output files from profiling in the specified directory, @@ -273,7 +276,6 @@ var ( testCoverPkgs []*Package // -coverpkg flag testProfile bool // some profiling flag testNeedBinary bool // profile needs to keep binary around - testI bool // -i flag testV bool // -v flag testFiles []string // -file flag(s) TODO: not respected testTimeout string // -timeout flag @@ -295,6 +297,8 @@ func runTest(cmd *Command, args []string) { var pkgArgs []string pkgArgs, testArgs = testFlags(args) + findExecCmd() // initialize cached result + raceInit() pkgs := packagesForBuild(pkgArgs) if len(pkgs) == 0 { @@ -334,7 +338,7 @@ func runTest(cmd *Command, args []string) { var b builder b.init() - if testI { + if buildI { buildV = testV deps := make(map[string]bool) @@ -411,7 +415,11 @@ func runTest(cmd *Command, args []string) { p.Stale = true // rebuild p.fake = true // do not warn about rebuild p.coverMode = testCoverMode - p.coverVars = declareCoverVars(p.ImportPath, p.GoFiles...) + var coverFiles []string + coverFiles = append(coverFiles, p.GoFiles...) + coverFiles = append(coverFiles, p.CgoFiles...) + coverFiles = append(coverFiles, p.TestGoFiles...) + p.coverVars = declareCoverVars(p.ImportPath, coverFiles...) } } @@ -516,7 +524,7 @@ func contains(x []string, s string) bool { func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) { if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { - build := &action{p: p} + build := b.action(modeBuild, modeBuild, p) run := &action{p: p, deps: []*action{build}} print := &action{f: (*builder).notest, p: p, deps: []*action{run}} return build, run, print, nil @@ -530,16 +538,31 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, var imports, ximports []*Package var stk importStack - stk.push(p.ImportPath + "_test") + stk.push(p.ImportPath + " (test)") for _, path := range p.TestImports { p1 := loadImport(path, p.Dir, &stk, p.build.TestImportPos[path]) if p1.Error != nil { return nil, nil, nil, p1.Error } + if contains(p1.Deps, p.ImportPath) { + // Same error that loadPackage returns (via reusePackage) in pkg.go. + // Can't change that code, because that code is only for loading the + // non-test copy of a package. + err := &PackageError{ + ImportStack: testImportStack(stk[0], p1, p.ImportPath), + Err: "import cycle not allowed in test", + isImportCycle: true, + } + return nil, nil, nil, err + } imports = append(imports, p1) } + stk.pop() + stk.push(p.ImportPath + "_test") + pxtestNeedsPtest := false for _, path := range p.XTestImports { if path == p.ImportPath { + pxtestNeedsPtest = true continue } p1 := loadImport(path, p.Dir, &stk, p.build.XTestImportPos[path]) @@ -618,7 +641,10 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, if localCover { ptest.coverMode = testCoverMode - ptest.coverVars = declareCoverVars(ptest.ImportPath, ptest.GoFiles...) + var coverFiles []string + coverFiles = append(coverFiles, ptest.GoFiles...) + coverFiles = append(coverFiles, ptest.CgoFiles...) + ptest.coverVars = declareCoverVars(ptest.ImportPath, coverFiles...) } } else { ptest = p @@ -637,11 +663,14 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, build: &build.Package{ ImportPos: p.build.XTestImportPos, }, - imports: append(ximports, ptest), + imports: ximports, pkgdir: testDir, fake: true, Stale: true, } + if pxtestNeedsPtest { + pxtest.imports = append(pxtest.imports, ptest) + } } // Action for building pkg.test. @@ -651,21 +680,20 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, GoFiles: []string{"_testmain.go"}, ImportPath: "testmain", Root: p.Root, - imports: []*Package{ptest}, build: &build.Package{Name: "main"}, pkgdir: testDir, fake: true, Stale: true, - } - if pxtest != nil { - pmain.imports = append(pmain.imports, pxtest) + omitDWARF: !testC && !testNeedBinary, } // The generated main also imports testing and regexp. stk.push("testmain") for dep := range testMainDeps { - if ptest.ImportPath != dep { - p1 := loadImport("testing", "", &stk, nil) + if dep == ptest.ImportPath { + pmain.imports = append(pmain.imports, ptest) + } else { + p1 := loadImport(dep, "", &stk, nil) if p1.Error != nil { return nil, nil, nil, p1.Error } @@ -687,6 +715,21 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, } } + // Do initial scan for metadata needed for writing _testmain.go + // Use that metadata to update the list of imports for package main. + // The list of imports is used by recompileForTest and by the loop + // afterward that gathers t.Cover information. + t, err := loadTestFuncs(ptest) + if err != nil { + return nil, nil, nil, err + } + if t.NeedTest || ptest.coverMode != "" { + pmain.imports = append(pmain.imports, ptest) + } + if t.NeedXtest { + pmain.imports = append(pmain.imports, pxtest) + } + if ptest != p && localCover { // We have made modifications to the package p being tested // and are rebuilding p (as ptest), writing it to the testDir tree. @@ -703,7 +746,15 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, recompileForTest(pmain, p, ptest, testDir) } - if err := writeTestmain(filepath.Join(testDir, "_testmain.go"), pmain, ptest); err != nil { + for _, cp := range pmain.imports { + if len(cp.coverVars) > 0 { + t.Cover = append(t.Cover, coverInfo{cp, cp.coverVars}) + } + } + + // writeTestmain writes _testmain.go. This must happen after recompileForTest, + // because recompileForTest modifies XXX. + if err := writeTestmain(filepath.Join(testDir, "_testmain.go"), t); err != nil { return nil, nil, nil, err } @@ -711,7 +762,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, if ptest != p { a := b.action(modeBuild, modeBuild, ptest) - a.objdir = testDir + string(filepath.Separator) + a.objdir = testDir + string(filepath.Separator) + "_obj_test" + string(filepath.Separator) a.objpkg = ptestObj a.target = ptestObj a.link = false @@ -719,7 +770,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, if pxtest != nil { a := b.action(modeBuild, modeBuild, pxtest) - a.objdir = testDir + string(filepath.Separator) + a.objdir = testDir + string(filepath.Separator) + "_obj_xtest" + string(filepath.Separator) a.objpkg = buildToolchain.pkgpath(testDir, pxtest) a.target = a.objpkg } @@ -765,6 +816,24 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, return pmainAction, runAction, printAction, nil } +func testImportStack(top string, p *Package, target string) []string { + stk := []string{top, p.ImportPath} +Search: + for p.ImportPath != target { + for _, p1 := range p.imports { + if p1.ImportPath == target || contains(p1.Deps, target) { + stk = append(stk, p1.ImportPath) + p = p1 + continue Search + } + } + // Can't happen, but in case it does... + stk = append(stk, "<lost path to cycle>") + break + } + return stk +} + func recompileForTest(pmain, preal, ptest *Package, testDir string) { // The "test copy" of preal is ptest. // For each package that depends on preal, make a "test copy" @@ -836,7 +905,7 @@ func declareCoverVars(importPath string, files ...string) map[string]*CoverVar { // runTest is the action for running a test binary. func (b *builder) runTest(a *action) error { - args := stringList(a.deps[0].target, testArgs) + args := stringList(findExecCmd(), a.deps[0].target, testArgs) a.testOutput = new(bytes.Buffer) if buildN || buildX { @@ -1007,31 +1076,26 @@ type coverInfo struct { Vars map[string]*CoverVar } -// writeTestmain writes the _testmain.go file for package p to -// the file named out. -func writeTestmain(out string, pmain, p *Package) error { - var cover []coverInfo - for _, cp := range pmain.imports { - if len(cp.coverVars) > 0 { - cover = append(cover, coverInfo{cp, cp.coverVars}) - } - } - +// loadTestFuncs returns the testFuncs describing the tests that will be run. +func loadTestFuncs(ptest *Package) (*testFuncs, error) { t := &testFuncs{ - Package: p, - Cover: cover, + Package: ptest, } - for _, file := range p.TestGoFiles { - if err := t.load(filepath.Join(p.Dir, file), "_test", &t.NeedTest); err != nil { - return err + for _, file := range ptest.TestGoFiles { + if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.NeedTest); err != nil { + return nil, err } } - for _, file := range p.XTestGoFiles { - if err := t.load(filepath.Join(p.Dir, file), "_xtest", &t.NeedXtest); err != nil { - return err + for _, file := range ptest.XTestGoFiles { + if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.NeedXtest); err != nil { + return nil, err } } + return t, nil +} +// writeTestmain writes the _testmain.go file for t to the file named out. +func writeTestmain(out string, t *testFuncs) error { f, err := os.Create(out) if err != nil { return err |