Source file src/internal/coverage/cfile/ts_test.go

     1  // Copyright 2022 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 cfile
     6  
     7  import (
     8  	"encoding/json"
     9  	"flag"
    10  	"internal/coverage"
    11  	"internal/testenv"
    12  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"strings"
    16  	"testing"
    17  	_ "unsafe"
    18  )
    19  
    20  func testGoCoverDir(t *testing.T) string {
    21  	if f := flag.Lookup("test.gocoverdir"); f != nil {
    22  		if dir := f.Value.String(); dir != "" {
    23  			return dir
    24  		}
    25  	}
    26  	return t.TempDir()
    27  }
    28  
    29  // TestTestSupport does a basic verification of the functionality in
    30  // ProcessCoverTestDir (doing this here as opposed to
    31  // relying on other test paths will provide a better signal when
    32  // running "go test -cover" for this package).
    33  func TestTestSupport(t *testing.T) {
    34  	if testing.CoverMode() == "" {
    35  		return
    36  	}
    37  	tgcd := testGoCoverDir(t)
    38  	t.Logf("testing.testGoCoverDir() returns %s mode=%s\n",
    39  		tgcd, testing.CoverMode())
    40  
    41  	textfile := filepath.Join(t.TempDir(), "file.txt")
    42  	var sb strings.Builder
    43  	err := ProcessCoverTestDir(tgcd, textfile,
    44  		testing.CoverMode(), "", &sb, nil)
    45  	if err != nil {
    46  		t.Fatalf("bad: %v", err)
    47  	}
    48  
    49  	// Check for existence of text file.
    50  	if inf, err := os.Open(textfile); err != nil {
    51  		t.Fatalf("problems opening text file %s: %v", textfile, err)
    52  	} else {
    53  		inf.Close()
    54  	}
    55  
    56  	// Check for percent output with expected tokens.
    57  	strout := sb.String()
    58  	want := "of statements"
    59  	if !strings.Contains(strout, want) {
    60  		t.Logf("output from run: %s\n", strout)
    61  		t.Fatalf("percent output missing token: %q", want)
    62  	}
    63  }
    64  
    65  // Kicks off a sub-test to verify that Snapshot() works properly.
    66  // We do this as a separate shell-out, so as to avoid potential
    67  // interactions with -coverpkg. For example, if you do
    68  //
    69  //	$ cd `go env GOROOT`
    70  //	$ cd src/internal/coverage
    71  //	$ go test -coverpkg=internal/coverage/decodecounter ./...
    72  //	...
    73  //	$
    74  //
    75  // The previous version of this test could fail due to the fact
    76  // that "cfile" itself was not being instrumented, as in the
    77  // scenario above.
    78  func TestCoverageSnapshot(t *testing.T) {
    79  	testenv.MustHaveGoRun(t)
    80  	args := []string{"test", "-tags", "SELECT_USING_THIS_TAG",
    81  		"-cover", "-run=TestCoverageSnapshotImpl", "internal/coverage/cfile"}
    82  	cmd := exec.Command(testenv.GoToolPath(t), args...)
    83  	if b, err := cmd.CombinedOutput(); err != nil {
    84  		t.Fatalf("go test failed (%v): %s", err, b)
    85  	}
    86  }
    87  
    88  const hellogo = `
    89  package main
    90  
    91  func main() {
    92    println("hello")
    93  }
    94  `
    95  
    96  // Returns a pair F,T where F is a meta-data file generated from
    97  // "hello.go" above, and T is a token to look for that should be
    98  // present in the coverage report from F.
    99  func genAuxMeta(t *testing.T, dstdir string) (string, string) {
   100  	// Do a GOCOVERDIR=<tmp> go run hello.go
   101  	src := filepath.Join(dstdir, "hello.go")
   102  	if err := os.WriteFile(src, []byte(hellogo), 0777); err != nil {
   103  		t.Fatalf("write failed: %v", err)
   104  	}
   105  	args := []string{"run", "-covermode=" + testing.CoverMode(), src}
   106  	cmd := exec.Command(testenv.GoToolPath(t), args...)
   107  	cmd.Env = updateGoCoverDir(os.Environ(), dstdir, true)
   108  	if b, err := cmd.CombinedOutput(); err != nil {
   109  		t.Fatalf("go run failed (%v): %s", err, b)
   110  	}
   111  
   112  	// Pick out the generated meta-data file.
   113  	files, err := os.ReadDir(dstdir)
   114  	if err != nil {
   115  		t.Fatalf("reading %s: %v", dstdir, err)
   116  	}
   117  	for _, f := range files {
   118  		if strings.HasPrefix(f.Name(), "covmeta") {
   119  			return filepath.Join(dstdir, f.Name()), "hello.go:"
   120  		}
   121  	}
   122  	t.Fatalf("could not locate generated meta-data file")
   123  	return "", ""
   124  }
   125  
   126  func TestAuxMetaDataFiles(t *testing.T) {
   127  	if testing.CoverMode() == "" {
   128  		return
   129  	}
   130  	testenv.MustHaveGoRun(t)
   131  	tgcd := testGoCoverDir(t)
   132  	t.Logf("testing.testGoCoverDir() returns %s mode=%s\n",
   133  		tgcd, testing.CoverMode())
   134  
   135  	td := t.TempDir()
   136  
   137  	// Manufacture a new, separate meta-data file not related to this
   138  	// test. Contents are not important, just so long as the
   139  	// packages/paths are different.
   140  	othermetadir := filepath.Join(td, "othermeta")
   141  	if err := os.Mkdir(othermetadir, 0777); err != nil {
   142  		t.Fatalf("mkdir failed: %v", err)
   143  	}
   144  	mfile, token := genAuxMeta(t, othermetadir)
   145  
   146  	// Write a metafiles file.
   147  	metafiles := filepath.Join(tgcd, coverage.MetaFilesFileName)
   148  	mfc := coverage.MetaFileCollection{
   149  		ImportPaths:       []string{"command-line-arguments"},
   150  		MetaFileFragments: []string{mfile},
   151  	}
   152  	jdata, err := json.Marshal(mfc)
   153  	if err != nil {
   154  		t.Fatalf("marshal MetaFileCollection: %v", err)
   155  	}
   156  	if err := os.WriteFile(metafiles, jdata, 0666); err != nil {
   157  		t.Fatalf("write failed: %v", err)
   158  	}
   159  
   160  	// Kick off guts of test.
   161  	var sb strings.Builder
   162  	textfile := filepath.Join(td, "file2.txt")
   163  	err = ProcessCoverTestDir(tgcd, textfile,
   164  		testing.CoverMode(), "", &sb, nil)
   165  	if err != nil {
   166  		t.Fatalf("bad: %v", err)
   167  	}
   168  	if err = os.Remove(metafiles); err != nil {
   169  		t.Fatalf("removing metafiles file: %v", err)
   170  	}
   171  
   172  	// Look for the expected things in the coverage profile.
   173  	contents, err := os.ReadFile(textfile)
   174  	strc := string(contents)
   175  	if err != nil {
   176  		t.Fatalf("problems reading text file %s: %v", textfile, err)
   177  	}
   178  	if !strings.Contains(strc, token) {
   179  		t.Logf("content: %s\n", string(contents))
   180  		t.Fatalf("cov profile does not contain aux meta content %q", token)
   181  	}
   182  }
   183  

View as plain text