"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":
canRun = false
}
}
+
+ switch runtime.GOOS {
+ case "windows":
+ exeSuffix = ".exe"
+ }
}
// The TestMain function creates a go command for testing purposes and
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.
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":
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)
+ }
+}
+
+// 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
}
-// 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) {
+// 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")
+ }
+ 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")
}
- for _, f := range files {
- if err := ioutil.WriteFile(filepath.Join(dir, f.path), []byte(f.contents), 0666); err != nil {
- t.Fatal(err)
+ re := regexp.MustCompile(match)
+ for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) {
+ if re.Match(ln) {
+ return true
}
}
- return &tempDir{dir}
+ return false
}
-// path returns the absolute pathname to file within tempDir.
-func (td *tempDir) path(name string) string {
- return filepath.Join(td.name, name)
+// 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)
}
-// 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)
+// 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 c
+}
+
+// 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)
+}
+
+// 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.
- return
- }
- }
- t.Log(err)
- t.Log(stdout)
- t.Log(stderr)
- t.Error("missing file:line in error message")
+ 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")
+ }
+
+ 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")
}
+++ /dev/null
-#!/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