1// Copyright 2022 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package cov_test 6 7import ( 8 "cmd/internal/cov" 9 "fmt" 10 "internal/coverage" 11 "internal/coverage/decodecounter" 12 "internal/coverage/decodemeta" 13 "internal/coverage/pods" 14 "internal/goexperiment" 15 "internal/testenv" 16 "os" 17 "path/filepath" 18 "testing" 19) 20 21// visitor implements the CovDataVisitor interface in a very stripped 22// down way, just keeps track of interesting events. 23type visitor struct { 24 metaFileCount int 25 counterFileCount int 26 funcCounterData int 27 metaFuncCount int 28} 29 30func (v *visitor) BeginPod(p pods.Pod) {} 31func (v *visitor) EndPod(p pods.Pod) {} 32func (v *visitor) VisitMetaDataFile(mdf string, mfr *decodemeta.CoverageMetaFileReader) { 33 v.metaFileCount++ 34} 35func (v *visitor) BeginCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int) { 36 v.counterFileCount++ 37} 38func (v *visitor) EndCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int) {} 39func (v *visitor) VisitFuncCounterData(payload decodecounter.FuncPayload) { v.funcCounterData++ } 40func (v *visitor) EndCounters() {} 41func (v *visitor) BeginPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) {} 42func (v *visitor) EndPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) {} 43func (v *visitor) VisitFunc(pkgIdx uint32, fnIdx uint32, fd *coverage.FuncDesc) { v.metaFuncCount++ } 44func (v *visitor) Finish() {} 45 46func TestIssue58411(t *testing.T) { 47 testenv.MustHaveGoBuild(t) 48 if !goexperiment.CoverageRedesign { 49 t.Skipf("skipping since this test requires 'go build -cover'") 50 } 51 52 // Build a tiny test program with -cover. Smallness is important; 53 // it is one of the factors that triggers issue 58411. 54 d := t.TempDir() 55 exepath := filepath.Join(d, "small.exe") 56 path := filepath.Join("testdata", "small.go") 57 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", 58 "-o", exepath, "-cover", path) 59 b, err := cmd.CombinedOutput() 60 if len(b) != 0 { 61 t.Logf("## build output:\n%s", b) 62 } 63 if err != nil { 64 t.Fatalf("build error: %v", err) 65 } 66 67 // Run to produce coverage data. Note the large argument; we need a large 68 // argument (more than 4k) to trigger the bug, but the overall file 69 // has to remain small (since large files will be read with mmap). 70 covdir := filepath.Join(d, "covdata") 71 if err = os.Mkdir(covdir, 0777); err != nil { 72 t.Fatalf("creating covdir: %v", err) 73 } 74 large := fmt.Sprintf("%07999d", 0) 75 cmd = testenv.Command(t, exepath, "1", "2", "3", large) 76 cmd.Dir = covdir 77 cmd.Env = append(os.Environ(), "GOCOVERDIR="+covdir) 78 b, err = cmd.CombinedOutput() 79 if err != nil { 80 t.Logf("## run output:\n%s", b) 81 t.Fatalf("build error: %v", err) 82 } 83 84 vis := &visitor{} 85 86 // Read resulting coverage data. Without the fix, this would 87 // yield a "short read" error. 88 const verbosityLevel = 0 89 const flags = 0 90 cdr := cov.MakeCovDataReader(vis, []string{covdir}, verbosityLevel, flags, nil) 91 err = cdr.Visit() 92 if err != nil { 93 t.Fatalf("visit failed: %v", err) 94 } 95 96 // make sure we saw a few things just for grins 97 const want = "{metaFileCount:1 counterFileCount:1 funcCounterData:1 metaFuncCount:1}" 98 got := fmt.Sprintf("%+v", *vis) 99 if want != got { 100 t.Errorf("visitor contents: want %v got %v\n", want, got) 101 } 102} 103