]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go,testing: re-implement testing.Coverage
authorThan McIntosh <thanm@google.com>
Fri, 12 May 2023 12:48:32 +0000 (08:48 -0400)
committerThan McIntosh <thanm@google.com>
Tue, 23 May 2023 11:37:31 +0000 (11:37 +0000)
This patch revives the testing.Coverage() function, which takes a
snapshot of the coverage counters within an executing "go test -cover"
test binary and returns a percentage approximating the percent of
statements covered so far.

Fixes #59590.

Change-Id: I541d47a42d71c8fb2edc473d86c8951fa80f4ab0
Reviewed-on: https://go-review.googlesource.com/c/go/+/495450
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/go/internal/load/test.go
src/cmd/go/testdata/script/testing_coverage.txt [new file with mode: 0644]
src/testing/cover.go
src/testing/newcover.go

index 61af11af270647a639f04c9c5182b3a2670a068c..4a39a74443480c279216ac539262665c238584be 100644 (file)
@@ -932,11 +932,14 @@ func init() {
 func runtime_coverage_processCoverTestDir(dir string, cfile string, cmode string, cpkgs string) error
 
 //go:linkname testing_registerCover2 testing.registerCover2
-func testing_registerCover2(mode string, tearDown func(coverprofile string, gocoverdir string) (string, error))
+func testing_registerCover2(mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64)
 
 //go:linkname runtime_coverage_markProfileEmitted runtime/coverage.markProfileEmitted
 func runtime_coverage_markProfileEmitted(val bool)
 
+//go:linkname runtime_coverage_snapshot runtime/coverage.snapshot
+func runtime_coverage_snapshot() float64
+
 func coverTearDown(coverprofile string, gocoverdir string) (string, error) {
        var err error
        if gocoverdir == "" {
@@ -957,7 +960,7 @@ func coverTearDown(coverprofile string, gocoverdir string) (string, error) {
 
 func main() {
 {{if .Cover}}
-       testing_registerCover2({{printf "%q" .Cover.Mode}}, coverTearDown)
+       testing_registerCover2({{printf "%q" .Cover.Mode}}, coverTearDown, runtime_coverage_snapshot)
 {{end}}
        m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, fuzzTargets, examples)
 {{with .TestMain}}
diff --git a/src/cmd/go/testdata/script/testing_coverage.txt b/src/cmd/go/testdata/script/testing_coverage.txt
new file mode 100644 (file)
index 0000000..6cf6adb
--- /dev/null
@@ -0,0 +1,57 @@
+
+# Rudimentary test of testing.Coverage().
+
+[short] skip
+[!GOEXPERIMENT:coverageredesign] skip
+
+# Simple test.
+go test -v -cover -count=1
+
+# Make sure test still passes when test executable is built and
+# run outside the go command.
+go test -c -o t.exe -cover
+exec ./t.exe
+
+-- go.mod --
+module hello
+
+go 1.20
+-- hello.go --
+package hello
+
+func Hello() {
+       println("hello")
+}
+
+// contents not especially interesting, just need some code
+func foo(n int) int {
+       t := 0
+       for i := 0; i < n; i++ {
+               for j := 0; j < i; j++ {
+                       t += i ^ j
+                       if t == 1010101 {
+                               break
+                       }
+               }
+       }
+       return t
+}
+
+-- hello_test.go --
+package hello
+
+import "testing"
+
+func TestTestCoverage(t *testing.T) {
+       Hello()
+       C1 := testing.Coverage()
+       foo(29)
+       C2 := testing.Coverage()
+       if C1 == 0.0 || C2 == 0.0 {
+               t.Errorf("unexpected zero values C1=%f C2=%f", C1, C2)
+       }
+       if C1 >= C2 {
+               t.Errorf("testing.Coverage() not monotonically increasing C1=%f C2=%f", C1, C2)
+       }
+}
+
index b52e53a9268dd7d9a9619579d4a3689f1cca4f85..6ad43ab9ff4a8b0fe7ccfbd7e4d66b361dbabc33 100644 (file)
@@ -47,6 +47,9 @@ type Cover struct {
 // It is not a replacement for the reports generated by 'go test -cover' and
 // 'go tool cover'.
 func Coverage() float64 {
+       if goexperiment.CoverageRedesign {
+               return coverage2()
+       }
        var n, d int64
        for _, counters := range cover.Counters {
                for i := range counters {
index 1805f791e63dec7f23ae15c1aed9f4ee9fffb309..6199f3bd7ba680ed5247d14ba205aa69bb1e6f7f 100644 (file)
@@ -15,16 +15,18 @@ import (
 // cover2 variable stores the current coverage mode and a
 // tear-down function to be called at the end of the testing run.
 var cover2 struct {
-       mode     string
-       tearDown func(coverprofile string, gocoverdir string) (string, error)
+       mode        string
+       tearDown    func(coverprofile string, gocoverdir string) (string, error)
+       snapshotcov func() float64
 }
 
 // registerCover2 is invoked during "go test -cover" runs by the test harness
 // code in _testmain.go; it is used to record a 'tear down' function
 // (to be called when the test is complete) and the coverage mode.
-func registerCover2(mode string, tearDown func(coverprofile string, gocoverdir string) (string, error)) {
+func registerCover2(mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64) {
        cover2.mode = mode
        cover2.tearDown = tearDown
+       cover2.snapshotcov = snapcov
 }
 
 // coverReport2 invokes a callback in _testmain.go that will
@@ -46,3 +48,12 @@ func coverReport2() {
 func testGoCoverDir() string {
        return *gocoverdir
 }
+
+// coverage2 returns a rough "coverage percentage so far"
+// number to support the testing.Coverage() function.
+func coverage2() float64 {
+       if cover2.mode == "" {
+               return 0.0
+       }
+       return cover2.snapshotcov()
+}