mirror of https://github.com/golang/go.git
4334 lines
129 KiB
Go
4334 lines
129 KiB
Go
// Copyright 2015 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package main_test
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"go/format"
|
|
"internal/race"
|
|
"internal/testenv"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
canRun = true // whether we can run go or ./testgo
|
|
canRace = false // whether we can run the race detector
|
|
canCgo = false // whether we can use cgo
|
|
|
|
exeSuffix string // ".exe" on Windows
|
|
|
|
skipExternal = false // skip external tests
|
|
)
|
|
|
|
func init() {
|
|
switch runtime.GOOS {
|
|
case "android", "nacl":
|
|
canRun = false
|
|
case "darwin":
|
|
switch runtime.GOARCH {
|
|
case "arm", "arm64":
|
|
canRun = false
|
|
}
|
|
case "linux":
|
|
switch runtime.GOARCH {
|
|
case "arm":
|
|
// many linux/arm machines are too slow to run
|
|
// the full set of external tests.
|
|
skipExternal = true
|
|
case "mips", "mipsle", "mips64", "mips64le":
|
|
// Also slow.
|
|
skipExternal = true
|
|
if testenv.Builder() != "" {
|
|
// On the builders, skip the cmd/go
|
|
// tests. They're too slow and already
|
|
// covered by other ports. There's
|
|
// nothing os/arch specific in the
|
|
// tests.
|
|
canRun = false
|
|
}
|
|
}
|
|
case "freebsd":
|
|
switch runtime.GOARCH {
|
|
case "arm":
|
|
// many freebsd/arm machines are too slow to run
|
|
// the full set of external tests.
|
|
skipExternal = true
|
|
canRun = false
|
|
}
|
|
case "windows":
|
|
exeSuffix = ".exe"
|
|
}
|
|
}
|
|
|
|
// testGOROOT is the GOROOT to use when running testgo, a cmd/go binary
|
|
// build from this process's current GOROOT, but run from a different
|
|
// (temp) directory.
|
|
var testGOROOT string
|
|
|
|
var testCC string
|
|
|
|
// The TestMain function creates a go command for testing purposes and
|
|
// deletes it after the tests have been run.
|
|
func TestMain(m *testing.M) {
|
|
if canRun {
|
|
args := []string{"build", "-tags", "testgo", "-o", "testgo" + exeSuffix}
|
|
if race.Enabled {
|
|
args = append(args, "-race")
|
|
}
|
|
out, err := exec.Command("go", args...).CombinedOutput()
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "building testgo failed: %v\n%s", err, out)
|
|
os.Exit(2)
|
|
}
|
|
|
|
out, err = exec.Command("go", "env", "GOROOT").CombinedOutput()
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "could not find testing GOROOT: %v\n%s", err, out)
|
|
os.Exit(2)
|
|
}
|
|
testGOROOT = strings.TrimSpace(string(out))
|
|
|
|
out, err = exec.Command("go", "env", "CC").CombinedOutput()
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "could not find testing CC: %v\n%s", err, out)
|
|
os.Exit(2)
|
|
}
|
|
testCC = strings.TrimSpace(string(out))
|
|
|
|
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":
|
|
// The race detector doesn't work on Alpine Linux:
|
|
// golang.org/issue/14481
|
|
canRace = canCgo && runtime.GOARCH == "amd64" && !isAlpineLinux()
|
|
}
|
|
}
|
|
|
|
// Don't let these environment variables confuse the test.
|
|
os.Unsetenv("GOBIN")
|
|
os.Unsetenv("GOPATH")
|
|
os.Unsetenv("GIT_ALLOW_PROTOCOL")
|
|
if home, ccacheDir := os.Getenv("HOME"), os.Getenv("CCACHE_DIR"); home != "" && ccacheDir == "" {
|
|
// On some systems the default C compiler is ccache.
|
|
// Setting HOME to a non-existent directory will break
|
|
// those systems. Set CCACHE_DIR to cope. Issue 17668.
|
|
os.Setenv("CCACHE_DIR", filepath.Join(home, ".ccache"))
|
|
}
|
|
os.Setenv("HOME", "/test-go-home-does-not-exist")
|
|
|
|
r := m.Run()
|
|
|
|
if canRun {
|
|
os.Remove("testgo" + exeSuffix)
|
|
}
|
|
|
|
os.Exit(r)
|
|
}
|
|
|
|
func isAlpineLinux() bool {
|
|
if runtime.GOOS != "linux" {
|
|
return false
|
|
}
|
|
fi, err := os.Lstat("/etc/alpine-release")
|
|
return err == nil && fi.Mode().IsRegular()
|
|
}
|
|
|
|
// The length of an mtime tick on this system. This is an estimate of
|
|
// how long we need to sleep to ensure that the mtime of two files is
|
|
// different.
|
|
// We used to try to be clever but that didn't always work (see golang.org/issue/12205).
|
|
var mtimeTick time.Duration = 1 * time.Second
|
|
|
|
// Manage a single run of the testgo binary.
|
|
type testgoData struct {
|
|
t *testing.T
|
|
temps []string
|
|
wd string
|
|
env []string
|
|
tempdir string
|
|
ran bool
|
|
inParallel bool
|
|
stdout, stderr bytes.Buffer
|
|
}
|
|
|
|
// testgo sets up for a test that runs testgo.
|
|
func testgo(t *testing.T) *testgoData {
|
|
testenv.MustHaveGoBuild(t)
|
|
|
|
if skipExternal {
|
|
t.Skip("skipping external tests on %s/%s", runtime.GOOS, runtime.GOARCH)
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
// parallel runs the test in parallel by calling t.Parallel.
|
|
func (tg *testgoData) parallel() {
|
|
if tg.ran {
|
|
tg.t.Fatal("internal testsuite error: call to parallel after run")
|
|
}
|
|
if tg.wd != "" {
|
|
tg.t.Fatal("internal testsuite error: call to parallel after cd")
|
|
}
|
|
for _, e := range tg.env {
|
|
if strings.HasPrefix(e, "GOROOT=") || strings.HasPrefix(e, "GOPATH=") || strings.HasPrefix(e, "GOBIN=") {
|
|
val := e[strings.Index(e, "=")+1:]
|
|
if strings.HasPrefix(val, "testdata") || strings.HasPrefix(val, "./testdata") {
|
|
tg.t.Fatalf("internal testsuite error: call to parallel with testdata in environment (%s)", e)
|
|
}
|
|
}
|
|
}
|
|
tg.inParallel = true
|
|
tg.t.Parallel()
|
|
}
|
|
|
|
// pwd returns the current directory.
|
|
func (tg *testgoData) pwd() string {
|
|
wd, err := os.Getwd()
|
|
if err != nil {
|
|
tg.t.Fatalf("could not get working directory: %v", err)
|
|
}
|
|
return wd
|
|
}
|
|
|
|
// cd changes the current directory to the named directory. Note that
|
|
// using this means that the test must not be run in parallel with any
|
|
// other tests.
|
|
func (tg *testgoData) cd(dir string) {
|
|
if tg.inParallel {
|
|
tg.t.Fatal("internal testsuite error: changing directory when running in parallel")
|
|
}
|
|
if tg.wd == "" {
|
|
tg.wd = tg.pwd()
|
|
}
|
|
abs, err := filepath.Abs(dir)
|
|
tg.must(os.Chdir(dir))
|
|
if err == nil {
|
|
tg.setenv("PWD", abs)
|
|
}
|
|
}
|
|
|
|
// sleep sleeps for one tick, where a tick is a conservative estimate
|
|
// of how long it takes for a file modification to get a different
|
|
// mtime.
|
|
func (tg *testgoData) sleep() {
|
|
time.Sleep(mtimeTick)
|
|
}
|
|
|
|
// setenv sets an environment variable to use when running the test go
|
|
// command.
|
|
func (tg *testgoData) setenv(name, val string) {
|
|
if tg.inParallel && (name == "GOROOT" || name == "GOPATH" || name == "GOBIN") && (strings.HasPrefix(val, "testdata") || strings.HasPrefix(val, "./testdata")) {
|
|
tg.t.Fatalf("internal testsuite error: call to setenv with testdata (%s=%s) after parallel", name, val)
|
|
}
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
func (tg *testgoData) goTool() string {
|
|
if tg.wd == "" {
|
|
return "./testgo" + exeSuffix
|
|
}
|
|
return filepath.Join(tg.wd, "testgo"+exeSuffix)
|
|
}
|
|
|
|
// doRun runs the test go command, recording stdout and stderr and
|
|
// returning exit status.
|
|
func (tg *testgoData) doRun(args []string) error {
|
|
if !canRun {
|
|
panic("testgoData.doRun called but canRun false")
|
|
}
|
|
if tg.inParallel {
|
|
for _, arg := range args {
|
|
if strings.HasPrefix(arg, "testdata") || strings.HasPrefix(arg, "./testdata") {
|
|
tg.t.Fatal("internal testsuite error: parallel run using testdata")
|
|
}
|
|
}
|
|
}
|
|
|
|
hasGoroot := false
|
|
for _, v := range tg.env {
|
|
if strings.HasPrefix(v, "GOROOT=") {
|
|
hasGoroot = true
|
|
break
|
|
}
|
|
}
|
|
prog := tg.goTool()
|
|
if !hasGoroot {
|
|
tg.setenv("GOROOT", testGOROOT)
|
|
}
|
|
|
|
tg.t.Logf("running testgo %v", args)
|
|
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
|
|
}
|
|
|
|
// 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()
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
}
|
|
|
|
// runGit runs a git command, and expects it to succeed.
|
|
func (tg *testgoData) runGit(dir string, args ...string) {
|
|
cmd := exec.Command("git", args...)
|
|
tg.stdout.Reset()
|
|
tg.stderr.Reset()
|
|
cmd.Stdout = &tg.stdout
|
|
cmd.Stderr = &tg.stderr
|
|
cmd.Dir = dir
|
|
cmd.Env = tg.env
|
|
status := cmd.Run()
|
|
if tg.stdout.Len() > 0 {
|
|
tg.t.Log("git standard output:")
|
|
tg.t.Log(tg.stdout.String())
|
|
}
|
|
if tg.stderr.Len() > 0 {
|
|
tg.t.Log("git standard error:")
|
|
tg.t.Log(tg.stderr.String())
|
|
}
|
|
if status != nil {
|
|
tg.t.Logf("git %v failed unexpectedly: %v", args, status)
|
|
tg.t.FailNow()
|
|
}
|
|
}
|
|
|
|
// 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()
|
|
}
|
|
|
|
// 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")
|
|
}
|
|
re := regexp.MustCompile(match)
|
|
for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) {
|
|
if re.Match(ln) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// doGrep looks for a regular expression in a buffer and fails if it
|
|
// is not found. The name argument is the name of the output we are
|
|
// searching, "output" or "error". The msg argument is logged on
|
|
// failure.
|
|
func (tg *testgoData) doGrep(match string, b *bytes.Buffer, name, msg string) {
|
|
if !tg.doGrepMatch(match, b) {
|
|
tg.t.Log(msg)
|
|
tg.t.Logf("pattern %v not found in standard %s", match, name)
|
|
tg.t.FailNow()
|
|
}
|
|
}
|
|
|
|
// grepStdout looks for a regular expression in the test run's
|
|
// standard output and fails, logging msg, if it is not found.
|
|
func (tg *testgoData) grepStdout(match, msg string) {
|
|
tg.doGrep(match, &tg.stdout, "output", msg)
|
|
}
|
|
|
|
// grepStderr looks for a regular expression in the test run's
|
|
// standard error and fails, logging msg, if it is not found.
|
|
func (tg *testgoData) grepStderr(match, msg string) {
|
|
tg.doGrep(match, &tg.stderr, "error", msg)
|
|
}
|
|
|
|
// grepBoth looks for a regular expression in the test run's standard
|
|
// output or stand error and fails, logging msg, if it is not found.
|
|
func (tg *testgoData) grepBoth(match, msg string) {
|
|
if !tg.doGrepMatch(match, &tg.stdout) && !tg.doGrepMatch(match, &tg.stderr) {
|
|
tg.t.Log(msg)
|
|
tg.t.Logf("pattern %v not found in standard output or standard error", match)
|
|
tg.t.FailNow()
|
|
}
|
|
}
|
|
|
|
// doGrepNot looks for a regular expression in a buffer and fails if
|
|
// it is found. The name and msg arguments are as for doGrep.
|
|
func (tg *testgoData) doGrepNot(match string, b *bytes.Buffer, name, msg string) {
|
|
if tg.doGrepMatch(match, b) {
|
|
tg.t.Log(msg)
|
|
tg.t.Logf("pattern %v found unexpectedly in standard %s", match, name)
|
|
tg.t.FailNow()
|
|
}
|
|
}
|
|
|
|
// grepStdoutNot looks for a regular expression in the test run's
|
|
// standard output and fails, logging msg, if it is found.
|
|
func (tg *testgoData) grepStdoutNot(match, msg string) {
|
|
tg.doGrepNot(match, &tg.stdout, "output", msg)
|
|
}
|
|
|
|
// grepStderrNot looks for a regular expression in the test run's
|
|
// standard error and fails, logging msg, if it is found.
|
|
func (tg *testgoData) grepStderrNot(match, msg string) {
|
|
tg.doGrepNot(match, &tg.stderr, "error", msg)
|
|
}
|
|
|
|
// grepBothNot looks for a regular expression in the test run's
|
|
// standard output or stand error and fails, logging msg, if it is
|
|
// found.
|
|
func (tg *testgoData) grepBothNot(match, msg string) {
|
|
if tg.doGrepMatch(match, &tg.stdout) || tg.doGrepMatch(match, &tg.stderr) {
|
|
tg.t.Log(msg)
|
|
tg.t.Fatalf("pattern %v found unexpectedly in standard output or standard error", match)
|
|
}
|
|
}
|
|
|
|
// doGrepCount counts the number of times a regexp is seen in a buffer.
|
|
func (tg *testgoData) doGrepCount(match string, b *bytes.Buffer) int {
|
|
if !tg.ran {
|
|
tg.t.Fatal("internal testsuite error: doGrepCount called before run")
|
|
}
|
|
re := regexp.MustCompile(match)
|
|
c := 0
|
|
for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) {
|
|
if re.Match(ln) {
|
|
c++
|
|
}
|
|
}
|
|
return c
|
|
}
|
|
|
|
// 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.Fatalf("internal testsuite error: creatingTemp(%q) with absolute path not in temporary directory", path)
|
|
}
|
|
// 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))
|
|
bytes := []byte(contents)
|
|
if strings.HasSuffix(path, ".go") {
|
|
formatted, err := format.Source(bytes)
|
|
if err == nil {
|
|
bytes = formatted
|
|
}
|
|
}
|
|
tg.must(ioutil.WriteFile(filepath.Join(tg.tempdir, path), bytes, 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)
|
|
}
|
|
|
|
// mustExist fails if path does not exist.
|
|
func (tg *testgoData) mustExist(path string) {
|
|
if _, err := os.Stat(path); err != nil {
|
|
if os.IsNotExist(err) {
|
|
tg.t.Fatalf("%s does not exist but should", path)
|
|
}
|
|
tg.t.Fatalf("%s stat failed: %v", path, err)
|
|
}
|
|
}
|
|
|
|
// mustNotExist fails if path exists.
|
|
func (tg *testgoData) mustNotExist(path string) {
|
|
if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) {
|
|
tg.t.Fatalf("%s exists but should not (%v)", path, err)
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
}
|
|
}
|
|
|
|
// wantArchive fails if path is not an archive.
|
|
func (tg *testgoData) wantArchive(path string) {
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
tg.t.Fatal(err)
|
|
}
|
|
buf := make([]byte, 100)
|
|
io.ReadFull(f, buf)
|
|
f.Close()
|
|
if !bytes.HasPrefix(buf, []byte("!<arch>\n")) {
|
|
tg.t.Fatalf("file %s exists but is not an archive", path)
|
|
}
|
|
}
|
|
|
|
// isStale reports whether pkg is stale, and why
|
|
func (tg *testgoData) isStale(pkg string) (bool, string) {
|
|
tg.run("list", "-f", "{{.Stale}}:{{.StaleReason}}", pkg)
|
|
v := strings.TrimSpace(tg.getStdout())
|
|
f := strings.SplitN(v, ":", 2)
|
|
if len(f) == 2 {
|
|
switch f[0] {
|
|
case "true":
|
|
return true, f[1]
|
|
case "false":
|
|
return false, f[1]
|
|
}
|
|
}
|
|
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, reason, msg string) {
|
|
stale, why := tg.isStale(pkg)
|
|
if !stale {
|
|
tg.t.Fatal(msg)
|
|
}
|
|
if reason == "" && why != "" || !strings.Contains(why, reason) {
|
|
tg.t.Errorf("wrong reason for Stale=true: %q, want %q", why, reason)
|
|
}
|
|
}
|
|
|
|
// wantNotStale fails with msg if pkg is stale.
|
|
func (tg *testgoData) wantNotStale(pkg, reason, msg string) {
|
|
stale, why := tg.isStale(pkg)
|
|
if stale {
|
|
tg.t.Fatal(msg)
|
|
}
|
|
if reason == "" && why != "" || !strings.Contains(why, reason) {
|
|
tg.t.Errorf("wrong reason for Stale=false: %q, want %q", why, reason)
|
|
}
|
|
}
|
|
|
|
// 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))
|
|
}
|
|
}
|
|
|
|
// failSSH puts an ssh executable in the PATH that always fails.
|
|
// This is to stub out uses of ssh by go get.
|
|
func (tg *testgoData) failSSH() {
|
|
wd, err := os.Getwd()
|
|
if err != nil {
|
|
tg.t.Fatal(err)
|
|
}
|
|
fail := filepath.Join(wd, "testdata/failssh")
|
|
tg.setenv("PATH", fmt.Sprintf("%v%c%v", fail, filepath.ListSeparator, os.Getenv("PATH")))
|
|
}
|
|
|
|
func TestFileLineInErrorMessages(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.tempFile("err.go", `package main; import "bar"`)
|
|
path := tg.path("err.go")
|
|
tg.runFail("run", path)
|
|
shortPath := path
|
|
if rel, err := filepath.Rel(tg.pwd(), path); err == nil && len(rel) < len(path) {
|
|
shortPath = rel
|
|
}
|
|
tg.grepStderr("^"+regexp.QuoteMeta(shortPath)+":", "missing file:line in error message")
|
|
}
|
|
|
|
func TestProgramNameInCrashMessages(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
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()
|
|
// TODO: tg.parallel()
|
|
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) {
|
|
if testing.Short() {
|
|
t.Skip("don't rebuild the standard library 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", "0")
|
|
tg.run("build", "-v", "-a", "math")
|
|
tg.grepStderr("runtime", "testgo build -a math in dev branch DID NOT build runtime, but should have")
|
|
|
|
// Everything is out of date. Rebuild to leave things in a better state.
|
|
tg.run("install", "std")
|
|
}
|
|
|
|
func TestGoBuildDashAInReleaseBranch(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("don't rebuild the standard library in short mode")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.run("install", "math", "net/http") // should be up to date already but just in case
|
|
tg.setenv("TESTGO_IS_GO_RELEASE", "1")
|
|
tg.run("install", "-v", "-a", "math")
|
|
tg.grepStderr("runtime", "testgo build -a math in release branch DID NOT build runtime, but should have")
|
|
|
|
// Now runtime.a is updated (newer mtime), so everything would look stale if not for being a release.
|
|
tg.run("build", "-v", "net/http")
|
|
tg.grepStderrNot("strconv", "testgo build -v net/http in release branch with newer runtime.a DID build strconv but should not have")
|
|
tg.grepStderrNot("golang.org/x/net/http2/hpack", "testgo build -v net/http in release branch with newer runtime.a DID build .../golang.org/x/net/http2/hpack but should not have")
|
|
tg.grepStderrNot("net/http", "testgo build -v net/http in release branch with newer runtime.a DID build net/http but should not have")
|
|
|
|
// Everything is out of date. Rebuild to leave things in a better state.
|
|
tg.run("install", "std")
|
|
}
|
|
|
|
func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("don't rebuild the standard library in short mode")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
|
|
addNL := func(name string) (restore func()) {
|
|
data, err := ioutil.ReadFile(name)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
old := data
|
|
data = append(data, '\n')
|
|
if err := ioutil.WriteFile(name, append(data, '\n'), 0666); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tg.sleep()
|
|
return func() {
|
|
if err := ioutil.WriteFile(name, old, 0666); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
tg.setenv("TESTGO_IS_GO_RELEASE", "1")
|
|
|
|
tg.tempFile("d1/src/p1/p1.go", `package p1`)
|
|
tg.setenv("GOPATH", tg.path("d1"))
|
|
tg.run("install", "-a", "p1")
|
|
tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly")
|
|
tg.sleep()
|
|
|
|
// Changing mtime and content of runtime/internal/sys/sys.go
|
|
// should have no effect: we're in a release, which doesn't rebuild
|
|
// for general mtime or content changes.
|
|
sys := runtime.GOROOT() + "/src/runtime/internal/sys/sys.go"
|
|
restore := addNL(sys)
|
|
defer restore()
|
|
tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after updating runtime/internal/sys/sys.go")
|
|
restore()
|
|
tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after restoring runtime/internal/sys/sys.go")
|
|
|
|
// But changing runtime/internal/sys/zversion.go should have an effect:
|
|
// that's how we tell when we flip from one release to another.
|
|
zversion := runtime.GOROOT() + "/src/runtime/internal/sys/zversion.go"
|
|
restore = addNL(zversion)
|
|
defer restore()
|
|
tg.wantStale("p1", "build ID mismatch", "./testgo list claims p1 is NOT stale, incorrectly, after changing to new release")
|
|
restore()
|
|
tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after changing back to old release")
|
|
addNL(zversion)
|
|
tg.wantStale("p1", "build ID mismatch", "./testgo list claims p1 is NOT stale, incorrectly, after changing again to new release")
|
|
tg.run("install", "p1")
|
|
tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with new release")
|
|
|
|
// Restore to "old" release.
|
|
restore()
|
|
tg.wantStale("p1", "build ID mismatch", "./testgo list claims p1 is NOT stale, incorrectly, after changing to old release after new build")
|
|
tg.run("install", "p1")
|
|
tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with old release")
|
|
|
|
// Everything is out of date. Rebuild to leave things in a better state.
|
|
tg.run("install", "std")
|
|
}
|
|
|
|
func TestGoListStandard(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
tg.cd(runtime.GOROOT() + "/src")
|
|
tg.run("list", "-f", "{{if not .Standard}}{{.ImportPath}}{{end}}", "./...")
|
|
stdout := tg.getStdout()
|
|
for _, line := range strings.Split(stdout, "\n") {
|
|
if strings.HasPrefix(line, "_/") && strings.HasSuffix(line, "/src") {
|
|
// $GOROOT/src shows up if there are any .go files there.
|
|
// We don't care.
|
|
continue
|
|
}
|
|
if line == "" {
|
|
continue
|
|
}
|
|
t.Errorf("package in GOROOT not listed as standard: %v", line)
|
|
}
|
|
|
|
// Similarly, expanding std should include some of our vendored code.
|
|
tg.run("list", "std", "cmd")
|
|
tg.grepStdout("golang.org/x/net/http2/hpack", "list std cmd did not mention vendored hpack")
|
|
tg.grepStdout("golang.org/x/arch/x86/x86asm", "list std cmd did not mention vendored x86asm")
|
|
}
|
|
|
|
func TestGoInstallCleansUpAfterGoBuild(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
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) {
|
|
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" + exeSuffix); err != nil {
|
|
t.Fatal("could not read file:", err)
|
|
} else {
|
|
if err := ioutil.WriteFile("mycmd"+exeSuffix, 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.parallel()
|
|
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 claims p1 is stale, incorrectly")
|
|
tg.wantNotStale("p2", "", "./testgo list claims p2 is stale, incorrectly")
|
|
tg.sleep()
|
|
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", "newer source file", "./testgo list claims p2 is NOT stale, incorrectly")
|
|
tg.wantStale("p1", "stale dependency", "./testgo list claims p1 is NOT stale, incorrectly")
|
|
|
|
tg.run("install", "p1")
|
|
tg.wantNotStale("p2", "", "./testgo list claims p2 is stale after reinstall, incorrectly")
|
|
tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after reinstall, incorrectly")
|
|
}
|
|
|
|
func TestGoInstallDetectsRemovedFiles(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
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", "build ID mismatch", "./testgo list mypkg claims mypkg is NOT stale after removing y.go; should be stale")
|
|
}
|
|
|
|
func TestWildcardMatchesSyntaxErrorDirs(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
tg.tempFile("src/mypkg/x.go", `package mypkg`)
|
|
tg.tempFile("src/mypkg/y.go", `pkg mypackage`)
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
tg.cd(tg.path("src/mypkg"))
|
|
tg.runFail("list", "./...")
|
|
tg.runFail("build", "./...")
|
|
tg.runFail("install", "./...")
|
|
}
|
|
|
|
func TestGoListWithTags(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.tempFile("src/mypkg/x.go", "// +build thetag\n\npackage mypkg\n")
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
tg.cd(tg.path("./src"))
|
|
tg.run("list", "-tags=thetag", "./my...")
|
|
tg.grepStdout("mypkg", "did not find mypkg")
|
|
}
|
|
|
|
func TestGoInstallErrorOnCrossCompileToBin(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("don't install into GOROOT in short mode")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.tempFile("src/mycmd/x.go", `package main
|
|
func main() {}`)
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
tg.cd(tg.path("src/mycmd"))
|
|
|
|
tg.run("build", "mycmd")
|
|
|
|
goarch := "386"
|
|
if runtime.GOARCH == "386" {
|
|
goarch = "amd64"
|
|
}
|
|
tg.setenv("GOOS", "linux")
|
|
tg.setenv("GOARCH", goarch)
|
|
tg.run("install", "mycmd")
|
|
tg.setenv("GOBIN", tg.path("."))
|
|
tg.runFail("install", "mycmd")
|
|
tg.run("install", "cmd/pack")
|
|
}
|
|
|
|
func TestGoInstallDetectsRemovedFilesInPackageMain(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
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", "build ID mismatch", "./testgo list mycmd claims mycmd is NOT stale after removing y.go; should be stale")
|
|
}
|
|
|
|
func testLocalRun(tg *testgoData, exepath, local, match string) {
|
|
out, err := exec.Command(exepath).Output()
|
|
if err != nil {
|
|
tg.t.Fatalf("error running %v: %v", exepath, 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) {
|
|
exepath := "./easy" + exeSuffix
|
|
tg.creatingTemp(exepath)
|
|
tg.run("build", "-o", exepath, filepath.Join("testdata", local, "easy.go"))
|
|
testLocalRun(tg, exepath, local, `(?m)^easysub\.Hello`)
|
|
}
|
|
|
|
func testLocalEasySub(tg *testgoData, local string) {
|
|
exepath := "./easysub" + exeSuffix
|
|
tg.creatingTemp(exepath)
|
|
tg.run("build", "-o", exepath, filepath.Join("testdata", local, "easysub", "main.go"))
|
|
testLocalRun(tg, exepath, local, `(?m)^easysub\.Hello`)
|
|
}
|
|
|
|
func testLocalHard(tg *testgoData, local string) {
|
|
exepath := "./hard" + exeSuffix
|
|
tg.creatingTemp(exepath)
|
|
tg.run("build", "-o", exepath, filepath.Join("testdata", local, "hard.go"))
|
|
testLocalRun(tg, exepath, 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()
|
|
// TODO: tg.parallel()
|
|
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(`testinternal(\/|\\)p\.go\:3\:8\: 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(`testinternal2(\/|\\)p\.go\:3\:8\: use of internal package not allowed`, "wrote error message for testdata/testinternal2")
|
|
}
|
|
|
|
func TestRunInternal(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
dir := filepath.Join(tg.pwd(), "testdata")
|
|
tg.setenv("GOPATH", dir)
|
|
tg.run("run", filepath.Join(dir, "src/run/good.go"))
|
|
tg.runFail("run", filepath.Join(dir, "src/run/bad.go"))
|
|
tg.grepStderr(`testdata(\/|\\)src(\/|\\)run(\/|\\)bad\.go\:3\:8\: use of internal package not allowed`, "unexpected error for run/bad.go")
|
|
}
|
|
|
|
func testMove(t *testing.T, vcs, url, base, config string) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
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 TestInternalPackageErrorsAreHandled(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.run("list", "./testdata/testinternal3")
|
|
}
|
|
|
|
func TestInternalCache(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/testinternal4"))
|
|
tg.runFail("build", "p")
|
|
tg.grepStderr("internal", "did not fail to build p")
|
|
}
|
|
|
|
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")
|
|
}
|
|
|
|
// cmd/go: custom import path checking should not apply to Go packages without import comment.
|
|
func TestIssue10952(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
if _, err := exec.LookPath("git"); err != nil {
|
|
t.Skip("skipping because git binary not found")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.tempDir("src")
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
const importPath = "github.com/zombiezen/go-get-issue-10952"
|
|
tg.run("get", "-d", "-u", importPath)
|
|
repoDir := tg.path("src/" + importPath)
|
|
tg.runGit(repoDir, "remote", "set-url", "origin", "https://"+importPath+".git")
|
|
tg.run("get", "-d", "-u", importPath)
|
|
}
|
|
|
|
func TestIssue16471(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
if _, err := exec.LookPath("git"); err != nil {
|
|
t.Skip("skipping because git binary not found")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.tempDir("src")
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
tg.must(os.MkdirAll(tg.path("src/rsc.io/go-get-issue-10952"), 0755))
|
|
tg.runGit(tg.path("src/rsc.io"), "clone", "https://github.com/zombiezen/go-get-issue-10952")
|
|
tg.runFail("get", "-u", "rsc.io/go-get-issue-10952")
|
|
tg.grepStderr("rsc.io/go-get-issue-10952 is a custom import path for https://github.com/rsc/go-get-issue-10952, but .* is checked out from https://github.com/zombiezen/go-get-issue-10952", "did not detect updated import path")
|
|
}
|
|
|
|
// Test git clone URL that uses SCP-like syntax and custom import path checking.
|
|
func TestIssue11457(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
if _, err := exec.LookPath("git"); err != nil {
|
|
t.Skip("skipping because git binary not found")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.tempDir("src")
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
const importPath = "rsc.io/go-get-issue-11457"
|
|
tg.run("get", "-d", "-u", importPath)
|
|
repoDir := tg.path("src/" + importPath)
|
|
tg.runGit(repoDir, "remote", "set-url", "origin", "git@github.com:rsc/go-get-issue-11457")
|
|
|
|
// At this time, custom import path checking compares remotes verbatim (rather than
|
|
// just the host and path, skipping scheme and user), so we expect go get -u to fail.
|
|
// However, the goal of this test is to verify that gitRemoteRepo correctly parsed
|
|
// the SCP-like syntax, and we expect it to appear in the error message.
|
|
tg.runFail("get", "-d", "-u", importPath)
|
|
want := " is checked out from ssh://git@github.com/rsc/go-get-issue-11457"
|
|
if !strings.HasSuffix(strings.TrimSpace(tg.getStderr()), want) {
|
|
t.Error("expected clone URL to appear in stderr")
|
|
}
|
|
}
|
|
|
|
func TestGetGitDefaultBranch(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
if _, err := exec.LookPath("git"); err != nil {
|
|
t.Skip("skipping because git binary not found")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.tempDir("src")
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
|
|
// This repo has two branches, master and another-branch.
|
|
// The another-branch is the default that you get from 'git clone'.
|
|
// The go get command variants should not override this.
|
|
const importPath = "github.com/rsc/go-get-default-branch"
|
|
|
|
tg.run("get", "-d", importPath)
|
|
repoDir := tg.path("src/" + importPath)
|
|
tg.runGit(repoDir, "branch", "--contains", "HEAD")
|
|
tg.grepStdout(`\* another-branch`, "not on correct default branch")
|
|
|
|
tg.run("get", "-d", "-u", importPath)
|
|
tg.runGit(repoDir, "branch", "--contains", "HEAD")
|
|
tg.grepStdout(`\* another-branch`, "not on correct default branch")
|
|
}
|
|
|
|
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()
|
|
// TODO: tg.parallel()
|
|
files, err := filepath.Glob("./testdata/testimport/*.go")
|
|
tg.must(err)
|
|
tg.run(append([]string{"test"}, files...)...)
|
|
}
|
|
|
|
func TestNonCanonicalImportPaths(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
tg.runFail("build", "canonical/d")
|
|
tg.grepStderr("package canonical/d", "did not report canonical/d")
|
|
tg.grepStderr("imports canonical/b", "did not report canonical/b")
|
|
tg.grepStderr("imports canonical/a/: non-canonical", "did not report canonical/a/")
|
|
}
|
|
|
|
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("build constraints exclude all Go files", "go install cgotest did not report 'build constraints exclude all Go files'")
|
|
}
|
|
|
|
func TestRelativeGOBINFail(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.tempFile("triv.go", `package main; func main() {}`)
|
|
tg.setenv("GOBIN", ".")
|
|
tg.runFail("install")
|
|
tg.grepStderr("cannot install, GOBIN must be an absolute path", "go install must fail if $GOBIN is a relative path")
|
|
}
|
|
|
|
// 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")
|
|
}
|
|
|
|
// Issue 12407
|
|
func TestBuildOutputToDevNull(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
tg.run("build", "-o", os.DevNull, "go-cmd-test")
|
|
}
|
|
|
|
func TestPackageMainTestImportsArchiveNotBinary(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
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.sleep()
|
|
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")
|
|
}
|
|
|
|
// The runtime version string takes one of two forms:
|
|
// "go1.X[.Y]" for Go releases, and "devel +hash" at tip.
|
|
// Determine whether we are in a released copy by
|
|
// inspecting the version.
|
|
var isGoRelease = strings.HasPrefix(runtime.Version(), "go1")
|
|
|
|
// Issue 12690
|
|
func TestPackageNotStaleWithTrailingSlash(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
|
|
// Make sure the packages below are not stale.
|
|
tg.run("install", "runtime", "os", "io")
|
|
|
|
goroot := runtime.GOROOT()
|
|
tg.setenv("GOROOT", goroot+"/")
|
|
|
|
want := ""
|
|
if isGoRelease {
|
|
want = "standard package in Go release distribution"
|
|
}
|
|
|
|
tg.wantNotStale("runtime", want, "with trailing slash in GOROOT, runtime listed as stale")
|
|
tg.wantNotStale("os", want, "with trailing slash in GOROOT, os listed as stale")
|
|
tg.wantNotStale("io", want, "with trailing slash in GOROOT, io listed as stale")
|
|
}
|
|
|
|
// 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")
|
|
}
|
|
|
|
// Issue 11065
|
|
func TestInstallToCurrentDirectoryCreatesExecutable(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
pkg := filepath.Join(tg.pwd(), "testdata", "src", "go-cmd-test")
|
|
tg.creatingTemp(filepath.Join(pkg, "go-cmd-test"+exeSuffix))
|
|
tg.setenv("GOBIN", pkg)
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
tg.cd(pkg)
|
|
tg.run("install")
|
|
tg.wantExecutable("go-cmd-test"+exeSuffix, "go install did not write to current directory")
|
|
}
|
|
|
|
// 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 TestGoGetNonPkg(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.tempDir("gobin")
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
tg.setenv("GOBIN", tg.path("gobin"))
|
|
tg.runFail("get", "-d", "golang.org/x/tools")
|
|
tg.grepStderr("golang.org/x/tools: no Go files", "missing error")
|
|
tg.runFail("get", "-d", "-u", "golang.org/x/tools")
|
|
tg.grepStderr("golang.org/x/tools: no Go files", "missing error")
|
|
tg.runFail("get", "-d", "golang.org/x/tools")
|
|
tg.grepStderr("golang.org/x/tools: no Go files", "missing error")
|
|
}
|
|
|
|
func TestGoGetTestOnlyPkg(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.tempDir("gopath")
|
|
tg.setenv("GOPATH", tg.path("gopath"))
|
|
tg.run("get", "golang.org/x/tour/content")
|
|
tg.run("get", "-t", "golang.org/x/tour/content")
|
|
}
|
|
|
|
func TestInstalls(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("don't install into GOROOT in short mode")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
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 TestRejectRelativeDotPathInGOPATHCommandLinePackage(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", ".")
|
|
tg.runFail("build", "testdata/src/go-cmd-test/helloworld.go")
|
|
tg.grepStderr("GOPATH entry is relative", "expected an error message rejecting relative GOPATH entries")
|
|
}
|
|
|
|
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")
|
|
tg.grepStderr("GOPATH entry is relative", "expected an error message rejecting relative GOPATH entries")
|
|
}
|
|
|
|
func TestRejectRelativePathsInGOPATHCommandLinePackage(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", "testdata")
|
|
tg.runFail("build", "testdata/src/go-cmd-test/helloworld.go")
|
|
tg.grepStderr("GOPATH entry is relative", "expected an error message rejecting relative GOPATH entries")
|
|
}
|
|
|
|
// Issue 4104.
|
|
func TestGoTestWithPackageListedMultipleTimes(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.run("test", "errors", "errors", "errors", "errors", "errors")
|
|
if strings.Contains(strings.TrimSpace(tg.getStdout()), "\n") {
|
|
t.Error("go test errors errors errors errors errors tested the same package multiple times")
|
|
}
|
|
}
|
|
|
|
func TestGoListHasAConsistentOrder(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
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.parallel()
|
|
tg.run("list", "std")
|
|
tg.grepStdoutNot("cmd/", "go list std shows commands")
|
|
}
|
|
|
|
func TestGoListCmdOnlyShowsCommands(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.run("list", "cmd")
|
|
out := strings.TrimSpace(tg.getStdout())
|
|
for _, line := range strings.Split(out, "\n") {
|
|
if !strings.Contains(line, "cmd/") {
|
|
t.Error("go list cmd shows non-commands")
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGoListDedupsPackages(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
tg.run("list", "xtestonly", "./testdata/src/xtestonly/...")
|
|
got := strings.TrimSpace(tg.getStdout())
|
|
const want = "xtestonly"
|
|
if got != want {
|
|
t.Errorf("got %q; want %q", got, want)
|
|
}
|
|
}
|
|
|
|
// Issue 4096. Validate the output of unsuccessful go install foo/quxx.
|
|
func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
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.parallel()
|
|
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()
|
|
tg.parallel()
|
|
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()
|
|
tg.parallel()
|
|
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()
|
|
tg.parallel()
|
|
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`)
|
|
}
|
|
}
|
|
|
|
func homeEnvName() string {
|
|
switch runtime.GOOS {
|
|
case "windows":
|
|
return "USERPROFILE"
|
|
case "plan9":
|
|
return "home"
|
|
default:
|
|
return "HOME"
|
|
}
|
|
}
|
|
|
|
func TestDefaultGOPATH(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.tempDir("home/go")
|
|
tg.setenv(homeEnvName(), tg.path("home"))
|
|
|
|
tg.run("env", "GOPATH")
|
|
tg.grepStdout(regexp.QuoteMeta(tg.path("home/go")), "want GOPATH=$HOME/go")
|
|
|
|
tg.setenv("GOROOT", tg.path("home/go"))
|
|
tg.run("env", "GOPATH")
|
|
tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go")
|
|
|
|
tg.setenv("GOROOT", tg.path("home/go")+"/")
|
|
tg.run("env", "GOPATH")
|
|
tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go/")
|
|
}
|
|
|
|
func TestDefaultGOPATHGet(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", "")
|
|
tg.tempDir("home")
|
|
tg.setenv(homeEnvName(), tg.path("home"))
|
|
|
|
// warn for creating directory
|
|
tg.run("get", "-v", "github.com/golang/example/hello")
|
|
tg.grepStderr("created GOPATH="+regexp.QuoteMeta(tg.path("home/go"))+"; see 'go help gopath'", "did not create GOPATH")
|
|
|
|
// no warning if directory already exists
|
|
tg.must(os.RemoveAll(tg.path("home/go")))
|
|
tg.tempDir("home/go")
|
|
tg.run("get", "github.com/golang/example/hello")
|
|
tg.grepStderrNot(".", "expected no output on standard error")
|
|
|
|
// error if $HOME/go is a file
|
|
tg.must(os.RemoveAll(tg.path("home/go")))
|
|
tg.tempFile("home/go", "")
|
|
tg.runFail("get", "github.com/golang/example/hello")
|
|
tg.grepStderr(`mkdir .*[/\\]go: .*(not a directory|cannot find the path)`, "expected error because $HOME/go is a file")
|
|
}
|
|
|
|
func TestDefaultGOPATHPrintedSearchList(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", "")
|
|
tg.tempDir("home")
|
|
tg.setenv(homeEnvName(), tg.path("home"))
|
|
|
|
tg.runFail("install", "github.com/golang/example/hello")
|
|
tg.grepStderr(regexp.QuoteMeta(tg.path("home/go/src/github.com/golang/example/hello"))+`.*from \$GOPATH`, "expected default GOPATH")
|
|
}
|
|
|
|
// Issue 4186. go get cannot be used to download packages to $GOROOT.
|
|
// Test that without GOPATH set, go get should fail.
|
|
func TestGoGetIntoGOROOT(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.tempDir("src")
|
|
|
|
// Fails because GOROOT=GOPATH
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
tg.setenv("GOROOT", tg.path("."))
|
|
tg.runFail("get", "-d", "github.com/golang/example/hello")
|
|
tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
|
|
tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
|
|
|
|
// Fails because GOROOT=GOPATH after cleaning.
|
|
tg.setenv("GOPATH", tg.path(".")+"/")
|
|
tg.setenv("GOROOT", tg.path("."))
|
|
tg.runFail("get", "-d", "github.com/golang/example/hello")
|
|
tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
|
|
tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
|
|
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
tg.setenv("GOROOT", tg.path(".")+"/")
|
|
tg.runFail("get", "-d", "github.com/golang/example/hello")
|
|
tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
|
|
tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
|
|
|
|
// Fails because GOROOT=$HOME/go so default GOPATH unset.
|
|
tg.tempDir("home/go")
|
|
tg.setenv(homeEnvName(), tg.path("home"))
|
|
tg.setenv("GOPATH", "")
|
|
tg.setenv("GOROOT", tg.path("home/go"))
|
|
tg.runFail("get", "-d", "github.com/golang/example/hello")
|
|
tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
|
|
|
|
tg.setenv(homeEnvName(), tg.path("home")+"/")
|
|
tg.setenv("GOPATH", "")
|
|
tg.setenv("GOROOT", tg.path("home/go"))
|
|
tg.runFail("get", "-d", "github.com/golang/example/hello")
|
|
tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
|
|
|
|
tg.setenv(homeEnvName(), tg.path("home"))
|
|
tg.setenv("GOPATH", "")
|
|
tg.setenv("GOROOT", tg.path("home/go")+"/")
|
|
tg.runFail("get", "-d", "github.com/golang/example/hello")
|
|
tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
|
|
}
|
|
|
|
func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
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()
|
|
// TODO: tg.parallel()
|
|
tg.makeTempdir()
|
|
tg.cd(tg.path("."))
|
|
tg.run("test", "-cpuprofile", "errors.prof", "errors")
|
|
tg.wantExecutable("errors.test"+exeSuffix, "go test -cpuprofile did not create errors.test")
|
|
}
|
|
|
|
func TestGoTestCpuprofileDashOControlsBinaryLocation(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
tg.makeTempdir()
|
|
tg.cd(tg.path("."))
|
|
tg.run("test", "-cpuprofile", "errors.prof", "-o", "myerrors.test"+exeSuffix, "errors")
|
|
tg.wantExecutable("myerrors.test"+exeSuffix, "go test -cpuprofile -o myerrors.test did not create myerrors.test")
|
|
}
|
|
|
|
func TestGoTestMutexprofileLeavesBinaryBehind(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
tg.makeTempdir()
|
|
tg.cd(tg.path("."))
|
|
tg.run("test", "-mutexprofile", "errors.prof", "errors")
|
|
tg.wantExecutable("errors.test"+exeSuffix, "go test -mutexprofile did not create errors.test")
|
|
}
|
|
|
|
func TestGoTestMutexprofileDashOControlsBinaryLocation(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
tg.makeTempdir()
|
|
tg.cd(tg.path("."))
|
|
tg.run("test", "-mutexprofile", "errors.prof", "-o", "myerrors.test"+exeSuffix, "errors")
|
|
tg.wantExecutable("myerrors.test"+exeSuffix, "go test -mutexprofile -o myerrors.test did not create myerrors.test")
|
|
}
|
|
|
|
func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.makeTempdir()
|
|
tg.run("test", "-c", "-o", tg.path("myerrors.test"+exeSuffix), "errors")
|
|
tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -c -o myerrors.test did not create myerrors.test")
|
|
}
|
|
|
|
func TestGoTestDashOWritesBinary(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.makeTempdir()
|
|
tg.run("test", "-o", tg.path("myerrors.test"+exeSuffix), "errors")
|
|
tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test")
|
|
}
|
|
|
|
func TestGoTestDashIDashOWritesBinary(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.makeTempdir()
|
|
tg.run("test", "-v", "-i", "-o", tg.path("myerrors.test"+exeSuffix), "errors")
|
|
tg.grepBothNot("PASS|FAIL", "test should not have run")
|
|
tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test")
|
|
}
|
|
|
|
// Issue 4568.
|
|
func TestSymlinksList(t *testing.T) {
|
|
testenv.MustHaveSymlink(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
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 14054.
|
|
func TestSymlinksVendor(t *testing.T) {
|
|
testenv.MustHaveSymlink(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
tg.tempDir("gopath/src/dir1/vendor/v")
|
|
tg.tempFile("gopath/src/dir1/p.go", "package main\nimport _ `v`\nfunc main(){}")
|
|
tg.tempFile("gopath/src/dir1/vendor/v/v.go", "package v")
|
|
tg.must(os.Symlink(tg.path("gopath/src/dir1"), tg.path("symdir1")))
|
|
tg.setenv("GOPATH", tg.path("gopath"))
|
|
tg.cd(tg.path("symdir1"))
|
|
tg.run("list", "-f", "{{.Root}}", ".")
|
|
if strings.TrimSpace(tg.getStdout()) != tg.path("gopath") {
|
|
t.Error("list confused by symlinks")
|
|
}
|
|
|
|
// All of these should succeed, not die in vendor-handling code.
|
|
tg.run("run", "p.go")
|
|
tg.run("build")
|
|
tg.run("install")
|
|
}
|
|
|
|
// Issue 15201.
|
|
func TestSymlinksVendor15201(t *testing.T) {
|
|
testenv.MustHaveSymlink(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
|
|
tg.tempDir("gopath/src/x/y/_vendor/src/x")
|
|
tg.must(os.Symlink("../../..", tg.path("gopath/src/x/y/_vendor/src/x/y")))
|
|
tg.tempFile("gopath/src/x/y/w/w.go", "package w\nimport \"x/y/z\"\n")
|
|
tg.must(os.Symlink("../_vendor/src", tg.path("gopath/src/x/y/w/vendor")))
|
|
tg.tempFile("gopath/src/x/y/z/z.go", "package z\n")
|
|
|
|
tg.setenv("GOPATH", tg.path("gopath/src/x/y/_vendor")+string(filepath.ListSeparator)+tg.path("gopath"))
|
|
tg.cd(tg.path("gopath/src"))
|
|
tg.run("list", "./...")
|
|
}
|
|
|
|
func TestSymlinksInternal(t *testing.T) {
|
|
testenv.MustHaveSymlink(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.tempDir("gopath/src/dir1/internal/v")
|
|
tg.tempFile("gopath/src/dir1/p.go", "package main\nimport _ `dir1/internal/v`\nfunc main(){}")
|
|
tg.tempFile("gopath/src/dir1/internal/v/v.go", "package v")
|
|
tg.must(os.Symlink(tg.path("gopath/src/dir1"), tg.path("symdir1")))
|
|
tg.setenv("GOPATH", tg.path("gopath"))
|
|
tg.cd(tg.path("symdir1"))
|
|
tg.run("list", "-f", "{{.Root}}", ".")
|
|
if strings.TrimSpace(tg.getStdout()) != tg.path("gopath") {
|
|
t.Error("list confused by symlinks")
|
|
}
|
|
|
|
// All of these should succeed, not die in internal-handling code.
|
|
tg.run("run", "p.go")
|
|
tg.run("build")
|
|
tg.run("install")
|
|
}
|
|
|
|
// Issue 4515.
|
|
func TestInstallWithTags(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
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.parallel()
|
|
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.run("list", "-json", "example/a")
|
|
tg.grepStdout("case-insensitive import collision", "go list -json example/a did not report import collision")
|
|
tg.runFail("build", "example/a")
|
|
tg.grepStderr("case-insensitive import collision", "go build 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")
|
|
|
|
tg.runFail("list", "example/a/pkg", "example/a/Pkg")
|
|
tg.grepStderr("case-insensitive import collision", "go list example/a/pkg example/a/Pkg did not report import collision")
|
|
tg.run("list", "-json", "-e", "example/a/pkg", "example/a/Pkg")
|
|
tg.grepStdout("case-insensitive import collision", "go list -json -e example/a/pkg example/a/Pkg did not report import collision")
|
|
tg.runFail("build", "example/a/pkg", "example/a/Pkg")
|
|
tg.grepStderr("case-insensitive import collision", "go build example/a/pkg example/a/Pkg did not report import collision")
|
|
}
|
|
|
|
// Issue 17451, 17662.
|
|
func TestSymlinkWarning(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
|
|
tg.tempDir("src/example/xx")
|
|
tg.tempDir("yy/zz")
|
|
tg.tempFile("yy/zz/zz.go", "package zz\n")
|
|
if err := os.Symlink(tg.path("yy"), tg.path("src/example/xx/yy")); err != nil {
|
|
t.Skip("symlink failed: %v", err)
|
|
}
|
|
tg.run("list", "example/xx/z...")
|
|
tg.grepStdoutNot(".", "list should not have matched anything")
|
|
tg.grepStderr("matched no packages", "list should have reported that pattern matched no packages")
|
|
tg.grepStderrNot("symlink", "list should not have reported symlink")
|
|
|
|
tg.run("list", "example/xx/...")
|
|
tg.grepStdoutNot(".", "list should not have matched anything")
|
|
tg.grepStderr("matched no packages", "list should have reported that pattern matched no packages")
|
|
tg.grepStderr("ignoring symlink", "list should have reported symlink")
|
|
}
|
|
|
|
// Issue 8181.
|
|
func TestGoGetDashTIssue8181(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
tg.run("get", "-v", "-t", "github.com/rsc/go-get-issue-8181/a", "github.com/rsc/go-get-issue-8181/b")
|
|
tg.run("list", "...")
|
|
tg.grepStdout("x/build/gerrit", "missing expected x/build/gerrit")
|
|
}
|
|
|
|
func TestIssue11307(t *testing.T) {
|
|
// go get -u was not working except in checkout directory
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
tg.run("get", "github.com/rsc/go-get-issue-11307")
|
|
tg.run("get", "-u", "github.com/rsc/go-get-issue-11307") // was failing
|
|
}
|
|
|
|
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.
|
|
for _, r := range " :" {
|
|
pwdForwardSlash = strings.Replace(pwdForwardSlash, string(r), "_", -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 TestCoverageImportMainLoop(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
tg.runFail("test", "importmain/test")
|
|
tg.grepStderr("not an importable package", "did not detect import main")
|
|
tg.runFail("test", "-cover", "importmain/test")
|
|
tg.grepStderr("not an importable package", "did not detect import main")
|
|
}
|
|
|
|
func TestPluginNonMain(t *testing.T) {
|
|
wd, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
pkg := filepath.Join(wd, "testdata", "testdep", "p2")
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
|
|
tg.runFail("build", "-buildmode=plugin", pkg)
|
|
}
|
|
|
|
func TestTestEmpty(t *testing.T) {
|
|
if !canRace {
|
|
t.Skip("no race detector")
|
|
}
|
|
|
|
wd, _ := os.Getwd()
|
|
testdata := filepath.Join(wd, "testdata")
|
|
for _, dir := range []string{"pkg", "test", "xtest", "pkgtest", "pkgxtest", "pkgtestxtest", "testxtest"} {
|
|
t.Run(dir, func(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", testdata)
|
|
tg.cd(filepath.Join(testdata, "src/empty/"+dir))
|
|
tg.run("test", "-cover", "-coverpkg=.", "-race")
|
|
})
|
|
if testing.Short() {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNoGoError(t *testing.T) {
|
|
wd, _ := os.Getwd()
|
|
testdata := filepath.Join(wd, "testdata")
|
|
for _, dir := range []string{"empty/test", "empty/xtest", "empty/testxtest", "exclude", "exclude/ignore", "exclude/empty"} {
|
|
t.Run(dir, func(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", testdata)
|
|
tg.cd(filepath.Join(testdata, "src"))
|
|
tg.runFail("build", "./"+dir)
|
|
var want string
|
|
if strings.Contains(dir, "test") {
|
|
want = "no non-test Go files in "
|
|
} else if dir == "exclude" {
|
|
want = "build constraints exclude all Go files in "
|
|
} else {
|
|
want = "no Go files in "
|
|
}
|
|
tg.grepStderr(want, "wrong reason for failure")
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTestRaceInstall(t *testing.T) {
|
|
if !canRace {
|
|
t.Skip("no race detector")
|
|
}
|
|
if testing.Short() && testenv.Builder() == "" {
|
|
t.Skip("don't rebuild the standard library in short mode")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
|
|
tg.tempDir("pkg")
|
|
pkgdir := tg.path("pkg")
|
|
tg.run("install", "-race", "-pkgdir="+pkgdir, "std")
|
|
tg.run("test", "-race", "-pkgdir="+pkgdir, "-i", "-v", "empty/pkg")
|
|
if tg.getStderr() != "" {
|
|
t.Error("go test -i -race: rebuilds cached packages")
|
|
}
|
|
}
|
|
|
|
func TestBuildDryRunWithCgo(t *testing.T) {
|
|
if !canCgo {
|
|
t.Skip("skipping because cgo not enabled")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.tempFile("foo.go", `package main
|
|
|
|
/*
|
|
#include <limits.h>
|
|
*/
|
|
import "C"
|
|
|
|
func main() {
|
|
println(C.INT_MAX)
|
|
}`)
|
|
tg.run("build", "-n", tg.path("foo.go"))
|
|
tg.grepStderrNot(`os.Stat .* no such file or directory`, "unexpected stat of archive file")
|
|
}
|
|
|
|
func TestCoverageWithCgo(t *testing.T) {
|
|
if !canCgo {
|
|
t.Skip("skipping because cgo not enabled")
|
|
}
|
|
|
|
for _, dir := range []string{"cgocover", "cgocover2", "cgocover3", "cgocover4"} {
|
|
t.Run(dir, func(t *testing.T) {
|
|
tg := testgo(t)
|
|
tg.parallel()
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
tg.run("test", "-short", "-cover", dir)
|
|
data := tg.getStdout() + tg.getStderr()
|
|
checkCoverage(tg, data)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCgoAsmError(t *testing.T) {
|
|
if !canCgo {
|
|
t.Skip("skipping because cgo not enabled")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
tg.parallel()
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
tg.runFail("build", "cgoasm")
|
|
tg.grepBoth("package using cgo has Go assembly file", "did not detect Go assembly file")
|
|
}
|
|
|
|
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.parallel()
|
|
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.parallel()
|
|
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")
|
|
}
|
|
|
|
func TestCgoPkgConfig(t *testing.T) {
|
|
if !canCgo {
|
|
t.Skip("skipping because cgo not enabled")
|
|
}
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
|
|
tg.run("env", "PKG_CONFIG")
|
|
pkgConfig := strings.TrimSpace(tg.getStdout())
|
|
if out, err := exec.Command(pkgConfig, "--atleast-pkgconfig-version", "0.24").CombinedOutput(); err != nil {
|
|
t.Skipf("%s --atleast-pkgconfig-version 0.24: %v\n%s", pkgConfig, err, out)
|
|
}
|
|
|
|
// OpenBSD's pkg-config is strict about whitespace and only
|
|
// supports backslash-escaped whitespace. It does not support
|
|
// quotes, which the normal freedesktop.org pkg-config does
|
|
// support. See http://man.openbsd.org/pkg-config.1
|
|
tg.tempFile("foo.pc", `
|
|
Name: foo
|
|
Description: The foo library
|
|
Version: 1.0.0
|
|
Cflags: -Dhello=10 -Dworld=+32 -DDEFINED_FROM_PKG_CONFIG=hello\ world
|
|
`)
|
|
tg.tempFile("foo.go", `package main
|
|
|
|
/*
|
|
#cgo pkg-config: foo
|
|
int value() {
|
|
return DEFINED_FROM_PKG_CONFIG;
|
|
}
|
|
*/
|
|
import "C"
|
|
import "os"
|
|
|
|
func main() {
|
|
if C.value() != 42 {
|
|
println("value() =", C.value(), "wanted 42")
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
`)
|
|
tg.setenv("PKG_CONFIG_PATH", tg.path("."))
|
|
tg.run("run", tg.path("foo.go"))
|
|
}
|
|
|
|
// "go test -c -test.bench=XXX errors" should not hang
|
|
func TestIssue6480(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
tg.makeTempdir()
|
|
tg.cd(tg.path("."))
|
|
tg.run("test", "-c", "-test.bench=XXX", "errors")
|
|
}
|
|
|
|
// cmd/cgo: undefined reference when linking a C-library using gccgo
|
|
func TestIssue7573(t *testing.T) {
|
|
if !canCgo {
|
|
t.Skip("skipping because cgo not enabled")
|
|
}
|
|
if _, err := exec.LookPath("gccgo"); err != nil {
|
|
t.Skip("skipping because no gccgo compiler found")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
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 TestListTemplateContextFunction(t *testing.T) {
|
|
t.Parallel()
|
|
for _, tt := range []struct {
|
|
v string
|
|
want string
|
|
}{
|
|
{"GOARCH", runtime.GOARCH},
|
|
{"GOOS", runtime.GOOS},
|
|
{"GOROOT", filepath.Clean(runtime.GOROOT())},
|
|
{"GOPATH", os.Getenv("GOPATH")},
|
|
{"CgoEnabled", ""},
|
|
{"UseAllFiles", ""},
|
|
{"Compiler", ""},
|
|
{"BuildTags", ""},
|
|
{"ReleaseTags", ""},
|
|
{"InstallSuffix", ""},
|
|
} {
|
|
tt := tt
|
|
t.Run(tt.v, func(t *testing.T) {
|
|
tg := testgo(t)
|
|
tg.parallel()
|
|
defer tg.cleanup()
|
|
tmpl := "{{context." + tt.v + "}}"
|
|
tg.run("list", "-f", tmpl)
|
|
if tt.want == "" {
|
|
return
|
|
}
|
|
if got := strings.TrimSpace(tg.getStdout()); got != tt.want {
|
|
t.Errorf("go list -f %q: got %q; want %q", tmpl, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// 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 library 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.parallel()
|
|
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) {
|
|
tg.sleep()
|
|
tg.must(os.Chtimes(tg.path("src/x/y/foo/foo.go"), time.Now(), time.Now()))
|
|
tg.sleep()
|
|
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 non-test Go files in", "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")
|
|
|
|
tg.runFail("test", "-c", "testcycle/q1")
|
|
tg.grepStderr("import cycle not allowed in test", "go test testcycle/q1 produced unexpected error")
|
|
}
|
|
|
|
func TestGoTestFooTestWorks(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.run("test", "testdata/standalone_test.go")
|
|
}
|
|
|
|
func TestGoTestFlagsAfterPackage(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.run("test", "testdata/flag_test.go", "-v", "-args", "-v=7") // Two distinct -v flags.
|
|
tg.run("test", "-v", "testdata/flag_test.go", "-args", "-v=7") // Two distinct -v flags.
|
|
}
|
|
|
|
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 TestGoGenerateEnv(t *testing.T) {
|
|
switch runtime.GOOS {
|
|
case "plan9", "windows":
|
|
t.Skipf("skipping because %s does not have the env command", runtime.GOOS)
|
|
}
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.tempFile("env.go", "package main\n\n//go:generate env")
|
|
tg.run("generate", tg.path("env.go"))
|
|
for _, v := range []string{"GOARCH", "GOOS", "GOFILE", "GOLINE", "GOPACKAGE", "DOLLAR"} {
|
|
tg.grepStdout("^"+v+"=", "go generate environment missing "+v)
|
|
}
|
|
}
|
|
|
|
func TestGoGenerateBadImports(t *testing.T) {
|
|
if runtime.GOOS == "windows" {
|
|
t.Skip("skipping because windows has no echo command")
|
|
}
|
|
|
|
// This package has an invalid import causing an import cycle,
|
|
// but go generate is supposed to still run.
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
tg.run("generate", "gencycle")
|
|
tg.grepStdout("hello world", "go generate gencycle did not run generator")
|
|
}
|
|
|
|
func TestGoGetCustomDomainWildcard(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
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 TestGoGetInternalWildcard(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
// used to fail with errors about internal packages
|
|
tg.run("get", "github.com/rsc/go-get-issue-11960/...")
|
|
}
|
|
|
|
func TestGoVetWithExternalTests(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
tg.run("install", "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) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
tg.run("install", "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 vet vetpkg did not run scan tagged file")
|
|
}
|
|
|
|
func TestGoVetWithFlagsOn(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
tg.run("install", "cmd/vet")
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
tg.runFail("vet", "-printf", "vetpkg")
|
|
tg.grepBoth("missing argument for Printf", "go vet -printf vetpkg did not find missing argument for Printf")
|
|
}
|
|
|
|
func TestGoVetWithFlagsOff(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
tg.run("install", "cmd/vet")
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
tg.run("vet", "-printf=false", "vetpkg")
|
|
}
|
|
|
|
// Issue 9767, 19769.
|
|
func TestGoGetDotSlashDownload(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
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", "./pprof_mac_fix")
|
|
}
|
|
|
|
// Issue 13037: Was not parsing <meta> tags in 404 served over HTTPS
|
|
func TestGoGetHTTPS404(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
switch runtime.GOOS {
|
|
case "darwin", "linux", "freebsd":
|
|
default:
|
|
t.Skipf("test case does not work on %s", runtime.GOOS)
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.tempDir("src")
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
tg.run("get", "bazil.org/fuse/fs/fstestutil")
|
|
}
|
|
|
|
// Test that you cannot import a main package.
|
|
// See golang.org/issue/4210 and golang.org/issue/17475.
|
|
func TestImportMain(t *testing.T) {
|
|
tg := testgo(t)
|
|
tg.parallel()
|
|
defer tg.cleanup()
|
|
|
|
// Importing package main from that package main's test should work.
|
|
tg.tempFile("src/x/main.go", `package main
|
|
var X int
|
|
func main() {}`)
|
|
tg.tempFile("src/x/main_test.go", `package main_test
|
|
import xmain "x"
|
|
import "testing"
|
|
var _ = xmain.X
|
|
func TestFoo(t *testing.T) {}
|
|
`)
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
tg.creatingTemp("x")
|
|
tg.run("build", "x")
|
|
tg.run("test", "x")
|
|
|
|
// Importing package main from another package should fail.
|
|
tg.tempFile("src/p1/p.go", `package p1
|
|
import xmain "x"
|
|
var _ = xmain.X
|
|
`)
|
|
tg.runFail("build", "p1")
|
|
tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
|
|
|
|
// ... even in that package's test.
|
|
tg.tempFile("src/p2/p.go", `package p2
|
|
`)
|
|
tg.tempFile("src/p2/p_test.go", `package p2
|
|
import xmain "x"
|
|
import "testing"
|
|
var _ = xmain.X
|
|
func TestFoo(t *testing.T) {}
|
|
`)
|
|
tg.run("build", "p2")
|
|
tg.runFail("test", "p2")
|
|
tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
|
|
|
|
// ... even if that package's test is an xtest.
|
|
tg.tempFile("src/p3/p.go", `package p
|
|
`)
|
|
tg.tempFile("src/p3/p_test.go", `package p_test
|
|
import xmain "x"
|
|
import "testing"
|
|
var _ = xmain.X
|
|
func TestFoo(t *testing.T) {}
|
|
`)
|
|
tg.run("build", "p3")
|
|
tg.runFail("test", "p3")
|
|
tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
|
|
|
|
// ... even if that package is a package main
|
|
tg.tempFile("src/p4/p.go", `package main
|
|
func main() {}
|
|
`)
|
|
tg.tempFile("src/p4/p_test.go", `package main
|
|
import xmain "x"
|
|
import "testing"
|
|
var _ = xmain.X
|
|
func TestFoo(t *testing.T) {}
|
|
`)
|
|
tg.creatingTemp("p4" + exeSuffix)
|
|
tg.run("build", "p4")
|
|
tg.runFail("test", "p4")
|
|
tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
|
|
|
|
// ... even if that package is a package main using an xtest.
|
|
tg.tempFile("src/p5/p.go", `package main
|
|
func main() {}
|
|
`)
|
|
tg.tempFile("src/p5/p_test.go", `package main_test
|
|
import xmain "x"
|
|
import "testing"
|
|
var _ = xmain.X
|
|
func TestFoo(t *testing.T) {}
|
|
`)
|
|
tg.creatingTemp("p5" + exeSuffix)
|
|
tg.run("build", "p5")
|
|
tg.runFail("test", "p5")
|
|
tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
|
|
}
|
|
|
|
// Test that you cannot use a local import in a package
|
|
// accessed by a non-local import (found in a GOPATH/GOROOT).
|
|
// See golang.org/issue/17475.
|
|
func TestImportLocal(t *testing.T) {
|
|
tg := testgo(t)
|
|
tg.parallel()
|
|
defer tg.cleanup()
|
|
|
|
tg.tempFile("src/dir/x/x.go", `package x
|
|
var X int
|
|
`)
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
tg.run("build", "dir/x")
|
|
|
|
// Ordinary import should work.
|
|
tg.tempFile("src/dir/p0/p.go", `package p0
|
|
import "dir/x"
|
|
var _ = x.X
|
|
`)
|
|
tg.run("build", "dir/p0")
|
|
|
|
// Relative import should not.
|
|
tg.tempFile("src/dir/p1/p.go", `package p1
|
|
import "../x"
|
|
var _ = x.X
|
|
`)
|
|
tg.runFail("build", "dir/p1")
|
|
tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
|
|
|
|
// ... even in a test.
|
|
tg.tempFile("src/dir/p2/p.go", `package p2
|
|
`)
|
|
tg.tempFile("src/dir/p2/p_test.go", `package p2
|
|
import "../x"
|
|
import "testing"
|
|
var _ = x.X
|
|
func TestFoo(t *testing.T) {}
|
|
`)
|
|
tg.run("build", "dir/p2")
|
|
tg.runFail("test", "dir/p2")
|
|
tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
|
|
|
|
// ... even in an xtest.
|
|
tg.tempFile("src/dir/p2/p_test.go", `package p2_test
|
|
import "../x"
|
|
import "testing"
|
|
var _ = x.X
|
|
func TestFoo(t *testing.T) {}
|
|
`)
|
|
tg.run("build", "dir/p2")
|
|
tg.runFail("test", "dir/p2")
|
|
tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
|
|
|
|
// Relative import starting with ./ should not work either.
|
|
tg.tempFile("src/dir/d.go", `package dir
|
|
import "./x"
|
|
var _ = x.X
|
|
`)
|
|
tg.runFail("build", "dir")
|
|
tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
|
|
|
|
// ... even in a test.
|
|
tg.tempFile("src/dir/d.go", `package dir
|
|
`)
|
|
tg.tempFile("src/dir/d_test.go", `package dir
|
|
import "./x"
|
|
import "testing"
|
|
var _ = x.X
|
|
func TestFoo(t *testing.T) {}
|
|
`)
|
|
tg.run("build", "dir")
|
|
tg.runFail("test", "dir")
|
|
tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
|
|
|
|
// ... even in an xtest.
|
|
tg.tempFile("src/dir/d_test.go", `package dir_test
|
|
import "./x"
|
|
import "testing"
|
|
var _ = x.X
|
|
func TestFoo(t *testing.T) {}
|
|
`)
|
|
tg.run("build", "dir")
|
|
tg.runFail("test", "dir")
|
|
tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
|
|
|
|
// Relative import plain ".." should not work.
|
|
tg.tempFile("src/dir/x/y/y.go", `package dir
|
|
import ".."
|
|
var _ = x.X
|
|
`)
|
|
tg.runFail("build", "dir/x/y")
|
|
tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
|
|
|
|
// ... even in a test.
|
|
tg.tempFile("src/dir/x/y/y.go", `package y
|
|
`)
|
|
tg.tempFile("src/dir/x/y/y_test.go", `package y
|
|
import ".."
|
|
import "testing"
|
|
var _ = x.X
|
|
func TestFoo(t *testing.T) {}
|
|
`)
|
|
tg.run("build", "dir/x/y")
|
|
tg.runFail("test", "dir/x/y")
|
|
tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
|
|
|
|
// ... even in an x test.
|
|
tg.tempFile("src/dir/x/y/y_test.go", `package y_test
|
|
import ".."
|
|
import "testing"
|
|
var _ = x.X
|
|
func TestFoo(t *testing.T) {}
|
|
`)
|
|
tg.run("build", "dir/x/y")
|
|
tg.runFail("test", "dir/x/y")
|
|
tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
|
|
|
|
// Relative import "." should not work.
|
|
tg.tempFile("src/dir/x/xx.go", `package x
|
|
import "."
|
|
var _ = x.X
|
|
`)
|
|
tg.runFail("build", "dir/x")
|
|
tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
|
|
|
|
// ... even in a test.
|
|
tg.tempFile("src/dir/x/xx.go", `package x
|
|
`)
|
|
tg.tempFile("src/dir/x/xx_test.go", `package x
|
|
import "."
|
|
import "testing"
|
|
var _ = x.X
|
|
func TestFoo(t *testing.T) {}
|
|
`)
|
|
tg.run("build", "dir/x")
|
|
tg.runFail("test", "dir/x")
|
|
tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
|
|
|
|
// ... even in an xtest.
|
|
tg.tempFile("src/dir/x/xx.go", `package x
|
|
`)
|
|
tg.tempFile("src/dir/x/xx_test.go", `package x_test
|
|
import "."
|
|
import "testing"
|
|
var _ = x.X
|
|
func TestFoo(t *testing.T) {}
|
|
`)
|
|
tg.run("build", "dir/x")
|
|
tg.runFail("test", "dir/x")
|
|
tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
|
|
}
|
|
|
|
func TestGoGetInsecure(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
tg.failSSH()
|
|
|
|
const repo = "insecure.go-get-issue-15410.appspot.com/pkg/p"
|
|
|
|
// Try go get -d of HTTP-only repo (should fail).
|
|
tg.runFail("get", "-d", repo)
|
|
|
|
// Try again with -insecure (should succeed).
|
|
tg.run("get", "-d", "-insecure", repo)
|
|
|
|
// Try updating without -insecure (should fail).
|
|
tg.runFail("get", "-d", "-u", "-f", repo)
|
|
}
|
|
|
|
func TestGoGetUpdateInsecure(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
|
|
const repo = "github.com/golang/example"
|
|
|
|
// Clone the repo via HTTP manually.
|
|
cmd := exec.Command("git", "clone", "-q", "http://"+repo, tg.path("src/"+repo))
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
t.Fatalf("cloning %v repo: %v\n%s", repo, err, out)
|
|
}
|
|
|
|
// Update without -insecure should fail.
|
|
// Update with -insecure should succeed.
|
|
// We need -f to ignore import comments.
|
|
const pkg = repo + "/hello"
|
|
tg.runFail("get", "-d", "-u", "-f", pkg)
|
|
tg.run("get", "-d", "-u", "-f", "-insecure", pkg)
|
|
}
|
|
|
|
func TestGoGetInsecureCustomDomain(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
|
|
const repo = "insecure.go-get-issue-15410.appspot.com/pkg/p"
|
|
tg.runFail("get", "-d", repo)
|
|
tg.run("get", "-d", "-insecure", repo)
|
|
}
|
|
|
|
func TestGoRunDirs(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.cd("testdata/rundir")
|
|
tg.runFail("run", "x.go", "sub/sub.go")
|
|
tg.grepStderr("named files must all be in one directory; have ./ and sub/", "wrong output")
|
|
tg.runFail("run", "sub/sub.go", "x.go")
|
|
tg.grepStderr("named files must all be in one directory; have sub/ and ./", "wrong output")
|
|
}
|
|
|
|
func TestGoInstallPkgdir(t *testing.T) {
|
|
tg := testgo(t)
|
|
tg.parallel()
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
pkg := tg.path(".")
|
|
tg.run("install", "-pkgdir", pkg, "errors")
|
|
_, err := os.Stat(filepath.Join(pkg, "errors.a"))
|
|
tg.must(err)
|
|
_, err = os.Stat(filepath.Join(pkg, "runtime.a"))
|
|
tg.must(err)
|
|
}
|
|
|
|
func TestGoTestRaceInstallCgo(t *testing.T) {
|
|
if !canRace {
|
|
t.Skip("skipping because race detector not supported")
|
|
}
|
|
|
|
// golang.org/issue/10500.
|
|
// This used to install a race-enabled cgo.
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.run("tool", "-n", "cgo")
|
|
cgo := strings.TrimSpace(tg.stdout.String())
|
|
old, err := os.Stat(cgo)
|
|
tg.must(err)
|
|
tg.run("test", "-race", "-i", "runtime/race")
|
|
new, err := os.Stat(cgo)
|
|
tg.must(err)
|
|
if !new.ModTime().Equal(old.ModTime()) {
|
|
t.Fatalf("go test -i runtime/race reinstalled cmd/cgo")
|
|
}
|
|
}
|
|
|
|
func TestGoTestRaceFailures(t *testing.T) {
|
|
if !canRace {
|
|
t.Skip("skipping because race detector not supported")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
tg.parallel()
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
|
|
tg.run("test", "testrace")
|
|
|
|
tg.runFail("test", "-race", "testrace")
|
|
tg.grepStdout("FAIL: TestRace", "TestRace did not fail")
|
|
tg.grepBothNot("PASS", "something passed")
|
|
|
|
tg.runFail("test", "-race", "testrace", "-run", "XXX", "-bench", ".")
|
|
tg.grepStdout("FAIL: BenchmarkRace", "BenchmarkRace did not fail")
|
|
tg.grepBothNot("PASS", "something passed")
|
|
}
|
|
|
|
func TestGoTestImportErrorStack(t *testing.T) {
|
|
const out = `package testdep/p1 (test)
|
|
imports testdep/p2
|
|
imports testdep/p3: build constraints exclude all Go files `
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
tg.runFail("test", "testdep/p1")
|
|
if !strings.Contains(tg.stderr.String(), out) {
|
|
t.Fatalf("did not give full import stack:\n\n%s", tg.stderr.String())
|
|
}
|
|
}
|
|
|
|
func TestGoGetUpdate(t *testing.T) {
|
|
// golang.org/issue/9224.
|
|
// The recursive updating was trying to walk to
|
|
// former dependencies, not current ones.
|
|
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
|
|
rewind := func() {
|
|
tg.run("get", "github.com/rsc/go-get-issue-9224-cmd")
|
|
cmd := exec.Command("git", "reset", "--hard", "HEAD~")
|
|
cmd.Dir = tg.path("src/github.com/rsc/go-get-issue-9224-lib")
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("git: %v\n%s", err, out)
|
|
}
|
|
}
|
|
|
|
rewind()
|
|
tg.run("get", "-u", "github.com/rsc/go-get-issue-9224-cmd")
|
|
|
|
// Again with -d -u.
|
|
rewind()
|
|
tg.run("get", "-d", "-u", "github.com/rsc/go-get-issue-9224-cmd")
|
|
}
|
|
|
|
// Issue #20512.
|
|
func TestGoGetRace(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
if !canRace {
|
|
t.Skip("skipping because race detector not supported")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
tg.run("get", "-race", "github.com/rsc/go-get-issue-9224-cmd")
|
|
}
|
|
|
|
func TestGoGetDomainRoot(t *testing.T) {
|
|
// golang.org/issue/9357.
|
|
// go get foo.io (not foo.io/subdir) was not working consistently.
|
|
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
|
|
// go-get-issue-9357.appspot.com is running
|
|
// the code at github.com/rsc/go-get-issue-9357,
|
|
// a trivial Go on App Engine app that serves a
|
|
// <meta> tag for the domain root.
|
|
tg.run("get", "-d", "go-get-issue-9357.appspot.com")
|
|
tg.run("get", "go-get-issue-9357.appspot.com")
|
|
tg.run("get", "-u", "go-get-issue-9357.appspot.com")
|
|
|
|
tg.must(os.RemoveAll(tg.path("src/go-get-issue-9357.appspot.com")))
|
|
tg.run("get", "go-get-issue-9357.appspot.com")
|
|
|
|
tg.must(os.RemoveAll(tg.path("src/go-get-issue-9357.appspot.com")))
|
|
tg.run("get", "-u", "go-get-issue-9357.appspot.com")
|
|
}
|
|
|
|
func TestGoInstallShadowedGOPATH(t *testing.T) {
|
|
// golang.org/issue/3652.
|
|
// go get foo.io (not foo.io/subdir) was not working consistently.
|
|
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", tg.path("gopath1")+string(filepath.ListSeparator)+tg.path("gopath2"))
|
|
|
|
tg.tempDir("gopath1/src/test")
|
|
tg.tempDir("gopath2/src/test")
|
|
tg.tempFile("gopath2/src/test/main.go", "package main\nfunc main(){}\n")
|
|
|
|
tg.cd(tg.path("gopath2/src/test"))
|
|
tg.runFail("install")
|
|
tg.grepStderr("no install location for.*gopath2.src.test: hidden by .*gopath1.src.test", "missing error")
|
|
}
|
|
|
|
func TestGoBuildGOPATHOrder(t *testing.T) {
|
|
// golang.org/issue/14176#issuecomment-179895769
|
|
// golang.org/issue/14192
|
|
// -I arguments to compiler could end up not in GOPATH order,
|
|
// leading to unexpected import resolution in the compiler.
|
|
// This is still not a complete fix (see golang.org/issue/14271 and next test)
|
|
// but it is clearly OK and enough to fix both of the two reported
|
|
// instances of the underlying problem. It will have to do for now.
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", tg.path("p1")+string(filepath.ListSeparator)+tg.path("p2"))
|
|
|
|
tg.tempFile("p1/src/foo/foo.go", "package foo\n")
|
|
tg.tempFile("p2/src/baz/baz.go", "package baz\n")
|
|
tg.tempFile("p2/pkg/"+runtime.GOOS+"_"+runtime.GOARCH+"/foo.a", "bad\n")
|
|
tg.tempFile("p1/src/bar/bar.go", `
|
|
package bar
|
|
import _ "baz"
|
|
import _ "foo"
|
|
`)
|
|
|
|
tg.run("install", "-x", "bar")
|
|
}
|
|
|
|
func TestGoBuildGOPATHOrderBroken(t *testing.T) {
|
|
// This test is known not to work.
|
|
// See golang.org/issue/14271.
|
|
t.Skip("golang.org/issue/14271")
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
|
|
tg.tempFile("p1/src/foo/foo.go", "package foo\n")
|
|
tg.tempFile("p2/src/baz/baz.go", "package baz\n")
|
|
tg.tempFile("p1/pkg/"+runtime.GOOS+"_"+runtime.GOARCH+"/baz.a", "bad\n")
|
|
tg.tempFile("p2/pkg/"+runtime.GOOS+"_"+runtime.GOARCH+"/foo.a", "bad\n")
|
|
tg.tempFile("p1/src/bar/bar.go", `
|
|
package bar
|
|
import _ "baz"
|
|
import _ "foo"
|
|
`)
|
|
|
|
colon := string(filepath.ListSeparator)
|
|
tg.setenv("GOPATH", tg.path("p1")+colon+tg.path("p2"))
|
|
tg.run("install", "-x", "bar")
|
|
|
|
tg.setenv("GOPATH", tg.path("p2")+colon+tg.path("p1"))
|
|
tg.run("install", "-x", "bar")
|
|
}
|
|
|
|
func TestIssue11709(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.tempFile("run.go", `
|
|
package main
|
|
import "os"
|
|
func main() {
|
|
if os.Getenv("TERM") != "" {
|
|
os.Exit(1)
|
|
}
|
|
}`)
|
|
tg.unsetenv("TERM")
|
|
tg.run("run", tg.path("run.go"))
|
|
}
|
|
|
|
func TestIssue12096(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.tempFile("test_test.go", `
|
|
package main
|
|
import ("os"; "testing")
|
|
func TestEnv(t *testing.T) {
|
|
if os.Getenv("TERM") != "" {
|
|
t.Fatal("TERM is set")
|
|
}
|
|
}`)
|
|
tg.unsetenv("TERM")
|
|
tg.run("test", tg.path("test_test.go"))
|
|
}
|
|
|
|
func TestGoBuildOutput(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
|
|
tg.makeTempdir()
|
|
tg.cd(tg.path("."))
|
|
|
|
nonExeSuffix := ".exe"
|
|
if exeSuffix == ".exe" {
|
|
nonExeSuffix = ""
|
|
}
|
|
|
|
tg.tempFile("x.go", "package main\nfunc main(){}\n")
|
|
tg.run("build", "x.go")
|
|
tg.wantExecutable("x"+exeSuffix, "go build x.go did not write x"+exeSuffix)
|
|
tg.must(os.Remove(tg.path("x" + exeSuffix)))
|
|
tg.mustNotExist("x" + nonExeSuffix)
|
|
|
|
tg.run("build", "-o", "myprog", "x.go")
|
|
tg.mustNotExist("x")
|
|
tg.mustNotExist("x.exe")
|
|
tg.wantExecutable("myprog", "go build -o myprog x.go did not write myprog")
|
|
tg.mustNotExist("myprog.exe")
|
|
|
|
tg.tempFile("p.go", "package p\n")
|
|
tg.run("build", "p.go")
|
|
tg.mustNotExist("p")
|
|
tg.mustNotExist("p.a")
|
|
tg.mustNotExist("p.o")
|
|
tg.mustNotExist("p.exe")
|
|
|
|
tg.run("build", "-o", "p.a", "p.go")
|
|
tg.wantArchive("p.a")
|
|
|
|
tg.run("build", "cmd/gofmt")
|
|
tg.wantExecutable("gofmt"+exeSuffix, "go build cmd/gofmt did not write gofmt"+exeSuffix)
|
|
tg.must(os.Remove(tg.path("gofmt" + exeSuffix)))
|
|
tg.mustNotExist("gofmt" + nonExeSuffix)
|
|
|
|
tg.run("build", "-o", "mygofmt", "cmd/gofmt")
|
|
tg.wantExecutable("mygofmt", "go build -o mygofmt cmd/gofmt did not write mygofmt")
|
|
tg.mustNotExist("mygofmt.exe")
|
|
tg.mustNotExist("gofmt")
|
|
tg.mustNotExist("gofmt.exe")
|
|
|
|
tg.run("build", "sync/atomic")
|
|
tg.mustNotExist("atomic")
|
|
tg.mustNotExist("atomic.exe")
|
|
|
|
tg.run("build", "-o", "myatomic.a", "sync/atomic")
|
|
tg.wantArchive("myatomic.a")
|
|
tg.mustNotExist("atomic")
|
|
tg.mustNotExist("atomic.a")
|
|
tg.mustNotExist("atomic.exe")
|
|
|
|
tg.runFail("build", "-o", "whatever", "cmd/gofmt", "sync/atomic")
|
|
tg.grepStderr("multiple packages", "did not reject -o with multiple packages")
|
|
}
|
|
|
|
func TestGoBuildARM(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping cross-compile in short mode")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
|
|
tg.makeTempdir()
|
|
tg.cd(tg.path("."))
|
|
|
|
tg.setenv("GOARCH", "arm")
|
|
tg.setenv("GOOS", "linux")
|
|
tg.setenv("GOARM", "5")
|
|
tg.tempFile("hello.go", `package main
|
|
func main() {}`)
|
|
tg.run("build", "hello.go")
|
|
tg.grepStderrNot("unable to find math.a", "did not build math.a correctly")
|
|
}
|
|
|
|
func TestIssue13655(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
for _, pkg := range []string{"runtime", "runtime/internal/atomic"} {
|
|
tg.run("list", "-f", "{{.Deps}}", pkg)
|
|
tg.grepStdout("runtime/internal/sys", "did not find required dependency of "+pkg+" on runtime/internal/sys")
|
|
}
|
|
}
|
|
|
|
// For issue 14337.
|
|
func TestParallelTest(t *testing.T) {
|
|
tg := testgo(t)
|
|
tg.parallel()
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
const testSrc = `package package_test
|
|
import (
|
|
"testing"
|
|
)
|
|
func TestTest(t *testing.T) {
|
|
}`
|
|
tg.tempFile("src/p1/p1_test.go", strings.Replace(testSrc, "package_test", "p1_test", 1))
|
|
tg.tempFile("src/p2/p2_test.go", strings.Replace(testSrc, "package_test", "p2_test", 1))
|
|
tg.tempFile("src/p3/p3_test.go", strings.Replace(testSrc, "package_test", "p3_test", 1))
|
|
tg.tempFile("src/p4/p4_test.go", strings.Replace(testSrc, "package_test", "p4_test", 1))
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
tg.run("test", "-p=4", "p1", "p2", "p3", "p4")
|
|
}
|
|
|
|
func TestCgoConsistentResults(t *testing.T) {
|
|
if !canCgo {
|
|
t.Skip("skipping because cgo not enabled")
|
|
}
|
|
switch runtime.GOOS {
|
|
case "freebsd":
|
|
testenv.SkipFlaky(t, 15405)
|
|
case "solaris":
|
|
testenv.SkipFlaky(t, 13247)
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
exe1 := tg.path("cgotest1" + exeSuffix)
|
|
exe2 := tg.path("cgotest2" + exeSuffix)
|
|
tg.run("build", "-o", exe1, "cgotest")
|
|
tg.run("build", "-x", "-o", exe2, "cgotest")
|
|
b1, err := ioutil.ReadFile(exe1)
|
|
tg.must(err)
|
|
b2, err := ioutil.ReadFile(exe2)
|
|
tg.must(err)
|
|
|
|
if !tg.doGrepMatch(`-fdebug-prefix-map=\$WORK`, &tg.stderr) {
|
|
t.Skip("skipping because C compiler does not support -fdebug-prefix-map")
|
|
}
|
|
if !bytes.Equal(b1, b2) {
|
|
t.Error("building cgotest twice did not produce the same output")
|
|
}
|
|
}
|
|
|
|
// Issue 14444: go get -u .../ duplicate loads errors
|
|
func TestGoGetUpdateAllDoesNotTryToLoadDuplicates(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
tg.run("get", "-u", ".../")
|
|
tg.grepStderrNot("duplicate loads of", "did not remove old packages from cache")
|
|
}
|
|
|
|
// Issue 17119 more duplicate load errors
|
|
func TestIssue17119(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
tg.runFail("build", "dupload")
|
|
tg.grepBothNot("duplicate load|internal error", "internal error")
|
|
}
|
|
|
|
func TestFatalInBenchmarkCauseNonZeroExitStatus(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
tg.runFail("test", "-run", "^$", "-bench", ".", "./testdata/src/benchfatal")
|
|
tg.grepBothNot("^ok", "test passed unexpectedly")
|
|
tg.grepBoth("FAIL.*benchfatal", "test did not run everything")
|
|
}
|
|
|
|
func TestBinaryOnlyPackages(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
|
|
tg.tempFile("src/p1/p1.go", `//go:binary-only-package
|
|
|
|
package p1
|
|
`)
|
|
tg.wantStale("p1", "cannot access install target", "p1 is binary-only but has no binary, should be stale")
|
|
tg.runFail("install", "p1")
|
|
tg.grepStderr("missing or invalid package binary", "did not report attempt to compile binary-only package")
|
|
|
|
tg.tempFile("src/p1/p1.go", `
|
|
package p1
|
|
import "fmt"
|
|
func F(b bool) { fmt.Printf("hello from p1\n"); if b { F(false) } }
|
|
`)
|
|
tg.run("install", "p1")
|
|
os.Remove(tg.path("src/p1/p1.go"))
|
|
tg.mustNotExist(tg.path("src/p1/p1.go"))
|
|
|
|
tg.tempFile("src/p2/p2.go", `//go:binary-only-packages-are-not-great
|
|
|
|
package p2
|
|
import "p1"
|
|
func F() { p1.F(true) }
|
|
`)
|
|
tg.runFail("install", "p2")
|
|
tg.grepStderr("no Go files", "did not complain about missing sources")
|
|
|
|
tg.tempFile("src/p1/missing.go", `//go:binary-only-package
|
|
|
|
package p1
|
|
func G()
|
|
`)
|
|
tg.wantNotStale("p1", "no source code", "should NOT want to rebuild p1 (first)")
|
|
tg.run("install", "-x", "p1") // no-op, up to date
|
|
tg.grepBothNot("/compile", "should not have run compiler")
|
|
tg.run("install", "p2") // does not rebuild p1 (or else p2 will fail)
|
|
tg.wantNotStale("p2", "", "should NOT want to rebuild p2")
|
|
|
|
// changes to the non-source-code do not matter,
|
|
// and only one file needs the special comment.
|
|
tg.tempFile("src/p1/missing2.go", `
|
|
package p1
|
|
func H()
|
|
`)
|
|
tg.wantNotStale("p1", "no source code", "should NOT want to rebuild p1 (second)")
|
|
tg.wantNotStale("p2", "", "should NOT want to rebuild p2")
|
|
|
|
tg.tempFile("src/p3/p3.go", `
|
|
package main
|
|
import (
|
|
"p1"
|
|
"p2"
|
|
)
|
|
func main() {
|
|
p1.F(false)
|
|
p2.F()
|
|
}
|
|
`)
|
|
tg.run("install", "p3")
|
|
|
|
tg.run("run", tg.path("src/p3/p3.go"))
|
|
tg.grepStdout("hello from p1", "did not see message from p1")
|
|
|
|
tg.tempFile("src/p4/p4.go", `package main`)
|
|
tg.tempFile("src/p4/p4not.go", `//go:binary-only-package
|
|
|
|
// +build asdf
|
|
|
|
package main
|
|
`)
|
|
tg.run("list", "-f", "{{.BinaryOnly}}", "p4")
|
|
tg.grepStdout("false", "did not see BinaryOnly=false for p4")
|
|
}
|
|
|
|
// Issue 16050.
|
|
func TestAlwaysLinkSysoFiles(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.tempDir("src/syso")
|
|
tg.tempFile("src/syso/a.syso", ``)
|
|
tg.tempFile("src/syso/b.go", `package syso`)
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
|
|
// We should see the .syso file regardless of the setting of
|
|
// CGO_ENABLED.
|
|
|
|
tg.setenv("CGO_ENABLED", "1")
|
|
tg.run("list", "-f", "{{.SysoFiles}}", "syso")
|
|
tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=1")
|
|
|
|
tg.setenv("CGO_ENABLED", "0")
|
|
tg.run("list", "-f", "{{.SysoFiles}}", "syso")
|
|
tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=0")
|
|
}
|
|
|
|
// Issue 16120.
|
|
func TestGenerateUsesBuildContext(t *testing.T) {
|
|
if runtime.GOOS == "windows" {
|
|
t.Skip("this test won't run under Windows")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.tempDir("src/gen")
|
|
tg.tempFile("src/gen/gen.go", "package gen\n//go:generate echo $GOOS $GOARCH\n")
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
|
|
tg.setenv("GOOS", "linux")
|
|
tg.setenv("GOARCH", "amd64")
|
|
tg.run("generate", "gen")
|
|
tg.grepStdout("linux amd64", "unexpected GOOS/GOARCH combination")
|
|
|
|
tg.setenv("GOOS", "darwin")
|
|
tg.setenv("GOARCH", "386")
|
|
tg.run("generate", "gen")
|
|
tg.grepStdout("darwin 386", "unexpected GOOS/GOARCH combination")
|
|
}
|
|
|
|
// Issue 14450: go get -u .../ tried to import not downloaded package
|
|
func TestGoGetUpdateWithWildcard(t *testing.T) {
|
|
testenv.MustHaveExternalNetwork(t)
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
const aPkgImportPath = "github.com/tmwh/go-get-issue-14450/a"
|
|
tg.run("get", aPkgImportPath)
|
|
tg.run("get", "-u", ".../")
|
|
tg.grepStderrNot("cannot find package", "did not update packages given wildcard path")
|
|
|
|
var expectedPkgPaths = []string{
|
|
"src/github.com/tmwh/go-get-issue-14450/b",
|
|
"src/github.com/tmwh/go-get-issue-14450-b-dependency/c",
|
|
"src/github.com/tmwh/go-get-issue-14450-b-dependency/d",
|
|
}
|
|
|
|
for _, importPath := range expectedPkgPaths {
|
|
_, err := os.Stat(tg.path(importPath))
|
|
tg.must(err)
|
|
}
|
|
const notExpectedPkgPath = "src/github.com/tmwh/go-get-issue-14450-c-dependency/e"
|
|
tg.mustNotExist(tg.path(notExpectedPkgPath))
|
|
}
|
|
|
|
func TestGoEnv(t *testing.T) {
|
|
tg := testgo(t)
|
|
tg.parallel()
|
|
defer tg.cleanup()
|
|
tg.setenv("GOARCH", "arm")
|
|
tg.run("env", "GOARCH")
|
|
tg.grepStdout("^arm$", "GOARCH not honored")
|
|
|
|
tg.run("env", "GCCGO")
|
|
tg.grepStdout(".", "GCCGO unexpectedly empty")
|
|
|
|
tg.run("env", "CGO_CFLAGS")
|
|
tg.grepStdout(".", "default CGO_CFLAGS unexpectedly empty")
|
|
|
|
tg.setenv("CGO_CFLAGS", "-foobar")
|
|
tg.run("env", "CGO_CFLAGS")
|
|
tg.grepStdout("^-foobar$", "CGO_CFLAGS not honored")
|
|
|
|
tg.setenv("CC", "gcc -fmust -fgo -ffaster")
|
|
tg.run("env", "CC")
|
|
tg.grepStdout("gcc", "CC not found")
|
|
tg.run("env", "GOGCCFLAGS")
|
|
tg.grepStdout("-ffaster", "CC arguments not found")
|
|
}
|
|
|
|
const (
|
|
noMatchesPattern = `(?m)^ok.*\[no tests to run\]`
|
|
okPattern = `(?m)^ok`
|
|
)
|
|
|
|
func TestMatchesNoTests(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
tg.run("test", "-run", "ThisWillNotMatch", "testdata/standalone_test.go")
|
|
tg.grepBoth(noMatchesPattern, "go test did not say [no tests to run]")
|
|
}
|
|
|
|
func TestMatchesNoTestsDoesNotOverrideBuildFailure(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
tg.runFail("test", "-run", "ThisWillNotMatch", "syntaxerror")
|
|
tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
|
|
tg.grepBoth("FAIL", "go test did not say FAIL")
|
|
}
|
|
|
|
func TestMatchesNoBenchmarksIsOK(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
tg.run("test", "-run", "^$", "-bench", "ThisWillNotMatch", "testdata/standalone_benchmark_test.go")
|
|
tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
|
|
tg.grepBoth(okPattern, "go test did not say ok")
|
|
}
|
|
|
|
func TestMatchesOnlyExampleIsOK(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
tg.run("test", "-run", "Example", "testdata/example1_test.go")
|
|
tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
|
|
tg.grepBoth(okPattern, "go test did not say ok")
|
|
}
|
|
|
|
func TestMatchesOnlyBenchmarkIsOK(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
tg.run("test", "-run", "^$", "-bench", ".", "testdata/standalone_benchmark_test.go")
|
|
tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
|
|
tg.grepBoth(okPattern, "go test did not say ok")
|
|
}
|
|
|
|
func TestBenchmarkLabels(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
tg.run("test", "-run", "^$", "-bench", ".", "bench")
|
|
tg.grepStdout(`(?m)^goos: `+runtime.GOOS, "go test did not print goos")
|
|
tg.grepStdout(`(?m)^goarch: `+runtime.GOARCH, "go test did not print goarch")
|
|
tg.grepStdout(`(?m)^pkg: bench`, "go test did not say pkg: bench")
|
|
tg.grepBothNot(`(?s)pkg:.*pkg:`, "go test said pkg multiple times")
|
|
}
|
|
|
|
func TestBenchmarkLabelsOutsideGOPATH(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
tg.run("test", "-run", "^$", "-bench", ".", "testdata/standalone_benchmark_test.go")
|
|
tg.grepStdout(`(?m)^goos: `+runtime.GOOS, "go test did not print goos")
|
|
tg.grepStdout(`(?m)^goarch: `+runtime.GOARCH, "go test did not print goarch")
|
|
tg.grepBothNot(`(?m)^pkg:`, "go test did say pkg:")
|
|
}
|
|
|
|
func TestMatchesOnlyTestIsOK(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
// TODO: tg.parallel()
|
|
tg.run("test", "-run", "Test", "testdata/standalone_test.go")
|
|
tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
|
|
tg.grepBoth(okPattern, "go test did not say ok")
|
|
}
|
|
|
|
func TestMatchesNoTestsWithSubtests(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.run("test", "-run", "ThisWillNotMatch", "testdata/standalone_sub_test.go")
|
|
tg.grepBoth(noMatchesPattern, "go test did not say [no tests to run]")
|
|
}
|
|
|
|
func TestMatchesNoSubtestsMatch(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.run("test", "-run", "Test/ThisWillNotMatch", "testdata/standalone_sub_test.go")
|
|
tg.grepBoth(noMatchesPattern, "go test did not say [no tests to run]")
|
|
}
|
|
|
|
func TestMatchesNoSubtestsDoesNotOverrideFailure(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.runFail("test", "-run", "TestThatFails/ThisWillNotMatch", "testdata/standalone_fail_sub_test.go")
|
|
tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
|
|
tg.grepBoth("FAIL", "go test did not say FAIL")
|
|
}
|
|
|
|
func TestMatchesOnlySubtestIsOK(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.run("test", "-run", "Test/Sub", "testdata/standalone_sub_test.go")
|
|
tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
|
|
tg.grepBoth(okPattern, "go test did not say ok")
|
|
}
|
|
|
|
func TestMatchesNoSubtestsParallel(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.run("test", "-run", "Test/Sub/ThisWillNotMatch", "testdata/standalone_parallel_sub_test.go")
|
|
tg.grepBoth(noMatchesPattern, "go test did not say [no tests to run]")
|
|
}
|
|
|
|
func TestMatchesOnlySubtestParallelIsOK(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.run("test", "-run", "Test/Sub/Nested", "testdata/standalone_parallel_sub_test.go")
|
|
tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
|
|
tg.grepBoth(okPattern, "go test did not say ok")
|
|
}
|
|
|
|
// Issue 18845
|
|
func TestBenchTimeout(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.run("test", "-bench", ".", "-timeout", "750ms", "testdata/timeoutbench_test.go")
|
|
}
|
|
|
|
func TestLinkXImportPathEscape(t *testing.T) {
|
|
// golang.org/issue/16710
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
exe := "./linkx" + exeSuffix
|
|
tg.creatingTemp(exe)
|
|
tg.run("build", "-o", exe, "-ldflags", "-X=my.pkg.Text=linkXworked", "my.pkg/main")
|
|
out, err := exec.Command(exe).CombinedOutput()
|
|
if err != nil {
|
|
tg.t.Fatal(err)
|
|
}
|
|
if string(out) != "linkXworked\n" {
|
|
tg.t.Log(string(out))
|
|
tg.t.Fatal(`incorrect output: expected "linkXworked\n"`)
|
|
}
|
|
}
|
|
|
|
// Issue 18044.
|
|
func TestLdBindNow(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.setenv("LD_BIND_NOW", "1")
|
|
tg.run("help")
|
|
}
|
|
|
|
// Issue 18225.
|
|
// This is really a cmd/asm issue but this is a convenient place to test it.
|
|
func TestConcurrentAsm(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
asm := `DATA ·constants<>+0x0(SB)/8,$0
|
|
GLOBL ·constants<>(SB),8,$8
|
|
`
|
|
tg.tempFile("go/src/p/a.s", asm)
|
|
tg.tempFile("go/src/p/b.s", asm)
|
|
tg.tempFile("go/src/p/p.go", `package p`)
|
|
tg.setenv("GOPATH", tg.path("go"))
|
|
tg.run("build", "p")
|
|
}
|
|
|
|
// Issue 18778.
|
|
func TestDotDotDotOutsideGOPATH(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
|
|
tg.tempFile("pkgs/a.go", `package x`)
|
|
tg.tempFile("pkgs/a_test.go", `package x_test
|
|
import "testing"
|
|
func TestX(t *testing.T) {}`)
|
|
|
|
tg.tempFile("pkgs/a/a.go", `package a`)
|
|
tg.tempFile("pkgs/a/a_test.go", `package a_test
|
|
import "testing"
|
|
func TestA(t *testing.T) {}`)
|
|
|
|
tg.cd(tg.path("pkgs"))
|
|
tg.run("build", "./...")
|
|
tg.run("test", "./...")
|
|
tg.run("list", "./...")
|
|
tg.grepStdout("pkgs$", "expected package not listed")
|
|
tg.grepStdout("pkgs/a", "expected package not listed")
|
|
}
|
|
|
|
// Issue 18975.
|
|
func TestFFLAGS(t *testing.T) {
|
|
if !canCgo {
|
|
t.Skip("skipping because cgo not enabled")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
|
|
tg.tempFile("p/src/p/main.go", `package main
|
|
// #cgo FFLAGS: -no-such-fortran-flag
|
|
import "C"
|
|
func main() {}
|
|
`)
|
|
tg.tempFile("p/src/p/a.f", `! comment`)
|
|
tg.setenv("GOPATH", tg.path("p"))
|
|
|
|
// This should normally fail because we are passing an unknown flag,
|
|
// but issue #19080 points to Fortran compilers that succeed anyhow.
|
|
// To work either way we call doRun directly rather than run or runFail.
|
|
tg.doRun([]string{"build", "-x", "p"})
|
|
|
|
tg.grepStderr("no-such-fortran-flag", `missing expected "-no-such-fortran-flag"`)
|
|
}
|
|
|
|
// Issue 19198.
|
|
// This is really a cmd/link issue but this is a convenient place to test it.
|
|
func TestDuplicateGlobalAsmSymbols(t *testing.T) {
|
|
if runtime.GOARCH != "386" && runtime.GOARCH != "amd64" {
|
|
t.Skipf("skipping test on %s", runtime.GOARCH)
|
|
}
|
|
if !canCgo {
|
|
t.Skip("skipping because cgo not enabled")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
|
|
asm := `
|
|
#include "textflag.h"
|
|
|
|
DATA sym<>+0x0(SB)/8,$0
|
|
GLOBL sym<>(SB),(NOPTR+RODATA),$8
|
|
|
|
TEXT ·Data(SB),NOSPLIT,$0
|
|
MOVB sym<>(SB), AX
|
|
MOVB AX, ret+0(FP)
|
|
RET
|
|
`
|
|
tg.tempFile("go/src/a/a.s", asm)
|
|
tg.tempFile("go/src/a/a.go", `package a; func Data() uint8`)
|
|
tg.tempFile("go/src/b/b.s", asm)
|
|
tg.tempFile("go/src/b/b.go", `package b; func Data() uint8`)
|
|
tg.tempFile("go/src/p/p.go", `
|
|
package main
|
|
import "a"
|
|
import "b"
|
|
import "C"
|
|
func main() {
|
|
_ = a.Data() + b.Data()
|
|
}
|
|
`)
|
|
tg.setenv("GOPATH", tg.path("go"))
|
|
exe := filepath.Join(tg.tempdir, "p.exe")
|
|
tg.creatingTemp(exe)
|
|
tg.run("build", "-o", exe, "p")
|
|
}
|
|
|
|
func TestBuildTagsNoComma(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.makeTempdir()
|
|
tg.setenv("GOPATH", tg.path("go"))
|
|
tg.run("install", "-tags", "tag1 tag2", "math")
|
|
tg.runFail("install", "-tags", "tag1,tag2", "math")
|
|
tg.grepBoth("space-separated list contains comma", "-tags with a comma-separated list didn't error")
|
|
tg.runFail("build", "-tags", "tag1,tag2", "math")
|
|
tg.grepBoth("space-separated list contains comma", "-tags with a comma-separated list didn't error")
|
|
}
|
|
|
|
func copyFile(src, dst string, perm os.FileMode) error {
|
|
sf, err := os.Open(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer sf.Close()
|
|
|
|
df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = io.Copy(df, sf)
|
|
err2 := df.Close()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return err2
|
|
}
|
|
|
|
func TestExecutableGOROOT(t *testing.T) {
|
|
if runtime.GOOS == "openbsd" {
|
|
t.Skipf("test case does not work on %s, missing os.Executable", runtime.GOOS)
|
|
}
|
|
|
|
// Env with no GOROOT.
|
|
var env []string
|
|
for _, e := range os.Environ() {
|
|
if !strings.HasPrefix(e, "GOROOT=") {
|
|
env = append(env, e)
|
|
}
|
|
}
|
|
|
|
check := func(t *testing.T, exe, want string) {
|
|
cmd := exec.Command(exe, "env", "GOROOT")
|
|
cmd.Env = env
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("%s env GOROOT: %v, %s", exe, err, out)
|
|
}
|
|
goroot, err := filepath.EvalSymlinks(strings.TrimSpace(string(out)))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want, err = filepath.EvalSymlinks(want)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.EqualFold(goroot, want) {
|
|
t.Errorf("go env GOROOT:\nhave %s\nwant %s", goroot, want)
|
|
} else {
|
|
t.Logf("go env GOROOT: %s", goroot)
|
|
}
|
|
}
|
|
|
|
// Note: Must not call tg methods inside subtests: tg is attached to outer t.
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
|
|
tg.makeTempdir()
|
|
tg.tempDir("new/bin")
|
|
newGoTool := tg.path("new/bin/go" + exeSuffix)
|
|
tg.must(copyFile(tg.goTool(), newGoTool, 0775))
|
|
newRoot := tg.path("new")
|
|
|
|
t.Run("RelocatedExe", func(t *testing.T) {
|
|
t.Skip("TODO: skipping known broken test; see golang.org/issue/20284")
|
|
|
|
// Should fall back to default location in binary.
|
|
// No way to dig out other than look at source code.
|
|
data, err := ioutil.ReadFile("../../runtime/internal/sys/zversion.go")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
m := regexp.MustCompile("const DefaultGoroot = `([^`]+)`").FindStringSubmatch(string(data))
|
|
if m == nil {
|
|
t.Fatal("cannot find DefaultGoroot in ../../runtime/internal/sys/zversion.go")
|
|
}
|
|
check(t, newGoTool, m[1])
|
|
})
|
|
|
|
// If the binary is sitting in a bin dir next to ../pkg/tool, that counts as a GOROOT,
|
|
// so it should find the new tree.
|
|
tg.tempDir("new/pkg/tool")
|
|
t.Run("RelocatedTree", func(t *testing.T) {
|
|
check(t, newGoTool, newRoot)
|
|
})
|
|
|
|
tg.tempDir("other/bin")
|
|
symGoTool := tg.path("other/bin/go" + exeSuffix)
|
|
|
|
// Symlink into go tree should still find go tree.
|
|
t.Run("SymlinkedExe", func(t *testing.T) {
|
|
testenv.MustHaveSymlink(t)
|
|
if err := os.Symlink(newGoTool, symGoTool); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
check(t, symGoTool, newRoot)
|
|
})
|
|
}
|
|
|
|
func TestNeedVersion(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.tempFile("goversion.go", `package main; func main() {}`)
|
|
path := tg.path("goversion.go")
|
|
tg.setenv("TESTGO_VERSION", "go1.testgo")
|
|
tg.runFail("run", path)
|
|
tg.grepStderr("compile", "does not match go tool version")
|
|
}
|
|
|
|
// Test that user can override default code generation flags.
|
|
func TestUserOverrideFlags(t *testing.T) {
|
|
if !canCgo {
|
|
t.Skip("skipping because cgo not enabled")
|
|
}
|
|
if runtime.GOOS != "linux" {
|
|
// We are testing platform-independent code, so it's
|
|
// OK to skip cases that work differently.
|
|
t.Skipf("skipping on %s because test only works if c-archive implies -shared", runtime.GOOS)
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.parallel()
|
|
tg.tempFile("override.go", `package main
|
|
|
|
import "C"
|
|
|
|
//export GoFunc
|
|
func GoFunc() {}
|
|
|
|
func main() {}`)
|
|
tg.creatingTemp("override.a")
|
|
tg.creatingTemp("override.h")
|
|
tg.run("build", "-x", "-buildmode=c-archive", "-gcflags=-shared=false", tg.path("override.go"))
|
|
tg.grepStderr("compile .*-shared .*-shared=false", "user can not override code generation flag")
|
|
}
|
|
|
|
func TestCgoFlagContainsSpace(t *testing.T) {
|
|
if !canCgo {
|
|
t.Skip("skipping because cgo not enabled")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
|
|
ccName := filepath.Base(testCC)
|
|
|
|
tg.tempFile(fmt.Sprintf("src/%s/main.go", ccName), fmt.Sprintf(`package main
|
|
import (
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
)
|
|
|
|
func main() {
|
|
cmd := exec.Command(%q, os.Args[1:]...)
|
|
cmd.Stdin = os.Stdin
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
err := cmd.Run()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
if os.Args[len(os.Args)-1] == "trivial.c" {
|
|
return
|
|
}
|
|
|
|
var success bool
|
|
for _, arg := range os.Args {
|
|
switch {
|
|
case strings.Contains(arg, "c flags"):
|
|
if success {
|
|
panic("duplicate CFLAGS")
|
|
}
|
|
success = true
|
|
case strings.Contains(arg, "ld flags"):
|
|
if success {
|
|
panic("duplicate LDFLAGS")
|
|
}
|
|
success = true
|
|
}
|
|
}
|
|
if !success {
|
|
panic("args should contains '-Ic flags' or '-Lld flags'")
|
|
}
|
|
}
|
|
`, testCC))
|
|
tg.cd(tg.path(fmt.Sprintf("src/%s", ccName)))
|
|
tg.run("build")
|
|
tg.setenv("CC", tg.path(fmt.Sprintf("src/%s/%s", ccName, ccName)))
|
|
|
|
tg.tempFile("src/cgo/main.go", `package main
|
|
// #cgo CFLAGS: -I"c flags"
|
|
// #cgo LDFLAGS: -L"ld flags"
|
|
import "C"
|
|
func main() {}
|
|
`)
|
|
tg.cd(tg.path("src/cgo"))
|
|
tg.run("run", "main.go")
|
|
}
|
|
|
|
// Issue #20435.
|
|
func TestGoTestRaceCoverModeFailures(t *testing.T) {
|
|
if !canRace {
|
|
t.Skip("skipping because race detector not supported")
|
|
}
|
|
|
|
tg := testgo(t)
|
|
tg.parallel()
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
|
|
tg.run("test", "testrace")
|
|
|
|
tg.runFail("test", "-race", "-covermode=set", "testrace")
|
|
tg.grepStderr(`-covermode must be "atomic", not "set", when -race is enabled`, "-race -covermode=set was allowed")
|
|
tg.grepBothNot("PASS", "something passed")
|
|
}
|
|
|
|
// Issue 9737: verify that GOARM and GO386 affect the computed build ID.
|
|
func TestBuildIDContainsArchModeEnv(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping in short mode")
|
|
}
|
|
|
|
var tg *testgoData
|
|
testWith := func(before, after func()) func(*testing.T) {
|
|
return func(t *testing.T) {
|
|
tg = testgo(t)
|
|
defer tg.cleanup()
|
|
tg.tempFile("src/mycmd/x.go", `package main
|
|
func main() {}`)
|
|
tg.setenv("GOPATH", tg.path("."))
|
|
|
|
tg.cd(tg.path("src/mycmd"))
|
|
tg.setenv("GOOS", "linux")
|
|
before()
|
|
tg.run("install", "mycmd")
|
|
after()
|
|
tg.wantStale("mycmd", "build ID mismatch", "should be stale after environment variable change")
|
|
}
|
|
}
|
|
|
|
t.Run("386", testWith(func() {
|
|
tg.setenv("GOARCH", "386")
|
|
tg.setenv("GO386", "387")
|
|
}, func() {
|
|
tg.setenv("GO386", "sse2")
|
|
}))
|
|
|
|
t.Run("arm", testWith(func() {
|
|
tg.setenv("GOARCH", "arm")
|
|
tg.setenv("GOARM", "5")
|
|
}, func() {
|
|
tg.setenv("GOARM", "7")
|
|
}))
|
|
}
|
|
|
|
func TestTestRegexps(t *testing.T) {
|
|
tg := testgo(t)
|
|
defer tg.cleanup()
|
|
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
|
tg.run("test", "-cpu=1", "-run=X/Y", "-bench=X/Y", "-count=2", "-v", "testregexp")
|
|
var lines []string
|
|
for _, line := range strings.SplitAfter(tg.getStdout(), "\n") {
|
|
if strings.Contains(line, "=== RUN") || strings.Contains(line, "--- BENCH") || strings.Contains(line, "LOG") {
|
|
lines = append(lines, line)
|
|
}
|
|
}
|
|
|
|
// Important parts:
|
|
// TestX is run, twice
|
|
// TestX/Y is run, twice
|
|
// TestXX is run, twice
|
|
// TestZ is not run
|
|
// BenchmarkX is run but only with N=1, once
|
|
// BenchmarkXX is run but only with N=1, once
|
|
// BenchmarkX/Y is run in full, twice
|
|
want := `=== RUN TestX
|
|
=== RUN TestX/Y
|
|
x_test.go:6: LOG: X running
|
|
x_test.go:8: LOG: Y running
|
|
=== RUN TestXX
|
|
z_test.go:10: LOG: XX running
|
|
=== RUN TestX
|
|
=== RUN TestX/Y
|
|
x_test.go:6: LOG: X running
|
|
x_test.go:8: LOG: Y running
|
|
=== RUN TestXX
|
|
z_test.go:10: LOG: XX running
|
|
--- BENCH: BenchmarkX/Y
|
|
x_test.go:15: LOG: Y running N=1
|
|
x_test.go:15: LOG: Y running N=100
|
|
x_test.go:15: LOG: Y running N=10000
|
|
x_test.go:15: LOG: Y running N=1000000
|
|
x_test.go:15: LOG: Y running N=100000000
|
|
x_test.go:15: LOG: Y running N=2000000000
|
|
--- BENCH: BenchmarkX/Y
|
|
x_test.go:15: LOG: Y running N=1
|
|
x_test.go:15: LOG: Y running N=100
|
|
x_test.go:15: LOG: Y running N=10000
|
|
x_test.go:15: LOG: Y running N=1000000
|
|
x_test.go:15: LOG: Y running N=100000000
|
|
x_test.go:15: LOG: Y running N=2000000000
|
|
--- BENCH: BenchmarkX
|
|
x_test.go:13: LOG: X running N=1
|
|
--- BENCH: BenchmarkXX
|
|
z_test.go:18: LOG: XX running N=1
|
|
`
|
|
|
|
have := strings.Join(lines, "")
|
|
if have != want {
|
|
t.Errorf("reduced output:<<<\n%s>>> want:<<<\n%s>>>", have, want)
|
|
}
|
|
}
|
|
|
|
func TestListTests(t *testing.T) {
|
|
var tg *testgoData
|
|
testWith := func(listName, expected string) func(*testing.T) {
|
|
return func(t *testing.T) {
|
|
tg = testgo(t)
|
|
defer tg.cleanup()
|
|
tg.run("test", "./testdata/src/testlist/...", fmt.Sprintf("-list=%s", listName))
|
|
tg.grepStdout(expected, fmt.Sprintf("-test.list=%s returned %q, expected %s", listName, tg.getStdout(), expected))
|
|
}
|
|
}
|
|
|
|
t.Run("Test", testWith("Test", "TestSimple"))
|
|
t.Run("Bench", testWith("Benchmark", "BenchmarkSimple"))
|
|
t.Run("Example1", testWith("Example", "ExampleSimple"))
|
|
t.Run("Example2", testWith("Example", "ExampleWithEmptyOutput"))
|
|
}
|