Defer inside loop; deferred calls accumulate until the function returns, not until the loop iteration ends. This can cause resource leaks
defer tg.cleanup()
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 }
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.