if testing.Short() {
t.Skipf("skipping test: too long for short mode")
}
- if !goexperiment.CoverageRedesign {
- t.Skipf("skipping new coverage tests (experiment not enabled)")
- }
-
testenv.MustHaveGoBuild(t)
modes := []string{"-covermode=set", "-covermode=atomic"}
"flag"
"fmt"
"internal/coverage/pods"
- "internal/goexperiment"
"internal/testenv"
"log"
"os"
func TestCovTool(t *testing.T) {
testenv.MustHaveGoBuild(t)
- if !goexperiment.CoverageRedesign {
- t.Skipf("stubbed out due to goexperiment.CoverageRedesign=false")
- }
dir := tempDir(t)
if testing.Short() {
t.Skip()
// GOCOVERDIR
// Directory into which to write code coverage data files
// generated by running a "go build -cover" binary.
-// Requires that GOEXPERIMENT=coverageredesign is enabled.
//
// Special-purpose environment variables:
//
GOCOVERDIR
Directory into which to write code coverage data files
generated by running a "go build -cover" binary.
- Requires that GOEXPERIMENT=coverageredesign is enabled.
Special-purpose environment variables:
CmdList.Run = runList // break init cycle
// Omit build -json because list has its own -json
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", "")
}
b.IsCmdList = true
b.NeedExport = *listExport
b.NeedCompiledGoFiles = *listCompiled
- if cfg.Experiment.CoverageRedesign && cfg.BuildCover {
+ if cfg.BuildCover {
load.PrepareForCoverageBuild(pkgs)
}
a := &work.Action{}
import (
"bytes"
"context"
- "crypto/sha256"
"encoding/json"
"errors"
"fmt"
type PackageInternal struct {
// Unexported fields are not part of the public API.
Build *build.Package
- 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
- 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")
- CmdlineFiles bool // package built from files listed on command line
- CmdlinePkg bool // package listed on command line
- CmdlinePkgLiteral bool // package listed as literal on command line (not via wildcard)
- Local bool // imported via local path (./ or ../)
- LocalPrefix string // interpret ./ and ../ imports relative to this prefix
- ExeName string // desired name for temporary executable
- FuzzInstrument bool // package should be instrumented for fuzzing
- 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
- GobinSubdir bool // install target would be subdir of GOBIN
- BuildInfo *debug.BuildInfo // add this info to package main
- TestmainGo *[]byte // content for _testmain.go
- Embed map[string][]string // //go:embed comment mapping
- OrigImportPath string // original import path before adding '_test' suffix
- PGOProfile string // path to PGO profile
- ForMain string // the main package if this package is built specifically for it
+ 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
+ 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")
+ CmdlineFiles bool // package built from files listed on command line
+ CmdlinePkg bool // package listed on command line
+ CmdlinePkgLiteral bool // package listed as literal on command line (not via wildcard)
+ Local bool // imported via local path (./ or ../)
+ LocalPrefix string // interpret ./ and ../ imports relative to this prefix
+ ExeName string // desired name for temporary executable
+ FuzzInstrument bool // package should be instrumented for fuzzing
+ Cover CoverSetup // coverage mode and other setup info of -cover is being applied to this package
+ OmitDebug bool // tell linker not to write debug information
+ GobinSubdir bool // install target would be subdir of GOBIN
+ BuildInfo *debug.BuildInfo // add this info to package main
+ TestmainGo *[]byte // content for _testmain.go
+ Embed map[string][]string // //go:embed comment mapping
+ OrigImportPath string // original import path before adding '_test' suffix
+ PGOProfile string // path to PGO profile
+ ForMain string // the main package if this package is built specifically for it
Asmflags []string // -asmflags for this package
Gcflags []string // -gcflags for this package
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).
type CoverSetup struct {
Mode string // coverage mode for this package
deps = append(deps, "runtime/asan")
}
// Building for coverage forces an import of runtime/coverage.
- if cfg.BuildCover && cfg.Experiment.CoverageRedesign {
+ if cfg.BuildCover {
deps = append(deps, "runtime/coverage")
}
if cfg.BuildCoverMode == "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.
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
-}
"unicode"
"unicode/utf8"
- "cmd/go/internal/cfg"
"cmd/go/internal/fsys"
"cmd/go/internal/str"
"cmd/go/internal/trace"
Local bool
Pkgs []*Package
Paths []string
- Vars []coverInfo
}
// TestPackagesFor is like TestPackagesAndErrors but it returns
// Also the linker introduces implicit dependencies reported by LinkerDeps.
stk.Push(ImportInfo{Pkg: "testmain"})
deps := TestMainDeps // cap==len, so safe for append
- if cover != nil && cfg.Experiment.CoverageRedesign {
+ if cover != nil {
deps = append(deps, "internal/coverage/cfile")
}
ldDeps, err := LinkerDeps(p)
stk.Pop()
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 = append(allTestImports, pmain.Internal.Imports...)
allTestImports = append(allTestImports, imports...)
}
if cover != nil {
- if cfg.Experiment.CoverageRedesign {
- // Here ptest needs to inherit the proper coverage mode (since
- // it contains p's Go files), whereas pmain contains only
- // test harness code (don't want to instrument it, and
- // we don't want coverage hooks in the pkg init).
- ptest.Internal.Cover.Mode = p.Internal.Cover.Mode
- pmain.Internal.Cover.Mode = "testmain"
- }
+ // Here ptest needs to inherit the proper coverage mode (since
+ // it contains p's Go files), whereas pmain contains only
+ // test harness code (don't want to instrument it, and
+ // we don't want coverage hooks in the pkg init).
+ ptest.Internal.Cover.Mode = p.Internal.Cover.Mode
+ pmain.Internal.Cover.Mode = "testmain"
+
// Should we apply coverage analysis locally, only for this
// package and only for this test? Yes, if -cover is on but
// -coverpkg has not specified a list of packages for global
// coverage.
if cover.Local {
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})
- }
- }
}
}
return !unicode.IsLower(rune)
}
-type coverInfo struct {
- Package *Package
- Vars map[string]*CoverVar
-}
-
// loadTestFuncs returns the testFuncs describing the tests that will be run.
// The returned testFuncs is always non-nil, even if an error occurred while
// processing test files.
func formatTestmain(t *testFuncs) ([]byte, error) {
var buf bytes.Buffer
tmpl := testmainTmpl
- if cfg.Experiment.CoverageRedesign {
- tmpl = testmainTmplNewCoverage
- }
if err := tmpl.Execute(&buf, t); err != nil {
return nil, err
}
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 (
"os"
{{if .TestMain}}
CmdRun.Run = runRun // break init loop
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", "")
}
cmdArgs := args[i:]
load.CheckPackageErrors([]*load.Package{p})
- if cfg.Experiment.CoverageRedesign && cfg.BuildCover {
+ if cfg.BuildCover {
load.PrepareForCoverageBuild([]*load.Package{p})
}
// patterns.
plist := load.TestPackageList(ctx, pkgOpts, pkgs)
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
// meta-data files from all of the packages mentioned in
// "-coverpkg" and write them to a summary file. This new
// later package. Note that if -coverpkg is in effect
// p.Internal.Cover.GenMeta will wind up being set for
// all matching packages.
- if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 &&
- cfg.BuildCoverPkg == nil &&
- cfg.Experiment.CoverageRedesign {
+ if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 && cfg.BuildCoverPkg == nil {
p.Internal.Cover.GenMeta = true
}
}
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 cfg.BuildCover && cfg.Experiment.CoverageRedesign {
+ if cfg.BuildCover {
if p.Internal.Cover.GenMeta {
p.Internal.Cover.Mode = cfg.BuildCoverMode
}
if p := a.Package; len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
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 {
return err
}
AddBuildFlags(CmdBuild, DefaultBuildFlags)
AddBuildFlags(CmdInstall, DefaultBuildFlags)
- if cfg.Experiment != nil && cfg.Experiment.CoverageRedesign {
- AddCoverFlags(CmdBuild, nil)
- AddCoverFlags(CmdInstall, nil)
- }
+ AddCoverFlags(CmdBuild, nil)
+ AddCoverFlags(CmdInstall, nil)
}
// Note that flags consulted by other parts of the code
cmd.Flag.StringVar(&cfg.DebugTrace, "debug-trace", "", "")
}
-// AddCoverFlags adds coverage-related flags to "cmd". If the
-// CoverageRedesign experiment is enabled, we add -cover{mode,pkg} to
-// the build command and only -coverprofile to the test command. If
-// the CoverageRedesign experiment is disabled, -cover* flags are
-// added only to the test command.
+// AddCoverFlags adds coverage-related flags to "cmd".
+// We add -cover{mode,pkg} to the build command and only
+// -coverprofile to the test command.
func AddCoverFlags(cmd *base.Command, coverProfileFlag *string) {
- addCover := false
- if cfg.Experiment != nil && cfg.Experiment.CoverageRedesign {
- // New coverage enabled: both build and test commands get
- // 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", "")
- }
+ 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 {
cmd.Flag.Var(coverFlag{V: stringFlag{coverProfileFlag}}, "coverprofile", "")
}
cfg.BuildO = ""
}
- if cfg.Experiment.CoverageRedesign && cfg.BuildCover {
+ if cfg.BuildCover {
load.PrepareForCoverageBuild(pkgs)
}
}
load.CheckPackageErrors(pkgs)
- if cfg.Experiment.CoverageRedesign && cfg.BuildCover {
+ if cfg.BuildCover {
load.PrepareForCoverageBuild(pkgs)
}
var sourceFile string
var coverFile string
- var key string
if base, found := strings.CutSuffix(file, ".cgo1.go"); found {
// cgo files have absolute paths
base = filepath.Base(base)
sourceFile = file
coverFile = objdir + base + ".cgo1.go"
- key = base + ".go"
} else {
sourceFile = filepath.Join(p.Dir, file)
coverFile = objdir + file
- key = file
}
coverFile = strings.TrimSuffix(coverFile, ".go") + ".cover.go"
- if cfg.Experiment.CoverageRedesign {
- infiles = append(infiles, sourceFile)
- 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
- }
- }
+ infiles = append(infiles, sourceFile)
+ outfiles = append(outfiles, coverFile)
if i < len(gofiles) {
gofiles[i] = coverFile
} else {
}
}
- if cfg.Experiment.CoverageRedesign {
- if len(infiles) != 0 {
- // Coverage instrumentation creates new top level
- // variables in the target package for things like
- // meta-data containers, counter vars, etc. To avoid
- // collisions with user variables, suffix the var name
- // with 12 hex digits from the SHA-256 hash of the
- // import path. Choice of 12 digits is historical/arbitrary,
- // we just need enough of the hash to avoid accidents,
- // as opposed to precluding determined attempts by
- // users to break things.
- sum := sha256.Sum256([]byte(a.Package.ImportPath))
- coverVar := fmt.Sprintf("goCover_%x_", sum[:6])
- mode := a.Package.Internal.Cover.Mode
- if mode == "" {
- panic("covermode should be set at this point")
- }
- if newoutfiles, err := b.cover2(a, infiles, outfiles, coverVar, mode); err != nil {
- return err
- } else {
- outfiles = newoutfiles
- gofiles = append([]string{newoutfiles[0]}, gofiles...)
- }
+ if len(infiles) != 0 {
+ // Coverage instrumentation creates new top level
+ // variables in the target package for things like
+ // meta-data containers, counter vars, etc. To avoid
+ // collisions with user variables, suffix the var name
+ // with 12 hex digits from the SHA-256 hash of the
+ // import path. Choice of 12 digits is historical/arbitrary,
+ // we just need enough of the hash to avoid accidents,
+ // as opposed to precluding determined attempts by
+ // users to break things.
+ sum := sha256.Sum256([]byte(a.Package.ImportPath))
+ coverVar := fmt.Sprintf("goCover_%x_", sum[:6])
+ mode := a.Package.Internal.Cover.Mode
+ if mode == "" {
+ panic("covermode should be set at this point")
+ }
+ if newoutfiles, err := b.cover(a, infiles, outfiles, coverVar, mode); err != nil {
+ return err
} else {
- // If there are no input files passed to cmd/cover,
- // then we don't want to pass -covercfg when building
- // 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 = ""
+ outfiles = newoutfiles
+ gofiles = append([]string{newoutfiles[0]}, gofiles...)
}
if ba, ok := a.Actor.(*buildActor); ok && ba.covMetaFileName != "" {
b.cacheObjdirFile(a, cache.Default(), ba.covMetaFileName)
// 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>
//
// Return value is an updated output files list; in addition to the
// regular outputs (instrumented source files) the cover tool also
// writes a separate file (appearing first in the list of outputs)
// 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"
covoutputs := a.Objdir + "coveroutfiles.txt"
odir := filepath.Dir(outfiles[0])
# inside and outside the standard library.
[short] skip
-[!GOEXPERIMENT:coverageredesign] skip
# Compile an object.
go tool compile -p tiny tiny/tiny.go tiny/tiny2.go
[short] skip
-# Skip if new coverage is not enabled.
-[!GOEXPERIMENT:coverageredesign] skip
-
#-------------------------------------------
# Build for coverage.
[short] skip
-# Hard-wire new coverage for this test.
-env GOEXPERIMENT=coverageredesign
-
# Build for coverage.
go build -gcflags=-m -o example.exe -cover example/main &
[race] go build -o examplewithrace.exe -race -cover example/main &
#
[short] skip
-[!GOEXPERIMENT:coverageredesign] skip
# Test all packages with -coverpkg=./...
go test -coverprofile=cov.p -coverpkg=./... ./...
# do not, some have tests and some do not.
[short] skip
-[!GOEXPERIMENT:coverageredesign] skip
# Verify correct statements percentages. We have a total of 10
# statements in the packages matched by "./..."; package "a" (for
# build arguments (such as -cover, -covermode). See issue #57785.
[short] skip
-[!GOEXPERIMENT:coverageredesign] skip
env GOBIN=$WORK/bin
# the "main" package is handled. See issue 57169 for details.
[short] skip
-[!GOEXPERIMENT:coverageredesign] skip
# Build this program with -cover and run to collect a profile.
# Initial run with simple coverage.
go test -cover ./pkg1 ./pkg2 ./pkg3 ./pkg4
-[!GOEXPERIMENT:coverageredesign] stdout 'pkg1 \[no test files\]'
-[GOEXPERIMENT:coverageredesign] stdout 'pkg1 coverage: 0.0% of statements'
+stdout 'pkg1 coverage: 0.0% of statements'
stdout 'pkg2 \S+ coverage: 0.0% of statements \[no tests to run\]'
stdout 'pkg3 \S+ coverage: 100.0% of statements'
stdout 'pkg4 \S+ coverage: \[no statements\]'
# Second run to make sure that caching works properly.
go test -x -cover ./pkg1 ./pkg2 ./pkg3 ./pkg4
-[!GOEXPERIMENT:coverageredesign] stdout 'pkg1 \[no test files\]'
-[GOEXPERIMENT:coverageredesign] stdout 'pkg1 coverage: 0.0% of statements'
+stdout 'pkg1 coverage: 0.0% of statements'
stdout 'pkg2 \S+ coverage: 0.0% of statements \[no tests to run\]'
stdout 'pkg3 \S+ coverage: 100.0% of statements'
stdout 'pkg4 \S+ coverage: \[no statements\]'
-[GOEXPERIMENT:coverageredesign] ! stderr 'link(\.exe"?)? -'
+! stderr 'link(\.exe"?)? -'
! stderr 'compile(\.exe"?)? -'
! stderr 'cover(\.exe"?)? -'
-[GOEXPERIMENT:coverageredesign] stderr 'covdata(\.exe"?)? percent'
+stderr 'covdata(\.exe"?)? percent'
# Now add in -coverprofile.
go test -cover -coverprofile=cov.dat ./pkg1 ./pkg2 ./pkg3 ./pkg4
-[!GOEXPERIMENT:coverageredesign] stdout 'pkg1 \[no test files\]'
-[GOEXPERIMENT:coverageredesign] stdout 'pkg1 coverage: 0.0% of statements'
+stdout 'pkg1 coverage: 0.0% of statements'
stdout 'pkg2 \S+ coverage: 0.0% of statements \[no tests to run\]'
stdout 'pkg3 \S+ coverage: 100.0% of statements'
stdout 'pkg4 \S+ coverage: \[no statements\]'
# Validate
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 --
module m
[short] skip
[compiler:gccgo] skip # gccgo has no cover tool
-[!GOEXPERIMENT:coverageredesign] skip
go test -short -cover -covermode=atomic -coverpkg=coverdep/p1 coverdep
[short] skip
-# Hard-wire new coverage for this test.
-env GOEXPERIMENT=coverageredesign
-
# Baseline run.
go test -cover example/foo
stdout 'coverage: 50.0% of statements$'
[short] skip
-# Skip if new coverage is turned off.
-[!GOEXPERIMENT:coverageredesign] skip
-
go test -cover example
-- go.mod --
# Rudimentary test of testing.Coverage().
[short] skip
-[!GOEXPERIMENT:coverageredesign] skip
# Simple test.
go test -v -cover -count=1
"internal/coverage/decodecounter"
"internal/coverage/decodemeta"
"internal/coverage/pods"
- "internal/goexperiment"
"internal/testenv"
"os"
"path/filepath"
func TestIssue58411(t *testing.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;
// it is one of the factors that triggers issue 58411.
}
baseline := goexperiment.Flags{
- RegabiWrappers: regabiSupported,
- RegabiArgs: regabiSupported,
- CoverageRedesign: true,
- AliasTypeParams: true,
- SwissMap: true,
- SpinbitMutex: haveXchg8,
- SyncHashTrieMap: true,
+ RegabiWrappers: regabiSupported,
+ RegabiArgs: regabiSupported,
+ AliasTypeParams: true,
+ SwissMap: true,
+ SpinbitMutex: haveXchg8,
+ SyncHashTrieMap: true,
}
// Start with the statically enabled set of experiments.
import (
"fmt"
"internal/coverage"
- "internal/goexperiment"
"internal/platform"
"internal/testenv"
"os"
if testing.Short() {
t.Skipf("skipping test: too long for short mode")
}
- if !goexperiment.CoverageRedesign {
- t.Skipf("skipping new coverage tests (experiment not enabled)")
- }
testenv.MustHaveGoBuild(t)
dir := t.TempDir()
if fixedTestDir {
if testing.Short() {
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
// go build, go run, and "-race" support.
"encoding/json"
"flag"
"internal/coverage"
- "internal/goexperiment"
"internal/testenv"
"os"
"os/exec"
// relying on other test paths will provide a better signal when
// running "go test -cover" for this package).
func TestTestSupport(t *testing.T) {
- if !goexperiment.CoverageRedesign {
- return
- }
if testing.CoverMode() == "" {
return
}
}
func TestAuxMetaDataFiles(t *testing.T) {
- if !goexperiment.CoverageRedesign {
- return
- }
if testing.CoverMode() == "" {
return
}
+++ /dev/null
-// Code generated by mkconsts.go. DO NOT EDIT.
-
-//go:build !goexperiment.coverageredesign
-
-package goexperiment
-
-const CoverageRedesign = false
-const CoverageRedesignInt = 0
+++ /dev/null
-// Code generated by mkconsts.go. DO NOT EDIT.
-
-//go:build goexperiment.coverageredesign
-
-package goexperiment
-
-const CoverageRedesign = true
-const CoverageRedesignInt = 1
// by default.
HeapMinimum512KiB bool
- // CoverageRedesign enables the new compiler-based code coverage
- // tooling.
- CoverageRedesign bool
-
// Arenas causes the "arena" standard library package to be visible
// to the outside world.
Arenas bool
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
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.
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.
// 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)
}
import (
"fmt"
- "internal/goexperiment"
"os"
_ "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.
-var cover2 struct {
+var cover struct {
mode string
tearDown func(coverprofile string, gocoverdir string) (string, error)
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
// (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 == "" {
return
}
- cover2.mode = mode
- cover2.tearDown = tearDown
- cover2.snapshotcov = snapcov
+ cover.mode = mode
+ cover.tearDown = tearDown
+ 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,
// for "go test -cover" runs.
-func coverReport2() {
- if !goexperiment.CoverageRedesign {
- panic("unexpected")
- }
- if errmsg, err := cover2.tearDown(*coverProfile, *gocoverdir); err != nil {
+func coverReport() {
+ if errmsg, err := cover.tearDown(*coverProfile, *gocoverdir); err != nil {
fmt.Fprintf(os.Stderr, "%s: %v\n", errmsg, err)
os.Exit(2)
}
}
-// coverage2 returns a rough "coverage percentage so far"
-// number to support the testing.Coverage() function.
-func coverage2() float64 {
- if cover2.mode == "" {
+// 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 cover.mode == "" {
return 0.0
}
- return cover2.snapshotcov()
+ return cover.snapshotcov()
}
"errors"
"flag"
"fmt"
- "internal/goexperiment"
"internal/race"
"io"
"math/rand"
// values are "set", "count", or "atomic". The return value will be
// empty if test coverage is not enabled.
func CoverMode() string {
- if goexperiment.CoverageRedesign {
- return cover2.mode
- }
- return cover.Mode
+ return cover.mode
}
// Verbose reports whether the -test.v flag is set.
// 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.
func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M {
- registerCover2(deps.InitRuntimeCoverage())
+ registerCover(deps.InitRuntimeCoverage())
Init()
return &M{
deps: deps,