github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/internal/coverage/test/counter_test.go (about)

     1  // Copyright 2021 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  
     5  package test
     6  
     7  import (
     8  	"fmt"
     9  	"internal/coverage"
    10  	"internal/coverage/decodecounter"
    11  	"internal/coverage/encodecounter"
    12  	"os"
    13  	"path/filepath"
    14  	"testing"
    15  )
    16  
    17  type ctrVis struct {
    18  	funcs []decodecounter.FuncPayload
    19  }
    20  
    21  func (v *ctrVis) NumFuncs() (int, error) {
    22  	return len(v.funcs), nil
    23  }
    24  
    25  func (v *ctrVis) VisitFuncs(f encodecounter.CounterVisitorFn) error {
    26  	for _, fn := range v.funcs {
    27  		if err := f(fn.PkgIdx, fn.FuncIdx, fn.Counters); err != nil {
    28  			return err
    29  		}
    30  	}
    31  	return nil
    32  }
    33  
    34  func mkfunc(p uint32, f uint32, c []uint32) decodecounter.FuncPayload {
    35  	return decodecounter.FuncPayload{
    36  		PkgIdx:   p,
    37  		FuncIdx:  f,
    38  		Counters: c,
    39  	}
    40  }
    41  
    42  func TestCounterDataWriterReader(t *testing.T) {
    43  	flavors := []coverage.CounterFlavor{
    44  		coverage.CtrRaw,
    45  		coverage.CtrULeb128,
    46  	}
    47  
    48  	isDead := func(fp decodecounter.FuncPayload) bool {
    49  		for _, v := range fp.Counters {
    50  			if v != 0 {
    51  				return false
    52  			}
    53  		}
    54  		return true
    55  	}
    56  
    57  	funcs := []decodecounter.FuncPayload{
    58  		mkfunc(0, 0, []uint32{13, 14, 15}),
    59  		mkfunc(0, 1, []uint32{16, 17}),
    60  		mkfunc(1, 0, []uint32{18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 976543, 7}),
    61  	}
    62  	writeVisitor := &ctrVis{funcs: funcs}
    63  
    64  	for kf, flav := range flavors {
    65  
    66  		t.Logf("testing flavor %d\n", flav)
    67  
    68  		// Open a counter data file in preparation for emitting data.
    69  		d := t.TempDir()
    70  		cfpath := filepath.Join(d, fmt.Sprintf("covcounters.hash.0.%d", kf))
    71  		of, err := os.OpenFile(cfpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
    72  		if err != nil {
    73  			t.Fatalf("opening covcounters: %v", err)
    74  		}
    75  
    76  		// Perform the encode and write.
    77  		cdfw := encodecounter.NewCoverageDataWriter(of, flav)
    78  		if cdfw == nil {
    79  			t.Fatalf("NewCoverageDataWriter failed")
    80  		}
    81  		finalHash := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0}
    82  		args := map[string]string{"argc": "3", "argv0": "arg0", "argv1": "arg1", "argv2": "arg_________2"}
    83  		if err := cdfw.Write(finalHash, args, writeVisitor); err != nil {
    84  			t.Fatalf("counter file Write failed: %v", err)
    85  		}
    86  		if err := of.Close(); err != nil {
    87  			t.Fatalf("closing covcounters: %v", err)
    88  		}
    89  		cdfw = nil
    90  
    91  		// Decode the same file.
    92  		var cdr *decodecounter.CounterDataReader
    93  		inf, err := os.Open(cfpath)
    94  		defer func() {
    95  			if err := inf.Close(); err != nil {
    96  				t.Fatalf("close failed with: %v", err)
    97  			}
    98  		}()
    99  
   100  		if err != nil {
   101  			t.Fatalf("reopening covcounters file: %v", err)
   102  		}
   103  		if cdr, err = decodecounter.NewCounterDataReader(cfpath, inf); err != nil {
   104  			t.Fatalf("opening covcounters for read: %v", err)
   105  		}
   106  		decodedArgs := cdr.OsArgs()
   107  		aWant := "[arg0 arg1 arg_________2]"
   108  		aGot := fmt.Sprintf("%+v", decodedArgs)
   109  		if aWant != aGot {
   110  			t.Errorf("reading decoded args, got %s want %s", aGot, aWant)
   111  		}
   112  		for i := range funcs {
   113  			if isDead(funcs[i]) {
   114  				continue
   115  			}
   116  			var fp decodecounter.FuncPayload
   117  			if ok, err := cdr.NextFunc(&fp); err != nil {
   118  				t.Fatalf("reading func %d: %v", i, err)
   119  			} else if !ok {
   120  				t.Fatalf("reading func %d: bad return", i)
   121  			}
   122  			got := fmt.Sprintf("%+v", fp)
   123  			want := fmt.Sprintf("%+v", funcs[i])
   124  			if got != want {
   125  				t.Errorf("cdr.NextFunc iter %d\ngot  %+v\nwant %+v", i, got, want)
   126  			}
   127  		}
   128  		var dummy decodecounter.FuncPayload
   129  		if ok, err := cdr.NextFunc(&dummy); err != nil {
   130  			t.Fatalf("reading func after loop: %v", err)
   131  		} else if ok {
   132  			t.Fatalf("reading func after loop: expected EOF")
   133  		}
   134  	}
   135  }
   136  
   137  func TestCounterDataAppendSegment(t *testing.T) {
   138  	d := t.TempDir()
   139  	cfpath := filepath.Join(d, "covcounters.hash2.0")
   140  	of, err := os.OpenFile(cfpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
   141  	if err != nil {
   142  		t.Fatalf("opening covcounters: %v", err)
   143  	}
   144  
   145  	const numSegments = 2
   146  
   147  	// Write a counter with with multiple segments.
   148  	args := map[string]string{"argc": "1", "argv0": "prog.exe"}
   149  	allfuncs := [][]decodecounter.FuncPayload{}
   150  	ctrs := []uint32{}
   151  	q := uint32(0)
   152  	var cdfw *encodecounter.CoverageDataWriter
   153  	for idx := 0; idx < numSegments; idx++ {
   154  		args[fmt.Sprintf("seg%d", idx)] = "x"
   155  		q += 7
   156  		ctrs = append(ctrs, q)
   157  		funcs := []decodecounter.FuncPayload{}
   158  		for k := 0; k < idx+1; k++ {
   159  			c := make([]uint32, len(ctrs))
   160  			copy(c, ctrs)
   161  			funcs = append(funcs, mkfunc(uint32(idx), uint32(k), c))
   162  		}
   163  		allfuncs = append(allfuncs, funcs)
   164  
   165  		writeVisitor := &ctrVis{funcs: funcs}
   166  
   167  		if idx == 0 {
   168  			// Perform the encode and write.
   169  			cdfw = encodecounter.NewCoverageDataWriter(of, coverage.CtrRaw)
   170  			if cdfw == nil {
   171  				t.Fatalf("NewCoverageDataWriter failed")
   172  			}
   173  			finalHash := [16]byte{1, 2}
   174  			if err := cdfw.Write(finalHash, args, writeVisitor); err != nil {
   175  				t.Fatalf("counter file Write failed: %v", err)
   176  			}
   177  		} else {
   178  			if err := cdfw.AppendSegment(args, writeVisitor); err != nil {
   179  				t.Fatalf("counter file AppendSegment failed: %v", err)
   180  			}
   181  		}
   182  	}
   183  	if err := of.Close(); err != nil {
   184  		t.Fatalf("closing covcounters: %v", err)
   185  	}
   186  
   187  	// Read the result file.
   188  	var cdr *decodecounter.CounterDataReader
   189  	inf, err := os.Open(cfpath)
   190  	defer func() {
   191  		if err := inf.Close(); err != nil {
   192  			t.Fatalf("close failed with: %v", err)
   193  		}
   194  	}()
   195  
   196  	if err != nil {
   197  		t.Fatalf("reopening covcounters file: %v", err)
   198  	}
   199  	if cdr, err = decodecounter.NewCounterDataReader(cfpath, inf); err != nil {
   200  		t.Fatalf("opening covcounters for read: %v", err)
   201  	}
   202  	ns := cdr.NumSegments()
   203  	if ns != numSegments {
   204  		t.Fatalf("got %d segments want %d", ns, numSegments)
   205  	}
   206  	if len(allfuncs) != numSegments {
   207  		t.Fatalf("expected %d got %d", numSegments, len(allfuncs))
   208  	}
   209  
   210  	for sidx := 0; sidx < int(ns); sidx++ {
   211  
   212  		if off, err := inf.Seek(0, os.SEEK_CUR); err != nil {
   213  			t.Fatalf("Seek failed: %v", err)
   214  		} else {
   215  			t.Logf("sidx=%d off=%d\n", sidx, off)
   216  		}
   217  
   218  		if sidx != 0 {
   219  			if ok, err := cdr.BeginNextSegment(); err != nil {
   220  				t.Fatalf("BeginNextSegment failed: %v", err)
   221  			} else if !ok {
   222  				t.Fatalf("BeginNextSegment return %v on iter %d",
   223  					ok, sidx)
   224  			}
   225  		}
   226  		funcs := allfuncs[sidx]
   227  		for i := range funcs {
   228  			var fp decodecounter.FuncPayload
   229  			if ok, err := cdr.NextFunc(&fp); err != nil {
   230  				t.Fatalf("reading func %d: %v", i, err)
   231  			} else if !ok {
   232  				t.Fatalf("reading func %d: bad return", i)
   233  			}
   234  			got := fmt.Sprintf("%+v", fp)
   235  			want := fmt.Sprintf("%+v", funcs[i])
   236  			if got != want {
   237  				t.Errorf("cdr.NextFunc iter %d\ngot  %+v\nwant %+v", i, got, want)
   238  			}
   239  		}
   240  	}
   241  }