github.com/aca02djr/gb@v0.4.1/cmd/gb/gb_test.go (about)

     1  // Copyright 2015 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main_test
     6  
     7  // gb functional tests adapted from src/cmd/go/go_test.go
     8  
     9  import (
    10  	"bytes"
    11  	"flag"
    12  	"fmt"
    13  	"go/format"
    14  	"io"
    15  	"io/ioutil"
    16  	"log"
    17  	"os"
    18  	"os/exec"
    19  	"path/filepath"
    20  	"regexp"
    21  	"runtime"
    22  	"strings"
    23  	"testing"
    24  )
    25  
    26  var (
    27  	canRun  = true  // whether we can run go or ./testgb
    28  	canRace = false // whether we can run the race detector
    29  
    30  	exeSuffix string // ".exe" on Windows
    31  
    32  	testgb string = "testgb"
    33  )
    34  
    35  func init() {
    36  	switch runtime.GOOS {
    37  	case "android", "nacl":
    38  		canRun = false
    39  	case "darwin":
    40  		switch runtime.GOARCH {
    41  		case "arm", "arm64":
    42  			canRun = false
    43  		}
    44  	}
    45  
    46  	switch runtime.GOOS {
    47  	case "windows":
    48  		exeSuffix = ".exe"
    49  	}
    50  	testgb += exeSuffix
    51  }
    52  
    53  // The TestMain function creates a gb command for testing purposes and
    54  // deletes it after the tests have been run.
    55  func TestMain(m *testing.M) {
    56  	flag.Parse()
    57  
    58  	if canRun {
    59  		dir, err := ioutil.TempDir("", "testgb")
    60  		if err != nil {
    61  			fmt.Fprintf(os.Stderr, "cannot create temporary directory: %v", err)
    62  			os.Exit(2)
    63  		}
    64  		testgb = filepath.Join(dir, testgb)
    65  		locations := [][]string{
    66  			[]string{runtime.GOROOT(), "bin", "go"},
    67  			[]string{runtime.GOROOT(), "..", "bin", "go"},
    68  			[]string{runtime.GOROOT(), "..", "..", "bin", "go"},
    69  		}
    70  		ok := false
    71  		for _, loc := range locations {
    72  			out, err := exec.Command(filepath.Join(loc...), "build", "-o", testgb).CombinedOutput()
    73  			if err == nil {
    74  				ok = true
    75  				break
    76  			}
    77  			log.Printf("building testgb failed: %v\n%s", err, out)
    78  		}
    79  		if !ok {
    80  			os.Exit(2)
    81  		}
    82  		_, err = os.Stat(filepath.Join(runtime.GOROOT(), "pkg", fmt.Sprintf("%s_%s_race", runtime.GOOS, runtime.GOARCH), "runtime.a"))
    83  		switch {
    84  		case os.IsNotExist(err):
    85  			log.Printf("go installation at %s is missing race support", runtime.GOROOT())
    86  		case runtime.GOARCH == "amd64":
    87  			canRace = runtime.GOOS == "linux" || runtime.GOOS == "freebsd" || runtime.GOOS == "windows" || runtime.GOOS == "darwin"
    88  		}
    89  	}
    90  
    91  	// Don't let these environment variables confuse the test.
    92  	os.Unsetenv("GOBIN")
    93  	os.Unsetenv("GOPATH")
    94  	os.Unsetenv("DEBUG")
    95  
    96  	r := m.Run()
    97  	os.Exit(r)
    98  }
    99  
   100  // T manage a single run of the testgb binary.
   101  type T struct {
   102  	*testing.T
   103  	temps          []string
   104  	wd             string
   105  	env            []string
   106  	tempdir        string
   107  	ran            bool
   108  	stdin          io.Reader
   109  	stdout, stderr bytes.Buffer
   110  }
   111  
   112  // must gives a fatal error if err is not nil.
   113  func (t *T) must(err error) {
   114  	if err != nil {
   115  		t.Fatal(err)
   116  	}
   117  }
   118  
   119  // check gives a test non-fatal error if err is not nil.
   120  func (t *T) check(err error) {
   121  	if err != nil {
   122  		t.Error(err)
   123  	}
   124  }
   125  
   126  // pwd returns the current directory.
   127  func (t *T) pwd() string {
   128  	wd, err := os.Getwd()
   129  	if err != nil {
   130  		t.Fatalf("could not get working directory: %v", err)
   131  	}
   132  	return wd
   133  }
   134  
   135  // cd changes the current directory to the named directory. extra args
   136  // are passed through filepath.Join before cd.
   137  func (t *T) cd(dir string, extra ...string) {
   138  	if t.wd == "" {
   139  		t.wd = t.pwd()
   140  	}
   141  	v := append([]string{dir}, extra...)
   142  	dir = filepath.Join(v...)
   143  	abs, err := filepath.Abs(dir)
   144  	t.must(os.Chdir(dir))
   145  	if err == nil {
   146  		t.setenv("PWD", abs)
   147  	}
   148  }
   149  
   150  // setenv sets an environment variable to use when running the test go
   151  // command.
   152  func (t *T) setenv(name, val string) {
   153  	t.unsetenv(name)
   154  	t.env = append(t.env, name+"="+val)
   155  }
   156  
   157  // unsetenv removes an environment variable.
   158  func (t *T) unsetenv(name string) {
   159  	if t.env == nil {
   160  		t.env = append([]string(nil), os.Environ()...)
   161  	}
   162  	for i, v := range t.env {
   163  		if strings.HasPrefix(v, name+"=") {
   164  			t.env = append(t.env[:i], t.env[i+1:]...)
   165  			break
   166  		}
   167  	}
   168  }
   169  
   170  // doRun runs the test go command, recording stdout and stderr and
   171  // returning exit status.
   172  func (t *T) doRun(args []string) error {
   173  	if !canRun {
   174  		t.Fatal("T.doRun called but canRun false")
   175  	}
   176  	t.Logf("running %v %v", testgb, args)
   177  	cmd := exec.Command(testgb, args...)
   178  	t.stdout.Reset()
   179  	t.stderr.Reset()
   180  	cmd.Stdin = t.stdin
   181  	cmd.Stdout = &t.stdout
   182  	cmd.Stderr = &t.stderr
   183  	cmd.Env = t.env
   184  	status := cmd.Run()
   185  	if t.stdout.Len() > 0 {
   186  		t.Log("standard output:")
   187  		t.Log(t.stdout.String())
   188  	}
   189  	if t.stderr.Len() > 0 {
   190  		t.Log("standard error:")
   191  		t.Log(t.stderr.String())
   192  	}
   193  	t.ran = true
   194  	return status
   195  }
   196  
   197  // run runs the test go command, and expects it to succeed.
   198  func (t *T) run(args ...string) {
   199  	if status := t.doRun(args); status != nil {
   200  		t.Logf("gb %v failed unexpectedly: %v", args, status)
   201  		t.FailNow()
   202  	}
   203  }
   204  
   205  // runFail runs the test go command, and expects it to fail.
   206  func (t *T) runFail(args ...string) {
   207  	if status := t.doRun(args); status == nil {
   208  		t.Fatal(testgb, "succeeded unexpectedly")
   209  	} else {
   210  		t.Log(testgb, "failed as expected:", status)
   211  	}
   212  }
   213  
   214  // getStdout returns standard output of the testgb run as a string.
   215  func (t *T) getStdout() string {
   216  	if !t.ran {
   217  		t.Fatal("internal testsuite error: stdout called before run")
   218  	}
   219  	return t.stdout.String()
   220  }
   221  
   222  // getStderr returns standard error of the testgb run as a string.
   223  func (t *T) getStderr() string {
   224  	if !t.ran {
   225  		t.Fatal("internal testsuite error: stdout called before run")
   226  	}
   227  	return t.stderr.String()
   228  }
   229  
   230  // doGrepMatch looks for a regular expression in a buffer, and returns
   231  // whether it is found.  The regular expression is matched against
   232  // each line separately, as with the grep command.
   233  func (t *T) doGrepMatch(match string, b *bytes.Buffer) bool {
   234  	if !t.ran {
   235  		t.Fatal("internal testsuite error: grep called before run")
   236  	}
   237  	re := regexp.MustCompile(match)
   238  	for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) {
   239  		if re.Match(ln) {
   240  			return true
   241  		}
   242  	}
   243  	return false
   244  }
   245  
   246  // doGrep looks for a regular expression in a buffer and fails if it
   247  // is not found.  The name argument is the name of the output we are
   248  // searching, "output" or "error".  The msg argument is logged on
   249  // failure.
   250  func (t *T) doGrep(match string, b *bytes.Buffer, name, msg string) {
   251  	if !t.doGrepMatch(match, b) {
   252  		t.Log(msg)
   253  		t.Logf("pattern %v not found in standard %s", match, name)
   254  		t.FailNow()
   255  	}
   256  }
   257  
   258  // grepStdout looks for a regular expression in the test run's
   259  // standard output and fails, logging msg, if it is not found.
   260  func (t *T) grepStdout(match, msg string) {
   261  	t.doGrep(match, &t.stdout, "output", msg)
   262  }
   263  
   264  // grepStderr looks for a regular expression in the test run's
   265  // standard error and fails, logging msg, if it is not found.
   266  func (t *T) grepStderr(match, msg string) {
   267  	t.doGrep(match, &t.stderr, "error", msg)
   268  }
   269  
   270  // grepBoth looks for a regular expression in the test run's standard
   271  // output or stand error and fails, logging msg, if it is not found.
   272  func (t *T) grepBoth(match, msg string) {
   273  	if !t.doGrepMatch(match, &t.stdout) && !t.doGrepMatch(match, &t.stderr) {
   274  		t.Log(msg)
   275  		t.Logf("pattern %v not found in standard output or standard error", match)
   276  		t.FailNow()
   277  	}
   278  }
   279  
   280  // doGrepNot looks for a regular expression in a buffer and fails if
   281  // it is found.  The name and msg arguments are as for doGrep.
   282  func (t *T) doGrepNot(match string, b *bytes.Buffer, name, msg string) {
   283  	if t.doGrepMatch(match, b) {
   284  		t.Log(msg)
   285  		t.Logf("pattern %v found unexpectedly in standard %s", match, name)
   286  		t.FailNow()
   287  	}
   288  }
   289  
   290  // grepStdoutNot looks for a regular expression in the test run's
   291  // standard output and fails, logging msg, if it is found.
   292  func (t *T) grepStdoutNot(match, msg string) {
   293  	t.doGrepNot(match, &t.stdout, "output", msg)
   294  }
   295  
   296  // grepStderrNot looks for a regular expression in the test run's
   297  // standard error and fails, logging msg, if it is found.
   298  func (t *T) grepStderrNot(match, msg string) {
   299  	t.doGrepNot(match, &t.stderr, "error", msg)
   300  }
   301  
   302  // grepBothNot looks for a regular expression in the test run's
   303  // standard output or stand error and fails, logging msg, if it is
   304  // found.
   305  func (t *T) grepBothNot(match, msg string) {
   306  	if t.doGrepMatch(match, &t.stdout) || t.doGrepMatch(match, &t.stderr) {
   307  		t.Log(msg)
   308  		t.Fatalf("pattern %v found unexpectedly in standard output or standard error", match)
   309  	}
   310  }
   311  
   312  // doGrepCount counts the number of times a regexp is seen in a buffer.
   313  func (t *T) doGrepCount(match string, b *bytes.Buffer) int {
   314  	if !t.ran {
   315  		t.Fatal("internal testsuite error: doGrepCount called before run")
   316  	}
   317  	re := regexp.MustCompile(match)
   318  	c := 0
   319  	for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) {
   320  		if re.Match(ln) {
   321  			c++
   322  		}
   323  	}
   324  	return c
   325  }
   326  
   327  // grepCountStdout returns the number of times a regexp is seen in
   328  // standard output.
   329  func (t *T) grepCountStdout(match string) int {
   330  	return t.doGrepCount(match, &t.stdout)
   331  }
   332  
   333  // grepCountStderr returns the number of times a regexp is seen in
   334  // standard error.
   335  func (t *T) grepCountStderr(match string) int {
   336  	return t.doGrepCount(match, &t.stderr)
   337  }
   338  
   339  // grepCountBoth returns the number of times a regexp is seen in both
   340  // standard output and standard error.
   341  func (t *T) grepCountBoth(match string) int {
   342  	return t.doGrepCount(match, &t.stdout) + t.doGrepCount(match, &t.stderr)
   343  }
   344  
   345  // creatingTemp records that the test plans to create a temporary file
   346  // or directory.  If the file or directory exists already, it will be
   347  // removed.  When the test completes, the file or directory will be
   348  // removed if it exists.
   349  func (t *T) creatingTemp(path string) {
   350  	if filepath.IsAbs(path) && !strings.HasPrefix(path, t.tempdir) {
   351  		t.Fatal("internal testsuite error: creatingTemp(%q) with absolute path not in temporary directory", path)
   352  	}
   353  	// If we have changed the working directory, make sure we have
   354  	// an absolute path, because we are going to change directory
   355  	// back before we remove the temporary.
   356  	if t.wd != "" && !filepath.IsAbs(path) {
   357  		path = filepath.Join(t.pwd(), path)
   358  	}
   359  	t.must(os.RemoveAll(path))
   360  	t.temps = append(t.temps, path)
   361  }
   362  
   363  // makeTempdir makes a temporary directory for a run of testgb.  If
   364  // the temporary directory was already created, this does nothing.
   365  func (t *T) makeTempdir() {
   366  	if t.tempdir == "" {
   367  		var err error
   368  		t.tempdir, err = ioutil.TempDir("", "testgb")
   369  		t.must(err)
   370  		t.tempdir, err = filepath.EvalSymlinks(t.tempdir) // resolve OSX's stupid symlinked /tmp
   371  		t.must(err)
   372  	}
   373  }
   374  
   375  // tempFile adds a temporary file for a run of testgb.
   376  func (t *T) tempFile(path, contents string) {
   377  	t.makeTempdir()
   378  	t.must(os.MkdirAll(filepath.Join(t.tempdir, filepath.Dir(path)), 0755))
   379  	bytes := []byte(contents)
   380  	if strings.HasSuffix(path, ".go") {
   381  		formatted, err := format.Source(bytes)
   382  		if err == nil {
   383  			bytes = formatted
   384  		}
   385  	}
   386  	t.must(ioutil.WriteFile(filepath.Join(t.tempdir, path), bytes, 0644))
   387  }
   388  
   389  // tempDir adds a temporary directory for a run of testgb.
   390  func (t *T) tempDir(path string) string {
   391  	t.makeTempdir()
   392  	path = filepath.Join(t.tempdir, path)
   393  	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
   394  		t.Fatal(err)
   395  	}
   396  	return path
   397  }
   398  
   399  // symlink adds a symlink from src to dst.
   400  func (t *T) symlink(src, dst string) string {
   401  	t.makeTempdir()
   402  	src = filepath.Join(t.tempdir, src)
   403  	dst = filepath.Join(t.tempdir, dst)
   404  	t.must(os.Symlink(src, dst))
   405  	return dst
   406  }
   407  
   408  // path returns the absolute pathname to file with the temporary
   409  // directory.
   410  func (t *T) path(names ...string) string {
   411  	if t.tempdir == "" {
   412  		t.Fatalf("internal testsuite error: path(%q) with no tempdir", filepath.Join(names...))
   413  	}
   414  	if len(names) == 0 || names[0] == "." {
   415  		return t.tempdir
   416  	}
   417  	return filepath.Join(append([]string{t.tempdir}, names...)...)
   418  }
   419  
   420  // mustExist fails if path does not exists.
   421  func (t *T) mustExist(path string) {
   422  	if _, err := os.Stat(path); err != nil {
   423  		t.Fatalf("%s does not exist (%v)", path, err)
   424  	}
   425  }
   426  
   427  // mustNotExist fails if path exists.
   428  func (t *T) mustNotExist(path string) {
   429  	if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) {
   430  		t.Fatalf("%s exists but should not (%v)", path, err)
   431  	}
   432  }
   433  
   434  // mustBeEmpty fails if root is not a directory or is not empty.
   435  func (t *T) mustBeEmpty(root string) {
   436  	fi, err := os.Stat(root)
   437  	if err != nil {
   438  		t.Fatalf("failed to stat: %s: %v", root, err)
   439  	}
   440  	if !fi.IsDir() {
   441  		t.Fatalf("%s exists but is not a directory", root)
   442  	}
   443  	var found []string
   444  	fn := func(path string, info os.FileInfo, err error) error {
   445  		if path == root {
   446  			return nil
   447  		}
   448  		if err != nil {
   449  			t.Fatalf("error during walk at %s: %v", path, err)
   450  		}
   451  		found = append(found, path)
   452  		return nil
   453  	}
   454  	err = filepath.Walk(root, fn)
   455  	if len(found) > 0 {
   456  		t.Fatalf("expected %s to be empty, found %s", root, found)
   457  	}
   458  }
   459  
   460  // wantExecutable fails with msg if path is not executable.
   461  func (t *T) wantExecutable(path, msg string) {
   462  	if st, err := os.Stat(path); err != nil {
   463  		if !os.IsNotExist(err) {
   464  			t.Log(err)
   465  		}
   466  		t.Fatal(msg)
   467  	} else {
   468  		if runtime.GOOS != "windows" && st.Mode()&0111 == 0 {
   469  			t.Fatalf("binary %s exists but is not executable", path)
   470  		}
   471  	}
   472  }
   473  
   474  // wantArchive fails if path is not an archive.
   475  func (t *T) wantArchive(path string) {
   476  	f, err := os.Open(path)
   477  	if err != nil {
   478  		t.Fatal(err)
   479  	}
   480  	buf := make([]byte, 100)
   481  	io.ReadFull(f, buf)
   482  	f.Close()
   483  	if !bytes.HasPrefix(buf, []byte("!<arch>\n")) {
   484  		t.Fatalf("file %s exists but is not an archive", path)
   485  	}
   486  }
   487  
   488  // isStale returns whether pkg is stale.
   489  func (t *T) isStale(pkg string) bool {
   490  	t.run("list", "-f", "{{.Stale}}", pkg)
   491  	switch v := strings.TrimSpace(t.getStdout()); v {
   492  	case "true":
   493  		return true
   494  	case "false":
   495  		return false
   496  	default:
   497  		t.Fatalf("unexpected output checking staleness of package %v: %v", pkg, v)
   498  		panic("unreachable")
   499  	}
   500  }
   501  
   502  // wantStale fails with msg if pkg is not stale.
   503  func (t *T) wantStale(pkg, msg string) {
   504  	if !t.isStale(pkg) {
   505  		t.Fatal(msg)
   506  	}
   507  }
   508  
   509  // wantNotStale fails with msg if pkg is stale.
   510  func (t *T) wantNotStale(pkg, msg string) {
   511  	if t.isStale(pkg) {
   512  		t.Fatal(msg)
   513  	}
   514  }
   515  
   516  // cleanup cleans up a test that runs testgb.
   517  func (t *T) cleanup() {
   518  	if t.wd != "" {
   519  		if err := os.Chdir(t.wd); err != nil {
   520  			// We are unlikely to be able to continue.
   521  			fmt.Fprintln(os.Stderr, "could not restore working directory, crashing:", err)
   522  			os.Exit(2)
   523  		}
   524  	}
   525  	for _, path := range t.temps {
   526  		t.check(os.RemoveAll(path))
   527  	}
   528  	if t.tempdir != "" {
   529  		t.check(os.RemoveAll(t.tempdir))
   530  	}
   531  }
   532  
   533  // resetReadOnlyFlagAll resets windows read-only flag
   534  // set on path and any children it contains.
   535  // The flag is set by git and has to be removed.
   536  // os.Remove refuses to remove files with read-only flag set.
   537  func (t *T) resetReadOnlyFlagAll(path string) {
   538  	fi, err := os.Stat(path)
   539  	if err != nil {
   540  		t.Fatalf("resetReadOnlyFlagAll(%q) failed: %v", path, err)
   541  	}
   542  	if !fi.IsDir() {
   543  		err := os.Chmod(path, 0666)
   544  		if err != nil {
   545  			t.Fatalf("resetReadOnlyFlagAll(%q) failed: %v", path, err)
   546  		}
   547  	}
   548  	fd, err := os.Open(path)
   549  	if err != nil {
   550  		t.Fatalf("resetReadOnlyFlagAll(%q) failed: %v", path, err)
   551  	}
   552  	defer fd.Close()
   553  	names, _ := fd.Readdirnames(-1)
   554  	for _, name := range names {
   555  		t.resetReadOnlyFlagAll(path + string(filepath.Separator) + name)
   556  	}
   557  }
   558  
   559  // Invoking plain "gb" should print usage to stderr and exit with 2.
   560  func TestNoArguments(t *testing.T) {
   561  	gb := T{T: t}
   562  	defer gb.cleanup()
   563  
   564  	gb.tempDir("src")
   565  	gb.cd(gb.tempdir)
   566  	gb.runFail()
   567  	gb.grepStderr("^Usage:", `expected "Usage: ..."`)
   568  }
   569  
   570  // Invoking plain "gb" outside a project should print to stderr and exit with 2.
   571  func TestOutsideProject(t *testing.T) {
   572  	gb := T{T: t}
   573  	defer gb.cleanup()
   574  
   575  	gb.tempDir("x")
   576  	gb.cd(gb.tempdir, "x")
   577  	gb.runFail()
   578  	gb.grepStderr("^Usage:", `expected "Usage: ..."`)
   579  }
   580  
   581  // Invoking gb outside a project should print to stderr and exit with 2.
   582  func TestInfoOutsideProject(t *testing.T) {
   583  	gb := T{T: t}
   584  	defer gb.cleanup()
   585  
   586  	gb.tempDir("x")
   587  	gb.cd(gb.tempdir, "x")
   588  	gb.runFail("info")
   589  	regex := `FATAL: unable to construct context: could not locate project root: could not find project root in "` +
   590  		regexp.QuoteMeta(filepath.Join(gb.tempdir, "x")) +
   591  		`" or its parents`
   592  	gb.grepStderr(regex, "expected FATAL")
   593  }
   594  
   595  // Invoking gb outside a project with -R should succeed.
   596  func TestInfoWithMinusR(t *testing.T) {
   597  	gb := T{T: t}
   598  	defer gb.cleanup()
   599  
   600  	gb.tempDir("x")
   601  	gb.tempDir("y")
   602  	gb.tempDir("y/src")
   603  	gb.cd(gb.tempdir, "x")
   604  	gb.run("info", "-R", filepath.Join(gb.tempdir, "y"))
   605  	gb.grepStdout(`^GB_PROJECT_DIR="`+regexp.QuoteMeta(filepath.Join(gb.tempdir, "y"))+`"$`, "missing GB_PROJECT_DIR")
   606  }
   607  
   608  func TestInfoCmd(t *testing.T) {
   609  	gb := T{T: t}
   610  	defer gb.cleanup()
   611  
   612  	gb.tempDir("src")
   613  	gb.cd(gb.tempdir)
   614  	gb.run("info")
   615  	gb.grepStdout(`^GB_PROJECT_DIR="`+regexp.QuoteMeta(gb.tempdir)+`"$`, "missing GB_PROJECT_DIR")
   616  	gb.grepStdout(`^GB_SRC_PATH="`+regexp.QuoteMeta(filepath.Join(gb.tempdir, "src")+string(filepath.ListSeparator)+filepath.Join(gb.tempdir, "vendor", "src"))+`"$`, "missing GB_SRC_PATH")
   617  	gb.grepStdout(`^GB_PKG_DIR="`+regexp.QuoteMeta(filepath.Join(gb.tempdir, "pkg", runtime.GOOS+"-"+runtime.GOARCH))+`"$`, "missing GB_PKG_DIR")
   618  	gb.grepStdout(`^GB_BIN_SUFFIX="-`+runtime.GOOS+"-"+runtime.GOARCH+`"$`, "missing GB_BIN_SUFFIX")
   619  	gb.grepStdout(`^GB_GOROOT="`+regexp.QuoteMeta(runtime.GOROOT())+`"$`, "missing GB_GOROOT")
   620  }
   621  
   622  func TestInfoWithArgs(t *testing.T) {
   623  	gb := T{T: t}
   624  	defer gb.cleanup()
   625  
   626  	gb.tempDir("src")
   627  	gb.cd(gb.tempdir)
   628  	gb.run("info", "GB_PROJECT_DIR", "GB_MISSING", "GB_GOROOT")
   629  	gb.grepStdout(`^`+regexp.QuoteMeta(gb.tempdir), "missing "+regexp.QuoteMeta(gb.tempdir))
   630  	gb.grepStdout(`^`+regexp.QuoteMeta(runtime.GOROOT()), "missing "+regexp.QuoteMeta(runtime.GOROOT()))
   631  	// second line should be empty
   632  	lines := bytes.Split(gb.stdout.Bytes(), []byte{'\n'})
   633  	if len(lines[1]) != 0 {
   634  		t.Fatal("want 0, got", len(lines[1]))
   635  	}
   636  }
   637  
   638  // Only succeeds if source order is preserved.
   639  func TestSourceFileNameOrderPreserved(t *testing.T) {
   640  	gb := T{T: t}
   641  	defer gb.cleanup()
   642  	gb.tempDir("src")
   643  	gb.tempDir("src/testorder")
   644  	gb.tempFile("src/testorder/example1_test.go", `// Copyright 2013 The Go Authors.  All rights reserved.
   645  // Use of this source code is governed by a BSD-style
   646  // license that can be found in the LICENSE file.
   647  
   648  // Make sure that go test runs Example_Z before Example_A, preserving source order.
   649  
   650  package p
   651  
   652  import "fmt"
   653  
   654  var n int
   655  
   656  func Example_Z() {
   657  	n++
   658  	fmt.Println(n)
   659  	// Output: 1
   660  }
   661  
   662  func Example_A() {
   663  	n++
   664  	fmt.Println(n)
   665  	// Output: 2
   666  }
   667  `)
   668  	gb.tempFile("src/testorder/example2_test.go", `// Copyright 2013 The Go Authors.  All rights reserved.
   669  // Use of this source code is governed by a BSD-style
   670  // license that can be found in the LICENSE file.
   671  
   672  // Make sure that go test runs Example_Y before Example_B, preserving source order.
   673  
   674  package p
   675  
   676  import "fmt"
   677  
   678  func Example_Y() {
   679  	n++
   680  	fmt.Println(n)
   681  	// Output: 3
   682  }
   683  
   684  func Example_B() {
   685  	n++
   686  	fmt.Println(n)
   687  	// Output: 4
   688  }
   689  `)
   690  	gb.cd(gb.tempdir)
   691  	gb.run("test", "testorder")
   692  }
   693  
   694  func TestBuildPackage(t *testing.T) {
   695  	gb := T{T: t}
   696  	defer gb.cleanup()
   697  	gb.tempDir("src")
   698  	gb.tempDir("src/pkg1")
   699  	gb.tempFile("src/pkg1/pkg.go", `package pkg1
   700  import "fmt"
   701  
   702  func helloworld() {
   703  	fmt.Println("hello world!")
   704  }
   705  `)
   706  	gb.cd(gb.tempdir)
   707  	tmpdir := gb.tempDir("tmp")
   708  	gb.setenv("TMP", tmpdir)
   709  	gb.run("build")
   710  	gb.grepStdout("^pkg1$", `expected "pkg1"`)
   711  	gb.mustBeEmpty(tmpdir)
   712  	gb.wantArchive(filepath.Join(gb.tempdir, "pkg", runtime.GOOS+"-"+runtime.GOARCH, "pkg1.a"))
   713  }
   714  
   715  func TestBuildOnlyOnePackage(t *testing.T) {
   716  	gb := T{T: t}
   717  	defer gb.cleanup()
   718  	gb.tempDir("src")
   719  	gb.tempDir("src/pkg1")
   720  	gb.tempFile("src/pkg1/pkg.go", `package pkg1
   721  import "fmt"
   722  
   723  func helloworld() {
   724  	fmt.Println("hello world!")
   725  }
   726  `)
   727  	gb.tempDir("src/pkg2")
   728  	gb.tempFile("src/pkg2/pkg.go", `package pkg2
   729  import "fmt"
   730  
   731  func helloworld() {
   732  	fmt.Println("hello world!")
   733  }
   734  `)
   735  	gb.cd(gb.tempdir)
   736  	tmpdir := gb.tempDir("tmp")
   737  	gb.setenv("TMP", tmpdir)
   738  	gb.run("build", "pkg1")
   739  	gb.grepStdout("^pkg1$", `expected "pkg1"`)
   740  	gb.grepStdoutNot("^pkg2$", `did not expect "pkg2"`)
   741  	gb.mustBeEmpty(tmpdir)
   742  	gb.wantArchive(filepath.Join(gb.tempdir, "pkg", runtime.GOOS+"-"+runtime.GOARCH, "pkg1.a"))
   743  }
   744  
   745  func TestBuildOnlyOnePackageFromWorkingDir(t *testing.T) {
   746  	gb := T{T: t}
   747  	defer gb.cleanup()
   748  	gb.tempDir("src")
   749  	gb.tempDir("src/pkg1")
   750  	gb.tempFile("src/pkg1/pkg.go", `package pkg1
   751  import "fmt"
   752  
   753  func helloworld() {
   754  	fmt.Println("hello world!")
   755  }
   756  `)
   757  	gb.tempDir("src/pkg2")
   758  	gb.tempFile("src/pkg2/pkg.go", `package pkg2
   759  import "fmt"
   760  
   761  func helloworld() {
   762  	fmt.Println("hello world!")
   763  }
   764  `)
   765  	gb.cd(filepath.Join(gb.tempdir, "src", "pkg1"))
   766  	tmpdir := gb.tempDir("tmp")
   767  	gb.setenv("TMP", tmpdir)
   768  	gb.run("build")
   769  	gb.grepStdout("^pkg1$", `expected "pkg1"`)
   770  	gb.grepStdoutNot("^pkg2$", `did not expect "pkg2"`)
   771  	gb.mustBeEmpty(tmpdir)
   772  	gb.wantArchive(filepath.Join(gb.tempdir, "pkg", runtime.GOOS+"-"+runtime.GOARCH, "pkg1.a"))
   773  }
   774  
   775  func TestBuildPackageWrongPackage(t *testing.T) {
   776  	gb := T{T: t}
   777  	defer gb.cleanup()
   778  	gb.tempDir("src")
   779  	gb.tempDir("src/pkg1")
   780  	gb.tempFile("src/pkg1/pkg.go", `package pkg1
   781  import "fmt"
   782  
   783  func helloworld() {
   784  	fmt.Println("hello world!")
   785  }
   786  `)
   787  	gb.cd(gb.tempdir)
   788  	gb.runFail("build", "pkg2")
   789  	gb.grepStderr(`^FATAL: command "build" failed: failed to resolve import path "pkg2": import "pkg2": not found`, "expected FATAL")
   790  }
   791  
   792  func TestBuildPackageNoSource(t *testing.T) {
   793  	gb := T{T: t}
   794  	defer gb.cleanup()
   795  	gb.tempDir("src")
   796  	gb.tempDir("src/pkg1")
   797  	gb.cd(gb.tempdir)
   798  	gb.runFail("build", "pkg1")
   799  	gb.grepStderr(`^FATAL: command "build" failed: failed to resolve import path "pkg1": no buildable Go source files in `+regexp.QuoteMeta(filepath.Join(gb.tempdir, "src", "pkg1")), "expected FATAL")
   800  }
   801  
   802  func TestTestPackageNoTests(t *testing.T) {
   803  	gb := T{T: t}
   804  	defer gb.cleanup()
   805  	gb.tempDir("src")
   806  	gb.tempDir("src/pkg1")
   807  	gb.tempFile("src/pkg1/pkg.go", `package pkg1
   808  import "fmt"
   809  
   810  func helloworld() {
   811  	fmt.Println("hello world!")
   812  }
   813  `)
   814  	gb.cd(gb.tempdir)
   815  	tmpdir := gb.tempDir("tmp")
   816  	gb.setenv("TMP", tmpdir)
   817  	gb.run("test", "pkg1")
   818  	gb.grepStdout("^pkg1$", `expected "pkg1"`)
   819  	gb.mustBeEmpty(tmpdir)
   820  	gb.mustNotExist(filepath.Join(gb.tempdir, "pkg")) // ensure no pkg directory is created
   821  }
   822  
   823  // test that compiling A in test scope compiles B in regular scope
   824  func TestTestDepdenantPackage(t *testing.T) {
   825  	gb := T{T: t}
   826  	defer gb.cleanup()
   827  	gb.tempDir("src")
   828  	gb.tempDir("src/A")
   829  	gb.tempDir("src/B")
   830  	gb.tempFile("src/B/B.go", `package B
   831  const X = 1
   832  `)
   833  	gb.tempFile("src/A/A_test.go", `package A
   834  import "testing"
   835  import "B"
   836  
   837  func TestX(t *testing.T) {
   838  	if B.X != 1 {
   839  		t.Fatal("expected 1, got %d", B.X)
   840  	}
   841  }
   842  `)
   843  	gb.cd(gb.tempdir)
   844  	tmpdir := gb.tempDir("tmp")
   845  	gb.setenv("TMP", tmpdir)
   846  	gb.run("test", "A")
   847  	gb.grepStdout("^B$", `expected "B"`) // output from build action
   848  	gb.grepStdout("^A$", `expected "A"`) // output from test action
   849  	gb.mustBeEmpty(tmpdir)
   850  	gb.wantArchive(filepath.Join(gb.tempdir, "pkg", runtime.GOOS+"-"+runtime.GOARCH, "B.a"))
   851  }
   852  
   853  func TestTestPackageOnlyTests(t *testing.T) {
   854  	gb := T{T: t}
   855  	defer gb.cleanup()
   856  	gb.tempDir("src")
   857  	gb.tempDir("src/pkg1")
   858  	gb.tempFile("src/pkg1/pkg_test.go", `package pkg1
   859  import "testing"
   860  
   861  func TestTest(t *testing.T) {
   862  	t.Log("hello")
   863  }
   864  `)
   865  	gb.cd(gb.tempdir)
   866  	tmpdir := gb.tempDir("tmp")
   867  	gb.setenv("TMP", tmpdir)
   868  	gb.run("test", "pkg1")
   869  	gb.grepStdout("^pkg1$", `expected "pkg1"`)
   870  	gb.mustBeEmpty(tmpdir)
   871  	gb.mustNotExist(filepath.Join(gb.tempdir, "pkg")) // ensure no pkg directory is created
   872  }
   873  
   874  func TestTestPackageFailedToBuild(t *testing.T) {
   875  	gb := T{T: t}
   876  	defer gb.cleanup()
   877  	gb.tempDir("src")
   878  	gb.tempDir("src/pkg1")
   879  	gb.tempFile("src/pkg1/pkg_test.go", `package pkg1
   880  import "testing"
   881  
   882  func TestTest(t *testing.T) {
   883  	t.Log("hello"	// missing parens
   884  }
   885  `)
   886  	gb.cd(gb.tempdir)
   887  	tmpdir := gb.tempDir("tmp")
   888  	gb.setenv("TMP", tmpdir)
   889  	gb.runFail("test")
   890  	gb.grepStderr(`FATAL: command "test" failed:`, "expected FATAL")
   891  	gb.mustBeEmpty(tmpdir)
   892  	gb.mustNotExist(filepath.Join(gb.tempdir, "pkg")) // ensure no pkg directory is created
   893  }
   894  
   895  func TestTestPackageTestFailed(t *testing.T) {
   896  	gb := T{T: t}
   897  	defer gb.cleanup()
   898  	gb.tempDir("src")
   899  	gb.tempDir("src/pkg1")
   900  	gb.tempFile("src/pkg1/pkg_test.go", `package pkg1
   901  import "testing"
   902  
   903  func TestTest(t *testing.T) {
   904  	t.Error("failed")
   905  }
   906  `)
   907  	gb.cd(gb.tempdir)
   908  	tmpdir := gb.tempDir("tmp")
   909  	gb.setenv("TMP", tmpdir)
   910  	gb.runFail("test")
   911  	gb.grepStderr("^# pkg1$", "expected # pkg1")
   912  	gb.grepStdout("pkg_test.go:6: failed", "expected message from test")
   913  	gb.mustBeEmpty(tmpdir)
   914  	gb.mustNotExist(filepath.Join(gb.tempdir, "pkg")) // ensure no pkg directory is created
   915  }
   916  
   917  func TestTestPackageMinusV(t *testing.T) {
   918  	gb := T{T: t}
   919  	defer gb.cleanup()
   920  	gb.tempDir("src")
   921  	gb.tempDir("src/pkg1")
   922  	gb.tempFile("src/pkg1/pkg_test.go", `package pkg1
   923  import "testing"
   924  
   925  func TestTest(t *testing.T) {
   926  	t.Logf("hello")
   927  }
   928  `)
   929  	gb.cd(gb.tempdir)
   930  	tmpdir := gb.tempDir("tmp")
   931  	gb.setenv("TMP", tmpdir)
   932  	gb.run("test", "-v")
   933  	gb.grepStdout("^pkg1$", "expected pkg1")
   934  	gb.grepStdout("pkg_test.go:6: hello", "expected output from test binary")
   935  	gb.grepStdout("PASS", "expected PASS")
   936  	gb.mustBeEmpty(tmpdir)
   937  	gb.mustNotExist(filepath.Join(gb.tempdir, "pkg")) // ensure no pkg directory is created
   938  }
   939  
   940  const issue349 = `package main
   941  
   942  import (
   943      "flag"
   944      "testing"
   945  )
   946  
   947  var name = flag.String("name", "nsf", "what is your name")
   948  
   949  func TestX(t *testing.T) {
   950      if *name != "jardin" {
   951          t.Fatalf("got: '%s', expected: 'jardin'", *name)
   952      }
   953  }
   954  `
   955  
   956  // https://github.com/constabulary/gb/issues/349
   957  func TestTestGbTestPassesUnknownFlags(t *testing.T) {
   958  	gb := T{T: t}
   959  	defer gb.cleanup()
   960  	gb.tempDir("src")
   961  	gb.tempDir("src/projectx")
   962  	gb.tempFile("src/projectx/main_test.go", issue349)
   963  	gb.cd(gb.tempdir)
   964  	tmpdir := gb.tempDir("tmp")
   965  	gb.setenv("TMP", tmpdir)
   966  	gb.run("test", "-name=jardin")
   967  	gb.grepStdout("^projectx$", "expected projectx") // output from gb test
   968  	gb.mustBeEmpty(tmpdir)
   969  	gb.mustNotExist(filepath.Join(gb.tempdir, "pkg")) // ensure no pkg directory is created
   970  }
   971  
   972  const issue473 = `package main
   973  
   974  import (
   975      "flag"
   976      "testing"
   977  )
   978  
   979  var name = flag.String("name", "nsf", "what is your name")
   980  
   981  func TestX(t *testing.T) {
   982  }
   983  
   984  func TestY(t *testing.T) {
   985  }
   986  `
   987  
   988  // https://github.com/constabulary/gb/issues/473
   989  func TestGbTestIssue473a(t *testing.T) {
   990  	gb := T{T: t}
   991  	defer gb.cleanup()
   992  	gb.tempDir("src")
   993  	gb.tempDir("src/projectx")
   994  	gb.tempFile("src/projectx/main_test.go", issue473)
   995  	gb.cd(gb.tempdir)
   996  	tmpdir := gb.tempDir("tmp")
   997  	gb.setenv("TMP", tmpdir)
   998  	gb.run("test", "-v", "projectx", "-run", "TestX")
   999  	gb.grepStdout("^projectx$", "expected projectx") // output from gb test
  1000  	gb.grepStdout("TestX", "expected TestX")
  1001  	gb.grepStdoutNot("TestY", "expected TestY")
  1002  	gb.mustBeEmpty(tmpdir)
  1003  	gb.mustNotExist(filepath.Join(gb.tempdir, "pkg")) // ensure no pkg directory is created
  1004  }
  1005  
  1006  func TestGbTestIssue473b(t *testing.T) {
  1007  	gb := T{T: t}
  1008  	defer gb.cleanup()
  1009  	gb.tempDir("src")
  1010  	gb.tempDir("src/projectx")
  1011  	gb.tempFile("src/projectx/main_test.go", issue473)
  1012  	gb.cd(gb.tempdir)
  1013  	tmpdir := gb.tempDir("tmp")
  1014  	gb.setenv("TMP", tmpdir)
  1015  	gb.run("test", "-v", "-run", "TestX", "projectx")
  1016  	gb.grepStdout("^projectx$", "expected projectx") // output from gb test
  1017  	gb.grepStdout("TestX", "expected TestX")
  1018  	gb.grepStdoutNot("TestY", "expected TestY")
  1019  	gb.mustBeEmpty(tmpdir)
  1020  	gb.mustNotExist(filepath.Join(gb.tempdir, "pkg")) // ensure no pkg directory is created
  1021  }
  1022  
  1023  func TestGbTestIssue473c(t *testing.T) {
  1024  	gb := T{T: t}
  1025  	defer gb.cleanup()
  1026  	gb.tempDir("src")
  1027  	gb.tempDir("src/projectx")
  1028  	gb.tempFile("src/projectx/main_test.go", issue473)
  1029  	gb.cd(gb.tempdir)
  1030  	tmpdir := gb.tempDir("tmp")
  1031  	gb.setenv("TMP", tmpdir)
  1032  	gb.run("test", "-v", "projectx")
  1033  	gb.grepStdout("^projectx$", "expected projectx") // output from gb test
  1034  	gb.grepStdout("TestX", "expected TestX")
  1035  	gb.grepStdout("TestY", "expected TestY")
  1036  	gb.mustBeEmpty(tmpdir)
  1037  	gb.mustNotExist(filepath.Join(gb.tempdir, "pkg")) // ensure no pkg directory is created
  1038  }
  1039  
  1040  func TestGbTestIssue473d(t *testing.T) {
  1041  	gb := T{T: t}
  1042  	defer gb.cleanup()
  1043  	gb.tempDir("src")
  1044  	gb.tempDir("src/projectx")
  1045  	gb.tempFile("src/projectx/main_test.go", issue473)
  1046  	gb.cd(gb.tempdir)
  1047  	tmpdir := gb.tempDir("tmp")
  1048  	gb.setenv("TMP", tmpdir)
  1049  	gb.run("test", "projectx", "-v")
  1050  	gb.grepStdout("^projectx$", "expected projectx") // output from gb test
  1051  	gb.grepStdout("TestX", "expected TestX")
  1052  	gb.grepStdout("TestY", "expected TestY")
  1053  	gb.mustBeEmpty(tmpdir)
  1054  	gb.mustNotExist(filepath.Join(gb.tempdir, "pkg")) // ensure no pkg directory is created
  1055  }
  1056  
  1057  // gb list with an empty project succeeds and returns nothing.
  1058  func TestGbListEmpty(t *testing.T) {
  1059  	gb := T{T: t}
  1060  	defer gb.cleanup()
  1061  	gb.tempDir("src")
  1062  	gb.cd(gb.tempdir)
  1063  	tmpdir := gb.tempDir("tmp")
  1064  	gb.setenv("TMP", tmpdir)
  1065  	gb.run("list")
  1066  	gb.grepStdoutNot(".", "expected no output")
  1067  	gb.grepStderrNot(".", "expected no output")
  1068  	gb.mustBeEmpty(tmpdir)
  1069  }
  1070  
  1071  // gb list with a project with source at the top level should return nothing.
  1072  func TestGbListSrcTopLevel(t *testing.T) {
  1073  	gb := T{T: t}
  1074  	defer gb.cleanup()
  1075  	gb.tempDir("src")
  1076  	gb.tempFile("src/main.go", "package main; func main() { println() }")
  1077  	gb.cd(gb.tempdir)
  1078  	gb.run("list")
  1079  	gb.grepStdoutNot(".", "expected no output")
  1080  	gb.grepStderrNot(".", "expected no output")
  1081  }
  1082  
  1083  func TestGbListSrcCmd(t *testing.T) {
  1084  	gb := T{T: t}
  1085  	defer gb.cleanup()
  1086  	gb.tempDir("src")
  1087  	gb.tempDir("src/cmd")
  1088  	gb.tempFile("src/cmd/main.go", "package main; func main() { println() }")
  1089  	gb.cd(gb.tempdir)
  1090  	gb.run("list")
  1091  	gb.grepStdout("cmd", "expected cmd")
  1092  }
  1093  
  1094  func mklistfixture(gb *T) {
  1095  	gb.tempDir("src/p")
  1096  	gb.tempDir("src/q")
  1097  	gb.tempDir("src/r/s")
  1098  	gb.tempFile("src/p/p.go", "package p; const P = 'p'")
  1099  	gb.tempFile("src/q/q.go", "package p; const Q = 'q'") // package name differs from import path
  1100  	gb.tempFile("src/r/r.go", "package r; const R = 'r'")
  1101  	gb.tempFile("src/r/s/s.go", "package s; const S = 's'")
  1102  }
  1103  
  1104  // gb list with a few projects should show them all.
  1105  func TestGbList(t *testing.T) {
  1106  	gb := T{T: t}
  1107  	defer gb.cleanup()
  1108  	mklistfixture(&gb)
  1109  	gb.cd(gb.tempdir)
  1110  	gb.run("list")
  1111  	gb.grepStdout("^p$", "expected 'p'")
  1112  	gb.grepStdout("^q$", "expected 'q'")
  1113  	gb.grepStdout("^r$", "expected 'r'")
  1114  	gb.grepStdout("^r/s$", "expected 'r/s'")
  1115  }
  1116  
  1117  func TestGbListPart(t *testing.T) {
  1118  	gb := T{T: t}
  1119  	defer gb.cleanup()
  1120  	mklistfixture(&gb)
  1121  	gb.cd(gb.tempdir)
  1122  	gb.run("list", "r/...", "q")
  1123  	gb.grepStdoutNot("^p$", "unexpected 'p'")
  1124  	gb.grepStdout("^q$", "expected 'q'")
  1125  	gb.grepStdout("^r$", "expected 'r'")
  1126  	gb.grepStdout("^r/s$", "expected 'r/s'")
  1127  }
  1128  
  1129  func TestGbListPackageNames(t *testing.T) {
  1130  	gb := T{T: t}
  1131  	defer gb.cleanup()
  1132  	mklistfixture(&gb)
  1133  	gb.cd(gb.tempdir)
  1134  	gb.run("list", "-f", "{{ .Name }}")
  1135  	gb.grepStdout("^p$", "expected 'p'")
  1136  	gb.grepStdoutNot("^q$", "unexpected 'q'")
  1137  	gb.grepStdout("^r$", "expected 'r'")
  1138  	gb.grepStdout("^s$", "expected 's'")
  1139  }
  1140  
  1141  func TestGbListFormatFromStdin(t *testing.T) {
  1142  	gb := T{T: t}
  1143  	defer gb.cleanup()
  1144  	mklistfixture(&gb)
  1145  	gb.cd(gb.tempdir)
  1146  	gb.stdin = strings.NewReader("{{ .Name }}")
  1147  	gb.run("list", "-s")
  1148  	gb.grepStdout("^p$", "expected 'p'")
  1149  	gb.grepStdoutNot("^q$", "unexpected 'q'")
  1150  	gb.grepStdout("^r$", "expected 'r'")
  1151  	gb.grepStdout("^s$", "expected 's'")
  1152  }
  1153  
  1154  // TODO(dfc) add tests for -json
  1155  
  1156  func skipWindows(t *testing.T, msg string) {
  1157  	if runtime.GOOS == "windows" {
  1158  		t.Skip("test skipped on windows:", msg)
  1159  	}
  1160  }
  1161  
  1162  // issue 481: check that project detection works correctly
  1163  // in the presence of symlinks above the project root.
  1164  func TestProjectRootDetectionWorksWithParentSymlink(t *testing.T) {
  1165  	skipWindows(t, "no symlinks, lol")
  1166  	gb := T{T: t}
  1167  	defer gb.cleanup()
  1168  
  1169  	gb.tempDir("code/project")
  1170  	gb.tempDir("code/project/src/a")
  1171  	gb.tempFile("code/project/src/a/a.go", "package a; const A = 'a'")
  1172  	root := gb.symlink("code", "code1")
  1173  	gb.cd(filepath.Join(root, "project"))
  1174  	gb.run("list")
  1175  	gb.grepStdout("^a$", "expected 'a'")
  1176  }
  1177  
  1178  func TestProjectRootDetectionWorksWithDirectSymlink(t *testing.T) {
  1179  	skipWindows(t, "no symlinks, lol")
  1180  	gb := T{T: t}
  1181  	defer gb.cleanup()
  1182  
  1183  	gb.tempDir("code/project")
  1184  	gb.tempDir("code/project/src/a")
  1185  	gb.tempFile("code/project/src/a/a.go", "package a; const A = 'a'")
  1186  	root := gb.symlink("code/project", "code/symlink")
  1187  	gb.cd(root)
  1188  	gb.run("list")
  1189  	gb.grepStdout("^a$", "expected 'a'")
  1190  }
  1191  
  1192  // issue 157
  1193  func TestTestWorksWithProjectSymlink(t *testing.T) {
  1194  	skipWindows(t, "no symlinks, lol")
  1195  	gb := T{T: t}
  1196  	defer gb.cleanup()
  1197  
  1198  	gb.tempDir("code/project")
  1199  	gb.tempDir("code/project/src/a")
  1200  	gb.tempFile("code/project/src/a/a.go", "package a; const A = 'a'")
  1201  	gb.tempFile("code/project/src/a/a_test.go", `package a
  1202  
  1203  import "testing"
  1204  
  1205  func TestA(t *testing.T) {
  1206  	if A != 'a' {
  1207  		t.Fatal("expected a, got", A)
  1208  	}
  1209  }
  1210  `)
  1211  	root := gb.symlink("code/project", "code/symlink")
  1212  	gb.cd(root)
  1213  	gb.run("test")
  1214  	gb.grepStdout("^a$", "expected 'a'")
  1215  }
  1216  
  1217  func TestTestWorksInsideProjectSymlink(t *testing.T) {
  1218  	skipWindows(t, "no symlinks, lol")
  1219  	gb := T{T: t}
  1220  	defer gb.cleanup()
  1221  
  1222  	gb.tempDir("code/project")
  1223  	gb.tempDir("code/project/src/a")
  1224  	gb.tempFile("code/project/src/a/a.go", "package a; const A = 'a'")
  1225  	gb.tempFile("code/project/src/a/a_test.go", `package a
  1226  
  1227  import "testing"
  1228  
  1229  func TestA(t *testing.T) {
  1230  	if A != 'a' {
  1231  		t.Fatal("expected a, got", A)
  1232  	}
  1233  }
  1234  `)
  1235  	root := gb.symlink("code/project", "code/symlink")
  1236  	gb.cd(filepath.Join(root, "src", "a"))
  1237  	gb.run("test")
  1238  	gb.grepStdout("^a$", "expected 'a'")
  1239  }
  1240  
  1241  // test -race flag is wired up correctly
  1242  func TestBuildRaceFlag(t *testing.T) {
  1243  	if !canRace {
  1244  		t.Skip("skipping because race detector not supported")
  1245  	}
  1246  
  1247  	gb := T{T: t}
  1248  	defer gb.cleanup()
  1249  
  1250  	gb.tempDir("src/x")
  1251  	gb.tempFile("src/x/x_race.go", "package x\nconst A = 1\n")
  1252  	gb.tempFile("src/x/y.go", "// +build race\n\npackage x\nconst B = 2\n")
  1253  	gb.tempFile("src/x/z.go", "package x\n const C = A +B\n")
  1254  	gb.cd(gb.tempdir)
  1255  	tmpdir := gb.tempDir("tmp")
  1256  	gb.setenv("TMP", tmpdir)
  1257  	gb.run("build", "-race", "x")
  1258  	gb.mustBeEmpty(tmpdir)
  1259  	gb.wantArchive(filepath.Join(gb.tempdir, "pkg", runtime.GOOS+"-"+runtime.GOARCH+"-race", "x.a"))
  1260  }
  1261  
  1262  func TestTestRaceFlag(t *testing.T) {
  1263  	if !canRace {
  1264  		t.Skip("skipping because race detector not supported")
  1265  	}
  1266  
  1267  	gb := T{T: t}
  1268  	defer gb.cleanup()
  1269  
  1270  	gb.tempDir("src/x")
  1271  	gb.tempFile("src/x/x_race.go", "package x\nconst A = 1\n")
  1272  	gb.tempFile("src/x/y.go", "// +build race\n\npackage x\nconst B = 2\n")
  1273  	gb.tempFile("src/x/q.go", "// +build !race\n\npackage x\nconst B = 7\n")
  1274  	gb.tempFile("src/x/x_test.go", `package x
  1275  import "testing"
  1276  
  1277  func TestRaceFlag(t *testing.T) {
  1278  	if A != 1 || B != 2 {
  1279  		t.Fatal("expected", 1, 2,"got", A, B)
  1280  	}
  1281  }
  1282  `)
  1283  	gb.cd(gb.tempdir)
  1284  	tmpdir := gb.tempDir("tmp")
  1285  	gb.setenv("TMP", tmpdir)
  1286  	gb.run("test", "-race", "x")
  1287  	gb.grepStdout("^x$", "expected x") // output from gb test
  1288  	gb.mustBeEmpty(tmpdir)
  1289  	gb.mustNotExist(filepath.Join(gb.tempdir, "pkg")) // ensure no pkg directory is created
  1290  }
  1291  
  1292  // check that go test -race builds and runs a racy binary, and that it finds the race.
  1293  func TestTestRace(t *testing.T) {
  1294  	if !canRace {
  1295  		t.Skip("skipping because race detector not supported")
  1296  	}
  1297  	if strings.HasPrefix(runtime.Version(), "go1.4") {
  1298  		t.Skipf("skipping race test as Go version %v incorrectly marks race failures as success", runtime.Version())
  1299  	}
  1300  
  1301  	gb := T{T: t}
  1302  	defer gb.cleanup()
  1303  
  1304  	gb.tempDir("src/race")
  1305  	gb.tempFile("src/race/map_test.go", `package race
  1306  import "testing"
  1307  
  1308  func TestRaceMapRW(t *testing.T) {
  1309          m := make(map[int]int)
  1310          ch := make(chan bool, 1)
  1311          go func() {
  1312                  _ = m[1]
  1313                  ch <- true
  1314          }()
  1315          m[1] = 1
  1316          <-ch
  1317  }
  1318  `)
  1319  	gb.cd(gb.tempdir)
  1320  	tmpdir := gb.tempDir("tmp")
  1321  	gb.setenv("TMP", tmpdir)
  1322  	gb.runFail("test", "-race")
  1323  	gb.mustBeEmpty(tmpdir)
  1324  }
  1325  
  1326  // check that missing -race support generates error message.
  1327  func TestRaceMissing(t *testing.T) {
  1328  	if canRace {
  1329  		t.Skip("skipping because race detector is available")
  1330  	}
  1331  
  1332  	gb := T{T: t}
  1333  	defer gb.cleanup()
  1334  
  1335  	gb.tempDir("src/race")
  1336  	gb.tempFile("src/race/map_test.go", `package race
  1337  import "testing"
  1338  
  1339  func TestRaceMapRW(t *testing.T) {
  1340          m := make(map[int]int)
  1341          ch := make(chan bool, 1)
  1342          go func() {
  1343                  _ = m[1]
  1344                  ch <- true
  1345          }()
  1346          m[1] = 1
  1347          <-ch
  1348  }
  1349  `)
  1350  	gb.cd(gb.tempdir)
  1351  	tmpdir := gb.tempDir("tmp")
  1352  	gb.setenv("TMP", tmpdir)
  1353  	gb.runFail("test", "-race")
  1354  	gb.grepStderr(regexp.QuoteMeta(fmt.Sprintf("FATAL: go installation at %s is missing race support", runtime.GOROOT())), "expected missing race support message")
  1355  	gb.mustBeEmpty(tmpdir)
  1356  }
  1357  
  1358  // test that gb will no build the stdlib directly, only as transitive deps.
  1359  func TestNoBuildStdlib(t *testing.T) {
  1360  	t.Skip("constabulary/gb#505")
  1361  	gb := T{T: t}
  1362  	defer gb.cleanup()
  1363  	gb.tempDir("src/")
  1364  	gb.cd(gb.tempdir)
  1365  	defer gb.cleanup()
  1366  	gb.runFail("build", "-f", "-F", "net/http")
  1367  }
  1368  
  1369  func TestCrossCompile(t *testing.T) {
  1370  	if strings.HasPrefix(runtime.Version(), "go1.4") {
  1371  		t.Skip("skipping cross compile test, not supported on", runtime.Version())
  1372  	}
  1373  	gb := T{T: t}
  1374  	defer gb.cleanup()
  1375  	gb.tempDir("src/p")
  1376  	gb.tempFile("src/p/main.go", `package main
  1377  func main() { println("hello world") }
  1378  `)
  1379  	gb.cd(gb.tempdir)
  1380  	tmpdir := gb.tempDir("tmp")
  1381  	goos := "windows"
  1382  	if runtime.GOOS == goos {
  1383  		goos = "linux"
  1384  	}
  1385  	goarch := "386"
  1386  	if runtime.GOARCH == goarch {
  1387  		goarch = "amd64"
  1388  	}
  1389  	gb.setenv("TMP", tmpdir)
  1390  	gb.setenv("GOOS", goos)
  1391  	gb.setenv("GOARCH", goarch)
  1392  	gb.run("build")
  1393  	gb.mustBeEmpty(tmpdir)
  1394  	name := fmt.Sprintf("p-%s-%s", goos, goarch)
  1395  	if goos == "windows" {
  1396  		name += ".exe"
  1397  	}
  1398  	gb.mustExist(gb.path("bin", name))
  1399  	gb.wantExecutable(gb.path("bin", name), "expected $PROJECT/bin/p-$GOOS-$GOARCH")
  1400  }
  1401  
  1402  // https://github.com/constabulary/gb/issues/416
  1403  func TestGbBuildBuildsPackgeCalledCmd(t *testing.T) {
  1404  	gb := T{T: t}
  1405  	defer gb.cleanup()
  1406  	gb.tempDir("src/cmd")
  1407  	gb.tempFile("src/cmd/main.go", `package main
  1408  func main() { println("hello world") }
  1409  `)
  1410  	gb.cd(gb.tempdir)
  1411  	tmpdir := gb.tempDir("tmp")
  1412  	gb.setenv("TMP", tmpdir)
  1413  	gb.run("build")
  1414  	gb.mustBeEmpty(tmpdir)
  1415  	gb.grepStdout("^cmd$", "expected cmd")
  1416  	name := "cmd"
  1417  	if runtime.GOOS == "windows" {
  1418  		name += ".exe"
  1419  	}
  1420  	gb.mustExist(gb.path("bin", name))
  1421  	gb.wantExecutable(gb.path("bin", name), "expected $PROJECT/bin/"+name)
  1422  }
  1423  
  1424  // https://github.com/constabulary/gb/issues/492
  1425  func TestGbBuildSubPackageOfCmd(t *testing.T) {
  1426  	gb := T{T: t}
  1427  	defer gb.cleanup()
  1428  	gb.tempDir("src/cmd/hello")
  1429  	gb.tempFile("src/cmd/hello/main.go", `package main
  1430  func main() { println("hello world") }
  1431  `)
  1432  	gb.cd(gb.tempdir)
  1433  	tmpdir := gb.tempDir("tmp")
  1434  	gb.setenv("TMP", tmpdir)
  1435  	gb.run("build")
  1436  	gb.mustBeEmpty(tmpdir)
  1437  	name := "hello"
  1438  	if runtime.GOOS == "windows" {
  1439  		name += ".exe"
  1440  	}
  1441  	gb.wantExecutable(gb.path("bin", name), "expected $PROJECT/bin/hello")
  1442  }
  1443  
  1444  // https://github.com/constabulary/gb/issues/515
  1445  func TestIssue515(t *testing.T) {
  1446  	gb := T{T: t}
  1447  	defer gb.cleanup()
  1448  	gb.tempDir("src/main")
  1449  	gb.tempFile("src/main/main.go", `package main
  1450  
  1451  import (
  1452      "log"
  1453      "net/http"
  1454  )
  1455  
  1456  func main() {
  1457      err := http.ListenAndServe(":8080", nil)
  1458      if err != nil {
  1459          log.Fatal("ListenAndServe: ", err)
  1460      } else {
  1461          log.Print("Server started!")
  1462      }
  1463  }
  1464  `)
  1465  	gb.cd(gb.tempdir)
  1466  	tmpdir := gb.tempDir("tmp")
  1467  	gb.setenv("TMP", tmpdir)
  1468  	gb.run("build")
  1469  	gb.mustBeEmpty(tmpdir)
  1470  	name := "main"
  1471  	if runtime.GOOS == "windows" {
  1472  		name += ".exe"
  1473  	}
  1474  	gb.wantExecutable(gb.path("bin", name), "expected $PROJECT/bin/main")
  1475  }
  1476  
  1477  func TestGbGenerate(t *testing.T) {
  1478  	if runtime.GOOS == "windows" {
  1479  		t.Skipf("windows doesn't have echo, lol")
  1480  	}
  1481  	gb := T{T: t}
  1482  	defer gb.cleanup()
  1483  	gb.tempDir("src/gentest")
  1484  	gb.tempFile("src/gentest/generate.go", `package gentest
  1485  //go:generate echo $GOPACKAGE $GOFILE
  1486  `)
  1487  	gb.cd(gb.tempdir)
  1488  	gb.run("generate")
  1489  	gb.grepStdout("^gentest generate.go$", "expected $GOPACKAGE $GOFILE")
  1490  }
  1491  
  1492  func TestGbDoc(t *testing.T) {
  1493  	if runtime.GOOS == "windows" {
  1494  		t.Skipf("windows doesn't have echo, lol")
  1495  	}
  1496  	gb := T{T: t}
  1497  	defer gb.cleanup()
  1498  	gb.tempDir("src/doctest")
  1499  	gb.tempFile("src/doctest/doc.go", `// Package doctest tests gb doc
  1500  package doctest
  1501  `)
  1502  	gb.cd(gb.tempdir)
  1503  	gb.run("doc", "doctest")
  1504  	gb.grepStdout("Package doctest tests gb doc$", "expected Package doctest tests gb doc")
  1505  }
  1506  
  1507  func TestIssue346(t *testing.T) {
  1508  	gb := T{T: t}
  1509  	defer gb.cleanup()
  1510  	gb.tempDir("src/p")
  1511  	gb.tempFile("src/p/main.go", `package main
  1512  func main() { println("hello world") }
  1513  `)
  1514  	gb.cd(gb.tempdir)
  1515  	tmpdir := gb.tempDir("tmp")
  1516  	gb.setenv("TMP", tmpdir)
  1517  
  1518  	goos := runtime.GOOS
  1519  
  1520  	// scenario 1: GOOS/GOARCH not set
  1521  	name := "p"
  1522  	if goos == "windows" {
  1523  		name += ".exe"
  1524  	}
  1525  	gb.unsetenv("GOOS")
  1526  	gb.unsetenv("GOARCH")
  1527  	gb.run("build")
  1528  	gb.wantExecutable(gb.path("bin", name), "expected $PROJECT/bin/p")
  1529  
  1530  	// scenario 2: GOOS/GOARCH are both set
  1531  	name = fmt.Sprintf("p-%s-%s", goos, runtime.GOARCH)
  1532  	if goos == "windows" {
  1533  		name += ".exe"
  1534  	}
  1535  	gb.setenv("GOOS", goos)
  1536  	gb.setenv("GOARCH", runtime.GOARCH)
  1537  	gb.run("build")
  1538  	gb.wantExecutable(gb.path("bin", name), "expected $PROJECT/bin/p-$GOOS-$GOARCH")
  1539  
  1540  	// scenario 3: just GOOS is set
  1541  	os.Remove(gb.path("bin", name))
  1542  	gb.unsetenv("GOARCH")
  1543  	gb.run("build")
  1544  	gb.mustNotExist(gb.path("bin", name))
  1545  }
  1546  
  1547  func TestGbBuildCannotReferencePackagesInGoroot(t *testing.T) {
  1548  	gb := T{T: t}
  1549  	defer gb.cleanup()
  1550  
  1551  	gb.tempDir("src")
  1552  	gb.cd(gb.tempdir)
  1553  	tmpdir := gb.tempDir("tmp")
  1554  
  1555  	gb.setenv("TMP", tmpdir)
  1556  	gb.runFail("build", "net/http") // net/http will be excluded by resolveRootPackages
  1557  	gb.mustBeEmpty(tmpdir)
  1558  	gb.mustNotExist(gb.path("pkg"))
  1559  	gb.grepStderr(`FATAL: command "build" failed: no packages supplied`, "expected FATAL")
  1560  }
  1561  
  1562  func TestGbBuildWillResolvePackagesInVendorAsRoots(t *testing.T) {
  1563  	gb := T{T: t}
  1564  	defer gb.cleanup()
  1565  
  1566  	gb.tempDir("src")
  1567  	gb.tempDir("vendor/src/test/test1")
  1568  	gb.tempFile("vendor/src/test/test1/test1.go", `package http
  1569  func init() {
  1570          println("Hello, world!")
  1571  }
  1572  `)
  1573  	gb.cd(gb.tempdir)
  1574  	tmpdir := gb.tempDir("tmp")
  1575  
  1576  	gb.setenv("TMP", tmpdir)
  1577  	gb.runFail("build") // should fail, nothing supplied
  1578  	gb.mustBeEmpty(tmpdir)
  1579  	gb.mustNotExist(gb.path("pkg"))
  1580  	gb.grepStderr(`FATAL: command "build" failed: no packages supplied`, "expected FATAL")
  1581  
  1582  	gb.runFail("build", "test/...") // should fail, globbing does not match $PROJECT/vendor/src
  1583  	gb.mustBeEmpty(tmpdir)
  1584  	gb.mustNotExist(gb.path("pkg"))
  1585  	gb.grepStderr(`FATAL: command "build" failed: no packages supplied`, "expected FATAL")
  1586  
  1587  	gb.run("build", "test/test1") // should resolve to vendor/src/test/test1
  1588  	gb.mustBeEmpty(tmpdir)
  1589  	gb.wantArchive(filepath.Join(gb.tempdir, "pkg", runtime.GOOS+"-"+runtime.GOARCH, "test", "test1.a"))
  1590  	gb.grepStdout(`^test/test`, "expected test/test1")
  1591  }
  1592  
  1593  func TestIssue550(t *testing.T) {
  1594  	gb := T{T: t}
  1595  	defer gb.cleanup()
  1596  
  1597  	gb.tempDir("src/x")
  1598  	gb.tempFile("src/x/x.go", `package main
  1599  
  1600  import (
  1601      "log"
  1602      "this/is/a/bad/path"
  1603  )
  1604  
  1605  func main() {
  1606      log.Println("Hello World.")
  1607  }
  1608  `)
  1609  	gb.cd(gb.tempdir)
  1610  	tmpdir := gb.tempDir("tmp")
  1611  
  1612  	gb.setenv("TMP", tmpdir)
  1613  	name := "x"
  1614  	if runtime.GOOS == "windows" {
  1615  		name += ".exe"
  1616  	}
  1617  	gb.runFail("build")
  1618  	gb.mustBeEmpty(tmpdir)
  1619  	gb.grepStderr(`FATAL: command "build" failed: failed to resolve import path "x": import "this/is/a/bad/path": not found`, "expected FATAL")
  1620  }