github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/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 "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 }