github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/internal/coverage/test/roundtrip_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/decodemeta" 11 "internal/coverage/encodemeta" 12 "internal/coverage/slicewriter" 13 "io" 14 "os" 15 "path/filepath" 16 "testing" 17 ) 18 19 func cmpFuncDesc(want, got coverage.FuncDesc) string { 20 swant := fmt.Sprintf("%+v", want) 21 sgot := fmt.Sprintf("%+v", got) 22 if swant == sgot { 23 return "" 24 } 25 return fmt.Sprintf("wanted %q got %q", swant, sgot) 26 } 27 28 func TestMetaDataEmptyPackage(t *testing.T) { 29 // Make sure that encoding/decoding works properly with packages 30 // that don't actually have any functions. 31 p := "empty/package" 32 pn := "package" 33 mp := "m" 34 b, err := encodemeta.NewCoverageMetaDataBuilder(p, pn, mp) 35 if err != nil { 36 t.Fatalf("making builder: %v", err) 37 } 38 drws := &slicewriter.WriteSeeker{} 39 b.Emit(drws) 40 drws.Seek(0, io.SeekStart) 41 dec, err := decodemeta.NewCoverageMetaDataDecoder(drws.BytesWritten(), false) 42 if err != nil { 43 t.Fatalf("making decoder: %v", err) 44 } 45 nf := dec.NumFuncs() 46 if nf != 0 { 47 t.Errorf("dec.NumFuncs(): got %d want %d", nf, 0) 48 } 49 pp := dec.PackagePath() 50 if pp != p { 51 t.Errorf("dec.PackagePath(): got %s want %s", pp, p) 52 } 53 ppn := dec.PackageName() 54 if ppn != pn { 55 t.Errorf("dec.PackageName(): got %s want %s", ppn, pn) 56 } 57 pmp := dec.ModulePath() 58 if pmp != mp { 59 t.Errorf("dec.ModulePath(): got %s want %s", pmp, mp) 60 } 61 } 62 63 func TestMetaDataEncoderDecoder(t *testing.T) { 64 // Test encode path. 65 pp := "foo/bar/pkg" 66 pn := "pkg" 67 mp := "barmod" 68 b, err := encodemeta.NewCoverageMetaDataBuilder(pp, pn, mp) 69 if err != nil { 70 t.Fatalf("making builder: %v", err) 71 } 72 f1 := coverage.FuncDesc{ 73 Funcname: "func", 74 Srcfile: "foo.go", 75 Units: []coverage.CoverableUnit{ 76 coverage.CoverableUnit{StLine: 1, StCol: 2, EnLine: 3, EnCol: 4, NxStmts: 5}, 77 coverage.CoverableUnit{StLine: 6, StCol: 7, EnLine: 8, EnCol: 9, NxStmts: 10}, 78 }, 79 } 80 idx := b.AddFunc(f1) 81 if idx != 0 { 82 t.Errorf("b.AddFunc(f1) got %d want %d", idx, 0) 83 } 84 85 f2 := coverage.FuncDesc{ 86 Funcname: "xfunc", 87 Srcfile: "bar.go", 88 Units: []coverage.CoverableUnit{ 89 coverage.CoverableUnit{StLine: 1, StCol: 2, EnLine: 3, EnCol: 4, NxStmts: 5}, 90 coverage.CoverableUnit{StLine: 6, StCol: 7, EnLine: 8, EnCol: 9, NxStmts: 10}, 91 coverage.CoverableUnit{StLine: 11, StCol: 12, EnLine: 13, EnCol: 14, NxStmts: 15}, 92 }, 93 } 94 idx = b.AddFunc(f2) 95 if idx != 1 { 96 t.Errorf("b.AddFunc(f2) got %d want %d", idx, 0) 97 } 98 99 // Emit into a writer. 100 drws := &slicewriter.WriteSeeker{} 101 b.Emit(drws) 102 103 // Test decode path. 104 drws.Seek(0, io.SeekStart) 105 dec, err := decodemeta.NewCoverageMetaDataDecoder(drws.BytesWritten(), false) 106 if err != nil { 107 t.Fatalf("NewCoverageMetaDataDecoder error: %v", err) 108 } 109 nf := dec.NumFuncs() 110 if nf != 2 { 111 t.Errorf("dec.NumFuncs(): got %d want %d", nf, 2) 112 } 113 114 gotpp := dec.PackagePath() 115 if gotpp != pp { 116 t.Errorf("packagepath: got %s want %s", gotpp, pp) 117 } 118 gotpn := dec.PackageName() 119 if gotpn != pn { 120 t.Errorf("packagename: got %s want %s", gotpn, pn) 121 } 122 123 cases := []coverage.FuncDesc{f1, f2} 124 for i := uint32(0); i < uint32(len(cases)); i++ { 125 var fn coverage.FuncDesc 126 if err := dec.ReadFunc(i, &fn); err != nil { 127 t.Fatalf("err reading function %d: %v", i, err) 128 } 129 res := cmpFuncDesc(cases[i], fn) 130 if res != "" { 131 t.Errorf("ReadFunc(%d): %s", i, res) 132 } 133 } 134 } 135 136 func createFuncs(i int) []coverage.FuncDesc { 137 res := []coverage.FuncDesc{} 138 lc := uint32(1) 139 for fi := 0; fi < i+1; fi++ { 140 units := []coverage.CoverableUnit{} 141 for ui := 0; ui < (fi+1)*(i+1); ui++ { 142 units = append(units, 143 coverage.CoverableUnit{StLine: lc, StCol: lc + 1, 144 EnLine: lc + 2, EnCol: lc + 3, NxStmts: lc + 4, 145 }) 146 lc += 5 147 } 148 f := coverage.FuncDesc{ 149 Funcname: fmt.Sprintf("func_%d_%d", i, fi), 150 Srcfile: fmt.Sprintf("foo_%d.go", i), 151 Units: units, 152 } 153 res = append(res, f) 154 } 155 return res 156 } 157 158 func createBlob(t *testing.T, i int) []byte { 159 nomodule := "" 160 b, err := encodemeta.NewCoverageMetaDataBuilder("foo/pkg", "pkg", nomodule) 161 if err != nil { 162 t.Fatalf("making builder: %v", err) 163 } 164 165 funcs := createFuncs(i) 166 for _, f := range funcs { 167 b.AddFunc(f) 168 } 169 drws := &slicewriter.WriteSeeker{} 170 b.Emit(drws) 171 return drws.BytesWritten() 172 } 173 174 func createMetaDataBlobs(t *testing.T, nb int) [][]byte { 175 res := [][]byte{} 176 for i := 0; i < nb; i++ { 177 res = append(res, createBlob(t, i)) 178 } 179 return res 180 } 181 182 func TestMetaDataWriterReader(t *testing.T) { 183 d := t.TempDir() 184 185 // Emit a meta-file... 186 mfpath := filepath.Join(d, "covmeta.hash.0") 187 of, err := os.OpenFile(mfpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) 188 if err != nil { 189 t.Fatalf("opening covmeta: %v", err) 190 } 191 //t.Logf("meta-file path is %s", mfpath) 192 blobs := createMetaDataBlobs(t, 7) 193 gran := coverage.CtrGranularityPerBlock 194 mfw := encodemeta.NewCoverageMetaFileWriter(mfpath, of) 195 finalHash := [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 196 err = mfw.Write(finalHash, blobs, coverage.CtrModeAtomic, gran) 197 if err != nil { 198 t.Fatalf("writing meta-file: %v", err) 199 } 200 if err = of.Close(); err != nil { 201 t.Fatalf("closing meta-file: %v", err) 202 } 203 204 // ... then read it back in, first time without setting fileView, 205 // second time setting it. 206 for k := 0; k < 2; k++ { 207 var fileView []byte 208 209 inf, err := os.Open(mfpath) 210 if err != nil { 211 t.Fatalf("open() on meta-file: %v", err) 212 } 213 214 if k != 0 { 215 // Use fileview to exercise different paths in reader. 216 fi, err := os.Stat(mfpath) 217 if err != nil { 218 t.Fatalf("stat() on meta-file: %v", err) 219 } 220 fileView = make([]byte, fi.Size()) 221 if _, err := inf.Read(fileView); err != nil { 222 t.Fatalf("read() on meta-file: %v", err) 223 } 224 if _, err := inf.Seek(int64(0), io.SeekStart); err != nil { 225 t.Fatalf("seek() on meta-file: %v", err) 226 } 227 } 228 229 mfr, err := decodemeta.NewCoverageMetaFileReader(inf, fileView) 230 if err != nil { 231 t.Fatalf("k=%d NewCoverageMetaFileReader failed with: %v", k, err) 232 } 233 np := mfr.NumPackages() 234 if np != 7 { 235 t.Fatalf("k=%d wanted 7 packages got %d", k, np) 236 } 237 md := mfr.CounterMode() 238 wmd := coverage.CtrModeAtomic 239 if md != wmd { 240 t.Fatalf("k=%d wanted mode %d got %d", k, wmd, md) 241 } 242 gran := mfr.CounterGranularity() 243 wgran := coverage.CtrGranularityPerBlock 244 if gran != wgran { 245 t.Fatalf("k=%d wanted gran %d got %d", k, wgran, gran) 246 } 247 248 payload := []byte{} 249 for pi := 0; pi < int(np); pi++ { 250 var pd *decodemeta.CoverageMetaDataDecoder 251 var err error 252 pd, payload, err = mfr.GetPackageDecoder(uint32(pi), payload) 253 if err != nil { 254 t.Fatalf("GetPackageDecoder(%d) failed with: %v", pi, err) 255 } 256 efuncs := createFuncs(pi) 257 nf := pd.NumFuncs() 258 if len(efuncs) != int(nf) { 259 t.Fatalf("decoding pk %d wanted %d funcs got %d", 260 pi, len(efuncs), nf) 261 } 262 var f coverage.FuncDesc 263 for fi := 0; fi < int(nf); fi++ { 264 if err := pd.ReadFunc(uint32(fi), &f); err != nil { 265 t.Fatalf("ReadFunc(%d) pk %d got error %v", 266 fi, pi, err) 267 } 268 res := cmpFuncDesc(efuncs[fi], f) 269 if res != "" { 270 t.Errorf("ReadFunc(%d) pk %d: %s", fi, pi, res) 271 } 272 } 273 } 274 inf.Close() 275 } 276 } 277 278 func TestMetaDataDecodeLitFlagIssue57942(t *testing.T) { 279 280 // Encode a package with a few functions. The funcs alternate 281 // between regular functions and function literals. 282 pp := "foo/bar/pkg" 283 pn := "pkg" 284 mp := "barmod" 285 b, err := encodemeta.NewCoverageMetaDataBuilder(pp, pn, mp) 286 if err != nil { 287 t.Fatalf("making builder: %v", err) 288 } 289 const NF = 6 290 const NCU = 1 291 ln := uint32(10) 292 wantfds := []coverage.FuncDesc{} 293 for fi := uint32(0); fi < NF; fi++ { 294 fis := fmt.Sprintf("%d", fi) 295 fd := coverage.FuncDesc{ 296 Funcname: "func" + fis, 297 Srcfile: "foo" + fis + ".go", 298 Units: []coverage.CoverableUnit{ 299 coverage.CoverableUnit{StLine: ln + 1, StCol: 2, EnLine: ln + 3, EnCol: 4, NxStmts: fi + 2}, 300 }, 301 Lit: (fi % 2) == 0, 302 } 303 wantfds = append(wantfds, fd) 304 b.AddFunc(fd) 305 } 306 307 // Emit into a writer. 308 drws := &slicewriter.WriteSeeker{} 309 b.Emit(drws) 310 311 // Decode the result. 312 drws.Seek(0, io.SeekStart) 313 dec, err := decodemeta.NewCoverageMetaDataDecoder(drws.BytesWritten(), false) 314 if err != nil { 315 t.Fatalf("making decoder: %v", err) 316 } 317 nf := dec.NumFuncs() 318 if nf != NF { 319 t.Fatalf("decoder number of functions: got %d want %d", nf, NF) 320 } 321 var fn coverage.FuncDesc 322 for i := uint32(0); i < uint32(NF); i++ { 323 if err := dec.ReadFunc(i, &fn); err != nil { 324 t.Fatalf("err reading function %d: %v", i, err) 325 } 326 res := cmpFuncDesc(wantfds[i], fn) 327 if res != "" { 328 t.Errorf("ReadFunc(%d): %s", i, res) 329 } 330 } 331 }