diff options
Diffstat (limited to 'src/testing/cover.go')
-rw-r--r-- | src/testing/cover.go | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/src/testing/cover.go b/src/testing/cover.go new file mode 100644 index 0000000..b52e53a --- /dev/null +++ b/src/testing/cover.go @@ -0,0 +1,121 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Support for test coverage. + +package testing + +import ( + "fmt" + "internal/goexperiment" + "os" + "sync/atomic" +) + +// CoverBlock records the coverage data for a single basic block. +// The fields are 1-indexed, as in an editor: The opening line of +// the file is number 1, for example. Columns are measured +// in bytes. +// NOTE: This struct is internal to the testing infrastructure and may change. +// It is not covered (yet) by the Go 1 compatibility guidelines. +type CoverBlock struct { + Line0 uint32 // Line number for block start. + Col0 uint16 // Column number for block start. + Line1 uint32 // Line number for block end. + Col1 uint16 // Column number for block end. + Stmts uint16 // Number of statements included in this block. +} + +var cover Cover + +// Cover records information about test coverage checking. +// NOTE: This struct is internal to the testing infrastructure and may change. +// It is not covered (yet) by the Go 1 compatibility guidelines. +type Cover struct { + Mode string + Counters map[string][]uint32 + Blocks map[string][]CoverBlock + CoveredPackages string +} + +// Coverage reports the current code coverage as a fraction in the range [0, 1]. +// If coverage is not enabled, Coverage returns 0. +// +// When running a large set of sequential test cases, checking Coverage after each one +// can be useful for identifying which test cases exercise new code paths. +// It is not a replacement for the reports generated by 'go test -cover' and +// 'go tool cover'. +func Coverage() float64 { + var n, d int64 + for _, counters := range cover.Counters { + for i := range counters { + if atomic.LoadUint32(&counters[i]) > 0 { + n++ + } + d++ + } + } + if d == 0 { + return 0 + } + return float64(n) / float64(d) +} + +// RegisterCover records the coverage data accumulators for the tests. +// NOTE: This function is internal to the testing infrastructure and may change. +// It is not covered (yet) by the Go 1 compatibility guidelines. +func RegisterCover(c Cover) { + cover = c +} + +// mustBeNil checks the error and, if present, reports it and exits. +func mustBeNil(err error) { + if err != nil { + fmt.Fprintf(os.Stderr, "testing: %s\n", err) + os.Exit(2) + } +} + +// coverReport reports the coverage percentage and writes a coverage profile if requested. +func coverReport() { + if goexperiment.CoverageRedesign { + coverReport2() + return + } + var f *os.File + var err error + if *coverProfile != "" { + f, err = os.Create(toOutputDir(*coverProfile)) + mustBeNil(err) + fmt.Fprintf(f, "mode: %s\n", cover.Mode) + defer func() { mustBeNil(f.Close()) }() + } + + var active, total int64 + var count uint32 + for name, counts := range cover.Counters { + blocks := cover.Blocks[name] + for i := range counts { + stmts := int64(blocks[i].Stmts) + total += stmts + count = atomic.LoadUint32(&counts[i]) // For -mode=atomic. + if count > 0 { + active += stmts + } + if f != nil { + _, err := fmt.Fprintf(f, "%s:%d.%d,%d.%d %d %d\n", name, + blocks[i].Line0, blocks[i].Col0, + blocks[i].Line1, blocks[i].Col1, + stmts, + count) + mustBeNil(err) + } + } + } + if total == 0 { + fmt.Println("coverage: [no statements]") + return + } + fmt.Printf("coverage: %.1f%% of statements%s\n", 100*float64(active)/float64(total), cover.CoveredPackages) +} |