summaryrefslogtreecommitdiffstats
path: root/src/internal/coverage/test/roundtrip_test.go
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
commit43a123c1ae6613b3efeed291fa552ecd909d3acf (patch)
treefd92518b7024bc74031f78a1cf9e454b65e73665 /src/internal/coverage/test/roundtrip_test.go
parentInitial commit. (diff)
downloadgolang-1.20-upstream.tar.xz
golang-1.20-upstream.zip
Adding upstream version 1.20.14.upstream/1.20.14upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/internal/coverage/test/roundtrip_test.go')
-rw-r--r--src/internal/coverage/test/roundtrip_test.go331
1 files changed, 331 insertions, 0 deletions
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)
+ }
+ }
+}