Source file src/internal/coverage/test/roundtrip_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/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  }
   332  

View as plain text