all: remove coverageredesign experiment

The coverageredesign experiment was turned on by default by
CL 436236 in September, 2022. We've documented it and people
are using it. This CL removes the ability to turn off the experiment.
This removes some old code that is no longer being executed.

For #51430

Change-Id: I88d4998c8b5ea98eef8145d7ca6ebd96f64fbc2b
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest,gotip-darwin-amd64-longtest,gotip-linux-arm64-longtest,gotip-windows-amd64-longtest
Reviewed-on: https://go-review.googlesource.com/c/go/+/644997
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Than McIntosh <thanm@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Commit-Queue: Ian Lance Taylor <iant@google.com>
This commit is contained in:
Ian Lance Taylor 2025-01-28 11:27:22 -08:00 committed by Gopher Robot
parent 26c59d3153
commit 41298239cf
33 changed files with 106 additions and 531 deletions

View File

@ -375,10 +375,6 @@ func TestIssue56044(t *testing.T) {
if testing.Short() { if testing.Short() {
t.Skipf("skipping test: too long for short mode") t.Skipf("skipping test: too long for short mode")
} }
if !goexperiment.CoverageRedesign {
t.Skipf("skipping new coverage tests (experiment not enabled)")
}
testenv.MustHaveGoBuild(t) testenv.MustHaveGoBuild(t)
modes := []string{"-covermode=set", "-covermode=atomic"} modes := []string{"-covermode=set", "-covermode=atomic"}

View File

@ -9,7 +9,6 @@ import (
"flag" "flag"
"fmt" "fmt"
"internal/coverage/pods" "internal/coverage/pods"
"internal/goexperiment"
"internal/testenv" "internal/testenv"
"log" "log"
"os" "os"
@ -150,9 +149,6 @@ const debugWorkDir = false
func TestCovTool(t *testing.T) { func TestCovTool(t *testing.T) {
testenv.MustHaveGoBuild(t) testenv.MustHaveGoBuild(t)
if !goexperiment.CoverageRedesign {
t.Skipf("stubbed out due to goexperiment.CoverageRedesign=false")
}
dir := tempDir(t) dir := tempDir(t)
if testing.Short() { if testing.Short() {
t.Skip() t.Skip()

View File

@ -2484,7 +2484,6 @@
// GOCOVERDIR // GOCOVERDIR
// Directory into which to write code coverage data files // Directory into which to write code coverage data files
// generated by running a "go build -cover" binary. // generated by running a "go build -cover" binary.
// Requires that GOEXPERIMENT=coverageredesign is enabled.
// //
// Special-purpose environment variables: // Special-purpose environment variables:
// //

View File

@ -657,7 +657,6 @@ Environment variables for use with code coverage:
GOCOVERDIR GOCOVERDIR
Directory into which to write code coverage data files Directory into which to write code coverage data files
generated by running a "go build -cover" binary. generated by running a "go build -cover" binary.
Requires that GOEXPERIMENT=coverageredesign is enabled.
Special-purpose environment variables: Special-purpose environment variables:

View File

@ -347,9 +347,7 @@ func init() {
CmdList.Run = runList // break init cycle CmdList.Run = runList // break init cycle
// Omit build -json because list has its own -json // Omit build -json because list has its own -json
work.AddBuildFlags(CmdList, work.OmitJSONFlag) work.AddBuildFlags(CmdList, work.OmitJSONFlag)
if cfg.Experiment != nil && cfg.Experiment.CoverageRedesign { work.AddCoverFlags(CmdList, nil)
work.AddCoverFlags(CmdList, nil)
}
CmdList.Flag.Var(&listJsonFields, "json", "") CmdList.Flag.Var(&listJsonFields, "json", "")
} }
@ -728,7 +726,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
b.IsCmdList = true b.IsCmdList = true
b.NeedExport = *listExport b.NeedExport = *listExport
b.NeedCompiledGoFiles = *listCompiled b.NeedCompiledGoFiles = *listCompiled
if cfg.Experiment.CoverageRedesign && cfg.BuildCover { if cfg.BuildCover {
load.PrepareForCoverageBuild(pkgs) load.PrepareForCoverageBuild(pkgs)
} }
a := &work.Action{} a := &work.Action{}

View File

@ -8,7 +8,6 @@ package load
import ( import (
"bytes" "bytes"
"context" "context"
"crypto/sha256"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -218,27 +217,26 @@ func (p *Package) IsTestOnly() bool {
type PackageInternal struct { type PackageInternal struct {
// Unexported fields are not part of the public API. // Unexported fields are not part of the public API.
Build *build.Package Build *build.Package
Imports []*Package // this package's direct imports Imports []*Package // this package's direct imports
CompiledImports []string // additional Imports necessary when using CompiledGoFiles (all from standard library); 1:1 with the end of PackagePublic.Imports CompiledImports []string // additional Imports necessary when using CompiledGoFiles (all from standard library); 1:1 with the end of PackagePublic.Imports
RawImports []string // this package's original imports as they appear in the text of the program; 1:1 with the end of PackagePublic.Imports RawImports []string // this package's original imports as they appear in the text of the program; 1:1 with the end of PackagePublic.Imports
ForceLibrary bool // this package is a library (even if named "main") ForceLibrary bool // this package is a library (even if named "main")
CmdlineFiles bool // package built from files listed on command line CmdlineFiles bool // package built from files listed on command line
CmdlinePkg bool // package listed on command line CmdlinePkg bool // package listed on command line
CmdlinePkgLiteral bool // package listed as literal on command line (not via wildcard) CmdlinePkgLiteral bool // package listed as literal on command line (not via wildcard)
Local bool // imported via local path (./ or ../) Local bool // imported via local path (./ or ../)
LocalPrefix string // interpret ./ and ../ imports relative to this prefix LocalPrefix string // interpret ./ and ../ imports relative to this prefix
ExeName string // desired name for temporary executable ExeName string // desired name for temporary executable
FuzzInstrument bool // package should be instrumented for fuzzing FuzzInstrument bool // package should be instrumented for fuzzing
Cover CoverSetup // coverage mode and other setup info of -cover is being applied to this package Cover CoverSetup // coverage mode and other setup info of -cover is being applied to this package
CoverVars map[string]*CoverVar // variables created by coverage analysis OmitDebug bool // tell linker not to write debug information
OmitDebug bool // tell linker not to write debug information GobinSubdir bool // install target would be subdir of GOBIN
GobinSubdir bool // install target would be subdir of GOBIN BuildInfo *debug.BuildInfo // add this info to package main
BuildInfo *debug.BuildInfo // add this info to package main TestmainGo *[]byte // content for _testmain.go
TestmainGo *[]byte // content for _testmain.go Embed map[string][]string // //go:embed comment mapping
Embed map[string][]string // //go:embed comment mapping OrigImportPath string // original import path before adding '_test' suffix
OrigImportPath string // original import path before adding '_test' suffix PGOProfile string // path to PGO profile
PGOProfile string // path to PGO profile ForMain string // the main package if this package is built specifically for it
ForMain string // the main package if this package is built specifically for it
Asmflags []string // -asmflags for this package Asmflags []string // -asmflags for this package
Gcflags []string // -gcflags for this package Gcflags []string // -gcflags for this package
@ -372,12 +370,6 @@ func (p *Package) Resolve(imports []string) []string {
return all return all
} }
// CoverVar holds the name of the generated coverage variables targeting the named file.
type CoverVar struct {
File string // local file name
Var string // name of count struct
}
// CoverSetup holds parameters related to coverage setup for a given package (covermode, etc). // CoverSetup holds parameters related to coverage setup for a given package (covermode, etc).
type CoverSetup struct { type CoverSetup struct {
Mode string // coverage mode for this package Mode string // coverage mode for this package
@ -2627,7 +2619,7 @@ func LinkerDeps(p *Package) ([]string, error) {
deps = append(deps, "runtime/asan") deps = append(deps, "runtime/asan")
} }
// Building for coverage forces an import of runtime/coverage. // Building for coverage forces an import of runtime/coverage.
if cfg.BuildCover && cfg.Experiment.CoverageRedesign { if cfg.BuildCover {
deps = append(deps, "runtime/coverage") deps = append(deps, "runtime/coverage")
} }
@ -3568,14 +3560,6 @@ func SelectCoverPackages(roots []*Package, match []func(*Package) bool, op strin
if cfg.BuildCoverMode == "atomic" { if cfg.BuildCoverMode == "atomic" {
EnsureImport(p, "sync/atomic") EnsureImport(p, "sync/atomic")
} }
// Generate covervars if using legacy coverage design.
if !cfg.Experiment.CoverageRedesign {
var coverFiles []string
coverFiles = append(coverFiles, p.GoFiles...)
coverFiles = append(coverFiles, p.CgoFiles...)
p.Internal.CoverVars = DeclareCoverVars(p, coverFiles...)
}
} }
// Warn about -coverpkg arguments that are not actually used. // Warn about -coverpkg arguments that are not actually used.
@ -3587,42 +3571,3 @@ func SelectCoverPackages(roots []*Package, match []func(*Package) bool, op strin
return covered return covered
} }
// DeclareCoverVars attaches the required cover variables names
// to the files, to be used when annotating the files. This
// function only called when using legacy coverage test/build
// (e.g. GOEXPERIMENT=coverageredesign is off).
func DeclareCoverVars(p *Package, files ...string) map[string]*CoverVar {
coverVars := make(map[string]*CoverVar)
coverIndex := 0
// We create the cover counters as new top-level variables in the package.
// We need to avoid collisions with user variables (GoCover_0 is unlikely but still)
// and more importantly with dot imports of other covered packages,
// so we append 12 hex digits from the SHA-256 of the import path.
// The point is only to avoid accidents, not to defeat users determined to
// break things.
sum := sha256.Sum256([]byte(p.ImportPath))
h := fmt.Sprintf("%x", sum[:6])
for _, file := range files {
if base.IsTestFile(file) {
continue
}
// For a package that is "local" (imported via ./ import or command line, outside GOPATH),
// we record the full path to the file name.
// Otherwise we record the import path, then a forward slash, then the file name.
// This makes profiles within GOPATH file system-independent.
// These names appear in the cmd/cover HTML interface.
var longFile string
if p.Internal.Local {
longFile = filepath.Join(p.Dir, file)
} else {
longFile = pathpkg.Join(p.ImportPath, file)
}
coverVars[file] = &CoverVar{
File: longFile,
Var: fmt.Sprintf("GoCover_%d_%x", coverIndex, h),
}
coverIndex++
}
return coverVars
}

View File

@ -23,7 +23,6 @@ import (
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
"cmd/go/internal/cfg"
"cmd/go/internal/fsys" "cmd/go/internal/fsys"
"cmd/go/internal/str" "cmd/go/internal/str"
"cmd/go/internal/trace" "cmd/go/internal/trace"
@ -42,7 +41,6 @@ type TestCover struct {
Local bool Local bool
Pkgs []*Package Pkgs []*Package
Paths []string Paths []string
Vars []coverInfo
} }
// TestPackagesFor is like TestPackagesAndErrors but it returns // TestPackagesFor is like TestPackagesAndErrors but it returns
@ -309,7 +307,7 @@ func TestPackagesAndErrors(ctx context.Context, done func(), opts PackageOpts, p
// Also the linker introduces implicit dependencies reported by LinkerDeps. // Also the linker introduces implicit dependencies reported by LinkerDeps.
stk.Push(ImportInfo{Pkg: "testmain"}) stk.Push(ImportInfo{Pkg: "testmain"})
deps := TestMainDeps // cap==len, so safe for append deps := TestMainDeps // cap==len, so safe for append
if cover != nil && cfg.Experiment.CoverageRedesign { if cover != nil {
deps = append(deps, "internal/coverage/cfile") deps = append(deps, "internal/coverage/cfile")
} }
ldDeps, err := LinkerDeps(p) ldDeps, err := LinkerDeps(p)
@ -334,22 +332,6 @@ func TestPackagesAndErrors(ctx context.Context, done func(), opts PackageOpts, p
stk.Pop() stk.Pop()
parallelizablePart := func() { parallelizablePart := func() {
if cover != nil && cover.Pkgs != nil && !cfg.Experiment.CoverageRedesign {
// Add imports, but avoid duplicates.
seen := map[*Package]bool{p: true, ptest: true}
for _, p1 := range pmain.Internal.Imports {
seen[p1] = true
}
for _, p1 := range cover.Pkgs {
if seen[p1] {
// Don't add duplicate imports.
continue
}
seen[p1] = true
pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
}
}
allTestImports := make([]*Package, 0, len(pmain.Internal.Imports)+len(imports)+len(ximports)) allTestImports := make([]*Package, 0, len(pmain.Internal.Imports)+len(imports)+len(ximports))
allTestImports = append(allTestImports, pmain.Internal.Imports...) allTestImports = append(allTestImports, pmain.Internal.Imports...)
allTestImports = append(allTestImports, imports...) allTestImports = append(allTestImports, imports...)
@ -397,35 +379,19 @@ func TestPackagesAndErrors(ctx context.Context, done func(), opts PackageOpts, p
} }
if cover != nil { if cover != nil {
if cfg.Experiment.CoverageRedesign { // Here ptest needs to inherit the proper coverage mode (since
// Here ptest needs to inherit the proper coverage mode (since // it contains p's Go files), whereas pmain contains only
// it contains p's Go files), whereas pmain contains only // test harness code (don't want to instrument it, and
// test harness code (don't want to instrument it, and // we don't want coverage hooks in the pkg init).
// we don't want coverage hooks in the pkg init). ptest.Internal.Cover.Mode = p.Internal.Cover.Mode
ptest.Internal.Cover.Mode = p.Internal.Cover.Mode pmain.Internal.Cover.Mode = "testmain"
pmain.Internal.Cover.Mode = "testmain"
}
// Should we apply coverage analysis locally, only for this // Should we apply coverage analysis locally, only for this
// package and only for this test? Yes, if -cover is on but // package and only for this test? Yes, if -cover is on but
// -coverpkg has not specified a list of packages for global // -coverpkg has not specified a list of packages for global
// coverage. // coverage.
if cover.Local { if cover.Local {
ptest.Internal.Cover.Mode = cover.Mode ptest.Internal.Cover.Mode = cover.Mode
if !cfg.Experiment.CoverageRedesign {
var coverFiles []string
coverFiles = append(coverFiles, ptest.GoFiles...)
coverFiles = append(coverFiles, ptest.CgoFiles...)
ptest.Internal.CoverVars = DeclareCoverVars(ptest, coverFiles...)
}
}
if !cfg.Experiment.CoverageRedesign {
for _, cp := range pmain.Internal.Imports {
if len(cp.Internal.CoverVars) > 0 {
t.Cover.Vars = append(t.Cover.Vars, coverInfo{cp, cp.Internal.CoverVars})
}
}
} }
} }
@ -625,11 +591,6 @@ func isTest(name, prefix string) bool {
return !unicode.IsLower(rune) return !unicode.IsLower(rune)
} }
type coverInfo struct {
Package *Package
Vars map[string]*CoverVar
}
// loadTestFuncs returns the testFuncs describing the tests that will be run. // loadTestFuncs returns the testFuncs describing the tests that will be run.
// The returned testFuncs is always non-nil, even if an error occurred while // The returned testFuncs is always non-nil, even if an error occurred while
// processing test files. // processing test files.
@ -655,9 +616,6 @@ func loadTestFuncs(ptest *Package) (*testFuncs, error) {
func formatTestmain(t *testFuncs) ([]byte, error) { func formatTestmain(t *testFuncs) ([]byte, error) {
var buf bytes.Buffer var buf bytes.Buffer
tmpl := testmainTmpl tmpl := testmainTmpl
if cfg.Experiment.CoverageRedesign {
tmpl = testmainTmplNewCoverage
}
if err := tmpl.Execute(&buf, t); err != nil { if err := tmpl.Execute(&buf, t); err != nil {
return nil, err return nil, err
} }
@ -825,119 +783,6 @@ var testmainTmpl = lazytemplate.New("main", `
package main package main
import (
"os"
{{if .TestMain}}
"reflect"
{{end}}
"testing"
"testing/internal/testdeps"
{{if .ImportTest}}
{{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
{{end}}
{{if .ImportXtest}}
{{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
{{end}}
{{if .Cover}}
{{range $i, $p := .Cover.Vars}}
_cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
{{end}}
{{end}}
)
var tests = []testing.InternalTest{
{{range .Tests}}
{"{{.Name}}", {{.Package}}.{{.Name}}},
{{end}}
}
var benchmarks = []testing.InternalBenchmark{
{{range .Benchmarks}}
{"{{.Name}}", {{.Package}}.{{.Name}}},
{{end}}
}
var fuzzTargets = []testing.InternalFuzzTarget{
{{range .FuzzTargets}}
{"{{.Name}}", {{.Package}}.{{.Name}}},
{{end}}
}
var examples = []testing.InternalExample{
{{range .Examples}}
{"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
{{end}}
}
func init() {
testdeps.ImportPath = {{.ImportPath | printf "%q"}}
}
{{if .Cover}}
// Only updated by init functions, so no need for atomicity.
var (
coverCounters = make(map[string][]uint32)
coverBlocks = make(map[string][]testing.CoverBlock)
)
func init() {
{{range $i, $p := .Cover.Vars}}
{{range $file, $cover := $p.Vars}}
coverRegisterFile({{printf "%q" $cover.File}}, _cover{{$i}}.{{$cover.Var}}.Count[:], _cover{{$i}}.{{$cover.Var}}.Pos[:], _cover{{$i}}.{{$cover.Var}}.NumStmt[:])
{{end}}
{{end}}
}
func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts []uint16) {
if 3*len(counter) != len(pos) || len(counter) != len(numStmts) {
panic("coverage: mismatched sizes")
}
if coverCounters[fileName] != nil {
// Already registered.
return
}
coverCounters[fileName] = counter
block := make([]testing.CoverBlock, len(counter))
for i := range counter {
block[i] = testing.CoverBlock{
Line0: pos[3*i+0],
Col0: uint16(pos[3*i+2]),
Line1: pos[3*i+1],
Col1: uint16(pos[3*i+2]>>16),
Stmts: numStmts[i],
}
}
coverBlocks[fileName] = block
}
{{end}}
func main() {
{{if .Cover}}
testing.RegisterCover(testing.Cover{
Mode: {{printf "%q" .Cover.Mode}},
Counters: coverCounters,
Blocks: coverBlocks,
CoveredPackages: {{printf "%q" .Covered}},
})
{{end}}
m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, fuzzTargets, examples)
{{with .TestMain}}
{{.Package}}.{{.Name}}(m)
os.Exit(int(reflect.ValueOf(m).Elem().FieldByName("exitCode").Int()))
{{else}}
os.Exit(m.Run())
{{end}}
}
`)
var testmainTmplNewCoverage = lazytemplate.New("main", `
// Code generated by 'go test'. DO NOT EDIT.
package main
import ( import (
"os" "os"
{{if .TestMain}} {{if .TestMain}}

View File

@ -66,9 +66,7 @@ func init() {
CmdRun.Run = runRun // break init loop CmdRun.Run = runRun // break init loop
work.AddBuildFlags(CmdRun, work.DefaultBuildFlags) work.AddBuildFlags(CmdRun, work.DefaultBuildFlags)
if cfg.Experiment != nil && cfg.Experiment.CoverageRedesign { work.AddCoverFlags(CmdRun, nil)
work.AddCoverFlags(CmdRun, nil)
}
CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "") CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "")
} }
@ -141,7 +139,7 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) {
cmdArgs := args[i:] cmdArgs := args[i:]
load.CheckPackageErrors([]*load.Package{p}) load.CheckPackageErrors([]*load.Package{p})
if cfg.Experiment.CoverageRedesign && cfg.BuildCover { if cfg.BuildCover {
load.PrepareForCoverageBuild([]*load.Package{p}) load.PrepareForCoverageBuild([]*load.Package{p})
} }

View File

@ -867,7 +867,7 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) {
// patterns. // patterns.
plist := load.TestPackageList(ctx, pkgOpts, pkgs) plist := load.TestPackageList(ctx, pkgOpts, pkgs)
testCoverPkgs = load.SelectCoverPackages(plist, match, "test") testCoverPkgs = load.SelectCoverPackages(plist, match, "test")
if cfg.Experiment.CoverageRedesign && len(testCoverPkgs) > 0 { if len(testCoverPkgs) > 0 {
// create a new singleton action that will collect up the // create a new singleton action that will collect up the
// meta-data files from all of the packages mentioned in // meta-data files from all of the packages mentioned in
// "-coverpkg" and write them to a summary file. This new // "-coverpkg" and write them to a summary file. This new
@ -984,9 +984,7 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) {
// later package. Note that if -coverpkg is in effect // later package. Note that if -coverpkg is in effect
// p.Internal.Cover.GenMeta will wind up being set for // p.Internal.Cover.GenMeta will wind up being set for
// all matching packages. // all matching packages.
if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 && if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 && cfg.BuildCoverPkg == nil {
cfg.BuildCoverPkg == nil &&
cfg.Experiment.CoverageRedesign {
p.Internal.Cover.GenMeta = true p.Internal.Cover.GenMeta = true
} }
} }
@ -1092,7 +1090,7 @@ var windowsBadWords = []string{
func builderTest(b *work.Builder, ctx context.Context, pkgOpts load.PackageOpts, p *load.Package, imported bool, writeCoverMetaAct *work.Action) (buildAction, runAction, printAction *work.Action, perr *load.Package, err error) { func builderTest(b *work.Builder, ctx context.Context, pkgOpts load.PackageOpts, p *load.Package, imported bool, writeCoverMetaAct *work.Action) (buildAction, runAction, printAction *work.Action, perr *load.Package, err error) {
if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
if cfg.BuildCover && cfg.Experiment.CoverageRedesign { if cfg.BuildCover {
if p.Internal.Cover.GenMeta { if p.Internal.Cover.GenMeta {
p.Internal.Cover.Mode = cfg.BuildCoverMode p.Internal.Cover.Mode = cfg.BuildCoverMode
} }
@ -1487,7 +1485,7 @@ func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action)
if p := a.Package; len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { if p := a.Package; len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
reportNoTestFiles := true reportNoTestFiles := true
if cfg.BuildCover && cfg.Experiment.CoverageRedesign && p.Internal.Cover.GenMeta { if cfg.BuildCover && p.Internal.Cover.GenMeta {
if err := sh.Mkdir(a.Objdir); err != nil { if err := sh.Mkdir(a.Objdir); err != nil {
return err return err
} }

View File

@ -247,10 +247,8 @@ func init() {
AddBuildFlags(CmdBuild, DefaultBuildFlags) AddBuildFlags(CmdBuild, DefaultBuildFlags)
AddBuildFlags(CmdInstall, DefaultBuildFlags) AddBuildFlags(CmdInstall, DefaultBuildFlags)
if cfg.Experiment != nil && cfg.Experiment.CoverageRedesign { AddCoverFlags(CmdBuild, nil)
AddCoverFlags(CmdBuild, nil) AddCoverFlags(CmdInstall, nil)
AddCoverFlags(CmdInstall, nil)
}
} }
// Note that flags consulted by other parts of the code // Note that flags consulted by other parts of the code
@ -361,26 +359,13 @@ func AddBuildFlags(cmd *base.Command, mask BuildFlagMask) {
cmd.Flag.StringVar(&cfg.DebugTrace, "debug-trace", "", "") cmd.Flag.StringVar(&cfg.DebugTrace, "debug-trace", "", "")
} }
// AddCoverFlags adds coverage-related flags to "cmd". If the // AddCoverFlags adds coverage-related flags to "cmd".
// CoverageRedesign experiment is enabled, we add -cover{mode,pkg} to // We add -cover{mode,pkg} to the build command and only
// the build command and only -coverprofile to the test command. If // -coverprofile to the test command.
// the CoverageRedesign experiment is disabled, -cover* flags are
// added only to the test command.
func AddCoverFlags(cmd *base.Command, coverProfileFlag *string) { func AddCoverFlags(cmd *base.Command, coverProfileFlag *string) {
addCover := false cmd.Flag.BoolVar(&cfg.BuildCover, "cover", false, "")
if cfg.Experiment != nil && cfg.Experiment.CoverageRedesign { cmd.Flag.Var(coverFlag{(*coverModeFlag)(&cfg.BuildCoverMode)}, "covermode", "")
// New coverage enabled: both build and test commands get cmd.Flag.Var(coverFlag{commaListFlag{&cfg.BuildCoverPkg}}, "coverpkg", "")
// coverage flags.
addCover = true
} else {
// New coverage disabled: only test command gets cover flags.
addCover = coverProfileFlag != nil
}
if addCover {
cmd.Flag.BoolVar(&cfg.BuildCover, "cover", false, "")
cmd.Flag.Var(coverFlag{(*coverModeFlag)(&cfg.BuildCoverMode)}, "covermode", "")
cmd.Flag.Var(coverFlag{commaListFlag{&cfg.BuildCoverPkg}}, "coverpkg", "")
}
if coverProfileFlag != nil { if coverProfileFlag != nil {
cmd.Flag.Var(coverFlag{V: stringFlag{coverProfileFlag}}, "coverprofile", "") cmd.Flag.Var(coverFlag{V: stringFlag{coverProfileFlag}}, "coverprofile", "")
} }
@ -515,7 +500,7 @@ func runBuild(ctx context.Context, cmd *base.Command, args []string) {
cfg.BuildO = "" cfg.BuildO = ""
} }
if cfg.Experiment.CoverageRedesign && cfg.BuildCover { if cfg.BuildCover {
load.PrepareForCoverageBuild(pkgs) load.PrepareForCoverageBuild(pkgs)
} }
@ -732,7 +717,7 @@ func runInstall(ctx context.Context, cmd *base.Command, args []string) {
} }
load.CheckPackageErrors(pkgs) load.CheckPackageErrors(pkgs)
if cfg.Experiment.CoverageRedesign && cfg.BuildCover { if cfg.BuildCover {
load.PrepareForCoverageBuild(pkgs) load.PrepareForCoverageBuild(pkgs)
} }

View File

@ -647,31 +647,18 @@ OverlayLoop:
var sourceFile string var sourceFile string
var coverFile string var coverFile string
var key string
if base, found := strings.CutSuffix(file, ".cgo1.go"); found { if base, found := strings.CutSuffix(file, ".cgo1.go"); found {
// cgo files have absolute paths // cgo files have absolute paths
base = filepath.Base(base) base = filepath.Base(base)
sourceFile = file sourceFile = file
coverFile = objdir + base + ".cgo1.go" coverFile = objdir + base + ".cgo1.go"
key = base + ".go"
} else { } else {
sourceFile = filepath.Join(p.Dir, file) sourceFile = filepath.Join(p.Dir, file)
coverFile = objdir + file coverFile = objdir + file
key = file
} }
coverFile = strings.TrimSuffix(coverFile, ".go") + ".cover.go" coverFile = strings.TrimSuffix(coverFile, ".go") + ".cover.go"
if cfg.Experiment.CoverageRedesign { infiles = append(infiles, sourceFile)
infiles = append(infiles, sourceFile) outfiles = append(outfiles, coverFile)
outfiles = append(outfiles, coverFile)
} else {
cover := p.Internal.CoverVars[key]
if cover == nil {
continue // Not covering this file.
}
if err := b.cover(a, coverFile, sourceFile, cover.Var); err != nil {
return err
}
}
if i < len(gofiles) { if i < len(gofiles) {
gofiles[i] = coverFile gofiles[i] = coverFile
} else { } else {
@ -679,36 +666,27 @@ OverlayLoop:
} }
} }
if cfg.Experiment.CoverageRedesign { if len(infiles) != 0 {
if len(infiles) != 0 { // Coverage instrumentation creates new top level
// Coverage instrumentation creates new top level // variables in the target package for things like
// variables in the target package for things like // meta-data containers, counter vars, etc. To avoid
// meta-data containers, counter vars, etc. To avoid // collisions with user variables, suffix the var name
// collisions with user variables, suffix the var name // with 12 hex digits from the SHA-256 hash of the
// with 12 hex digits from the SHA-256 hash of the // import path. Choice of 12 digits is historical/arbitrary,
// import path. Choice of 12 digits is historical/arbitrary, // we just need enough of the hash to avoid accidents,
// we just need enough of the hash to avoid accidents, // as opposed to precluding determined attempts by
// as opposed to precluding determined attempts by // users to break things.
// users to break things. sum := sha256.Sum256([]byte(a.Package.ImportPath))
sum := sha256.Sum256([]byte(a.Package.ImportPath)) coverVar := fmt.Sprintf("goCover_%x_", sum[:6])
coverVar := fmt.Sprintf("goCover_%x_", sum[:6]) mode := a.Package.Internal.Cover.Mode
mode := a.Package.Internal.Cover.Mode if mode == "" {
if mode == "" { panic("covermode should be set at this point")
panic("covermode should be set at this point") }
} if newoutfiles, err := b.cover(a, infiles, outfiles, coverVar, mode); err != nil {
if newoutfiles, err := b.cover2(a, infiles, outfiles, coverVar, mode); err != nil { return err
return err
} else {
outfiles = newoutfiles
gofiles = append([]string{newoutfiles[0]}, gofiles...)
}
} else { } else {
// If there are no input files passed to cmd/cover, outfiles = newoutfiles
// then we don't want to pass -covercfg when building gofiles = append([]string{newoutfiles[0]}, gofiles...)
// the package with the compiler, so set covermode to
// the empty string so as to signal that we need to do
// that.
p.Internal.Cover.Mode = ""
} }
if ba, ok := a.Actor.(*buildActor); ok && ba.covMetaFileName != "" { if ba, ok := a.Actor.(*buildActor); ok && ba.covMetaFileName != "" {
b.cacheObjdirFile(a, cache.Default(), ba.covMetaFileName) b.cacheObjdirFile(a, cache.Default(), ba.covMetaFileName)
@ -1909,26 +1887,13 @@ func (b *Builder) installHeader(ctx context.Context, a *Action) error {
// cover runs, in effect, // cover runs, in effect,
// //
// go tool cover -mode=b.coverMode -var="varName" -o dst.go src.go
func (b *Builder) cover(a *Action, dst, src string, varName string) error {
return b.Shell(a).run(a.Objdir, "", nil,
cfg.BuildToolexec,
base.Tool("cover"),
"-mode", a.Package.Internal.Cover.Mode,
"-var", varName,
"-o", dst,
src)
}
// cover2 runs, in effect,
//
// go tool cover -pkgcfg=<config file> -mode=b.coverMode -var="varName" -o <outfiles> <infiles> // go tool cover -pkgcfg=<config file> -mode=b.coverMode -var="varName" -o <outfiles> <infiles>
// //
// Return value is an updated output files list; in addition to the // Return value is an updated output files list; in addition to the
// regular outputs (instrumented source files) the cover tool also // regular outputs (instrumented source files) the cover tool also
// writes a separate file (appearing first in the list of outputs) // writes a separate file (appearing first in the list of outputs)
// that will contain coverage counters and meta-data. // that will contain coverage counters and meta-data.
func (b *Builder) cover2(a *Action, infiles, outfiles []string, varName string, mode string) ([]string, error) { func (b *Builder) cover(a *Action, infiles, outfiles []string, varName string, mode string) ([]string, error) {
pkgcfg := a.Objdir + "pkgcfg.txt" pkgcfg := a.Objdir + "pkgcfg.txt"
covoutputs := a.Objdir + "coveroutfiles.txt" covoutputs := a.Objdir + "coveroutfiles.txt"
odir := filepath.Dir(outfiles[0]) odir := filepath.Dir(outfiles[0])

View File

@ -5,7 +5,6 @@
# inside and outside the standard library. # inside and outside the standard library.
[short] skip [short] skip
[!GOEXPERIMENT:coverageredesign] skip
# Compile an object. # Compile an object.
go tool compile -p tiny tiny/tiny.go tiny/tiny2.go go tool compile -p tiny tiny/tiny.go tiny/tiny2.go

View File

@ -3,9 +3,6 @@
[short] skip [short] skip
# Skip if new coverage is not enabled.
[!GOEXPERIMENT:coverageredesign] skip
#------------------------------------------- #-------------------------------------------
# Build for coverage. # Build for coverage.

View File

@ -2,9 +2,6 @@
[short] skip [short] skip
# Hard-wire new coverage for this test.
env GOEXPERIMENT=coverageredesign
# Build for coverage. # Build for coverage.
go build -gcflags=-m -o example.exe -cover example/main & go build -gcflags=-m -o example.exe -cover example/main &
[race] go build -o examplewithrace.exe -race -cover example/main & [race] go build -o examplewithrace.exe -race -cover example/main &

View File

@ -16,7 +16,6 @@
# #
[short] skip [short] skip
[!GOEXPERIMENT:coverageredesign] skip
# Test all packages with -coverpkg=./... # Test all packages with -coverpkg=./...
go test -coverprofile=cov.p -coverpkg=./... ./... go test -coverprofile=cov.p -coverpkg=./... ./...

View File

@ -5,7 +5,6 @@
# do not, some have tests and some do not. # do not, some have tests and some do not.
[short] skip [short] skip
[!GOEXPERIMENT:coverageredesign] skip
# Verify correct statements percentages. We have a total of 10 # Verify correct statements percentages. We have a total of 10
# statements in the packages matched by "./..."; package "a" (for # statements in the packages matched by "./..."; package "a" (for

View File

@ -3,7 +3,6 @@
# build arguments (such as -cover, -covermode). See issue #57785. # build arguments (such as -cover, -covermode). See issue #57785.
[short] skip [short] skip
[!GOEXPERIMENT:coverageredesign] skip
env GOBIN=$WORK/bin env GOBIN=$WORK/bin

View File

@ -4,7 +4,6 @@
# the "main" package is handled. See issue 57169 for details. # the "main" package is handled. See issue 57169 for details.
[short] skip [short] skip
[!GOEXPERIMENT:coverageredesign] skip
# Build this program with -cover and run to collect a profile. # Build this program with -cover and run to collect a profile.

View File

@ -10,35 +10,32 @@ env GOCACHE=$WORK/cache
# Initial run with simple coverage. # Initial run with simple coverage.
go test -cover ./pkg1 ./pkg2 ./pkg3 ./pkg4 go test -cover ./pkg1 ./pkg2 ./pkg3 ./pkg4
[!GOEXPERIMENT:coverageredesign] stdout 'pkg1 \[no test files\]' stdout 'pkg1 coverage: 0.0% of statements'
[GOEXPERIMENT:coverageredesign] stdout 'pkg1 coverage: 0.0% of statements'
stdout 'pkg2 \S+ coverage: 0.0% of statements \[no tests to run\]' stdout 'pkg2 \S+ coverage: 0.0% of statements \[no tests to run\]'
stdout 'pkg3 \S+ coverage: 100.0% of statements' stdout 'pkg3 \S+ coverage: 100.0% of statements'
stdout 'pkg4 \S+ coverage: \[no statements\]' stdout 'pkg4 \S+ coverage: \[no statements\]'
# Second run to make sure that caching works properly. # Second run to make sure that caching works properly.
go test -x -cover ./pkg1 ./pkg2 ./pkg3 ./pkg4 go test -x -cover ./pkg1 ./pkg2 ./pkg3 ./pkg4
[!GOEXPERIMENT:coverageredesign] stdout 'pkg1 \[no test files\]' stdout 'pkg1 coverage: 0.0% of statements'
[GOEXPERIMENT:coverageredesign] stdout 'pkg1 coverage: 0.0% of statements'
stdout 'pkg2 \S+ coverage: 0.0% of statements \[no tests to run\]' stdout 'pkg2 \S+ coverage: 0.0% of statements \[no tests to run\]'
stdout 'pkg3 \S+ coverage: 100.0% of statements' stdout 'pkg3 \S+ coverage: 100.0% of statements'
stdout 'pkg4 \S+ coverage: \[no statements\]' stdout 'pkg4 \S+ coverage: \[no statements\]'
[GOEXPERIMENT:coverageredesign] ! stderr 'link(\.exe"?)? -' ! stderr 'link(\.exe"?)? -'
! stderr 'compile(\.exe"?)? -' ! stderr 'compile(\.exe"?)? -'
! stderr 'cover(\.exe"?)? -' ! stderr 'cover(\.exe"?)? -'
[GOEXPERIMENT:coverageredesign] stderr 'covdata(\.exe"?)? percent' stderr 'covdata(\.exe"?)? percent'
# Now add in -coverprofile. # Now add in -coverprofile.
go test -cover -coverprofile=cov.dat ./pkg1 ./pkg2 ./pkg3 ./pkg4 go test -cover -coverprofile=cov.dat ./pkg1 ./pkg2 ./pkg3 ./pkg4
[!GOEXPERIMENT:coverageredesign] stdout 'pkg1 \[no test files\]' stdout 'pkg1 coverage: 0.0% of statements'
[GOEXPERIMENT:coverageredesign] stdout 'pkg1 coverage: 0.0% of statements'
stdout 'pkg2 \S+ coverage: 0.0% of statements \[no tests to run\]' stdout 'pkg2 \S+ coverage: 0.0% of statements \[no tests to run\]'
stdout 'pkg3 \S+ coverage: 100.0% of statements' stdout 'pkg3 \S+ coverage: 100.0% of statements'
stdout 'pkg4 \S+ coverage: \[no statements\]' stdout 'pkg4 \S+ coverage: \[no statements\]'
# Validate # Validate
go tool cover -func=cov.dat go tool cover -func=cov.dat
[GOEXPERIMENT:coverageredesign] stdout 'pkg1/a.go:5:\s+F\s+0.0%' stdout 'pkg1/a.go:5:\s+F\s+0.0%'
-- go.mod -- -- go.mod --
module m module m

View File

@ -1,6 +1,5 @@
[short] skip [short] skip
[compiler:gccgo] skip # gccgo has no cover tool [compiler:gccgo] skip # gccgo has no cover tool
[!GOEXPERIMENT:coverageredesign] skip
go test -short -cover -covermode=atomic -coverpkg=coverdep/p1 coverdep go test -short -cover -covermode=atomic -coverpkg=coverdep/p1 coverdep

View File

@ -1,9 +1,6 @@
[short] skip [short] skip
# Hard-wire new coverage for this test.
env GOEXPERIMENT=coverageredesign
# Baseline run. # Baseline run.
go test -cover example/foo go test -cover example/foo
stdout 'coverage: 50.0% of statements$' stdout 'coverage: 50.0% of statements$'

View File

@ -4,9 +4,6 @@
[short] skip [short] skip
# Skip if new coverage is turned off.
[!GOEXPERIMENT:coverageredesign] skip
go test -cover example go test -cover example
-- go.mod -- -- go.mod --

View File

@ -2,7 +2,6 @@
# Rudimentary test of testing.Coverage(). # Rudimentary test of testing.Coverage().
[short] skip [short] skip
[!GOEXPERIMENT:coverageredesign] skip
# Simple test. # Simple test.
go test -v -cover -count=1 go test -v -cover -count=1

View File

@ -11,7 +11,6 @@ import (
"internal/coverage/decodecounter" "internal/coverage/decodecounter"
"internal/coverage/decodemeta" "internal/coverage/decodemeta"
"internal/coverage/pods" "internal/coverage/pods"
"internal/goexperiment"
"internal/testenv" "internal/testenv"
"os" "os"
"path/filepath" "path/filepath"
@ -45,9 +44,6 @@ func (v *visitor) Finish()
func TestIssue58411(t *testing.T) { func TestIssue58411(t *testing.T) {
testenv.MustHaveGoBuild(t) testenv.MustHaveGoBuild(t)
if !goexperiment.CoverageRedesign {
t.Skipf("skipping since this test requires 'go build -cover'")
}
// Build a tiny test program with -cover. Smallness is important; // Build a tiny test program with -cover. Smallness is important;
// it is one of the factors that triggers issue 58411. // it is one of the factors that triggers issue 58411.

View File

@ -74,13 +74,12 @@ func ParseGOEXPERIMENT(goos, goarch, goexp string) (*ExperimentFlags, error) {
} }
baseline := goexperiment.Flags{ baseline := goexperiment.Flags{
RegabiWrappers: regabiSupported, RegabiWrappers: regabiSupported,
RegabiArgs: regabiSupported, RegabiArgs: regabiSupported,
CoverageRedesign: true, AliasTypeParams: true,
AliasTypeParams: true, SwissMap: true,
SwissMap: true, SpinbitMutex: haveXchg8,
SpinbitMutex: haveXchg8, SyncHashTrieMap: true,
SyncHashTrieMap: true,
} }
// Start with the statically enabled set of experiments. // Start with the statically enabled set of experiments.

View File

@ -7,7 +7,6 @@ package cfile
import ( import (
"fmt" "fmt"
"internal/coverage" "internal/coverage"
"internal/goexperiment"
"internal/platform" "internal/platform"
"internal/testenv" "internal/testenv"
"os" "os"
@ -25,9 +24,6 @@ func TestCoverageApis(t *testing.T) {
if testing.Short() { if testing.Short() {
t.Skipf("skipping test: too long for short mode") t.Skipf("skipping test: too long for short mode")
} }
if !goexperiment.CoverageRedesign {
t.Skipf("skipping new coverage tests (experiment not enabled)")
}
testenv.MustHaveGoBuild(t) testenv.MustHaveGoBuild(t)
dir := t.TempDir() dir := t.TempDir()
if fixedTestDir { if fixedTestDir {
@ -465,9 +461,6 @@ func TestIssue56006EmitDataRaceCoverRunningGoroutine(t *testing.T) {
if testing.Short() { if testing.Short() {
t.Skipf("skipping test: too long for short mode") t.Skipf("skipping test: too long for short mode")
} }
if !goexperiment.CoverageRedesign {
t.Skipf("skipping new coverage tests (experiment not enabled)")
}
// This test requires "go test -race -cover", meaning that we need // This test requires "go test -race -cover", meaning that we need
// go build, go run, and "-race" support. // go build, go run, and "-race" support.

View File

@ -8,7 +8,6 @@ import (
"encoding/json" "encoding/json"
"flag" "flag"
"internal/coverage" "internal/coverage"
"internal/goexperiment"
"internal/testenv" "internal/testenv"
"os" "os"
"os/exec" "os/exec"
@ -32,9 +31,6 @@ func testGoCoverDir(t *testing.T) string {
// relying on other test paths will provide a better signal when // relying on other test paths will provide a better signal when
// running "go test -cover" for this package). // running "go test -cover" for this package).
func TestTestSupport(t *testing.T) { func TestTestSupport(t *testing.T) {
if !goexperiment.CoverageRedesign {
return
}
if testing.CoverMode() == "" { if testing.CoverMode() == "" {
return return
} }
@ -128,9 +124,6 @@ func genAuxMeta(t *testing.T, dstdir string) (string, string) {
} }
func TestAuxMetaDataFiles(t *testing.T) { func TestAuxMetaDataFiles(t *testing.T) {
if !goexperiment.CoverageRedesign {
return
}
if testing.CoverMode() == "" { if testing.CoverMode() == "" {
return return
} }

View File

@ -1,8 +0,0 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build !goexperiment.coverageredesign
package goexperiment
const CoverageRedesign = false
const CoverageRedesignInt = 0

View File

@ -1,8 +0,0 @@
// Code generated by mkconsts.go. DO NOT EDIT.
//go:build goexperiment.coverageredesign
package goexperiment
const CoverageRedesign = true
const CoverageRedesignInt = 1

View File

@ -83,10 +83,6 @@ type Flags struct {
// by default. // by default.
HeapMinimum512KiB bool HeapMinimum512KiB bool
// CoverageRedesign enables the new compiler-based code coverage
// tooling.
CoverageRedesign bool
// Arenas causes the "arena" standard library package to be visible // Arenas causes the "arena" standard library package to be visible
// to the outside world. // to the outside world.
Arenas bool Arenas bool

View File

@ -6,13 +6,6 @@
package testing package testing
import (
"fmt"
"internal/goexperiment"
"os"
"sync/atomic"
)
// CoverBlock records the coverage data for a single basic block. // CoverBlock records the coverage data for a single basic block.
// The fields are 1-indexed, as in an editor: The opening line of // The fields are 1-indexed, as in an editor: The opening line of
// the file is number 1, for example. Columns are measured // the file is number 1, for example. Columns are measured
@ -27,8 +20,6 @@ type CoverBlock struct {
Stmts uint16 // Number of statements included in this block. Stmts uint16 // Number of statements included in this block.
} }
var cover Cover
// Cover records information about test coverage checking. // 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.
@ -39,86 +30,8 @@ type Cover struct {
CoveredPackages string 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 {
if goexperiment.CoverageRedesign {
return coverage2()
}
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. // 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 RegisterCover(c Cover) { 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)
} }

View File

@ -8,49 +8,52 @@ package testing
import ( import (
"fmt" "fmt"
"internal/goexperiment"
"os" "os"
_ "unsafe" // for linkname _ "unsafe" // for linkname
) )
// cover2 variable stores the current coverage mode and a // cover variable stores the current coverage mode and a
// tear-down function to be called at the end of the testing run. // tear-down function to be called at the end of the testing run.
var cover2 struct { var cover struct {
mode string mode string
tearDown func(coverprofile string, gocoverdir string) (string, error) tearDown func(coverprofile string, gocoverdir string) (string, error)
snapshotcov func() float64 snapshotcov func() float64
} }
// registerCover2 is invoked during "go test -cover" runs. // registerCover is invoked during "go test -cover" runs.
// It is used to record a 'tear down' function // It is used to record a 'tear down' function
// (to be called when the test is complete) and the coverage mode. // (to be called when the test is complete) and the coverage mode.
func registerCover2(mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64) { func registerCover(mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64) {
if mode == "" { if mode == "" {
return return
} }
cover2.mode = mode cover.mode = mode
cover2.tearDown = tearDown cover.tearDown = tearDown
cover2.snapshotcov = snapcov cover.snapshotcov = snapcov
} }
// coverReport2 invokes a callback in _testmain.go that will // coverReport reports the coverage percentage and
// writes a coverage profile if requested.
// This invokes a callback in _testmain.go that will
// emit coverage data at the point where test execution is complete, // emit coverage data at the point where test execution is complete,
// for "go test -cover" runs. // for "go test -cover" runs.
func coverReport2() { func coverReport() {
if !goexperiment.CoverageRedesign { if errmsg, err := cover.tearDown(*coverProfile, *gocoverdir); err != nil {
panic("unexpected")
}
if errmsg, err := cover2.tearDown(*coverProfile, *gocoverdir); err != nil {
fmt.Fprintf(os.Stderr, "%s: %v\n", errmsg, err) fmt.Fprintf(os.Stderr, "%s: %v\n", errmsg, err)
os.Exit(2) os.Exit(2)
} }
} }
// coverage2 returns a rough "coverage percentage so far" // Coverage reports the current code coverage as a fraction in the range [0, 1].
// number to support the testing.Coverage() function. // If coverage is not enabled, Coverage returns 0.
func coverage2() float64 { //
if cover2.mode == "" { // 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 {
if cover.mode == "" {
return 0.0 return 0.0
} }
return cover2.snapshotcov() return cover.snapshotcov()
} }

View File

@ -403,7 +403,6 @@ import (
"errors" "errors"
"flag" "flag"
"fmt" "fmt"
"internal/goexperiment"
"internal/race" "internal/race"
"io" "io"
"math/rand" "math/rand"
@ -700,10 +699,7 @@ func Testing() bool {
// values are "set", "count", or "atomic". The return value will be // values are "set", "count", or "atomic". The return value will be
// empty if test coverage is not enabled. // empty if test coverage is not enabled.
func CoverMode() string { func CoverMode() string {
if goexperiment.CoverageRedesign { return cover.mode
return cover2.mode
}
return cover.Mode
} }
// Verbose reports whether the -test.v flag is set. // Verbose reports whether the -test.v flag is set.
@ -2021,7 +2017,7 @@ type testDeps interface {
// It is not meant to be called directly and is not subject to the Go 1 compatibility document. // It is not meant to be called directly and is not subject to the Go 1 compatibility document.
// It may change signature from release to release. // It may change signature from release to release.
func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M { func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M {
registerCover2(deps.InitRuntimeCoverage()) registerCover(deps.InitRuntimeCoverage())
Init() Init()
return &M{ return &M{
deps: deps, deps: deps,