diff --git a/src/cmd/cover/cover_test.go b/src/cmd/cover/cover_test.go index aebe6f8cb51..3e5c076d361 100644 --- a/src/cmd/cover/cover_test.go +++ b/src/cmd/cover/cover_test.go @@ -30,9 +30,10 @@ const ( var ( // Input files. - testMain = filepath.Join(testdata, "main.go") - testTest = filepath.Join(testdata, "test.go") - coverProfile = filepath.Join(testdata, "profile.cov") + testMain = filepath.Join(testdata, "main.go") + testTest = filepath.Join(testdata, "test.go") + coverProfile = filepath.Join(testdata, "profile.cov") + toolexecSource = filepath.Join(testdata, "toolexec.go") // The HTML test files are in a separate directory // so they are a complete package. @@ -53,11 +54,17 @@ var ( // testcover is a newly built version of the cover program. testcover string - // testcoverErr records an error building testcover. + // toolexec is a program to use as the go tool's -toolexec argument. + toolexec string + + // testcoverErr records an error building testcover or toolexec. testcoverErr error // testcoverOnce is used to build testcover once. testcoverOnce sync.Once + + // toolexecArg is the argument to pass to the go tool. + toolexecArg string ) var debug = flag.Bool("debug", false, "keep rewritten files for debugging") @@ -94,14 +101,43 @@ func buildCover(t *testing.T) { t.Helper() testenv.MustHaveGoBuild(t) testcoverOnce.Do(func() { - testcover = filepath.Join(testTempDir, "testcover.exe") - t.Logf("running [go build -o %s]", testcover) - out, err := exec.Command(testenv.GoToolPath(t), "build", "-o", testcover).CombinedOutput() - t.Logf("%s", out) - testcoverErr = err + var wg sync.WaitGroup + wg.Add(2) + + var err1, err2 error + go func() { + defer wg.Done() + testcover = filepath.Join(testTempDir, "cover.exe") + t.Logf("running [go build -o %s]", testcover) + out, err := exec.Command(testenv.GoToolPath(t), "build", "-o", testcover).CombinedOutput() + if len(out) > 0 { + t.Logf("%s", out) + } + err1 = err + }() + + go func() { + defer wg.Done() + toolexec = filepath.Join(testTempDir, "toolexec.exe") + t.Logf("running [go -build -o %s %s]", toolexec, toolexecSource) + out, err := exec.Command(testenv.GoToolPath(t), "build", "-o", toolexec, toolexecSource).CombinedOutput() + if len(out) > 0 { + t.Logf("%s", out) + } + err2 = err + }() + + wg.Wait() + + testcoverErr = err1 + if err2 != nil && err1 == nil { + testcoverErr = err2 + } + + toolexecArg = "-toolexec=" + toolexec + " " + testcover }) if testcoverErr != nil { - t.Fatal("failed to build testcover program:", testcoverErr) + t.Fatal("failed to build testcover or toolexec program:", testcoverErr) } } @@ -335,7 +371,7 @@ func TestCoverHTML(t *testing.T) { buildCover(t) // go test -coverprofile testdata/html/html.cov cmd/cover/testdata/html - cmd := exec.Command(testenv.GoToolPath(t), "test", "-coverprofile", htmlProfile, "cmd/cover/testdata/html") + cmd := exec.Command(testenv.GoToolPath(t), "test", toolexecArg, "-coverprofile", htmlProfile, "cmd/cover/testdata/html") run(cmd, t) // testcover -html testdata/html/html.cov -o testdata/html/html.html cmd = exec.Command(testcover, "-html", htmlProfile, "-o", htmlHTML) diff --git a/src/cmd/cover/testdata/toolexec.go b/src/cmd/cover/testdata/toolexec.go new file mode 100644 index 00000000000..1769efedbeb --- /dev/null +++ b/src/cmd/cover/testdata/toolexec.go @@ -0,0 +1,33 @@ +// Copyright 2018 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. + +// The toolexec program is a helper program for cmd/cover tests. +// It is used so that the go tool will call the newly built version +// of the cover program, rather than the installed one. +// +// The tests arrange to run the go tool with the argument +// -toolexec="/path/to/toolexec /path/to/testcover" +// The go tool will invoke this program (compiled into /path/to/toolexec) +// with the arguments shown above followed by the command to run. +// This program will check whether it is expected to run the cover +// program, and if so replace it with /path/to/testcover. +package main + +import ( + "os" + "os/exec" + "strings" +) + +func main() { + if strings.HasSuffix(strings.TrimSuffix(os.Args[2], ".exe"), "cover") { + os.Args[2] = os.Args[1] + } + cmd := exec.Command(os.Args[2], os.Args[3:]...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + os.Exit(1) + } +}