// Copyright 2022 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package cov_test import ( "cmd/internal/cov" "fmt" "internal/coverage" "internal/coverage/decodecounter" "internal/coverage/decodemeta" "internal/coverage/pods" "internal/goexperiment" "internal/testenv" "os" "path/filepath" "testing" ) // visitor implements the CovDataVisitor interface in a very stripped // down way, just keeps track of interesting events. type visitor struct { metaFileCount int counterFileCount int funcCounterData int metaFuncCount int } func (v *visitor) BeginPod(p pods.Pod) {} func (v *visitor) EndPod(p pods.Pod) {} func (v *visitor) VisitMetaDataFile(mdf string, mfr *decodemeta.CoverageMetaFileReader) { v.metaFileCount++ } func (v *visitor) BeginCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int) { v.counterFileCount++ } func (v *visitor) EndCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int) {} func (v *visitor) VisitFuncCounterData(payload decodecounter.FuncPayload) { v.funcCounterData++ } func (v *visitor) EndCounters() {} func (v *visitor) BeginPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) {} func (v *visitor) EndPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) {} func (v *visitor) VisitFunc(pkgIdx uint32, fnIdx uint32, fd *coverage.FuncDesc) { v.metaFuncCount++ } func (v *visitor) Finish() {} 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. d := t.TempDir() exepath := filepath.Join(d, "small.exe") path := filepath.Join("testdata", "small.go") cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", exepath, "-cover", path) b, err := cmd.CombinedOutput() if len(b) != 0 { t.Logf("## build output:\n%s", b) } if err != nil { t.Fatalf("build error: %v", err) } // Run to produce coverage data. Note the large argument; we need a large // argument (more than 4k) to trigger the bug, but the overall file // has to remain small (since large files will be read with mmap). covdir := filepath.Join(d, "covdata") if err = os.Mkdir(covdir, 0777); err != nil { t.Fatalf("creating covdir: %v", err) } large := fmt.Sprintf("%07999d", 0) cmd = testenv.Command(t, exepath, "1", "2", "3", large) cmd.Dir = covdir cmd.Env = append(os.Environ(), "GOCOVERDIR="+covdir) b, err = cmd.CombinedOutput() if err != nil { t.Logf("## run output:\n%s", b) t.Fatalf("build error: %v", err) } vis := &visitor{} // Read resulting coverage data. Without the fix, this would // yield a "short read" error. const verbosityLevel = 0 const flags = 0 cdr := cov.MakeCovDataReader(vis, []string{covdir}, verbosityLevel, flags, nil) err = cdr.Visit() if err != nil { t.Fatalf("visit failed: %v", err) } // make sure we saw a few things just for grins const want = "{metaFileCount:1 counterFileCount:1 funcCounterData:1 metaFuncCount:1}" got := fmt.Sprintf("%+v", *vis) if want != got { t.Errorf("visitor contents: want %v got %v\n", want, got) } }