Source file src/internal/coverage/test/counter_test.go

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

View as plain text