2021-09-29 16:42:55 -04:00
|
|
|
// 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"
|
2022-10-10 14:45:12 -04:00
|
|
|
"io"
|
2021-09-29 16:42:55 -04:00
|
|
|
"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)
|
2022-10-10 14:45:12 -04:00
|
|
|
drws.Seek(0, io.SeekStart)
|
2021-09-29 16:42:55 -04:00
|
|
|
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.
|
2022-10-10 14:45:12 -04:00
|
|
|
drws.Seek(0, io.SeekStart)
|
2021-09-29 16:42:55 -04:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-28 12:24:31 -04:00
|
|
|
func TestMetaDataWriterReader(t *testing.T) {
|
2021-09-29 16:42:55 -04:00
|
|
|
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)
|
|
|
|
|
}
|
2022-10-10 14:45:12 -04:00
|
|
|
if _, err := inf.Seek(int64(0), io.SeekStart); err != nil {
|
2021-09-29 16:42:55 -04:00
|
|
|
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()
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-20 14:03:43 -05:00
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|