Commit dc32b7f0 authored by Ian Lance Taylor's avatar Ian Lance Taylor

cmd/go: rewrite testsuite from bash to Go

Change-Id: I8473e3f7653d5389d5fcd94862f0831049b8266e
Reviewed-on: https://go-review.googlesource.com/10809Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 1f029fa6
......@@ -12,14 +12,26 @@ import (
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
"testing"
"time"
)
// Whether we can run go or ./testgo.
var canRun = true
// The suffix for executables, because Windows.
var exeSuffix string
// Whether we can run the race detector.
var canRace bool
// Whether we can use cgo.
var canCgo bool
func init() {
switch runtime.GOOS {
case "android", "nacl":
......@@ -30,6 +42,11 @@ func init() {
canRun = false
}
}
switch runtime.GOOS {
case "windows":
exeSuffix = ".exe"
}
}
// The TestMain function creates a go command for testing purposes and
......@@ -38,12 +55,26 @@ func TestMain(m *testing.M) {
flag.Parse()
if canRun {
// We give the executable a .exe extension because Windows.
out, err := exec.Command("go", "build", "-tags", "testgo", "-o", "testgo.exe").CombinedOutput()
out, err := exec.Command("go", "build", "-tags", "testgo", "-o", "testgo"+exeSuffix).CombinedOutput()
if err != nil {
fmt.Fprintf(os.Stderr, "building testgo failed: %v\n%s", err, out)
os.Exit(2)
}
if out, err := exec.Command("./testgo"+exeSuffix, "env", "CGO_ENABLED").Output(); err != nil {
fmt.Fprintf(os.Stderr, "running testgo failed: %v\n", err)
canRun = false
} else {
canCgo, err = strconv.ParseBool(strings.TrimSpace(string(out)))
if err != nil {
fmt.Fprintf(os.Stderr, "can't parse go env CGO_ENABLED output: %v\n", strings.TrimSpace(string(out)))
}
}
switch runtime.GOOS {
case "linux", "darwin", "freebsd", "windows":
canRace = canCgo && runtime.GOARCH == "amd64"
}
}
// Don't let these environment variables confuse the test.
......@@ -54,14 +85,25 @@ func TestMain(m *testing.M) {
r := m.Run()
if canRun {
os.Remove("testgo.exe")
os.Remove("testgo" + exeSuffix)
}
os.Exit(r)
}
// Skip a test if we can't run ./testgo.
func checkTestGo(t *testing.T) {
// Manage a single run of the testgo binary.
type testgoData struct {
t *testing.T
temps []string
wd string
env []string
tempdir string
ran bool
stdout, stderr bytes.Buffer
}
// testgo sets up for a test that runs testgo.
func testgo(t *testing.T) *testgoData {
if !canRun {
switch runtime.GOOS {
case "android", "nacl":
......@@ -75,82 +117,1648 @@ func checkTestGo(t *testing.T) {
t.Skip("skipping for unknown reason")
}
}
return &testgoData{t: t}
}
// must gives a fatal error if err is not nil.
func (tg *testgoData) must(err error) {
if err != nil {
tg.t.Fatal(err)
}
}
// check gives a test non-fatal error if err is not nil.
func (tg *testgoData) check(err error) {
if err != nil {
tg.t.Error(err)
}
}
// runTestGo runs the test go command, returning stdout, stderr, and
// status. The contents of addEnv are added to the environment.
func runTestGo(addEnv []string, args ...string) (stdout, stderr string, err error) {
// pwd returns the current directory.
func (tg *testgoData) pwd() string {
wd, err := os.Getwd()
if err != nil {
tg.t.Fatalf("could not get working directory: %v", err)
}
return wd
}
// cd changes the current directory to the named directory. Note that
// using this means that the test must not be run in parallel with any
// other tests.
func (tg *testgoData) cd(dir string) {
if tg.wd == "" {
tg.wd = tg.pwd()
}
tg.must(os.Chdir(dir))
}
// setenv sets an environment variable to use when running the test go
// command.
func (tg *testgoData) setenv(name, val string) {
tg.unsetenv(name)
tg.env = append(tg.env, name+"="+val)
}
// unsetenv removes an environment variable.
func (tg *testgoData) unsetenv(name string) {
if tg.env == nil {
tg.env = append([]string(nil), os.Environ()...)
}
for i, v := range tg.env {
if strings.HasPrefix(v, name+"=") {
tg.env = append(tg.env[:i], tg.env[i+1:]...)
break
}
}
}
// doRun runs the test go command, recording stdout and stderr and
// returning exit status.
func (tg *testgoData) doRun(args []string) error {
if !canRun {
panic("runTestGo called but canRun false")
panic("testgoData.doRun called but canRun false")
}
tg.t.Logf("running testgo %v", args)
var prog string
if tg.wd == "" {
prog = "./testgo" + exeSuffix
} else {
prog = filepath.Join(tg.wd, "testgo"+exeSuffix)
}
cmd := exec.Command(prog, args...)
tg.stdout.Reset()
tg.stderr.Reset()
cmd.Stdout = &tg.stdout
cmd.Stderr = &tg.stderr
cmd.Env = tg.env
status := cmd.Run()
if tg.stdout.Len() > 0 {
tg.t.Log("standard output:")
tg.t.Log(tg.stdout.String())
}
if tg.stderr.Len() > 0 {
tg.t.Log("standard error:")
tg.t.Log(tg.stderr.String())
}
tg.ran = true
return status
}
cmd := exec.Command("./testgo.exe", args...)
var ob, eb bytes.Buffer
cmd.Stdout = &ob
cmd.Stderr = &eb
if len(addEnv) > 0 {
cmd.Env = append(addEnv, os.Environ()...)
// run runs the test go command, and expects it to succeed.
func (tg *testgoData) run(args ...string) {
if status := tg.doRun(args); status != nil {
tg.t.Logf("go %v failed unexpectedly: %v", args, status)
tg.t.FailNow()
}
err = cmd.Run()
return ob.String(), eb.String(), err
}
// tempFile describes a file to put into a temporary directory.
type tempFile struct {
path string
contents string
// runFail runs the test go command, and expects it to fail.
func (tg *testgoData) runFail(args ...string) {
if status := tg.doRun(args); status == nil {
tg.t.Fatal("testgo succeeded unexpectedly")
} else {
tg.t.Log("testgo failed as expected:", status)
}
}
// tempDir describes a temporary directory created for a single test.
type tempDir struct {
name string
// getStdout returns standard output of the testgo run as a string.
func (tg *testgoData) getStdout() string {
if !tg.ran {
tg.t.Fatal("internal testsuite error: stdout called before run")
}
return tg.stdout.String()
}
// makeTempDir creates a temporary directory for a single test.
func makeTempDir(t *testing.T, files []tempFile) *tempDir {
dir, err := ioutil.TempDir("", "gotest")
if err != nil {
t.Fatal(err)
// getStderr returns standard error of the testgo run as a string.
func (tg *testgoData) getStderr() string {
if !tg.ran {
tg.t.Fatal("internal testsuite error: stdout called before run")
}
for _, f := range files {
if err := ioutil.WriteFile(filepath.Join(dir, f.path), []byte(f.contents), 0666); err != nil {
t.Fatal(err)
return tg.stderr.String()
}
// doGrepMatch looks for a regular expression in a buffer, and returns
// whether it is found. The regular expression is matched against
// each line separately, as with the grep command.
func (tg *testgoData) doGrepMatch(match string, b *bytes.Buffer) bool {
if !tg.ran {
tg.t.Fatal("internal testsuite error: grep called before run")
}
re := regexp.MustCompile(match)
for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) {
if re.Match(ln) {
return true
}
}
return false
}
// doGrep looks for a regular expression in a buffer and fails if it
// is not found. The name argument is the name of the output we are
// searching, "output" or "error". The msg argument is logged on
// failure.
func (tg *testgoData) doGrep(match string, b *bytes.Buffer, name, msg string) {
if !tg.doGrepMatch(match, b) {
tg.t.Log(msg)
tg.t.Logf("pattern %v not found in standard %s", match, name)
tg.t.FailNow()
}
}
// grepStdout looks for a regular expression in the test run's
// standard output and fails, logging msg, if it is not found.
func (tg *testgoData) grepStdout(match, msg string) {
tg.doGrep(match, &tg.stdout, "output", msg)
}
// grepStderr looks for a regular expression in the test run's
// standard error and fails, logging msg, if it is not found.
func (tg *testgoData) grepStderr(match, msg string) {
tg.doGrep(match, &tg.stderr, "error", msg)
}
// grepBoth looks for a regular expression in the test run's standard
// output or stand error and fails, logging msg, if it is not found.
func (tg *testgoData) grepBoth(match, msg string) {
if !tg.doGrepMatch(match, &tg.stdout) && !tg.doGrepMatch(match, &tg.stderr) {
tg.t.Log(msg)
tg.t.Logf("pattern %v not found in standard output or standard error", match)
tg.t.FailNow()
}
}
// doGrepNot looks for a regular expression in a buffer and fails if
// it is found. The name and msg arguments are as for doGrep.
func (tg *testgoData) doGrepNot(match string, b *bytes.Buffer, name, msg string) {
if tg.doGrepMatch(match, b) {
tg.t.Log(msg)
tg.t.Logf("pattern %v found unexpectedly in standard %s", match, name)
tg.t.FailNow()
}
}
// grepStdoutNot looks for a regular expression in the test run's
// standard output and fails, logging msg, if it is found.
func (tg *testgoData) grepStdoutNot(match, msg string) {
tg.doGrepNot(match, &tg.stdout, "output", msg)
}
// grepStderrNot looks for a regular expression in the test run's
// standard error and fails, logging msg, if it is found.
func (tg *testgoData) grepStderrNot(match, msg string) {
tg.doGrepNot(match, &tg.stderr, "error", msg)
}
// grepBothNot looks for a regular expression in the test run's
// standard output or stand error and fails, logging msg, if it is
// found.
func (tg *testgoData) grepBothNot(match, msg string) {
if tg.doGrepMatch(match, &tg.stdout) || tg.doGrepMatch(match, &tg.stderr) {
tg.t.Log(msg)
tg.t.Fatalf("pattern %v found unexpectedly in standard output or standard error", match)
}
}
// doGrepCount counts the number of times a regexp is seen in a buffer.
func (tg *testgoData) doGrepCount(match string, b *bytes.Buffer) int {
if !tg.ran {
tg.t.Fatal("internal testsuite error: doGrepCount called before run")
}
re := regexp.MustCompile(match)
c := 0
for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) {
if re.Match(ln) {
c++
}
}
return &tempDir{dir}
return c
}
// path returns the absolute pathname to file within tempDir.
func (td *tempDir) path(name string) string {
return filepath.Join(td.name, name)
// grepCountStdout returns the number of times a regexp is seen in
// standard output.
func (tg *testgoData) grepCountStdout(match string) int {
return tg.doGrepCount(match, &tg.stdout)
}
// Remove a temporary directory after a test completes. This is
// normally called via defer.
func (td *tempDir) remove(t *testing.T) {
if err := os.RemoveAll(td.name); err != nil {
fmt.Fprintln(os.Stderr, err)
// grepCountStderr returns the number of times a regexp is seen in
// standard error.
func (tg *testgoData) grepCountStderr(match string) int {
return tg.doGrepCount(match, &tg.stderr)
}
// grepCountBoth returns the number of times a regexp is seen in both
// standard output and standard error.
func (tg *testgoData) grepCountBoth(match string) int {
return tg.doGrepCount(match, &tg.stdout) + tg.doGrepCount(match, &tg.stderr)
}
// creatingTemp records that the test plans to create a temporary file
// or directory. If the file or directory exists already, it will be
// removed. When the test completes, the file or directory will be
// removed if it exists.
func (tg *testgoData) creatingTemp(path string) {
if filepath.IsAbs(path) && !strings.HasPrefix(path, tg.tempdir) {
tg.t.Fatal("internal testsuite error: creatingTemp(%q) with absolute path not in temporary directory")
}
// If we have changed the working directory, make sure we have
// an absolute path, because we are going to change directory
// back before we remove the temporary.
if tg.wd != "" && !filepath.IsAbs(path) {
path = filepath.Join(tg.pwd(), path)
}
tg.must(os.RemoveAll(path))
tg.temps = append(tg.temps, path)
}
// makeTempdir makes a temporary directory for a run of testgo. If
// the temporary directory was already created, this does nothing.
func (tg *testgoData) makeTempdir() {
if tg.tempdir == "" {
var err error
tg.tempdir, err = ioutil.TempDir("", "gotest")
tg.must(err)
}
}
// tempFile adds a temporary file for a run of testgo.
func (tg *testgoData) tempFile(path, contents string) {
tg.makeTempdir()
tg.must(os.MkdirAll(filepath.Join(tg.tempdir, filepath.Dir(path)), 0755))
tg.must(ioutil.WriteFile(filepath.Join(tg.tempdir, path), []byte(contents), 0644))
}
// tempDir adds a temporary directory for a run of testgo.
func (tg *testgoData) tempDir(path string) {
tg.makeTempdir()
if err := os.MkdirAll(filepath.Join(tg.tempdir, path), 0755); err != nil && !os.IsExist(err) {
tg.t.Fatal(err)
}
}
// path returns the absolute pathname to file with the temporary
// directory.
func (tg *testgoData) path(name string) string {
if tg.tempdir == "" {
tg.t.Fatalf("internal testsuite error: path(%q) with no tempdir", name)
}
if name == "." {
return tg.tempdir
}
return filepath.Join(tg.tempdir, name)
}
// wantExecutable fails with msg if path is not executable.
func (tg *testgoData) wantExecutable(path, msg string) {
if st, err := os.Stat(path); err != nil {
if !os.IsNotExist(err) {
tg.t.Log(err)
}
tg.t.Fatal(msg)
} else {
if runtime.GOOS != "windows" && st.Mode()&0111 == 0 {
tg.t.Fatalf("binary %s exists but is not executable", path)
}
}
}
// isStale returns whether pkg is stale.
func (tg *testgoData) isStale(pkg string) bool {
tg.run("list", "-f", "{{.Stale}}", pkg)
switch v := strings.TrimSpace(tg.getStdout()); v {
case "true":
return true
case "false":
return false
default:
tg.t.Fatalf("unexpected output checking staleness of package %v: %v", pkg, v)
panic("unreachable")
}
}
// wantStale fails with msg if pkg is not stale.
func (tg *testgoData) wantStale(pkg, msg string) {
if !tg.isStale(pkg) {
tg.t.Fatal(msg)
}
}
// wantNotStale fails with msg if pkg is stale.
func (tg *testgoData) wantNotStale(pkg, msg string) {
if tg.isStale(pkg) {
tg.t.Fatal(msg)
}
}
// cleanup cleans up a test that runs testgo.
func (tg *testgoData) cleanup() {
if tg.wd != "" {
if err := os.Chdir(tg.wd); err != nil {
// We are unlikely to be able to continue.
fmt.Fprintln(os.Stderr, "could not restore working directory, crashing:", err)
os.Exit(2)
}
}
for _, path := range tg.temps {
tg.check(os.RemoveAll(path))
}
if tg.tempdir != "" {
tg.check(os.RemoveAll(tg.tempdir))
}
}
func TestFileLineInErrorMessages(t *testing.T) {
checkTestGo(t)
td := makeTempDir(t, []tempFile{{"err.go", `package main; import "bar"`}})
defer td.remove(t)
path := td.path("err.go")
stdout, stderr, err := runTestGo(nil, "run", path)
if err == nil {
t.Fatal("go command did not fail")
}
lines := strings.Split(stderr, "\n")
for _, ln := range lines {
if strings.HasPrefix(ln, path+":") {
// Test has passed.
tg := testgo(t)
defer tg.cleanup()
tg.tempFile("err.go", `package main; import "bar"`)
path := tg.path("err.go")
tg.runFail("run", path)
tg.grepStderr("^"+regexp.QuoteMeta(path)+":", "missing file:line in error message")
}
func TestProgramNameInCrashMessages(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.tempFile("triv.go", `package main; func main() {}`)
tg.runFail("build", "-ldflags", "-crash_for_testing", tg.path("triv.go"))
tg.grepStderr(`[/\\]tool[/\\].*[/\\]link`, "missing linker name in error message")
}
func TestBrokenTestsWithoutTestFunctionsAllFail(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("test", "./testdata/src/badtest/...")
tg.grepBothNot("^ok", "test passed unexpectedly")
tg.grepBoth("FAIL.*badtest/badexec", "test did not run everything")
tg.grepBoth("FAIL.*badtest/badsyntax", "test did not run everything")
tg.grepBoth("FAIL.*badtest/badvar", "test did not run everything")
}
func TestGoBuildDashAInDevBranch(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.run("install", "math") // should be up to date already but just in case
tg.setenv("TESTGO_IS_GO_RELEASE", "0")
tg.run("build", "-v", "-a", "math")
tg.grepStderr("runtime", "testgo build -a math in dev branch DID NOT build runtime, but should have")
}
func TestGoBuilDashAInReleaseBranch(t *testing.T) {
if testing.Short() {
t.Skip("don't rebuild the standard libary in short mode")
}
tg := testgo(t)
defer tg.cleanup()
tg.run("install", "math") // should be up to date already but just in case
tg.setenv("TESTGO_IS_GO_RELEASE", "1")
tg.run("build", "-v", "-a", "math")
tg.grepStderrNot("runtime", "testgo build -a math in dev branch DID build runtime, but should NOT have")
}
func TestGoInstallCleansUpAfterGoBuild(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping on Windows because of http://golang.org/issue/9645")
}
tg := testgo(t)
defer tg.cleanup()
tg.tempFile("src/mycmd/main.go", `package main; func main(){}`)
tg.setenv("GOPATH", tg.path("."))
tg.cd(tg.path("src/mycmd"))
doesNotExist := func(file, msg string) {
if _, err := os.Stat(file); err == nil {
t.Fatal(msg)
} else if !os.IsNotExist(err) {
// See http://golang.org/issue/11132.
if runtime.GOOS == "plan9" && strings.Contains(err.Error(), "stat buffer too short") {
return
}
t.Fatal(msg, "error:", err)
}
}
tg.run("build")
tg.wantExecutable("mycmd"+exeSuffix, "testgo build did not write command binary")
tg.run("install")
doesNotExist("mycmd"+exeSuffix, "testgo install did not remove command binary")
tg.run("build")
tg.wantExecutable("mycmd"+exeSuffix, "testgo build did not write command binary (second time)")
// Running install with arguments does not remove the target,
// even in the same directory.
tg.run("install", "mycmd")
tg.wantExecutable("mycmd"+exeSuffix, "testgo install mycmd removed command binary when run in mycmd")
tg.run("build")
tg.wantExecutable("mycmd"+exeSuffix, "testgo build did not write command binary (third time)")
// And especially not outside the directory.
tg.cd(tg.path("."))
if data, err := ioutil.ReadFile("src/mycmd/mycmd"); err != nil {
t.Fatal("could not read file:", err)
} else {
if err := ioutil.WriteFile("mycmd", data, 0555); err != nil {
t.Fatal("could not write file:", err)
}
}
tg.run("install", "mycmd")
tg.wantExecutable("src/mycmd/mycmd"+exeSuffix, "testgo install mycmd removed command binary from its source dir when run outside mycmd")
tg.wantExecutable("mycmd"+exeSuffix, "testgo install mycmd removed command binary from current dir when run outside mycmd")
}
func TestGoInstallRebuildsStalePackagesInOtherGOPATH(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.tempFile("d1/src/p1/p1.go", `package p1
import "p2"
func F() { p2.F() }
`)
tg.tempFile("d2/src/p2/p2.go", `package p2
func F() {}
`)
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", tg.path("d1")+sep+tg.path("d2"))
tg.run("install", "p1")
tg.wantNotStale("p1", "./testgo list mypkg claims p1 is stale, incorrectly")
tg.wantNotStale("p2", "./testgo list mypkg claims p2 is stale, incorrectly")
// TODO(iant): Sleep for one "tick", where a tick is the
// granularity of mtime on the file system.
time.Sleep(time.Second)
if f, err := os.OpenFile(tg.path("d2/src/p2/p2.go"), os.O_WRONLY|os.O_APPEND, 0); err != nil {
t.Fatal(err)
} else if _, err = f.WriteString(`func G() {}`); err != nil {
t.Fatal(err)
} else {
tg.must(f.Close())
}
tg.wantStale("p2", "./testgo list mypkg claims p2 is NOT stale, incorrectly")
tg.wantStale("p1", "./testgo list mypkg claims p1 is NOT stale, incorrectly")
tg.run("install", "p1")
tg.wantNotStale("p2", "./testgo list mypkg claims p2 is stale after reinstall, incorrectly")
tg.wantNotStale("p1", "./testgo list mypkg claims p1 is stale after reinstall, incorrectly")
}
func TestGoInstallDetectsRemovedFiles(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.tempFile("src/mypkg/x.go", `package mypkg`)
tg.tempFile("src/mypkg/y.go", `package mypkg`)
tg.tempFile("src/mypkg/z.go", `// +build missingtag
package mypkg`)
tg.setenv("GOPATH", tg.path("."))
tg.run("install", "mypkg")
tg.wantNotStale("mypkg", "./testgo list mypkg claims mypkg is stale, incorrectly")
// z.go was not part of the build; removing it is okay.
tg.must(os.Remove(tg.path("src/mypkg/z.go")))
tg.wantNotStale("mypkg", "./testgo list mypkg claims mypkg is stale after removing z.go; should not be stale")
// y.go was part of the package; removing it should be detected.
tg.must(os.Remove(tg.path("src/mypkg/y.go")))
tg.wantStale("mypkg", "./testgo list mypkg claims mypkg is NOT stale after removing y.go; should be stale")
}
func TestGoInstsallDetectsRemovedFilesInPackageMain(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.tempFile("src/mycmd/x.go", `package main
func main() {}
`)
tg.tempFile("src/mycmd/y.go", `package main`)
tg.tempFile("src/mycmd/z.go", `// +build missingtag
package main
`)
tg.setenv("GOPATH", tg.path("."))
tg.run("install", "mycmd")
tg.wantNotStale("mycmd", "./testgo list mypkg claims mycmd is stale, incorrectly")
// z.go was not part of the build; removing it is okay.
tg.must(os.Remove(tg.path("src/mycmd/z.go")))
tg.wantNotStale("mycmd", "./testgo list mycmd claims mycmd is stale after removing z.go; should not be stale")
// y.go was part of the package; removing it should be detected.
tg.must(os.Remove(tg.path("src/mycmd/y.go")))
tg.wantStale("mycmd", "./testgo list mycmd claims mycmd is NOT stale after removing y.go; should be stale")
}
func testLocalRun(tg *testgoData, local, match string) {
out, err := exec.Command("./hello" + exeSuffix).Output()
if err != nil {
tg.t.Fatal("error running hello:", err)
}
if !regexp.MustCompile(match).Match(out) {
tg.t.Log(string(out))
tg.t.Errorf("testdata/%s/easy.go did not generate expected output", local)
}
}
func testLocalEasy(tg *testgoData, local string) {
tg.creatingTemp("./hello" + exeSuffix)
tg.run("build", "-o", "hello"+exeSuffix, filepath.Join("testdata", local, "easy.go"))
testLocalRun(tg, local, `(?m)^easysub\.Hello`)
}
func testLocalEasySub(tg *testgoData, local string) {
tg.creatingTemp("./hello" + exeSuffix)
tg.run("build", "-o", "hello"+exeSuffix, filepath.Join("testdata", local, "easysub", "main.go"))
testLocalRun(tg, local, `(?m)^easysub\.Hello`)
}
func testLocalHard(tg *testgoData, local string) {
tg.creatingTemp("./hello" + exeSuffix)
tg.run("build", "-o", "hello"+exeSuffix, filepath.Join("testdata", local, "hard.go"))
testLocalRun(tg, local, `(?m)^sub\.Hello`)
}
func testLocalInstall(tg *testgoData, local string) {
tg.runFail("install", filepath.Join("testdata", local, "easy.go"))
}
func TestLocalImportsEasy(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
testLocalEasy(tg, "local")
}
func TestLocalImportsEasySub(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
testLocalEasySub(tg, "local")
}
func TestLocalImportsHard(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
testLocalHard(tg, "local")
}
func TestLocalImportsGoInstallShouldFail(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
testLocalInstall(tg, "local")
}
const badDirName = `#$%:, &()*;<=>?\^{}`
func copyBad(tg *testgoData) {
if runtime.GOOS == "windows" {
tg.t.Skipf("skipping test because %q is an invalid directory name", badDirName)
}
tg.must(filepath.Walk("testdata/local",
func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
var data []byte
data, err = ioutil.ReadFile(path)
if err != nil {
return err
}
newpath := strings.Replace(path, "local", badDirName, 1)
tg.tempFile(newpath, string(data))
return nil
}))
tg.cd(tg.path("."))
}
func TestBadImportsEasy(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
copyBad(tg)
testLocalEasy(tg, badDirName)
}
func TestBadImportsEasySub(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
copyBad(tg)
testLocalEasySub(tg, badDirName)
}
func TestBadImportsHard(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
copyBad(tg)
testLocalHard(tg, badDirName)
}
func TestBadImportsGoInstallShouldFail(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
copyBad(tg)
testLocalInstall(tg, badDirName)
}
func TestInternalPackagesInGOROOTAreRespected(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("build", "-v", "./testdata/testinternal")
tg.grepBoth("use of internal package not allowed", "wrong error message for testdata/testinternal")
}
func TestInternalPackagesOutsideGOROOTAreRespected(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("build", "-v", "./testdata/testinternal2")
tg.grepBoth("use of internal package not allowed", "wrote error message for testdata/testinternal2")
}
func testMove(t *testing.T, vcs, url, base, config string) {
if testing.Short() {
t.Skip("skipping test that uses network in short mode")
}
tg := testgo(t)
defer tg.cleanup()
tg.tempDir("src")
tg.setenv("GOPATH", tg.path("."))
tg.run("get", "-d", url)
tg.run("get", "-d", "-u", url)
switch vcs {
case "svn":
// SVN doesn't believe in text files so we can't just edit the config.
// Check out a different repo into the wrong place.
tg.must(os.RemoveAll(tg.path("src/code.google.com/p/rsc-svn")))
tg.run("get", "-d", "-u", "code.google.com/p/rsc-svn2/trunk")
tg.must(os.Rename(tg.path("src/code.google.com/p/rsc-svn2"), tg.path("src/code.google.com/p/rsc-svn")))
default:
path := tg.path(filepath.Join("src", config))
data, err := ioutil.ReadFile(path)
tg.must(err)
data = bytes.Replace(data, []byte(base), []byte(base+"XXX"), -1)
tg.must(ioutil.WriteFile(path, data, 0644))
}
if vcs == "git" {
// git will ask for a username and password when we
// run go get -d -f -u. An empty username and
// password will work. Prevent asking by setting
// GIT_ASKPASS.
tg.creatingTemp("sink" + exeSuffix)
tg.tempFile("src/sink/sink.go", `package main; func main() {}`)
tg.run("build", "-o", "sink"+exeSuffix, "sink")
tg.setenv("GIT_ASKPASS", filepath.Join(tg.pwd(), "sink"+exeSuffix))
}
tg.runFail("get", "-d", "-u", url)
tg.grepStderr("is a custom import path for", "go get -d -u "+url+" failed for wrong reason")
tg.runFail("get", "-d", "-f", "-u", url)
tg.grepStderr("validating server certificate|not found", "go get -d -f -u "+url+" failed for wrong reason")
}
func TestMoveGit(t *testing.T) {
testMove(t, "git", "rsc.io/pdf", "pdf", "rsc.io/pdf/.git/config")
}
// TODO(rsc): Set up a test case on bitbucket for hg.
// func TestMoveHG(t *testing.T) {
// testMove(t, "hg", "rsc.io/x86/x86asm", "x86", "rsc.io/x86/.hg/hgrc")
// }
// TODO(rsc): Set up a test case on SourceForge (?) for svn.
// func testMoveSVN(t *testing.T) {
// testMove(t, "svn", "code.google.com/p/rsc-svn/trunk", "-", "-")
// }
func TestImportCommandMatch(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/importcom"))
tg.run("build", "./testdata/importcom/works.go")
}
func TestImportCommentMismatch(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/importcom"))
tg.runFail("build", "./testdata/importcom/wrongplace.go")
tg.grepStderr(`wrongplace expects import "my/x"`, "go build did not mention incorrect import")
}
func TestImportCommentSyntaxError(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/importcom"))
tg.runFail("build", "./testdata/importcom/bad.go")
tg.grepStderr("cannot parse import comment", "go build did not mention syntax error")
}
func TestImportCommentConflict(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/importcom"))
tg.runFail("build", "./testdata/importcom/conflict.go")
tg.grepStderr("found import comments", "go build did not mention comment conflict")
}
func TestDisallowedCSourceFiles(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.runFail("build", "badc")
tg.grepStderr("C source files not allowed", "go test did not say C source files not allowed")
}
func TestErrorMessageForSyntaxErrorInTestGoFileSaysFAIL(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.runFail("test", "syntaxerror")
tg.grepStderr("FAIL", "go test did not say FAIL")
}
func TestWildcardsDoNotLookInUselessDirectories(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.runFail("list", "...")
tg.grepBoth("badpkg", "go list ... failure does not mention badpkg")
tg.run("list", "m...")
}
func TestRelativeImportsGoTest(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.run("test", "./testdata/testimport")
}
func TestRelativeImportsGoTestDashI(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.run("test", "-i", "./testdata/testimport")
}
func TestRelativeImportsInCommandLinePackage(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
files, err := filepath.Glob("./testdata/testimport/*.go")
tg.must(err)
tg.run(append([]string{"test"}, files...)...)
}
func TestVersionControlErrorMessageIncludesCorrectDirectory(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/shadow/root1"))
tg.runFail("get", "-u", "foo")
// TODO(iant): We should not have to use strconv.Quote here.
// The code in vcs.go should be changed so that it is not required.
quoted := strconv.Quote(filepath.Join("testdata", "shadow", "root1", "src", "foo"))
quoted = quoted[1 : len(quoted)-1]
tg.grepStderr(regexp.QuoteMeta(quoted), "go get -u error does not mention shadow/root1/src/foo")
}
func TestInstallFailsWithNoBuildableFiles(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.setenv("CGO_ENABLED", "0")
tg.runFail("install", "cgotest")
tg.grepStderr("no buildable Go source files", "go install cgotest did not report 'no buildable Go Source files'")
}
// Test that without $GOBIN set, binaries get installed
// into the GOPATH bin directory.
func TestInstallIntoGOPATH(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.creatingTemp("testdata/bin/go-cmd-test" + exeSuffix)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.run("install", "go-cmd-test")
tg.wantExecutable("testdata/bin/go-cmd-test"+exeSuffix, "go install go-cmd-test did not write to testdata/bin/go-cmd-test")
}
func TestPackageMainTestImportsArchiveNotBinary(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
gobin := filepath.Join(tg.pwd(), "testdata", "bin")
tg.creatingTemp(gobin)
tg.setenv("GOBIN", gobin)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.must(os.Chtimes("./testdata/src/main_test/m.go", time.Now(), time.Now()))
tg.run("test", "main_test")
tg.run("install", "main_test")
tg.wantNotStale("main_test", "after go install, main listed as stale")
tg.run("test", "main_test")
}
// With $GOBIN set, binaries get installed to $GOBIN.
func TestInstallIntoGOBIN(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
gobin := filepath.Join(tg.pwd(), "testdata", "bin1")
tg.creatingTemp(gobin)
tg.setenv("GOBIN", gobin)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.run("install", "go-cmd-test")
tg.wantExecutable("testdata/bin1/go-cmd-test"+exeSuffix, "go install go-cmd-test did not write to testdata/bin1/go-cmd-test")
}
// Without $GOBIN set, installing a program outside $GOPATH should fail
// (there is nowhere to install it).
func TestInstallWithoutDestinationFails(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("install", "testdata/src/go-cmd-test/helloworld.go")
tg.grepStderr("no install location for .go files listed on command line", "wrong error")
}
// With $GOBIN set, should install there.
func TestInstallToGOBINCommandLinePackage(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
gobin := filepath.Join(tg.pwd(), "testdata", "bin1")
tg.creatingTemp(gobin)
tg.setenv("GOBIN", gobin)
tg.run("install", "testdata/src/go-cmd-test/helloworld.go")
tg.wantExecutable("testdata/bin1/helloworld"+exeSuffix, "go install testdata/src/go-cmd-test/helloworld.go did not write testdata/bin1/helloworld")
}
func TestGodocInstalls(t *testing.T) {
if testing.Short() {
t.Skip("skipping test that uses network in short mode")
}
// godoc installs into GOBIN
tg := testgo(t)
defer tg.cleanup()
tg.tempDir("gobin")
tg.setenv("GOPATH", tg.path("."))
tg.setenv("GOBIN", tg.path("gobin"))
tg.run("get", "golang.org/x/tools/cmd/godoc")
tg.wantExecutable(tg.path("gobin/godoc"), "did not install godoc to $GOBIN")
tg.unsetenv("GOBIN")
// godoc installs into GOROOT
goroot := runtime.GOROOT()
tg.setenv("GOROOT", goroot)
tg.check(os.RemoveAll(filepath.Join(goroot, "bin", "godoc")))
tg.run("install", "golang.org/x/tools/cmd/godoc")
tg.wantExecutable(filepath.Join(goroot, "bin", "godoc"), "did not install godoc to $GOROOT/bin")
}
func TestInstalls(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.tempDir("gobin")
tg.setenv("GOPATH", tg.path("."))
goroot := runtime.GOROOT()
tg.setenv("GOROOT", goroot)
// cmd/fix installs into tool
tg.run("env", "GOOS")
goos := strings.TrimSpace(tg.getStdout())
tg.setenv("GOOS", goos)
tg.run("env", "GOARCH")
goarch := strings.TrimSpace(tg.getStdout())
tg.setenv("GOARCH", goarch)
fixbin := filepath.Join(goroot, "pkg", "tool", goos+"_"+goarch, "fix") + exeSuffix
tg.must(os.RemoveAll(fixbin))
tg.run("install", "cmd/fix")
tg.wantExecutable(fixbin, "did not install cmd/fix to $GOROOT/pkg/tool")
tg.must(os.Remove(fixbin))
tg.setenv("GOBIN", tg.path("gobin"))
tg.run("install", "cmd/fix")
tg.wantExecutable(fixbin, "did not install cmd/fix to $GOROOT/pkg/tool with $GOBIN set")
tg.unsetenv("GOBIN")
// gopath program installs into GOBIN
tg.tempFile("src/progname/p.go", `package main; func main() {}`)
tg.setenv("GOBIN", tg.path("gobin"))
tg.run("install", "progname")
tg.unsetenv("GOBIN")
tg.wantExecutable(tg.path("gobin/progname")+exeSuffix, "did not install progname to $GOBIN/progname")
// gopath program installs into GOPATH/bin
tg.run("install", "progname")
tg.wantExecutable(tg.path("bin/progname")+exeSuffix, "did not install progname to $GOPATH/bin/progname")
}
func TestRejectRelativePathsInGOPATHCommandLinePackage(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", ".")
tg.runFail("build", "testdata/src/go-cmd-test/helloworld.go")
}
func TestRejectRelativePathsInGOPATH(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", sep+filepath.Join(tg.pwd(), "testdata")+sep+".")
tg.runFail("build", "go-cmd-test")
}
// Issue 4104.
func TestGoTestWithPackageListedMultipleTimes(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.run("test", "fmt", "fmt", "fmt", "fmt", "fmt")
if strings.Index(strings.TrimSpace(tg.getStdout()), "\n") != -1 {
t.Error("go test fmt fmt fmt fmt fmt tested the same package multiple times")
}
}
func TestGoListHasAConsistentOrder(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.run("list", "std")
first := tg.getStdout()
tg.run("list", "std")
if first != tg.getStdout() {
t.Error("go list std ordering is inconsistent")
}
}
func TestGoListStdDoesNotIncludeCommands(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.run("list", "std")
tg.grepStdoutNot("cmd/", "go list std shows commands")
}
func TestGoListCmdOnlyShowsCommands(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.run("list", "cmd")
out := strings.TrimSpace(tg.getStdout())
for _, line := range strings.Split(out, "\n") {
if strings.Index(line, "cmd/") == -1 {
t.Error("go list cmd shows non-commands")
break
}
}
}
// Issue 4096. Validate the output of unsuccessful go install foo/quxx.
func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("install", "foo/quxx")
if tg.grepCountBoth(`cannot find package "foo/quxx" in any of`) != 1 {
t.Error(`go install foo/quxx expected error: .*cannot find package "foo/quxx" in any of`)
}
}
func TestGOROOTSearchFailureReporting(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("install", "foo/quxx")
if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("foo", "quxx"))+` \(from \$GOROOT\)$`) != 1 {
t.Error(`go install foo/quxx expected error: .*foo/quxx (from $GOROOT)`)
}
}
func TestMultipleGOPATHEntriesReportedSeparately(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
tg.runFail("install", "foo/quxx")
if tg.grepCountBoth(`testdata[/\\].[/\\]src[/\\]foo[/\\]quxx`) != 2 {
t.Error(`go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)\n.*testdata/b/src/foo/quxx`)
}
}
// Test (from $GOPATH) annotation is reported for the first GOPATH entry,
func TestMentionGOPATHInFirstGOPATHEntry(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
tg.runFail("install", "foo/quxx")
if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("testdata", "a", "src", "foo", "quxx"))+` \(from \$GOPATH\)$`) != 1 {
t.Error(`go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)`)
}
}
// but not on the second.
func TestMentionGOPATHNotOnSecondEntry(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
tg.runFail("install", "foo/quxx")
if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("testdata", "b", "src", "foo", "quxx"))+`$`) != 1 {
t.Error(`go install foo/quxx expected error: .*testdata/b/src/foo/quxx`)
}
}
// Test missing GOPATH is reported.
func TestMissingGOPATHIsReported(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", "")
tg.runFail("install", "foo/quxx")
if tg.grepCountBoth(`\(\$GOPATH not set\)$`) != 1 {
t.Error(`go install foo/quxx expected error: ($GOPATH not set)`)
}
}
// Issue 4186. go get cannot be used to download packages to $GOROOT.
// Test that without GOPATH set, go get should fail.
func TestWithoutGOPATHGoGetFails(t *testing.T) {
if testing.Short() {
t.Skip("skipping test that uses network in short mode")
}
tg := testgo(t)
defer tg.cleanup()
tg.tempDir("src")
tg.setenv("GOPATH", "")
tg.setenv("GOROOT", tg.path("."))
tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch")
}
// Test that with GOPATH=$GOROOT, go get should fail.
func TestWithGOPATHEqualsGOROOTGoGetFails(t *testing.T) {
if testing.Short() {
t.Skip("skipping test that uses network in short mode")
}
t.Log(err)
t.Log(stdout)
t.Log(stderr)
t.Error("missing file:line in error message")
tg := testgo(t)
defer tg.cleanup()
tg.tempDir("src")
tg.setenv("GOPATH", tg.path("."))
tg.setenv("GOROOT", tg.path("."))
tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch")
}
func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.tempFile("main.go", `package main
var extern string
func main() {
println(extern)
}`)
tg.run("run", "-ldflags", `-X main.extern "hello world"`, tg.path("main.go"))
tg.grepStderr("^hello world", `ldflags -X main.extern 'hello world' failed`)
}
func TestGoTestCpuprofileLeavesBinaryBehind(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.creatingTemp("strings.prof")
tg.creatingTemp("strings.test" + exeSuffix)
tg.run("test", "-cpuprofile", "strings.prof", "strings")
tg.wantExecutable("strings.test"+exeSuffix, "go test -cpuprofile did not create strings.test")
}
func TestGoTestCpuProfileDashOControlsBinaryLocation(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.creatingTemp("strings.prof")
tg.creatingTemp("mystrings.test" + exeSuffix)
tg.run("test", "-cpuprofile", "strings.prof", "-o", "mystrings.test"+exeSuffix, "strings")
tg.wantExecutable("mystrings.test"+exeSuffix, "go test -cpuprofile -o mystrings.test did not create mystrings.test")
}
func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.creatingTemp("mystrings.test" + exeSuffix)
tg.run("test", "-c", "-o", "mystrings.test"+exeSuffix, "strings")
tg.wantExecutable("mystrings.test"+exeSuffix, "go test -c -o mystrings.test did not create mystrings.test")
}
func TestGoTestDashOWritesBinary(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.creatingTemp("mystrings.test" + exeSuffix)
tg.run("test", "-o", "mystrings.test"+exeSuffix, "strings")
tg.wantExecutable("mystrings.test"+exeSuffix, "go test -o mystrings.test did not create mystrings.test")
}
// Issue 4568.
func TestSymlinksDoNotConfuseGoList(t *testing.T) {
switch runtime.GOOS {
case "plan9", "windows":
t.Skipf("skipping symlink test on %s", runtime.GOOS)
}
tg := testgo(t)
defer tg.cleanup()
tg.tempDir("src")
tg.must(os.Symlink(tg.path("."), tg.path("src/dir1")))
tg.tempFile("src/dir1/p.go", "package p")
tg.setenv("GOPATH", tg.path("."))
tg.cd(tg.path("src"))
tg.run("list", "-f", "{{.Root}}", "dir1")
if strings.TrimSpace(tg.getStdout()) != tg.path(".") {
t.Error("confused by symlinks")
}
}
// Issue 4515.
func TestInstallWithTags(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.tempDir("bin")
tg.tempFile("src/example/a/main.go", `package main
func main() {}`)
tg.tempFile("src/example/b/main.go", `// +build mytag
package main
func main() {}`)
tg.setenv("GOPATH", tg.path("."))
tg.run("install", "-tags", "mytag", "example/a", "example/b")
tg.wantExecutable(tg.path("bin/a"+exeSuffix), "go install example/a example/b did not install binaries")
tg.wantExecutable(tg.path("bin/b"+exeSuffix), "go install example/a example/b did not install binaries")
tg.must(os.Remove(tg.path("bin/a" + exeSuffix)))
tg.must(os.Remove(tg.path("bin/b" + exeSuffix)))
tg.run("install", "-tags", "mytag", "example/...")
tg.wantExecutable(tg.path("bin/a"+exeSuffix), "go install example/... did not install binaries")
tg.wantExecutable(tg.path("bin/b"+exeSuffix), "go install example/... did not install binaries")
tg.run("list", "-tags", "mytag", "example/b...")
if strings.TrimSpace(tg.getStdout()) != "example/b" {
t.Error("go list example/b did not find example/b")
}
}
// Issue 4773
func TestCaseCollisions(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.tempDir("src/example/a/pkg")
tg.tempDir("src/example/a/Pkg")
tg.tempDir("src/example/b")
tg.setenv("GOPATH", tg.path("."))
tg.tempFile("src/example/a/a.go", `package p
import (
_ "example/a/pkg"
_ "example/a/Pkg"
)`)
tg.tempFile("src/example/a/pkg/pkg.go", `package pkg`)
tg.tempFile("src/example/a/Pkg/pkg.go", `package pkg`)
tg.runFail("list", "example/a")
tg.grepStderr("case-insensitive import collision", "go list example/a did not report import collision")
tg.tempFile("src/example/b/file.go", `package b`)
tg.tempFile("src/example/b/FILE.go", `package b`)
f, err := os.Open(tg.path("src/example/b"))
tg.must(err)
names, err := f.Readdirnames(0)
tg.must(err)
tg.check(f.Close())
args := []string{"list"}
if len(names) == 2 {
// case-sensitive file system, let directory read find both files
args = append(args, "example/b")
} else {
// case-insensitive file system, list files explicitly on command line
args = append(args, tg.path("src/example/b/file.go"), tg.path("src/example/b/FILE.go"))
}
tg.runFail(args...)
tg.grepStderr("case-insensitive file name collision", "go list example/b did not report file name collision")
}
// Issue 8181.
func TestGoGetDashTIssue8181(t *testing.T) {
if testing.Short() {
t.Skip("skipping test that uses network in short mode")
}
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
tg.run("get", "-t", "code.google.com/p/go-get-issue-8181/a", "code.google.com/p/go-get-issue-8181/b")
tg.runFail("list", "...")
tg.grepStdout("go.tools/godoc", "missing expected go.tools/godoc")
}
func TestShadowingLogic(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
pwd := tg.pwd()
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", filepath.Join(pwd, "testdata", "shadow", "root1")+sep+filepath.Join(pwd, "testdata", "shadow", "root2"))
// The math in root1 is not "math" because the standard math is.
tg.run("list", "-f", "({{.ImportPath}}) ({{.ConflictDir}})", "./testdata/shadow/root1/src/math")
pwdForwardSlash := strings.Replace(pwd, string(os.PathSeparator), "/", -1)
if !strings.HasPrefix(pwdForwardSlash, "/") {
pwdForwardSlash = "/" + pwdForwardSlash
}
// The output will have makeImportValid applies, but we only
// bother to deal with characters we might reasonably see.
pwdForwardSlash = strings.Replace(pwdForwardSlash, ":", "_", -1)
want := "(_" + pwdForwardSlash + "/testdata/shadow/root1/src/math) (" + filepath.Join(runtime.GOROOT(), "src", "math") + ")"
if strings.TrimSpace(tg.getStdout()) != want {
t.Error("shadowed math is not shadowed; looking for", want)
}
// The foo in root1 is "foo".
tg.run("list", "-f", "({{.ImportPath}}) ({{.ConflictDir}})", "./testdata/shadow/root1/src/foo")
if strings.TrimSpace(tg.getStdout()) != "(foo) ()" {
t.Error("unshadowed foo is shadowed")
}
// The foo in root2 is not "foo" because the foo in root1 got there first.
tg.run("list", "-f", "({{.ImportPath}}) ({{.ConflictDir}})", "./testdata/shadow/root2/src/foo")
want = "(_" + pwdForwardSlash + "/testdata/shadow/root2/src/foo) (" + filepath.Join(pwd, "testdata", "shadow", "root1", "src", "foo") + ")"
if strings.TrimSpace(tg.getStdout()) != want {
t.Error("shadowed foo is not shadowed; looking for", want)
}
// The error for go install should mention the conflicting directory.
tg.runFail("install", "./testdata/shadow/root2/src/foo")
want = "go install: no install location for " + filepath.Join(pwd, "testdata", "shadow", "root2", "src", "foo") + ": hidden by " + filepath.Join(pwd, "testdata", "shadow", "root1", "src", "foo")
if strings.TrimSpace(tg.getStderr()) != want {
t.Error("wrong shadowed install error; looking for", want)
}
}
// Only succeeds if source order is preserved.
func TestSourceFileNameOrderPreserved(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.run("test", "testdata/example1_test.go", "testdata/example2_test.go")
}
// Check that coverage analysis works at all.
// Don't worry about the exact numbers but require not 0.0%.
func checkCoverage(tg *testgoData, data string) {
if regexp.MustCompile(`[^0-9]0\.0%`).MatchString(data) {
tg.t.Error("some coverage results are 0.0%")
}
tg.t.Log(data)
}
func TestCoverageRuns(t *testing.T) {
if testing.Short() {
t.Skip("don't build libraries for coverage in short mode")
}
tg := testgo(t)
defer tg.cleanup()
tg.run("test", "-short", "-coverpkg=strings", "strings", "regexp")
data := tg.getStdout() + tg.getStderr()
tg.run("test", "-short", "-cover", "strings", "math", "regexp")
data += tg.getStdout() + tg.getStderr()
checkCoverage(tg, data)
}
// Check that coverage analysis uses set mode.
func TestCoverageUsesSetMode(t *testing.T) {
if testing.Short() {
t.Skip("don't build libraries for coverage in short mode")
}
tg := testgo(t)
defer tg.cleanup()
tg.creatingTemp("testdata/cover.out")
tg.run("test", "-short", "-cover", "encoding/binary", "-coverprofile=testdata/cover.out")
data := tg.getStdout() + tg.getStderr()
if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil {
t.Error(err)
} else {
if !bytes.Contains(out, []byte("mode: set")) {
t.Error("missing mode: set")
}
}
checkCoverage(tg, data)
}
func TestCoverageUsesAtomicModeForRace(t *testing.T) {
if testing.Short() {
t.Skip("don't build libraries for coverage in short mode")
}
if !canRace {
t.Skip("skipping because race detector not supported")
}
tg := testgo(t)
defer tg.cleanup()
tg.creatingTemp("testdata/cover.out")
tg.run("test", "-short", "-race", "-cover", "encoding/binary", "-coverprofile=testdata/cover.out")
data := tg.getStdout() + tg.getStderr()
if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil {
t.Error(err)
} else {
if !bytes.Contains(out, []byte("mode: atomic")) {
t.Error("missing mode: atomic")
}
}
checkCoverage(tg, data)
}
func TestCoverageUsesActualSettingToOverrideEvenForRace(t *testing.T) {
if testing.Short() {
t.Skip("don't build libraries for coverage in short mode")
}
if !canRace {
t.Skip("skipping because race detector not supported")
}
tg := testgo(t)
defer tg.cleanup()
tg.creatingTemp("testdata/cover.out")
tg.run("test", "-short", "-race", "-cover", "encoding/binary", "-covermode=count", "-coverprofile=testdata/cover.out")
data := tg.getStdout() + tg.getStderr()
if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil {
t.Error(err)
} else {
if !bytes.Contains(out, []byte("mode: count")) {
t.Error("missing mode: count")
}
}
checkCoverage(tg, data)
}
func TestCoverageWithCgo(t *testing.T) {
if !canCgo {
t.Skip("skipping because cgo not enabled")
}
tg := testgo(t)
defer tg.cleanup()
tg.run("test", "-short", "-cover", "./testdata/cgocover")
data := tg.getStdout() + tg.getStderr()
checkCoverage(tg, data)
}
func TestCgoDependsOnSyscall(t *testing.T) {
if testing.Short() {
t.Skip("skipping test that removes $GOROOT/pkg/*_race in short mode")
}
if !canCgo {
t.Skip("skipping because cgo not enabled")
}
if !canRace {
t.Skip("skipping because race detector not supported")
}
tg := testgo(t)
defer tg.cleanup()
files, err := filepath.Glob(filepath.Join(runtime.GOROOT(), "pkg", "*_race"))
tg.must(err)
for _, file := range files {
tg.check(os.RemoveAll(file))
}
tg.tempFile("src/foo/foo.go", `
package foo
//#include <stdio.h>
import "C"`)
tg.setenv("GOPATH", tg.path("."))
tg.run("build", "-race", "foo")
}
func TestCgoShowsFullPathNames(t *testing.T) {
if !canCgo {
t.Skip("skipping because cgo not enabled")
}
tg := testgo(t)
defer tg.cleanup()
tg.tempFile("src/x/y/dirname/foo.go", `
package foo
import "C"
func f() {`)
tg.setenv("GOPATH", tg.path("."))
tg.runFail("build", "x/y/dirname")
tg.grepBoth("x/y/dirname", "error did not use full path")
}
func TestCgoHandlesWlORIGIN(t *testing.T) {
if !canCgo {
t.Skip("skipping because cgo not enabled")
}
tg := testgo(t)
defer tg.cleanup()
tg.tempFile("src/origin/origin.go", `package origin
// #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
// void f(void) {}
import "C"
func f() { C.f() }`)
tg.setenv("GOPATH", tg.path("."))
tg.run("build", "origin")
}
// "go test -c -test.bench=XXX fmt" should not hang'
func TestIssue6480(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.creatingTemp("fmt.test" + exeSuffix)
tg.run("test", "-c", "-test.bench=XXX", "fmt")
}
// cmd/cgo: undefined reference when linking a C-library using gccgo
func TestIssue7573(t *testing.T) {
if _, err := exec.LookPath("gccgo"); err != nil {
t.Skip("skipping because no gccgo compiler found")
}
tg := testgo(t)
defer tg.cleanup()
tg.tempFile("src/cgoref/cgoref.go", `
package main
// #cgo LDFLAGS: -L alibpath -lalib
// void f(void) {}
import "C"
func main() { C.f() }`)
tg.setenv("GOPATH", tg.path("."))
tg.run("build", "-n", "-compiler", "gccgo", "cgoref")
tg.grepStderr(`gccgo.*\-L alibpath \-lalib`, `no Go-inline "#cgo LDFLAGS:" ("-L alibpath -lalib") passed to gccgo linking stage`)
}
func TestListTemplateCanUseContextFunction(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.run("list", "-f", "GOARCH: {{context.GOARCH}}")
}
// cmd/go: "go test" should fail if package does not build
func TestIssue7108(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.runFail("test", "notest")
}
// cmd/go: go test -a foo does not rebuild regexp.
func TestIssue6844(t *testing.T) {
if testing.Short() {
t.Skip("don't rebuild the standard libary in short mode")
}
tg := testgo(t)
defer tg.cleanup()
tg.creatingTemp("deps.test" + exeSuffix)
tg.run("test", "-x", "-a", "-c", "testdata/dep_test.go")
tg.grepStderr("regexp", "go test -x -a -c testdata/dep-test.go did not rebuild regexp")
}
func TestBuildDashIInstallsDependencies(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.tempFile("src/x/y/foo/foo.go", `package foo
func F() {}`)
tg.tempFile("src/x/y/bar/bar.go", `package bar
import "x/y/foo"
func F() { foo.F() }`)
tg.setenv("GOPATH", tg.path("."))
checkbar := func(desc string) {
// TODO(iant): Sleep for one "tick", where a tick is
// the granularity of mtime on the file system.
time.Sleep(time.Second)
tg.must(os.Chtimes(tg.path("src/x/y/foo/foo.go"), time.Now(), time.Now()))
time.Sleep(time.Second)
tg.run("build", "-v", "-i", "x/y/bar")
tg.grepBoth("x/y/foo", "first build -i "+desc+" did not build x/y/foo")
tg.run("build", "-v", "-i", "x/y/bar")
tg.grepBothNot("x/y/foo", "second build -i "+desc+" built x/y/foo")
}
checkbar("pkg")
tg.creatingTemp("bar" + exeSuffix)
tg.tempFile("src/x/y/bar/bar.go", `package main
import "x/y/foo"
func main() { foo.F() }`)
checkbar("cmd")
}
func TestGoBuildInTestOnlyDirectoryFailsWithAGoodError(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("build", "./testdata/testonly")
tg.grepStderr("no buildable Go", "go build ./testdata/testonly produced unexpected error")
}
func TestGoTestDetectsTestOnlyImportCycles(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.runFail("test", "-c", "testcycle/p3")
tg.grepStderr("import cycle not allowed in test", "go test testcycle/p3 produced unexpected error")
}
func TestGoTestFooTestWorks(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.run("test", "testdata/standalone_test.go")
}
func TestGoTestXtestonlyWorks(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.run("clean", "-i", "xtestonly")
tg.run("test", "xtestonly")
}
func TestGoTestBuildsAnXtestContainingOnlyNonRunnableExamples(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.run("test", "-v", "./testdata/norunexample")
tg.grepStdout("File with non-runnable example was built.", "file with non-runnable example was not built")
}
func TestGoGenerateHandlesSimpleCommand(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping because windows has no echo command")
}
tg := testgo(t)
defer tg.cleanup()
tg.run("generate", "./testdata/generate/test1.go")
tg.grepStdout("Success", "go generate ./testdata/generate/test1.go generated wrong output")
}
func TestGoGenerateHandlesCommandAlias(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping because windows has no echo command")
}
tg := testgo(t)
defer tg.cleanup()
tg.run("generate", "./testdata/generate/test2.go")
tg.grepStdout("Now is the time for all good men", "go generate ./testdata/generate/test2.go generated wrong output")
}
func TestGoGenerateVariableSubstitution(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping because windows has no echo command")
}
tg := testgo(t)
defer tg.cleanup()
tg.run("generate", "./testdata/generate/test3.go")
tg.grepStdout(runtime.GOARCH+" test3.go:7 pabc xyzp/test3.go/123", "go generate ./testdata/generate/test3.go generated wrong output")
}
func TestGoGenerateRunFlag(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping because windows has no echo command")
}
tg := testgo(t)
defer tg.cleanup()
tg.run("generate", "-run", "y.s", "./testdata/generate/test4.go")
tg.grepStdout("yes", "go generate -run yes ./testdata/generate/test4.go did not select yes")
tg.grepStdoutNot("no", "go generate -run yes ./testdata/generate/test4.go selected no")
}
func TestGoGetWorksWithVanityWildcards(t *testing.T) {
if testing.Short() {
t.Skip("skipping test that uses network in short mode")
}
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
tg.run("get", "-u", "rsc.io/pdf/...")
tg.wantExecutable(tg.path("bin/pdfpasswd"+exeSuffix), "did not build rsc/io/pdf/pdfpasswd")
}
func TestGoVetWithExternalTests(t *testing.T) {
if testing.Short() {
t.Skip("skipping test that uses network in short mode")
}
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
tg.run("get", "golang.org/x/tools/cmd/vet")
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.runFail("vet", "vetpkg")
tg.grepBoth("missing argument for Printf", "go vet vetpkg did not find missing argument for Printf")
}
func TestGoVetWithTags(t *testing.T) {
if testing.Short() {
t.Skip("skipping test that uses network in short mode")
}
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
tg.run("get", "golang.org/x/tools/cmd/vet")
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.runFail("vet", "-tags", "tagtest", "vetpkg")
tg.grepBoth(`c\.go.*wrong number of args for format`, "go get vetpkg did not run scan tagged file")
}
// Issue 9767.
func TestGoGetRscIoToolstash(t *testing.T) {
if testing.Short() {
t.Skip("skipping test that uses network in short mode")
}
tg := testgo(t)
defer tg.cleanup()
tg.tempDir("src/rsc.io")
tg.setenv("GOPATH", tg.path("."))
tg.cd(tg.path("src/rsc.io"))
tg.run("get", "./toolstash")
}
#!/bin/bash
# Copyright 2012 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.
set -e
go build -tags testgo -o testgo
go() {
echo TEST ERROR: ran go, not testgo: go "$@" >&2
exit 2
}
started=false
testdesc=""
nl="
"
TEST() {
if $started; then
stop
fi
echo TEST: "$@"
testdesc="$@"
started=true
ok=true
}
stop() {
if ! $started; then
echo TEST ERROR: stop missing start >&2
exit 2
fi
started=false
if $ok; then
echo PASS
else
echo FAIL
testfail="$testfail $testdesc$nl"
allok=false
fi
}
ok=true
allok=true
unset GOBIN
unset GOPATH
unset GOROOT
TEST 'program name in crash messages'
linker=$(./testgo env GOCHAR)l
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
./testgo build -ldflags -crash_for_testing $(./testgo env GOROOT)/test/helloworld.go 2>$d/err.out || true
if ! grep -q "/tool/.*/$linker" $d/err.out; then
echo "missing linker name in error message"
cat $d/err.out
ok=false
fi
rm -r $d
TEST broken tests without Test functions all fail
d=$(mktemp -d -t testgoXXX)
./testgo test ./testdata/src/badtest/... >$d/err 2>&1 || true
if grep -q '^ok' $d/err; then
echo test passed unexpectedly:
grep '^ok' $d/err
ok=false
elif ! grep -q 'FAIL.*badtest/badexec' $d/err || ! grep -q 'FAIL.*badtest/badsyntax' $d/err || ! grep -q 'FAIL.*badtest/badvar' $d/err; then
echo test did not run everything
cat $d/err
ok=false
fi
rm -rf $d
TEST 'go build -a in dev branch'
./testgo install math || ok=false # should be up to date already but just in case
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
if ! TESTGO_IS_GO_RELEASE=0 ./testgo build -v -a math 2>$d/err.out; then
cat $d/err.out
ok=false
elif ! grep -q runtime $d/err.out; then
echo "testgo build -a math in dev branch DID NOT build runtime, but should have"
cat $d/err.out
ok=false
fi
rm -r $d
TEST 'go build -a in release branch'
./testgo install math || ok=false # should be up to date already but just in case
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
if ! TESTGO_IS_GO_RELEASE=1 ./testgo build -v -a math 2>$d/err.out; then
cat $d/err.out
ok=false
elif grep -q runtime $d/err.out; then
echo "testgo build -a math in dev branch DID build runtime, but should NOT have"
cat $d/err.out
ok=false
fi
rm -r $d
TEST 'go install cleans up after go build'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/mycmd
echo 'package main; func main(){}' >$d/src/mycmd/main.go
old=$(pwd)
cd $d/src/mycmd
"$old/testgo" build
if [ ! -x mycmd ]; then
echo "testgo build did not write command binary"
ok=false
fi
"$old/testgo" install
if [ -e mycmd ]; then
echo "testgo install did not remove command binary"
ok=false
fi
"$old/testgo" build
if [ ! -x mycmd ]; then
echo "testgo build did not write command binary (second time)"
ok=false
fi
# install with arguments does not remove the target,
# even in the same directory
"$old/testgo" install mycmd
if [ ! -e mycmd ]; then
echo "testgo install mycmd removed command binary when run in mycmd"
ok=false
fi
"$old/testgo" build
if [ ! -x mycmd ]; then
echo "testgo build did not write command binary (third time)"
ok=false
fi
# and especially not outside the directory
cd $d
cp src/mycmd/mycmd .
"$old/testgo" install mycmd
if [ ! -e $d/src/mycmd/mycmd ]; then
echo "testgo install mycmd removed command binary from its source dir when run outside mycmd"
ok=false
fi
if [ ! -e $d/mycmd ]; then
echo "testgo install mycmd removed command binary from current dir when run outside mycmd"
ok=false
fi
cd "$old"
rm -r $d
TEST 'go install rebuilds stale packages in other GOPATH'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d/d1:$d/d2
mkdir -p $d/d1/src/p1 $d/d2/src/p2
echo 'package p1
import "p2"
func F() { p2.F() }
' > $d/d1/src/p1/p1.go
echo 'package p2
func F() {}
' > $d/d2/src/p2/p2.go
if ! ./testgo install p1; then
echo "./testgo install p1 failed"
ok=false
elif [ "$(./testgo list -f '{{.Stale}}' p1)" != false ]; then
echo "./testgo list mypkg claims p1 is stale, incorrectly"
ok=false
elif [ "$(./testgo list -f '{{.Stale}}' p2)" != false ]; then
echo "./testgo list mypkg claims p2 is stale, incorrectly"
ok=false
else
sleep 1
echo 'func G() {}' >>$d/d2/src/p2/p2.go
if [ "$(./testgo list -f '{{.Stale}}' p2)" != true ]; then
echo "./testgo list mypkg claims p2 is NOT stale, incorrectly"
ok=false
elif [ "$(./testgo list -f '{{.Stale}}' p1)" != true ]; then
echo "./testgo list mypkg claims p1 is NOT stale, incorrectly"
ok=false
fi
if ! ./testgo install p1; then
echo "./testgo install p1 failed second time"
ok=false
else
if [ "$(./testgo list -f '{{.Stale}}' p2)" != false ]; then
echo "./testgo list mypkg claims p2 is stale after reinstall, incorrectly"
ok=false
elif [ "$(./testgo list -f '{{.Stale}}' p1)" != false ]; then
echo "./testgo list mypkg claims p1 is stale after reinstall, incorrectly"
ok=false
fi
fi
fi
rm -r $d
TEST 'go install detects removed files'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/mypkg
echo package mypkg >$d/src/mypkg/x.go
echo package mypkg >$d/src/mypkg/y.go
echo '// +build missingtag
package mypkg' >$d/src/mypkg/z.go
if ! ./testgo install mypkg; then
echo "./testgo install mypkg failed"
ok=false
elif [ "$(./testgo list -f '{{.Stale}}' mypkg)" != false ]; then
echo "./testgo list mypkg claims mypkg is stale, incorrectly"
ok=false
else
# z.go was not part of the build; removing it is okay.
rm $d/src/mypkg/z.go
if [ "$(./testgo list -f '{{.Stale}}' mypkg)" != false ]; then
echo "./testgo list mypkg claims mypkg is stale after removing z.go; should not be stale"
ok=false
./testgo install mypkg
fi
# y.go was part of the package; removing it should be detected.
rm $d/src/mypkg/y.go
if [ "$(./testgo list -f '{{.Stale}}' mypkg)" != true ]; then
echo "./testgo list mypkg claims mypkg is NOT stale after removing y.go; should be stale"
ok=false
fi
fi
rm -r $d
TEST 'go install detects removed files in package main'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/mycmd
echo 'package main
func main() {}
' >$d/src/mycmd/x.go
echo package main >$d/src/mycmd/y.go
echo '// +build missingtag
package main' >$d/src/mycmd/z.go
if ! ./testgo install mycmd; then
echo "./testgo install mycmd failed"
ok=false
elif [ "$(./testgo list -f '{{.Stale}}' mycmd)" != false ]; then
echo "./testgo list mypkg claims mycmd is stale, incorrectly"
ok=false
else
# z.go was not part of the build; removing it is okay.
rm $d/src/mycmd/z.go
if [ "$(./testgo list -f '{{.Stale}}' mycmd)" != false ]; then
echo "./testgo list mycmd claims mycmd is stale after removing z.go; should not be stale"
ok=false
./testgo install mycmd
fi
# y.go was part of the package; removing it should be detected.
rm $d/src/mycmd/y.go
if [ "$(./testgo list -f '{{.Stale}}' mycmd)" != true ]; then
echo "./testgo list mycmd claims mycmd is NOT stale after removing y.go; should be stale"
ok=false
fi
fi
rm -r $d
# Test local (./) imports.
testlocal() {
local="$1"
TEST local imports $2 '(easy)'
./testgo build -o hello "testdata/$local/easy.go" || ok=false
./hello >hello.out || ok=false
if ! grep -q '^easysub\.Hello' hello.out; then
echo "testdata/$local/easy.go did not generate expected output"
cat hello.out
ok=false
fi
TEST local imports $2 '(easysub)'
./testgo build -o hello "testdata/$local/easysub/main.go" || ok=false
./hello >hello.out || ok=false
if ! grep -q '^easysub\.Hello' hello.out; then
echo "testdata/$local/easysub/main.go did not generate expected output"
cat hello.out
ok=false
fi
TEST local imports $2 '(hard)'
./testgo build -o hello "testdata/$local/hard.go" || ok=false
./hello >hello.out || ok=false
if ! grep -q '^sub\.Hello' hello.out || ! grep -q '^subsub\.Hello' hello.out ; then
echo "testdata/$local/hard.go did not generate expected output"
cat hello.out
ok=false
fi
rm -f hello.out hello
# Test that go install x.go fails.
TEST local imports $2 '(go install should fail)'
if ./testgo install "testdata/$local/easy.go" >/dev/null 2>&1; then
echo "go install testdata/$local/easy.go succeeded"
ok=false
fi
}
# Test local imports
testlocal local ''
# Test local imports again, with bad characters in the directory name.
bad='#$%:, &()*;<=>?\^{}'
rm -rf "testdata/$bad"
cp -R testdata/local "testdata/$bad"
testlocal "$bad" 'with bad characters in path'
rm -rf "testdata/$bad"
TEST 'internal packages in $GOROOT are respected'
if ./testgo build -v ./testdata/testinternal >testdata/std.out 2>&1; then
echo "go build ./testdata/testinternal succeeded incorrectly"
ok=false
elif ! grep 'use of internal package not allowed' testdata/std.out >/dev/null; then
echo "wrong error message for testdata/testinternal"
cat std.out
ok=false
fi
TEST 'internal packages outside $GOROOT are respected (as of Go 1.5)'
if ./testgo build -v ./testdata/testinternal2 >testdata/std.out 2>&1; then
echo "go build ./testdata/testinternal2 succeeded incorrectly"
ok=false
elif ! grep 'use of internal package not allowed' testdata/std.out >/dev/null; then
echo "wrong error message for testdata/testinternal2"
cat std.out
ok=false
fi
# Test that 'go get -u' reports moved packages.
testmove() {
vcs=$1
url=$2
base=$3
config=$4
TEST go get -u notices $vcs package that moved
d=$(mktemp -d -t testgoXXX)
mkdir -p $d/src
if ! GOPATH=$d ./testgo get -d $url; then
echo 'go get -d $url failed'
ok=false
elif ! GOPATH=$d ./testgo get -d -u $url; then
echo 'go get -d -u $url failed'
ok=false
else
set +e
case "$vcs" in
svn)
# SVN doesn't believe in text files so we can't just edit the config.
# Check out a different repo into the wrong place.
rm -rf $d/src/code.google.com/p/rsc-svn
GOPATH=$d ./testgo get -d -u code.google.com/p/rsc-svn2/trunk
mv $d/src/code.google.com/p/rsc-svn2 $d/src/code.google.com/p/rsc-svn
;;
*)
echo '1,$s;'"$base"';'"$base"'XXX;
w
q' | ed $d/src/$config >/dev/null 2>&1
esac
set -e
if GOPATH=$d ./testgo get -d -u $url 2>$d/err; then
echo "go get -d -u $url succeeded with wrong remote repo"
cat $d/err
ok=false
elif ! grep 'is a custom import path for' $d/err >/dev/null; then
echo "go get -d -u $url failed for wrong reason"
cat $d/err
ok=false
fi
if GOPATH=$d ./testgo get -d -f -u $url 2>$d/err; then
echo "go get -d -u $url succeeded with wrong remote repo"
cat $d/err
ok=false
elif ! egrep -i 'validating server certificate|not found' $d/err >/dev/null; then
echo "go get -d -f -u $url failed for wrong reason"
cat $d/err
ok=false
fi
fi
rm -rf $d
}
testmove git rsc.io/pdf pdf rsc.io/pdf/.git/config
# TODO(rsc): Set up a test case on bitbucket for hg.
# testmove hg rsc.io/x86/x86asm x86 rsc.io/x86/.hg/hgrc
# TODO(rsc): Set up a test case on SourceForge (?) for svn.
# testmove svn code.google.com/p/rsc-svn/trunk - -
export GOPATH=$(pwd)/testdata/importcom
TEST 'import comment - match'
if ! ./testgo build ./testdata/importcom/works.go; then
echo 'go build ./testdata/importcom/works.go failed'
ok=false
fi
TEST 'import comment - mismatch'
if ./testgo build ./testdata/importcom/wrongplace.go 2>testdata/err; then
echo 'go build ./testdata/importcom/wrongplace.go suceeded'
ok=false
elif ! grep 'wrongplace expects import "my/x"' testdata/err >/dev/null; then
echo 'go build did not mention incorrect import:'
cat testdata/err
ok=false
fi
TEST 'import comment - syntax error'
if ./testgo build ./testdata/importcom/bad.go 2>testdata/err; then
echo 'go build ./testdata/importcom/bad.go suceeded'
ok=false
elif ! grep 'cannot parse import comment' testdata/err >/dev/null; then
echo 'go build did not mention syntax error:'
cat testdata/err
ok=false
fi
TEST 'import comment - conflict'
if ./testgo build ./testdata/importcom/conflict.go 2>testdata/err; then
echo 'go build ./testdata/importcom/conflict.go suceeded'
ok=false
elif ! grep 'found import comments' testdata/err >/dev/null; then
echo 'go build did not mention comment conflict:'
cat testdata/err
ok=false
fi
rm -f ./testdata/err
unset GOPATH
export GOPATH=$(pwd)/testdata/src
TEST disallowed C source files
export GOPATH=$(pwd)/testdata
if ./testgo build badc 2>testdata/err; then
echo 'go build badc succeeded'
ok=false
elif ! grep 'C source files not allowed' testdata/err >/dev/null; then
echo 'go test did not say C source files not allowed:'
cat testdata/err
ok=false
fi
rm -f ./testdata/err
unset GOPATH
TEST error message for syntax error in test go file says FAIL
export GOPATH=$(pwd)/testdata
if ./testgo test syntaxerror 2>testdata/err; then
echo 'go test syntaxerror succeeded'
ok=false
elif ! grep FAIL testdata/err >/dev/null; then
echo 'go test did not say FAIL:'
cat testdata/err
ok=false
fi
rm -f ./testdata/err
unset GOPATH
TEST wildcards do not look in useless directories
export GOPATH=$(pwd)/testdata
if ./testgo list ... >testdata/err 2>&1; then
echo "go list ... succeeded"
ok=false
elif ! grep badpkg testdata/err >/dev/null; then
echo "go list ... failure does not mention badpkg"
cat testdata/err
ok=false
elif ! ./testgo list m... >testdata/err 2>&1; then
echo "go list m... failed"
ok=false
fi
rm -rf ./testdata/err
unset GOPATH
# Test tests with relative imports.
TEST relative imports '(go test)'
if ! ./testgo test ./testdata/testimport; then
echo "go test ./testdata/testimport failed"
ok=false
fi
# Test installation with relative imports.
TEST relative imports '(go test -i)'
if ! ./testgo test -i ./testdata/testimport; then
echo "go test -i ./testdata/testimport failed"
ok=false
fi
# Test tests with relative imports in packages synthesized
# from Go files named on the command line.
TEST relative imports in command-line package
if ! ./testgo test ./testdata/testimport/*.go; then
echo "go test ./testdata/testimport/*.go failed"
ok=false
fi
TEST version control error message includes correct directory
export GOPATH=$(pwd)/testdata/shadow/root1
if ./testgo get -u foo 2>testdata/err; then
echo "go get -u foo succeeded unexpectedly"
ok=false
elif ! grep testdata/shadow/root1/src/foo testdata/err >/dev/null; then
echo "go get -u error does not mention shadow/root1/src/foo:"
cat testdata/err
ok=false
fi
unset GOPATH
TEST go install fails with no buildable files
export GOPATH=$(pwd)/testdata
export CGO_ENABLED=0
if ./testgo install cgotest 2>testdata/err; then
echo "go install cgotest succeeded unexpectedly"
elif ! grep 'no buildable Go source files' testdata/err >/dev/null; then
echo "go install cgotest did not report 'no buildable Go source files'"
cat testdata/err
ok=false
fi
unset CGO_ENABLED
unset GOPATH
# Test that without $GOBIN set, binaries get installed
# into the GOPATH bin directory.
TEST install into GOPATH
rm -rf testdata/bin
if ! GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
echo "go install go-cmd-test failed"
ok=false
elif ! test -x testdata/bin/go-cmd-test; then
echo "go install go-cmd-test did not write to testdata/bin/go-cmd-test"
ok=false
fi
TEST package main_test imports archive not binary
export GOBIN=$(pwd)/testdata/bin
mkdir -p $GOBIN
export GOPATH=$(pwd)/testdata
touch ./testdata/src/main_test/m.go
if ! ./testgo test main_test; then
echo "go test main_test failed without install"
ok=false
elif ! ./testgo install main_test; then
echo "go test main_test failed"
ok=false
elif [ "$(./testgo list -f '{{.Stale}}' main_test)" != false ]; then
echo "after go install, main listed as stale"
ok=false
elif ! ./testgo test main_test; then
echo "go test main_test failed after install"
ok=false
fi
rm -rf $GOBIN
unset GOBIN
# And with $GOBIN set, binaries get installed to $GOBIN.
TEST install into GOBIN
if ! GOBIN=$(pwd)/testdata/bin1 GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
echo "go install go-cmd-test failed"
ok=false
elif ! test -x testdata/bin1/go-cmd-test; then
echo "go install go-cmd-test did not write to testdata/bin1/go-cmd-test"
ok=false
fi
# Without $GOBIN set, installing a program outside $GOPATH should fail
# (there is nowhere to install it).
TEST install without destination fails
if ./testgo install testdata/src/go-cmd-test/helloworld.go 2>testdata/err; then
echo "go install testdata/src/go-cmd-test/helloworld.go should have failed, did not"
ok=false
elif ! grep 'no install location for .go files listed on command line' testdata/err; then
echo "wrong error:"
cat testdata/err
ok=false
fi
rm -f testdata/err
# With $GOBIN set, should install there.
TEST install to GOBIN '(command-line package)'
if ! GOBIN=$(pwd)/testdata/bin1 ./testgo install testdata/src/go-cmd-test/helloworld.go; then
echo "go install testdata/src/go-cmd-test/helloworld.go failed"
ok=false
elif ! test -x testdata/bin1/helloworld; then
echo "go install testdata/src/go-cmd-test/helloworld.go did not write testdata/bin1/helloworld"
ok=false
fi
TEST godoc installs into GOBIN
d=$(mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir $d/gobin
GOBIN=$d/gobin ./testgo get golang.org/x/tools/cmd/godoc || ok=false
if [ ! -x $d/gobin/godoc ]; then
echo did not install godoc to '$GOBIN'
GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' golang.org/x/tools/cmd/godoc || true
ok=false
fi
TEST godoc installs into GOROOT
GOROOT=$(./testgo env GOROOT)
rm -f $GOROOT/bin/godoc
./testgo install golang.org/x/tools/cmd/godoc || ok=false
if [ ! -x $GOROOT/bin/godoc ]; then
echo did not install godoc to '$GOROOT/bin'
./testgo list -f 'Target: {{.Target}}' golang.org/x/tools/cmd/godoc || true
ok=false
fi
TEST cmd/fix installs into tool
GOOS=$(./testgo env GOOS)
GOARCH=$(./testgo env GOARCH)
rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix
./testgo install cmd/fix || ok=false
if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then
echo 'did not install cmd/fix to $GOROOT/pkg/tool'
GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix || true
ok=false
fi
rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix
GOBIN=$d/gobin ./testgo install cmd/fix || ok=false
if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then
echo 'did not install cmd/fix to $GOROOT/pkg/tool with $GOBIN set'
GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix || true
ok=false
fi
TEST gopath program installs into GOBIN
mkdir $d/src/progname
echo 'package main; func main() {}' >$d/src/progname/p.go
GOBIN=$d/gobin ./testgo install progname || ok=false
if [ ! -x $d/gobin/progname ]; then
echo 'did not install progname to $GOBIN/progname'
./testgo list -f 'Target: {{.Target}}' cmd/api || true
ok=false
fi
rm -f $d/gobin/progname $d/bin/progname
TEST gopath program installs into GOPATH/bin
./testgo install progname || ok=false
if [ ! -x $d/bin/progname ]; then
echo 'did not install progname to $GOPATH/bin/progname'
./testgo list -f 'Target: {{.Target}}' progname || true
ok=false
fi
unset GOPATH
rm -rf $d
# Reject relative paths in GOPATH.
TEST reject relative paths in GOPATH '(command-line package)'
if GOPATH=. ./testgo build testdata/src/go-cmd-test/helloworld.go; then
echo 'GOPATH="." go build should have failed, did not'
ok=false
fi
TEST reject relative paths in GOPATH
if GOPATH=:$(pwd)/testdata:. ./testgo build go-cmd-test; then
echo 'GOPATH=":$(pwd)/testdata:." go build should have failed, did not'
ok=false
fi
# issue 4104
TEST go test with package listed multiple times
if [ $(./testgo test fmt fmt fmt fmt fmt | wc -l) -ne 1 ] ; then
echo 'go test fmt fmt fmt fmt fmt tested the same package multiple times'
ok=false
fi
TEST go list has a consistent order
./testgo list std > test_std.list || ok=false
if ! ./testgo list std | cmp -s test_std.list - ; then
echo "go list std ordering is inconsistent"
ok=false
fi
rm -f test_std.list
TEST go list std does not include commands
if ./testgo list std | grep cmd/; then
echo "go list std shows commands"
ok=false
fi
TEST go list cmd only shows commands
if ./testgo list cmd | grep -v 'cmd/'; then
echo "go list cmd shows non-commands"
ok=false
fi
# issue 4096. Validate the output of unsuccessful go install foo/quxx
TEST unsuccessful go install should mention missing package
if [ $(./testgo install 'foo/quxx' 2>&1 | grep -c 'cannot find package "foo/quxx" in any of') -ne 1 ] ; then
echo 'go install foo/quxx expected error: .*cannot find package "foo/quxx" in any of'
ok=false
fi
# test GOROOT search failure is reported
TEST GOROOT search failure reporting
if [ $(./testgo install 'foo/quxx' 2>&1 | egrep -c 'foo/quxx \(from \$GOROOT\)$') -ne 1 ] ; then
echo 'go install foo/quxx expected error: .*foo/quxx (from $GOROOT)'
ok=false
fi
# test multiple GOPATH entries are reported separately
TEST multiple GOPATH entries reported separately
if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/./src/foo/quxx') -ne 2 ] ; then
echo 'go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)\n.*testdata/b/src/foo/quxx'
ok=false
fi
# test (from $GOPATH) annotation is reported for the first GOPATH entry
TEST mention GOPATH in first GOPATH entry
if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/a/src/foo/quxx \(from \$GOPATH\)$') -ne 1 ] ; then
echo 'go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)'
ok=false
fi
# but not on the second
TEST but not the second entry
if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/b/src/foo/quxx$') -ne 1 ] ; then
echo 'go install foo/quxx expected error: .*testdata/b/src/foo/quxx'
ok=false
fi
# test missing GOPATH is reported
TEST missing GOPATH is reported
if [ $(GOPATH= ./testgo install 'foo/quxx' 2>&1 | egrep -c '\(\$GOPATH not set\)$') -ne 1 ] ; then
echo 'go install foo/quxx expected error: ($GOPATH not set)'
ok=false
fi
# issue 4186. go get cannot be used to download packages to $GOROOT
# Test that without GOPATH set, go get should fail
TEST without GOPATH, go get fails
d=$(mktemp -d -t testgoXXX)
mkdir -p $d/src
if GOPATH= GOROOT=$d ./testgo get -d golang.org/x/codereview/cmd/hgpatch ; then
echo 'go get golang.org/x/codereview/cmd/hgpatch should not succeed with $GOPATH unset'
ok=false
fi
rm -rf $d
# Test that with GOPATH=$GOROOT, go get should fail
TEST with GOPATH=GOROOT, go get fails
d=$(mktemp -d -t testgoXXX)
mkdir -p $d/src
if GOPATH=$d GOROOT=$d ./testgo get -d golang.org/x/codereview/cmd/hgpatch ; then
echo 'go get golang.org/x/codereview/cmd/hgpatch should not succeed with GOPATH=$GOROOT'
ok=false
fi
rm -rf $d
TEST ldflags arguments with spaces '(issue 3941)'
d=$(mktemp -d -t testgoXXX)
cat >$d/main.go<<EOF
package main
var extern string
func main() {
println(extern)
}
EOF
./testgo run -ldflags '-X main.extern "hello world"' $d/main.go 2>hello.out || ok=false
if ! grep -q '^hello world' hello.out; then
echo "ldflags -X main.extern 'hello world' failed. Output:"
cat hello.out
ok=false
fi
rm -rf $d hello.out
TEST go test -cpuprofile leaves binary behind
./testgo test -cpuprofile strings.prof strings || ok=false
if [ ! -x strings.test ]; then
echo "go test -cpuprofile did not create strings.test"
ok=false
fi
rm -f strings.prof strings.test
TEST go test -cpuprofile -o controls binary location
./testgo test -cpuprofile strings.prof -o mystrings.test strings || ok=false
if [ ! -x mystrings.test ]; then
echo "go test -cpuprofile -o mystrings.test did not create mystrings.test"
ok=false
fi
rm -f strings.prof mystrings.test
TEST go test -c -o controls binary location
./testgo test -c -o mystrings.test strings || ok=false
if [ ! -x mystrings.test ]; then
echo "go test -c -o mystrings.test did not create mystrings.test"
ok=false
fi
rm -f mystrings.test
TEST go test -o writes binary
./testgo test -o mystrings.test strings || ok=false
if [ ! -x mystrings.test ]; then
echo "go test -o mystrings.test did not create mystrings.test"
ok=false
fi
rm -f mystrings.test
TEST symlinks do not confuse go list '(issue 4568)'
old=$(pwd)
tmp=$(cd /tmp && pwd -P)
d=$(TMPDIR=$tmp mktemp -d -t testgoXXX)
mkdir -p $d/src
(
ln -s $d $d/src/dir1
cd $d/src
echo package p >dir1/p.go
export GOPATH=$d
if [ "$($old/testgo list -f '{{.Root}}' dir1)" != "$d" ]; then
echo Confused by symlinks.
echo "Package in current directory $(pwd) should have Root $d"
env|grep WD
$old/testgo list -json . dir1
touch $d/failed
fi
)
if [ -f $d/failed ]; then
ok=false
fi
rm -rf $d
TEST 'install with tags (issue 4515)'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
mkdir -p $d/src/example/a $d/src/example/b $d/bin
cat >$d/src/example/a/main.go <<EOF
package main
func main() {}
EOF
cat >$d/src/example/b/main.go <<EOF
// +build mytag
package main
func main() {}
EOF
GOPATH=$d ./testgo install -tags mytag example/a example/b || ok=false
if [ ! -x $d/bin/a -o ! -x $d/bin/b ]; then
echo go install example/a example/b did not install binaries
ok=false
fi
rm -f $d/bin/*
GOPATH=$d ./testgo install -tags mytag example/... || ok=false
if [ ! -x $d/bin/a -o ! -x $d/bin/b ]; then
echo go install example/... did not install binaries
ok=false
fi
rm -f $d/bin/*go
export GOPATH=$d
if [ "$(./testgo list -tags mytag example/b...)" != "example/b" ]; then
echo go list example/b did not find example/b
ok=false
fi
unset GOPATH
rm -rf $d
TEST case collisions '(issue 4773)'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/example/{a/pkg,a/Pkg,b}
cat >$d/src/example/a/a.go <<EOF
package p
import (
_ "example/a/pkg"
_ "example/a/Pkg"
)
EOF
cat >$d/src/example/a/pkg/pkg.go <<EOF
package pkg
EOF
cat >$d/src/example/a/Pkg/pkg.go <<EOF
package pkg
EOF
if ./testgo list example/a 2>$d/out; then
echo go list example/a should have failed, did not.
ok=false
elif ! grep "case-insensitive import collision" $d/out >/dev/null; then
echo go list example/a did not report import collision.
ok=false
fi
cat >$d/src/example/b/file.go <<EOF
package b
EOF
cat >$d/src/example/b/FILE.go <<EOF
package b
EOF
if [ $(ls $d/src/example/b | wc -l) = 2 ]; then
# case-sensitive file system, let directory read find both files
args="example/b"
else
# case-insensitive file system, list files explicitly on command line.
args="$d/src/example/b/file.go $d/src/example/b/FILE.go"
fi
if ./testgo list $args 2>$d/out; then
echo go list example/b should have failed, did not.
ok=false
elif ! grep "case-insensitive file name collision" $d/out >/dev/null; then
echo go list example/b did not report file name collision.
ok=false
fi
TEST go get -t "code.google.com/p/go-get-issue-8181/{a,b}"
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
if ./testgo get -t code.google.com/p/go-get-issue-8181/{a,b}; then
./testgo list ... | grep go.tools/godoc > /dev/null || ok=false
else
ok=false
fi
unset GOPATH
rm -rf $d
TEST shadowing logic
export GOPATH=$(pwd)/testdata/shadow/root1:$(pwd)/testdata/shadow/root2
# The math in root1 is not "math" because the standard math is.
set +e
cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/math)
set -e
if [ "$cdir" != "(_$(pwd)/testdata/shadow/root1/src/math) ($GOROOT/src/math)" ]; then
echo shadowed math is not shadowed: "$cdir"
ok=false
fi
# The foo in root1 is "foo".
set +e
cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/foo)
set -e
if [ "$cdir" != "(foo) ()" ]; then
echo unshadowed foo is shadowed: "$cdir"
ok=false
fi
# The foo in root2 is not "foo" because the foo in root1 got there first.
set +e
cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root2/src/foo)
set -e
if [ "$cdir" != "(_$(pwd)/testdata/shadow/root2/src/foo) ($(pwd)/testdata/shadow/root1/src/foo)" ]; then
echo shadowed foo is not shadowed: "$cdir"
ok=false
fi
# The error for go install should mention the conflicting directory.
set +e
err=$(./testgo install ./testdata/shadow/root2/src/foo 2>&1)
set -e
if [ "$err" != "go install: no install location for $(pwd)/testdata/shadow/root2/src/foo: hidden by $(pwd)/testdata/shadow/root1/src/foo" ]; then
echo wrong shadowed install error: "$err"
ok=false
fi
# Only succeeds if source order is preserved.
TEST source file name order preserved
./testgo test testdata/example[12]_test.go || ok=false
# Check that coverage analysis works at all.
# Don't worry about the exact numbers but require not 0.0%.
checkcoverage() {
if grep '[^0-9]0\.0%' testdata/cover.txt >/dev/null; then
echo 'some coverage results are 0.0%'
ok=false
fi
cat testdata/cover.txt
rm -f testdata/cover.txt
}
TEST coverage runs
./testgo test -short -coverpkg=strings strings regexp >testdata/cover.txt 2>&1 || ok=false
./testgo test -short -cover strings math regexp >>testdata/cover.txt 2>&1 || ok=false
checkcoverage
# Check that coverage analysis uses set mode.
TEST coverage uses set mode
if ./testgo test -short -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
if ! grep -q 'mode: set' testdata/cover.out; then
ok=false
fi
checkcoverage
else
ok=false
fi
rm -f testdata/cover.out testdata/cover.txt
TEST coverage uses atomic mode for -race.
if ./testgo test -short -race -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
if ! grep -q 'mode: atomic' testdata/cover.out; then
ok=false
fi
checkcoverage
else
ok=false
fi
rm -f testdata/cover.out
TEST coverage uses actual setting to override even for -race.
if ./testgo test -short -race -cover encoding/binary -covermode=count -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
if ! grep -q 'mode: count' testdata/cover.out; then
ok=false
fi
checkcoverage
else
ok=false
fi
rm -f testdata/cover.out
TEST coverage with cgo
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
./testgo test -short -cover ./testdata/cgocover >testdata/cover.txt 2>&1 || ok=false
checkcoverage
TEST cgo depends on syscall
rm -rf $GOROOT/pkg/*_race
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/foo
echo '
package foo
//#include <stdio.h>
import "C"
' >$d/src/foo/foo.go
./testgo build -race foo || ok=false
rm -rf $d
unset GOPATH
TEST cgo shows full path names
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/x/y/dirname
echo '
package foo
import "C"
func f() {
' >$d/src/x/y/dirname/foo.go
if ./testgo build x/y/dirname >$d/err 2>&1; then
echo build succeeded unexpectedly.
ok=false
elif ! grep x/y/dirname $d/err >/dev/null; then
echo error did not use full path.
cat $d/err
ok=false
fi
rm -rf $d
unset GOPATH
TEST 'cgo handles -Wl,$ORIGIN'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/origin
echo '
package origin
// #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
// void f(void) {}
import "C"
func f() { C.f() }
' >$d/src/origin/origin.go
if ! ./testgo build origin; then
echo build failed
ok=false
fi
rm -rf $d
unset GOPATH
TEST 'Issue 6480: "go test -c -test.bench=XXX fmt" should not hang'
if ! ./testgo test -c -test.bench=XXX fmt; then
echo build test failed
ok=false
fi
rm -f fmt.test
if which gccgo >/dev/null; then
TEST 'Issue 7573: cmd/cgo: undefined reference when linking a C-library using gccgo'
d=$(mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/cgoref
ldflags="-L alibpath -lalib"
echo "
package main
// #cgo LDFLAGS: $ldflags
// void f(void) {}
import \"C\"
func main() { C.f() }
" >$d/src/cgoref/cgoref.go
go_cmds="$(./testgo build -n -compiler gccgo cgoref 2>&1 1>/dev/null)"
ldflags_count="$(echo "$go_cmds" | egrep -c "^gccgo.*$(echo $ldflags | sed -e 's/-/\\-/g')" || true)"
if [ "$ldflags_count" -lt 1 ]; then
echo "No Go-inline "#cgo LDFLAGS:" (\"$ldflags\") passed to gccgo linking stage."
ok=false
fi
rm -rf $d
unset ldflags_count
unset go_cmds
unset ldflags
unset GOPATH
fi
TEST list template can use context function
if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then
echo unable to use context in list template
ok=false
fi
TEST 'Issue 7108: cmd/go: "go test" should fail if package does not build'
export GOPATH=$(pwd)/testdata
if ./testgo test notest >/dev/null 2>&1; then
echo 'go test notest succeeded, but should fail'
ok=false
fi
unset GOPATH
TEST 'Issue 6844: cmd/go: go test -a foo does not rebuild regexp'
if ! ./testgo test -x -a -c testdata/dep_test.go 2>deplist; then
echo "go test -x -a -c testdata/dep_test.go failed"
ok=false
elif ! grep -q regexp deplist; then
echo "go test -x -a -c testdata/dep_test.go did not rebuild regexp"
ok=false
fi
rm -f deplist
rm -f deps.test
TEST list template can use context function
if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then
echo unable to use context in list template
ok=false
fi
TEST build -i installs dependencies
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/x/y/foo $d/src/x/y/bar
echo '
package foo
func F() {}
' >$d/src/x/y/foo/foo.go
checkbar() {
desc="$1"
sleep 1
touch $d/src/x/y/foo/foo.go
if ! ./testgo build -v -i x/y/bar &> $d/err; then
echo build -i "$1" failed
cat $d/err
ok=false
elif ! grep x/y/foo $d/err >/dev/null; then
echo first build -i "$1" did not build x/y/foo
cat $d/err
ok=false
fi
if ! ./testgo build -v -i x/y/bar &> $d/err; then
echo second build -i "$1" failed
cat $d/err
ok=false
elif grep x/y/foo $d/err >/dev/null; then
echo second build -i "$1" built x/y/foo
cat $d/err
ok=false
fi
}
echo '
package bar
import "x/y/foo"
func F() { foo.F() }
' >$d/src/x/y/bar/bar.go
checkbar pkg
TEST build -i installs dependencies for command
echo '
package main
import "x/y/foo"
func main() { foo.F() }
' >$d/src/x/y/bar/bar.go
checkbar cmd
rm -rf $d bar
unset GOPATH
TEST 'go build in test-only directory fails with a good error'
if ./testgo build ./testdata/testonly 2>testdata/err.out; then
echo "go build ./testdata/testonly succeeded, should have failed"
ok=false
elif ! grep 'no buildable Go' testdata/err.out >/dev/null; then
echo "go build ./testdata/testonly produced unexpected error:"
cat testdata/err.out
ok=false
fi
rm -f testdata/err.out
TEST 'go test detects test-only import cycles'
export GOPATH=$(pwd)/testdata
if ./testgo test -c testcycle/p3 2>testdata/err.out; then
echo "go test testcycle/p3 succeeded, should have failed"
ok=false
elif ! grep 'import cycle not allowed in test' testdata/err.out >/dev/null; then
echo "go test testcycle/p3 produced unexpected error:"
cat testdata/err.out
ok=false
fi
rm -f testdata/err.out
unset GOPATH
TEST 'go test foo_test.go works'
if ! ./testgo test testdata/standalone_test.go; then
echo "go test testdata/standalone_test.go failed"
ok=false
fi
TEST 'go test xtestonly works'
export GOPATH=$(pwd)/testdata
./testgo clean -i xtestonly || ok=false
if ! ./testgo test xtestonly >/dev/null; then
echo "go test xtestonly failed"
ok=false
fi
unset GOPATH
TEST 'go test builds an xtest containing only non-runnable examples'
if ! ./testgo test -v ./testdata/norunexample > testdata/std.out; then
echo "go test ./testdata/norunexample failed"
ok=false
elif ! grep 'File with non-runnable example was built.' testdata/std.out > /dev/null; then
echo "file with non-runnable example was not built"
ok=false
fi
rm -f testdata/std.out
TEST 'go generate handles simple command'
if ! ./testgo generate ./testdata/generate/test1.go > testdata/std.out; then
echo "go generate ./testdata/generate/test1.go failed to run"
ok=false
elif ! grep 'Success' testdata/std.out > /dev/null; then
echo "go generate ./testdata/generate/test1.go generated wrong output"
ok=false
fi
TEST 'go generate handles command alias'
if ! ./testgo generate ./testdata/generate/test2.go > testdata/std.out; then
echo "go generate ./testdata/generate/test2.go failed to run"
ok=false
elif ! grep 'Now is the time for all good men' testdata/std.out > /dev/null; then
echo "go generate ./testdata/generate/test2.go generated wrong output"
ok=false
fi
TEST 'go generate variable substitution'
if ! ./testgo generate ./testdata/generate/test3.go > testdata/std.out; then
echo "go generate ./testdata/generate/test3.go failed to run"
ok=false
elif ! grep "$GOARCH test3.go:7 pabc xyzp/test3.go/123" testdata/std.out > /dev/null; then
echo "go generate ./testdata/generate/test3.go generated wrong output"
ok=false
fi
TEST 'go generate run flag'
if ! ./testgo generate -run y.s ./testdata/generate/test4.go > testdata/std.out; then
echo "go test -run yes ./testdata/generate/test4.go failed to run"
ok=false
elif ! grep "yes" testdata/std.out > /dev/null; then
echo "go generate -run yes ./testdata/generate/test4.go did not select yes"
ok=false
elif grep "no" testdata/std.out > /dev/null; then
echo "go generate -run yes ./testdata/generate/test4.go selected no"
ok=false
fi
TEST go get works with vanity wildcards
d=$(mktemp -d -t testgoXXX)
export GOPATH=$d
if ! ./testgo get -u rsc.io/pdf/...; then
ok=false
elif [ ! -x $d/bin/pdfpasswd ]; then
echo did not build rsc.io/pdf/pdfpasswd
ok=false
fi
unset GOPATH
rm -rf $d
TEST go vet with external tests
d=$(mktemp -d -t testgoXXX)
export GOPATH=$d
./testgo get golang.org/x/tools/cmd/vet
export GOPATH=$(pwd)/testdata
if ./testgo vet vetpkg >$d/err 2>&1; then
echo "go vet vetpkg passes incorrectly"
ok=false
elif ! grep -q 'missing argument for Printf' $d/err; then
echo "go vet vetpkg did not find missing argument for Printf"
cat $d/err
ok=false
fi
unset GOPATH
rm -rf $d
TEST go vet with -tags
d=$(mktemp -d -t testgoXXX)
export GOPATH=$d
./testgo get golang.org/x/tools/cmd/vet
export GOPATH=$(pwd)/testdata
if ./testgo vet -tags tagtest vetpkg >$d/err 2>&1; then
echo "go vet vetpkg passes incorrectly"
ok=false
elif ! grep -q 'c\.go.*wrong number of args for format' $d/err; then
echo "go vet vetpkg did not scan tagged file"
cat $d/err
ok=false
fi
unset GOPATH
rm -rf $d
TEST go get ./rsc.io/toolstash '(golang.org/issue/9767)'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
export testgo=$(pwd)/testgo
mkdir -p $GOPATH/src/rsc.io
(cd $GOPATH/src/rsc.io && $testgo get ./toolstash) || ok=false
unset GOPATH
unset testgo
rm -rf $d
# clean up
if $started; then stop; fi
rm -rf testdata/bin testdata/bin1 testdata/std.out
rm -f testgo
if $allok; then
echo PASS
else
echo FAIL:
echo "$testfail"
exit 1
fi
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment