Commit ccc45534 authored by Russ Cox's avatar Russ Cox

cmd/go, testing: streamline direct use of test binaries

Before:

        $ go test -c -cover fmt
        $ ./fmt.test -test.covermode=set
        PASS
        coverage: 65.1% of statements in strconv
        $

After:

        $ go test -c -cover fmt
        $ ./fmt.test
        PASS
        coverage: 65.1% of statements in strconv
        $

In addition to being cumbersome, the old flag didn't make sense:
the cover mode cannot be changed after the binary has been built.

Another useful effect of this CL is that if you happen to do

        $ go test -c -covermode=atomic fmt

and then forget you did that and run benchmarks,
the final line of the output (the coverage summary) reminds you
that you are benchmarking with coverage enabled, which might
not be what you want.

        $ ./fmt.test -test.bench .
        PASS
        BenchmarkSprintfEmpty	10000000	       217 ns/op
        BenchmarkSprintfString	 2000000	       755 ns/op
        BenchmarkSprintfInt	 2000000	       774 ns/op
        BenchmarkSprintfIntInt	 1000000	      1363 ns/op
        BenchmarkSprintfPrefixedInt	 1000000	      1501 ns/op
        BenchmarkSprintfFloat	 1000000	      1257 ns/op
        BenchmarkManyArgs	  500000	      5346 ns/op
        BenchmarkScanInts	    1000	   2562402 ns/op
        BenchmarkScanRecursiveInt	     500	   3189457 ns/op
        coverage: 91.4% of statements
        $

As part of passing the new mode setting in via _testmain.go, merge
the two registration mechanisms into one extensible mechanism
(a struct).

R=r
CC=golang-dev
https://golang.org/cl/11219043
parent 4419d7e5
...@@ -744,7 +744,6 @@ control the execution of any test: ...@@ -744,7 +744,6 @@ control the execution of any test:
-cover -cover
Enable coverage analysis. Enable coverage analysis.
TODO: This feature is not yet fully implemented.
-covermode set,count,atomic -covermode set,count,atomic
Set the mode for coverage analysis for the package[s] Set the mode for coverage analysis for the package[s]
...@@ -754,18 +753,18 @@ control the execution of any test: ...@@ -754,18 +753,18 @@ control the execution of any test:
count: int: how many times does this statement run? count: int: how many times does this statement run?
atomic: int: count, but correct in multithreaded tests; atomic: int: count, but correct in multithreaded tests;
significantly more expensive. significantly more expensive.
Implies -cover. Sets -cover.
-coverpkg pkg1,pkg2,pkg3 -coverpkg pkg1,pkg2,pkg3
Apply coverage analysis in each test to the given list of packages. Apply coverage analysis in each test to the given list of packages.
If this option is not present, each test applies coverage analysis to The default is for each test to analyze only the package being tested.
the package being tested. Packages are specified as import paths. Packages are specified as import paths.
Implies -cover. Sets -cover.
-coverprofile cover.out -coverprofile cover.out
Write a coverage profile to the specified file after all tests Write a coverage profile to the specified file after all tests
have passed. have passed.
Implies -cover. Sets -cover.
-cpu 1,2,4 -cpu 1,2,4
Specify a list of GOMAXPROCS values for which the tests or Specify a list of GOMAXPROCS values for which the tests or
......
...@@ -139,18 +139,18 @@ control the execution of any test: ...@@ -139,18 +139,18 @@ control the execution of any test:
count: int: how many times does this statement run? count: int: how many times does this statement run?
atomic: int: count, but correct in multithreaded tests; atomic: int: count, but correct in multithreaded tests;
significantly more expensive. significantly more expensive.
Implies -cover. Sets -cover.
-coverpkg pkg1,pkg2,pkg3 -coverpkg pkg1,pkg2,pkg3
Apply coverage analysis in each test to the given list of packages. Apply coverage analysis in each test to the given list of packages.
The default is for each test to analyze only the package being tested. The default is for each test to analyze only the package being tested.
Packages are specified as import paths. Packages are specified as import paths.
Implies -cover. Sets -cover.
-coverprofile cover.out -coverprofile cover.out
Write a coverage profile to the specified file after all tests Write a coverage profile to the specified file after all tests
have passed. have passed.
Implies -cover. Sets -cover.
-cpu 1,2,4 -cpu 1,2,4
Specify a list of GOMAXPROCS values for which the tests or Specify a list of GOMAXPROCS values for which the tests or
...@@ -1040,6 +1040,10 @@ type testFuncs struct { ...@@ -1040,6 +1040,10 @@ type testFuncs struct {
Cover []coverInfo Cover []coverInfo
} }
func (t *testFuncs) CoverMode() string {
return testCoverMode
}
func (t *testFuncs) CoverEnabled() bool { func (t *testFuncs) CoverEnabled() bool {
return testCover return testCover
} }
...@@ -1201,8 +1205,12 @@ func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts ...@@ -1201,8 +1205,12 @@ func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts
func main() { func main() {
{{if .CoverEnabled}} {{if .CoverEnabled}}
testing.CoveredPackage({{printf "%q" .Tested}}, {{printf "%q" .Covered}}) testing.RegisterCover(testing.Cover{
testing.RegisterCover(coverCounters, coverBlocks) Mode: {{printf "%q" .CoverMode}},
Counters: coverCounters,
Blocks: coverBlocks,
CoveredPackages: {{printf "%q" .Covered}},
})
{{end}} {{end}}
testing.Main(matchString, tests, benchmarks, examples) testing.Main(matchString, tests, benchmarks, examples)
} }
......
...@@ -28,7 +28,7 @@ var usageMessage = `Usage of go test: ...@@ -28,7 +28,7 @@ var usageMessage = `Usage of go test:
-benchmem=false: print memory allocation statistics for benchmarks -benchmem=false: print memory allocation statistics for benchmarks
-benchtime=1s: passes -test.benchtime to test -benchtime=1s: passes -test.benchtime to test
-cover=false: enable coverage analysis -cover=false: enable coverage analysis
-covermode="set": passes -test.covermode to test if -cover -covermode="set": specifies mode for coverage analysis
-coverpkg="": comma-separated list of packages for coverage analysis -coverpkg="": comma-separated list of packages for coverage analysis
-coverprofile="": passes -test.coverprofile to test if -cover -coverprofile="": passes -test.coverprofile to test if -cover
-cpu="": passes -test.cpu to test -cpu="": passes -test.cpu to test
...@@ -115,6 +115,7 @@ var testFlagDefn = []*testFlagSpec{ ...@@ -115,6 +115,7 @@ var testFlagDefn = []*testFlagSpec{
func testFlags(args []string) (packageNames, passToTest []string) { func testFlags(args []string) (packageNames, passToTest []string) {
inPkg := false inPkg := false
outputDir := "" outputDir := ""
testCoverMode = "set"
for i := 0; i < len(args); i++ { for i := 0; i < len(args); i++ {
if !strings.HasPrefix(args[i], "-") { if !strings.HasPrefix(args[i], "-") {
if !inPkg && packageNames == nil { if !inPkg && packageNames == nil {
...@@ -208,12 +209,7 @@ func testFlags(args []string) (packageNames, passToTest []string) { ...@@ -208,12 +209,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
passToTest = append(passToTest, "-test."+f.name+"="+value) passToTest = append(passToTest, "-test."+f.name+"="+value)
} }
} }
if testCover {
if testCoverMode == "" {
testCoverMode = "set"
}
passToTest = append(passToTest, "-test.covermode", testCoverMode)
}
// Tell the test what directory we're running in, so it can write the profiles there. // Tell the test what directory we're running in, so it can write the profiles there.
if testProfile && outputDir == "" { if testProfile && outputDir == "" {
dir, err := os.Getwd() dir, err := os.Getwd()
......
...@@ -22,30 +22,23 @@ type CoverBlock struct { ...@@ -22,30 +22,23 @@ type CoverBlock struct {
Stmts uint16 Stmts uint16
} }
var ( var cover Cover
coverCounters map[string][]uint32
coverBlocks map[string][]CoverBlock
)
var (
testedPackage string // The package being tested.
coveredPackage string // List of the package[s] being covered, if distinct from the tested package.
)
// RegisterCover records the coverage data accumulators for the tests. // Cover records information about test coverage checking.
// NOTE: This struct is internal to the testing infrastructure and may change. // NOTE: This struct is internal to the testing infrastructure and may change.
// It is not covered (yet) by the Go 1 compatibility guidelines. // It is not covered (yet) by the Go 1 compatibility guidelines.
func RegisterCover(c map[string][]uint32, b map[string][]CoverBlock) { type Cover struct {
coverCounters = c Mode string
coverBlocks = b Counters map[string][]uint32
Blocks map[string][]CoverBlock
CoveredPackages string
} }
// CoveredPackage records the names of the packages being tested and covered. // RegisterCover records the coverage data accumulators for the tests.
// NOTE: This function is internal to the testing infrastructure and may change. // NOTE: This function is internal to the testing infrastructure and may change.
// It is not covered (yet) by the Go 1 compatibility guidelines. // It is not covered (yet) by the Go 1 compatibility guidelines.
func CoveredPackage(tested, covered string) { func RegisterCover(c Cover) {
testedPackage = tested cover = c
coveredPackage = covered
} }
// mustBeNil checks the error and, if present, reports it and exits. // mustBeNil checks the error and, if present, reports it and exits.
...@@ -63,13 +56,13 @@ func coverReport() { ...@@ -63,13 +56,13 @@ func coverReport() {
if *coverProfile != "" { if *coverProfile != "" {
f, err = os.Create(toOutputDir(*coverProfile)) f, err = os.Create(toOutputDir(*coverProfile))
mustBeNil(err) mustBeNil(err)
fmt.Fprintf(f, "mode: %s\n", *coverMode) fmt.Fprintf(f, "mode: %s\n", cover.Mode)
defer func() { mustBeNil(f.Close()) }() defer func() { mustBeNil(f.Close()) }()
} }
var active, total int64 var active, total int64
for name, counts := range coverCounters { for name, counts := range cover.Counters {
blocks := coverBlocks[name] blocks := cover.Blocks[name]
for i, count := range counts { for i, count := range counts {
stmts := int64(blocks[i].Stmts) stmts := int64(blocks[i].Stmts)
total += stmts total += stmts
...@@ -89,5 +82,5 @@ func coverReport() { ...@@ -89,5 +82,5 @@ func coverReport() {
if total == 0 { if total == 0 {
total = 1 total = 1
} }
fmt.Printf("coverage: %.1f%% of statements%s\n", 100*float64(active)/float64(total), coveredPackage) fmt.Printf("coverage: %.1f%% of statements%s\n", 100*float64(active)/float64(total), cover.CoveredPackages)
} }
...@@ -122,8 +122,7 @@ var ( ...@@ -122,8 +122,7 @@ var (
// Report as tests are run; default is silent for success. // Report as tests are run; default is silent for success.
chatty = flag.Bool("test.v", false, "verbose: print additional output") chatty = flag.Bool("test.v", false, "verbose: print additional output")
coverMode = flag.String("test.covermode", "", "cover mode: set, count, atomic; default is none") coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to the named file after execution")
coverProfile = flag.String("test.coverprofile", "", "write a coveraage profile to the named file after execution")
match = flag.String("test.run", "", "regular expression to select tests and examples to run") match = flag.String("test.run", "", "regular expression to select tests and examples to run")
memProfile = flag.String("test.memprofile", "", "write a memory profile to the named file after execution") memProfile = flag.String("test.memprofile", "", "write a memory profile to the named file after execution")
memProfileRate = flag.Int("test.memprofilerate", 0, "if >=0, sets runtime.MemProfileRate") memProfileRate = flag.Int("test.memprofilerate", 0, "if >=0, sets runtime.MemProfileRate")
...@@ -489,6 +488,10 @@ func before() { ...@@ -489,6 +488,10 @@ func before() {
if *blockProfile != "" && *blockProfileRate >= 0 { if *blockProfile != "" && *blockProfileRate >= 0 {
runtime.SetBlockProfileRate(*blockProfileRate) runtime.SetBlockProfileRate(*blockProfileRate)
} }
if *coverProfile != "" && cover.Mode == "" {
fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n")
os.Exit(2)
}
} }
// after runs after all testing. // after runs after all testing.
...@@ -520,7 +523,7 @@ func after() { ...@@ -520,7 +523,7 @@ func after() {
} }
f.Close() f.Close()
} }
if *coverMode != "" { if cover.Mode != "" {
coverReport() coverReport()
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment