2021-10-28 12:24:31 -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/decodecounter"
|
|
|
|
|
"internal/coverage/encodecounter"
|
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"testing"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type ctrVis struct {
|
|
|
|
|
funcs []decodecounter.FuncPayload
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (v *ctrVis) NumFuncs() (int, error) {
|
|
|
|
|
return len(v.funcs), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
2022-10-10 14:45:12 -04:00
|
|
|
defer func() {
|
|
|
|
|
if err := inf.Close(); err != nil {
|
|
|
|
|
t.Fatalf("close failed with: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
2021-10-28 12:24:31 -04:00
|
|
|
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)
|
2022-10-10 14:45:12 -04:00
|
|
|
defer func() {
|
|
|
|
|
if err := inf.Close(); err != nil {
|
|
|
|
|
t.Fatalf("close failed with: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
2021-10-28 12:24:31 -04:00
|
|
|
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, os.SEEK_CUR); 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)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|