diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go index 61af11af27..4a39a74443 100644 --- a/src/cmd/go/internal/load/test.go +++ b/src/cmd/go/internal/load/test.go @@ -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 index 0000000000..6cf6adbbd7 --- /dev/null +++ b/src/cmd/go/testdata/script/testing_coverage.txt @@ -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) + } +} + diff --git a/src/testing/cover.go b/src/testing/cover.go index b52e53a926..6ad43ab9ff 100644 --- a/src/testing/cover.go +++ b/src/testing/cover.go @@ -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 { diff --git a/src/testing/newcover.go b/src/testing/newcover.go index 1805f791e6..6199f3bd7b 100644 --- a/src/testing/newcover.go +++ b/src/testing/newcover.go @@ -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() +}