src/cmd/go/go_test.go GO 2,607 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 2,607.
1// Copyright 2015 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45package main_test67import (8	"bytes"9	"debug/elf"10	"debug/macho"11	"debug/pe"12	"flag"13	"fmt"14	"go/format"15	"internal/godebug"16	"internal/platform"17	"internal/testenv"18	"io"19	"io/fs"20	"log"21	"math"22	"os"23	"os/exec"24	"path/filepath"25	"regexp"26	"runtime"27	"slices"28	"strconv"29	"strings"30	"testing"31	"time"3233	"cmd/go/internal/base"34	"cmd/go/internal/cache"35	"cmd/go/internal/cfg"36	"cmd/go/internal/gover"37	"cmd/go/internal/search"38	"cmd/go/internal/toolchain"39	"cmd/go/internal/vcs"40	"cmd/go/internal/vcweb/vcstest"41	"cmd/go/internal/web/intercept"42	"cmd/go/internal/work"43	"cmd/internal/robustio"44	"cmd/internal/sys"4546	cmdgo "cmd/go"47)4849func 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}5657var (58	canRace = false // whether we can run the race detector59	canMSan = false // whether we can run the memory sanitizer60	canASan = false // whether we can run the address sanitizer61)6263var (64	goHostOS, goHostArch string65	cgoEnabled           string // raw value from 'go env CGO_ENABLED'66)6768// netTestSem is a semaphore limiting the number of tests that may use the69// external network in parallel. If non-nil, it contains one buffer slot per70// test (send to acquire), with a low enough limit that the overall number of71// connections (summed across subprocesses) stays at or below base.NetLimit.72var netTestSem chan struct{}7374var exeSuffix string = func() string {75	if runtime.GOOS == "windows" {76		return ".exe"77	}78	return ""79}()8081func 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}8788// testGOROOT is the GOROOT to use when running testgo, a cmd/go binary89// build from this process's current GOROOT, but run from a different90// (temp) directory.91var testGOROOT string9293var testGOCACHE string9495var testGo string96var testTmpDir string97var testBin string9899// The TestMain function creates a go command for testing purposes and100// 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 = v112		}113114		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 nil120				}121122				rel := search.InDir(a.Target, testGOROOT)123				if rel == "" {124					return nil125				}126127				callerPos := ""128				if _, file, line, ok := runtime.Caller(1); ok {129					if shortFile := search.InDir(file, filepath.Join(testGOROOT, "src")); shortFile != "" {130						file = shortFile131					}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		}138139		if vcsTestHost := os.Getenv("TESTGO_VCSTEST_HOST"); vcsTestHost != "" {140			vcs.VCSTestRepoURL = "http://" + vcsTestHost141			vcs.VCSTestHosts = vcstest.Hosts142			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 []intercept.Interceptor148			for _, host := range vcstest.Hosts {149				interceptors = append(interceptors,150					intercept.Interceptor{Scheme: "http", FromHost: host, ToHost: vcsTestHost},151					intercept.Interceptor{Scheme: "https", FromHost: host, ToHost: vcsTestTLSHost, Client: vcsTestClient})152			}153			intercept.EnableTestHooks(interceptors)154		}155156		cmdgo.Main()157		os.Exit(0)158	}159	os.Setenv("CMDGO_TEST_RUN_MAIN", "true")160161	// $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/go165		fmt.Printf("cmd/go test is not compatible with $GO_GCFLAGS being set\n")166		fmt.Printf("SKIP\n")167		return168	}169170	flag.Parse()171172	if *proxyAddr != "" {173		StartProxy()174		select {}175	}176177	// Run with a temporary TMPDIR to check that the tests don't178	// 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)189190	dir, err := os.MkdirTemp(topTmpdir, "tmpdir")191	if err != nil {192		log.Fatal(err)193	}194	testTmpDir = dir195	if !*testWork {196		defer removeAll(testTmpDir)197	}198199	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		}211212		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)223224		// The whole GOROOT/pkg tree was installed using the GOHOSTOS/GOHOSTARCH225		// 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 toolchain228		// (installed in GOROOT/pkg/tool/GOOS_GOARCH).229		// If these are not the same toolchain, then the entire standard library230		// will look out of date (the compilers in those two different tool directories231		// are built for different architectures and have different build IDs),232		// which will cause many tests to do unnecessary rebuilds and some233		// 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)239240		cgoEnabled = goEnv("CGO_ENABLED")241242		// 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()255256			dst, err := os.OpenFile(testGo, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o777)257			if err != nil {258				log.Fatal(err)259			}260261			_, err = io.Copy(dst, src)262			if closeErr := dst.Close(); err == nil {263				err = closeErr264			}265			if err != nil {266				log.Fatal(err)267			}268		}269270		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))276277		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/14481282		// gccgo does not support the race detector.283		if isAlpineLinux() || runtime.Compiler == "gccgo" {284			canRace = false285		}286	}287288	if n, limited := base.NetLimit(); limited && n > 0 {289		// Split the network limit into chunks, so that each parallel script can290		// have one chunk. We want to run as many parallel scripts as possible, but291		// 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	}298299	// 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 break308	// 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 gone312	}313314	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	}321322	r := m.Run()323	if !*testWork {324		removeAll(testTmpDir) // os.Exit won't run defer325	}326327	if !*testWork {328		// There shouldn't be anything left in topTmpdir.329		var extraFiles, extraDirs []string330		err := filepath.WalkDir(topTmpdir, func(path string, d fs.DirEntry, err error) error {331			if err != nil {332				return err333			}334			if path == topTmpdir {335				return nil336			}337338			if rel, err := filepath.Rel(topTmpdir, path); err == nil {339				path = rel340			}341			if d.IsDir() {342				extraDirs = append(extraDirs, path)343			} else {344				extraFiles = append(extraFiles, path)345			}346			return nil347		})348		if err != nil {349			log.Fatal(err)350		}351352		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		}357358		removeAll(topTmpdir)359	}360361	os.Exit(r)362}363364func isAlpineLinux() bool {365	if runtime.GOOS != "linux" {366		return false367	}368	fi, err := os.Lstat("/etc/alpine-release")369	return err == nil && fi.Mode().IsRegular()370}371372// The length of an mtime tick on this system. This is an estimate of373// how long we need to sleep to ensure that the mtime of two files is374// 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.Second377378// Manage a single run of the testgo binary.379type testgoData struct {380	t              *testing.T381	temps          []string382	env            []string383	tempdir        string384	ran            bool385	inParallel     bool386	stdout, stderr bytes.Buffer387	execDir        string // dir for tg.run388}389390// 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}396397// 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)402403	return &testgoData{t: t}404}405406// 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}413414// 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}421422// 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 = true437	tg.t.Parallel()438}439440// 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 wd448}449450// sleep sleeps for one tick, where a tick is a conservative estimate451// of how long it takes for a file modification to get a different452// mtime.453func (tg *testgoData) sleep() {454	time.Sleep(mtimeTick)455}456457// setenv sets an environment variable to use when running the test go458// 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}464465// 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, "TESTGOVCSREMOTE=panic")472		}473	}474	for i, v := range tg.env {475		if strings.HasPrefix(v, name+"=") {476			tg.env = slices.Delete(tg.env, i, i+1)477			break478		}479	}480}481482func (tg *testgoData) goTool() string {483	return testGo484}485486// doRun runs the test go command, recording stdout and stderr and487// returning exit status.488func (tg *testgoData) doRun(args []string) error {489	tg.t.Helper()490	if !tg.inParallel {491		tg.t.Fatal("all tests using testgoData must run in parallel")492	}493	for _, arg := range args {494		if strings.HasPrefix(arg, "testdata") || strings.HasPrefix(arg, "./testdata") {495			tg.t.Fatal("internal testsuite error: parallel run using testdata")496		}497	}498499	hasGoroot := false500	for _, v := range tg.env {501		if strings.HasPrefix(v, "GOROOT=") {502			hasGoroot = true503			break504		}505	}506	prog := tg.goTool()507	if !hasGoroot {508		tg.setenv("GOROOT", testGOROOT)509	}510511	tg.t.Logf("running testgo %v", args)512	cmd := testenv.Command(tg.t, prog, args...)513	tg.stdout.Reset()514	tg.stderr.Reset()515	cmd.Dir = tg.execDir516	cmd.Stdout = &tg.stdout517	cmd.Stderr = &tg.stderr518	cmd.Env = tg.env519	status := cmd.Run()520	if tg.stdout.Len() > 0 {521		tg.t.Log("standard output:")522		tg.t.Log(tg.stdout.String())523	}524	if tg.stderr.Len() > 0 {525		tg.t.Log("standard error:")526		tg.t.Log(tg.stderr.String())527	}528	tg.ran = true529	return status530}531532// run runs the test go command, and expects it to succeed.533func (tg *testgoData) run(args ...string) {534	tg.t.Helper()535	if status := tg.doRun(args); status != nil {536		wd, _ := os.Getwd()537		tg.t.Logf("go %v failed unexpectedly in %s: %v", args, wd, status)538		tg.t.FailNow()539	}540}541542// runFail runs the test go command, and expects it to fail.543func (tg *testgoData) runFail(args ...string) {544	tg.t.Helper()545	if status := tg.doRun(args); status == nil {546		tg.t.Fatal("testgo succeeded unexpectedly")547	} else {548		tg.t.Log("testgo failed as expected:", status)549	}550}551552// getStdout returns standard output of the testgo run as a string.553func (tg *testgoData) getStdout() string {554	tg.t.Helper()555	if !tg.ran {556		tg.t.Fatal("internal testsuite error: stdout called before run")557	}558	return tg.stdout.String()559}560561// getStderr returns standard error of the testgo run as a string.562func (tg *testgoData) getStderr() string {563	tg.t.Helper()564	if !tg.ran {565		tg.t.Fatal("internal testsuite error: stdout called before run")566	}567	return tg.stderr.String()568}569570// doGrepMatch looks for a regular expression in a buffer, and returns571// whether it is found. The regular expression is matched against572// each line separately, as with the grep command.573func (tg *testgoData) doGrepMatch(match string, b *bytes.Buffer) bool {574	tg.t.Helper()575	if !tg.ran {576		tg.t.Fatal("internal testsuite error: grep called before run")577	}578	re := regexp.MustCompile(match)579	for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) {580		if re.Match(ln) {581			return true582		}583	}584	return false585}586587// doGrep looks for a regular expression in a buffer and fails if it588// is not found. The name argument is the name of the output we are589// searching, "output" or "error". The msg argument is logged on590// failure.591func (tg *testgoData) doGrep(match string, b *bytes.Buffer, name, msg string) {592	tg.t.Helper()593	if !tg.doGrepMatch(match, b) {594		tg.t.Log(msg)595		tg.t.Logf("pattern %v not found in standard %s", match, name)596		tg.t.FailNow()597	}598}599600// grepStdout looks for a regular expression in the test run's601// standard output and fails, logging msg, if it is not found.602func (tg *testgoData) grepStdout(match, msg string) {603	tg.t.Helper()604	tg.doGrep(match, &tg.stdout, "output", msg)605}606607// grepStderr looks for a regular expression in the test run's608// standard error and fails, logging msg, if it is not found.609func (tg *testgoData) grepStderr(match, msg string) {610	tg.t.Helper()611	tg.doGrep(match, &tg.stderr, "error", msg)612}613614// grepBoth looks for a regular expression in the test run's standard615// output or stand error and fails, logging msg, if it is not found.616func (tg *testgoData) grepBoth(match, msg string) {617	tg.t.Helper()618	if !tg.doGrepMatch(match, &tg.stdout) && !tg.doGrepMatch(match, &tg.stderr) {619		tg.t.Log(msg)620		tg.t.Logf("pattern %v not found in standard output or standard error", match)621		tg.t.FailNow()622	}623}624625// doGrepNot looks for a regular expression in a buffer and fails if626// it is found. The name and msg arguments are as for doGrep.627func (tg *testgoData) doGrepNot(match string, b *bytes.Buffer, name, msg string) {628	tg.t.Helper()629	if tg.doGrepMatch(match, b) {630		tg.t.Log(msg)631		tg.t.Logf("pattern %v found unexpectedly in standard %s", match, name)632		tg.t.FailNow()633	}634}635636// grepStdoutNot looks for a regular expression in the test run's637// standard output and fails, logging msg, if it is found.638func (tg *testgoData) grepStdoutNot(match, msg string) {639	tg.t.Helper()640	tg.doGrepNot(match, &tg.stdout, "output", msg)641}642643// grepStderrNot looks for a regular expression in the test run's644// standard error and fails, logging msg, if it is found.645func (tg *testgoData) grepStderrNot(match, msg string) {646	tg.t.Helper()647	tg.doGrepNot(match, &tg.stderr, "error", msg)648}649650// grepBothNot looks for a regular expression in the test run's651// standard output or standard error and fails, logging msg, if it is652// found.653func (tg *testgoData) grepBothNot(match, msg string) {654	tg.t.Helper()655	if tg.doGrepMatch(match, &tg.stdout) || tg.doGrepMatch(match, &tg.stderr) {656		tg.t.Log(msg)657		tg.t.Fatalf("pattern %v found unexpectedly in standard output or standard error", match)658	}659}660661// doGrepCount counts the number of times a regexp is seen in a buffer.662func (tg *testgoData) doGrepCount(match string, b *bytes.Buffer) int {663	tg.t.Helper()664	if !tg.ran {665		tg.t.Fatal("internal testsuite error: doGrepCount called before run")666	}667	re := regexp.MustCompile(match)668	c := 0669	for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) {670		if re.Match(ln) {671			c++672		}673	}674	return c675}676677// grepCountBoth returns the number of times a regexp is seen in both678// standard output and standard error.679func (tg *testgoData) grepCountBoth(match string) int {680	tg.t.Helper()681	return tg.doGrepCount(match, &tg.stdout) + tg.doGrepCount(match, &tg.stderr)682}683684// creatingTemp records that the test plans to create a temporary file685// or directory. If the file or directory exists already, it will be686// removed. When the test completes, the file or directory will be687// removed if it exists.688func (tg *testgoData) creatingTemp(path string) {689	tg.t.Helper()690	if filepath.IsAbs(path) && !strings.HasPrefix(path, tg.tempdir) {691		tg.t.Fatalf("internal testsuite error: creatingTemp(%q) with absolute path not in temporary directory", path)692	}693	tg.must(robustio.RemoveAll(path))694	tg.temps = append(tg.temps, path)695}696697// makeTempdir makes a temporary directory for a run of testgo. If698// the temporary directory was already created, this does nothing.699func (tg *testgoData) makeTempdir() {700	tg.t.Helper()701	if tg.tempdir == "" {702		var err error703		tg.tempdir, err = os.MkdirTemp("", "gotest")704		tg.must(err)705	}706}707708// tempFile adds a temporary file for a run of testgo.709func (tg *testgoData) tempFile(path, contents string) {710	tg.t.Helper()711	tg.makeTempdir()712	tg.must(os.MkdirAll(filepath.Join(tg.tempdir, filepath.Dir(path)), 0755))713	bytes := []byte(contents)714	if strings.HasSuffix(path, ".go") {715		formatted, err := format.Source(bytes)716		if err == nil {717			bytes = formatted718		}719	}720	tg.must(os.WriteFile(filepath.Join(tg.tempdir, path), bytes, 0644))721}722723// tempDir adds a temporary directory for a run of testgo.724func (tg *testgoData) tempDir(path string) {725	tg.t.Helper()726	tg.makeTempdir()727	if err := os.MkdirAll(filepath.Join(tg.tempdir, path), 0755); err != nil && !os.IsExist(err) {728		tg.t.Fatal(err)729	}730}731732// path returns the absolute pathname to file with the temporary733// directory.734func (tg *testgoData) path(name string) string {735	tg.t.Helper()736	if tg.tempdir == "" {737		tg.t.Fatalf("internal testsuite error: path(%q) with no tempdir", name)738	}739	if name == "." {740		return tg.tempdir741	}742	return filepath.Join(tg.tempdir, name)743}744745// mustExist fails if path does not exist.746func (tg *testgoData) mustExist(path string) {747	tg.t.Helper()748	if _, err := os.Stat(path); err != nil {749		if os.IsNotExist(err) {750			tg.t.Fatalf("%s does not exist but should", path)751		}752		tg.t.Fatalf("%s stat failed: %v", path, err)753	}754}755756// mustNotExist fails if path exists.757func (tg *testgoData) mustNotExist(path string) {758	tg.t.Helper()759	if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) {760		tg.t.Fatalf("%s exists but should not (%v)", path, err)761	}762}763764// wantExecutable fails with msg if path is not executable.765func (tg *testgoData) wantExecutable(path, msg string) {766	tg.t.Helper()767	if st, err := os.Stat(path); err != nil {768		if !os.IsNotExist(err) {769			tg.t.Log(err)770		}771		tg.t.Fatal(msg)772	} else {773		if runtime.GOOS != "windows" && st.Mode()&0111 == 0 {774			tg.t.Fatalf("binary %s exists but is not executable", path)775		}776	}777}778779// isStale reports whether pkg is stale, and why780func (tg *testgoData) isStale(pkg string) (bool, string) {781	tg.t.Helper()782	tg.run("list", "-f", "{{.Stale}}:{{.StaleReason}}", pkg)783	v := strings.TrimSpace(tg.getStdout())784	f := strings.SplitN(v, ":", 2)785	if len(f) == 2 {786		switch f[0] {787		case "true":788			return true, f[1]789		case "false":790			return false, f[1]791		}792	}793	tg.t.Fatalf("unexpected output checking staleness of package %v: %v", pkg, v)794	panic("unreachable")795}796797// wantStale fails with msg if pkg is not stale.798func (tg *testgoData) wantStale(pkg, reason, msg string) {799	tg.t.Helper()800	stale, why := tg.isStale(pkg)801	if !stale {802		tg.t.Fatal(msg)803	}804	// We always accept the reason as being "not installed but805	// available in build cache", because when that is the case go806	// list doesn't try to sort out the underlying reason why the807	// package is not installed.808	if reason == "" && why != "" || !strings.Contains(why, reason) && !strings.Contains(why, "not installed but available in build cache") {809		tg.t.Errorf("wrong reason for Stale=true: %q, want %q", why, reason)810	}811}812813// wantNotStale fails with msg if pkg is stale.814func (tg *testgoData) wantNotStale(pkg, reason, msg string) {815	tg.t.Helper()816	stale, why := tg.isStale(pkg)817	if stale {818		tg.t.Fatal(msg)819	}820	if reason == "" && why != "" || !strings.Contains(why, reason) {821		tg.t.Errorf("wrong reason for Stale=false: %q, want %q", why, reason)822	}823}824825// If -testwork is specified, the test prints the name of the temp directory826// and does not remove it when done, so that a programmer can827// poke at the test file tree afterward.828var testWork = flag.Bool("testwork", false, "")829830// cleanup cleans up a test that runs testgo.831func (tg *testgoData) cleanup() {832	tg.t.Helper()833	if *testWork {834		if tg.tempdir != "" {835			tg.t.Logf("TESTWORK=%s\n", tg.path("."))836		}837		return838	}839	for _, path := range tg.temps {840		tg.check(removeAll(path))841	}842	if tg.tempdir != "" {843		tg.check(removeAll(tg.tempdir))844	}845}846847func removeAll(dir string) error {848	// module cache has 0444 directories;849	// make them writable in order to remove content.850	filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {851		// chmod not only directories, but also things that we couldn't even stat852		// due to permission errors: they may also be unreadable directories.853		if err != nil || info.IsDir() {854			os.Chmod(path, 0777)855		}856		return nil857	})858	return robustio.RemoveAll(dir)859}860861func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {862	if testing.Short() {863		t.Skip("skipping lengthy test in short mode")864	}865866	tg := testgo(t)867	defer tg.cleanup()868	tg.parallel()869870	// Set GOCACHE to an empty directory so that a previous run of871	// this test does not affect the staleness of the packages it builds.872	tg.tempDir("gocache")873	tg.setenv("GOCACHE", tg.path("gocache"))874875	// Copy the runtime packages into a temporary GOROOT876	// so that we can change files.877	var dirs []string878	tg.run("list", "-deps", "runtime")879	pkgs := strings.Split(strings.TrimSpace(tg.getStdout()), "\n")880	for _, pkg := range pkgs {881		dirs = append(dirs, filepath.Join("src", pkg))882	}883	dirs = append(dirs,884		filepath.Join("pkg/tool", goHostOS+"_"+goHostArch),885		"pkg/include",886	)887	for _, copydir := range dirs {888		srcdir := filepath.Join(testGOROOT, copydir)889		tg.tempDir(filepath.Join("goroot", copydir))890		err := filepath.WalkDir(srcdir,891			func(path string, info fs.DirEntry, err error) error {892				if err != nil {893					return err894				}895				if info.IsDir() {896					return nil897				}898				srcrel, err := filepath.Rel(srcdir, path)899				if err != nil {900					return err901				}902				dest := filepath.Join("goroot", copydir, srcrel)903				if _, err := os.Stat(dest); err == nil {904					return nil905				}906				data, err := os.ReadFile(path)907				if err != nil {908					return err909				}910				tg.tempFile(dest, string(data))911				if strings.Contains(copydir, filepath.Join("pkg", "tool")) {912					os.Chmod(tg.path(dest), 0777)913				}914				return nil915			})916		if err != nil {917			t.Fatal(err)918		}919	}920	tg.setenv("GOROOT", tg.path("goroot"))921922	addVar := func(name string, idx int) (restore func()) {923		data, err := os.ReadFile(name)924		if err != nil {925			t.Fatal(err)926		}927		old := data928		data = append(data, fmt.Sprintf("var DummyUnusedVar%d bool\n", idx)...)929		if err := os.WriteFile(name, append(data, '\n'), 0666); err != nil {930			t.Fatal(err)931		}932		tg.sleep()933		return func() {934			if err := os.WriteFile(name, old, 0666); err != nil {935				t.Fatal(err)936			}937		}938	}939940	// Every main package depends on the "runtime".941	tg.tempFile("d1/src/p1/p1.go", `package main; func main(){}`)942	tg.setenv("GOPATH", tg.path("d1"))943	// Pass -i flag to rebuild everything outdated.944	tg.run("install", "p1")945	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, before any changes")946947	// Changing mtime of internal/runtime/sys/sys.go948	// should have no effect: only the content matters.949	// In fact this should be true even outside a release branch.950	sys := tg.path("goroot/src/internal/runtime/sys/sys.go")951	tg.sleep()952	restore := addVar(sys, 0)953	restore()954	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after updating mtime of internal/runtime/sys/sys.go")955956	// But changing content of any file should have an effect.957	// Previously zversion.go was the only one that mattered;958	// now they all matter, so keep using sys.go.959	restore = addVar(sys, 1)960	defer restore()961	tg.wantStale("p1", "stale dependency: internal/runtime/sys", "./testgo list claims p1 is NOT stale, incorrectly, after changing sys.go")962	restore()963	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after changing back to old release")964	addVar(sys, 2)965	tg.wantStale("p1", "stale dependency: internal/runtime/sys", "./testgo list claims p1 is NOT stale, incorrectly, after changing sys.go again")966	tg.run("install", "p1")967	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with new release")968969	// Restore to "old" release.970	restore()971	tg.wantStale("p1", "not installed but available in build cache", "./testgo list claims p1 is NOT stale, incorrectly, after restoring sys.go")972	tg.run("install", "p1")973	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with old release")974}975976// Issue 4104.977func TestGoTestWithPackageListedMultipleTimes(t *testing.T) {978	tooSlow(t, "links and runs a test")979980	tg := testgo(t)981	defer tg.cleanup()982	tg.parallel()983	tg.run("test", "errors", "errors", "errors", "errors", "errors")984	if strings.Contains(strings.TrimSpace(tg.getStdout()), "\n") {985		t.Error("go test errors errors errors errors errors tested the same package multiple times")986	}987}988989func TestGoListHasAConsistentOrder(t *testing.T) {990	tooSlow(t, "walks all of GOROOT/src twice")991992	tg := testgo(t)993	defer tg.cleanup()994	tg.parallel()995	tg.run("list", "std")996	first := tg.getStdout()997	tg.run("list", "std")998	if first != tg.getStdout() {999		t.Error("go list std ordering is inconsistent")1000	}1001}10021003func TestGoListStdDoesNotIncludeCommands(t *testing.T) {1004	tooSlow(t, "walks all of GOROOT/src")10051006	tg := testgo(t)1007	defer tg.cleanup()1008	tg.parallel()1009	tg.run("list", "std")1010	tg.grepStdoutNot("cmd/", "go list std shows commands")1011}10121013func TestGoListCmdOnlyShowsCommands(t *testing.T) {1014	skipIfGccgo(t, "gccgo does not have GOROOT")1015	tooSlow(t, "walks all of GOROOT/src/cmd")10161017	tg := testgo(t)1018	defer tg.cleanup()1019	tg.parallel()1020	tg.run("list", "cmd")1021	out := strings.TrimSpace(tg.getStdout())1022	for _, line := range strings.Split(out, "\n") {1023		if !strings.Contains(line, "cmd/") {1024			t.Error("go list cmd shows non-commands")1025			break1026		}1027	}1028}10291030func TestGoListDeps(t *testing.T) {1031	tg := testgo(t)1032	defer tg.cleanup()1033	tg.parallel()1034	tg.tempDir("src/p1/p2/p3/p4")1035	tg.setenv("GOPATH", tg.path("."))1036	tg.tempFile("src/p1/p.go", "package p1\nimport _ \"p1/p2\"\n")1037	tg.tempFile("src/p1/p2/p.go", "package p2\nimport _ \"p1/p2/p3\"\n")1038	tg.tempFile("src/p1/p2/p3/p.go", "package p3\nimport _ \"p1/p2/p3/p4\"\n")1039	tg.tempFile("src/p1/p2/p3/p4/p.go", "package p4\n")1040	tg.run("list", "-f", "{{.Deps}}", "p1")1041	tg.grepStdout("p1/p2/p3/p4", "Deps(p1) does not mention p4")10421043	tg.run("list", "-deps", "p1")1044	tg.grepStdout("p1/p2/p3/p4", "-deps p1 does not mention p4")10451046	if runtime.Compiler != "gccgo" {1047		// Check the list is in dependency order.1048		tg.run("list", "-deps", "math")1049		want := "unsafe\ninternal/cpu\nmath/bits\nmath\n"1050		out := tg.stdout.String()1051		if !strings.Contains(out, "internal/cpu") {1052			// Some systems don't use internal/cpu.1053			want = "unsafe\nmath/bits\nmath\n"1054		}1055		if tg.stdout.String() != want {1056			t.Fatalf("list -deps math: wrong order\nhave %q\nwant %q", tg.stdout.String(), want)1057		}1058	}1059}10601061func TestGoListCompiledCgo(t *testing.T) {1062	tooSlow(t, "compiles cgo files")10631064	tg := testgo(t)1065	defer tg.cleanup()1066	tg.parallel()1067	tg.makeTempdir()1068	tg.setenv("GOCACHE", tg.tempdir)10691070	tg.run("list", "-f", `{{join .CgoFiles "\n"}}`, "net")1071	if tg.stdout.String() == "" {1072		t.Skip("net does not use cgo")1073	}1074	if strings.Contains(tg.stdout.String(), tg.tempdir) {1075		t.Fatalf(".CgoFiles unexpectedly mentioned cache %s", tg.tempdir)1076	}1077	tg.run("list", "-compiled", "-f", `{{.Dir}}{{"\n"}}{{join .CompiledGoFiles "\n"}}`, "net")1078	if !strings.Contains(tg.stdout.String(), tg.tempdir) {1079		t.Fatalf(".CompiledGoFiles with -compiled did not mention cache %s", tg.tempdir)1080	}1081	dir := ""1082	for _, file := range strings.Split(tg.stdout.String(), "\n") {1083		if file == "" {1084			continue1085		}1086		if dir == "" {1087			dir = file1088			continue1089		}1090		if !strings.Contains(file, "/") && !strings.Contains(file, `\`) {1091			file = filepath.Join(dir, file)1092		}1093		if _, err := os.Stat(file); err != nil {1094			t.Fatalf("cannot find .CompiledGoFiles result %s: %v", file, err)1095		}1096	}1097}10981099func TestGoListExport(t *testing.T) {1100	tooSlow(t, "runs build for -export")11011102	skipIfGccgo(t, "gccgo does not have standard packages")1103	tg := testgo(t)1104	defer tg.cleanup()1105	tg.parallel()1106	tg.makeTempdir()1107	tg.setenv("GOCACHE", tg.tempdir)11081109	tg.run("list", "-f", "{{.Export}}", "strings")1110	if tg.stdout.String() != "" {1111		t.Fatalf(".Export without -export unexpectedly set")1112	}1113	tg.run("list", "-export", "-f", "{{.Export}}", "strings")1114	file := strings.TrimSpace(tg.stdout.String())1115	if file == "" {1116		t.Fatalf(".Export with -export was empty")1117	}1118	if _, err := os.Stat(file); err != nil {1119		t.Fatalf("cannot find .Export result %s: %v", file, err)1120	}11211122	tg.run("list", "-export", "-f", "{{.BuildID}}", "strings")1123	buildID := strings.TrimSpace(tg.stdout.String())1124	if buildID == "" {1125		t.Fatalf(".BuildID with -export was empty")1126	}11271128	tg.run("tool", "buildid", file)1129	toolBuildID := strings.TrimSpace(tg.stdout.String())1130	if buildID != toolBuildID {1131		t.Fatalf(".BuildID with -export %q disagrees with 'go tool buildid' %q", buildID, toolBuildID)1132	}1133}11341135// Issue 4096. Validate the output of unsuccessful go install foo/quxx.1136func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) {1137	tg := testgo(t)1138	defer tg.cleanup()1139	tg.parallel()1140	tg.runFail("install", "foo/quxx")1141	if tg.grepCountBoth(`cannot find package "foo/quxx" in any of`) != 1 {1142		t.Error(`go install foo/quxx expected error: .*cannot find package "foo/quxx" in any of`)1143	}1144}11451146func TestGOROOTSearchFailureReporting(t *testing.T) {1147	tg := testgo(t)1148	defer tg.cleanup()1149	tg.parallel()1150	tg.runFail("install", "foo/quxx")1151	if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("foo", "quxx"))+` \(from \$GOROOT\)$`) != 1 {1152		t.Error(`go install foo/quxx expected error: .*foo/quxx (from $GOROOT)`)1153	}1154}11551156func TestMultipleGOPATHEntriesReportedSeparately(t *testing.T) {1157	tg := testgo(t)1158	defer tg.cleanup()1159	tg.parallel()1160	sep := string(filepath.ListSeparator)1161	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))1162	tg.runFail("install", "foo/quxx")1163	if tg.grepCountBoth(`testdata[/\\].[/\\]src[/\\]foo[/\\]quxx`) != 2 {1164		t.Error(`go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)\n.*testdata/b/src/foo/quxx`)1165	}1166}11671168// Test (from $GOPATH) annotation is reported for the first GOPATH entry,1169func TestMentionGOPATHInFirstGOPATHEntry(t *testing.T) {1170	tg := testgo(t)1171	defer tg.cleanup()1172	tg.parallel()1173	sep := string(filepath.ListSeparator)1174	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))1175	tg.runFail("install", "foo/quxx")1176	if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("testdata", "a", "src", "foo", "quxx"))+` \(from \$GOPATH\)$`) != 1 {1177		t.Error(`go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)`)1178	}1179}11801181// but not on the second.1182func TestMentionGOPATHNotOnSecondEntry(t *testing.T) {1183	tg := testgo(t)1184	defer tg.cleanup()1185	tg.parallel()1186	sep := string(filepath.ListSeparator)1187	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))1188	tg.runFail("install", "foo/quxx")1189	if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("testdata", "b", "src", "foo", "quxx"))+`$`) != 1 {1190		t.Error(`go install foo/quxx expected error: .*testdata/b/src/foo/quxx`)1191	}1192}11931194func homeEnvName() string {1195	switch runtime.GOOS {1196	case "windows":1197		return "USERPROFILE"1198	case "plan9":1199		return "home"1200	default:1201		return "HOME"1202	}1203}12041205func tempEnvName() string {1206	switch runtime.GOOS {1207	case "windows":1208		return "TMP"1209	case "plan9":1210		return "TMPDIR" // actually plan 9 doesn't have one at all but this is fine1211	default:1212		return "TMPDIR"1213	}1214}12151216func pathEnvName() string {1217	switch runtime.GOOS {1218	case "plan9":1219		return "path"1220	default:1221		return "PATH"1222	}1223}12241225func TestDefaultGOPATH(t *testing.T) {1226	tg := testgo(t)1227	defer tg.cleanup()1228	tg.parallel()1229	tg.tempDir("home/go")1230	tg.setenv(homeEnvName(), tg.path("home"))1231	// Set TEST_TELEMETRY_DIR to a path that doesn't exist1232	// so that the counter uploading code doesn't write1233	// the counter token file to the temp dir after the test finishes.1234	tg.setenv("TEST_TELEMETRY_DIR", "/no-telemetry-dir")12351236	tg.run("env", "GOPATH")1237	tg.grepStdout(regexp.QuoteMeta(tg.path("home/go")), "want GOPATH=$HOME/go")12381239	tg.setenv("GOROOT", tg.path("home/go"))1240	tg.run("env", "GOPATH")1241	tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go")12421243	tg.setenv("GOROOT", tg.path("home/go")+"/")1244	tg.run("env", "GOPATH")1245	tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go/")1246}12471248func TestDefaultGOPATHPrintedSearchList(t *testing.T) {1249	tg := testgo(t)1250	defer tg.cleanup()1251	tg.parallel()1252	tg.setenv("GOPATH", "")1253	tg.tempDir("home")1254	tg.setenv(homeEnvName(), tg.path("home"))1255	// Set TEST_TELEMETRY_DIR to a path that doesn't exist1256	// so that the counter uploading code doesn't write1257	// the counter token file to the temp dir after the test finishes.1258	tg.setenv("TEST_TELEMETRY_DIR", "/no-telemetry-dir")12591260	tg.runFail("install", "github.com/golang/example/hello")1261	tg.grepStderr(regexp.QuoteMeta(tg.path("home/go/src/github.com/golang/example/hello"))+`.*from \$GOPATH`, "expected default GOPATH")1262}12631264func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {1265	skipIfGccgo(t, "gccgo does not support -ldflags -X")1266	tooSlow(t, "compiles and links a binary")12671268	tg := testgo(t)1269	defer tg.cleanup()1270	tg.parallel()1271	tg.tempFile("main.go", `package main1272		var extern string1273		func main() {1274			println(extern)1275		}`)1276	tg.run("run", "-ldflags", `-X "main.extern=hello world"`, tg.path("main.go"))1277	tg.grepStderr("^hello world", `ldflags -X "main.extern=hello world"' failed`)1278}12791280func TestLdFlagsLongArgumentsIssue42295(t *testing.T) {1281	// Test the extremely long command line arguments that contain '\n' characters1282	// get encoded and passed correctly.1283	skipIfGccgo(t, "gccgo does not support -ldflags -X")1284	tooSlow(t, "compiles and links a binary")12851286	tg := testgo(t)1287	defer tg.cleanup()1288	tg.parallel()1289	tg.tempFile("main.go", `package main1290		var extern string1291		func main() {1292			print(extern)1293		}`)1294	testStr := "test test test test test \n\\ "1295	var buf strings.Builder1296	for buf.Len() < sys.ExecArgLengthLimit+1 {1297		buf.WriteString(testStr)1298	}1299	tg.run("run", "-ldflags", fmt.Sprintf(`-X "main.extern=%s"`, buf.String()), tg.path("main.go"))1300	if tg.stderr.String() != buf.String() {1301		t.Errorf("strings differ")1302	}1303}13041305func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) {1306	skipIfGccgo(t, "gccgo has no standard packages")1307	tooSlow(t, "compiles and links a test binary")13081309	tg := testgo(t)1310	defer tg.cleanup()1311	tg.parallel()1312	tg.makeTempdir()1313	tg.run("test", "-c", "-o", tg.path("myerrors.test"+exeSuffix), "errors")1314	tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -c -o myerrors.test did not create myerrors.test")1315}13161317func TestGoTestDashOWritesBinary(t *testing.T) {1318	skipIfGccgo(t, "gccgo has no standard packages")1319	tooSlow(t, "compiles and runs a test binary")13201321	tg := testgo(t)1322	defer tg.cleanup()1323	tg.parallel()1324	tg.makeTempdir()1325	tg.run("test", "-o", tg.path("myerrors.test"+exeSuffix), "errors")1326	tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test")1327}13281329// Issue 4515.1330func TestInstallWithTags(t *testing.T) {1331	tooSlow(t, "compiles and links binaries")13321333	tg := testgo(t)1334	defer tg.cleanup()1335	tg.parallel()1336	tg.tempDir("bin")1337	tg.tempFile("src/example/a/main.go", `package main1338		func main() {}`)1339	tg.tempFile("src/example/b/main.go", `// +build mytag13401341		package main1342		func main() {}`)1343	tg.setenv("GOPATH", tg.path("."))1344	tg.run("install", "-tags", "mytag", "example/a", "example/b")1345	tg.wantExecutable(tg.path("bin/a"+exeSuffix), "go install example/a example/b did not install binaries")1346	tg.wantExecutable(tg.path("bin/b"+exeSuffix), "go install example/a example/b did not install binaries")1347	tg.must(os.Remove(tg.path("bin/a" + exeSuffix)))1348	tg.must(os.Remove(tg.path("bin/b" + exeSuffix)))1349	tg.run("install", "-tags", "mytag", "example/...")1350	tg.wantExecutable(tg.path("bin/a"+exeSuffix), "go install example/... did not install binaries")1351	tg.wantExecutable(tg.path("bin/b"+exeSuffix), "go install example/... did not install binaries")1352	tg.run("list", "-tags", "mytag", "example/b...")1353	if strings.TrimSpace(tg.getStdout()) != "example/b" {1354		t.Error("go list example/b did not find example/b")1355	}1356}13571358// Issue 17451, 17662.1359func TestSymlinkWarning(t *testing.T) {1360	tg := testgo(t)1361	defer tg.cleanup()1362	tg.parallel()1363	tg.makeTempdir()1364	tg.setenv("GOPATH", tg.path("."))13651366	tg.tempDir("src/example/xx")1367	tg.tempDir("yy/zz")1368	tg.tempFile("yy/zz/zz.go", "package zz\n")1369	if err := os.Symlink(tg.path("yy"), tg.path("src/example/xx/yy")); err != nil {1370		t.Skipf("symlink failed: %v", err)1371	}1372	tg.run("list", "example/xx/z...")1373	tg.grepStdoutNot(".", "list should not have matched anything")1374	tg.grepStderr("matched no packages", "list should have reported that pattern matched no packages")1375	tg.grepStderrNot("symlink", "list should not have reported symlink")13761377	tg.run("list", "example/xx/...")1378	tg.grepStdoutNot(".", "list should not have matched anything")1379	tg.grepStderr("matched no packages", "list should have reported that pattern matched no packages")1380	tg.grepStderr("ignoring symlink", "list should have reported symlink")1381}13821383func TestCgoShowsFullPathNames(t *testing.T) {1384	testenv.MustHaveCGO(t)13851386	tg := testgo(t)1387	defer tg.cleanup()1388	tg.parallel()1389	tg.tempFile("src/x/y/dirname/foo.go", `1390		package foo1391		import "C"1392		func f() {`)1393	tg.setenv("GOPATH", tg.path("."))1394	tg.runFail("build", "x/y/dirname")1395	tg.grepBoth("x/y/dirname", "error did not use full path")1396}13971398func TestCgoHandlesWlORIGIN(t *testing.T) {1399	tooSlow(t, "compiles cgo files")1400	testenv.MustHaveCGO(t)14011402	tg := testgo(t)1403	defer tg.cleanup()1404	tg.parallel()1405	tg.tempFile("src/origin/origin.go", `package origin1406		// #cgo !darwin,!windows LDFLAGS: -Wl,-rpath,$ORIGIN1407		// void f(void) {}1408		import "C"1409		func f() { C.f() }`)1410	tg.setenv("GOPATH", tg.path("."))1411	tg.run("build", "origin")1412}14131414func TestCgoPkgConfig(t *testing.T) {1415	tooSlow(t, "compiles cgo files")1416	testenv.MustHaveCGO(t)14171418	tg := testgo(t)1419	defer tg.cleanup()1420	tg.parallel()14211422	tg.run("env", "PKG_CONFIG")1423	pkgConfig := strings.TrimSpace(tg.getStdout())1424	testenv.MustHaveExecPath(t, pkgConfig)1425	if out, err := testenv.Command(t, pkgConfig, "--atleast-pkgconfig-version", "0.24").CombinedOutput(); err != nil {1426		t.Skipf("%s --atleast-pkgconfig-version 0.24: %v\n%s", pkgConfig, err, out)1427	}14281429	// OpenBSD's pkg-config is strict about whitespace and only1430	// supports backslash-escaped whitespace. It does not support1431	// quotes, which the normal freedesktop.org pkg-config does1432	// support. See https://man.openbsd.org/pkg-config.11433	tg.tempFile("foo.pc", `1434Name: foo1435Description: The foo library1436Version: 1.0.01437Cflags: -Dhello=10 -Dworld=+32 -DDEFINED_FROM_PKG_CONFIG=hello\ world1438`)1439	tg.tempFile("foo.go", `package main14401441/*1442#cgo pkg-config: foo1443int value() {1444	return DEFINED_FROM_PKG_CONFIG;1445}1446*/1447import "C"1448import "os"14491450func main() {1451	if C.value() != 42 {1452		println("value() =", C.value(), "wanted 42")1453		os.Exit(1)1454	}1455}1456`)1457	tg.setenv("PKG_CONFIG_PATH", tg.path("."))1458	tg.run("run", tg.path("foo.go"))14591460	libs := `Libs: -Wl,-rpath=/path\ with\ spaces/bin`1461	if runtime.GOOS == "darwin" {1462		libs = "" // darwin linker doesn't have -rpath1463	}1464	// test for ldflags1465	tg.tempFile("bar.pc", `1466Name: bar1467Description: The bar library1468Version: 1.0.01469`+libs+`1470`)14711472	tg.tempFile("bar.go", `package main1473/*1474#cgo pkg-config: bar1475*/1476import "C"1477func main() {}1478`)1479	tg.run("run", tg.path("bar.go"))1480}14811482// Test that you cannot use a local import in a package1483// accessed by a non-local import (found in a GOPATH/GOROOT).1484// See golang.org/issue/17475.1485func TestImportLocal(t *testing.T) {1486	tooSlow(t, "builds a lot of sequential packages")14871488	tg := testgo(t)1489	tg.parallel()1490	defer tg.cleanup()14911492	tg.tempFile("src/dir/x/x.go", `package x1493		var X int1494	`)1495	tg.setenv("GOPATH", tg.path("."))1496	tg.run("build", "dir/x")14971498	// Ordinary import should work.1499	tg.tempFile("src/dir/p0/p.go", `package p01500		import "dir/x"1501		var _ = x.X1502	`)1503	tg.run("build", "dir/p0")15041505	// Relative import should not.1506	tg.tempFile("src/dir/p1/p.go", `package p11507		import "../x"1508		var _ = x.X1509	`)1510	tg.runFail("build", "dir/p1")1511	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")15121513	// ... even in a test.1514	tg.tempFile("src/dir/p2/p.go", `package p21515	`)1516	tg.tempFile("src/dir/p2/p_test.go", `package p21517		import "../x"1518		import "testing"1519		var _ = x.X1520		func TestFoo(t *testing.T) {}1521	`)1522	tg.run("build", "dir/p2")1523	tg.runFail("test", "dir/p2")1524	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")15251526	// ... even in an xtest.1527	tg.tempFile("src/dir/p2/p_test.go", `package p2_test1528		import "../x"1529		import "testing"1530		var _ = x.X1531		func TestFoo(t *testing.T) {}1532	`)1533	tg.run("build", "dir/p2")1534	tg.runFail("test", "dir/p2")1535	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")15361537	// Relative import starting with ./ should not work either.1538	tg.tempFile("src/dir/d.go", `package dir1539		import "./x"1540		var _ = x.X1541	`)1542	tg.runFail("build", "dir")1543	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")15441545	// ... even in a test.1546	tg.tempFile("src/dir/d.go", `package dir1547	`)1548	tg.tempFile("src/dir/d_test.go", `package dir1549		import "./x"1550		import "testing"1551		var _ = x.X1552		func TestFoo(t *testing.T) {}1553	`)1554	tg.run("build", "dir")1555	tg.runFail("test", "dir")1556	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")15571558	// ... even in an xtest.1559	tg.tempFile("src/dir/d_test.go", `package dir_test1560		import "./x"1561		import "testing"1562		var _ = x.X1563		func TestFoo(t *testing.T) {}1564	`)1565	tg.run("build", "dir")1566	tg.runFail("test", "dir")1567	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")15681569	// Relative import plain ".." should not work.1570	tg.tempFile("src/dir/x/y/y.go", `package dir1571		import ".."1572		var _ = x.X1573	`)1574	tg.runFail("build", "dir/x/y")1575	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")15761577	// ... even in a test.1578	tg.tempFile("src/dir/x/y/y.go", `package y1579	`)1580	tg.tempFile("src/dir/x/y/y_test.go", `package y1581		import ".."1582		import "testing"1583		var _ = x.X1584		func TestFoo(t *testing.T) {}1585	`)1586	tg.run("build", "dir/x/y")1587	tg.runFail("test", "dir/x/y")1588	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")15891590	// ... even in an x test.1591	tg.tempFile("src/dir/x/y/y_test.go", `package y_test1592		import ".."1593		import "testing"1594		var _ = x.X1595		func TestFoo(t *testing.T) {}1596	`)1597	tg.run("build", "dir/x/y")1598	tg.runFail("test", "dir/x/y")1599	tg.grepStderr("local import.*in non-local package", "did not diagnose local import")16001601	// Relative import "." should not work.1602	tg.tempFile("src/dir/x/xx.go", `package x1603		import "."1604		var _ = x.X1605	`)1606	tg.runFail("build", "dir/x")1607	tg.grepStderr("cannot import current directory", "did not diagnose import current directory")16081609	// ... even in a test.1610	tg.tempFile("src/dir/x/xx.go", `package x1611	`)1612	tg.tempFile("src/dir/x/xx_test.go", `package x1613		import "."1614		import "testing"1615		var _ = x.X1616		func TestFoo(t *testing.T) {}1617	`)1618	tg.run("build", "dir/x")1619	tg.runFail("test", "dir/x")1620	tg.grepStderr("cannot import current directory", "did not diagnose import current directory")16211622	// ... even in an xtest.1623	tg.tempFile("src/dir/x/xx.go", `package x1624	`)1625	tg.tempFile("src/dir/x/xx_test.go", `package x_test1626		import "."1627		import "testing"1628		var _ = x.X1629		func TestFoo(t *testing.T) {}1630	`)1631	tg.run("build", "dir/x")1632	tg.runFail("test", "dir/x")1633	tg.grepStderr("cannot import current directory", "did not diagnose import current directory")1634}16351636func TestGoInstallPkgdir(t *testing.T) {1637	skipIfGccgo(t, "gccgo has no standard packages")1638	tooSlow(t, "builds a package with cgo dependencies")1639	// Only the stdlib packages that use cgo have install1640	// targets, (we're using net below) so cgo is required1641	// for the install.1642	testenv.MustHaveCGO(t)16431644	tg := testgo(t)1645	tg.parallel()1646	tg.setenv("GODEBUG", "installgoroot=all")1647	defer tg.cleanup()1648	tg.makeTempdir()1649	pkg := tg.path(".")1650	tg.run("install", "-pkgdir", pkg, "net")1651	tg.mustExist(filepath.Join(pkg, "net.a"))1652	tg.mustNotExist(filepath.Join(pkg, "runtime/cgo.a"))1653}16541655// For issue 14337.1656func TestParallelTest(t *testing.T) {1657	tooSlow(t, "links and runs test binaries")16581659	tg := testgo(t)1660	tg.parallel()1661	defer tg.cleanup()1662	tg.makeTempdir()1663	const testSrc = `package package_test1664		import (1665			"testing"1666		)1667		func TestTest(t *testing.T) {1668		}`1669	tg.tempFile("src/p1/p1_test.go", strings.Replace(testSrc, "package_test", "p1_test", 1))1670	tg.tempFile("src/p2/p2_test.go", strings.Replace(testSrc, "package_test", "p2_test", 1))1671	tg.tempFile("src/p3/p3_test.go", strings.Replace(testSrc, "package_test", "p3_test", 1))1672	tg.tempFile("src/p4/p4_test.go", strings.Replace(testSrc, "package_test", "p4_test", 1))1673	tg.setenv("GOPATH", tg.path("."))1674	tg.run("test", "-p=4", "p1", "p2", "p3", "p4")1675}16761677// Issue 16050 and 21884.1678func TestLinkSysoFiles(t *testing.T) {1679	if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {1680		t.Skip("not linux/amd64")1681	}16821683	tg := testgo(t)1684	defer tg.cleanup()1685	tg.parallel()1686	tg.tempDir("src/syso")1687	tg.tempFile("src/syso/a.syso", ``)1688	tg.tempFile("src/syso/b.go", `package syso`)1689	tg.setenv("GOPATH", tg.path("."))16901691	// We should see the .syso file regardless of the setting of1692	// CGO_ENABLED.16931694	tg.setenv("CGO_ENABLED", "1")1695	tg.run("list", "-f", "{{.SysoFiles}}", "syso")1696	tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=1")16971698	tg.setenv("CGO_ENABLED", "0")1699	tg.run("list", "-f", "{{.SysoFiles}}", "syso")1700	tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=0")17011702	tg.setenv("CGO_ENABLED", "1")1703	tg.run("list", "-msan", "-f", "{{.SysoFiles}}", "syso")1704	tg.grepStdoutNot("a.syso", "unexpected syso file with -msan")1705}17061707// Issue 16120.1708func TestGenerateUsesBuildContext(t *testing.T) {1709	if runtime.GOOS == "windows" {1710		t.Skip("this test won't run under Windows")1711	}17121713	tg := testgo(t)1714	defer tg.cleanup()1715	tg.parallel()1716	tg.tempDir("src/gen")1717	tg.tempFile("src/gen/gen.go", "package gen\n//go:generate echo $GOOS $GOARCH\n")1718	tg.setenv("GOPATH", tg.path("."))17191720	tg.setenv("GOOS", "linux")1721	tg.setenv("GOARCH", "amd64")1722	tg.run("generate", "gen")1723	tg.grepStdout("linux amd64", "unexpected GOOS/GOARCH combination")17241725	tg.setenv("GOOS", "darwin")1726	tg.setenv("GOARCH", "arm64")1727	tg.run("generate", "gen")1728	tg.grepStdout("darwin arm64", "unexpected GOOS/GOARCH combination")1729}17301731func TestGoEnv(t *testing.T) {1732	tg := testgo(t)1733	tg.parallel()1734	defer tg.cleanup()1735	tg.setenv("GOOS", "freebsd") // to avoid invalid pair errors1736	tg.setenv("GOARCH", "arm")1737	tg.run("env", "GOARCH")1738	tg.grepStdout("^arm$", "GOARCH not honored")17391740	tg.run("env", "GCCGO")1741	tg.grepStdout(".", "GCCGO unexpectedly empty")17421743	tg.run("env", "CGO_CFLAGS")1744	tg.grepStdout(".", "default CGO_CFLAGS unexpectedly empty")17451746	tg.setenv("CGO_CFLAGS", "-foobar")1747	tg.run("env", "CGO_CFLAGS")1748	tg.grepStdout("^-foobar$", "CGO_CFLAGS not honored")17491750	tg.setenv("CC", "gcc -fmust -fgo -ffaster")1751	tg.run("env", "CC")1752	tg.grepStdout("gcc", "CC not found")1753	tg.run("env", "GOGCCFLAGS")1754	tg.grepStdout("-ffaster", "CC arguments not found")17551756	tg.run("env", "GOVERSION")1757	envVersion := strings.TrimSpace(tg.stdout.String())17581759	tg.run("version")1760	cmdVersion := strings.TrimSpace(tg.stdout.String())17611762	// If 'go version' is "go version <version> <goos>/<goarch>", then1763	// 'go env GOVERSION' is just "<version>".1764	if cmdVersion == envVersion || !strings.Contains(cmdVersion, envVersion) {1765		t.Fatalf("'go env GOVERSION' %q should be a shorter substring of 'go version' %q", envVersion, cmdVersion)1766	}1767}17681769const (1770	noMatchesPattern = `(?m)^ok.*\[no tests to run\]`1771	okPattern        = `(?m)^ok`1772)17731774// Issue 18044.1775func TestLdBindNow(t *testing.T) {1776	tg := testgo(t)1777	defer tg.cleanup()1778	tg.parallel()1779	tg.setenv("LD_BIND_NOW", "1")1780	tg.run("help")1781}17821783// Issue 18225.1784// This is really a cmd/asm issue but this is a convenient place to test it.1785func TestConcurrentAsm(t *testing.T) {1786	skipIfGccgo(t, "gccgo does not use cmd/asm")1787	tg := testgo(t)1788	defer tg.cleanup()1789	tg.parallel()1790	asm := `DATA ·constants<>+0x0(SB)/8,$01791GLOBL ·constants<>(SB),8,$81792`1793	tg.tempFile("go/src/p/a.s", asm)1794	tg.tempFile("go/src/p/b.s", asm)1795	tg.tempFile("go/src/p/p.go", `package p`)1796	tg.setenv("GOPATH", tg.path("go"))1797	tg.run("build", "p")1798}17991800// Issue 18975.1801func TestFFLAGS(t *testing.T) {1802	testenv.MustHaveCGO(t)18031804	tg := testgo(t)1805	defer tg.cleanup()1806	tg.parallel()18071808	tg.tempFile("p/src/p/main.go", `package main1809		// #cgo FFLAGS: -no-such-fortran-flag1810		import "C"1811		func main() {}1812	`)1813	tg.tempFile("p/src/p/a.f", `! comment`)1814	tg.setenv("GOPATH", tg.path("p"))18151816	// This should normally fail because we are passing an unknown flag,1817	// but issue #19080 points to Fortran compilers that succeed anyhow.1818	// To work either way we call doRun directly rather than run or runFail.1819	tg.doRun([]string{"build", "-x", "p"})18201821	tg.grepStderr("no-such-fortran-flag", `missing expected "-no-such-fortran-flag"`)1822}18231824// Issue 19198.1825// This is really a cmd/link issue but this is a convenient place to test it.1826func TestDuplicateGlobalAsmSymbols(t *testing.T) {1827	skipIfGccgo(t, "gccgo does not use cmd/asm")1828	tooSlow(t, "links a binary with cgo dependencies")1829	if runtime.GOARCH != "386" && runtime.GOARCH != "amd64" {1830		t.Skipf("skipping test on %s", runtime.GOARCH)1831	}1832	testenv.MustHaveCGO(t)18331834	tg := testgo(t)1835	defer tg.cleanup()1836	tg.parallel()18371838	asm := `1839#include "textflag.h"18401841DATA sym<>+0x0(SB)/8,$01842GLOBL sym<>(SB),(NOPTR+RODATA),$818431844TEXT ·Data(SB),NOSPLIT,$01845	MOVB sym<>(SB), AX1846	MOVB AX, ret+0(FP)1847	RET1848`1849	tg.tempFile("go/src/a/a.s", asm)1850	tg.tempFile("go/src/a/a.go", `package a; func Data() uint8`)1851	tg.tempFile("go/src/b/b.s", asm)1852	tg.tempFile("go/src/b/b.go", `package b; func Data() uint8`)1853	tg.tempFile("go/src/p/p.go", `1854package main1855import "a"1856import "b"1857import "C"1858func main() {1859	_ = a.Data() + b.Data()1860}1861`)1862	tg.setenv("GOPATH", tg.path("go"))1863	exe := tg.path("p.exe")1864	tg.creatingTemp(exe)1865	tg.run("build", "-o", exe, "p")1866}18671868func copyFile(src, dst string, perm fs.FileMode) error {1869	sf, err := os.Open(src)1870	if err != nil {1871		return err1872	}1873	defer sf.Close()18741875	df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)1876	if err != nil {1877		return err1878	}18791880	_, err = io.Copy(df, sf)1881	err2 := df.Close()1882	if err != nil {1883		return err1884	}1885	return err21886}18871888func TestNeedVersion(t *testing.T) {1889	skipIfGccgo(t, "gccgo does not use cmd/compile")1890	tg := testgo(t)1891	defer tg.cleanup()1892	tg.parallel()1893	tg.tempFile("goversion.go", `package main; func main() {}`)1894	path := tg.path("goversion.go")1895	tg.setenv("TESTGO_TOOLCHAIN_VERSION", "go1.testgo")1896	tg.runFail("run", path)1897	tg.grepStderr("compile", "does not match go tool version")1898}18991900func TestBuildmodePIE(t *testing.T) {1901	tooSlow(t, "links binaries")1902	t.Parallel()19031904	if !platform.BuildModeSupported(runtime.Compiler, "pie", runtime.GOOS, runtime.GOARCH) {1905		t.Skipf("skipping test because buildmode=pie is not supported on %s/%s", runtime.GOOS, runtime.GOARCH)1906	}1907	// Skip on alpine until https://go.dev/issues/54354 resolved.1908	if strings.HasSuffix(testenv.Builder(), "-alpine") {1909		t.Skip("skipping PIE tests on alpine; see https://go.dev/issues/54354")1910	}1911	t.Run("non-cgo", func(t *testing.T) {1912		testBuildmodePIE(t, false, true)1913	})1914	t.Run("cgo", func(t *testing.T) {1915		testenv.MustHaveCGO(t)1916		testBuildmodePIE(t, true, true)1917	})1918}19191920func TestWindowsDefaultBuildmodIsPIE(t *testing.T) {1921	if runtime.GOOS != "windows" {1922		t.Skip("skipping windows only test")1923	}1924	tooSlow(t, "links binaries")1925	t.Parallel()19261927	t.Run("non-cgo", func(t *testing.T) {1928		testBuildmodePIE(t, false, false)1929	})1930	t.Run("cgo", func(t *testing.T) {1931		testenv.MustHaveCGO(t)1932		testBuildmodePIE(t, true, false)1933	})1934}19351936func testBuildmodePIE(t *testing.T, useCgo, setBuildmodeToPIE bool) {1937	tg := testgo(t)1938	defer tg.cleanup()1939	tg.parallel()19401941	var s string1942	if useCgo {1943		s = `import "C";`1944	}1945	tg.tempFile("main.go", fmt.Sprintf(`package main;%s func main() { print("hello") }`, s))1946	src := tg.path("main.go")1947	obj := tg.path("main.exe")1948	args := []string{"build"}1949	if setBuildmodeToPIE {1950		args = append(args, "-buildmode=pie")1951	}1952	args = append(args, "-o", obj, src)1953	tg.run(args...)19541955	switch runtime.GOOS {1956	case "linux", "android", "freebsd":1957		f, err := elf.Open(obj)1958		if err != nil {1959			t.Fatal(err)1960		}1961		defer f.Close()1962		if f.Type != elf.ET_DYN {1963			t.Errorf("PIE type must be ET_DYN, but %s", f.Type)1964		}1965	case "darwin", "ios":1966		f, err := macho.Open(obj)1967		if err != nil {1968			t.Fatal(err)1969		}1970		defer f.Close()1971		if f.Flags&macho.FlagDyldLink == 0 {1972			t.Error("PIE must have DyldLink flag, but not")1973		}1974		if f.Flags&macho.FlagPIE == 0 {1975			t.Error("PIE must have PIE flag, but not")1976		}1977	case "windows":1978		f, err := pe.Open(obj)1979		if err != nil {1980			t.Fatal(err)1981		}1982		defer f.Close()1983		if f.Section(".reloc") == nil {1984			t.Error(".reloc section is not present")1985		}1986		if (f.FileHeader.Characteristics & pe.IMAGE_FILE_RELOCS_STRIPPED) != 0 {1987			t.Error("IMAGE_FILE_RELOCS_STRIPPED flag is set")1988		}1989		var dc uint161990		switch oh := f.OptionalHeader.(type) {1991		case *pe.OptionalHeader32:1992			dc = oh.DllCharacteristics1993		case *pe.OptionalHeader64:1994			dc = oh.DllCharacteristics1995			if (dc & pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) == 0 {1996				t.Error("IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA flag is not set")1997			}1998		default:1999			t.Fatalf("unexpected optional header type of %T", f.OptionalHeader)2000		}

