summaryrefslogtreecommitdiffstats
path: root/src/internal/coverage/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal/coverage/test')
-rw-r--r--src/internal/coverage/test/counter_test.go237
-rw-r--r--src/internal/coverage/test/roundtrip_test.go331
2 files changed, 568 insertions, 0 deletions
diff --git a/src/internal/coverage/test/counter_test.go b/src/internal/coverage/test/counter_test.go
new file mode 100644
index 0000000..e29baed
--- /dev/null
+++ b/src/internal/coverage/test/counter_test.go
@@ -0,0 +1,237 @@
+// Copyright 2021 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 test
+
+import (
+ "fmt"
+ "internal/coverage"
+ "internal/coverage/decodecounter"
+ "internal/coverage/encodecounter"
+ "io"
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+type ctrVis struct {
+ funcs []decodecounter.FuncPayload
+}
+
+func (v *ctrVis) VisitFuncs(f encodecounter.CounterVisitorFn) error {
+ for _, fn := range v.funcs {
+ if err := f(fn.PkgIdx, fn.FuncIdx, fn.Counters); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func mkfunc(p uint32, f uint32, c []uint32) decodecounter.FuncPayload {
+ return decodecounter.FuncPayload{
+ PkgIdx: p,
+ FuncIdx: f,
+ Counters: c,
+ }
+}
+
+func TestCounterDataWriterReader(t *testing.T) {
+ flavors := []coverage.CounterFlavor{
+ coverage.CtrRaw,
+ coverage.CtrULeb128,
+ }
+
+ isDead := func(fp decodecounter.FuncPayload) bool {
+ for _, v := range fp.Counters {
+ if v != 0 {
+ return false
+ }
+ }
+ return true
+ }
+
+ funcs := []decodecounter.FuncPayload{
+ mkfunc(0, 0, []uint32{13, 14, 15}),
+ mkfunc(0, 1, []uint32{16, 17}),
+ mkfunc(1, 0, []uint32{18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 976543, 7}),
+ }
+ writeVisitor := &ctrVis{funcs: funcs}
+
+ for kf, flav := range flavors {
+
+ t.Logf("testing flavor %d\n", flav)
+
+ // Open a counter data file in preparation for emitting data.
+ d := t.TempDir()
+ cfpath := filepath.Join(d, fmt.Sprintf("covcounters.hash.0.%d", kf))
+ of, err := os.OpenFile(cfpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
+ if err != nil {
+ t.Fatalf("opening covcounters: %v", err)
+ }
+
+ // Perform the encode and write.
+ cdfw := encodecounter.NewCoverageDataWriter(of, flav)
+ if cdfw == nil {
+ t.Fatalf("NewCoverageDataWriter failed")
+ }
+ finalHash := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0}
+ args := map[string]string{"argc": "3", "argv0": "arg0", "argv1": "arg1", "argv2": "arg_________2"}
+ if err := cdfw.Write(finalHash, args, writeVisitor); err != nil {
+ t.Fatalf("counter file Write failed: %v", err)
+ }
+ if err := of.Close(); err != nil {
+ t.Fatalf("closing covcounters: %v", err)
+ }
+ cdfw = nil
+
+ // Decode the same file.
+ var cdr *decodecounter.CounterDataReader
+ inf, err := os.Open(cfpath)
+ defer func() {
+ if err := inf.Close(); err != nil {
+ t.Fatalf("close failed with: %v", err)
+ }
+ }()
+
+ if err != nil {
+ t.Fatalf("reopening covcounters file: %v", err)
+ }
+ if cdr, err = decodecounter.NewCounterDataReader(cfpath, inf); err != nil {
+ t.Fatalf("opening covcounters for read: %v", err)
+ }
+ decodedArgs := cdr.OsArgs()
+ aWant := "[arg0 arg1 arg_________2]"
+ aGot := fmt.Sprintf("%+v", decodedArgs)
+ if aWant != aGot {
+ t.Errorf("reading decoded args, got %s want %s", aGot, aWant)
+ }
+ for i := range funcs {
+ if isDead(funcs[i]) {
+ continue
+ }
+ var fp decodecounter.FuncPayload
+ if ok, err := cdr.NextFunc(&fp); err != nil {
+ t.Fatalf("reading func %d: %v", i, err)
+ } else if !ok {
+ t.Fatalf("reading func %d: bad return", i)
+ }
+ got := fmt.Sprintf("%+v", fp)
+ want := fmt.Sprintf("%+v", funcs[i])
+ if got != want {
+ t.Errorf("cdr.NextFunc iter %d\ngot %+v\nwant %+v", i, got, want)
+ }
+ }
+ var dummy decodecounter.FuncPayload
+ if ok, err := cdr.NextFunc(&dummy); err != nil {
+ t.Fatalf("reading func after loop: %v", err)
+ } else if ok {
+ t.Fatalf("reading func after loop: expected EOF")
+ }
+ }
+}
+
+func TestCounterDataAppendSegment(t *testing.T) {
+ d := t.TempDir()
+ cfpath := filepath.Join(d, "covcounters.hash2.0")
+ of, err := os.OpenFile(cfpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
+ if err != nil {
+ t.Fatalf("opening covcounters: %v", err)
+ }
+
+ const numSegments = 2
+
+ // Write a counter with with multiple segments.
+ args := map[string]string{"argc": "1", "argv0": "prog.exe"}
+ allfuncs := [][]decodecounter.FuncPayload{}
+ ctrs := []uint32{}
+ q := uint32(0)
+ var cdfw *encodecounter.CoverageDataWriter
+ for idx := 0; idx < numSegments; idx++ {
+ args[fmt.Sprintf("seg%d", idx)] = "x"
+ q += 7
+ ctrs = append(ctrs, q)
+ funcs := []decodecounter.FuncPayload{}
+ for k := 0; k < idx+1; k++ {
+ c := make([]uint32, len(ctrs))
+ copy(c, ctrs)
+ funcs = append(funcs, mkfunc(uint32(idx), uint32(k), c))
+ }
+ allfuncs = append(allfuncs, funcs)
+
+ writeVisitor := &ctrVis{funcs: funcs}
+
+ if idx == 0 {
+ // Perform the encode and write.
+ cdfw = encodecounter.NewCoverageDataWriter(of, coverage.CtrRaw)
+ if cdfw == nil {
+ t.Fatalf("NewCoverageDataWriter failed")
+ }
+ finalHash := [16]byte{1, 2}
+ if err := cdfw.Write(finalHash, args, writeVisitor); err != nil {
+ t.Fatalf("counter file Write failed: %v", err)
+ }
+ } else {
+ if err := cdfw.AppendSegment(args, writeVisitor); err != nil {
+ t.Fatalf("counter file AppendSegment failed: %v", err)
+ }
+ }
+ }
+ if err := of.Close(); err != nil {
+ t.Fatalf("closing covcounters: %v", err)
+ }
+
+ // Read the result file.
+ var cdr *decodecounter.CounterDataReader
+ inf, err := os.Open(cfpath)
+ defer func() {
+ if err := inf.Close(); err != nil {
+ t.Fatalf("close failed with: %v", err)
+ }
+ }()
+
+ if err != nil {
+ t.Fatalf("reopening covcounters file: %v", err)
+ }
+ if cdr, err = decodecounter.NewCounterDataReader(cfpath, inf); err != nil {
+ t.Fatalf("opening covcounters for read: %v", err)
+ }
+ ns := cdr.NumSegments()
+ if ns != numSegments {
+ t.Fatalf("got %d segments want %d", ns, numSegments)
+ }
+ if len(allfuncs) != numSegments {
+ t.Fatalf("expected %d got %d", numSegments, len(allfuncs))
+ }
+
+ for sidx := 0; sidx < int(ns); sidx++ {
+ if off, err := inf.Seek(0, io.SeekCurrent); err != nil {
+ t.Fatalf("Seek failed: %v", err)
+ } else {
+ t.Logf("sidx=%d off=%d\n", sidx, off)
+ }
+
+ if sidx != 0 {
+ if ok, err := cdr.BeginNextSegment(); err != nil {
+ t.Fatalf("BeginNextSegment failed: %v", err)
+ } else if !ok {
+ t.Fatalf("BeginNextSegment return %v on iter %d",
+ ok, sidx)
+ }
+ }
+ funcs := allfuncs[sidx]
+ for i := range funcs {
+ var fp decodecounter.FuncPayload
+ if ok, err := cdr.NextFunc(&fp); err != nil {
+ t.Fatalf("reading func %d: %v", i, err)
+ } else if !ok {
+ t.Fatalf("reading func %d: bad return", i)
+ }
+ got := fmt.Sprintf("%+v", fp)
+ want := fmt.Sprintf("%+v", funcs[i])
+ if got != want {
+ t.Errorf("cdr.NextFunc iter %d\ngot %+v\nwant %+v", i, got, want)
+ }
+ }
+ }
+}
diff --git a/src/internal/coverage/test/roundtrip_test.go b/src/internal/coverage/test/roundtrip_test.go
new file mode 100644
index 0000000..614f56e
--- /dev/null
+++ b/src/internal/coverage/test/roundtrip_test.go
@@ -0,0 +1,331 @@
+// Copyright 2021 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 test
+
+import (
+ "fmt"
+ "internal/coverage"
+ "internal/coverage/decodemeta"
+ "internal/coverage/encodemeta"
+ "internal/coverage/slicewriter"
+ "io"
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func cmpFuncDesc(want, got coverage.FuncDesc) string {
+ swant := fmt.Sprintf("%+v", want)
+ sgot := fmt.Sprintf("%+v", got)
+ if swant == sgot {
+ return ""
+ }
+ return fmt.Sprintf("wanted %q got %q", swant, sgot)
+}
+
+func TestMetaDataEmptyPackage(t *testing.T) {
+ // Make sure that encoding/decoding works properly with packages
+ // that don't actually have any functions.
+ p := "empty/package"
+ pn := "package"
+ mp := "m"
+ b, err := encodemeta.NewCoverageMetaDataBuilder(p, pn, mp)
+ if err != nil {
+ t.Fatalf("making builder: %v", err)
+ }
+ drws := &slicewriter.WriteSeeker{}
+ b.Emit(drws)
+ drws.Seek(0, io.SeekStart)
+ dec, err := decodemeta.NewCoverageMetaDataDecoder(drws.BytesWritten(), false)
+ if err != nil {
+ t.Fatalf("making decoder: %v", err)
+ }
+ nf := dec.NumFuncs()
+ if nf != 0 {
+ t.Errorf("dec.NumFuncs(): got %d want %d", nf, 0)
+ }
+ pp := dec.PackagePath()
+ if pp != p {
+ t.Errorf("dec.PackagePath(): got %s want %s", pp, p)
+ }
+ ppn := dec.PackageName()
+ if ppn != pn {
+ t.Errorf("dec.PackageName(): got %s want %s", ppn, pn)
+ }
+ pmp := dec.ModulePath()
+ if pmp != mp {
+ t.Errorf("dec.ModulePath(): got %s want %s", pmp, mp)
+ }
+}
+
+func TestMetaDataEncoderDecoder(t *testing.T) {
+ // Test encode path.
+ pp := "foo/bar/pkg"
+ pn := "pkg"
+ mp := "barmod"
+ b, err := encodemeta.NewCoverageMetaDataBuilder(pp, pn, mp)
+ if err != nil {
+ t.Fatalf("making builder: %v", err)
+ }
+ f1 := coverage.FuncDesc{
+ Funcname: "func",
+ Srcfile: "foo.go",
+ Units: []coverage.CoverableUnit{
+ coverage.CoverableUnit{StLine: 1, StCol: 2, EnLine: 3, EnCol: 4, NxStmts: 5},
+ coverage.CoverableUnit{StLine: 6, StCol: 7, EnLine: 8, EnCol: 9, NxStmts: 10},
+ },
+ }
+ idx := b.AddFunc(f1)
+ if idx != 0 {
+ t.Errorf("b.AddFunc(f1) got %d want %d", idx, 0)
+ }
+
+ f2 := coverage.FuncDesc{
+ Funcname: "xfunc",
+ Srcfile: "bar.go",
+ Units: []coverage.CoverableUnit{
+ coverage.CoverableUnit{StLine: 1, StCol: 2, EnLine: 3, EnCol: 4, NxStmts: 5},
+ coverage.CoverableUnit{StLine: 6, StCol: 7, EnLine: 8, EnCol: 9, NxStmts: 10},
+ coverage.CoverableUnit{StLine: 11, StCol: 12, EnLine: 13, EnCol: 14, NxStmts: 15},
+ },
+ }
+ idx = b.AddFunc(f2)
+ if idx != 1 {
+ t.Errorf("b.AddFunc(f2) got %d want %d", idx, 0)
+ }
+
+ // Emit into a writer.
+ drws := &slicewriter.WriteSeeker{}
+ b.Emit(drws)
+
+ // Test decode path.
+ drws.Seek(0, io.SeekStart)
+ dec, err := decodemeta.NewCoverageMetaDataDecoder(drws.BytesWritten(), false)
+ if err != nil {
+ t.Fatalf("NewCoverageMetaDataDecoder error: %v", err)
+ }
+ nf := dec.NumFuncs()
+ if nf != 2 {
+ t.Errorf("dec.NumFuncs(): got %d want %d", nf, 2)
+ }
+
+ gotpp := dec.PackagePath()
+ if gotpp != pp {
+ t.Errorf("packagepath: got %s want %s", gotpp, pp)
+ }
+ gotpn := dec.PackageName()
+ if gotpn != pn {
+ t.Errorf("packagename: got %s want %s", gotpn, pn)
+ }
+
+ cases := []coverage.FuncDesc{f1, f2}
+ for i := uint32(0); i < uint32(len(cases)); i++ {
+ var fn coverage.FuncDesc
+ if err := dec.ReadFunc(i, &fn); err != nil {
+ t.Fatalf("err reading function %d: %v", i, err)
+ }
+ res := cmpFuncDesc(cases[i], fn)
+ if res != "" {
+ t.Errorf("ReadFunc(%d): %s", i, res)
+ }
+ }
+}
+
+func createFuncs(i int) []coverage.FuncDesc {
+ res := []coverage.FuncDesc{}
+ lc := uint32(1)
+ for fi := 0; fi < i+1; fi++ {
+ units := []coverage.CoverableUnit{}
+ for ui := 0; ui < (fi+1)*(i+1); ui++ {
+ units = append(units,
+ coverage.CoverableUnit{StLine: lc, StCol: lc + 1,
+ EnLine: lc + 2, EnCol: lc + 3, NxStmts: lc + 4,
+ })
+ lc += 5
+ }
+ f := coverage.FuncDesc{
+ Funcname: fmt.Sprintf("func_%d_%d", i, fi),
+ Srcfile: fmt.Sprintf("foo_%d.go", i),
+ Units: units,
+ }
+ res = append(res, f)
+ }
+ return res
+}
+
+func createBlob(t *testing.T, i int) []byte {
+ nomodule := ""
+ b, err := encodemeta.NewCoverageMetaDataBuilder("foo/pkg", "pkg", nomodule)
+ if err != nil {
+ t.Fatalf("making builder: %v", err)
+ }
+
+ funcs := createFuncs(i)
+ for _, f := range funcs {
+ b.AddFunc(f)
+ }
+ drws := &slicewriter.WriteSeeker{}
+ b.Emit(drws)
+ return drws.BytesWritten()
+}
+
+func createMetaDataBlobs(t *testing.T, nb int) [][]byte {
+ res := [][]byte{}
+ for i := 0; i < nb; i++ {
+ res = append(res, createBlob(t, i))
+ }
+ return res
+}
+
+func TestMetaDataWriterReader(t *testing.T) {
+ d := t.TempDir()
+
+ // Emit a meta-file...
+ mfpath := filepath.Join(d, "covmeta.hash.0")
+ of, err := os.OpenFile(mfpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
+ if err != nil {
+ t.Fatalf("opening covmeta: %v", err)
+ }
+ //t.Logf("meta-file path is %s", mfpath)
+ blobs := createMetaDataBlobs(t, 7)
+ gran := coverage.CtrGranularityPerBlock
+ mfw := encodemeta.NewCoverageMetaFileWriter(mfpath, of)
+ finalHash := [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
+ err = mfw.Write(finalHash, blobs, coverage.CtrModeAtomic, gran)
+ if err != nil {
+ t.Fatalf("writing meta-file: %v", err)
+ }
+ if err = of.Close(); err != nil {
+ t.Fatalf("closing meta-file: %v", err)
+ }
+
+ // ... then read it back in, first time without setting fileView,
+ // second time setting it.
+ for k := 0; k < 2; k++ {
+ var fileView []byte
+
+ inf, err := os.Open(mfpath)
+ if err != nil {
+ t.Fatalf("open() on meta-file: %v", err)
+ }
+
+ if k != 0 {
+ // Use fileview to exercise different paths in reader.
+ fi, err := os.Stat(mfpath)
+ if err != nil {
+ t.Fatalf("stat() on meta-file: %v", err)
+ }
+ fileView = make([]byte, fi.Size())
+ if _, err := inf.Read(fileView); err != nil {
+ t.Fatalf("read() on meta-file: %v", err)
+ }
+ if _, err := inf.Seek(int64(0), io.SeekStart); err != nil {
+ t.Fatalf("seek() on meta-file: %v", err)
+ }
+ }
+
+ mfr, err := decodemeta.NewCoverageMetaFileReader(inf, fileView)
+ if err != nil {
+ t.Fatalf("k=%d NewCoverageMetaFileReader failed with: %v", k, err)
+ }
+ np := mfr.NumPackages()
+ if np != 7 {
+ t.Fatalf("k=%d wanted 7 packages got %d", k, np)
+ }
+ md := mfr.CounterMode()
+ wmd := coverage.CtrModeAtomic
+ if md != wmd {
+ t.Fatalf("k=%d wanted mode %d got %d", k, wmd, md)
+ }
+ gran := mfr.CounterGranularity()
+ wgran := coverage.CtrGranularityPerBlock
+ if gran != wgran {
+ t.Fatalf("k=%d wanted gran %d got %d", k, wgran, gran)
+ }
+
+ payload := []byte{}
+ for pi := 0; pi < int(np); pi++ {
+ var pd *decodemeta.CoverageMetaDataDecoder
+ var err error
+ pd, payload, err = mfr.GetPackageDecoder(uint32(pi), payload)
+ if err != nil {
+ t.Fatalf("GetPackageDecoder(%d) failed with: %v", pi, err)
+ }
+ efuncs := createFuncs(pi)
+ nf := pd.NumFuncs()
+ if len(efuncs) != int(nf) {
+ t.Fatalf("decoding pk %d wanted %d funcs got %d",
+ pi, len(efuncs), nf)
+ }
+ var f coverage.FuncDesc
+ for fi := 0; fi < int(nf); fi++ {
+ if err := pd.ReadFunc(uint32(fi), &f); err != nil {
+ t.Fatalf("ReadFunc(%d) pk %d got error %v",
+ fi, pi, err)
+ }
+ res := cmpFuncDesc(efuncs[fi], f)
+ if res != "" {
+ t.Errorf("ReadFunc(%d) pk %d: %s", fi, pi, res)
+ }
+ }
+ }
+ inf.Close()
+ }
+}
+
+func TestMetaDataDecodeLitFlagIssue57942(t *testing.T) {
+
+ // Encode a package with a few functions. The funcs alternate
+ // between regular functions and function literals.
+ pp := "foo/bar/pkg"
+ pn := "pkg"
+ mp := "barmod"
+ b, err := encodemeta.NewCoverageMetaDataBuilder(pp, pn, mp)
+ if err != nil {
+ t.Fatalf("making builder: %v", err)
+ }
+ const NF = 6
+ const NCU = 1
+ ln := uint32(10)
+ wantfds := []coverage.FuncDesc{}
+ for fi := uint32(0); fi < NF; fi++ {
+ fis := fmt.Sprintf("%d", fi)
+ fd := coverage.FuncDesc{
+ Funcname: "func" + fis,
+ Srcfile: "foo" + fis + ".go",
+ Units: []coverage.CoverableUnit{
+ coverage.CoverableUnit{StLine: ln + 1, StCol: 2, EnLine: ln + 3, EnCol: 4, NxStmts: fi + 2},
+ },
+ Lit: (fi % 2) == 0,
+ }
+ wantfds = append(wantfds, fd)
+ b.AddFunc(fd)
+ }
+
+ // Emit into a writer.
+ drws := &slicewriter.WriteSeeker{}
+ b.Emit(drws)
+
+ // Decode the result.
+ drws.Seek(0, io.SeekStart)
+ dec, err := decodemeta.NewCoverageMetaDataDecoder(drws.BytesWritten(), false)
+ if err != nil {
+ t.Fatalf("making decoder: %v", err)
+ }
+ nf := dec.NumFuncs()
+ if nf != NF {
+ t.Fatalf("decoder number of functions: got %d want %d", nf, NF)
+ }
+ var fn coverage.FuncDesc
+ for i := uint32(0); i < uint32(NF); i++ {
+ if err := dec.ReadFunc(i, &fn); err != nil {
+ t.Fatalf("err reading function %d: %v", i, err)
+ }
+ res := cmpFuncDesc(wantfds[i], fn)
+ if res != "" {
+ t.Errorf("ReadFunc(%d): %s", i, res)
+ }
+ }
+}