// Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main_test import ( "bytes" "fmt" "internal/testenv" "io/ioutil" "os" "os/exec" "path/filepath" "regexp" "testing" ) const ( // Data directory, also the package directory for the test. testdata = "testdata" // Binaries we compile. testcover = "./testcover.exe" ) var ( // Files we use. testMain = filepath.Join(testdata, "main.go") testTest = filepath.Join(testdata, "test.go") coverInput = filepath.Join(testdata, "test_line.go") coverOutput = filepath.Join(testdata, "test_cover.go") ) var debug = false // Keeps the rewritten files around if set. // Run this shell script, but do it in Go so it can be run by "go test". // // replace the word LINE with the line number < testdata/test.go > testdata/test_line.go // go build -o ./testcover // ./testcover -mode=count -var=CoverTest -o ./testdata/test_cover.go testdata/test_line.go // go run ./testdata/main.go ./testdata/test.go // func TestCover(t *testing.T) { testenv.MustHaveGoBuild(t) // Read in the test file (testTest) and write it, with LINEs specified, to coverInput. file, err := ioutil.ReadFile(testTest) if err != nil { t.Fatal(err) } lines := bytes.Split(file, []byte("\n")) for i, line := range lines { lines[i] = bytes.Replace(line, []byte("LINE"), []byte(fmt.Sprint(i+1)), -1) } if err := ioutil.WriteFile(coverInput, bytes.Join(lines, []byte("\n")), 0666); err != nil { t.Fatal(err) } // defer removal of test_line.go if !debug { defer os.Remove(coverInput) } // go build -o testcover cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", testcover) run(cmd, t) // defer removal of testcover defer os.Remove(testcover) // ./testcover -mode=count -var=thisNameMustBeVeryLongToCauseOverflowOfCounterIncrementStatementOntoNextLineForTest -o ./testdata/test_cover.go testdata/test_line.go cmd = exec.Command(testcover, "-mode=count", "-var=thisNameMustBeVeryLongToCauseOverflowOfCounterIncrementStatementOntoNextLineForTest", "-o", coverOutput, coverInput) run(cmd, t) // defer removal of ./testdata/test_cover.go if !debug { defer os.Remove(coverOutput) } // go run ./testdata/main.go ./testdata/test.go cmd = exec.Command(testenv.GoToolPath(t), "run", testMain, coverOutput) run(cmd, t) file, err = ioutil.ReadFile(coverOutput) if err != nil { t.Fatal(err) } // compiler directive must appear right next to function declaration. if got, err := regexp.MatchString(".*\n//go:nosplit\nfunc someFunction().*", string(file)); err != nil || !got { t.Errorf("misplaced compiler directive: got=(%v, %v); want=(true; nil)", got, err) } // "go:linkname" compiler directive should be present. if got, err := regexp.MatchString(`.*go\:linkname some\_name some\_name.*`, string(file)); err != nil || !got { t.Errorf("'go:linkname' compiler directive not found: got=(%v, %v); want=(true; nil)", got, err) } // No other comments should be present in generated code. c := ".*// This comment shouldn't appear in generated go code.*" if got, err := regexp.MatchString(c, string(file)); err != nil || got { t.Errorf("non compiler directive comment %q found. got=(%v, %v); want=(false; nil)", c, got, err) } } func run(c *exec.Cmd, t *testing.T) { c.Stdout = os.Stdout c.Stderr = os.Stderr err := c.Run() if err != nil { t.Fatal(err) } }