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
5package main_test
6
7import (
8	"bytes"
9	"debug/elf"
10	"debug/macho"
11	"debug/pe"
12	"encoding/binary"
13	"flag"
14	"fmt"
15	"go/format"
16	"internal/race"
17	"internal/testenv"
18	"io"
19	"io/fs"
20	"log"
21	"os"
22	"os/exec"
23	"path/filepath"
24	"regexp"
25	"runtime"
26	"strconv"
27	"strings"
28	"testing"
29	"time"
30
31	"cmd/go/internal/cache"
32	"cmd/go/internal/cfg"
33	"cmd/go/internal/robustio"
34	"cmd/go/internal/work"
35	"cmd/internal/sys"
36)
37
38func init() {
39	// GOVCS defaults to public:git|hg,private:all,
40	// which breaks many tests here - they can't use non-git, non-hg VCS at all!
41	// Change to fully permissive.
42	// The tests of the GOVCS setting itself are in ../../testdata/script/govcs.txt.
43	os.Setenv("GOVCS", "*:all")
44}
45
46var (
47	canRace = false // whether we can run the race detector
48	canCgo  = false // whether we can use cgo
49	canMSan = false // whether we can run the memory sanitizer
50)
51
52var exeSuffix string = func() string {
53	if runtime.GOOS == "windows" {
54		return ".exe"
55	}
56	return ""
57}()
58
59func tooSlow(t *testing.T) {
60	if testing.Short() {
61		// In -short mode; skip test, except run it on the {darwin,linux,windows}/amd64 builders.
62		if testenv.Builder() != "" && runtime.GOARCH == "amd64" && (runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows") {
63			return
64		}
65		t.Helper()
66		t.Skip("skipping test in -short mode")
67	}
68}
69
70// testGOROOT is the GOROOT to use when running testgo, a cmd/go binary
71// build from this process's current GOROOT, but run from a different
72// (temp) directory.
73var testGOROOT string
74
75var testCC string
76var testGOCACHE string
77
78var testGo string
79var testTmpDir string
80var testBin string
81
82// The TestMain function creates a go command for testing purposes and
83// deletes it after the tests have been run.
84func TestMain(m *testing.M) {
85	// $GO_GCFLAGS a compiler debug flag known to cmd/dist, make.bash, etc.
86	// It is not a standard go command flag; use os.Getenv, not cfg.Getenv.
87	if os.Getenv("GO_GCFLAGS") != "" {
88		fmt.Fprintf(os.Stderr, "testing: warning: no tests to run\n") // magic string for cmd/go
89		fmt.Printf("cmd/go test is not compatible with $GO_GCFLAGS being set\n")
90		fmt.Printf("SKIP\n")
91		return
92	}
93
94	flag.Parse()
95
96	if *proxyAddr != "" {
97		StartProxy()
98		select {}
99	}
100
101	// Run with a temporary TMPDIR to check that the tests don't
102	// leave anything behind.
103	topTmpdir, err := os.MkdirTemp("", "cmd-go-test-")
104	if err != nil {
105		log.Fatal(err)
106	}
107	if !*testWork {
108		defer removeAll(topTmpdir)
109	}
110	os.Setenv(tempEnvName(), topTmpdir)
111
112	dir, err := os.MkdirTemp(topTmpdir, "tmpdir")
113	if err != nil {
114		log.Fatal(err)
115	}
116	testTmpDir = dir
117	if !*testWork {
118		defer removeAll(testTmpDir)
119	}
120
121	testGOCACHE = cache.DefaultDir()
122	if testenv.HasGoBuild() {
123		testBin = filepath.Join(testTmpDir, "testbin")
124		if err := os.Mkdir(testBin, 0777); err != nil {
125			log.Fatal(err)
126		}
127		testGo = filepath.Join(testBin, "go"+exeSuffix)
128		args := []string{"build", "-tags", "testgo", "-o", testGo}
129		if race.Enabled {
130			args = append(args, "-race")
131		}
132		gotool, err := testenv.GoTool()
133		if err != nil {
134			fmt.Fprintln(os.Stderr, err)
135			os.Exit(2)
136		}
137
138		goEnv := func(name string) string {
139			out, err := exec.Command(gotool, "env", name).CombinedOutput()
140			if err != nil {
141				fmt.Fprintf(os.Stderr, "go env %s: %v\n%s", name, err, out)
142				os.Exit(2)
143			}
144			return strings.TrimSpace(string(out))
145		}
146		testGOROOT = goEnv("GOROOT")
147		os.Setenv("TESTGO_GOROOT", testGOROOT)
148		// Ensure that GOROOT is set explicitly.
149		// Otherwise, if the toolchain was built with GOROOT_FINAL set but has not
150		// yet been moved to its final location, programs that invoke runtime.GOROOT
151		// may accidentally use the wrong path.
152		os.Setenv("GOROOT", testGOROOT)
153
154		// The whole GOROOT/pkg tree was installed using the GOHOSTOS/GOHOSTARCH
155		// toolchain (installed in GOROOT/pkg/tool/GOHOSTOS_GOHOSTARCH).
156		// The testgo.exe we are about to create will be built for GOOS/GOARCH,
157		// which means it will use the GOOS/GOARCH toolchain
158		// (installed in GOROOT/pkg/tool/GOOS_GOARCH).
159		// If these are not the same toolchain, then the entire standard library
160		// will look out of date (the compilers in those two different tool directories
161		// are built for different architectures and have different build IDs),
162		// which will cause many tests to do unnecessary rebuilds and some
163		// tests to attempt to overwrite the installed standard library.
164		// Bail out entirely in this case.
165		hostGOOS := goEnv("GOHOSTOS")
166		hostGOARCH := goEnv("GOHOSTARCH")
167		if hostGOOS != runtime.GOOS || hostGOARCH != runtime.GOARCH {
168			fmt.Fprintf(os.Stderr, "testing: warning: no tests to run\n") // magic string for cmd/go
169			fmt.Printf("cmd/go test is not compatible with GOOS/GOARCH != GOHOSTOS/GOHOSTARCH (%s/%s != %s/%s)\n", runtime.GOOS, runtime.GOARCH, hostGOOS, hostGOARCH)
170			fmt.Printf("SKIP\n")
171			return
172		}
173
174		buildCmd := exec.Command(gotool, args...)
175		buildCmd.Env = append(os.Environ(), "GOFLAGS=-mod=vendor")
176		out, err := buildCmd.CombinedOutput()
177		if err != nil {
178			fmt.Fprintf(os.Stderr, "building testgo failed: %v\n%s", err, out)
179			os.Exit(2)
180		}
181
182		out, err = exec.Command(gotool, "env", "CC").CombinedOutput()
183		if err != nil {
184			fmt.Fprintf(os.Stderr, "could not find testing CC: %v\n%s", err, out)
185			os.Exit(2)
186		}
187		testCC = strings.TrimSpace(string(out))
188
189		cmd := exec.Command(testGo, "env", "CGO_ENABLED")
190		cmd.Stderr = new(strings.Builder)
191		if out, err := cmd.Output(); err != nil {
192			fmt.Fprintf(os.Stderr, "running testgo failed: %v\n%s", err, cmd.Stderr)
193			os.Exit(2)
194		} else {
195			canCgo, err = strconv.ParseBool(strings.TrimSpace(string(out)))
196			if err != nil {
197				fmt.Fprintf(os.Stderr, "can't parse go env CGO_ENABLED output: %v\n", strings.TrimSpace(string(out)))
198			}
199		}
200
201		out, err = exec.Command(gotool, "env", "GOCACHE").CombinedOutput()
202		if err != nil {
203			fmt.Fprintf(os.Stderr, "could not find testing GOCACHE: %v\n%s", err, out)
204			os.Exit(2)
205		}
206		testGOCACHE = strings.TrimSpace(string(out))
207
208		canMSan = canCgo && sys.MSanSupported(runtime.GOOS, runtime.GOARCH)
209		canRace = canCgo && sys.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH)
210		// The race detector doesn't work on Alpine Linux:
211		// golang.org/issue/14481
212		// gccgo does not support the race detector.
213		if isAlpineLinux() || runtime.Compiler == "gccgo" {
214			canRace = false
215		}
216	}
217	// Don't let these environment variables confuse the test.
218	os.Setenv("GOENV", "off")
219	os.Unsetenv("GOFLAGS")
220	os.Unsetenv("GOBIN")
221	os.Unsetenv("GOPATH")
222	os.Unsetenv("GIT_ALLOW_PROTOCOL")
223	os.Setenv("HOME", "/test-go-home-does-not-exist")
224	// On some systems the default C compiler is ccache.
225	// Setting HOME to a non-existent directory will break
226	// those systems. Disable ccache and use real compiler. Issue 17668.
227	os.Setenv("CCACHE_DISABLE", "1")
228	if cfg.Getenv("GOCACHE") == "" {
229		os.Setenv("GOCACHE", testGOCACHE) // because $HOME is gone
230	}
231
232	r := m.Run()
233	if !*testWork {
234		removeAll(testTmpDir) // os.Exit won't run defer
235	}
236
237	if !*testWork {
238		// There shouldn't be anything left in topTmpdir.
239		dirf, err := os.Open(topTmpdir)
240		if err != nil {
241			log.Fatal(err)
242		}
243		names, err := dirf.Readdirnames(0)
244		if err != nil {
245			log.Fatal(err)
246		}
247		if len(names) > 0 {
248			log.Fatalf("unexpected files left in tmpdir: %v", names)
249		}
250
251		removeAll(topTmpdir)
252	}
253
254	os.Exit(r)
255}
256
257func isAlpineLinux() bool {
258	if runtime.GOOS != "linux" {
259		return false
260	}
261	fi, err := os.Lstat("/etc/alpine-release")
262	return err == nil && fi.Mode().IsRegular()
263}
264
265// The length of an mtime tick on this system. This is an estimate of
266// how long we need to sleep to ensure that the mtime of two files is
267// different.
268// We used to try to be clever but that didn't always work (see golang.org/issue/12205).
269var mtimeTick time.Duration = 1 * time.Second
270
271// Manage a single run of the testgo binary.
272type testgoData struct {
273	t              *testing.T
274	temps          []string
275	env            []string
276	tempdir        string
277	ran            bool
278	inParallel     bool
279	stdout, stderr bytes.Buffer
280	execDir        string // dir for tg.run
281}
282
283// skipIfGccgo skips the test if using gccgo.
284func skipIfGccgo(t *testing.T, msg string) {
285	if runtime.Compiler == "gccgo" {
286		t.Skipf("skipping test not supported on gccgo: %s", msg)
287	}
288}
289
290// testgo sets up for a test that runs testgo.
291func testgo(t *testing.T) *testgoData {
292	t.Helper()
293	testenv.MustHaveGoBuild(t)
294	testenv.SkipIfShortAndSlow(t)
295
296	return &testgoData{t: t}
297}
298
299// must gives a fatal error if err is not nil.
300func (tg *testgoData) must(err error) {
301	tg.t.Helper()
302	if err != nil {
303		tg.t.Fatal(err)
304	}
305}
306
307// check gives a test non-fatal error if err is not nil.
308func (tg *testgoData) check(err error) {
309	tg.t.Helper()
310	if err != nil {
311		tg.t.Error(err)
312	}
313}
314
315// parallel runs the test in parallel by calling t.Parallel.
316func (tg *testgoData) parallel() {
317	tg.t.Helper()
318	if tg.ran {
319		tg.t.Fatal("internal testsuite error: call to parallel after run")
320	}
321	for _, e := range tg.env {
322		if strings.HasPrefix(e, "GOROOT=") || strings.HasPrefix(e, "GOPATH=") || strings.HasPrefix(e, "GOBIN=") {
323			val := e[strings.Index(e, "=")+1:]
324			if strings.HasPrefix(val, "testdata") || strings.HasPrefix(val, "./testdata") {
325				tg.t.Fatalf("internal testsuite error: call to parallel with testdata in environment (%s)", e)
326			}
327		}
328	}
329	tg.inParallel = true
330	tg.t.Parallel()
331}
332
333// pwd returns the current directory.
334func (tg *testgoData) pwd() string {
335	tg.t.Helper()
336	wd, err := os.Getwd()
337	if err != nil {
338		tg.t.Fatalf("could not get working directory: %v", err)
339	}
340	return wd
341}
342
343// sleep sleeps for one tick, where a tick is a conservative estimate
344// of how long it takes for a file modification to get a different
345// mtime.
346func (tg *testgoData) sleep() {
347	time.Sleep(mtimeTick)
348}
349
350// setenv sets an environment variable to use when running the test go
351// command.
352func (tg *testgoData) setenv(name, val string) {
353	tg.t.Helper()
354	if tg.inParallel && (name == "GOROOT" || name == "GOPATH" || name == "GOBIN") && (strings.HasPrefix(val, "testdata") || strings.HasPrefix(val, "./testdata")) {
355		tg.t.Fatalf("internal testsuite error: call to setenv with testdata (%s=%s) after parallel", name, val)
356	}
357	tg.unsetenv(name)
358	tg.env = append(tg.env, name+"="+val)
359}
360
361// unsetenv removes an environment variable.
362func (tg *testgoData) unsetenv(name string) {
363	if tg.env == nil {
364		tg.env = append([]string(nil), os.Environ()...)
365		tg.env = append(tg.env, "GO111MODULE=off")
366	}
367	for i, v := range tg.env {
368		if strings.HasPrefix(v, name+"=") {
369			tg.env = append(tg.env[:i], tg.env[i+1:]...)
370			break
371		}
372	}
373}
374
375func (tg *testgoData) goTool() string {
376	return testGo
377}
378
379// doRun runs the test go command, recording stdout and stderr and
380// returning exit status.
381func (tg *testgoData) doRun(args []string) error {
382	tg.t.Helper()
383	if tg.inParallel {
384		for _, arg := range args {
385			if strings.HasPrefix(arg, "testdata") || strings.HasPrefix(arg, "./testdata") {
386				tg.t.Fatal("internal testsuite error: parallel run using testdata")
387			}
388		}
389	}
390
391	hasGoroot := false
392	for _, v := range tg.env {
393		if strings.HasPrefix(v, "GOROOT=") {
394			hasGoroot = true
395			break
396		}
397	}
398	prog := tg.goTool()
399	if !hasGoroot {
400		tg.setenv("GOROOT", testGOROOT)
401	}
402
403	tg.t.Logf("running testgo %v", args)
404	cmd := exec.Command(prog, args...)
405	tg.stdout.Reset()
406	tg.stderr.Reset()
407	cmd.Dir = tg.execDir
408	cmd.Stdout = &tg.stdout
409	cmd.Stderr = &tg.stderr
410	cmd.Env = tg.env
411	status := cmd.Run()
412	if tg.stdout.Len() > 0 {
413		tg.t.Log("standard output:")
414		tg.t.Log(tg.stdout.String())
415	}
416	if tg.stderr.Len() > 0 {
417		tg.t.Log("standard error:")
418		tg.t.Log(tg.stderr.String())
419	}
420	tg.ran = true
421	return status
422}
423
424// run runs the test go command, and expects it to succeed.
425func (tg *testgoData) run(args ...string) {
426	tg.t.Helper()
427	if status := tg.doRun(args); status != nil {
428		wd, _ := os.Getwd()
429		tg.t.Logf("go %v failed unexpectedly in %s: %v", args, wd, status)
430		tg.t.FailNow()
431	}
432}
433
434// runFail runs the test go command, and expects it to fail.
435func (tg *testgoData) runFail(args ...string) {
436	tg.t.Helper()
437	if status := tg.doRun(args); status == nil {
438		tg.t.Fatal("testgo succeeded unexpectedly")
439	} else {
440		tg.t.Log("testgo failed as expected:", status)
441	}
442}
443
444// runGit runs a git command, and expects it to succeed.
445func (tg *testgoData) runGit(dir string, args ...string) {
446	tg.t.Helper()
447	cmd := exec.Command("git", args...)
448	tg.stdout.Reset()
449	tg.stderr.Reset()
450	cmd.Stdout = &tg.stdout
451	cmd.Stderr = &tg.stderr
452	cmd.Dir = dir
453	cmd.Env = tg.env
454	status := cmd.Run()
455	if tg.stdout.Len() > 0 {
456		tg.t.Log("git standard output:")
457		tg.t.Log(tg.stdout.String())
458	}
459	if tg.stderr.Len() > 0 {
460		tg.t.Log("git standard error:")
461		tg.t.Log(tg.stderr.String())
462	}
463	if status != nil {
464		tg.t.Logf("git %v failed unexpectedly: %v", args, status)
465		tg.t.FailNow()
466	}
467}
468
469// getStdout returns standard output of the testgo run as a string.
470func (tg *testgoData) getStdout() string {
471	tg.t.Helper()
472	if !tg.ran {
473		tg.t.Fatal("internal testsuite error: stdout called before run")
474	}
475	return tg.stdout.String()
476}
477
478// getStderr returns standard error of the testgo run as a string.
479func (tg *testgoData) getStderr() string {
480	tg.t.Helper()
481	if !tg.ran {
482		tg.t.Fatal("internal testsuite error: stdout called before run")
483	}
484	return tg.stderr.String()
485}
486
487// doGrepMatch looks for a regular expression in a buffer, and returns
488// whether it is found. The regular expression is matched against
489// each line separately, as with the grep command.
490func (tg *testgoData) doGrepMatch(match string, b *bytes.Buffer) bool {
491	tg.t.Helper()
492	if !tg.ran {
493		tg.t.Fatal("internal testsuite error: grep called before run")
494	}
495	re := regexp.MustCompile(match)
496	for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) {
497		if re.Match(ln) {
498			return true
499		}
500	}
501	return false
502}
503
504// doGrep looks for a regular expression in a buffer and fails if it
505// is not found. The name argument is the name of the output we are
506// searching, "output" or "error". The msg argument is logged on
507// failure.
508func (tg *testgoData) doGrep(match string, b *bytes.Buffer, name, msg string) {
509	tg.t.Helper()
510	if !tg.doGrepMatch(match, b) {
511		tg.t.Log(msg)
512		tg.t.Logf("pattern %v not found in standard %s", match, name)
513		tg.t.FailNow()
514	}
515}
516
517// grepStdout looks for a regular expression in the test run's
518// standard output and fails, logging msg, if it is not found.
519func (tg *testgoData) grepStdout(match, msg string) {
520	tg.t.Helper()
521	tg.doGrep(match, &tg.stdout, "output", msg)
522}
523
524// grepStderr looks for a regular expression in the test run's
525// standard error and fails, logging msg, if it is not found.
526func (tg *testgoData) grepStderr(match, msg string) {
527	tg.t.Helper()
528	tg.doGrep(match, &tg.stderr, "error", msg)
529}
530
531// grepBoth looks for a regular expression in the test run's standard
532// output or stand error and fails, logging msg, if it is not found.
533func (tg *testgoData) grepBoth(match, msg string) {
534	tg.t.Helper()
535	if !tg.doGrepMatch(match, &tg.stdout) && !tg.doGrepMatch(match, &tg.stderr) {
536		tg.t.Log(msg)
537		tg.t.Logf("pattern %v not found in standard output or standard error", match)
538		tg.t.FailNow()
539	}
540}
541
542// doGrepNot looks for a regular expression in a buffer and fails if
543// it is found. The name and msg arguments are as for doGrep.
544func (tg *testgoData) doGrepNot(match string, b *bytes.Buffer, name, msg string) {
545	tg.t.Helper()
546	if tg.doGrepMatch(match, b) {
547		tg.t.Log(msg)
548		tg.t.Logf("pattern %v found unexpectedly in standard %s", match, name)
549		tg.t.FailNow()
550	}
551}
552
553// grepStdoutNot looks for a regular expression in the test run's
554// standard output and fails, logging msg, if it is found.
555func (tg *testgoData) grepStdoutNot(match, msg string) {
556	tg.t.Helper()
557	tg.doGrepNot(match, &tg.stdout, "output", msg)
558}
559
560// grepStderrNot looks for a regular expression in the test run's
561// standard error and fails, logging msg, if it is found.
562func (tg *testgoData) grepStderrNot(match, msg string) {
563	tg.t.Helper()
564	tg.doGrepNot(match, &tg.stderr, "error", msg)
565}
566
567// grepBothNot looks for a regular expression in the test run's
568// standard output or standard error and fails, logging msg, if it is
569// found.
570func (tg *testgoData) grepBothNot(match, msg string) {
571	tg.t.Helper()
572	if tg.doGrepMatch(match, &tg.stdout) || tg.doGrepMatch(match, &tg.stderr) {
573		tg.t.Log(msg)
574		tg.t.Fatalf("pattern %v found unexpectedly in standard output or standard error", match)
575	}
576}
577
578// doGrepCount counts the number of times a regexp is seen in a buffer.
579func (tg *testgoData) doGrepCount(match string, b *bytes.Buffer) int {
580	tg.t.Helper()
581	if !tg.ran {
582		tg.t.Fatal("internal testsuite error: doGrepCount called before run")
583	}
584	re := regexp.MustCompile(match)
585	c := 0
586	for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) {
587		if re.Match(ln) {
588			c++
589		}
590	}
591	return c
592}
593
594// grepCountBoth returns the number of times a regexp is seen in both
595// standard output and standard error.
596func (tg *testgoData) grepCountBoth(match string) int {
597	tg.t.Helper()
598	return tg.doGrepCount(match, &tg.stdout) + tg.doGrepCount(match, &tg.stderr)
599}
600
601// creatingTemp records that the test plans to create a temporary file
602// or directory. If the file or directory exists already, it will be
603// removed. When the test completes, the file or directory will be
604// removed if it exists.
605func (tg *testgoData) creatingTemp(path string) {
606	tg.t.Helper()
607	if filepath.IsAbs(path) && !strings.HasPrefix(path, tg.tempdir) {
608		tg.t.Fatalf("internal testsuite error: creatingTemp(%q) with absolute path not in temporary directory", path)
609	}
610	tg.must(robustio.RemoveAll(path))
611	tg.temps = append(tg.temps, path)
612}
613
614// makeTempdir makes a temporary directory for a run of testgo. If
615// the temporary directory was already created, this does nothing.
616func (tg *testgoData) makeTempdir() {
617	tg.t.Helper()
618	if tg.tempdir == "" {
619		var err error
620		tg.tempdir, err = os.MkdirTemp("", "gotest")
621		tg.must(err)
622	}
623}
624
625// tempFile adds a temporary file for a run of testgo.
626func (tg *testgoData) tempFile(path, contents string) {
627	tg.t.Helper()
628	tg.makeTempdir()
629	tg.must(os.MkdirAll(filepath.Join(tg.tempdir, filepath.Dir(path)), 0755))
630	bytes := []byte(contents)
631	if strings.HasSuffix(path, ".go") {
632		formatted, err := format.Source(bytes)
633		if err == nil {
634			bytes = formatted
635		}
636	}
637	tg.must(os.WriteFile(filepath.Join(tg.tempdir, path), bytes, 0644))
638}
639
640// tempDir adds a temporary directory for a run of testgo.
641func (tg *testgoData) tempDir(path string) {
642	tg.t.Helper()
643	tg.makeTempdir()
644	if err := os.MkdirAll(filepath.Join(tg.tempdir, path), 0755); err != nil && !os.IsExist(err) {
645		tg.t.Fatal(err)
646	}
647}
648
649// path returns the absolute pathname to file with the temporary
650// directory.
651func (tg *testgoData) path(name string) string {
652	tg.t.Helper()
653	if tg.tempdir == "" {
654		tg.t.Fatalf("internal testsuite error: path(%q) with no tempdir", name)
655	}
656	if name == "." {
657		return tg.tempdir
658	}
659	return filepath.Join(tg.tempdir, name)
660}
661
662// mustExist fails if path does not exist.
663func (tg *testgoData) mustExist(path string) {
664	tg.t.Helper()
665	if _, err := os.Stat(path); err != nil {
666		if os.IsNotExist(err) {
667			tg.t.Fatalf("%s does not exist but should", path)
668		}
669		tg.t.Fatalf("%s stat failed: %v", path, err)
670	}
671}
672
673// mustNotExist fails if path exists.
674func (tg *testgoData) mustNotExist(path string) {
675	tg.t.Helper()
676	if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) {
677		tg.t.Fatalf("%s exists but should not (%v)", path, err)
678	}
679}
680
681// mustHaveContent succeeds if filePath is a path to a file,
682// and that file is readable and not empty.
683func (tg *testgoData) mustHaveContent(filePath string) {
684	tg.mustExist(filePath)
685	f, err := os.Stat(filePath)
686	if err != nil {
687		tg.t.Fatal(err)
688	}
689	if f.Size() == 0 {
690		tg.t.Fatalf("expected %s to have data, but is empty", filePath)
691	}
692}
693
694// wantExecutable fails with msg if path is not executable.
695func (tg *testgoData) wantExecutable(path, msg string) {
696	tg.t.Helper()
697	if st, err := os.Stat(path); err != nil {
698		if !os.IsNotExist(err) {
699			tg.t.Log(err)
700		}
701		tg.t.Fatal(msg)
702	} else {
703		if runtime.GOOS != "windows" && st.Mode()&0111 == 0 {
704			tg.t.Fatalf("binary %s exists but is not executable", path)
705		}
706	}
707}
708
709// isStale reports whether pkg is stale, and why
710func (tg *testgoData) isStale(pkg string) (bool, string) {
711	tg.t.Helper()
712	tg.run("list", "-f", "{{.Stale}}:{{.StaleReason}}", pkg)
713	v := strings.TrimSpace(tg.getStdout())
714	f := strings.SplitN(v, ":", 2)
715	if len(f) == 2 {
716		switch f[0] {
717		case "true":
718			return true, f[1]
719		case "false":
720			return false, f[1]
721		}
722	}
723	tg.t.Fatalf("unexpected output checking staleness of package %v: %v", pkg, v)
724	panic("unreachable")
725}
726
727// wantStale fails with msg if pkg is not stale.
728func (tg *testgoData) wantStale(pkg, reason, msg string) {
729	tg.t.Helper()
730	stale, why := tg.isStale(pkg)
731	if !stale {
732		tg.t.Fatal(msg)
733	}
734	// We always accept the reason as being "not installed but
735	// available in build cache", because when that is the case go
736	// list doesn't try to sort out the underlying reason why the
737	// package is not installed.
738	if reason == "" && why != "" || !strings.Contains(why, reason) && !strings.Contains(why, "not installed but available in build cache") {
739		tg.t.Errorf("wrong reason for Stale=true: %q, want %q", why, reason)
740	}
741}
742
743// wantNotStale fails with msg if pkg is stale.
744func (tg *testgoData) wantNotStale(pkg, reason, msg string) {
745	tg.t.Helper()
746	stale, why := tg.isStale(pkg)
747	if stale {
748		tg.t.Fatal(msg)
749	}
750	if reason == "" && why != "" || !strings.Contains(why, reason) {
751		tg.t.Errorf("wrong reason for Stale=false: %q, want %q", why, reason)
752	}
753}
754
755// If -testwork is specified, the test prints the name of the temp directory
756// and does not remove it when done, so that a programmer can
757// poke at the test file tree afterward.
758var testWork = flag.Bool("testwork", false, "")
759
760// cleanup cleans up a test that runs testgo.
761func (tg *testgoData) cleanup() {
762	tg.t.Helper()
763	if *testWork {
764		tg.t.Logf("TESTWORK=%s\n", tg.path("."))
765		return
766	}
767	for _, path := range tg.temps {
768		tg.check(removeAll(path))
769	}
770	if tg.tempdir != "" {
771		tg.check(removeAll(tg.tempdir))
772	}
773}
774
775func removeAll(dir string) error {
776	// module cache has 0444 directories;
777	// make them writable in order to remove content.
778	filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {
779		// chmod not only directories, but also things that we couldn't even stat
780		// due to permission errors: they may also be unreadable directories.
781		if err != nil || info.IsDir() {
782			os.Chmod(path, 0777)
783		}
784		return nil
785	})
786	return robustio.RemoveAll(dir)
787}
788
789// failSSH puts an ssh executable in the PATH that always fails.
790// This is to stub out uses of ssh by go get.
791func (tg *testgoData) failSSH() {
792	tg.t.Helper()
793	wd, err := os.Getwd()
794	if err != nil {
795		tg.t.Fatal(err)
796	}
797	fail := filepath.Join(wd, "testdata/failssh")
798	tg.setenv("PATH", fmt.Sprintf("%v%c%v", fail, filepath.ListSeparator, os.Getenv("PATH")))
799}
800
801func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
802	if testing.Short() {
803		t.Skip("skipping lengthy test in short mode")
804	}
805
806	tg := testgo(t)
807	defer tg.cleanup()
808	tg.parallel()
809
810	// Copy the runtime packages into a temporary GOROOT
811	// so that we can change files.
812	for _, copydir := range []string{
813		"src/runtime",
814		"src/internal/bytealg",
815		"src/internal/cpu",
816		"src/math/bits",
817		"src/unsafe",
818		filepath.Join("pkg", runtime.GOOS+"_"+runtime.GOARCH),
819		filepath.Join("pkg/tool", runtime.GOOS+"_"+runtime.GOARCH),
820		"pkg/include",
821	} {
822		srcdir := filepath.Join(testGOROOT, copydir)
823		tg.tempDir(filepath.Join("goroot", copydir))
824		err := filepath.WalkDir(srcdir,
825			func(path string, info fs.DirEntry, err error) error {
826				if err != nil {
827					return err
828				}
829				if info.IsDir() {
830					return nil
831				}
832				srcrel, err := filepath.Rel(srcdir, path)
833				if err != nil {
834					return err
835				}
836				dest := filepath.Join("goroot", copydir, srcrel)
837				data, err := os.ReadFile(path)
838				if err != nil {
839					return err
840				}
841				tg.tempFile(dest, string(data))
842				if strings.Contains(copydir, filepath.Join("pkg", "tool")) {
843					os.Chmod(tg.path(dest), 0777)
844				}
845				return nil
846			})
847		if err != nil {
848			t.Fatal(err)
849		}
850	}
851	tg.setenv("GOROOT", tg.path("goroot"))
852
853	addVar := func(name string, idx int) (restore func()) {
854		data, err := os.ReadFile(name)
855		if err != nil {
856			t.Fatal(err)
857		}
858		old := data
859		data = append(data, fmt.Sprintf("var DummyUnusedVar%d bool\n", idx)...)
860		if err := os.WriteFile(name, append(data, '\n'), 0666); err != nil {
861			t.Fatal(err)
862		}
863		tg.sleep()
864		return func() {
865			if err := os.WriteFile(name, old, 0666); err != nil {
866				t.Fatal(err)
867			}
868		}
869	}
870
871	// Every main package depends on the "runtime".
872	tg.tempFile("d1/src/p1/p1.go", `package main; func main(){}`)
873	tg.setenv("GOPATH", tg.path("d1"))
874	// Pass -i flag to rebuild everything outdated.
875	tg.run("install", "-i", "p1")
876	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, before any changes")
877
878	// Changing mtime of runtime/internal/sys/sys.go
879	// should have no effect: only the content matters.
880	// In fact this should be true even outside a release branch.
881	sys := tg.path("goroot/src/runtime/internal/sys/sys.go")
882	tg.sleep()
883	restore := addVar(sys, 0)
884	restore()
885	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after updating mtime of runtime/internal/sys/sys.go")
886
887	// But changing content of any file should have an effect.
888	// Previously zversion.go was the only one that mattered;
889	// now they all matter, so keep using sys.go.
890	restore = addVar(sys, 1)
891	defer restore()
892	tg.wantStale("p1", "stale dependency: runtime/internal/sys", "./testgo list claims p1 is NOT stale, incorrectly, after changing sys.go")
893	restore()
894	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after changing back to old release")
895	addVar(sys, 2)
896	tg.wantStale("p1", "stale dependency: runtime", "./testgo list claims p1 is NOT stale, incorrectly, after changing sys.go again")
897	tg.run("install", "-i", "p1")
898	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with new release")
899
900	// Restore to "old" release.
901	restore()
902	tg.wantStale("p1", "stale dependency: runtime/internal/sys", "./testgo list claims p1 is NOT stale, incorrectly, after restoring sys.go")
903	tg.run("install", "-i", "p1")
904	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with old release")
905}
906
907// cmd/go: custom import path checking should not apply to Go packages without import comment.
908func TestIssue10952(t *testing.T) {
909	testenv.MustHaveExternalNetwork(t)
910	testenv.MustHaveExecPath(t, "git")
911
912	tg := testgo(t)
913	defer tg.cleanup()
914	tg.parallel()
915	tg.tempDir("src")
916	tg.setenv("GOPATH", tg.path("."))
917	const importPath = "github.com/zombiezen/go-get-issue-10952"
918	tg.run("get", "-d", "-u", importPath)
919	repoDir := tg.path("src/" + importPath)
920	tg.runGit(repoDir, "remote", "set-url", "origin", "https://"+importPath+".git")
921	tg.run("get", "-d", "-u", importPath)
922}
923
924func TestIssue16471(t *testing.T) {
925	testenv.MustHaveExternalNetwork(t)
926	testenv.MustHaveExecPath(t, "git")
927
928	tg := testgo(t)
929	defer tg.cleanup()
930	tg.parallel()
931	tg.tempDir("src")
932	tg.setenv("GOPATH", tg.path("."))
933	tg.must(os.MkdirAll(tg.path("src/rsc.io/go-get-issue-10952"), 0755))
934	tg.runGit(tg.path("src/rsc.io"), "clone", "https://github.com/zombiezen/go-get-issue-10952")
935	tg.runFail("get", "-u", "rsc.io/go-get-issue-10952")
936	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")
937}
938
939// Test git clone URL that uses SCP-like syntax and custom import path checking.
940func TestIssue11457(t *testing.T) {
941	testenv.MustHaveExternalNetwork(t)
942	testenv.MustHaveExecPath(t, "git")
943
944	tg := testgo(t)
945	defer tg.cleanup()
946	tg.parallel()
947	tg.tempDir("src")
948	tg.setenv("GOPATH", tg.path("."))
949	const importPath = "rsc.io/go-get-issue-11457"
950	tg.run("get", "-d", "-u", importPath)
951	repoDir := tg.path("src/" + importPath)
952	tg.runGit(repoDir, "remote", "set-url", "origin", "git@github.com:rsc/go-get-issue-11457")
953
954	// At this time, custom import path checking compares remotes verbatim (rather than
955	// just the host and path, skipping scheme and user), so we expect go get -u to fail.
956	// However, the goal of this test is to verify that gitRemoteRepo correctly parsed
957	// the SCP-like syntax, and we expect it to appear in the error message.
958	tg.runFail("get", "-d", "-u", importPath)
959	want := " is checked out from ssh://git@github.com/rsc/go-get-issue-11457"
960	if !strings.HasSuffix(strings.TrimSpace(tg.getStderr()), want) {
961		t.Error("expected clone URL to appear in stderr")
962	}
963}
964
965func TestGetGitDefaultBranch(t *testing.T) {
966	testenv.MustHaveExternalNetwork(t)
967	testenv.MustHaveExecPath(t, "git")
968
969	tg := testgo(t)
970	defer tg.cleanup()
971	tg.parallel()
972	tg.tempDir("src")
973	tg.setenv("GOPATH", tg.path("."))
974
975	// This repo has two branches, master and another-branch.
976	// The another-branch is the default that you get from 'git clone'.
977	// The go get command variants should not override this.
978	const importPath = "github.com/rsc/go-get-default-branch"
979
980	tg.run("get", "-d", importPath)
981	repoDir := tg.path("src/" + importPath)
982	tg.runGit(repoDir, "branch", "--contains", "HEAD")
983	tg.grepStdout(`\* another-branch`, "not on correct default branch")
984
985	tg.run("get", "-d", "-u", importPath)
986	tg.runGit(repoDir, "branch", "--contains", "HEAD")
987	tg.grepStdout(`\* another-branch`, "not on correct default branch")
988}
989
990// Security issue. Don't disable. See golang.org/issue/22125.
991func TestAccidentalGitCheckout(t *testing.T) {
992	testenv.MustHaveExternalNetwork(t)
993	testenv.MustHaveExecPath(t, "git")
994	testenv.MustHaveExecPath(t, "svn")
995
996	tg := testgo(t)
997	defer tg.cleanup()
998	tg.parallel()
999	tg.tempDir("src")
1000
1001	tg.setenv("GOPATH", tg.path("."))
1002
1003	tg.runFail("get", "-u", "vcs-test.golang.org/go/test1-svn-git")
1004	tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason")
1005
1006	if _, err := os.Stat(tg.path("SrC")); err == nil {
1007		// This case only triggers on a case-insensitive file system.
1008		tg.runFail("get", "-u", "vcs-test.golang.org/go/test2-svn-git/test2main")
1009		tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason")
1010	}
1011}
1012
1013func TestPackageMainTestCompilerFlags(t *testing.T) {
1014	tg := testgo(t)
1015	defer tg.cleanup()
1016	tg.parallel()
1017	tg.makeTempdir()
1018	tg.setenv("GOPATH", tg.path("."))
1019	tg.tempFile("src/p1/p1.go", "package main\n")
1020	tg.tempFile("src/p1/p1_test.go", "package main\nimport \"testing\"\nfunc Test(t *testing.T){}\n")
1021	tg.run("test", "-c", "-n", "p1")
1022	tg.grepBothNot(`([\\/]compile|gccgo).* (-p main|-fgo-pkgpath=main).*p1\.go`, "should not have run compile -p main p1.go")
1023	tg.grepStderr(`([\\/]compile|gccgo).* (-p p1|-fgo-pkgpath=p1).*p1\.go`, "should have run compile -p p1 p1.go")
1024}
1025
1026// Issue 4104.
1027func TestGoTestWithPackageListedMultipleTimes(t *testing.T) {
1028	tooSlow(t)
1029	tg := testgo(t)
1030	defer tg.cleanup()
1031	tg.parallel()
1032	tg.run("test", "errors", "errors", "errors", "errors", "errors")
1033	if strings.Contains(strings.TrimSpace(tg.getStdout()), "\n") {
1034		t.Error("go test errors errors errors errors errors tested the same package multiple times")
1035	}
1036}
1037
1038func TestGoListHasAConsistentOrder(t *testing.T) {
1039	tooSlow(t)
1040	tg := testgo(t)
1041	defer tg.cleanup()
1042	tg.parallel()
1043	tg.run("list", "std")
1044	first := tg.getStdout()
1045	tg.run("list", "std")
1046	if first != tg.getStdout() {
1047		t.Error("go list std ordering is inconsistent")
1048	}
1049}
1050
1051func TestGoListStdDoesNotIncludeCommands(t *testing.T) {
1052	tooSlow(t)
1053	tg := testgo(t)
1054	defer tg.cleanup()
1055	tg.parallel()
1056	tg.run("list", "std")
1057	tg.grepStdoutNot("cmd/", "go list std shows commands")
1058}
1059
1060func TestGoListCmdOnlyShowsCommands(t *testing.T) {
1061	skipIfGccgo(t, "gccgo does not have GOROOT")
1062	tooSlow(t)
1063	tg := testgo(t)
1064	defer tg.cleanup()
1065	tg.parallel()
1066	tg.run("list", "cmd")
1067	out := strings.TrimSpace(tg.getStdout())
1068	for _, line := range strings.Split(out, "\n") {
1069		if !strings.Contains(line, "cmd/") {
1070			t.Error("go list cmd shows non-commands")
1071			break
1072		}
1073	}
1074}
1075
1076func TestGoListDeps(t *testing.T) {
1077	tg := testgo(t)
1078	defer tg.cleanup()
1079	tg.parallel()
1080	tg.tempDir("src/p1/p2/p3/p4")
1081	tg.setenv("GOPATH", tg.path("."))
1082	tg.tempFile("src/p1/p.go", "package p1\nimport _ \"p1/p2\"\n")
1083	tg.tempFile("src/p1/p2/p.go", "package p2\nimport _ \"p1/p2/p3\"\n")
1084	tg.tempFile("src/p1/p2/p3/p.go", "package p3\nimport _ \"p1/p2/p3/p4\"\n")
1085	tg.tempFile("src/p1/p2/p3/p4/p.go", "package p4\n")
1086	tg.run("list", "-f", "{{.Deps}}", "p1")
1087	tg.grepStdout("p1/p2/p3/p4", "Deps(p1) does not mention p4")
1088
1089	tg.run("list", "-deps", "p1")
1090	tg.grepStdout("p1/p2/p3/p4", "-deps p1 does not mention p4")
1091
1092	if runtime.Compiler != "gccgo" {
1093		// Check the list is in dependency order.
1094		tg.run("list", "-deps", "math")
1095		want := "internal/cpu\nunsafe\nmath/bits\nmath\n"
1096		out := tg.stdout.String()
1097		if !strings.Contains(out, "internal/cpu") {
1098			// Some systems don't use internal/cpu.
1099			want = "unsafe\nmath/bits\nmath\n"
1100		}
1101		if tg.stdout.String() != want {
1102			t.Fatalf("list -deps math: wrong order\nhave %q\nwant %q", tg.stdout.String(), want)
1103		}
1104	}
1105}
1106
1107func TestGoListTest(t *testing.T) {
1108	skipIfGccgo(t, "gccgo does not have standard packages")
1109	tg := testgo(t)
1110	defer tg.cleanup()
1111	tg.parallel()
1112	tg.makeTempdir()
1113	tg.setenv("GOCACHE", tg.tempdir)
1114
1115	tg.run("list", "-test", "-deps", "sort")
1116	tg.grepStdout(`^sort.test$`, "missing test main")
1117	tg.grepStdout(`^sort$`, "missing real sort")
1118	tg.grepStdout(`^sort \[sort.test\]$`, "missing test copy of sort")
1119	tg.grepStdout(`^testing \[sort.test\]$`, "missing test copy of testing")
1120	tg.grepStdoutNot(`^testing$`, "unexpected real copy of testing")
1121
1122	tg.run("list", "-test", "sort")
1123	tg.grepStdout(`^sort.test$`, "missing test main")
1124	tg.grepStdout(`^sort$`, "missing real sort")
1125	tg.grepStdout(`^sort \[sort.test\]$`, "unexpected test copy of sort")
1126	tg.grepStdoutNot(`^testing \[sort.test\]$`, "unexpected test copy of testing")
1127	tg.grepStdoutNot(`^testing$`, "unexpected real copy of testing")
1128
1129	tg.run("list", "-test", "cmd/dist", "cmd/doc")
1130	tg.grepStdout(`^cmd/dist$`, "missing cmd/dist")
1131	tg.grepStdout(`^cmd/doc$`, "missing cmd/doc")
1132	tg.grepStdout(`^cmd/doc\.test$`, "missing cmd/doc test")
1133	tg.grepStdoutNot(`^cmd/dist\.test$`, "unexpected cmd/dist test")
1134	tg.grepStdoutNot(`^testing`, "unexpected testing")
1135
1136	tg.run("list", "-test", "runtime/cgo")
1137	tg.grepStdout(`^runtime/cgo$`, "missing runtime/cgo")
1138
1139	tg.run("list", "-deps", "-f", "{{if .DepOnly}}{{.ImportPath}}{{end}}", "sort")
1140	tg.grepStdout(`^internal/reflectlite$`, "missing internal/reflectlite")
1141	tg.grepStdoutNot(`^sort`, "unexpected sort")
1142}
1143
1144func TestGoListCompiledCgo(t *testing.T) {
1145	tooSlow(t)
1146	tg := testgo(t)
1147	defer tg.cleanup()
1148	tg.parallel()
1149	tg.makeTempdir()
1150	tg.setenv("GOCACHE", tg.tempdir)
1151
1152	tg.run("list", "-f", `{{join .CgoFiles "\n"}}`, "net")
1153	if tg.stdout.String() == "" {
1154		t.Skip("net does not use cgo")
1155	}
1156	if strings.Contains(tg.stdout.String(), tg.tempdir) {
1157		t.Fatalf(".CgoFiles unexpectedly mentioned cache %s", tg.tempdir)
1158	}
1159	tg.run("list", "-compiled", "-f", `{{.Dir}}{{"\n"}}{{join .CompiledGoFiles "\n"}}`, "net")
1160	if !strings.Contains(tg.stdout.String(), tg.tempdir) {
1161		t.Fatalf(".CompiledGoFiles with -compiled did not mention cache %s", tg.tempdir)
1162	}
1163	dir := ""
1164	for _, file := range strings.Split(tg.stdout.String(), "\n") {
1165		if file == "" {
1166			continue
1167		}
1168		if dir == "" {
1169			dir = file
1170			continue
1171		}
1172		if !strings.Contains(file, "/") && !strings.Contains(file, `\`) {
1173			file = filepath.Join(dir, file)
1174		}
1175		if _, err := os.Stat(file); err != nil {
1176			t.Fatalf("cannot find .CompiledGoFiles result %s: %v", file, err)
1177		}
1178	}
1179}
1180
1181func TestGoListExport(t *testing.T) {
1182	skipIfGccgo(t, "gccgo does not have standard packages")
1183	tg := testgo(t)
1184	defer tg.cleanup()
1185	tg.parallel()
1186	tg.makeTempdir()
1187	tg.setenv("GOCACHE", tg.tempdir)
1188
1189	tg.run("list", "-f", "{{.Export}}", "strings")
1190	if tg.stdout.String() != "" {
1191		t.Fatalf(".Export without -export unexpectedly set")
1192	}
1193	tg.run("list", "-export", "-f", "{{.Export}}", "strings")
1194	file := strings.TrimSpace(tg.stdout.String())
1195	if file == "" {
1196		t.Fatalf(".Export with -export was empty")
1197	}
1198	if _, err := os.Stat(file); err != nil {
1199		t.Fatalf("cannot find .Export result %s: %v", file, err)
1200	}
1201
1202	tg.run("list", "-export", "-f", "{{.BuildID}}", "strings")
1203	buildID := strings.TrimSpace(tg.stdout.String())
1204	if buildID == "" {
1205		t.Fatalf(".BuildID with -export was empty")
1206	}
1207
1208	tg.run("tool", "buildid", file)
1209	toolBuildID := strings.TrimSpace(tg.stdout.String())
1210	if buildID != toolBuildID {
1211		t.Fatalf(".BuildID with -export %q disagrees with 'go tool buildid' %q", buildID, toolBuildID)
1212	}
1213}
1214
1215// Issue 4096. Validate the output of unsuccessful go install foo/quxx.
1216func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) {
1217	tg := testgo(t)
1218	defer tg.cleanup()
1219	tg.parallel()
1220	tg.runFail("install", "foo/quxx")
1221	if tg.grepCountBoth(`cannot find package "foo/quxx" in any of`) != 1 {
1222		t.Error(`go install foo/quxx expected error: .*cannot find package "foo/quxx" in any of`)
1223	}
1224}
1225
1226func TestGOROOTSearchFailureReporting(t *testing.T) {
1227	tg := testgo(t)
1228	defer tg.cleanup()
1229	tg.parallel()
1230	tg.runFail("install", "foo/quxx")
1231	if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("foo", "quxx"))+` \(from \$GOROOT\)$`) != 1 {
1232		t.Error(`go install foo/quxx expected error: .*foo/quxx (from $GOROOT)`)
1233	}
1234}
1235
1236func TestMultipleGOPATHEntriesReportedSeparately(t *testing.T) {
1237	tg := testgo(t)
1238	defer tg.cleanup()
1239	tg.parallel()
1240	sep := string(filepath.ListSeparator)
1241	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
1242	tg.runFail("install", "foo/quxx")
1243	if tg.grepCountBoth(`testdata[/\\].[/\\]src[/\\]foo[/\\]quxx`) != 2 {
1244		t.Error(`go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)\n.*testdata/b/src/foo/quxx`)
1245	}
1246}
1247
1248// Test (from $GOPATH) annotation is reported for the first GOPATH entry,
1249func TestMentionGOPATHInFirstGOPATHEntry(t *testing.T) {
1250	tg := testgo(t)
1251	defer tg.cleanup()
1252	tg.parallel()
1253	sep := string(filepath.ListSeparator)
1254	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
1255	tg.runFail("install", "foo/quxx")
1256	if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("testdata", "a", "src", "foo", "quxx"))+` \(from \$GOPATH\)$`) != 1 {
1257		t.Error(`go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)`)
1258	}
1259}
1260
1261// but not on the second.
1262func TestMentionGOPATHNotOnSecondEntry(t *testing.T) {
1263	tg := testgo(t)
1264	defer tg.cleanup()
1265	tg.parallel()
1266	sep := string(filepath.ListSeparator)
1267	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
1268	tg.runFail("install", "foo/quxx")
1269	if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("testdata", "b", "src", "foo", "quxx"))+`$`) != 1 {
1270		t.Error(`go install foo/quxx expected error: .*testdata/b/src/foo/quxx`)
1271	}
1272}
1273
1274func homeEnvName() string {
1275	switch runtime.GOOS {
1276	case "windows":
1277		return "USERPROFILE"
1278	case "plan9":
1279		return "home"
1280	default:
1281		return "HOME"
1282	}
1283}
1284
1285func tempEnvName() string {
1286	switch runtime.GOOS {
1287	case "windows":
1288		return "TMP"
1289	case "plan9":
1290		return "TMPDIR" // actually plan 9 doesn't have one at all but this is fine
1291	default:
1292		return "TMPDIR"
1293	}
1294}
1295
1296func TestDefaultGOPATH(t *testing.T) {
1297	tg := testgo(t)
1298	defer tg.cleanup()
1299	tg.parallel()
1300	tg.tempDir("home/go")
1301	tg.setenv(homeEnvName(), tg.path("home"))
1302
1303	tg.run("env", "GOPATH")
1304	tg.grepStdout(regexp.QuoteMeta(tg.path("home/go")), "want GOPATH=$HOME/go")
1305
1306	tg.setenv("GOROOT", tg.path("home/go"))
1307	tg.run("env", "GOPATH")
1308	tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go")
1309
1310	tg.setenv("GOROOT", tg.path("home/go")+"/")
1311	tg.run("env", "GOPATH")
1312	tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go/")
1313}
1314
1315func TestDefaultGOPATHGet(t *testing.T) {
1316	testenv.MustHaveExternalNetwork(t)
1317	testenv.MustHaveExecPath(t, "git")
1318
1319	tg := testgo(t)
1320	defer tg.cleanup()
1321	tg.parallel()
1322	tg.setenv("GOPATH", "")
1323	tg.tempDir("home")
1324	tg.setenv(homeEnvName(), tg.path("home"))
1325
1326	// warn for creating directory
1327	tg.run("get", "-v", "github.com/golang/example/hello")
1328	tg.grepStderr("created GOPATH="+regexp.QuoteMeta(tg.path("home/go"))+"; see 'go help gopath'", "did not create GOPATH")
1329
1330	// no warning if directory already exists
1331	tg.must(robustio.RemoveAll(tg.path("home/go")))
1332	tg.tempDir("home/go")
1333	tg.run("get", "github.com/golang/example/hello")
1334	tg.grepStderrNot(".", "expected no output on standard error")
1335
1336	// error if $HOME/go is a file
1337	tg.must(robustio.RemoveAll(tg.path("home/go")))
1338	tg.tempFile("home/go", "")
1339	tg.runFail("get", "github.com/golang/example/hello")
1340	tg.grepStderr(`mkdir .*[/\\]go: .*(not a directory|cannot find the path)`, "expected error because $HOME/go is a file")
1341}
1342
1343func TestDefaultGOPATHPrintedSearchList(t *testing.T) {
1344	tg := testgo(t)
1345	defer tg.cleanup()
1346	tg.parallel()
1347	tg.setenv("GOPATH", "")
1348	tg.tempDir("home")
1349	tg.setenv(homeEnvName(), tg.path("home"))
1350
1351	tg.runFail("install", "github.com/golang/example/hello")
1352	tg.grepStderr(regexp.QuoteMeta(tg.path("home/go/src/github.com/golang/example/hello"))+`.*from \$GOPATH`, "expected default GOPATH")
1353}
1354
1355func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
1356	skipIfGccgo(t, "gccgo does not support -ldflags -X")
1357	tooSlow(t)
1358	tg := testgo(t)
1359	defer tg.cleanup()
1360	tg.parallel()
1361	tg.tempFile("main.go", `package main
1362		var extern string
1363		func main() {
1364			println(extern)
1365		}`)
1366	tg.run("run", "-ldflags", `-X "main.extern=hello world"`, tg.path("main.go"))
1367	tg.grepStderr("^hello world", `ldflags -X "main.extern=hello world"' failed`)
1368}
1369
1370func TestLdFlagsLongArgumentsIssue42295(t *testing.T) {
1371	// Test the extremely long command line arguments that contain '\n' characters
1372	// get encoded and passed correctly.
1373	skipIfGccgo(t, "gccgo does not support -ldflags -X")
1374	tooSlow(t)
1375	tg := testgo(t)
1376	defer tg.cleanup()
1377	tg.parallel()
1378	tg.tempFile("main.go", `package main
1379		var extern string
1380		func main() {
1381			print(extern)
1382		}`)
1383	testStr := "test test test test test \n\\ "
1384	var buf bytes.Buffer
1385	for buf.Len() < work.ArgLengthForResponseFile+1 {
1386		buf.WriteString(testStr)
1387	}
1388	tg.run("run", "-ldflags", fmt.Sprintf(`-X "main.extern=%s"`, buf.String()), tg.path("main.go"))
1389	if tg.stderr.String() != buf.String() {
1390		t.Errorf("strings differ")
1391	}
1392}
1393
1394func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) {
1395	skipIfGccgo(t, "gccgo has no standard packages")
1396	tooSlow(t)
1397	tg := testgo(t)
1398	defer tg.cleanup()
1399	tg.parallel()
1400	tg.makeTempdir()
1401	tg.run("test", "-c", "-o", tg.path("myerrors.test"+exeSuffix), "errors")
1402	tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -c -o myerrors.test did not create myerrors.test")
1403}
1404
1405func TestGoTestDashOWritesBinary(t *testing.T) {
1406	skipIfGccgo(t, "gccgo has no standard packages")
1407	tooSlow(t)
1408	tg := testgo(t)
1409	defer tg.cleanup()
1410	tg.parallel()
1411	tg.makeTempdir()
1412	tg.run("test", "-o", tg.path("myerrors.test"+exeSuffix), "errors")
1413	tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test")
1414}
1415
1416func TestGoTestDashIDashOWritesBinary(t *testing.T) {
1417	skipIfGccgo(t, "gccgo has no standard packages")
1418	tooSlow(t)
1419	tg := testgo(t)
1420	defer tg.cleanup()
1421	tg.parallel()
1422	tg.makeTempdir()
1423
1424	// don't let test -i overwrite runtime
1425	tg.wantNotStale("runtime", "", "must be non-stale before test -i")
1426
1427	tg.run("test", "-v", "-i", "-o", tg.path("myerrors.test"+exeSuffix), "errors")
1428	tg.grepBothNot("PASS|FAIL", "test should not have run")
1429	tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test")
1430}
1431
1432// Issue 4515.
1433func TestInstallWithTags(t *testing.T) {
1434	tooSlow(t)
1435	tg := testgo(t)
1436	defer tg.cleanup()
1437	tg.parallel()
1438	tg.tempDir("bin")
1439	tg.tempFile("src/example/a/main.go", `package main
1440		func main() {}`)
1441	tg.tempFile("src/example/b/main.go", `// +build mytag
1442
1443		package main
1444		func main() {}`)
1445	tg.setenv("GOPATH", tg.path("."))
1446	tg.run("install", "-tags", "mytag", "example/a", "example/b")
1447	tg.wantExecutable(tg.path("bin/a"+exeSuffix), "go install example/a example/b did not install binaries")
1448	tg.wantExecutable(tg.path("bin/b"+exeSuffix), "go install example/a example/b did not install binaries")
1449	tg.must(os.Remove(tg.path("bin/a" + exeSuffix)))
1450	tg.must(os.Remove(tg.path("bin/b" + exeSuffix)))
1451	tg.run("install", "-tags", "mytag", "example/...")
1452	tg.wantExecutable(tg.path("bin/a"+exeSuffix), "go install example/... did not install binaries")
1453	tg.wantExecutable(tg.path("bin/b"+exeSuffix), "go install example/... did not install binaries")
1454	tg.run("list", "-tags", "mytag", "example/b...")
1455	if strings.TrimSpace(tg.getStdout()) != "example/b" {
1456		t.Error("go list example/b did not find example/b")
1457	}
1458}
1459
1460// Issue 17451, 17662.
1461func TestSymlinkWarning(t *testing.T) {
1462	tg := testgo(t)
1463	defer tg.cleanup()
1464	tg.parallel()
1465	tg.makeTempdir()
1466	tg.setenv("GOPATH", tg.path("."))
1467
1468	tg.tempDir("src/example/xx")
1469	tg.tempDir("yy/zz")
1470	tg.tempFile("yy/zz/zz.go", "package zz\n")
1471	if err := os.Symlink(tg.path("yy"), tg.path("src/example/xx/yy")); err != nil {
1472		t.Skipf("symlink failed: %v", err)
1473	}
1474	tg.run("list", "example/xx/z...")
1475	tg.grepStdoutNot(".", "list should not have matched anything")
1476	tg.grepStderr("matched no packages", "list should have reported that pattern matched no packages")
1477	tg.grepStderrNot("symlink", "list should not have reported symlink")
1478
1479	tg.run("list", "example/xx/...")
1480	tg.grepStdoutNot(".", "list should not have matched anything")
1481	tg.grepStderr("matched no packages", "list should have reported that pattern matched no packages")
1482	tg.grepStderr("ignoring symlink", "list should have reported symlink")
1483}
1484
1485func TestCgoShowsFullPathNames(t *testing.T) {
1486	if !canCgo {
1487		t.Skip("skipping because cgo not enabled")
1488	}
1489
1490	tg := testgo(t)
1491	defer tg.cleanup()
1492	tg.parallel()
1493	tg.tempFile("src/x/y/dirname/foo.go", `
1494		package foo
1495		import "C"
1496		func f() {`)
1497	tg.setenv("GOPATH", tg.path("."))
1498	tg.runFail("build", "x/y/dirname")
1499	tg.grepBoth("x/y/dirname", "error did not use full path")
1500}
1501
1502func TestCgoHandlesWlORIGIN(t *testing.T) {
1503	tooSlow(t)
1504	if !canCgo {
1505		t.Skip("skipping because cgo not enabled")
1506	}
1507
1508	tg := testgo(t)
1509	defer tg.cleanup()
1510	tg.parallel()
1511	tg.tempFile("src/origin/origin.go", `package origin
1512		// #cgo !darwin LDFLAGS: -Wl,-rpath,$ORIGIN
1513		// void f(void) {}
1514		import "C"
1515		func f() { C.f() }`)
1516	tg.setenv("GOPATH", tg.path("."))
1517	tg.run("build", "origin")
1518}
1519
1520func TestCgoPkgConfig(t *testing.T) {
1521	tooSlow(t)
1522	if !canCgo {
1523		t.Skip("skipping because cgo not enabled")
1524	}
1525	tg := testgo(t)
1526	defer tg.cleanup()
1527	tg.parallel()
1528
1529	tg.run("env", "PKG_CONFIG")
1530	pkgConfig := strings.TrimSpace(tg.getStdout())
1531	testenv.MustHaveExecPath(t, pkgConfig)
1532	if out, err := exec.Command(pkgConfig, "--atleast-pkgconfig-version", "0.24").CombinedOutput(); err != nil {
1533		t.Skipf("%s --atleast-pkgconfig-version 0.24: %v\n%s", pkgConfig, err, out)
1534	}
1535
1536	// OpenBSD's pkg-config is strict about whitespace and only
1537	// supports backslash-escaped whitespace. It does not support
1538	// quotes, which the normal freedesktop.org pkg-config does
1539	// support. See https://man.openbsd.org/pkg-config.1
1540	tg.tempFile("foo.pc", `
1541Name: foo
1542Description: The foo library
1543Version: 1.0.0
1544Cflags: -Dhello=10 -Dworld=+32 -DDEFINED_FROM_PKG_CONFIG=hello\ world
1545`)
1546	tg.tempFile("foo.go", `package main
1547
1548/*
1549#cgo pkg-config: foo
1550int value() {
1551	return DEFINED_FROM_PKG_CONFIG;
1552}
1553*/
1554import "C"
1555import "os"
1556
1557func main() {
1558	if C.value() != 42 {
1559		println("value() =", C.value(), "wanted 42")
1560		os.Exit(1)
1561	}
1562}
1563`)
1564	tg.setenv("PKG_CONFIG_PATH", tg.path("."))
1565	tg.run("run", tg.path("foo.go"))
1566}
1567
1568func TestListTemplateContextFunction(t *testing.T) {
1569	t.Parallel()
1570	for _, tt := range []struct {
1571		v    string
1572		want string
1573	}{
1574		{"GOARCH", runtime.GOARCH},
1575		{"GOOS", runtime.GOOS},
1576		{"GOROOT", filepath.Clean(runtime.GOROOT())},
1577		{"GOPATH", os.Getenv("GOPATH")},
1578		{"CgoEnabled", ""},
1579		{"UseAllFiles", ""},
1580		{"Compiler", ""},
1581		{"BuildTags", ""},
1582		{"ReleaseTags", ""},
1583		{"InstallSuffix", ""},
1584	} {
1585		tt := tt
1586		t.Run(tt.v, func(t *testing.T) {
1587			tg := testgo(t)
1588			tg.parallel()
1589			defer tg.cleanup()
1590			tmpl := "{{context." + tt.v + "}}"
1591			tg.run("list", "-f", tmpl)
1592			if tt.want == "" {
1593				return
1594			}
1595			if got := strings.TrimSpace(tg.getStdout()); got != tt.want {
1596				t.Errorf("go list -f %q: got %q; want %q", tmpl, got, tt.want)
1597			}
1598		})
1599	}
1600}
1601
1602// Test that you cannot use a local import in a package
1603// accessed by a non-local import (found in a GOPATH/GOROOT).
1604// See golang.org/issue/17475.
1605func TestImportLocal(t *testing.T) {
1606	tooSlow(t)
1607
1608	tg := testgo(t)
1609	tg.parallel()
1610	defer tg.cleanup()
1611
1612	tg.tempFile("src/dir/x/x.go", `package x
1613		var X int
1614	`)
1615	tg.setenv("GOPATH", tg.path("."))
1616	tg.run("build", "dir/x")
1617
1618	// Ordinary import should work.
1619	tg.tempFile("src/dir/p0/p.go", `package p0
1620		import "dir/x"
1621		var _ = x.X
1622	`)
1623	tg.run("build", "dir/p0")
1624
1625	// Relative import should not.
1626	tg.tempFile("src/dir/p1/p.go", `package p1
1627		import "../x"
1628		var _ = x.X
1629	`)
1630	tg.runFail("build", "dir/p1")
1631	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
1632
1633	// ... even in a test.
1634	tg.tempFile("src/dir/p2/p.go", `package p2
1635	`)
1636	tg.tempFile("src/dir/p2/p_test.go", `package p2
1637		import "../x"
1638		import "testing"
1639		var _ = x.X
1640		func TestFoo(t *testing.T) {}
1641	`)
1642	tg.run("build", "dir/p2")
1643	tg.runFail("test", "dir/p2")
1644	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
1645
1646	// ... even in an xtest.
1647	tg.tempFile("src/dir/p2/p_test.go", `package p2_test
1648		import "../x"
1649		import "testing"
1650		var _ = x.X
1651		func TestFoo(t *testing.T) {}
1652	`)
1653	tg.run("build", "dir/p2")
1654	tg.runFail("test", "dir/p2")
1655	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
1656
1657	// Relative import starting with ./ should not work either.
1658	tg.tempFile("src/dir/d.go", `package dir
1659		import "./x"
1660		var _ = x.X
1661	`)
1662	tg.runFail("build", "dir")
1663	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
1664
1665	// ... even in a test.
1666	tg.tempFile("src/dir/d.go", `package dir
1667	`)
1668	tg.tempFile("src/dir/d_test.go", `package dir
1669		import "./x"
1670		import "testing"
1671		var _ = x.X
1672		func TestFoo(t *testing.T) {}
1673	`)
1674	tg.run("build", "dir")
1675	tg.runFail("test", "dir")
1676	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
1677
1678	// ... even in an xtest.
1679	tg.tempFile("src/dir/d_test.go", `package dir_test
1680		import "./x"
1681		import "testing"
1682		var _ = x.X
1683		func TestFoo(t *testing.T) {}
1684	`)
1685	tg.run("build", "dir")
1686	tg.runFail("test", "dir")
1687	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
1688
1689	// Relative import plain ".." should not work.
1690	tg.tempFile("src/dir/x/y/y.go", `package dir
1691		import ".."
1692		var _ = x.X
1693	`)
1694	tg.runFail("build", "dir/x/y")
1695	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
1696
1697	// ... even in a test.
1698	tg.tempFile("src/dir/x/y/y.go", `package y
1699	`)
1700	tg.tempFile("src/dir/x/y/y_test.go", `package y
1701		import ".."
1702		import "testing"
1703		var _ = x.X
1704		func TestFoo(t *testing.T) {}
1705	`)
1706	tg.run("build", "dir/x/y")
1707	tg.runFail("test", "dir/x/y")
1708	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
1709
1710	// ... even in an x test.
1711	tg.tempFile("src/dir/x/y/y_test.go", `package y_test
1712		import ".."
1713		import "testing"
1714		var _ = x.X
1715		func TestFoo(t *testing.T) {}
1716	`)
1717	tg.run("build", "dir/x/y")
1718	tg.runFail("test", "dir/x/y")
1719	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
1720
1721	// Relative import "." should not work.
1722	tg.tempFile("src/dir/x/xx.go", `package x
1723		import "."
1724		var _ = x.X
1725	`)
1726	tg.runFail("build", "dir/x")
1727	tg.grepStderr("cannot import current directory", "did not diagnose import current directory")
1728
1729	// ... even in a test.
1730	tg.tempFile("src/dir/x/xx.go", `package x
1731	`)
1732	tg.tempFile("src/dir/x/xx_test.go", `package x
1733		import "."
1734		import "testing"
1735		var _ = x.X
1736		func TestFoo(t *testing.T) {}
1737	`)
1738	tg.run("build", "dir/x")
1739	tg.runFail("test", "dir/x")
1740	tg.grepStderr("cannot import current directory", "did not diagnose import current directory")
1741
1742	// ... even in an xtest.
1743	tg.tempFile("src/dir/x/xx.go", `package x
1744	`)
1745	tg.tempFile("src/dir/x/xx_test.go", `package x_test
1746		import "."
1747		import "testing"
1748		var _ = x.X
1749		func TestFoo(t *testing.T) {}
1750	`)
1751	tg.run("build", "dir/x")
1752	tg.runFail("test", "dir/x")
1753	tg.grepStderr("cannot import current directory", "did not diagnose import current directory")
1754}
1755
1756func TestGoInstallPkgdir(t *testing.T) {
1757	skipIfGccgo(t, "gccgo has no standard packages")
1758	tooSlow(t)
1759
1760	tg := testgo(t)
1761	tg.parallel()
1762	defer tg.cleanup()
1763	tg.makeTempdir()
1764	pkg := tg.path(".")
1765	tg.run("install", "-pkgdir", pkg, "sync")
1766	tg.mustExist(filepath.Join(pkg, "sync.a"))
1767	tg.mustNotExist(filepath.Join(pkg, "sync/atomic.a"))
1768	tg.run("install", "-i", "-pkgdir", pkg, "sync")
1769	tg.mustExist(filepath.Join(pkg, "sync.a"))
1770	tg.mustExist(filepath.Join(pkg, "sync/atomic.a"))
1771}
1772
1773// For issue 14337.
1774func TestParallelTest(t *testing.T) {
1775	tooSlow(t)
1776	tg := testgo(t)
1777	tg.parallel()
1778	defer tg.cleanup()
1779	tg.makeTempdir()
1780	const testSrc = `package package_test
1781		import (
1782			"testing"
1783		)
1784		func TestTest(t *testing.T) {
1785		}`
1786	tg.tempFile("src/p1/p1_test.go", strings.Replace(testSrc, "package_test", "p1_test", 1))
1787	tg.tempFile("src/p2/p2_test.go", strings.Replace(testSrc, "package_test", "p2_test", 1))
1788	tg.tempFile("src/p3/p3_test.go", strings.Replace(testSrc, "package_test", "p3_test", 1))
1789	tg.tempFile("src/p4/p4_test.go", strings.Replace(testSrc, "package_test", "p4_test", 1))
1790	tg.setenv("GOPATH", tg.path("."))
1791	tg.run("test", "-p=4", "p1", "p2", "p3", "p4")
1792}
1793
1794func TestBinaryOnlyPackages(t *testing.T) {
1795	tooSlow(t)
1796
1797	tg := testgo(t)
1798	defer tg.cleanup()
1799	tg.parallel()
1800	tg.makeTempdir()
1801	tg.setenv("GOPATH", tg.path("."))
1802
1803	tg.tempFile("src/p1/p1.go", `//go:binary-only-package
1804
1805		package p1
1806	`)
1807	tg.wantStale("p1", "binary-only packages are no longer supported", "p1 is binary-only, and this message should always be printed")
1808	tg.runFail("install", "p1")
1809	tg.grepStderr("binary-only packages are no longer supported", "did not report attempt to compile binary-only package")
1810
1811	tg.tempFile("src/p1/p1.go", `
1812		package p1
1813		import "fmt"
1814		func F(b bool) { fmt.Printf("hello from p1\n"); if b { F(false) } }
1815	`)
1816	tg.run("install", "p1")
1817	os.Remove(tg.path("src/p1/p1.go"))
1818	tg.mustNotExist(tg.path("src/p1/p1.go"))
1819
1820	tg.tempFile("src/p2/p2.go", `//go:binary-only-packages-are-not-great
1821
1822		package p2
1823		import "p1"
1824		func F() { p1.F(true) }
1825	`)
1826	tg.runFail("install", "p2")
1827	tg.grepStderr("no Go files", "did not complain about missing sources")
1828
1829	tg.tempFile("src/p1/missing.go", `//go:binary-only-package
1830
1831		package p1
1832		import _ "fmt"
1833		func G()
1834	`)
1835	tg.wantStale("p1", "binary-only package", "should NOT want to rebuild p1 (first)")
1836	tg.runFail("install", "p2")
1837	tg.grepStderr("p1: binary-only packages are no longer supported", "did not report error for binary-only p1")
1838
1839	tg.run("list", "-deps", "-f", "{{.ImportPath}}: {{.BinaryOnly}}", "p2")
1840	tg.grepStdout("p1: true", "p1 not listed as BinaryOnly")
1841	tg.grepStdout("p2: false", "p2 listed as BinaryOnly")
1842}
1843
1844// Issue 16050.
1845func TestAlwaysLinkSysoFiles(t *testing.T) {
1846	tg := testgo(t)
1847	defer tg.cleanup()
1848	tg.parallel()
1849	tg.tempDir("src/syso")
1850	tg.tempFile("src/syso/a.syso", ``)
1851	tg.tempFile("src/syso/b.go", `package syso`)
1852	tg.setenv("GOPATH", tg.path("."))
1853
1854	// We should see the .syso file regardless of the setting of
1855	// CGO_ENABLED.
1856
1857	tg.setenv("CGO_ENABLED", "1")
1858	tg.run("list", "-f", "{{.SysoFiles}}", "syso")
1859	tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=1")
1860
1861	tg.setenv("CGO_ENABLED", "0")
1862	tg.run("list", "-f", "{{.SysoFiles}}", "syso")
1863	tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=0")
1864}
1865
1866// Issue 16120.
1867func TestGenerateUsesBuildContext(t *testing.T) {
1868	if runtime.GOOS == "windows" {
1869		t.Skip("this test won't run under Windows")
1870	}
1871
1872	tg := testgo(t)
1873	defer tg.cleanup()
1874	tg.parallel()
1875	tg.tempDir("src/gen")
1876	tg.tempFile("src/gen/gen.go", "package gen\n//go:generate echo $GOOS $GOARCH\n")
1877	tg.setenv("GOPATH", tg.path("."))
1878
1879	tg.setenv("GOOS", "linux")
1880	tg.setenv("GOARCH", "amd64")
1881	tg.run("generate", "gen")
1882	tg.grepStdout("linux amd64", "unexpected GOOS/GOARCH combination")
1883
1884	tg.setenv("GOOS", "darwin")
1885	tg.setenv("GOARCH", "arm64")
1886	tg.run("generate", "gen")
1887	tg.grepStdout("darwin arm64", "unexpected GOOS/GOARCH combination")
1888}
1889
1890func TestGoEnv(t *testing.T) {
1891	tg := testgo(t)
1892	tg.parallel()
1893	defer tg.cleanup()
1894	tg.setenv("GOOS", "freebsd") // to avoid invalid pair errors
1895	tg.setenv("GOARCH", "arm")
1896	tg.run("env", "GOARCH")
1897	tg.grepStdout("^arm$", "GOARCH not honored")
1898
1899	tg.run("env", "GCCGO")
1900	tg.grepStdout(".", "GCCGO unexpectedly empty")
1901
1902	tg.run("env", "CGO_CFLAGS")
1903	tg.grepStdout(".", "default CGO_CFLAGS unexpectedly empty")
1904
1905	tg.setenv("CGO_CFLAGS", "-foobar")
1906	tg.run("env", "CGO_CFLAGS")
1907	tg.grepStdout("^-foobar$", "CGO_CFLAGS not honored")
1908
1909	tg.setenv("CC", "gcc -fmust -fgo -ffaster")
1910	tg.run("env", "CC")
1911	tg.grepStdout("gcc", "CC not found")
1912	tg.run("env", "GOGCCFLAGS")
1913	tg.grepStdout("-ffaster", "CC arguments not found")
1914
1915	tg.run("env", "GOVERSION")
1916	envVersion := strings.TrimSpace(tg.stdout.String())
1917
1918	tg.run("version")
1919	cmdVersion := strings.TrimSpace(tg.stdout.String())
1920
1921	// If 'go version' is "go version <version> <goos>/<goarch>", then
1922	// 'go env GOVERSION' is just "<version>".
1923	if cmdVersion == envVersion || !strings.Contains(cmdVersion, envVersion) {
1924		t.Fatalf("'go env GOVERSION' %q should be a shorter substring of 'go version' %q", envVersion, cmdVersion)
1925	}
1926}
1927
1928const (
1929	noMatchesPattern = `(?m)^ok.*\[no tests to run\]`
1930	okPattern        = `(?m)^ok`
1931)
1932
1933// Issue 18044.
1934func TestLdBindNow(t *testing.T) {
1935	tg := testgo(t)
1936	defer tg.cleanup()
1937	tg.parallel()
1938	tg.setenv("LD_BIND_NOW", "1")
1939	tg.run("help")
1940}
1941
1942// Issue 18225.
1943// This is really a cmd/asm issue but this is a convenient place to test it.
1944func TestConcurrentAsm(t *testing.T) {
1945	skipIfGccgo(t, "gccgo does not use cmd/asm")
1946	tg := testgo(t)
1947	defer tg.cleanup()
1948	tg.parallel()
1949	asm := `DATA ·constants<>+0x0(SB)/8,$0
1950GLOBL ·constants<>(SB),8,$8
1951`
1952	tg.tempFile("go/src/p/a.s", asm)
1953	tg.tempFile("go/src/p/b.s", asm)
1954	tg.tempFile("go/src/p/p.go", `package p`)
1955	tg.setenv("GOPATH", tg.path("go"))
1956	tg.run("build", "p")
1957}
1958
1959// Issue 18975.
1960func TestFFLAGS(t *testing.T) {
1961	if !canCgo {
1962		t.Skip("skipping because cgo not enabled")
1963	}
1964
1965	tg := testgo(t)
1966	defer tg.cleanup()
1967	tg.parallel()
1968
1969	tg.tempFile("p/src/p/main.go", `package main
1970		// #cgo FFLAGS: -no-such-fortran-flag
1971		import "C"
1972		func main() {}
1973	`)
1974	tg.tempFile("p/src/p/a.f", `! comment`)
1975	tg.setenv("GOPATH", tg.path("p"))
1976
1977	// This should normally fail because we are passing an unknown flag,
1978	// but issue #19080 points to Fortran compilers that succeed anyhow.
1979	// To work either way we call doRun directly rather than run or runFail.
1980	tg.doRun([]string{"build", "-x", "p"})
1981
1982	tg.grepStderr("no-such-fortran-flag", `missing expected "-no-such-fortran-flag"`)
1983}
1984
1985// Issue 19198.
1986// This is really a cmd/link issue but this is a convenient place to test it.
1987func TestDuplicateGlobalAsmSymbols(t *testing.T) {
1988	skipIfGccgo(t, "gccgo does not use cmd/asm")
1989	tooSlow(t)
1990	if runtime.GOARCH != "386" && runtime.GOARCH != "amd64" {
1991		t.Skipf("skipping test on %s", runtime.GOARCH)
1992	}
1993	if !canCgo {
1994		t.Skip("skipping because cgo not enabled")
1995	}
1996
1997	tg := testgo(t)
1998	defer tg.cleanup()
1999	tg.parallel()
2000
2001	asm := `
2002#include "textflag.h"
2003
2004DATA sym<>+0x0(SB)/8,$0
2005GLOBL sym<>(SB),(NOPTR+RODATA),$8
2006
2007TEXT ·Data(SB),NOSPLIT,$0
2008	MOVB sym<>(SB), AX
2009	MOVB AX, ret+0(FP)
2010	RET
2011`
2012	tg.tempFile("go/src/a/a.s", asm)
2013	tg.tempFile("go/src/a/a.go", `package a; func Data() uint8`)
2014	tg.tempFile("go/src/b/b.s", asm)
2015	tg.tempFile("go/src/b/b.go", `package b; func Data() uint8`)
2016	tg.tempFile("go/src/p/p.go", `
2017package main
2018import "a"
2019import "b"
2020import "C"
2021func main() {
2022	_ = a.Data() + b.Data()
2023}
2024`)
2025	tg.setenv("GOPATH", tg.path("go"))
2026	exe := tg.path("p.exe")
2027	tg.creatingTemp(exe)
2028	tg.run("build", "-o", exe, "p")
2029}
2030
2031func copyFile(src, dst string, perm fs.FileMode) error {
2032	sf, err := os.Open(src)
2033	if err != nil {
2034		return err
2035	}
2036	defer sf.Close()
2037
2038	df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
2039	if err != nil {
2040		return err
2041	}
2042
2043	_, err = io.Copy(df, sf)
2044	err2 := df.Close()
2045	if err != nil {
2046		return err
2047	}
2048	return err2
2049}
2050
2051func TestNeedVersion(t *testing.T) {
2052	skipIfGccgo(t, "gccgo does not use cmd/compile")
2053	tg := testgo(t)
2054	defer tg.cleanup()
2055	tg.parallel()
2056	tg.tempFile("goversion.go", `package main; func main() {}`)
2057	path := tg.path("goversion.go")
2058	tg.setenv("TESTGO_VERSION", "go1.testgo")
2059	tg.runFail("run", path)
2060	tg.grepStderr("compile", "does not match go tool version")
2061}
2062
2063func TestBuildmodePIE(t *testing.T) {
2064	if testing.Short() && testenv.Builder() == "" {
2065		t.Skipf("skipping in -short mode on non-builder")
2066	}
2067
2068	platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
2069	switch platform {
2070	case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/riscv64", "linux/s390x",
2071		"android/amd64", "android/arm", "android/arm64", "android/386",
2072		"freebsd/amd64",
2073		"windows/386", "windows/amd64", "windows/arm":
2074	case "darwin/amd64":
2075	default:
2076		t.Skipf("skipping test because buildmode=pie is not supported on %s", platform)
2077	}
2078	t.Run("non-cgo", func(t *testing.T) {
2079		testBuildmodePIE(t, false, true)
2080	})
2081	if canCgo {
2082		switch runtime.GOOS {
2083		case "darwin", "freebsd", "linux", "windows":
2084			t.Run("cgo", func(t *testing.T) {
2085				testBuildmodePIE(t, true, true)
2086			})
2087		}
2088	}
2089}
2090
2091func TestWindowsDefaultBuildmodIsPIE(t *testing.T) {
2092	if testing.Short() && testenv.Builder() == "" {
2093		t.Skipf("skipping in -short mode on non-builder")
2094	}
2095
2096	if runtime.GOOS != "windows" {
2097		t.Skip("skipping windows only test")
2098	}
2099
2100	t.Run("non-cgo", func(t *testing.T) {
2101		testBuildmodePIE(t, false, false)
2102	})
2103	if canCgo {
2104		t.Run("cgo", func(t *testing.T) {
2105			testBuildmodePIE(t, true, false)
2106		})
2107	}
2108}
2109
2110func testBuildmodePIE(t *testing.T, useCgo, setBuildmodeToPIE bool) {
2111	tg := testgo(t)
2112	defer tg.cleanup()
2113	tg.parallel()
2114
2115	var s string
2116	if useCgo {
2117		s = `import "C";`
2118	}
2119	tg.tempFile("main.go", fmt.Sprintf(`package main;%s func main() { print("hello") }`, s))
2120	src := tg.path("main.go")
2121	obj := tg.path("main.exe")
2122	args := []string{"build"}
2123	if setBuildmodeToPIE {
2124		args = append(args, "-buildmode=pie")
2125	}
2126	args = append(args, "-o", obj, src)
2127	tg.run(args...)
2128
2129	switch runtime.GOOS {
2130	case "linux", "android", "freebsd":
2131		f, err := elf.Open(obj)
2132		if err != nil {
2133			t.Fatal(err)
2134		}
2135		defer f.Close()
2136		if f.Type != elf.ET_DYN {
2137			t.Errorf("PIE type must be ET_DYN, but %s", f.Type)
2138		}
2139	case "darwin":
2140		f, err := macho.Open(obj)
2141		if err != nil {
2142			t.Fatal(err)
2143		}
2144		defer f.Close()
2145		if f.Flags&macho.FlagDyldLink == 0 {
2146			t.Error("PIE must have DyldLink flag, but not")
2147		}
2148		if f.Flags&macho.FlagPIE == 0 {
2149			t.Error("PIE must have PIE flag, but not")
2150		}
2151	case "windows":
2152		f, err := pe.Open(obj)
2153		if err != nil {
2154			t.Fatal(err)
2155		}
2156		defer f.Close()
2157		if f.Section(".reloc") == nil {
2158			t.Error(".reloc section is not present")
2159		}
2160		if (f.FileHeader.Characteristics & pe.IMAGE_FILE_RELOCS_STRIPPED) != 0 {
2161			t.Error("IMAGE_FILE_RELOCS_STRIPPED flag is set")
2162		}
2163		var dc uint16
2164		switch oh := f.OptionalHeader.(type) {
2165		case *pe.OptionalHeader32:
2166			dc = oh.DllCharacteristics
2167		case *pe.OptionalHeader64:
2168			dc = oh.DllCharacteristics
2169			if (dc & pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) == 0 {
2170				t.Error("IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA flag is not set")
2171			}
2172		default:
2173			t.Fatalf("unexpected optional header type of %T", f.OptionalHeader)
2174		}
2175		if (dc & pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) == 0 {
2176			t.Error("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag is not set")
2177		}
2178		if useCgo {
2179			// Test that only one symbol is exported (#40795).
2180			// PIE binaries don´t require .edata section but unfortunately
2181			// binutils doesn´t generate a .reloc section unless there is
2182			// at least one symbol exported.
2183			// See https://sourceware.org/bugzilla/show_bug.cgi?id=19011
2184			section := f.Section(".edata")
2185			if section == nil {
2186				t.Fatalf(".edata section is not present")
2187			}
2188			// TODO: deduplicate this struct from cmd/link/internal/ld/pe.go
2189			type IMAGE_EXPORT_DIRECTORY struct {
2190				_                 [2]uint32
2191				_                 [2]uint16
2192				_                 [2]uint32
2193				NumberOfFunctions uint32
2194				NumberOfNames     uint32
2195				_                 [3]uint32
2196			}
2197			var e IMAGE_EXPORT_DIRECTORY
2198			if err := binary.Read(section.Open(), binary.LittleEndian, &e); err != nil {
2199				t.Fatalf("binary.Read failed: %v", err)
2200			}
2201
2202			// Only _cgo_dummy_export should be exported
2203			if e.NumberOfFunctions != 1 {
2204				t.Fatalf("got %d exported functions; want 1", e.NumberOfFunctions)
2205			}
2206			if e.NumberOfNames != 1 {
2207				t.Fatalf("got %d exported names; want 1", e.NumberOfNames)
2208			}
2209		}
2210	default:
2211		panic("unreachable")
2212	}
2213
2214	out, err := exec.Command(obj).CombinedOutput()
2215	if err != nil {
2216		t.Fatal(err)
2217	}
2218
2219	if string(out) != "hello" {
2220		t.Errorf("got %q; want %q", out, "hello")
2221	}
2222}
2223
2224func TestUpxCompression(t *testing.T) {
2225	if runtime.GOOS != "linux" ||
2226		(runtime.GOARCH != "amd64" && runtime.GOARCH != "386") {
2227		t.Skipf("skipping upx test on %s/%s", runtime.GOOS, runtime.GOARCH)
2228	}
2229
2230	testenv.MustHaveExecPath(t, "upx")
2231	out, err := exec.Command("upx", "--version").CombinedOutput()
2232	if err != nil {
2233		t.Fatalf("upx --version failed: %v", err)
2234	}
2235
2236	// upx --version prints `upx <version>` in the first line of output:
2237	//   upx 3.94
2238	//   [...]
2239	re := regexp.MustCompile(`([[:digit:]]+)\.([[:digit:]]+)`)
2240	upxVersion := re.FindStringSubmatch(string(out))
2241	if len(upxVersion) != 3 {
2242		t.Fatalf("bad upx version string: %s", upxVersion)
2243	}
2244
2245	major, err1 := strconv.Atoi(upxVersion[1])
2246	minor, err2 := strconv.Atoi(upxVersion[2])
2247	if err1 != nil || err2 != nil {
2248		t.Fatalf("bad upx version string: %s", upxVersion[0])
2249	}
2250
2251	// Anything below 3.94 is known not to work with go binaries
2252	if (major < 3) || (major == 3 && minor < 94) {
2253		t.Skipf("skipping because upx version %v.%v is too old", major, minor)
2254	}
2255
2256	tg := testgo(t)
2257	defer tg.cleanup()
2258	tg.parallel()
2259
2260	tg.tempFile("main.go", `package main; import "fmt"; func main() { fmt.Print("hello upx") }`)
2261	src := tg.path("main.go")
2262	obj := tg.path("main")
2263	tg.run("build", "-o", obj, src)
2264
2265	out, err = exec.Command("upx", obj).CombinedOutput()
2266	if err != nil {
2267		t.Logf("executing upx\n%s\n", out)
2268		t.Fatalf("upx failed with %v", err)
2269	}
2270
2271	out, err = exec.Command(obj).CombinedOutput()
2272	if err != nil {
2273		t.Logf("%s", out)
2274		t.Fatalf("running compressed go binary failed with error %s", err)
2275	}
2276	if string(out) != "hello upx" {
2277		t.Fatalf("bad output from compressed go binary:\ngot %q; want %q", out, "hello upx")
2278	}
2279}
2280
2281func TestCacheListStale(t *testing.T) {
2282	tooSlow(t)
2283	if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
2284		t.Skip("GODEBUG gocacheverify")
2285	}
2286	tg := testgo(t)
2287	defer tg.cleanup()
2288	tg.parallel()
2289	tg.makeTempdir()
2290	tg.setenv("GOCACHE", tg.path("cache"))
2291	tg.tempFile("gopath/src/p/p.go", "package p; import _ \"q\"; func F(){}\n")
2292	tg.tempFile("gopath/src/q/q.go", "package q; func F(){}\n")
2293	tg.tempFile("gopath/src/m/m.go", "package main; import _ \"q\"; func main(){}\n")
2294
2295	tg.setenv("GOPATH", tg.path("gopath"))
2296	tg.run("install", "p", "m")
2297	tg.run("list", "-f={{.ImportPath}} {{.Stale}}", "m", "q", "p")
2298	tg.grepStdout("^m false", "m should not be stale")
2299	tg.grepStdout("^q true", "q should be stale")
2300	tg.grepStdout("^p false", "p should not be stale")
2301}
2302
2303func TestCacheCoverage(t *testing.T) {
2304	tooSlow(t)
2305
2306	if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
2307		t.Skip("GODEBUG gocacheverify")
2308	}
2309
2310	tg := testgo(t)
2311	defer tg.cleanup()
2312	tg.parallel()
2313	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
2314	tg.makeTempdir()
2315
2316	tg.setenv("GOCACHE", tg.path("c1"))
2317	tg.run("test", "-cover", "-short", "strings")
2318	tg.run("test", "-cover", "-short", "math", "strings")
2319}
2320
2321func TestIssue22588(t *testing.T) {
2322	// Don't get confused by stderr coming from tools.
2323	tg := testgo(t)
2324	defer tg.cleanup()
2325	tg.parallel()
2326
2327	if _, err := os.Stat("/usr/bin/time"); err != nil {
2328		t.Skip(err)
2329	}
2330
2331	tg.run("list", "-f={{.Stale}}", "runtime")
2332	tg.run("list", "-toolexec=/usr/bin/time", "-f={{.Stale}}", "runtime")
2333	tg.grepStdout("false", "incorrectly reported runtime as stale")
2334}
2335
2336func TestIssue22531(t *testing.T) {
2337	tooSlow(t)
2338	if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
2339		t.Skip("GODEBUG gocacheverify")
2340	}
2341	tg := testgo(t)
2342	defer tg.cleanup()
2343	tg.parallel()
2344	tg.makeTempdir()
2345	tg.setenv("GOPATH", tg.tempdir)
2346	tg.setenv("GOCACHE", tg.path("cache"))
2347	tg.tempFile("src/m/main.go", "package main /* c1 */; func main() {}\n")
2348	tg.run("install", "-x", "m")
2349	tg.run("list", "-f", "{{.Stale}}", "m")
2350	tg.grepStdout("false", "reported m as stale after install")
2351	tg.run("tool", "buildid", tg.path("bin/m"+exeSuffix))
2352
2353	// The link action ID did not include the full main build ID,
2354	// even though the full main build ID is written into the
2355	// eventual binary. That caused the following install to
2356	// be a no-op, thinking the gofmt binary was up-to-date,
2357	// even though .Stale could see it was not.
2358	tg.tempFile("src/m/main.go", "package main /* c2 */; func main() {}\n")
2359	tg.run("install", "-x", "m")
2360	tg.run("list", "-f", "{{.Stale}}", "m")
2361	tg.grepStdout("false", "reported m as stale after reinstall")
2362	tg.run("tool", "buildid", tg.path("bin/m"+exeSuffix))
2363}
2364
2365func TestIssue22596(t *testing.T) {
2366	tooSlow(t)
2367	if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
2368		t.Skip("GODEBUG gocacheverify")
2369	}
2370	tg := testgo(t)
2371	defer tg.cleanup()
2372	tg.parallel()
2373	tg.makeTempdir()
2374	tg.setenv("GOCACHE", tg.path("cache"))
2375	tg.tempFile("gopath1/src/p/p.go", "package p; func F(){}\n")
2376	tg.tempFile("gopath2/src/p/p.go", "package p; func F(){}\n")
2377
2378	tg.setenv("GOPATH", tg.path("gopath1"))
2379	tg.run("list", "-f={{.Target}}", "p")
2380	target1 := strings.TrimSpace(tg.getStdout())
2381	tg.run("install", "p")
2382	tg.wantNotStale("p", "", "p stale after install")
2383
2384	tg.setenv("GOPATH", tg.path("gopath2"))
2385	tg.run("list", "-f={{.Target}}", "p")
2386	target2 := strings.TrimSpace(tg.getStdout())
2387	tg.must(os.MkdirAll(filepath.Dir(target2), 0777))
2388	tg.must(copyFile(target1, target2, 0666))
2389	tg.wantStale("p", "build ID mismatch", "p not stale after copy from gopath1")
2390	tg.run("install", "p")
2391	tg.wantNotStale("p", "", "p stale after install2")
2392}
2393
2394func TestTestCache(t *testing.T) {
2395	tooSlow(t)
2396
2397	if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
2398		t.Skip("GODEBUG gocacheverify")
2399	}
2400	tg := testgo(t)
2401	defer tg.cleanup()
2402	tg.parallel()
2403	tg.makeTempdir()
2404	tg.setenv("GOPATH", tg.tempdir)
2405	tg.setenv("GOCACHE", tg.path("cache"))
2406
2407	// The -p=1 in the commands below just makes the -x output easier to read.
2408
2409	t.Log("\n\nINITIAL\n\n")
2410
2411	tg.tempFile("src/p1/p1.go", "package p1\nvar X =  1\n")
2412	tg.tempFile("src/p2/p2.go", "package p2\nimport _ \"p1\"\nvar X = 1\n")
2413	tg.tempFile("src/t/t1/t1_test.go", "package t\nimport \"testing\"\nfunc Test1(*testing.T) {}\n")
2414	tg.tempFile("src/t/t2/t2_test.go", "package t\nimport _ \"p1\"\nimport \"testing\"\nfunc Test2(*testing.T) {}\n")
2415	tg.tempFile("src/t/t3/t3_test.go", "package t\nimport \"p1\"\nimport \"testing\"\nfunc Test3(t *testing.T) {t.Log(p1.X)}\n")
2416	tg.tempFile("src/t/t4/t4_test.go", "package t\nimport \"p2\"\nimport \"testing\"\nfunc Test4(t *testing.T) {t.Log(p2.X)}")
2417	tg.run("test", "-x", "-v", "-short", "t/...")
2418
2419	t.Log("\n\nREPEAT\n\n")
2420
2421	tg.run("test", "-x", "-v", "-short", "t/...")
2422	tg.grepStdout(`ok  \tt/t1\t\(cached\)`, "did not cache t1")
2423	tg.grepStdout(`ok  \tt/t2\t\(cached\)`, "did not cache t2")
2424	tg.grepStdout(`ok  \tt/t3\t\(cached\)`, "did not cache t3")
2425	tg.grepStdout(`ok  \tt/t4\t\(cached\)`, "did not cache t4")
2426	tg.grepStderrNot(`[\\/](compile|gccgo) `, "incorrectly ran compiler")
2427	tg.grepStderrNot(`[\\/](link|gccgo) `, "incorrectly ran linker")
2428	tg.grepStderrNot(`p[0-9]\.test`, "incorrectly ran test")
2429
2430	t.Log("\n\nCOMMENT\n\n")
2431
2432	// Changing the program text without affecting the compiled package
2433	// should result in the package being rebuilt but nothing more.
2434	tg.tempFile("src/p1/p1.go", "package p1\nvar X = 01\n")
2435	tg.run("test", "-p=1", "-x", "-v", "-short", "t/...")
2436	tg.grepStdout(`ok  \tt/t1\t\(cached\)`, "did not cache t1")
2437	tg.grepStdout(`ok  \tt/t2\t\(cached\)`, "did not cache t2")
2438	tg.grepStdout(`ok  \tt/t3\t\(cached\)`, "did not cache t3")
2439	tg.grepStdout(`ok  \tt/t4\t\(cached\)`, "did not cache t4")
2440	tg.grepStderrNot(`([\\/](compile|gccgo) ).*t[0-9]_test\.go`, "incorrectly ran compiler")
2441	tg.grepStderrNot(`[\\/](link|gccgo) `, "incorrectly ran linker")
2442	tg.grepStderrNot(`t[0-9]\.test.*test\.short`, "incorrectly ran test")
2443
2444	t.Log("\n\nCHANGE\n\n")
2445
2446	// Changing the actual package should have limited effects.
2447	tg.tempFile("src/p1/p1.go", "package p1\nvar X = 02\n")
2448	tg.run("test", "-p=1", "-x", "-v", "-short", "t/...")
2449
2450	// p2 should have been rebuilt.
2451	tg.grepStderr(`([\\/]compile|gccgo).*p2.go`, "did not recompile p2")
2452
2453	// t1 does not import anything, should not have been rebuilt.
2454	tg.grepStderrNot(`([\\/]compile|gccgo).*t1_test.go`, "incorrectly recompiled t1")
2455	tg.grepStderrNot(`([\\/]link|gccgo).*t1_test`, "incorrectly relinked t1_test")
2456	tg.grepStdout(`ok  \tt/t1\t\(cached\)`, "did not cache t/t1")
2457
2458	// t2 imports p1 and must be rebuilt and relinked,
2459	// but the change should not have any effect on the test binary,
2460	// so the test should not have been rerun.
2461	tg.grepStderr(`([\\/]compile|gccgo).*t2_test.go`, "did not recompile t2")
2462	tg.grepStderr(`([\\/]link|gccgo).*t2\.test`, "did not relink t2_test")
2463	// This check does not currently work with gccgo, as garbage
2464	// collection of unused variables is not turned on by default.
2465	if runtime.Compiler != "gccgo" {
2466		tg.grepStdout(`ok  \tt/t2\t\(cached\)`, "did not cache t/t2")
2467	}
2468
2469	// t3 imports p1, and changing X changes t3's test binary.
2470	tg.grepStderr(`([\\/]compile|gccgo).*t3_test.go`, "did not recompile t3")
2471	tg.grepStderr(`([\\/]link|gccgo).*t3\.test`, "did not relink t3_test")
2472	tg.grepStderr(`t3\.test.*-test.short`, "did not rerun t3_test")
2473	tg.grepStdoutNot(`ok  \tt/t3\t\(cached\)`, "reported cached t3_test result")
2474
2475	// t4 imports p2, but p2 did not change, so t4 should be relinked, not recompiled,
2476	// and not rerun.
2477	tg.grepStderrNot(`([\\/]compile|gccgo).*t4_test.go`, "incorrectly recompiled t4")
2478	tg.grepStderr(`([\\/]link|gccgo).*t4\.test`, "did not relink t4_test")
2479	// This check does not currently work with gccgo, as garbage
2480	// collection of unused variables is not turned on by default.
2481	if runtime.Compiler != "gccgo" {
2482		tg.grepStdout(`ok  \tt/t4\t\(cached\)`, "did not cache t/t4")
2483	}
2484}
2485
2486func TestTestSkipVetAfterFailedBuild(t *testing.T) {
2487	tg := testgo(t)
2488	defer tg.cleanup()
2489	tg.parallel()
2490
2491	tg.tempFile("x_test.go", `package x
2492		func f() {
2493			return 1
2494		}
2495	`)
2496
2497	tg.runFail("test", tg.path("x_test.go"))
2498	tg.grepStderrNot(`vet`, "vet should be skipped after the failed build")
2499}
2500
2501func TestTestVetRebuild(t *testing.T) {
2502	tooSlow(t)
2503	tg := testgo(t)
2504	defer tg.cleanup()
2505	tg.parallel()
2506
2507	// golang.org/issue/23701.
2508	// b_test imports b with augmented method from export_test.go.
2509	// b_test also imports a, which imports b.
2510	// Must not accidentally see un-augmented b propagate through a to b_test.
2511	tg.tempFile("src/a/a.go", `package a
2512		import "b"
2513		type Type struct{}
2514		func (*Type) M() b.T {return 0}
2515	`)
2516	tg.tempFile("src/b/b.go", `package b
2517		type T int
2518		type I interface {M() T}
2519	`)
2520	tg.tempFile("src/b/export_test.go", `package b
2521		func (*T) Method() *T { return nil }
2522	`)
2523	tg.tempFile("src/b/b_test.go", `package b_test
2524		import (
2525			"testing"
2526			"a"
2527			. "b"
2528		)
2529		func TestBroken(t *testing.T) {
2530			x := new(T)
2531			x.Method()
2532			_ = new(a.Type)
2533		}
2534	`)
2535
2536	tg.setenv("GOPATH", tg.path("."))
2537	tg.run("test", "b")
2538	tg.run("vet", "b")
2539}
2540
2541func TestInstallDeps(t *testing.T) {
2542	tooSlow(t)
2543	tg := testgo(t)
2544	defer tg.cleanup()
2545	tg.parallel()
2546	tg.makeTempdir()
2547	tg.setenv("GOPATH", tg.tempdir)
2548
2549	tg.tempFile("src/p1/p1.go", "package p1\nvar X =  1\n")
2550	tg.tempFile("src/p2/p2.go", "package p2\nimport _ \"p1\"\n")
2551	tg.tempFile("src/main1/main.go", "package main\nimport _ \"p2\"\nfunc main() {}\n")
2552
2553	tg.run("list", "-f={{.Target}}", "p1")
2554	p1 := strings.TrimSpace(tg.getStdout())
2555	tg.run("list", "-f={{.Target}}", "p2")
2556	p2 := strings.TrimSpace(tg.getStdout())
2557	tg.run("list", "-f={{.Target}}", "main1")
2558	main1 := strings.TrimSpace(tg.getStdout())
2559
2560	tg.run("install", "main1")
2561
2562	tg.mustExist(main1)
2563	tg.mustNotExist(p2)
2564	tg.mustNotExist(p1)
2565
2566	tg.run("install", "p2")
2567	tg.mustExist(p2)
2568	tg.mustNotExist(p1)
2569
2570	// don't let install -i overwrite runtime
2571	tg.wantNotStale("runtime", "", "must be non-stale before install -i")
2572
2573	tg.run("install", "-i", "main1")
2574	tg.mustExist(p1)
2575	tg.must(os.Remove(p1))
2576
2577	tg.run("install", "-i", "p2")
2578	tg.mustExist(p1)
2579}
2580
2581// Issue 22986.
2582func TestImportPath(t *testing.T) {
2583	tooSlow(t)
2584	tg := testgo(t)
2585	defer tg.cleanup()
2586	tg.parallel()
2587
2588	tg.tempFile("src/a/a.go", `
2589package main
2590
2591import (
2592	"log"
2593	p "a/p-1.0"
2594)
2595
2596func main() {
2597	if !p.V {
2598		log.Fatal("false")
2599	}
2600}`)
2601
2602	tg.tempFile("src/a/a_test.go", `
2603package main_test
2604
2605import (
2606	p "a/p-1.0"
2607	"testing"
2608)
2609
2610func TestV(t *testing.T) {
2611	if !p.V {
2612		t.Fatal("false")
2613	}
2614}`)
2615
2616	tg.tempFile("src/a/p-1.0/p.go", `
2617package p
2618
2619var V = true
2620
2621func init() {}
2622`)
2623
2624	tg.setenv("GOPATH", tg.path("."))
2625	tg.run("build", "-o", tg.path("a.exe"), "a")
2626	tg.run("test", "a")
2627}
2628
2629func TestBadCommandLines(t *testing.T) {
2630	tg := testgo(t)
2631	defer tg.cleanup()
2632	tg.parallel()
2633
2634	tg.tempFile("src/x/x.go", "package x\n")
2635	tg.setenv("GOPATH", tg.path("."))
2636
2637	tg.run("build", "x")
2638
2639	tg.tempFile("src/x/@y.go", "package x\n")
2640	tg.runFail("build", "x")
2641	tg.grepStderr("invalid input file name \"@y.go\"", "did not reject @y.go")
2642	tg.must(os.Remove(tg.path("src/x/@y.go")))
2643
2644	tg.tempFile("src/x/-y.go", "package x\n")
2645	tg.runFail("build", "x")
2646	tg.grepStderr("invalid input file name \"-y.go\"", "did not reject -y.go")
2647	tg.must(os.Remove(tg.path("src/x/-y.go")))
2648
2649	if runtime.Compiler == "gccgo" {
2650		tg.runFail("build", "-gccgoflags=all=@x", "x")
2651	} else {
2652		tg.runFail("build", "-gcflags=all=@x", "x")
2653	}
2654	tg.grepStderr("invalid command-line argument @x in command", "did not reject @x during exec")
2655
2656	tg.tempFile("src/@x/x.go", "package x\n")
2657	tg.setenv("GOPATH", tg.path("."))
2658	tg.runFail("build", "@x")
2659	tg.grepStderr("invalid input directory name \"@x\"|can only use path@version syntax with 'go get' and 'go install' in module-aware mode", "did not reject @x directory")
2660
2661	tg.tempFile("src/@x/y/y.go", "package y\n")
2662	tg.setenv("GOPATH", tg.path("."))
2663	tg.runFail("build", "@x/y")
2664	tg.grepStderr("invalid import path \"@x/y\"|can only use path@version syntax with 'go get' and 'go install' in module-aware mode", "did not reject @x/y import path")
2665
2666	tg.tempFile("src/-x/x.go", "package x\n")
2667	tg.setenv("GOPATH", tg.path("."))
2668	tg.runFail("build", "--", "-x")
2669	tg.grepStderr("invalid import path \"-x\"", "did not reject -x import path")
2670
2671	tg.tempFile("src/-x/y/y.go", "package y\n")
2672	tg.setenv("GOPATH", tg.path("."))
2673	tg.runFail("build", "--", "-x/y")
2674	tg.grepStderr("invalid import path \"-x/y\"", "did not reject -x/y import path")
2675}
2676
2677func TestTwoPkgConfigs(t *testing.T) {
2678	if !canCgo {
2679		t.Skip("no cgo")
2680	}
2681	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
2682		t.Skipf("no shell scripts on %s", runtime.GOOS)
2683	}
2684	tooSlow(t)
2685	tg := testgo(t)
2686	defer tg.cleanup()
2687	tg.parallel()
2688	tg.tempFile("src/x/a.go", `package x
2689		// #cgo pkg-config: --static a
2690		import "C"
2691	`)
2692	tg.tempFile("src/x/b.go", `package x
2693		// #cgo pkg-config: --static a
2694		import "C"
2695	`)
2696	tg.tempFile("pkg-config.sh", `#!/bin/sh
2697echo $* >>`+tg.path("pkg-config.out"))
2698	tg.must(os.Chmod(tg.path("pkg-config.sh"), 0755))
2699	tg.setenv("GOPATH", tg.path("."))
2700	tg.setenv("PKG_CONFIG", tg.path("pkg-config.sh"))
2701	tg.run("build", "x")
2702	out, err := os.ReadFile(tg.path("pkg-config.out"))
2703	tg.must(err)
2704	out = bytes.TrimSpace(out)
2705	want := "--cflags --static --static -- a a\n--libs --static --static -- a a"
2706	if !bytes.Equal(out, []byte(want)) {
2707		t.Errorf("got %q want %q", out, want)
2708	}
2709}
2710
2711func TestCgoCache(t *testing.T) {
2712	if !canCgo {
2713		t.Skip("no cgo")
2714	}
2715	tooSlow(t)
2716
2717	tg := testgo(t)
2718	defer tg.cleanup()
2719	tg.parallel()
2720	tg.tempFile("src/x/a.go", `package main
2721		// #ifndef VAL
2722		// #define VAL 0
2723		// #endif
2724		// int val = VAL;
2725		import "C"
2726		import "fmt"
2727		func main() { fmt.Println(C.val) }
2728	`)
2729	tg.setenv("GOPATH", tg.path("."))
2730	exe := tg.path("x.exe")
2731	tg.run("build", "-o", exe, "x")
2732	tg.setenv("CGO_LDFLAGS", "-lnosuchlibraryexists")
2733	tg.runFail("build", "-o", exe, "x")
2734	tg.grepStderr(`nosuchlibraryexists`, "did not run linker with changed CGO_LDFLAGS")
2735}
2736
2737// Issue 23982
2738func TestFilepathUnderCwdFormat(t *testing.T) {
2739	tg := testgo(t)
2740	defer tg.cleanup()
2741	tg.parallel()
2742	tg.run("test", "-x", "-cover", "log")
2743	tg.grepStderrNot(`\.log\.cover\.go`, "-x output should contain correctly formatted filepath under cwd")
2744}
2745
2746// Issue 24396.
2747func TestDontReportRemoveOfEmptyDir(t *testing.T) {
2748	tg := testgo(t)
2749	defer tg.cleanup()
2750	tg.parallel()
2751	tg.tempFile("src/a/a.go", `package a`)
2752	tg.setenv("GOPATH", tg.path("."))
2753	tg.run("install", "-x", "a")
2754	tg.run("install", "-x", "a")
2755	// The second install should have printed only a WORK= line,
2756	// nothing else.
2757	if bytes.Count(tg.stdout.Bytes(), []byte{'\n'})+bytes.Count(tg.stderr.Bytes(), []byte{'\n'}) > 1 {
2758		t.Error("unnecessary output when installing installed package")
2759	}
2760}
2761
2762// Issue 24704.
2763func TestLinkerTmpDirIsDeleted(t *testing.T) {
2764	skipIfGccgo(t, "gccgo does not use cmd/link")
2765	if !canCgo {
2766		t.Skip("skipping because cgo not enabled")
2767	}
2768	tooSlow(t)
2769
2770	tg := testgo(t)
2771	defer tg.cleanup()
2772	tg.parallel()
2773	tg.tempFile("a.go", `package main; import "C"; func main() {}`)
2774	tg.run("build", "-ldflags", "-v", "-o", os.DevNull, tg.path("a.go"))
2775	// Find line that has "host link:" in linker output.
2776	stderr := tg.getStderr()
2777	var hostLinkLine string
2778	for _, line := range strings.Split(stderr, "\n") {
2779		if !strings.Contains(line, "host link:") {
2780			continue
2781		}
2782		hostLinkLine = line
2783		break
2784	}
2785	if hostLinkLine == "" {
2786		t.Fatal(`fail to find with "host link:" string in linker output`)
2787	}
2788	// Find parameter, like "/tmp/go-link-408556474/go.o" inside of
2789	// "host link:" line, and extract temp directory /tmp/go-link-408556474
2790	// out of it.
2791	tmpdir := hostLinkLine
2792	i := strings.Index(tmpdir, `go.o"`)
2793	if i == -1 {
2794		t.Fatalf(`fail to find "go.o" in "host link:" line %q`, hostLinkLine)
2795	}
2796	tmpdir = tmpdir[:i-1]
2797	i = strings.LastIndex(tmpdir, `"`)
2798	if i == -1 {
2799		t.Fatalf(`fail to find " in "host link:" line %q`, hostLinkLine)
2800	}
2801	tmpdir = tmpdir[i+1:]
2802	// Verify that temp directory has been removed.
2803	_, err := os.Stat(tmpdir)
2804	if err == nil {
2805		t.Fatalf("temp directory %q has not been removed", tmpdir)
2806	}
2807	if !os.IsNotExist(err) {
2808		t.Fatalf("Stat(%q) returns unexpected error: %v", tmpdir, err)
2809	}
2810}
2811
2812// Issue 25093.
2813func TestCoverpkgTestOnly(t *testing.T) {
2814	skipIfGccgo(t, "gccgo has no cover tool")
2815	tooSlow(t)
2816	tg := testgo(t)
2817	defer tg.cleanup()
2818	tg.parallel()
2819	tg.tempFile("src/a/a.go", `package a
2820		func F(i int) int {
2821			return i*i
2822		}`)
2823	tg.tempFile("src/atest/a_test.go", `
2824		package a_test
2825		import ( "a"; "testing" )
2826		func TestF(t *testing.T) { a.F(2) }
2827	`)
2828	tg.setenv("GOPATH", tg.path("."))
2829	tg.run("test", "-coverpkg=a", "atest")
2830	tg.grepStderrNot("no packages being tested depend on matches", "bad match message")
2831	tg.grepStdout("coverage: 100", "no coverage")
2832}
2833