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 }