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