Code quality findings 60

Defer inside loop; deferred calls accumulate until the function returns, not until the loop iteration ends. This can cause resource leaks
warning correctness defer-in-loop
defer tg.cleanup()
Defer inside loop; deferred calls accumulate until the function returns, not until the loop iteration ends. This can cause resource leaks
warning correctness defer-in-loop
defer tg.cleanup()
Defer inside loop; deferred calls accumulate until the function returns, not until the loop iteration ends. This can cause resource leaks
warning correctness defer-in-loop
defer tg.cleanup()
Blank identifier discarding results; verify intentional ignoring of return values
warning correctness blank-identifier-discard
var _ = x.X
Blank identifier discarding results; verify intentional ignoring of return values
warning correctness blank-identifier-discard
var _ = x.X
Blank identifier discarding results; verify intentional ignoring of return values
warning correctness blank-identifier-discard
var _ = x.X
Blank identifier discarding results; verify intentional ignoring of return values
warning correctness blank-identifier-discard
var _ = x.X
Blank identifier discarding results; verify intentional ignoring of return values
warning correctness blank-identifier-discard
var _ = x.X
Blank identifier discarding results; verify intentional ignoring of return values
warning correctness blank-identifier-discard
var _ = x.X
Blank identifier discarding results; verify intentional ignoring of return values
warning correctness blank-identifier-discard
var _ = x.X
Blank identifier discarding results; verify intentional ignoring of return values
warning correctness blank-identifier-discard
var _ = x.X
Blank identifier discarding results; verify intentional ignoring of return values
warning correctness blank-identifier-discard
var _ = x.X
Blank identifier discarding results; verify intentional ignoring of return values
warning correctness blank-identifier-discard
var _ = x.X
Blank identifier discarding results; verify intentional ignoring of return values
warning correctness blank-identifier-discard
var _ = x.X
Blank identifier discarding results; verify intentional ignoring of return values
warning correctness blank-identifier-discard
var _ = x.X
Blank identifier discarding results; verify intentional ignoring of return values
warning correctness blank-identifier-discard
var _ = x.X
Blank identifier discarding results; verify intentional ignoring of return values
warning correctness blank-identifier-discard
_ = a.Data() + b.Data()
Blank identifier discarding results; verify intentional ignoring of return values
warning correctness blank-identifier-discard
_ = new(a.Type)
Defer inside loop; deferred calls accumulate until the function returns, not until the loop iteration ends. This can cause resource leaks
warning correctness defer-in-loop
defer tg.cleanup()
Hidden side effects; favor explicit initialization in main() or functions
info correctness func-init
func init() {
Deeply nested control structures reduce readability; consider extracting to functions or using early returns
info maintainability deep-nesting
if v := os.Getenv("TESTGO_TOOLCHAIN_VERSION"); v != "" {
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
if shortFile := search.InDir(file, filepath.Join(testGOROOT, "src")); shortFile != "" {
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
return fmt.Errorf("%stestgo must not write to GOROOT (installing to %s) (%v)", callerPos, filepath.Join("GOROOT", rel), notice)
Multiple appends without pre-allocation; use make() with capacity when size is known
info performance append-without-prealloc
interceptors = append(interceptors,
Formatted output to console; prefer structured logging for consistency
info correctness fmt-printf
fmt.Printf("cmd/go test is not compatible with $GO_GCFLAGS being set\n")
Formatted output to console; prefer structured logging for consistency
info correctness fmt-printf
fmt.Printf("SKIP\n")
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
testBin = filepath.Join(testTmpDir, "testbin")
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
testGo = filepath.Join(testBin, "go"+exeSuffix)
Fixed delays can mask issues; prefer timers or channels for synchronization
info correctness time-sleep
time.Sleep(mtimeTick)
Multiple appends without pre-allocation; use make() with capacity when size is known
info performance append-without-prealloc
tg.env = append([]string(nil), os.Environ()...)
Multiple appends without pre-allocation; use make() with capacity when size is known
info performance append-without-prealloc
tg.env = append(tg.env, "GO111MODULE=off", "TESTGONETWORK=panic")
Multiple appends without pre-allocation; use make() with capacity when size is known
info performance append-without-prealloc
tg.env = append(tg.env, "TESTGOVCSREMOTE=panic")
Range over slice copies each element by value; use index or pointer receiver for large structs to avoid copies
info performance copy-large-struct
for i, v := range tg.env {
Regexp compiled inside function; compile once at package level to avoid recompilation on each call
info performance regexp-compile-in-func
re := regexp.MustCompile(match)
Regexp compiled inside function; compile once at package level to avoid recompilation on each call
info performance regexp-compile-in-func
re := regexp.MustCompile(match)
Multiple appends without pre-allocation; use make() with capacity when size is known
info performance append-without-prealloc
tg.temps = append(tg.temps, path)
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
tg.must(os.MkdirAll(filepath.Join(tg.tempdir, filepath.Dir(path)), 0755))
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
tg.must(os.WriteFile(filepath.Join(tg.tempdir, path), bytes, 0644))
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
if err := os.MkdirAll(filepath.Join(tg.tempdir, path), 0755); err != nil && !os.IsExist(err) {
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
return filepath.Join(tg.tempdir, name)
Multiple appends without pre-allocation; use make() with capacity when size is known
info performance append-without-prealloc
dirs = append(dirs, filepath.Join("src", pkg))
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
dirs = append(dirs, filepath.Join("src", pkg))
Multiple appends without pre-allocation; use make() with capacity when size is known
info performance append-without-prealloc
dirs = append(dirs,
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
filepath.Join("pkg/tool", goHostOS+"_"+goHostArch),
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
srcdir := filepath.Join(testGOROOT, copydir)
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
tg.tempDir(filepath.Join("goroot", copydir))
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
dest := filepath.Join("goroot", copydir, srcrel)
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
if strings.Contains(copydir, filepath.Join("pkg", "tool")) {
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
file = filepath.Join(dir, file)
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("foo", "quxx"))+` \(from \$GOROOT\)$`) != 1 {
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("testdata", "a", "src", "foo", "quxx"))+` \(from \$GOPATH\)$`) != 1 {
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("testdata", "b", "src", "foo", "quxx"))+`$`) != 1 {
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
tg.mustExist(filepath.Join(pkg, "net.a"))
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
tg.mustNotExist(filepath.Join(pkg, "runtime/cgo.a"))
Can cause issues on Windows consider filepath.Join instead
info correctness path-join-windows
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
Hidden side effects; favor explicit initialization in main() or functions
info correctness func-init
func init() {}
Unstructured output; use a structured logging library (e.g., slog, zap, zerolog, logrus)
info correctness fmt-println
func main() { fmt.Println(C.val) }

Security findings 4

Ensure restrictive umask values
security permissive-file-mode
if err := os.Mkdir(testBin, 0777); err != nil {
Ensure restrictive umask values
security permissive-file-mode
os.Chmod(path, 0777)
Ensure restrictive umask values
security permissive-file-mode
os.Chmod(tg.path(dest), 0777)
Ensure restrictive umask values
security permissive-file-mode
tg.must(os.MkdirAll(filepath.Dir(target2), 0777))

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.