diff options
Diffstat (limited to 'src/cmd/go/testdata/script')
801 files changed, 46731 insertions, 0 deletions
diff --git a/src/cmd/go/testdata/script/README b/src/cmd/go/testdata/script/README new file mode 100644 index 0000000..792a158 --- /dev/null +++ b/src/cmd/go/testdata/script/README @@ -0,0 +1,425 @@ +This file is generated by 'go generate cmd/go'. DO NOT EDIT. + +This directory holds test scripts *.txt run during 'go test cmd/go'. +To run a specific script foo.txt + + go test cmd/go -run=Script/^foo$ + +In general script files should have short names: a few words, not whole sentences. +The first word should be the general category of behavior being tested, +often the name of a go subcommand (list, build, test, ...) or concept (vendor, pattern). + +Each script is a text archive (go doc internal/txtar). +The script begins with an actual command script to run +followed by the content of zero or more supporting files to +create in the script's temporary file system before it starts executing. + +As an example, run_hello.txt says: + + # hello world + go run hello.go + stderr 'hello world' + ! stdout . + + -- hello.go -- + package main + func main() { println("hello world") } + +Each script runs in a fresh temporary work directory tree, available to scripts as $WORK. +Scripts also have access to other environment variables, including: + + GOARCH=<target GOARCH> + GOCACHE=<actual GOCACHE being used outside the test> + GOEXE=<executable file suffix: .exe on Windows, empty on other systems> + GOOS=<target GOOS> + GOPATH=$WORK/gopath + GOPROXY=<local module proxy serving from cmd/go/testdata/mod> + GOROOT=<actual GOROOT> + GOROOT_FINAL=<actual GOROOT_FINAL> + TESTGO_GOROOT=<GOROOT used to build cmd/go, for use in tests that may change GOROOT> + HOME=/no-home + PATH=<actual PATH> + TMPDIR=$WORK/tmp + GODEBUG=<actual GODEBUG> + devnull=<value of os.DevNull> + goversion=<current Go version; for example, 1.12> + +On Plan 9, the variables $path and $home are set instead of $PATH and $HOME. +On Windows, the variables $USERPROFILE and $TMP are set instead of +$HOME and $TMPDIR. + +The lines at the top of the script are a sequence of commands to be executed by +a small script engine configured in ../../script_test.go (not the system shell). + +The scripts' supporting files are unpacked relative to $GOPATH/src +(aka $WORK/gopath/src) and then the script begins execution in that directory as +well. Thus the example above runs in $WORK/gopath/src with GOPATH=$WORK/gopath +and $WORK/gopath/src/hello.go containing the listed contents. + +Each line of a script is parsed into a sequence of space-separated command +words, with environment variable expansion within each word and # marking +an end-of-line comment. Additional variables named ':' and '/' are expanded +within script arguments (expanding to the value of os.PathListSeparator and +os.PathSeparator respectively) but are not inherited in subprocess environments. + +Adding single quotes around text keeps spaces in that text from being treated +as word separators and also disables environment variable expansion. Inside a +single-quoted block of text, a repeated single quote indicates a literal single +quote, as in: + + 'Don''t communicate by sharing memory.' + +A line beginning with # is a comment and conventionally explains what is being +done or tested at the start of a new section of the script. + +Commands are executed one at a time, and errors are checked for each command; +if any command fails unexpectedly, no subsequent commands in the script are +executed. The command prefix ! indicates that the command on the rest of the +line (typically go or a matching predicate) must fail instead of succeeding. +The command prefix ? indicates that the command may or may not succeed, but the +script should continue regardless. + +The command prefix [cond] indicates that the command on the rest of the line +should only run when the condition is satisfied. + +A condition can be negated: [!root] means to run the rest of the line only if +the user is not root. Multiple conditions may be given for a single command, +for example, '[linux] [amd64] skip'. The command will run if all conditions are +satisfied. + +When TestScript runs a script and the script fails, by default TestScript shows +the execution of the most recent phase of the script (since the last # comment) +and only shows the # comments for earlier phases. For example, here is a +multi-phase script with a bug in it: + + # GOPATH with p1 in d2, p2 in d2 + env GOPATH=$WORK${/}d1${:}$WORK${/}d2 + + # build & install p1 + env + go install -i p1 + ! stale p1 + ! stale p2 + + # modify p2 - p1 should appear stale + cp $WORK/p2x.go $WORK/d2/src/p2/p2.go + stale p1 p2 + + # build & install p1 again + go install -i p11 + ! stale p1 + ! stale p2 + + -- $WORK/d1/src/p1/p1.go -- + package p1 + import "p2" + func F() { p2.F() } + -- $WORK/d2/src/p2/p2.go -- + package p2 + func F() {} + -- $WORK/p2x.go -- + package p2 + func F() {} + func G() {} + +The bug is that the final phase installs p11 instead of p1. The test failure looks like: + + $ go test -run=Script + --- FAIL: TestScript (3.75s) + --- FAIL: TestScript/install_rebuild_gopath (0.16s) + script_test.go:223: + # GOPATH with p1 in d2, p2 in d2 (0.000s) + # build & install p1 (0.087s) + # modify p2 - p1 should appear stale (0.029s) + # build & install p1 again (0.022s) + > go install -i p11 + [stderr] + can't load package: package p11: cannot find package "p11" in any of: + /Users/rsc/go/src/p11 (from $GOROOT) + $WORK/d1/src/p11 (from $GOPATH) + $WORK/d2/src/p11 + [exit status 1] + FAIL: unexpected go command failure + + script_test.go:73: failed at testdata/script/install_rebuild_gopath.txt:15 in $WORK/gopath/src + + FAIL + exit status 1 + FAIL cmd/go 4.875s + $ + +Note that the commands in earlier phases have been hidden, so that the relevant +commands are more easily found, and the elapsed time for a completed phase +is shown next to the phase heading. To see the entire execution, use "go test -v", +which also adds an initial environment dump to the beginning of the log. + +Note also that in reported output, the actual name of the per-script temporary directory +has been consistently replaced with the literal string $WORK. + +The cmd/go test flag -testwork (which must appear on the "go test" command line after +standard test flags) causes each test to log the name of its $WORK directory and other +environment variable settings and also to leave that directory behind when it exits, +for manual debugging of failing tests: + + $ go test -run=Script -work + --- FAIL: TestScript (3.75s) + --- FAIL: TestScript/install_rebuild_gopath (0.16s) + script_test.go:223: + WORK=/tmp/cmd-go-test-745953508/script-install_rebuild_gopath + GOARCH= + GOCACHE=/Users/rsc/Library/Caches/go-build + GOOS= + GOPATH=$WORK/gopath + GOROOT=/Users/rsc/go + HOME=/no-home + TMPDIR=$WORK/tmp + exe= + + # GOPATH with p1 in d2, p2 in d2 (0.000s) + # build & install p1 (0.085s) + # modify p2 - p1 should appear stale (0.030s) + # build & install p1 again (0.019s) + > go install -i p11 + [stderr] + can't load package: package p11: cannot find package "p11" in any of: + /Users/rsc/go/src/p11 (from $GOROOT) + $WORK/d1/src/p11 (from $GOPATH) + $WORK/d2/src/p11 + [exit status 1] + FAIL: unexpected go command failure + + script_test.go:73: failed at testdata/script/install_rebuild_gopath.txt:15 in $WORK/gopath/src + + FAIL + exit status 1 + FAIL cmd/go 4.875s + $ + + $ WORK=/tmp/cmd-go-test-745953508/script-install_rebuild_gopath + $ cd $WORK/d1/src/p1 + $ cat p1.go + package p1 + import "p2" + func F() { p2.F() } + $ + +The available commands are: +cat files... + concatenate files and print to the script's stdout buffer + + +cc args... + run the platform C compiler + + +cd dir + change the working directory + + +chmod perm paths... + change file mode bits + + Changes the permissions of the named files or directories to + be equal to perm. + Only numerical permissions are supported. + +cmp [-q] file1 file2 + compare files for differences + + By convention, file1 is the actual data and file2 is the + expected data. + The command succeeds if the file contents are identical. + File1 can be 'stdout' or 'stderr' to compare the stdout or + stderr buffer from the most recent command. + +cmpenv [-q] file1 file2 + compare files for differences, with environment expansion + + By convention, file1 is the actual data and file2 is the + expected data. + The command succeeds if the file contents are identical + after substituting variables from the script environment. + File1 can be 'stdout' or 'stderr' to compare the script's + stdout or stderr buffer. + +cp src... dst + copy files to a target file or directory + + src can include 'stdout' or 'stderr' to copy from the + script's stdout or stderr buffer. + +echo string... + display a line of text + + +env [key[=value]...] + set or log the values of environment variables + + With no arguments, print the script environment to the log. + Otherwise, add the listed key=value pairs to the environment + or print the listed keys. + +exec program [args...] [&] + run an executable program with arguments + + Note that 'exec' does not terminate the script (unlike Unix + shells). + +exists [-readonly] [-exec] file... + check that files exist + + +go [args...] [&] + run the 'go' program provided by the script host + + +grep [-count=N] [-q] 'pattern' file + find lines in a file that match a pattern + + The command succeeds if at least one match (or the exact + count, if given) is found. + The -q flag suppresses printing of matches. + +help [-v] name... + log help text for commands and conditions + + To display help for a specific condition, enclose it in + brackets: 'help [amd64]'. + To display complete documentation when listing all commands, + pass the -v flag. + +mkdir path... + create directories, if they do not already exist + + Unlike Unix mkdir, parent directories are always created if + needed. + +mv old new + rename a file or directory to a new path + + OS-specific restrictions may apply when old and new are in + different directories. + +replace [old new]... file + replace strings in a file + + The 'old' and 'new' arguments are unquoted as if in quoted + Go strings. + +rm path... + remove a file or directory + + If the path is a directory, its contents are removed + recursively. + +skip [msg] + skip the current test + + +sleep duration [&] + sleep for a specified duration + + The duration must be given as a Go time.Duration string. + +stale target... + check that build targets are stale + + +stderr [-count=N] [-q] 'pattern' file + find lines in the stderr buffer that match a pattern + + The command succeeds if at least one match (or the exact + count, if given) is found. + The -q flag suppresses printing of matches. + +stdout [-count=N] [-q] 'pattern' file + find lines in the stdout buffer that match a pattern + + The command succeeds if at least one match (or the exact + count, if given) is found. + The -q flag suppresses printing of matches. + +stop [msg] + stop execution of the script + + The message is written to the script log, but no error is + reported from the script engine. + +symlink path -> target + create a symlink + + Creates path as a symlink to target. + The '->' token (like in 'ls -l' output on Unix) is required. + +wait + wait for completion of background commands + + Waits for all background commands to complete. + The output (and any error) from each command is printed to + the log in the order in which the commands were started. + After the call to 'wait', the script's stdout and stderr + buffers contain the concatenation of the background + commands' outputs. + + + +The available conditions are: +[GOARCH:*] + runtime.GOARCH == <suffix> +[GODEBUG:*] + GODEBUG contains <suffix> +[GOEXPERIMENT:*] + GOEXPERIMENT <suffix> is enabled +[GOOS:*] + runtime.GOOS == <suffix> +[abscc] + default $CC path is absolute and exists +[asan] + GOOS/GOARCH supports -asan +[buildmode:*] + go supports -buildmode=<suffix> +[case-sensitive] + $WORK filesystem is case-sensitive +[cc:*] + go env CC = <suffix> (ignoring the go/env file) +[cgo] + host CGO_ENABLED +[cgolinkext] + platform requires external linking for cgo +[compiler:*] + runtime.Compiler == <suffix> +[cross] + cmd/go GOOS/GOARCH != GOHOSTOS/GOHOSTARCH +[exec:*] + <suffix> names an executable in the test binary's PATH +[fuzz] + GOOS/GOARCH supports -fuzz +[fuzz-instrumented] + GOOS/GOARCH supports -fuzz with instrumentation +[git] + the 'git' executable exists and provides the standard CLI +[go-builder] + GO_BUILDER_NAME is non-empty +[link] + testenv.HasLink() +[mismatched-goroot] + test's GOROOT_FINAL does not match the real GOROOT +[msan] + GOOS/GOARCH supports -msan +[mustlinkext] + platform always requires external linking +[net:*] + can connect to external network host <suffix> +[race] + GOOS/GOARCH supports -race +[root] + os.Geteuid() == 0 +[short] + testing.Short() +[symlink] + testenv.HasSymlink() +[trimpath] + test binary was built with -trimpath +[verbose] + testing.Verbose() + diff --git a/src/cmd/go/testdata/script/autocgo.txt b/src/cmd/go/testdata/script/autocgo.txt new file mode 100644 index 0000000..586c802 --- /dev/null +++ b/src/cmd/go/testdata/script/autocgo.txt @@ -0,0 +1,29 @@ +# Test automatic setting of CGO_ENABLED based on $CC and what's in $PATH. + +[!cgo] skip +[cross] skip + +# Assume we're on a system that can enable cgo normally. +env CGO_ENABLED= +go env CGO_ENABLED +stdout 1 + +# Clearing CC and removing everything but Go from the PATH should usually +# disable cgo: no C compiler anymore (unless the baked-in defaultCC is an +# absolute path and exists. +env CC= +env PATH=$GOROOT/bin +go env CGO_ENABLED +[!abscc] stdout 0 +[abscc] stdout 1 + +# Setting CC should re-enable cgo. +env CC=cc +go env CGO_ENABLED +stdout 1 + +# So should setting CGO_ENABLED. +env CC= +env CGO_ENABLED=1 +go env CGO_ENABLED +stdout 1 diff --git a/src/cmd/go/testdata/script/badgo.txt b/src/cmd/go/testdata/script/badgo.txt new file mode 100644 index 0000000..cf4e258 --- /dev/null +++ b/src/cmd/go/testdata/script/badgo.txt @@ -0,0 +1,50 @@ +go get example.net/badgo@v1.0.0 +go get example.net/badgo@v1.1.0 +go get example.net/badgo@v1.2.0 +go get example.net/badgo@v1.3.0 +go get example.net/badgo@v1.4.0 +go get example.net/badgo@v1.5.0 +! go get example.net/badgo@v1.6.0 +stderr 'invalid go version .X.Y.: must match format 1.23' + +-- go.mod -- +module m + +replace ( + example.net/badgo v1.0.0 => ./v1.0.0 + example.net/badgo v1.1.0 => ./v1.1.0 + example.net/badgo v1.2.0 => ./v1.2.0 + example.net/badgo v1.3.0 => ./v1.3.0 + example.net/badgo v1.4.0 => ./v1.4.0 + example.net/badgo v1.5.0 => ./v1.5.0 + example.net/badgo v1.6.0 => ./v1.6.0 +) + +-- v1.0.0/go.mod -- +module example.net/badgo +go 1.17.0 + +-- v1.1.0/go.mod -- +module example.net/badgo +go 1.17rc2 + +-- v1.2.0/go.mod -- +module example.net/badgo +go 1.17.1 + +-- v1.3.0/go.mod -- +module example.net/badgo +go v1.17.0 + +-- v1.4.0/go.mod -- +module example.net/badgo +go v1.17.0-rc.2 + +-- v1.5.0/go.mod -- +module example.net/badgo +go v1.17.1 + +-- v1.6.0/go.mod -- +module example.net/badgo +go X.Y + diff --git a/src/cmd/go/testdata/script/bug.txt b/src/cmd/go/testdata/script/bug.txt new file mode 100644 index 0000000..f64fb85 --- /dev/null +++ b/src/cmd/go/testdata/script/bug.txt @@ -0,0 +1,58 @@ +# Verify that go bug creates the appropriate URL issue body + +[!GOOS:linux] skip +[short] skip + +go install +go build -o $TMPDIR/go ./go +env BROWSER=$GOPATH/bin/browser PATH=$TMPDIR:$PATH +go bug +exists $TMPDIR/browser +grep '^go version' $TMPDIR/browser +grep '^GOROOT/bin/go version: go version' $TMPDIR/browser +grep '^GOROOT/bin/go tool compile -V: compile version' $TMPDIR/browser +grep '^uname -sr: Linux' $TMPDIR/browser + +-- go.mod -- +module browser + +-- main.go -- +package main + +import ( + "fmt" + "net/url" + "os" + "path/filepath" +) + +func main() { + u, err := url.Parse(os.Args[1]) + if err != nil { + panic(err) + } + body, err := url.PathUnescape(u.Query().Get("body")) + if err != nil { + panic(err) + } + out := filepath.Join(os.TempDir(), "browser") + f, err := os.Create(out) + if err != nil { + panic(err) + } + fmt.Fprintln(f, body) + if err := f.Close(); err != nil { + panic(err) + } +} + +-- go/main.go -- +package main + +import ( + "os" +) + +func main() { + os.Exit(1) +} diff --git a/src/cmd/go/testdata/script/build_GOTMPDIR.txt b/src/cmd/go/testdata/script/build_GOTMPDIR.txt new file mode 100644 index 0000000..4c9129e --- /dev/null +++ b/src/cmd/go/testdata/script/build_GOTMPDIR.txt @@ -0,0 +1,50 @@ +# Set GOCACHE to a clean directory to ensure that 'go build' has work to report. +[!GOOS:windows] env GOCACHE=$WORK/gocache +[GOOS:windows] env GOCACHE=$WORK\gocache + +# 'go build' should use GOTMPDIR if set. +[!GOOS:windows] env GOTMPDIR=$WORK/my-favorite-tmpdir +[GOOS:windows] env GOTMPDIR=$WORK\my-favorite-tmpdir +mkdir $GOTMPDIR +go build -x hello.go +stderr ^WORK=.*my-favorite-tmpdir + +# Make GOTMPDIR a regular file. This prevents the creation of work directories, +# so we can check that certain commands don't create them. +# This simulates running on a full disk or a read-only volume. +rm $GOTMPDIR +cp hello.go $GOTMPDIR # any file will do + +# 'go build' should fail if GOTMPDIR is read-only. +! go build -x . +stderr '^go: creating work dir: \w+ '$GOTMPDIR + +# 'go list' should only fail if it needs to build something. +go list -x . +! stderr 'creating work dir' +stdout m +go list -m all +stdout m +! go list -x -export . +stderr '^go: creating work dir: \w+ '$GOTMPDIR + +# 'go clean -cache' and 'go clean -modcache' should not fail. +go clean -x -cache +! stderr 'creating work dir' +go clean -x -modcache +! stderr 'creating work dir' + +# 'go env' should not fail for specific variables. +# Without arguments, it needs to initialize a builder to load cgo flags, and +# that uses a temporary directory. +! go env +stderr '^go: creating work dir: \w+ '$GOTMPDIR +go env GOROOT + +-- go.mod -- +module m + +go 1.15 +-- hello.go -- +package main +func main() { println("hello") } diff --git a/src/cmd/go/testdata/script/build_acl_windows.txt b/src/cmd/go/testdata/script/build_acl_windows.txt new file mode 100644 index 0000000..2cb60e0 --- /dev/null +++ b/src/cmd/go/testdata/script/build_acl_windows.txt @@ -0,0 +1,44 @@ +[!GOOS:windows] stop +[!exec:icacls] skip +[!exec:powershell] skip + +# Create $WORK\guest and give the Guests group full access. +# Files created within that directory will have different security attributes by default. +mkdir $WORK\guest +exec icacls $WORK\guest /grant '*S-1-5-32-546:(oi)(ci)f' + +env TMP=$WORK\guest +env TEMP=$WORK\guest + +# Build a binary using the guest directory as an intermediate +cd TestACL +go build -o main.exe main.go +# Build the same binary, but write it to the guest directory. +go build -o $TMP\main.exe main.go + +# Read ACLs for the files. +exec powershell -Command 'Get-Acl main.exe | Select -expand AccessToString' +cp stdout $WORK\exe-acl.txt +exec powershell -Command 'Get-Acl main.go | Select -expand AccessToString' +cp stdout $WORK\src-acl.txt +cd $TMP +exec powershell -Command 'Get-Acl main.exe | Select -expand AccessToString' +cp stdout $WORK\guest-acl.txt + +cd $WORK + +# The executable written to the source directory should have the same ACL as the source file. +cmp $WORK\exe-acl.txt $WORK\src-acl.txt + +# The file written to the guest-allowed directory should give Guests control. +grep 'BUILTIN\\Guests\s+Allow' $WORK\guest-acl.txt + +# The file written to the ordinary directory should not. +! grep 'BUILTIN\\Guests\s+Allow' $WORK\exe-acl.txt + + +-- TestACL/go.mod -- +module TestACL +-- TestACL/main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/build_arm.txt b/src/cmd/go/testdata/script/build_arm.txt new file mode 100644 index 0000000..ff2a364 --- /dev/null +++ b/src/cmd/go/testdata/script/build_arm.txt @@ -0,0 +1,13 @@ +[short] skip 'skipping cross-compile in short mode' + +env GOARCH=arm +env GOOS=linux +env GOARM=5 + +go build hello.go +! stderr 'unable to find math.a' + +-- hello.go -- +package main + +func main() {}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/build_buildvcs_auto.txt b/src/cmd/go/testdata/script/build_buildvcs_auto.txt new file mode 100644 index 0000000..cfd5d82 --- /dev/null +++ b/src/cmd/go/testdata/script/build_buildvcs_auto.txt @@ -0,0 +1,91 @@ +# Regression test for https://go.dev/issue/51748: by default, 'go build' should +# not attempt to stamp VCS information when the VCS tool is not present. + +[short] skip +[!git] skip + +cd sub +exec git init . +exec git config user.name 'Nameless Gopher' +exec git config user.email 'nobody@golang.org' +exec git add sub.go +exec git commit -m 'initial state' +cd .. + +exec git init +exec git config user.name 'Nameless Gopher' +exec git config user.email 'nobody@golang.org' +exec git submodule add ./sub +exec git add go.mod example.go +exec git commit -m 'initial state' + + +# Control case: with a git binary in $PATH, +# 'go build' on a package in the same git repo +# succeeds and stamps VCS metadata by default. + +go build -o example.exe . +go version -m example.exe +stdout '^\tbuild\tvcs=git$' +stdout '^\tbuild\tvcs.modified=false$' + + +# Building a binary from a different (nested) VCS repo should not stamp VCS +# info. It should be an error if VCS stamps are requested explicitly with +# '-buildvcs' (since we know the VCS metadata exists), but not an error +# with '-buildvcs=auto'. + +go build -o sub.exe ./sub +go version -m sub.exe +! stdout '^\tbuild\tvcs' + +! go build -buildvcs -o sub.exe ./sub +stderr '\Aerror obtaining VCS status: main package is in repository ".*" but current directory is in repository ".*"\n\tUse -buildvcs=false to disable VCS stamping.\n\z' + +cd ./sub +go build -o sub.exe . +go version -m sub.exe +! stdout '^\tbuild\tvcs' + +! go build -buildvcs -o sub.exe . +stderr '\Aerror obtaining VCS status: main module is in repository ".*" but current directory is in repository ".*"\n\tUse -buildvcs=false to disable VCS stamping.\n\z' +cd .. + + +# After removing 'git' from $PATH, 'go build -buildvcs' should fail... + +env PATH= +env path= +! go build -buildvcs -o example.exe . +stderr 'go: missing Git command\. See https://golang\.org/s/gogetcmd$' + +# ...but by default we should omit VCS metadata when the tool is missing. + +go build -o example.exe . +go version -m example.exe +! stdout '^\tbuild\tvcs' + +# The default behavior can be explicitly set with '-buildvcs=auto'. + +go build -buildvcs=auto -o example.exe . +go version -m example.exe +! stdout '^\tbuild\tvcs' + +# Other flag values should be rejected with a useful error message. + +! go build -buildvcs=hg -o example.exe . +stderr '\Ainvalid boolean value "hg" for -buildvcs: value is neither ''auto'' nor a valid bool\nusage: go build .*\nRun ''go help build'' for details.\n\z' + + +-- go.mod -- +module example + +go 1.18 +-- example.go -- +package main + +func main() {} +-- sub/sub.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/build_cache_arch_mode.txt b/src/cmd/go/testdata/script/build_cache_arch_mode.txt new file mode 100644 index 0000000..931827f --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_arch_mode.txt @@ -0,0 +1,21 @@ +# Issue 9737: verify that GOARM affects the computed build ID + +[short] skip + +# arm +env GOOS=linux +env GOARCH=arm +env GOARM=5 +go install mycmd +env GOARM=7 +stale mycmd + + +-- go.mod -- +module mycmd + +go 1.16 +-- x.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/build_cache_compile.txt b/src/cmd/go/testdata/script/build_cache_compile.txt new file mode 100644 index 0000000..64b391f --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_compile.txt @@ -0,0 +1,21 @@ +env GO111MODULE=off +[short] skip + +# Set up fresh GOCACHE. +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +# Building trivial non-main package should run compiler the first time. +go build -x lib.go +stderr '(compile|gccgo)( |\.exe).*lib\.go' + +# ... but not again ... +go build -x lib.go +! stderr '(compile|gccgo)( |\.exe).*lib\.go' + +# ... unless we use -a. +go build -a -x lib.go +stderr '(compile|gccgo)( |\.exe)' + +-- lib.go -- +package lib diff --git a/src/cmd/go/testdata/script/build_cache_disabled.txt b/src/cmd/go/testdata/script/build_cache_disabled.txt new file mode 100644 index 0000000..cb1a755 --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_disabled.txt @@ -0,0 +1,50 @@ +# The build cache is required to build anything. It also may be needed to +# initialize the build system, which is needed for commands like 'go env'. +# However, there are lots of commands the cache is not needed for, and we +# shouldn't require it when it won't be used. +# +# TODO(golang.org/issue/39882): commands below should work, too. +# * go clean -modcache +# * go env +# * go fix +# * go fmt +# * go generate +# * go get +# * go list (without -export or -compiled) + +env GOCACHE=off + +# Commands that don't completely load packages should work. +go doc fmt +stdout Printf + +! go tool compile -h +stderr usage: + +go version +stdout '^go version' + + +# Module commands that don't load packages should work. +go mod init m +exists go.mod + +go mod edit -require rsc.io/quote@v1.5.2 + +go mod download rsc.io/quote + +go mod graph +stdout rsc.io/quote + +go mod verify + + +# Commands that load but don't build packages should work. +go fmt . + +go doc . + +-- main.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/build_cache_gomips.txt b/src/cmd/go/testdata/script/build_cache_gomips.txt new file mode 100644 index 0000000..0cbf16a --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_gomips.txt @@ -0,0 +1,40 @@ +env GO111MODULE=off +[short] skip # rebuilds std for mips + +# Set up fresh GOCACHE. +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +# Building for mipsle without setting GOMIPS will use floating point registers. +env GOARCH=mipsle +env GOOS=linux +go build -gcflags=-S f.go +stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+ + +# Clean cache +go clean -cache + +# Building with GOMIPS=softfloat will not use floating point registers +env GOMIPS=softfloat +go build -gcflags=-S f.go +! stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+ + +# Clean cache +go clean -cache + +# Build without setting GOMIPS +env GOMIPS= +go build -gcflags=-S f.go +stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+ + +# Building with GOMIPS should still not use floating point registers. +env GOMIPS=softfloat +go build -gcflags=-S f.go +! stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+ + +-- f.go -- +package f + +func F(x float64) float64 { + return x + x +} diff --git a/src/cmd/go/testdata/script/build_cache_link.txt b/src/cmd/go/testdata/script/build_cache_link.txt new file mode 100644 index 0000000..b9c740a --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_link.txt @@ -0,0 +1,26 @@ +env GO111MODULE=off +[short] skip + +# Set up fresh GOCACHE. +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +# Building a main package should run the compiler and linker ... +go build -o $devnull -x main.go +stderr '(compile|gccgo)( |\.exe).*main\.go' +stderr '(link|gccgo)( |\.exe)' + +# ... and then the linker again ... +go build -o $devnull -x main.go +! stderr '(compile|gccgo)( |\.exe).*main\.go' +stderr '(link|gccgo)( |\.exe)' + +# ... but the output binary can serve as a cache. +go build -o main$GOEXE -x main.go +stderr '(link|gccgo)( |\.exe)' +go build -o main$GOEXE -x main.go +! stderr '(link|gccgo)( |\.exe)' + +-- main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/build_cache_output.txt b/src/cmd/go/testdata/script/build_cache_output.txt new file mode 100644 index 0000000..fc040b4 --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_output.txt @@ -0,0 +1,67 @@ +env GO111MODULE=off +env GODEBUG=gocachetest=1 + +[!compiler:gc] skip +[short] skip # clears cache, rebuilds too much + +# Set up fresh GOCACHE. +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +# Building a trivial non-main package should run compiler the first time. +go build -x -gcflags=-m lib.go +stderr 'compile( |\.exe"?)' +stderr 'lib.go:2.* can inline f' + +# ... but not the second, even though it still prints the compiler output. +go build -x -gcflags=-m lib.go +! stderr 'compile( |\.exe"?)' +stderr 'lib.go:2.* can inline f' + +# Building a trivial main package should run the compiler and linker the first time. +go build -x -gcflags=-m -ldflags='-v -w' main.go +stderr 'compile( |\.exe"?)' +stderr 'main.go:2.* can inline main' # from compiler +stderr 'link(\.exe"?)? -' +stderr '\d+ symbols' # from linker + +# ... but not the second, even though it still prints the compiler and linker output. +go build -x -gcflags=-m -ldflags='-v -w' main.go +! stderr 'compile( |\.exe"?)' +stderr 'main.go:2.* can inline main' # from compiler +! stderr 'link(\.exe"?)? -' +stderr '\d+ symbols' # from linker + +# Running a test should run the compiler, linker, and the test the first time. +go test -v -x -gcflags=-m -ldflags=-v p +stderr 'compile( |\.exe"?)' +stderr 'p_test.go:.*can inline Test' # from compile of p_test +stderr 'testmain\.go:.*inlin' # from compile of testmain +stderr 'link(\.exe"?)? -' +stderr '\d+ symbols' # from linker +stderr 'p\.test( |\.exe"?)' +stdout 'TEST' # from test + +# ... but not the second, even though it still prints the compiler, linker, and test output. +go test -v -x -gcflags=-m -ldflags=-v p +! stderr 'compile( |\.exe"?)' +stderr 'p_test.go:.*can inline Test' # from compile of p_test +stderr 'testmain\.go:.*inlin' # from compile of testmain +! stderr 'link(\.exe"?)? -' +stderr '\d+ symbols' # from linker +! stderr 'p\.test( |\.exe"?)' +stdout 'TEST' # from test + + +-- lib.go -- +package p +func f(x *int) *int { return x } + +-- main.go -- +package main +func main() {} + +-- p/p_test.go -- +package p +import "testing" +func Test(t *testing.T) {println("TEST")} diff --git a/src/cmd/go/testdata/script/build_cache_trimpath.txt b/src/cmd/go/testdata/script/build_cache_trimpath.txt new file mode 100644 index 0000000..7ee3c3b --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_trimpath.txt @@ -0,0 +1,47 @@ +[short] skip +env GO111MODULE=on + +# Set up fresh GOCACHE. +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +cd $WORK +go build -o a.out + +# Varying -trimpath should cause a rebuild. +go build -x -o a.out -trimpath +stderr '(compile|gccgo)( |\.exe)' +stderr 'link( |\.exe)' + +# Two distinct versions of the same module with identical content should +# still be cached separately. +# Verifies golang.org/issue/35412. +go get example.com/stack@v1.0.0 +go run -trimpath printstack.go +stdout '^example.com/stack@v1.0.0/stack.go$' +go get example.com/stack@v1.0.1 +go run -trimpath printstack.go +stdout '^example.com/stack@v1.0.1/stack.go$' + +-- $WORK/hello.go -- +package main +func main() { println("hello") } + +-- $WORK/printstack.go -- +// +build ignore + +package main + +import ( + "fmt" + + "example.com/stack" +) + +func main() { + fmt.Println(stack.TopFile()) +} +-- $WORK/go.mod -- +module m + +go 1.14 diff --git a/src/cmd/go/testdata/script/build_cc_cache_issue64423.txt b/src/cmd/go/testdata/script/build_cc_cache_issue64423.txt new file mode 100644 index 0000000..f1bc2c3 --- /dev/null +++ b/src/cmd/go/testdata/script/build_cc_cache_issue64423.txt @@ -0,0 +1,121 @@ +# Regression test for https://go.dev/issue/64423: +# +# When we parse the version for a Clang binary, we should accept +# an arbitrary vendor prefix, which (as of 2023) may be injected +# by defining CLANG_VENDOR when building clang itself. +# +# Since we don't want to actually rebuild the Clang toolchain in +# this test, we instead simulate it by injecting a fake "clang" +# binary that runs the real one as a subprocess. + +[!cgo] skip +[short] skip 'builds and links a fake clang binary' +[!cc:clang] skip 'test is specific to clang version parsing' + +# Save the location of the real clang command for our fake one to use. +go run ./which clang +cp stdout $WORK/.realclang + +# Build a fake clang and ensure that it is the one in $PATH. +mkdir $WORK/bin +go build -o $WORK/bin/clang$GOEXE ./fakeclang +[!GOOS:plan9] env PATH=$WORK${/}bin +[GOOS:plan9] env path=$WORK${/}bin + +# Force CGO_ENABLED=1 so that the following commands should error +# out if the fake clang doesn't work. +env CGO_ENABLED=1 + +# The bug in https://go.dev/issue/64423 resulted in cache keys that +# didn't contain any information about the C compiler. +# Since the bug was in cache key computation, isolate the cache: +# if we change the way caching works, we want the test to fail +# instead of accidentally reusing the cached information from a +# previous test run. +env GOCACHE=$WORK${/}.cache +mkdir $GOCACHE + +go build -x runtime/cgo + + # Tell our fake clang to stop working. + # Previously, 'go build -x runtime/cgo' would continue to + # succeed because both the broken clang and the non-broken one + # resulted in a cache key with no clang version information. +env GO_BREAK_CLANG=1 +! go build -x runtime/cgo +stderr '# runtime/cgo\nGO_BREAK_CLANG is set' + +-- go.mod -- +module example/issue64423 +go 1.20 +-- which/main.go -- +package main + +import ( + "os" + "os/exec" +) + +func main() { + path, err := exec.LookPath(os.Args[1]) + if err != nil { + panic(err) + } + os.Stdout.WriteString(path) +} +-- fakeclang/main.go -- +package main + +import ( + "bufio" + "bytes" + "log" + "os" + "os/exec" + "path/filepath" + "strings" +) + +func main() { + if os.Getenv("GO_BREAK_CLANG") != "" { + os.Stderr.WriteString("GO_BREAK_CLANG is set\n") + os.Exit(1) + } + + b, err := os.ReadFile(filepath.Join(os.Getenv("WORK"), ".realclang")) + if err != nil { + log.Fatal(err) + } + clang := string(bytes.TrimSpace(b)) + cmd := exec.Command(clang, os.Args[1:]...) + cmd.Stdout = os.Stdout + stderr, err := cmd.StderrPipe() + if err != nil { + log.Fatal(err) + } + + if err := cmd.Start(); err != nil { + log.Fatal(err) + } + + r := bufio.NewReader(stderr) + for { + line, err := r.ReadString('\n') + if line != "" { + if strings.Contains(line, "clang version") { + // Simulate a clang version string with an arbitrary vendor prefix. + const vendorString = "Gopher Solutions Unlimited " + os.Stderr.WriteString(vendorString) + } + os.Stderr.WriteString(line) + } + if err != nil { + break + } + } + os.Stderr.Close() + + if err := cmd.Wait(); err != nil { + os.Exit(1) + } +} diff --git a/src/cmd/go/testdata/script/build_cd_gopath_different.txt b/src/cmd/go/testdata/script/build_cd_gopath_different.txt new file mode 100644 index 0000000..64d7d74 --- /dev/null +++ b/src/cmd/go/testdata/script/build_cd_gopath_different.txt @@ -0,0 +1,73 @@ +[compiler:gccgo] skip 'gccgo does not support -ldflags -X' +env GO111MODULE=off +go build run_go.go + +# Apply identity function to GOPATH +exec ./run_go$GOEXE $GOPATH/src/my.pkg/main $GOPATH IDENTITY build -o $WORK/tmp/a.exe -ldflags -X=my.pkg.Text=linkXworked +exec $WORK/tmp/a.exe +stderr 'linkXworked' +rm $WORK/tmp/a.exe + +[!GOOS:windows] stop 'rest of the tests only apply to Windows' + +# Replace '\' with '/' in GOPATH +exec ./run_go$GOEXE $GOPATH/src/my.pkg/main $GOPATH REPLACE_SLASH build -o $WORK/tmp/a.exe -ldflags -X=my.pkg.Text=linkXworked +exec $WORK/tmp/a.exe +stderr 'linkXworked' +rm $WORK/tmp/a.exe + +# Apply identity function to GOPATH +exec ./run_go$GOEXE $GOPATH/src/my.pkg/main $GOPATH UPPER build -o $WORK/tmp/a.exe -ldflags -X=my.pkg.Text=linkXworked +exec $WORK/tmp/a.exe +stderr 'linkXworked' +rm $WORK/tmp/a.exe + +# Apply identity function to GOPATH +exec ./run_go$GOEXE $GOPATH/src/my.pkg/main $GOPATH LOWER build -o $WORK/tmp/a.exe -ldflags -X=my.pkg.Text=linkXworked +exec $WORK/tmp/a.exe +stderr 'linkXworked' +rm $WORK/tmp/a.exe + +-- run_go.go -- +package main + +import ( + "fmt" + "os" + "os/exec" + "strings" +) + +func main() { + dir := os.Args[1] + gopath := os.Args[2] + switch os.Args[3] { + case "IDENTITY": + case "REPLACE_SLASH": gopath = strings.ReplaceAll(gopath, `\`, `/`) + case "UPPER": gopath = strings.ToUpper(gopath) + case "LOWER": gopath = strings.ToLower(gopath) + default: fmt.Fprintln(os.Stderr, "bad op"); os.Exit(1) + } + cmd := exec.Command("go", os.Args[4:]...) + cmd.Dir = dir + cmd.Env = append(os.Environ(), "GOPATH="+gopath) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +-- my.pkg/main/main.go -- +package main + +import "my.pkg" + +func main() { + println(pkg.Text) +} +-- my.pkg/pkg.go -- +package pkg + +var Text = "unset" diff --git a/src/cmd/go/testdata/script/build_cgo_consistent_results.txt b/src/cmd/go/testdata/script/build_cgo_consistent_results.txt new file mode 100644 index 0000000..f22994f --- /dev/null +++ b/src/cmd/go/testdata/script/build_cgo_consistent_results.txt @@ -0,0 +1,23 @@ +[short] skip +[!cgo] skip + +[GOOS:solaris] skip "skipping on Solaris; see golang.org/issue/13247" +[GOOS:illumos] skip "skipping on Solaris; see golang.org/issue/13247" + +go build -o $WORK/exe1$GOEXE cgotest +go build -x -o $WORK/exe2$GOEXE cgotest + +# TODO(matloob): skip if stderr does not contain '-fdebug-prefix-map=\$WORK' + +cmp $WORK/exe1$GOEXE $WORK/exe2$GOEXE + +-- go.mod -- +module cgotest + +go 1.16 +-- m.go -- +package cgotest + +import "C" + +var _ C.int diff --git a/src/cmd/go/testdata/script/build_cgo_error.txt b/src/cmd/go/testdata/script/build_cgo_error.txt new file mode 100644 index 0000000..c11ab46 --- /dev/null +++ b/src/cmd/go/testdata/script/build_cgo_error.txt @@ -0,0 +1,17 @@ +[short] skip +[!cgo] skip + +! go build . +stderr '# foo\nfoo.c:' +! stderr 'EXTRA string' + +-- go.mod -- +module foo + +go 1.20 +-- foo.go -- +package foo + +import "C" +-- foo.c -- +#include "doesnotexist.h"
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/build_concurrent_backend.txt b/src/cmd/go/testdata/script/build_concurrent_backend.txt new file mode 100644 index 0000000..9cac635 --- /dev/null +++ b/src/cmd/go/testdata/script/build_concurrent_backend.txt @@ -0,0 +1,10 @@ +# Tests golang.org/issue/48490 +# cmd/go should enable concurrent compilation by default + +# Reset all experiments, since one of them can disable +# concurrent compilation, e.g: fieldtrack. +env GOEXPERIMENT=none + +env GOMAXPROCS=4 +go build -n -x -a fmt +stderr ' -c=4 ' diff --git a/src/cmd/go/testdata/script/build_cwd_newline.txt b/src/cmd/go/testdata/script/build_cwd_newline.txt new file mode 100644 index 0000000..91cb57f --- /dev/null +++ b/src/cmd/go/testdata/script/build_cwd_newline.txt @@ -0,0 +1,138 @@ +[GOOS:windows] skip 'filesystem normalizes / to \' +[GOOS:plan9] skip 'filesystem disallows \n in paths' + +# If the directory path containing a package to be built includes a newline, +# the go command should refuse to even try to build the package. + +env DIR=$WORK${/}${newline}'package main'${newline}'func main() { panic("uh-oh")'${newline}'/*' + +mkdir $DIR +cd $DIR +exec pwd +cp $WORK/go.mod ./go.mod +cp $WORK/main.go ./main.go +cp $WORK/main_nocgo.go ./main_nocgo.go +cp $WORK/main_test.go ./main_test.go + +! go build -o $devnull . +stderr 'package example: invalid package directory .*uh-oh' + +[cgo] ! go build -o $devnull main.go +[!cgo] ! go build -o $devnull main_nocgo.go +stderr 'package command-line-arguments: invalid package directory .*uh-oh' + +! go run . +stderr 'package example: invalid package directory .*uh-oh' + +[cgo] ! go run main.go +[!cgo] ! go run main_nocgo.go +stderr 'package command-line-arguments: invalid package directory .*uh-oh' + +! go test . +stderr 'package example: invalid package directory .*uh-oh' + +[cgo] ! go test -v main.go main_test.go +[!cgo] ! go test -v main_nocgo.go main_test.go +stderr 'package command-line-arguments: invalid package directory .*uh-oh' + +go list -compiled -e -f '{{with .CompiledGoFiles}}{{.}}{{end}}' . +! stdout . +! stderr . +! exists obj_ + + +# The cgo tool should only accept the source file if the working directory +# is not written in line directives in the resulting files. + +[cgo] ! go tool cgo main.go +[cgo] stderr 'cgo: input path contains newline character: .*uh-oh' +[cgo] ! exists _obj + +[cgo] go tool cgo -trimpath=$PWD main.go +[cgo] grep '//line main\.go:1:1' _obj/main.cgo1.go +[cgo] ! grep 'uh-oh' _obj/main.cgo1.go +[cgo] rm _obj + + +# Since we do preserve $PWD (or set it appropriately) for commands, and we do +# not resolve symlinks unnecessarily, referring to the contents of the unsafe +# directory via a safe symlink should be ok, and should not inject the data from +# the symlink target path. + +[!symlink] stop 'remainder of test checks symlink behavior' +[short] stop 'links and runs binaries' + +symlink $WORK${/}link -> $DIR + +[cgo] go run $WORK${/}link${/}main.go +[!cgo] go run $WORK${/}link${/}main_nocgo.go +! stdout panic +! stderr panic +stderr '^ok$' + +[cgo] go test -v $WORK${/}link${/}main.go $WORK${/}link${/}main_test.go +[!cgo] go test -v $WORK${/}link${/}main_nocgo.go $WORK${/}link${/}main_test.go +! stdout panic +! stderr panic +stdout '^ok$' # 'go test' combines the test's stdout into stderr + +cd $WORK/link + +[cgo] ! go run $DIR${/}main.go +[!cgo] ! go run $DIR${/}main_nocgo.go +stderr 'package command-line-arguments: invalid package directory .*uh-oh' + +go run . +! stdout panic +! stderr panic +stderr '^ok$' + +[cgo] go run main.go +[!cgo] go run main_nocgo.go +! stdout panic +! stderr panic +stderr '^ok$' + +go test -v +! stdout panic +! stderr panic +stdout '^ok$' # 'go test' combines the test's stdout into stderr + +go test -v . +! stdout panic +! stderr panic +stdout '^ok$' # 'go test' combines the test's stdout into stderr + +[cgo] go tool cgo main.go +[cgo] grep '//line .*'${/}'link'${/}'main\.go:1:1' _obj/main.cgo1.go +[cgo] ! grep 'uh-oh' _obj/main.cgo1.go + +-- $WORK/go.mod -- +module example +go 1.19 +-- $WORK/main.go -- +package main + +import "C" + +func main() { + /* nothing here */ + println("ok") +} +-- $WORK/main_nocgo.go -- +//go:build !cgo + +package main + +func main() { + /* nothing here */ + println("ok") +} +-- $WORK/main_test.go -- +package main + +import "testing" + +func TestMain(*testing.M) { + main() +} diff --git a/src/cmd/go/testdata/script/build_darwin_cc_arch.txt b/src/cmd/go/testdata/script/build_darwin_cc_arch.txt new file mode 100644 index 0000000..df3fa5b --- /dev/null +++ b/src/cmd/go/testdata/script/build_darwin_cc_arch.txt @@ -0,0 +1,24 @@ +# Test that we pass -arch flag to C compiler on Darwin (issue 43692). + +[!GOOS:darwin] skip +[!cgo] skip + +# clear CC, in case user sets it +env CC= + +env CGO_ENABLED=1 + +env GOARCH=amd64 +go build -n -x c.go +stderr 'clang.*-arch x86_64' + +env GOARCH=arm64 +go build -n -x c.go +stderr 'clang.*-arch arm64' + +-- c.go -- +package main + +import "C" + +func main() {} diff --git a/src/cmd/go/testdata/script/build_dash_n_cgo.txt b/src/cmd/go/testdata/script/build_dash_n_cgo.txt new file mode 100644 index 0000000..3f49ef6 --- /dev/null +++ b/src/cmd/go/testdata/script/build_dash_n_cgo.txt @@ -0,0 +1,18 @@ +# Tests golang.org/issue/14944 + +[!cgo] skip + +go build -n foo.go +! stderr 'os.Stat .* no such file or directory' # there shouldn't be a stat of the archive file + +-- foo.go -- +package main + +/* +#include <limits.h> +*/ +import "C" + +func main() { + println(C.INT_MAX) +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/build_dash_o_dev_null.txt b/src/cmd/go/testdata/script/build_dash_o_dev_null.txt new file mode 100644 index 0000000..e415fc2 --- /dev/null +++ b/src/cmd/go/testdata/script/build_dash_o_dev_null.txt @@ -0,0 +1,13 @@ +# Issue #25579 + +[short] skip + +go build -o $devnull hello.go +! exists 'hello'$GOEXE + +-- hello.go -- +package main + +func main() { + println("hello, world") +} diff --git a/src/cmd/go/testdata/script/build_dash_x.txt b/src/cmd/go/testdata/script/build_dash_x.txt new file mode 100644 index 0000000..e5580a2 --- /dev/null +++ b/src/cmd/go/testdata/script/build_dash_x.txt @@ -0,0 +1,48 @@ +[short] skip +[!cgo] skip + +[!exec:/usr/bin/env] skip +[!exec:bash] skip + +mkdir $WORK/tmp/cache +env GOCACHE=$WORK/tmp/cache + +# Before building our test main.go, ensure that an up-to-date copy of +# runtime/cgo is present in the cache. If it isn't, the 'go build' step below +# will fail with "can't open import". See golang.org/issue/29004. +# +# (The fix in golang.org/issue/29004 didn't completely fix the underlying issue: +# cmd/go/internal/load adds a bunch of implicit dependencies +# based on various heuristics, and, due to a bug described in +# https://golang.org/issue/31544#issuecomment-490607180, +# those implicit dependencies are not added early enough during +# loading to properly affect the import graph.) +go build runtime/cgo + +go build -x -o main main.go +cp stderr commands.txt +cat header.txt commands.txt +cp stdout test.sh + +exec ./main +cmp stderr hello.txt +rm ./main + +exec /usr/bin/env bash -x test.sh +exec ./main +cmp stderr hello.txt + +grep '^WORK=(.*)\n' commands.txt + +-- main.go -- +package main + +import "C" + +func main() { + print("hello\n") +} +-- header.txt -- +set -e +-- hello.txt -- +hello diff --git a/src/cmd/go/testdata/script/build_exe.txt b/src/cmd/go/testdata/script/build_exe.txt new file mode 100644 index 0000000..a994d17 --- /dev/null +++ b/src/cmd/go/testdata/script/build_exe.txt @@ -0,0 +1,25 @@ +# go build with -o and -buildmode=exe should report an error on a non-main package. + +! go build -buildmode=exe -o out$GOEXE ./not_main +stderr '-buildmode=exe requires exactly one main package' +! exists out$GOEXE +! go build -buildmode=exe -o out$GOEXE ./main_one ./main_two +stderr '-buildmode=exe requires exactly one main package' +! exists out$GOEXE + +-- go.mod -- +module m + +go 1.16 +-- not_main/not_main.go -- +package not_main + +func F() {} +-- main_one/main_one.go -- +package main + +func main() {} +-- main_two/main_two.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/build_gcflags.txt b/src/cmd/go/testdata/script/build_gcflags.txt new file mode 100644 index 0000000..9603e0b --- /dev/null +++ b/src/cmd/go/testdata/script/build_gcflags.txt @@ -0,0 +1,22 @@ +env GO111MODULE=off + +# Test that the user can override default code generation flags. + +[compiler:gccgo] skip # gccgo does not use -gcflags +[!cgo] skip +[!GOOS:linux] skip # test only works if c-archive implies -shared +[short] skip + +env GOCACHE=$WORK/gocache # Looking for compile commands, so need a clean cache. +go build -x -n -buildmode=c-archive -gcflags=all=-shared=false ./override.go +stderr '^.*/compile (.* )?-shared (.* )?-shared=false' + +-- override.go -- +package main + +import "C" + +//export GoFunc +func GoFunc() {} + +func main() {} diff --git a/src/cmd/go/testdata/script/build_gcflags_order.txt b/src/cmd/go/testdata/script/build_gcflags_order.txt new file mode 100644 index 0000000..3725c89 --- /dev/null +++ b/src/cmd/go/testdata/script/build_gcflags_order.txt @@ -0,0 +1,22 @@ +# Tests golang.org/issue/47682 +# Flags specified with -gcflags should appear after other flags generated by cmd/go. + +cd m +go build -n -gcflags=-lang=go1.17 +stderr ' -lang=go1.16.* -lang=go1.17' +! go build -gcflags='-c 0' +stderr 'compile: -c must be at least 1, got 0' + +-- m/go.mod -- +module example.com + +go 1.16 + +-- m/main.go -- +package main + +func main() { + var s = []int{1, 2, 3} + var pa = (*[2]int)(s[1:]) + println(pa[1]) +} diff --git a/src/cmd/go/testdata/script/build_gopath_order.txt b/src/cmd/go/testdata/script/build_gopath_order.txt new file mode 100644 index 0000000..caf2502 --- /dev/null +++ b/src/cmd/go/testdata/script/build_gopath_order.txt @@ -0,0 +1,36 @@ +# golang.org/issue/14176#issuecomment-179895769 +# golang.org/issue/14192 +# -I arguments to compiler could end up not in GOPATH order, +# leading to unexpected import resolution in the compiler. + +env GO111MODULE=off +env GOPATH=$WORK/p1${:}$WORK/p2 +mkdir $WORK/p1/src/foo $WORK/p2/src/baz +mkdir $WORK/p2/pkg/${GOOS}_${GOARCH} $WORK/p1/src/bar +cp foo.go $WORK/p1/src/foo/foo.go +cp baz.go $WORK/p2/src/baz/baz.go +cp foo.a $WORK/p2/pkg/${GOOS}_${GOARCH}/foo.a +cp bar.go $WORK/p1/src/bar/bar.go + +go install -x bar + +# add in baz.a to the mix +mkdir $WORK/p1/pkg/${GOOS}_${GOARCH} +cp baz.a $WORK/p1/pkg/${GOOS}_${GOARCH}/baz.a +env GOPATH=$WORK/p1${:}$WORK/p2 +go install -x bar +env GOPATH=$WORK/p2${:}$WORK/p1 +go install -x bar + +-- foo.go -- +package foo +-- baz.go -- +package baz +-- foo.a -- +bad +-- baz.a -- +bad +-- bar.go -- +package bar +import _ "baz" +import _ "foo" diff --git a/src/cmd/go/testdata/script/build_ignore_leading_bom.txt b/src/cmd/go/testdata/script/build_ignore_leading_bom.txt new file mode 100644 index 0000000..37141f3 --- /dev/null +++ b/src/cmd/go/testdata/script/build_ignore_leading_bom.txt @@ -0,0 +1,27 @@ +# Per https://golang.org/ref/spec#Source_code_representation: +# a compiler may ignore a UTF-8-encoded byte order mark (U+FEFF) +# if it is the first Unicode code point in the source text. + +go list -f 'Imports: {{.Imports}} EmbedFiles: {{.EmbedFiles}}' . +stdout '^Imports: \[embed m/hello\] EmbedFiles: \[.*file\]$' + +-- go.mod -- +module m + +go 1.16 +-- m.go -- +package main + +import ( + _ "embed" + + "m/hello" +) + +//go:embed file +var s string + +-- hello/hello.go -- +package hello + +-- file -- diff --git a/src/cmd/go/testdata/script/build_import_comment.txt b/src/cmd/go/testdata/script/build_import_comment.txt new file mode 100644 index 0000000..b500340 --- /dev/null +++ b/src/cmd/go/testdata/script/build_import_comment.txt @@ -0,0 +1,68 @@ +# Test in GOPATH mode first. +env GO111MODULE=off +cd m + +# Import comment matches +go build -n works.go + +# Import comment mismatch +! go build -n wrongplace.go +stderr 'wrongplace expects import "my/x"' + +# Import comment syntax error +! go build -n bad.go +stderr 'cannot parse import comment' + +# Import comment conflict +! go build -n conflict.go +stderr 'found import comments' + + +# Test in module mode. +# We ignore import comments, so these commands should succeed. +env GO111MODULE=on + +# Import comment matches +go build -n works.go + +# Import comment mismatch +go build -n wrongplace.go + +# Import comment syntax error +go build -n bad.go + +# Import comment conflict +go build -n conflict.go + +-- m/go.mod -- +module m + +go 1.16 +-- m/bad.go -- +package p + +import "m/bad" +-- m/conflict.go -- +package p + +import "m/conflict" +-- m/works.go -- +package p + +import _ "m/works/x" +-- m/wrongplace.go -- +package p + +import "m/wrongplace" +-- m/bad/bad.go -- +package bad // import +-- m/conflict/a.go -- +package conflict // import "a" +-- m/conflict/b.go -- +package conflict /* import "b" */ +-- m/works/x/x.go -- +package x // import "m/works/x" +-- m/works/x/x1.go -- +package x // important! not an import comment +-- m/wrongplace/x.go -- +package x // import "my/x" diff --git a/src/cmd/go/testdata/script/build_import_cycle.txt b/src/cmd/go/testdata/script/build_import_cycle.txt new file mode 100644 index 0000000..16e4e87 --- /dev/null +++ b/src/cmd/go/testdata/script/build_import_cycle.txt @@ -0,0 +1,13 @@ +# mod_import_cycle covers this error in module mode. +env GO111MODULE=off + +! go build selfimport +stderr -count=1 'import cycle not allowed' + +go list -e -f '{{.Error}}' selfimport # Don't hang forever +stdout -count=1 'import cycle not allowed' + +-- selfimport/selfimport.go -- +package selfimport + +import "selfimport" diff --git a/src/cmd/go/testdata/script/build_internal.txt b/src/cmd/go/testdata/script/build_internal.txt new file mode 100644 index 0000000..0a37d65 --- /dev/null +++ b/src/cmd/go/testdata/script/build_internal.txt @@ -0,0 +1,65 @@ +# Test internal package errors are handled +cd testinternal3 +go list . +stdout 'testinternal3' + +# Test internal cache +cd ../testinternal4 +! go build testinternal4/p +stderr 'internal' + +# Test internal packages outside GOROOT are respected +cd ../testinternal2 +env GO111MODULE=off +! go build -v . +stderr 'p\.go:3:8: use of internal package .*internal/w not allowed' +env GO111MODULE='' + +[compiler:gccgo] skip # gccgo does not have GOROOT +cd ../testinternal +! go build -v . +stderr 'p\.go:3:8: use of internal package net/http/internal not allowed' + +-- testinternal/go.mod -- +module testinternal + +go 1.16 +-- testinternal/p.go -- +package p + +import _ "net/http/internal" +-- testinternal2/go.mod -- +module testinternal2 + +go 1.16 +-- testinternal2/p.go -- +package p + +import _ "./x/y/z/internal/w" +-- testinternal2/x/y/z/internal/w/w.go -- +package w +-- testinternal3/go.mod -- +module testinternal3 + +go 1.16 +-- testinternal3/t.go -- +package t + +import _ "internal/does-not-exist" +-- testinternal4/go.mod -- +module testinternal4 + +go 1.16 +-- testinternal4/p/p.go -- +package p + +import ( + _ "testinternal4/q/internal/x" + _ "testinternal4/q/j" +) +-- testinternal4/q/internal/x/x.go -- +package x +-- testinternal4/q/j/j.go -- +package j + +import _ "testinternal4/q/internal/x" diff --git a/src/cmd/go/testdata/script/build_issue48319.txt b/src/cmd/go/testdata/script/build_issue48319.txt new file mode 100644 index 0000000..4543303 --- /dev/null +++ b/src/cmd/go/testdata/script/build_issue48319.txt @@ -0,0 +1,46 @@ +# Regression test for https://go.dev/issue/48319: +# cgo builds should not include debug information from a stale GOROOT_FINAL. + +[short] skip +[!cgo] skip + +# This test is sensitive to cache invalidation, +# so use a separate build cache that we can control. +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +# Build a binary using a specific value of GOROOT_FINAL. +env GOROOT_FINAL=$WORK${/}goroot1 +go build -o main.exe +mv main.exe main1.exe + +# Now clean the cache and build using a different GOROOT_FINAL. +# The resulting binaries should differ in their debug metadata. +go clean -cache +env GOROOT_FINAL=$WORK${/}goroot2 +go build -o main.exe +mv main.exe main2.exe +! cmp -q main2.exe main1.exe + +# Set GOROOT_FINAL back to the first value. +# If the build is properly reproducible, the two binaries should match. +env GOROOT_FINAL=$WORK${/}goroot1 +go build -o main.exe +cmp -q main.exe main1.exe + +-- go.mod -- +module main + +go 1.18 +-- main.go -- +package main + +import "C" + +import "runtime" + +var _ C.int + +func main() { + println(runtime.GOROOT()) +} diff --git a/src/cmd/go/testdata/script/build_issue59571.txt b/src/cmd/go/testdata/script/build_issue59571.txt new file mode 100644 index 0000000..2cf3259 --- /dev/null +++ b/src/cmd/go/testdata/script/build_issue59571.txt @@ -0,0 +1,40 @@ +# Regression test for https://go.dev/issue/59571 +# Build should be reproducible, even with aliased generic types. + +go build -a -o 1.a +go build -a -o 2.a +cmp -q 1.a 2.a + +-- go.mod -- +module m + +go 1.20 +-- m.go -- +package m + +type ( + SliceFlag[T any] struct{} + + Alias1 = SliceFlag[[1]int] + Alias2 = SliceFlag[[2]int] + Alias3 = SliceFlag[[3]int] + Alias4 = SliceFlag[[4]int] + Alias5 = SliceFlag[[5]int] + Alias6 = SliceFlag[[6]int] + Alias7 = SliceFlag[[7]int] + Alias8 = SliceFlag[[8]int] + Alias9 = SliceFlag[[9]int] + Alias10 = SliceFlag[[10]int] + Alias11 = SliceFlag[[11]int] + Alias12 = SliceFlag[[12]int] + Alias13 = SliceFlag[[13]int] + Alias14 = SliceFlag[[14]int] + Alias15 = SliceFlag[[15]int] + Alias16 = SliceFlag[[16]int] + Alias17 = SliceFlag[[17]int] + Alias18 = SliceFlag[[18]int] + Alias19 = SliceFlag[[19]int] + Alias20 = SliceFlag[[20]int] +) + +func (x *SliceFlag[T]) String() string { return "zzz" } diff --git a/src/cmd/go/testdata/script/build_issue62156.txt b/src/cmd/go/testdata/script/build_issue62156.txt new file mode 100644 index 0000000..d241570 --- /dev/null +++ b/src/cmd/go/testdata/script/build_issue62156.txt @@ -0,0 +1,27 @@ +# Regression test for https://go.dev/issue/62156: +# DWARF generation for inlined functions may require more runtime type +# descriptors to be written. + +go build + +-- go.mod -- +module m + +go 1.20 +-- main.go -- +package main + +import "m/sub" + +func main() { sub.F() } +-- sub/sub.go -- +package sub + +type iface interface{ m() } + +func F() { + f := func(rt []iface) []iface { + return append([]iface{}, rt...) + } + f(nil) +} diff --git a/src/cmd/go/testdata/script/build_issue6480.txt b/src/cmd/go/testdata/script/build_issue6480.txt new file mode 100644 index 0000000..991112f --- /dev/null +++ b/src/cmd/go/testdata/script/build_issue6480.txt @@ -0,0 +1,128 @@ +# "go test -c -test.bench=XXX errors" should not hang. +# "go test -c" should also produce reproducible binaries. +# "go test -c" should also appear to write a new binary every time, +# even if it's really just updating the mtime on an existing up-to-date binary. + +[compiler:gccgo] skip +[short] skip + +# Install some commands to compare mtimes +env GOBIN=$WORK/tmp/bin +go install m/now m/mtime m/before + +# Initial builds +go test -c -test.bench=XXX errors +go test -c -o errors2.test errors +cmp errors.test$GOEXE errors2.test # // errors2.test has no exeSuffix because -o above doesn't have it + +# Check errors.test mtime is updated +exec $GOBIN/now +cp stdout start_time.txt +go test -x -c -test.bench=XXX errors +! stderr '[\\/]link|gccgo' # make sure up-to-date test binary is not relinked +exec $GOBIN/mtime errors.test$GOEXE +cp stdout errors1_mod_time.txt +exec $GOBIN/before start_time.txt errors1_mod_time.txt +rm start_time.txt errors1_mod_time.txt + +# Check errors2.test mtime is updated +exec $GOBIN/now +cp stdout start_time.txt +go test -x -c -o errors2.test errors +! stderr '[\\/]link|gccgo' # make sure up-to-date test binary is not relinked +exec $GOBIN/mtime errors2.test +cp stdout errors2_mod_time.txt +exec $GOBIN/before start_time.txt errors2_mod_time.txt + +-- go.mod -- +module m + +go 1.16 +-- now/now.go -- +// Writes time.Now() to a file +package main + +import ( + "encoding/json" + "fmt" + "os" + "time" +) + +func main() { + if err := json.NewEncoder(os.Stdout).Encode(time.Now()); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} +-- mtime/mtime.go -- +package main + +import ( + "encoding/json" + "fmt" + "os" +) + +func main() { + info, err := os.Stat(os.Args[1]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if err := json.NewEncoder(os.Stdout).Encode(info.ModTime()); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} +-- before/before.go -- +package main + +import ( + "encoding/json" + "fmt" + "os" + "time" +) + +func truncateLike(t, p time.Time) time.Time { + nano := p.UnixNano() + d := 1 * time.Nanosecond + for nano%int64(d) == 0 && d < 1*time.Second { + d *= 10 + } + for nano%int64(d) == 0 && d < 2*time.Second { + d *= 2 + } + return t.Truncate(d) +} + +func main() { + var t1 time.Time + b1, err := os.ReadFile(os.Args[1]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if err := json.Unmarshal(b1, &t1); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + var t2 time.Time + b2, err := os.ReadFile(os.Args[2]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if err := json.Unmarshal(b2, &t2); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + t1 = truncateLike(t1, t2) + if !t1.Before(t2) { + fmt.Fprintf(os.Stderr, "time in %v (%v) is not before time in %v (%v)", os.Args[1], t1, os.Args[2], t2) + os.Exit(1) + } +} diff --git a/src/cmd/go/testdata/script/build_issue_65528.txt b/src/cmd/go/testdata/script/build_issue_65528.txt new file mode 100644 index 0000000..ab4d62b --- /dev/null +++ b/src/cmd/go/testdata/script/build_issue_65528.txt @@ -0,0 +1,9 @@ +go build + +-- go.mod -- +module test + +go 1.0 + +-- p.go -- +package p diff --git a/src/cmd/go/testdata/script/build_link_x_import_path_escape.txt b/src/cmd/go/testdata/script/build_link_x_import_path_escape.txt new file mode 100644 index 0000000..d47c482 --- /dev/null +++ b/src/cmd/go/testdata/script/build_link_x_import_path_escape.txt @@ -0,0 +1,22 @@ +[compiler:gccgo] skip 'gccgo does not support -ldflags -X' + +go build -o linkx$GOEXE -ldflags -X=my.pkg.Text=linkXworked my.pkg/main +exec ./linkx$GOEXE +stderr '^linkXworked$' + +-- go.mod -- +module my.pkg + +go 1.16 +-- main/main.go -- +package main + +import "my.pkg" + +func main() { + println(pkg.Text) +} +-- pkg.go -- +package pkg + +var Text = "unset" diff --git a/src/cmd/go/testdata/script/build_multi_main.txt b/src/cmd/go/testdata/script/build_multi_main.txt new file mode 100644 index 0000000..8afd8b8 --- /dev/null +++ b/src/cmd/go/testdata/script/build_multi_main.txt @@ -0,0 +1,43 @@ +# Verify build -o can output multiple executables to a directory. + +mkdir $WORK/bin +go build -o $WORK/bin ./cmd/c1 ./cmd/c2 +! stderr 'multiple packages' + +! go build -o $WORK/bin ./pkg1 ./pkg1 +stderr 'no main packages' + +! go build ./cmd/c1 +stderr 'already exists and is a directory' + +# Verify build -o output correctly local packages +mkdir $WORK/local +go build -o $WORK/local ./exec.go +exists $WORK/local/exec$GOEXE + +-- go.mod -- +module exmod + +-- cmd/c1/main.go -- +package main + +func main() {} + +-- cmd/c2/main.go -- +package main + +func main() {} + +-- pkg1/pkg1.go -- +package pkg1 + +-- pkg2/pkg2.go -- +package pkg2 + +-- exec.go -- +package main + +func main() {} + +-- c1$GOEXE/keep.txt -- +Create c1 directory. diff --git a/src/cmd/go/testdata/script/build_n_cgo.txt b/src/cmd/go/testdata/script/build_n_cgo.txt new file mode 100644 index 0000000..fa01927 --- /dev/null +++ b/src/cmd/go/testdata/script/build_n_cgo.txt @@ -0,0 +1,18 @@ +[!cgo] skip + +# Test that nothing is prepended to $WORK path prefix. +# See issue golang.org/issue/37012. +go build -n +! stderr '[/\\]\$WORK' +stderr '[ =]\$WORK' + +-- go.mod -- +module m + +go 1.16 +-- main.go -- +package main + +import "C" + +var _ C.int diff --git a/src/cmd/go/testdata/script/build_negative_p.txt b/src/cmd/go/testdata/script/build_negative_p.txt new file mode 100644 index 0000000..9123907 --- /dev/null +++ b/src/cmd/go/testdata/script/build_negative_p.txt @@ -0,0 +1,5 @@ +! go build -p=-1 example.go +stderr 'go: -p must be a positive integer: -1' + +-- example.go -- +package example
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/build_no_go.txt b/src/cmd/go/testdata/script/build_no_go.txt new file mode 100644 index 0000000..b61d752 --- /dev/null +++ b/src/cmd/go/testdata/script/build_no_go.txt @@ -0,0 +1,41 @@ +! go build ./empty/test +stderr 'no non-test Go files in ' + +! go build ./empty/xtest +stderr 'no non-test Go files in ' + +! go build ./empty/testxtest +stderr 'no non-test Go files in ' + +! go build ./exclude +stderr 'build constraints exclude all Go files in ' + +! go build ./exclude/ignore +stderr 'no Go files in ' + +! go build ./exclude/empty +stderr 'no Go files in ' + +-- go.mod -- +module m + +go 1.16 +-- empty/test/test_test.go -- +package p +-- empty/testxtest/test_test.go -- +package p +-- empty/testxtest/xtest_test.go -- +package p_test +-- empty/xtest/xtest_test.go -- +package p_test +-- exclude/empty/x.txt -- +-- exclude/ignore/_x.go -- +package x +-- exclude/x.go -- +// +build linux,!linux + +package x +-- exclude/x_linux.go -- +// +build windows + +package x diff --git a/src/cmd/go/testdata/script/build_nocache.txt b/src/cmd/go/testdata/script/build_nocache.txt new file mode 100644 index 0000000..b21e755 --- /dev/null +++ b/src/cmd/go/testdata/script/build_nocache.txt @@ -0,0 +1,40 @@ +env GO111MODULE=off + +# As of Go 1.12, the module cache is required. + +# If none of the variables we use to locate GOCACHE are set, the cache is off +# and we cannot build. +env GOCACHE= +env XDG_CACHE_HOME= +env HOME= +[GOOS:plan9] env home= +[GOOS:windows] env LocalAppData= +! go build -o triv triv.go +stderr 'build cache is required, but could not be located: GOCACHE is not defined and .*' + +# If GOCACHE is set but is not an absolute path, and we cannot build. +env GOCACHE=test +! go build -o triv triv.go +stderr 'build cache is required, but could not be located: GOCACHE is not an absolute path' + +# An explicit GOCACHE=off also disables builds. +env GOCACHE=off +! go build -o triv triv.go +stderr 'build cache is disabled by GOCACHE=off' + +# If GOCACHE is set to an unwritable directory, we should diagnose it as such. +[GOOS:windows] stop # Does not support unwritable directories. +[root] skip # Can write to unwritable directories. + +mkdir $WORK/unwritable/home +chmod 0555 $WORK/unwritable/home +[!GOOS:plan9] env HOME=$WORK/unwritable/home +[GOOS:plan9] env home=$WORK/unwritable/home + +env GOCACHE=$WORK/unwritable/home +! go build -o triv triv.go +stderr 'failed to initialize build cache.* permission denied' + +-- triv.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/build_output.txt b/src/cmd/go/testdata/script/build_output.txt new file mode 100644 index 0000000..457960f --- /dev/null +++ b/src/cmd/go/testdata/script/build_output.txt @@ -0,0 +1,117 @@ +[compiler:gccgo] skip 'gccgo has no standard packages' +[short] skip + +[!GOOS:windows] env NONEXE='.exe' +[GOOS:windows] env NONEXE='' + +env GOBIN=$WORK/tmp/bin +go install m/isarchive & + +go build x.go +exists -exec x$GOEXE +rm x$GOEXE +! exists x$NONEXE + +go build -o myprog x.go +! exists x +! exists x.exe +exists -exec myprog +! exists myprogr.exe + +! exists bin +go build -o bin/x x.go +exists -exec bin/x +rm bin + +! exists bin +go build -o bin/ x.go +exists -exec bin/x$GOEXE +rm bin + +[GOOS:windows] ! exists bin +[GOOS:windows] go build -o bin\x x.go +[GOOS:windows] exists -exec bin\x +[GOOS:windows] rm bin + +[GOOS:windows] ! exists bin +[GOOS:windows] go build -o bin\ x.go +[GOOS:windows] exists -exec bin\x.exe +[GOOS:windows] rm bin + +! exists bin +mkdir bin +go build -o bin x.go +exists -exec bin/x$GOEXE +rm bin + +go build p.go +! exists p +! exists p.a +! exists p.o +! exists p.exe + +wait # for isarchive + +go build -o p.a p.go +exists p.a +exec $GOBIN/isarchive p.a + +go build cmd/gofmt +exists -exec gofmt$GOEXE +rm gofmt$GOEXE +! exists gofmt$NONEXE + +go build -o mygofmt cmd/gofmt +exists -exec mygofmt +! exists mygofmt.exe +! exists gofmt +! exists gofmt.exe + +go build sync/atomic +! exists atomic +! exists atomic.exe + +go build -o myatomic.a sync/atomic +exists myatomic.a +exec $GOBIN/isarchive myatomic.a +! exists atomic +! exists atomic.a +! exists atomic.exe + +! go build -o whatever cmd/gofmt sync/atomic +stderr 'multiple packages' + +-- go.mod -- +module m + +go 1.16 +-- x.go -- +package main + +func main() {} +-- p.go -- +package p +-- isarchive/isarchive.go -- +package main + +import ( + "bytes" + "fmt" + "io" + "os" +) + +func main() { + f, err := os.Open(os.Args[1]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + buf := make([]byte, 100) + io.ReadFull(f, buf) + f.Close() + if !bytes.HasPrefix(buf, []byte("!<arch>\n")) { + fmt.Fprintf(os.Stderr, "file %s exists but is not an archive\n", os.Args[1]) + os.Exit(1) + } +} diff --git a/src/cmd/go/testdata/script/build_overlay.txt b/src/cmd/go/testdata/script/build_overlay.txt new file mode 100644 index 0000000..b64bc02 --- /dev/null +++ b/src/cmd/go/testdata/script/build_overlay.txt @@ -0,0 +1,313 @@ +[short] skip + +# Test building in overlays. +# TODO(#39958): add a test case where the destination file in the replace map +# isn't a go file. Either completely exclude that case in fs.IsDirWithGoFiles +# if the compiler doesn't allow it, or test that it works all the way. +# TODO(#39958): add a test that both gc and gccgo assembly files can include .h +# files. + +# The main package (m) is contained in an overlay. It imports m/dir2 which has one +# file in an overlay and one file outside the overlay, which in turn imports m/dir, +# which only has source files in the overlay. + +cd m + +! go build . +go build -overlay overlay.json -o main$GOEXE . +exec ./main$goexe +stdout '^hello$' + +go build -overlay overlay.json -o print_abspath$GOEXE ./printpath +exec ./print_abspath$GOEXE +stdout $WORK[/\\]gopath[/\\]src[/\\]m[/\\]printpath[/\\]main.go + +go build -overlay overlay.json -o print_trimpath$GOEXE -trimpath ./printpath +exec ./print_trimpath$GOEXE +stdout ^m[/\\]printpath[/\\]main.go + +go build -overlay overlay.json -o print_trimpath_two_files$GOEXE printpath/main.go printpath/other.go +exec ./print_trimpath_two_files$GOEXE +stdout $WORK[/\\]gopath[/\\]src[/\\]m[/\\]printpath[/\\]main.go +stdout $WORK[/\\]gopath[/\\]src[/\\]m[/\\]printpath[/\\]other.go + +[cgo] go build -overlay overlay.json -o main_cgo_replace$GOEXE ./cgo_hello_replace +[cgo] exec ./main_cgo_replace$GOEXE +[cgo] stdout '^hello cgo\r?\n' + +[cgo] go build -overlay overlay.json -o main_cgo_quote$GOEXE ./cgo_hello_quote +[cgo] exec ./main_cgo_quote$GOEXE +[cgo] stdout '^hello cgo\r?\n' + +[cgo] go build -overlay overlay.json -o main_cgo_angle$GOEXE ./cgo_hello_angle +[cgo] exec ./main_cgo_angle$GOEXE +[cgo] stdout '^hello cgo\r?\n' + +go build -overlay overlay.json -o main_call_asm$GOEXE ./call_asm +exec ./main_call_asm$GOEXE +! stdout . + +[cgo] go list -compiled -overlay overlay.json -f '{{range .CompiledGoFiles}}{{. | printf "%s\n"}}{{end}}' ./cgo_hello_replace +[cgo] cp stdout compiled_cgo_sources.txt +[cgo] go run ../print_line_comments.go compiled_cgo_sources.txt +[cgo] stdout $GOPATH[/\\]src[/\\]m[/\\]cgo_hello_replace[/\\]cgo_hello_replace.go +[cgo] ! stdout $GOPATH[/\\]src[/\\]m[/\\]overlay[/\\]hello.c + +# Change the contents of a file in the overlay and ensure that makes the target stale +env OLD_GOCACHE=$GOCACHE +env GOCACHE=$WORK/cache # use a fresh cache so that multiple runs of the test don't interfere +go build -x -overlay overlay.json ./test_cache +stderr '(compile|gccgo)( |\.exe).*test_cache.go' +go build -x -overlay overlay.json ./test_cache +! stderr '(compile|gccgo)( |\.exe).*test_cache.go' # cached +cp overlay/test_cache_different.go overlay/test_cache.go +go build -x -overlay overlay.json ./test_cache +stderr '(compile|gccgo)( |\.exe).*test_cache.go' # not cached +env CACHE=$OLD_GOCACHE + +# Run same tests but with gccgo. +env GO111MODULE=off +[!exec:gccgo] stop +[cross] stop # gccgo can't necessarily cross-compile + +! go build -compiler=gccgo . +go build -compiler=gccgo -overlay overlay.json -o main_gccgo$GOEXE . +exec ./main_gccgo$goexe +stdout '^hello$' + +go build -compiler=gccgo -overlay overlay.json -o print_abspath_gccgo$GOEXE ./printpath +exec ./print_abspath_gccgo$GOEXE +stdout $WORK[/\\]gopath[/\\]src[/\\]m[/\\]printpath[/\\]main.go + +go build -compiler=gccgo -overlay overlay.json -o print_trimpath_gccgo$GOEXE -trimpath ./printpath +exec ./print_trimpath_gccgo$GOEXE +stdout ^\.[/\\]printpath[/\\]main.go + + +go build -compiler=gccgo -overlay overlay.json -o main_cgo_replace_gccgo$GOEXE ./cgo_hello_replace +exec ./main_cgo_replace_gccgo$GOEXE +stdout '^hello cgo\r?\n' + +go build -compiler=gccgo -overlay overlay.json -o main_cgo_quote_gccgo$GOEXE ./cgo_hello_quote +exec ./main_cgo_quote_gccgo$GOEXE +stdout '^hello cgo\r?\n' + +go build -compiler=gccgo -overlay overlay.json -o main_cgo_angle_gccgo$GOEXE ./cgo_hello_angle +exec ./main_cgo_angle_gccgo$GOEXE +stdout '^hello cgo\r?\n' + +go build -compiler=gccgo -overlay overlay.json -o main_call_asm_gccgo$GOEXE ./call_asm +exec ./main_call_asm_gccgo$GOEXE +! stdout . + + +-- m/go.mod -- +// TODO(matloob): how do overlays work with go.mod (especially if mod=readonly) +module m + +go 1.16 + +-- m/dir2/h.go -- +package dir2 + +func PrintMessage() { + printMessage() +} +-- m/dir/foo.txt -- +The build action code currently expects the package directory +to exist, so it can run the compiler in that directory. +TODO(matloob): Remove this requirement. +-- m/printpath/about.txt -- +the actual code is in the overlay +-- m/overlay.json -- +{ + "Replace": { + "f.go": "overlay/f.go", + "dir/g.go": "overlay/dir_g.go", + "dir2/i.go": "overlay/dir2_i.go", + "printpath/main.go": "overlay/printpath.go", + "printpath/other.go": "overlay2/printpath2.go", + "call_asm/asm_gc.s": "overlay/asm_gc.s", + "call_asm/asm_gccgo.s": "overlay/asm_gccgo.s", + "test_cache/main.go": "overlay/test_cache.go", + "cgo_hello_replace/cgo_header.h": "overlay/cgo_head.h", + "cgo_hello_replace/hello.c": "overlay/hello.c", + "cgo_hello_quote/cgo_hello.go": "overlay/cgo_hello_quote.go", + "cgo_hello_quote/cgo_header.h": "overlay/cgo_head.h", + "cgo_hello_angle/cgo_hello.go": "overlay/cgo_hello_angle.go", + "cgo_hello_angle/cgo_header.h": "overlay/cgo_head.h" + } +} +-- m/cgo_hello_replace/cgo_hello_replace.go -- +package main + +// #include "cgo_header.h" +import "C" + +func main() { + C.say_hello() +} +-- m/cgo_hello_replace/cgo_header.h -- + // Test that this header is replaced with one that has the proper declaration. +void say_goodbye(); + +-- m/cgo_hello_replace/hello.c -- +#include <stdio.h> + +void say_goodbye() { puts("goodbye cgo\n"); fflush(stdout); } + +-- m/overlay/f.go -- +package main + +import "m/dir2" + +func main() { + dir2.PrintMessage() +} +-- m/call_asm/main.go -- +package main + +func foo() // There will be a "missing function body" error if the assembly file isn't found. + +func main() { + foo() +} +-- m/overlay/dir_g.go -- +package dir + +import "fmt" + +func PrintMessage() { + fmt.Println("hello") +} +-- m/overlay/printpath.go -- +package main + +import ( + "fmt" + "path/filepath" + "runtime" +) + +func main() { + _, file, _, _ := runtime.Caller(0) + + // Since https://golang.org/cl/214286, the runtime's debug paths are + // slash-separated regardless of platform, so normalize them to system file + // paths. + fmt.Println(filepath.FromSlash(file)) +} +-- m/overlay2/printpath2.go -- +package main + +import ( + "fmt" + "path/filepath" + "runtime" +) + +func init() { + _, file, _, _ := runtime.Caller(0) + fmt.Println(filepath.FromSlash(file)) +} +-- m/overlay/dir2_i.go -- +package dir2 + +import "m/dir" + +func printMessage() { + dir.PrintMessage() +} +-- m/overlay/cgo_hello_quote.go -- +package main + +// #include "cgo_header.h" +import "C" + +func main() { + C.say_hello() +} +-- m/overlay/cgo_hello_angle.go -- +package main + +// #include <cgo_header.h> +import "C" + +func main() { + C.say_hello() +} +-- m/overlay/cgo_head.h -- +void say_hello(); +-- m/overlay/hello.c -- +#include <stdio.h> + +void say_hello() { puts("hello cgo\n"); fflush(stdout); } +-- m/overlay/asm_gc.s -- +// +build gc + +TEXT ·foo(SB),0,$0 + RET + +-- m/overlay/asm_gccgo.s -- +// +build gccgo + +.globl main.foo +.text +main.foo: + ret + +-- m/overlay/test_cache.go -- +package foo + +import "fmt" + +func bar() { + fmt.Println("something") +} +-- m/overlay/test_cache_different.go -- +package foo + +import "fmt" + +func bar() { + fmt.Println("different") +} +-- m/cgo_hello_quote/hello.c -- +#include <stdio.h> + +void say_hello() { puts("hello cgo\n"); fflush(stdout); } +-- m/cgo_hello_angle/hello.c -- +#include <stdio.h> + +void say_hello() { puts("hello cgo\n"); fflush(stdout); } + +-- print_line_comments.go -- +package main + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "strings" +) + +func main() { + compiledGoFilesArg := os.Args[1] + b, err := ioutil.ReadFile(compiledGoFilesArg) + if err != nil { + log.Fatal(err) + } + compiledGoFiles := strings.Split(strings.TrimSpace(string(b)), "\n") + for _, f := range compiledGoFiles { + b, err := ioutil.ReadFile(f) + if err != nil { + log.Fatal(err) + } + for _, line := range strings.Split(string(b), "\n") { + if strings.HasPrefix(line, "#line") || strings.HasPrefix(line, "//line") { + fmt.Println(line) + } + } + } +} diff --git a/src/cmd/go/testdata/script/build_patterns_outside_gopath.txt b/src/cmd/go/testdata/script/build_patterns_outside_gopath.txt new file mode 100644 index 0000000..6a600cf --- /dev/null +++ b/src/cmd/go/testdata/script/build_patterns_outside_gopath.txt @@ -0,0 +1,36 @@ +# Tests issue #18778 +[short] skip + +cd pkgs + +env GO111MODULE=off +go build ./... +! stdout . +go test ./... +stdout '^ok' +go list ./... +stdout 'pkgs$' +stdout 'pkgs/a' + +-- pkgs/go.mod -- +module pkgs + +go 1.16 +-- pkgs/a.go -- +package x +-- pkgs/a_test.go -- +package x_test + +import "testing" + +func TestX(t *testing.T) { +} +-- pkgs/a/a.go -- +package a +-- pkgs/a/a_test.go -- +package a_test + +import "testing" + +func TestA(t *testing.T) { +} diff --git a/src/cmd/go/testdata/script/build_pgo.txt b/src/cmd/go/testdata/script/build_pgo.txt new file mode 100644 index 0000000..3b0804b --- /dev/null +++ b/src/cmd/go/testdata/script/build_pgo.txt @@ -0,0 +1,74 @@ +# Test go build -pgo flag. +# Specifically, the build cache handles profile content correctly. + +[short] skip 'compiles and links executables' + +# build without PGO +go build triv.go + +# build with PGO, should trigger rebuild +# starting with an empty profile (the compiler accepts it) +go build -x -pgo=prof -o triv.exe triv.go +stderr 'compile.*-pgoprofile=.*prof.*triv.go' + +# check that PGO appears in build info +# N.B. we can't start the stdout check with -pgo because the script assumes that +# if the first arg starts with - it is a grep flag. +go version -m triv.exe +stdout 'build\s+-pgo=.*'${/}'prof' + +# store the build ID +go list -export -json=BuildID -pgo=prof triv.go +stdout '"BuildID":' # check that output actually contains a build ID +cp stdout list.out + +# build again with the same profile, should be cached +go build -x -pgo=prof -o triv.exe triv.go +! stderr 'compile.*triv.go' + +# check that the build ID is the same +go list -export -json=BuildID -pgo=prof triv.go +cmp stdout list.out + +# overwrite the prof +go run overwrite.go + +# build again, profile content changed, should trigger rebuild +go build -n -pgo=prof triv.go +stderr 'compile.*-pgoprofile=.*prof.*p.go' + +# check that the build ID is different +go list -export -json=BuildID -pgo=prof triv.go +! cmp stdout list.out + +# build with trimpath, buildinfo path should be trimmed +go build -x -pgo=prof -trimpath -o triv.exe triv.go + +# check that path is trimmed +go version -m triv.exe +stdout 'build\s+-pgo=prof' + +-- prof -- +-- triv.go -- +package main +func main() {} +-- overwrite.go -- +package main + +import ( + "os" + "runtime/pprof" +) + +func main() { + f, err := os.Create("prof") + if err != nil { + panic(err) + } + err = pprof.StartCPUProfile(f) + if err != nil { + panic(err) + } + pprof.StopCPUProfile() + f.Close() +} diff --git a/src/cmd/go/testdata/script/build_pgo_auto.txt b/src/cmd/go/testdata/script/build_pgo_auto.txt new file mode 100644 index 0000000..509be0d --- /dev/null +++ b/src/cmd/go/testdata/script/build_pgo_auto.txt @@ -0,0 +1,97 @@ +# Test go build -pgo=auto flag. + +[short] skip 'compiles and links executables' + +# use default.pgo for a single main package +go build -n -pgo=auto -o a1.exe ./a/a1 +stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go' + +# check that pgo applied to dependencies +stderr 'compile.*-p test/dep.*-pgoprofile=.*default\.pgo' + +# check that pgo appears in build info +# N.B. we can't start the stdout check with -pgo because the script assumes that +# if the first arg starts with - it is a grep flag. +stderr 'build\\t-pgo=.*default\.pgo' + +# check also that -pgo appears with the other flags, before non-flag settings +! stderr 'build\\t[A-Za-z].*build\\t-pgo' + +# use default.pgo for ... with a single main package +go build -n -pgo=auto ./a/... +stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go' + +# check that pgo appears in build info +stderr 'build\\t-pgo=.*default\.pgo' + +# build succeeds without PGO when default.pgo file is absent +go build -n -pgo=auto -o nopgo.exe ./nopgo +stderr 'compile.*nopgo.go' +! stderr 'compile.*-pgoprofile' + +# check that pgo doesn't appear in build info +! stderr 'build\\t-pgo=' + +# other build-related commands +go install -a -n -pgo=auto ./a/a1 +stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go' + +go run -a -n -pgo=auto ./a/a1 +stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go' + +go test -a -n -pgo=auto ./a/a1 +stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go.*a1_test.go' +stderr 'compile.*-pgoprofile=.*default\.pgo.*external_test.go' + +# go list commands should succeed as usual +go list -pgo=auto ./a/a1 + +go list -test -pgo=auto ./a/a1 + +go list -deps -pgo=auto ./a/a1 + +# -pgo=auto is the default. Commands without explicit -pgo=auto +# should work as -pgo=auto. +go build -a -n -o a1.exe ./a/a1 +stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go' +stderr 'compile.*-p test/dep.*-pgoprofile=.*default\.pgo' + +# check that pgo appears in build info +stderr 'build\\t-pgo=.*default\.pgo' + +go build -a -n -o nopgo.exe ./nopgo +stderr 'compile.*nopgo.go' +! stderr 'compile.*-pgoprofile' + +# check that pgo doesn't appear in build info +! stderr 'build\\t-pgo=' + +# -pgo=off should turn off PGO. +go build -a -n -pgo=off -o a1.exe ./a/a1 +stderr 'compile.*a1.go' +! stderr 'compile.*-pgoprofile' + +# check that pgo doesn't appear in build info +! stderr 'build\\t-pgo=' + +-- go.mod -- +module test +go 1.20 +-- a/a1/a1.go -- +package main +import _ "test/dep" +func main() {} +-- a/a1/a1_test.go -- +package main +import "testing" +func TestA(*testing.T) {} +-- a/a1/external_test.go -- +package main_test +import "testing" +func TestExternal(*testing.T) {} +-- a/a1/default.pgo -- +-- nopgo/nopgo.go -- +package main +func main() {} +-- dep/dep.go -- +package dep diff --git a/src/cmd/go/testdata/script/build_pgo_auto_multi.txt b/src/cmd/go/testdata/script/build_pgo_auto_multi.txt new file mode 100644 index 0000000..991b72c --- /dev/null +++ b/src/cmd/go/testdata/script/build_pgo_auto_multi.txt @@ -0,0 +1,109 @@ +# Test go build -pgo=auto flag with multiple main packages. + +go install -a -n -pgo=auto ./a ./b ./nopgo + +# a/default.pgo applies to package a and (transitive) +# dependencies. +stderr 'compile.*-pgoprofile=.*a(/|\\\\)default\.pgo.*a(/|\\\\)a\.go' +stderr 'compile.*-pgoprofile=.*a(/|\\\\)default\.pgo.*dep(/|\\\\)dep\.go' +stderr 'compile.*-pgoprofile=.*a(/|\\\\)default\.pgo.*dep2(/|\\\\)dep2\.go' +stderr -count=1 'compile.*-pgoprofile=.*a(/|\\\\)default\.pgo.*dep3(/|\\\\)dep3\.go' + +# b/default.pgo applies to package b and (transitive) +# dependencies. +stderr 'compile.*-pgoprofile=.*b(/|\\\\)default\.pgo.*b(/|\\\\)b\.go' +stderr 'compile.*-pgoprofile=.*b(/|\\\\)default\.pgo.*dep(/|\\\\)dep\.go' +stderr 'compile.*-pgoprofile=.*b(/|\\\\)default\.pgo.*dep2(/|\\\\)dep2\.go' +stderr -count=1 'compile.*-pgoprofile=.*b(/|\\\\)default\.pgo.*dep3(/|\\\\)dep3\.go' + +# nopgo should be built without PGO. +! stderr 'compile.*-pgoprofile=.*nopgo(/|\\\\)nopgo\.go' + +# Dependencies should also be built without PGO. +# Here we want to match a compile action without -pgoprofile, +# by matching 3 occurrences of "compile dep.go", among which +# 2 of them have -pgoprofile (therefore one without). +stderr -count=3 'compile.*dep(/|\\\\)dep.go' +stderr -count=2 'compile.*-pgoprofile=.*dep(/|\\\\)dep\.go' + +stderr -count=3 'compile.*dep2(/|\\\\)dep2.go' +stderr -count=2 'compile.*-pgoprofile=.*dep2(/|\\\\)dep2\.go' + +stderr -count=3 'compile.*dep3(/|\\\\)dep3.go' +stderr -count=2 'compile.*-pgoprofile=.*dep3(/|\\\\)dep3\.go' + +# check that pgo appears or not in build info as expected +stderr 'path\\ttest/a\\n.*build\\t-pgo=.*a(/|\\\\)default\.pgo' +stderr 'path\\ttest/b\\n.*build\\t-pgo=.*b(/|\\\\)default\.pgo' +! stderr 'path\\ttest/nopgo\\n.*build\\t-pgo=' + +# go test works the same way +go test -a -n -pgo=auto ./a ./b ./nopgo +stderr 'compile.*-pgoprofile=.*a(/|\\\\)default\.pgo.*a(/|\\\\)a_test\.go' +stderr 'compile.*-pgoprofile=.*a(/|\\\\)default\.pgo.*dep(/|\\\\)dep\.go' +stderr 'compile.*-pgoprofile=.*b(/|\\\\)default\.pgo.*b(/|\\\\)b_test\.go' +stderr 'compile.*-pgoprofile=.*b(/|\\\\)default\.pgo.*dep(/|\\\\)dep\.go' +! stderr 'compile.*-pgoprofile=.*nopgo(/|\\\\)nopgo_test\.go' + +# test-only dependencies also have profiles attached +stderr 'compile.*-pgoprofile=.*a(/|\\\\)default\.pgo.*testdep(/|\\\\)testdep\.go' +stderr 'compile.*-pgoprofile=.*b(/|\\\\)default\.pgo.*testdep(/|\\\\)testdep\.go' +stderr 'compile.*-pgoprofile=.*a(/|\\\\)default\.pgo.*testdep2(/|\\\\)testdep2\.go' +stderr 'compile.*-pgoprofile=.*b(/|\\\\)default\.pgo.*testdep2(/|\\\\)testdep2\.go' + +# go list -deps prints packages built multiple times. +go list -pgo=auto -deps ./a ./b ./nopgo +stdout 'test/dep \[test/a\]' +stdout 'test/dep \[test/b\]' +stdout 'test/dep$' + +# Here we have 3 main packages, a, b, and nopgo, where a and b each has +# its own default.pgo profile, and nopgo has none. +# All 3 main packages import dep and dep2, both of which then import dep3 +# (a diamond-shape import graph). +-- go.mod -- +module test +go 1.20 +-- a/a.go -- +package main +import _ "test/dep" +import _ "test/dep2" +func main() {} +-- a/a_test.go -- +package main +import "testing" +import _ "test/testdep" +func TestA(*testing.T) {} +-- a/default.pgo -- +-- b/b.go -- +package main +import _ "test/dep" +import _ "test/dep2" +func main() {} +-- b/b_test.go -- +package main +import "testing" +import _ "test/testdep" +func TestB(*testing.T) {} +-- b/default.pgo -- +-- nopgo/nopgo.go -- +package main +import _ "test/dep" +import _ "test/dep2" +func main() {} +-- nopgo/nopgo_test.go -- +package main +import "testing" +func TestNopgo(*testing.T) {} +-- dep/dep.go -- +package dep +import _ "test/dep3" +-- dep2/dep2.go -- +package dep2 +-- dep3/dep3.go -- +package dep3 +-- testdep/testdep.go -- +package testdep +import _ "test/testdep2" +-- testdep2/testdep2.go -- +package testdep2 diff --git a/src/cmd/go/testdata/script/build_pie_race.txt b/src/cmd/go/testdata/script/build_pie_race.txt new file mode 100644 index 0000000..39bea05 --- /dev/null +++ b/src/cmd/go/testdata/script/build_pie_race.txt @@ -0,0 +1,30 @@ +# go build -buildmode=pie -race main.go on Darwin should work without errors + +[!race] skip 'test requires race detector support' + +[!GOOS:darwin] ! go build -buildmode=pie -race +[!GOOS:darwin] stderr '^-buildmode=pie not supported when -race is enabled on '$GOOS'/'$GOARCH'$' +[!GOOS:darwin] stop 'not testing -buildmode=pie -race on platform that does not support it' + +go build -buildmode=pie -race bytes +! stderr . + +[short] stop 'not linking a binary in -short mode' + +go build -buildmode=pie -race main.go +! stderr . +exec ./main +stdout 'Hello, 世界' + +-- go.mod -- +module m + +go 1.21 +-- main.go -- +package main + +import "fmt" + +func main() { + fmt.Println("Hello, 世界") +} diff --git a/src/cmd/go/testdata/script/build_plugin_non_main.txt b/src/cmd/go/testdata/script/build_plugin_non_main.txt new file mode 100644 index 0000000..e0bbbef --- /dev/null +++ b/src/cmd/go/testdata/script/build_plugin_non_main.txt @@ -0,0 +1,13 @@ +# Plugins are not supported on all platforms. +[!buildmode:plugin] skip + +go build -n testdep +! go build -buildmode=plugin testdep +stderr '-buildmode=plugin requires exactly one main package' + +-- go.mod -- +module testdep + +go 1.16 +-- testdep.go -- +package p diff --git a/src/cmd/go/testdata/script/build_plugin_reproducible.txt b/src/cmd/go/testdata/script/build_plugin_reproducible.txt new file mode 100644 index 0000000..5369954 --- /dev/null +++ b/src/cmd/go/testdata/script/build_plugin_reproducible.txt @@ -0,0 +1,11 @@ +[!buildmode:plugin] skip +[short] skip + +go build -trimpath -buildvcs=false -buildmode=plugin -o a.so main.go +go build -trimpath -buildvcs=false -buildmode=plugin -o b.so main.go +cmp -q a.so b.so + +-- main.go -- +package main + +func main() {}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/build_relative_pkgdir.txt b/src/cmd/go/testdata/script/build_relative_pkgdir.txt new file mode 100644 index 0000000..57f18ee --- /dev/null +++ b/src/cmd/go/testdata/script/build_relative_pkgdir.txt @@ -0,0 +1,9 @@ +env GO111MODULE=off + +# Regression test for golang.org/issue/21309: accept relative -pkgdir argument. + +[short] skip + +mkdir $WORK/gocache +env GOCACHE=$WORK/gocache +go build -pkgdir=. runtime diff --git a/src/cmd/go/testdata/script/build_relative_tmpdir.txt b/src/cmd/go/testdata/script/build_relative_tmpdir.txt new file mode 100644 index 0000000..ea7412e --- /dev/null +++ b/src/cmd/go/testdata/script/build_relative_tmpdir.txt @@ -0,0 +1,18 @@ +env GO111MODULE=off + +# If GOTMPDIR is relative, 'go build' should derive an absolute $WORK directory. +cd $WORK +mkdir tmp +env GOTMPDIR=tmp +go build -work a +stderr 'WORK='$WORK + +# Similarly if TMP/TMPDIR is relative. +env GOTMPDIR= +env TMP=tmp # Windows +env TMPDIR=tmp # Unix +go build -work a +stderr 'WORK='$WORK + +-- a/a.go -- +package a diff --git a/src/cmd/go/testdata/script/build_runtime_gcflags.txt b/src/cmd/go/testdata/script/build_runtime_gcflags.txt new file mode 100644 index 0000000..c87e480 --- /dev/null +++ b/src/cmd/go/testdata/script/build_runtime_gcflags.txt @@ -0,0 +1,11 @@ +env GO111MODULE=off +[short] skip # rebuilds all of std + +# Set up fresh GOCACHE. +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +# Verify the standard library (specifically runtime/internal/atomic) can be +# built with -gcflags when -n is given. See golang.org/issue/29346. +go build -n -gcflags=all='-l' std +stderr 'compile.* runtime/internal/atomic .* -l' diff --git a/src/cmd/go/testdata/script/build_shorten_pkg.txt b/src/cmd/go/testdata/script/build_shorten_pkg.txt new file mode 100644 index 0000000..38672b6 --- /dev/null +++ b/src/cmd/go/testdata/script/build_shorten_pkg.txt @@ -0,0 +1,81 @@ +[short] skip + +# This test may go away when the loopvar experiment goes away. +# Accurate reporting of notable loops in the presence of inlining +# can create warnings in sibling directories, and it's nice if those +# can be trimmed like subdirectory paths are. + +env GOEXPERIMENT=loopvar +go build -gcflags=inlines/a=-d=loopvar=2 . +stderr ^\.[\\/]b[\\/]b\.go:12:6:.*loop.inlined.into.a[\\/]a\.go +stderr ^\.[\\/]b[\\/]b\.go:12:9:.*loop.inlined.into.a[\\/]a\.go + +-- go.mod -- +module inlines + +go 1.21 +-- a/a.go -- +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +import "inlines/b" + +func F() []*int { + var s []*int + for i := 0; i < 10; i++ { + s = append(s, &i) + } + return s +} + +func Fb() []*int { + bf, _ := b.F() + return bf +} +-- b/b.go -- +package b + +var slice = []int{1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024} + +func F() ([]*int, []*int) { + return g() +} + +func g() ([]*int, []*int) { + var s []*int + var t []*int + for i, j := range slice { + s = append(s, &i) + t = append(t, &j) + } + return s[:len(s)-1], t +} +-- main.go -- +package main + +import ( + "fmt" + "inlines/a" + "inlines/b" +) + +func sum(s []*int) int { + sum := 0 + for _, pi := range s { + sum += *pi + } + return sum +} + +func main() { + af := a.F() + bf, _ := b.F() + abf := a.Fb() + + saf, sbf, sabf := sum(af), sum(bf), sum(abf) + + fmt.Printf("af, bf, abf sums = %d, %d, %d\n", saf, sbf, sabf) +} diff --git a/src/cmd/go/testdata/script/build_single_error.txt b/src/cmd/go/testdata/script/build_single_error.txt new file mode 100644 index 0000000..241cdb9 --- /dev/null +++ b/src/cmd/go/testdata/script/build_single_error.txt @@ -0,0 +1,18 @@ +# go test ./... with a bad package should report the error once (#44624). +! go test ./... +stderr -count=1 undefined + +-- go.mod -- +module example.com + +go 1.18 +-- a/a.go -- +package a + +import "example.com/b" +-- b/b.go -- +package b + +var X = Y +-- b/b_test.go -- +package b diff --git a/src/cmd/go/testdata/script/build_static.txt b/src/cmd/go/testdata/script/build_static.txt new file mode 100644 index 0000000..7db90a1 --- /dev/null +++ b/src/cmd/go/testdata/script/build_static.txt @@ -0,0 +1,44 @@ +[short] skip 'links and runs binaries' + +# This test requires external linking. Assume that if cgo is supported +# then external linking works. +[!cgo] skip 'requires a C linker' + +# Only run on Unix systems. +[GOOS:windows] skip +[GOOS:plan9] skip + +# Ordinary build should work. +go build +exec ./hello +stdout Hello + +# Building with -linkmode=external should not say anything about +# runtime/cgo (issue #31544). +go build -ldflags=-linkmode=external +! stderr runtime/cgo +exec ./hello +stdout Hello + +# Some targets don't support -static +[GOOS:darwin] skip 'no static linking on Darwin' +[GOOS:solaris] skip 'no static linking on Solaris' + +# Building with -linkmode=external -extldflags=-static should work. +go build -ldflags='-linkmode=external -extldflags=-static' +! stderr runtime/cgo +exec ./hello +stdout Hello + +-- go.mod -- +module hello + +go 1.20 +-- hello.go -- +package main + +import "fmt" + +func main() { + fmt.Println("Hello, world") +} diff --git a/src/cmd/go/testdata/script/build_tag_goexperiment.txt b/src/cmd/go/testdata/script/build_tag_goexperiment.txt new file mode 100644 index 0000000..bee218f --- /dev/null +++ b/src/cmd/go/testdata/script/build_tag_goexperiment.txt @@ -0,0 +1,31 @@ +[short] skip +# Reset all experiments so fieldtrack is definitely off. +env GOEXPERIMENT=none +go run m +stderr 'fieldtrack off' +# Turn fieldtrack on. +env GOEXPERIMENT=none,fieldtrack +go run m +stderr 'fieldtrack on' + +-- ft_off.go -- +// +build !goexperiment.fieldtrack + +package main + +func main() { + println("fieldtrack off") +} + +-- ft_on.go -- +// +build goexperiment.fieldtrack + +package main + +func main() { + println("fieldtrack on") +} + +-- go.mod -- +module m +go 1.14 diff --git a/src/cmd/go/testdata/script/build_tags_no_comma.txt b/src/cmd/go/testdata/script/build_tags_no_comma.txt new file mode 100644 index 0000000..a14a200 --- /dev/null +++ b/src/cmd/go/testdata/script/build_tags_no_comma.txt @@ -0,0 +1,4 @@ +[compiler:gccgo] skip 'gccgo has no standard packages' +go build -tags 'tag1 tag2' math +! go build -tags 'tag1,tag2 tag3' math +stderr 'space-separated list contains comma'
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/build_test_only.txt b/src/cmd/go/testdata/script/build_test_only.txt new file mode 100644 index 0000000..8693a80 --- /dev/null +++ b/src/cmd/go/testdata/script/build_test_only.txt @@ -0,0 +1,19 @@ +# Named explicitly, test-only packages should be reported as +# unbuildable/uninstallable, even if there is a wildcard also matching. +! go build m/testonly m/testonly... +stderr 'no non-test Go files in' +! go install ./testonly +stderr 'no non-test Go files in' + +# Named through a wildcard, the test-only packages should be silently ignored. +go build m/testonly... +go install ./testonly... + +-- go.mod -- +module m + +go 1.16 +-- testonly/t_test.go -- +package testonly +-- testonly2/t.go -- +package testonly2 diff --git a/src/cmd/go/testdata/script/build_trimpath.txt b/src/cmd/go/testdata/script/build_trimpath.txt new file mode 100644 index 0000000..2a2aa20 --- /dev/null +++ b/src/cmd/go/testdata/script/build_trimpath.txt @@ -0,0 +1,164 @@ +[short] skip + +# If GOROOT_FINAL is set, 'go build -trimpath' bakes that into the resulting +# binary instead of GOROOT. Explicitly unset it here. +env GOROOT_FINAL= + +# Set up two identical directories that can be used as GOPATH. +env GO111MODULE=on +mkdir $WORK/a/src/paths $WORK/b/src/paths +cp paths.go $WORK/a/src/paths +cp paths.go $WORK/b/src/paths +cp overlay.json $WORK/a/src/paths +cp overlay.json $WORK/b/src/paths +cp go.mod $WORK/a/src/paths/ +cp go.mod $WORK/b/src/paths/ + + +# A binary built without -trimpath should contain the module root dir +# and GOROOT for debugging and stack traces. +cd $WORK/a/src/paths +go build -o $WORK/paths-dbg.exe . +exec $WORK/paths-dbg.exe $WORK/paths-dbg.exe +stdout 'binary contains module root: true' +stdout 'binary contains GOROOT: true' + +# A binary built with -trimpath should not contain the current workspace +# or GOROOT. +go build -trimpath -o $WORK/paths-a.exe . +exec $WORK/paths-a.exe $WORK/paths-a.exe +stdout 'binary contains module root: false' +stdout 'binary contains GOROOT: false' + +# A binary from an external module built with -trimpath should not contain +# the current workspace or GOROOT. +go get rsc.io/fortune +go install -trimpath rsc.io/fortune +exec $WORK/paths-a.exe $GOPATH/bin/fortune$GOEXE +stdout 'binary contains module root: false' +stdout 'binary contains GOROOT: false' +go mod edit -droprequire rsc.io/fortune + +# Two binaries built from identical packages in different directories +# should be identical. +cd $WORK/b/src/paths +go build -trimpath -o $WORK/paths-b.exe +cmp -q $WORK/paths-a.exe $WORK/paths-b.exe + + +# Same sequence of tests but with overlays. +# A binary built without -trimpath should contain the module root dir +# and GOROOT for debugging and stack traces. +cd $WORK/a/src/paths +go build -overlay overlay.json -o $WORK/paths-dbg.exe ./overlaydir +exec $WORK/paths-dbg.exe $WORK/paths-dbg.exe +stdout 'binary contains module root: true' +stdout 'binary contains GOROOT: true' + +# A binary built with -trimpath should not contain the current workspace +# or GOROOT. +go build -overlay overlay.json -trimpath -o $WORK/paths-a.exe ./overlaydir +exec $WORK/paths-a.exe $WORK/paths-a.exe +stdout 'binary contains module root: false' +stdout 'binary contains GOROOT: false' + +# Two binaries built from identical packages in different directories +# should be identical. +cd $WORK/b/src/paths +go build -overlay overlay.json -trimpath -o $WORK/paths-b.exe ./overlaydir +cmp -q $WORK/paths-a.exe $WORK/paths-b.exe + + +# Same sequence of tests but in GOPATH mode. +# A binary built without -trimpath should contain GOPATH and GOROOT. +env GO111MODULE=off +cd $WORK +env GOPATH=$WORK/a +go build -o paths-dbg.exe paths +exec ./paths-dbg.exe paths-dbg.exe +stdout 'binary contains GOPATH: true' +stdout 'binary contains GOROOT: true' + +# A binary built with -trimpath should not contain GOPATH or GOROOT. +go build -trimpath -o paths-a.exe paths +exec ./paths-a.exe paths-a.exe +stdout 'binary contains GOPATH: false' +stdout 'binary contains GOROOT: false' + +# Two binaries built from identical packages in different GOPATH roots +# should be identical. +env GOPATH=$WORK/b +go build -trimpath -o paths-b.exe paths +cmp -q paths-a.exe paths-b.exe + + +# Same sequence of tests but with gccgo. +# gccgo does not support builds in module mode. +[!exec:gccgo] stop +[cross] stop # gccgo can't necessarily cross-compile +env GOPATH=$WORK/a + +# A binary built with gccgo without -trimpath should contain the current +# GOPATH and GOROOT. +go build -compiler=gccgo -o paths-dbg.exe paths +exec ./paths-dbg.exe paths-dbg.exe +stdout 'binary contains GOPATH: true' +stdout 'binary contains GOROOT: false' # gccgo doesn't load std from GOROOT. + +# A binary built with gccgo with -trimpath should not contain GOPATH or GOROOT. +go build -compiler=gccgo -trimpath -o paths-a.exe paths +exec ./paths-a.exe paths-a.exe +stdout 'binary contains GOPATH: false' +stdout 'binary contains GOROOT: false' + +# Two binaries built from identical packages in different directories +# should be identical. +env GOPATH=$WORK/b +go build -compiler=gccgo -trimpath -o paths-b.exe paths +cmp -q paths-a.exe paths-b.exe + +-- paths.go -- +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "strings" +) + +func main() { + exe := os.Args[1] + data, err := ioutil.ReadFile(exe) + if err != nil { + log.Fatal(err) + } + + if os.Getenv("GO111MODULE") == "on" { + out, err := exec.Command("go", "env", "GOMOD").Output() + if err != nil { + log.Fatal(err) + } + modRoot := filepath.Dir(strings.TrimSpace(string(out))) + check(data, "module root", modRoot) + } else { + check(data, "GOPATH", os.Getenv("GOPATH")) + } + check(data, "GOROOT", os.Getenv("GOROOT")) +} + +func check(data []byte, desc, dir string) { + containsDir := bytes.Contains(data, []byte(dir)) + containsSlashDir := bytes.Contains(data, []byte(filepath.ToSlash(dir))) + fmt.Printf("binary contains %s: %v\n", desc, containsDir || containsSlashDir) +} +-- overlay.json -- +{ "Replace": { "overlaydir/paths.go": "paths.go" } } +-- go.mod -- +module paths + +go 1.14 diff --git a/src/cmd/go/testdata/script/build_trimpath_cgo.txt b/src/cmd/go/testdata/script/build_trimpath_cgo.txt new file mode 100644 index 0000000..5289824 --- /dev/null +++ b/src/cmd/go/testdata/script/build_trimpath_cgo.txt @@ -0,0 +1,184 @@ +# This test builds a cgo binary and verifies the source directory path +# does not appear in the binary, either literally or in compressed DWARF. +# TODO(golang.org/issue/36072): ideally we should build a binary from identical +# sources in different directories and verify the binary and all intermediate +# files are identical. + +[short] skip +[!cgo] skip + +# Check that the source path appears when -trimpath is not used. +go build -o hello.exe . +grep -q gopath[/\\]src hello.exe +go run ./list-dwarf hello.exe +stdout gopath[/\\]src + +# Check that the source path does not appear when -trimpath is used. +[GOOS:aix] stop # can't inspect XCOFF binaries +go build -trimpath -o hello.exe . +! grep -q gopath[/\\]src hello.exe +go run ./list-dwarf hello.exe +! stdout gopath/src + + +# Do the above, with the cgo (but not .c) sources in an overlay +# Check that the source path appears when -trimpath is not used. +mkdir $WORK/overlay +cp hello.go $WORK/overlay/hello.go +mkdir hello_overlay +cp hello.c hello_overlay/hello.c +go build -overlay overlay.json -o hello_overlay.exe ./hello_overlay +grep -q gopath[/\\]src hello_overlay.exe +! grep -q $WORK[/\\]overlay hello_overlay.exe +go run ./list-dwarf hello_overlay.exe +stdout gopath[/\\]src +! stdout $WORK[/\\]overlay + +# Check that the source path does not appear when -trimpath is used. +go build -overlay overlay.json -trimpath -o hello_overlay.exe ./hello_overlay +! grep -q gopath[/\\]src hello_overlay.exe +! grep -q $WORK[/\\]overlay hello_overlay.exe +go run ./list-dwarf hello_overlay.exe +! stdout gopath/src +! stdout $WORK[/\\]overlay + +-- go.mod -- +module m + +go 1.14 +-- overlay.json -- +{ + "Replace": { + "hello_overlay/hello.go": "../../overlay/hello.go" + } +} +-- hello.c -- +#include <stdio.h> + +void say_hello() { puts("Hello, world!\n"); } + +-- hello.go -- +package main + +// void say_hello(); +import "C" + +func main() { + C.say_hello() +} + +-- list-dwarf/list-dwarf.go -- +package main + +import ( + "debug/dwarf" + "fmt" + "io" + "log" + "os" + "sort" +) + +func main() { + files, err := run(os.Args[1]) + if err != nil { + log.Fatal(err) + } + for _, file := range files { + fmt.Println(file) + } +} + +func run(exePath string) ([]string, error) { + dwarfData, err := readDWARF(exePath) + if err != nil { + return nil, err + } + + dwarfReader := dwarfData.Reader() + files := make(map[string]bool) + for { + e, err := dwarfReader.Next() + if err != nil { + return nil, err + } + if e == nil { + break + } + lr, err := dwarfData.LineReader(e) + if err != nil { + return nil, err + } + if lr == nil { + continue + } + + var le dwarf.LineEntry + for { + if err := lr.Next(&le); err != nil { + if err == io.EOF { + break + } + return nil, err + } + files[le.File.Name] = true + } + } + + sortedFiles := make([]string, 0, len(files)) + for file := range files { + sortedFiles = append(sortedFiles, file) + } + sort.Strings(sortedFiles) + return sortedFiles, nil +} +-- list-dwarf/read_darwin.go -- +package main + +import ( + "debug/dwarf" + "debug/macho" +) + +func readDWARF(exePath string) (*dwarf.Data, error) { + machoFile, err := macho.Open(exePath) + if err != nil { + return nil, err + } + defer machoFile.Close() + return machoFile.DWARF() +} +-- list-dwarf/read_elf.go -- +// +build android dragonfly freebsd illumos linux netbsd openbsd solaris + +package main + +import ( + "debug/dwarf" + "debug/elf" +) + +func readDWARF(exePath string) (*dwarf.Data, error) { + elfFile, err := elf.Open(exePath) + if err != nil { + return nil, err + } + defer elfFile.Close() + return elfFile.DWARF() +} +-- list-dwarf/read_windows.go -- +package main + +import ( + "debug/dwarf" + "debug/pe" +) + +func readDWARF(exePath string) (*dwarf.Data, error) { + peFile, err := pe.Open(exePath) + if err != nil { + return nil, err + } + defer peFile.Close() + return peFile.DWARF() +} diff --git a/src/cmd/go/testdata/script/build_trimpath_goroot.txt b/src/cmd/go/testdata/script/build_trimpath_goroot.txt new file mode 100644 index 0000000..a26cfd2 --- /dev/null +++ b/src/cmd/go/testdata/script/build_trimpath_goroot.txt @@ -0,0 +1,103 @@ +# Regression test for https://go.dev/issue/51461 and https://go.dev/issue/51483. +# +# When built with -trimpath, runtime.GOROOT() returned the bogus string "go" +# if GOROOT was not set explicitly in the environment. +# It should instead return the empty string, since we know that we don't +# have a valid path to return. +# +# TODO(#51483): when runtime.GOROOT() returns the empty string, +# go/build should default to 'go env GOROOT' instead. + +env GOROOT_FINAL= + +[trimpath] env GOROOT= +[trimpath] ! go env GOROOT +[trimpath] stderr '^go: cannot find GOROOT directory: ''go'' binary is trimmed and GOROOT is not set$' +[trimpath] env GOROOT=$TESTGO_GOROOT + +[short] stop + +# With GOROOT still set but GOROOT_FINAL unset, 'go build' and 'go test -c' +# should cause runtime.GOROOT() to report either the correct GOROOT +# (without -trimpath) or no GOROOT at all (with -trimpath). + +go build -o example.exe . +go build -trimpath -o example-trimpath.exe . +go test -c -o example.test.exe . +go test -trimpath -c -o example.test-trimpath.exe . + +env GOROOT= + +exec ./example.exe +stdout '^GOROOT '$TESTGO_GOROOT'$' +stdout '^runtime '$TESTGO_GOROOT${/}src${/}runtime'$' + +! exec ./example-trimpath.exe +stdout '^GOROOT $' +stderr 'cannot find package "runtime" in any of:\n\t\(\$GOROOT not set\)\n\t'$WORK${/}gopath${/}src${/}runtime' \(from \$GOPATH\)\n\z' + +exec ./example.test.exe -test.v +stdout '^GOROOT '$TESTGO_GOROOT'$' +stdout '^runtime '$TESTGO_GOROOT${/}src${/}runtime'$' + +! exec ./example.test-trimpath.exe -test.v +stdout '^GOROOT $' +stderr 'cannot find package "runtime" in any of:\n\t\(\$GOROOT not set\)\n\t'$WORK${/}gopath${/}src${/}runtime' \(from \$GOPATH\)$' + +# If a correct GOROOT is baked in to the 'go' command itself, 'go run' and +# 'go test' should not implicitly set GOROOT in the process environment +# (because that could mask an unexpected production dependency on the GOROOT +# environment variable), but 'go generate' should (because the generator may +# reasonably expect to be able to locate the GOROOT for which it is generating +# code). + +[trimpath] stop +[mismatched-goroot] stop + +! go run -trimpath . +stdout '^GOROOT $' +stderr 'cannot find package "runtime" in any of:\n\t\(\$GOROOT not set\)\n\t'$WORK${/}gopath${/}src${/}runtime' \(from \$GOPATH\)\nexit status 1\n\z' + +! go test -trimpath -v . +stdout '^GOROOT $' +stdout 'cannot find package "runtime" in any of:\n\t\(\$GOROOT not set\)\n\t'$WORK${/}gopath${/}src${/}runtime' \(from \$GOPATH\)$' + +env GOFLAGS=-trimpath +go generate . +stdout '^GOROOT '$TESTGO_GOROOT'$' +stdout '^runtime '$TESTGO_GOROOT${/}src${/}runtime'$' + +-- go.mod -- +module example + +go 1.19 +-- main.go -- +package main + +//go:generate go run . + +import ( + "fmt" + "go/build" + "os" + "runtime" +) + +func main() { + fmt.Println("GOROOT", runtime.GOROOT()) + + p, err := build.Default.Import("runtime", "", build.FindOnly) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + fmt.Println("runtime", p.Dir) +} +-- main_test.go -- +package main + +import "testing" + +func TestMain(*testing.M) { + main() +} diff --git a/src/cmd/go/testdata/script/build_unsupported_goos.txt b/src/cmd/go/testdata/script/build_unsupported_goos.txt new file mode 100644 index 0000000..c94d6d2 --- /dev/null +++ b/src/cmd/go/testdata/script/build_unsupported_goos.txt @@ -0,0 +1,6 @@ +[compiler:gccgo] skip # gccgo assumes cross-compilation is always possible + +env GOOS=windwos # intentional misspelling of windows + +! go build -n exclude +stderr 'unsupported GOOS/GOARCH pair' diff --git a/src/cmd/go/testdata/script/build_vendor.txt b/src/cmd/go/testdata/script/build_vendor.txt new file mode 100644 index 0000000..f430ff2 --- /dev/null +++ b/src/cmd/go/testdata/script/build_vendor.txt @@ -0,0 +1,42 @@ +# Build +env GO111MODULE=off +go build vend/x +! stdout . +! stderr . + +-- vend/dir1/dir1.go -- +package dir1 +-- vend/subdir/bad.go -- +package subdir + +import _ "r" +-- vend/subdir/good.go -- +package subdir + +import _ "p" +-- vend/vendor/p/p.go -- +package p +-- vend/vendor/q/q.go -- +package q +-- vend/vendor/vend/dir1/dir2/dir2.go -- +package dir2 +-- vend/x/invalid/invalid.go -- +package invalid + +import "vend/x/invalid/vendor/foo" +-- vend/x/vendor/p/p/p.go -- +package p + +import _ "notfound" +-- vend/x/vendor/p/p.go -- +package p +-- vend/x/vendor/r/r.go -- +package r +-- vend/x/x.go -- +package x + +import _ "p" +import _ "q" +import _ "r" +import _ "vend/dir1" // not vendored +import _ "vend/dir1/dir2" // vendored diff --git a/src/cmd/go/testdata/script/cache_unix.txt b/src/cmd/go/testdata/script/cache_unix.txt new file mode 100644 index 0000000..e11804d --- /dev/null +++ b/src/cmd/go/testdata/script/cache_unix.txt @@ -0,0 +1,37 @@ +env GO111MODULE=off + +# Integration test for cache directory calculation (cmd/go/internal/cache). + +[GOOS:windows] skip 'windows does not use XDG_CACHE_HOME' +[GOOS:darwin] skip 'darwin does not use XDG_CACHE_HOME' +[GOOS:ios] skip 'ios does not use XDG_CACHE_HOME' +[GOOS:plan9] skip 'plan9 does not use XDG_CACHE_HOME' + +mkdir $WORK/gocache +mkdir $WORK/xdg +mkdir $WORK/home + +# Set GOCACHE, XDG_CACHE_HOME, and HOME. +env GOCACHE=$WORK/gocache +env XDG_CACHE_HOME=$WORK/xdg +env HOME=$WORK/home + +# With all three set, we should prefer GOCACHE. +go env GOCACHE +stdout $WORK'/gocache$' + +# Without GOCACHE, we should prefer XDG_CACHE_HOME over HOME. +env GOCACHE= +go env GOCACHE +stdout $WORK'/xdg/go-build$$' + +# With only HOME set, we should use $HOME/.cache. +env XDG_CACHE_HOME= +go env GOCACHE +stdout $WORK'/home/.cache/go-build$' + +# With no guidance from the environment, we must disable the cache, but that +# should not cause commands that do not write to the cache to fail. +env HOME= +go env GOCACHE +stdout 'off' diff --git a/src/cmd/go/testdata/script/cache_vet.txt b/src/cmd/go/testdata/script/cache_vet.txt new file mode 100644 index 0000000..6689048 --- /dev/null +++ b/src/cmd/go/testdata/script/cache_vet.txt @@ -0,0 +1,22 @@ +env GO111MODULE=off + +[short] skip +[GODEBUG:gocacheverify=1] skip +[compiler:gccgo] skip # gccgo has no standard packages + +# Start with a clean build cache: +# test failures may be masked if the cache has just the right entries already. +env GOCACHE=$WORK/cache + +# Run 'go vet os/user' once to warm up the cache. +go vet os/user + +# Check that second vet reuses cgo-derived inputs. +# The first command could be build instead of vet, +# except that if the cache is empty and there's a net.a +# in GOROOT/pkg, the build will not bother to regenerate +# and cache the cgo outputs, whereas vet always will. + +go vet -x os/user +! stderr '^(clang|gcc)' # should not have run compiler +! stderr '[\\/]cgo ' # should not have run cgo diff --git a/src/cmd/go/testdata/script/cgo_asm_error.txt b/src/cmd/go/testdata/script/cgo_asm_error.txt new file mode 100644 index 0000000..7aaa713 --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_asm_error.txt @@ -0,0 +1,25 @@ +[!cgo] skip + +# Test that cgo package can't contain a go assembly file. + +# Ensure the build fails and reports that the package has a Go assembly file. +! go build cgoasm +stderr 'package using cgo has Go assembly file' + +-- go.mod -- +module cgoasm + +go 1.16 +-- p.go -- +package p + +/* +// hi +*/ +import "C" + +func F() {} +-- p.s -- +TEXT asm(SB),$0 + RET + diff --git a/src/cmd/go/testdata/script/cgo_bad_directives.txt b/src/cmd/go/testdata/script/cgo_bad_directives.txt new file mode 100644 index 0000000..7d28171 --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_bad_directives.txt @@ -0,0 +1,129 @@ +[!cgo] skip +[short] skip + +cp x.go.txt x.go + +# Only allow //go:cgo_ldflag .* in cgo-generated code +[compiler:gc] cp x_gc.go.txt x.go +[compiler:gc] ! go build x +[compiler:gc] stderr '//go:cgo_ldflag .* only allowed in cgo-generated code' + +# Ignore _* files +rm x.go +! go build . +stderr 'no Go files' +cp cgo_yy.go.txt _cgo_yy.go +! go build . +stderr 'no Go files' #_* files are ignored... + +[compiler:gc] ! go build _cgo_yy.go # ... but if forced, the comment is rejected +# Actually, today there is a separate issue that _ files named +# on the command line are ignored. Once that is fixed, +# we want to see the cgo_ldflag error. +[compiler:gc] stderr '//go:cgo_ldflag only allowed in cgo-generated code|no Go files' + +rm _cgo_yy.go + +# Reject #cgo CFLAGS: -fplugin=foo.so +cp x.go.txt x.go +cp y_fplugin.go.txt y.go +! go build x +stderr 'invalid flag in #cgo CFLAGS: -fplugin=foo.so' + +# Reject #cgo CFLAGS: -lbar -fplugin=foo.so +cp y_lbar_fplugin.go.txt y.go +! go build x +stderr 'invalid flag in #cgo CFLAGS: -fplugin=foo.so' + +# Reject #cgo pkg-config: -foo +cp y_pkgconfig_dash_foo.txt y.go +! go build x +stderr 'invalid pkg-config package name: -foo' + +# Reject #cgo pkg-config: @foo +cp y_pkgconfig_at_foo.txt y.go +! go build x +stderr 'invalid pkg-config package name: @foo' + +# Reject #cgo CFLAGS: @foo +cp y_cflags_at_foo.txt y.go +! go build x +stderr 'invalid flag in #cgo CFLAGS: @foo' + +# Reject #cgo CFLAGS: -D +cp y_cflags_dash_d.txt y.go +! go build x +stderr 'invalid flag in #cgo CFLAGS: -D without argument' + +# Note that -I @foo is allowed because we rewrite it into -I /path/to/src/@foo +# before the check is applied. There's no such rewrite for -D. + +# Reject #cgo CFLAGS: -D @foo +cp y_cflags_dash_d_space_at_foo.txt y.go +! go build x +stderr 'invalid flag in #cgo CFLAGS: -D @foo' + +# Reject #cgo CFLAGS -D@foo +cp y_cflags_dash_d_at_foo.txt y.go +! go build x +stderr 'invalid flag in #cgo CFLAGS: -D@foo' + +# Check for CFLAGS in commands +env CGO_CFLAGS=-D@foo +cp y_no_cflags.txt y.go +go build -n x +stderr '-D@foo' + +-- go.mod -- +module x + +go 1.16 +-- x_gc.go.txt -- +package x + +//go:cgo_ldflag "-fplugin=foo.so" + +import "C" +-- cgo_yy.go.txt -- +package x + +//go:cgo_ldflag "-fplugin=foo.so" + +import "C" +-- x.go.txt -- +package x +-- y_fplugin.go.txt -- +package x +// #cgo CFLAGS: -fplugin=foo.so +import "C" +-- y_lbar_fplugin.go.txt -- +package x +// #cgo CFLAGS: -Ibar -fplugin=foo.so +import "C" +-- y_pkgconfig_dash_foo.txt -- +package x +// #cgo pkg-config: -foo +import "C" +-- y_pkgconfig_at_foo.txt -- +package x +// #cgo pkg-config: @foo +import "C" +-- y_cflags_at_foo.txt -- +package x +// #cgo CFLAGS: @foo +import "C" +-- y_cflags_dash_d.txt -- +package x +// #cgo CFLAGS: -D +import "C" +-- y_cflags_dash_d_space_at_foo.txt -- +package x +// #cgo CFLAGS: -D @foo +import "C" +-- y_cflags_dash_d_at_foo.txt -- +package x +// #cgo CFLAGS: -D@foo +import "C" +-- y_no_cflags.txt -- +package x +import "C" diff --git a/src/cmd/go/testdata/script/cgo_badmethod_issue57926.txt b/src/cmd/go/testdata/script/cgo_badmethod_issue57926.txt new file mode 100644 index 0000000..81ef850 --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_badmethod_issue57926.txt @@ -0,0 +1,31 @@ +[short] skip +[!cgo] skip + +# Test that cgo rejects attempts to declare methods +# on the types C.T or *C.T; see issue #57926. + +! go build +stderr 'cannot define new methods on non-local type C.T' +stderr 'cannot define new methods on non-local type \*C.T' +! stderr 'Alias' + +-- go.mod -- +module example.com +go 1.12 + +-- a.go -- +package a + +/* +typedef int T; +*/ +import "C" + +func (C.T) f() {} +func (recv *C.T) g() {} + +// The check is more education than enforcement, +// and is easily defeated using a type alias. +type Alias = C.T +func (Alias) h() {} +func (*Alias) i() {} diff --git a/src/cmd/go/testdata/script/cgo_depends_on_syscall.txt b/src/cmd/go/testdata/script/cgo_depends_on_syscall.txt new file mode 100644 index 0000000..bd4777c --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_depends_on_syscall.txt @@ -0,0 +1,15 @@ +[!cgo] skip +[!race] skip + +go list -race -deps foo +stdout syscall + +-- go.mod -- +module foo + +go 1.16 +-- foo.go -- +package foo + +// #include <stdio.h> +import "C" diff --git a/src/cmd/go/testdata/script/cgo_flag_contains_space.txt b/src/cmd/go/testdata/script/cgo_flag_contains_space.txt new file mode 100644 index 0000000..a3372bb --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_flag_contains_space.txt @@ -0,0 +1,16 @@ +[short] skip +[!cgo] skip + +env GOCACHE=$WORK/gocache # Looking for compile flags, so need a clean cache. +go build -x -n main.go +stderr '"-I[^"]+c flags"' # find quoted c flags +! stderr '"-I[^"]+c flags".*"-I[^"]+c flags"' # don't find too many quoted c flags per line +stderr '"-L[^"]+ld flags"' # find quoted ld flags +! stderr '"-L[^"]+c flags".*"-L[^"]+c flags"' # don't find too many quoted ld flags per line + +-- main.go -- +package main +// #cgo CFLAGS: -I"c flags" +// #cgo LDFLAGS: -L"ld flags" +import "C" +func main() {} diff --git a/src/cmd/go/testdata/script/cgo_path.txt b/src/cmd/go/testdata/script/cgo_path.txt new file mode 100644 index 0000000..be23893 --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_path.txt @@ -0,0 +1,41 @@ +[!cgo] skip + +# Require that CC is something that requires a PATH lookup. +# Normally, the default is gcc or clang, but if CC was set during make.bash, +# that becomes the default. +[!cc:clang] [!cc:gcc] skip 'C compiler is not gcc or clang' + +env GOCACHE=$WORK/gocache # Looking for compile flags, so need a clean cache. +[!GOOS:windows] env PATH=.:$PATH +[!GOOS:windows] chmod 0755 p/gcc p/clang +[!GOOS:windows] exists -exec p/gcc p/clang +[GOOS:windows] exists -exec p/gcc.bat p/clang.bat +! exists p/bug.txt +! go build -x +stderr '^cgo: C compiler "(clang|gcc)" not found: exec: "(clang|gcc)": cannot run executable found relative to current directory' +! exists p/bug.txt + +-- go.mod -- +module m + +-- m.go -- +package m + +import _ "m/p" + +-- p/p.go -- +package p + +// #define X 1 +import "C" + +-- p/gcc -- +#!/bin/sh +echo ran gcc >bug.txt +-- p/clang -- +#!/bin/sh +echo ran clang >bug.txt +-- p/gcc.bat -- +echo ran gcc >bug.txt +-- p/clang.bat -- +echo ran clang >bug.txt diff --git a/src/cmd/go/testdata/script/cgo_path_space.txt b/src/cmd/go/testdata/script/cgo_path_space.txt new file mode 100644 index 0000000..1a78902 --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_path_space.txt @@ -0,0 +1,56 @@ +# Check that if the PATH directory containing the C compiler has a space, +# we can still use that compiler with cgo. +# Verifies #43808. +[!cgo] skip + +# Set CC explicitly to something that requires a PATH lookup. +# Normally, the default is gcc or clang, but if CC was set during make.bash, +# that becomes the default. +[exec:clang] env CC=clang +[exec:gcc] env CC=gcc +[!exec:clang] [!exec:gcc] skip 'Unknown C compiler' + +[!GOOS:windows] chmod 0755 $WORK/'program files'/clang +[!GOOS:windows] chmod 0755 $WORK/'program files'/gcc +[!GOOS:windows] exists -exec $WORK/'program files'/clang +[!GOOS:windows] exists -exec $WORK/'program files'/gcc +[!GOOS:windows] env PATH=$WORK/'program files':$PATH +[GOOS:windows] exists -exec $WORK/'program files'/gcc.bat +[GOOS:windows] exists -exec $WORK/'program files'/clang.bat +[GOOS:windows] env PATH=$WORK\'program files';%PATH% + +! exists $WORK/log.txt +? go build -x +exists $WORK/log.txt +rm $WORK/log.txt + +# TODO(#41400, #43078): when CC is set explicitly, it should be allowed to +# contain spaces separating arguments, and it should be possible to quote +# arguments with spaces (including the path), as in CGO_CFLAGS and other +# variables. For now, this doesn't work. +[!GOOS:windows] env CC=$WORK/'program files'/gcc +[GOOS:windows] env CC=$WORK\'program files'\gcc.bat +! go build -x +! exists $WORK/log.txt + +-- go.mod -- +module m + +-- m.go -- +package m + +// #define X 1 +import "C" + +-- $WORK/program files/gcc -- +#!/bin/sh + +echo ok >$WORK/log.txt +-- $WORK/program files/clang -- +#!/bin/sh + +echo ok >$WORK/log.txt +-- $WORK/program files/gcc.bat -- +echo ok >%WORK%\log.txt +-- $WORK/program files/clang.bat -- +echo ok >%WORK%\log.txt diff --git a/src/cmd/go/testdata/script/cgo_path_space_quote.txt b/src/cmd/go/testdata/script/cgo_path_space_quote.txt new file mode 100644 index 0000000..9556101 --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_path_space_quote.txt @@ -0,0 +1,58 @@ +# This test checks that the CC environment variable may contain quotes and +# spaces. Arguments are normally split on spaces, tabs, newlines. If an +# argument contains these characters, the entire argument may be quoted +# with single or double quotes. This is the same as -gcflags and similar +# options. + +[short] skip +[!exec:clang] [!exec:gcc] skip +[!cgo] skip + +env GOENV=$WORK/go.env +mkdir 'program files' +go build -o 'program files' './which cc/which cc.go' +[exec:clang] env CC='"'$PWD${/}program' 'files${/}which' 'cc"' 'clang +[!exec:clang] env CC='"'$PWD${/}program' 'files${/}which' 'cc"' 'gcc +go env CC +stdout 'program files[/\\]which cc" (clang|gcc)$' +go env -w CC=$CC +env CC= +go env CC +stdout 'program files[/\\]which cc" (clang|gcc)$' + +go run . +stdout 1 + +-- go.mod -- +module test + +go 1.17 +-- which cc/which cc.go -- +package main + +import ( + "fmt" + "os" + "os/exec" +) + +func main() { + args := append([]string{"-DWRAPPER_WAS_USED=1"}, os.Args[2:]...) + cmd := exec.Command(os.Args[1], args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} +-- hello.go -- +package main + +// int x = WRAPPER_WAS_USED; +import "C" +import "fmt" + +func main() { + fmt.Println(C.x) +} diff --git a/src/cmd/go/testdata/script/cgo_stale.txt b/src/cmd/go/testdata/script/cgo_stale.txt new file mode 100644 index 0000000..0d30aea --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_stale.txt @@ -0,0 +1,39 @@ +# golang.org/issue/46347: a stale runtime/cgo should only force a single rebuild + +[!cgo] skip +[short] skip + + +# If we set a unique CGO_CFLAGS, the installed copy of runtime/cgo +# should be reported as stale. + +env CGO_CFLAGS=-DTestScript_cgo_stale=true +stale runtime/cgo + + +# If we then build a package that uses cgo, runtime/cgo should be rebuilt and +# cached with the new flag, but not installed to GOROOT. +# It has no install target, and thus is never stale. + +env GOCACHE=$WORK/cache # Use a fresh cache to avoid interference between runs. + +go build -x . +stderr '[/\\]cgo'$GOEXE'["]? .* -importpath runtime/cgo' +! stale runtime/cgo + + +# After runtime/cgo has been rebuilt and cached, it should not be rebuilt again. + +go build -x . +! stderr '[/\\]cgo'$GOEXE'["]? .* -importpath runtime/cgo' +! stale runtime/cgo + + +-- go.mod -- +module example.com/m + +go 1.17 +-- m.go -- +package m + +import "C" diff --git a/src/cmd/go/testdata/script/cgo_stale_precompiled.txt b/src/cmd/go/testdata/script/cgo_stale_precompiled.txt new file mode 100644 index 0000000..b2a0e0c --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_stale_precompiled.txt @@ -0,0 +1,40 @@ +# Regression test for https://go.dev/issue/47215 and https://go.dev/issue/50183: +# A mismatched $GOROOT_FINAL or missing $CC caused the C dependencies of the net +# package to appear stale, and it could not be rebuilt due to a missing $CC. + +[!cgo] skip + +# This test may start with the runtime/cgo package already stale. +# Explicitly rebuild it to ensure that it is cached. +# (See https://go.dev/issue/50892.) +# +# If running in non-short mode, explicitly vary CGO_CFLAGS +# as a control case (to ensure that our regexps do catch rebuilds). + +[!short] env GOCACHE=$WORK/cache +[!short] env CGO_CFLAGS=-DTestScript_cgo_stale_precompiled=true +go build -x runtime/cgo +[!short] stderr '[/\\]cgo'$GOEXE'["]? .* -importpath runtime/cgo' + +# https://go.dev/issue/50183: a mismatched GOROOT_FINAL caused net to be stale. +env oldGOROOT_FINAL=$GOROOT_FINAL +env GOROOT_FINAL=$WORK${/}goroot +go build -x runtime/cgo +! stderr '[/\\]cgo'$GOEXE'["]? .* -importpath runtime/cgo' + +env GOROOT_FINAL=$oldGOROOT_FINAL + +# https://go.dev/issue/47215: a missing $(go env CC) caused the precompiled net +# to be stale. But as of https://go.dev/cl/452457 the precompiled libraries are +# no longer installed anyway! Since we're requiring a C compiler in order to +# build and use cgo libraries in the standard library, we should make sure it +# matches what's in the cache. + +[abscc] stop + +env CGO_ENABLED=1 +env CC='' +[!GOOS:plan9] env PATH='' # Guaranteed not to include $(go env CC)! +[GOOS:plan9] env path='' +! go build -x runtime/cgo +stderr 'C compiler .* not found' diff --git a/src/cmd/go/testdata/script/cgo_suspect_flag_force_external.txt b/src/cmd/go/testdata/script/cgo_suspect_flag_force_external.txt new file mode 100644 index 0000000..6dc30be --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_suspect_flag_force_external.txt @@ -0,0 +1,201 @@ +# Test case to verify that when we have a package that uses CGO in +# combination with selected "unusual" flags (involving plugins, LTO) +# that we force external linking. See related +# issues 58619, 58620, and 58848. + +[compiler:gccgo] skip # only external linking for gccgo + +[!cgo] skip 'test verifies behavior that depends on CGO_CFLAGS' +[mustlinkext] skip 'test expects internal linking for non-cgo programs' + +# Here we build three program: one with explicit CGO use, one with no +# CGO use, and one that uses a stdlib package ("runtime/cgo") that has +# CGO in it. It used to be that only the explicit use of CGO would +# trigger external linking, and that the program that only used +# "runtime/cgo" would always be handled with internal linking. This caused +# issues when users included odd/unusual flags (ex: -fplugin, -flto) +# in CGO_CFLAGS, causing the Go linker to have to read and interpret +# non-standard host objects. +# +# As of 1.21 we continue to use internal linking for programs whose +# CGO use comes only from stdlib packages in the absence of any flag +# funny business, however if the Go command sees flags that may be suspicious, +# it signals the Go linker to invoke the external linker. + +# The next few tests run builds passing "-n" to the Go command, then +# checking the output to see if the Go command is trying to pass a +# "preferlinkext" token to the linker to request external linking. + +#----------------------- + +# Use a fresh GOCACHE for these next steps, so as to have the real +# actions for the runtime/cgo package appear in the "-n -x" output. +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +# First build: there is no CGO in use, so no token should be present regardless +# of weird CGO flags. +go build -x -n -o dummy.exe ./noUseOfCgo +! stderr preferlinkext +env CGO_CFLAGS=-flto +go build -x -n -o dummy.exe ./noUseOfCgo +! stderr preferlinkext +env CGO_CFLAGS= + +# Second build uses CGO, so we expect to see the token present in the +# -n output only when strange flags are used. +go build -x -n -o dummy.exe ./usesInternalCgo +! stderr preferlinkext +env CGO_CFLAGS=-flto +go build -x -n -o dummy.exe ./usesInternalCgo +stderr preferlinkext +env CGO_CFLAGS=-fplugin +go build -x -n -o dummy.exe ./usesInternalCgo +stderr preferlinkext +env CGO_CFLAGS=-fprofile-instr-generate +go build -x -n -o dummy.exe ./usesInternalCgo +stderr preferlinkext + +# The -fdebug-prefix-map=path is permitted for internal linking. +env CGO_CFLAGS=-fdebug-prefix-map=/some/sandbox/execroot/workspace=/tmp/new +go build -x -n -o dummy.exe ./usesInternalCgo +! stderr preferlinkext +env CGO_CFLAGS=-fdebug-prefix-map=/Users/someone/.cache/bazel/_bazel_someone/3fa7e4650c43657ead684537951f49e2/sandbox/linux-sandbox/10/execroot/rules_go_static=. +go build -x -n -o dummy.exe ./usesInternalCgo +! stderr preferlinkext +# The -ffile-prefix-map=path is permitted for internal linking too. +env CGO_CFLAGS=-ffile-prefix-map=/Users/someone/.cache/bazel/_bazel_someone/3fa7e4650c43657ead684537951f49e2/sandbox/linux-sandbox/10/execroot/rules_go_static/bazel-out/aarch64-fastbuild-ST-b33d65c724e6/bin/external/io_bazel_rules_go/stdlib_=. +go build -x -n -o dummy.exe ./usesInternalCgo +! stderr preferlinkext +# Verifying that -fdebug-prefix-map=path, -ffile-prefix-map, -no-canonical-prefixes +# and -fno-canonical-systemd-headers are permitted for internal linking. +env CGO_CFLAGS=-fdebug-prefix-map=old=/tmp/new +go build -x -n -o dummy.exe ./usesInternalCgo +! stderr preferlinkext +env CGO_CFLAGS=-ffile-prefix-map=/Users/someone/_11233/things=new +go build -x -n -o dummy.exe ./usesInternalCgo +! stderr preferlinkext +env CGO_CFLAGS=-no-canonical-prefixes +go build -x -n -o dummy.exe ./usesInternalCgo +! stderr preferlinkext +env CGO_CFLAGS=-fno-canonical-system-headers +go build -x -n -o dummy.exe ./usesInternalCgo +! stderr preferlinkext +env CGO_CFLAGS= + +[short] skip + +# In the remaining tests below we do actual builds (without -n) to +# verify that the Go linker is going the right thing in addition to the +# Go command. Here the idea is to pass "-tmpdir" to the linker, then +# check after the link is done for the presence of the file +# <tmpdir>/go.o, which the Go linker creates prior to kicking off the +# external linker. + +mkdir tmp1 +mkdir tmp2 +mkdir tmp3 +mkdir tmp4 +mkdir tmp5 + +# First build: no external linking expected +go build -ldflags=-tmpdir=tmp1 -o $devnull ./noUseOfCgo & + +# Second build: using only "runtime/cgo", expect internal linking. +go build -ldflags=-tmpdir=tmp2 -o $devnull ./usesInternalCgo & + +# Third build: program uses only "runtime/cgo", so we would normally +# expect internal linking, except that cflags contain suspicious entries +# (in this case, a flag that does not appear on the allow list). +env CGO_CFLAGS=-fmerge-all-constants +env CGO_LDFLAGS=-fmerge-all-constants +go build -ldflags=-tmpdir=tmp3 -o $devnull ./usesInternalCgo & +env CGO_CFLAGS= +env CGO_LDFLAGS= + +# Fourth build: explicit CGO, expect external linking. +go build -ldflags=-tmpdir=tmp4 -o $devnull ./usesExplicitCgo & + +# Fifth build: explicit CGO, but we specifically asked for internal linking +# via a flag, so using internal linking it is. +[cgolinkext] go list ./usesInternalCgo +[!cgolinkext] go build '-ldflags=-tmpdir=tmp5 -linkmode=internal' -o $devnull ./usesInternalCgo & + +# Sixth build: explicit CGO use in a non-main package. +go build -o p.a ./nonMainPackageUsesExplicitCgo & + +wait + +# Check first build: no external linking expected +! exists tmp1/go.o + +# Check second build: using only "runtime/cgo", expect internal linking. +[!cgolinkext] ! exists tmp2/go.o +[cgolinkext] exists tmp2/go.o + +# Check third build: has suspicious flag. +exists tmp3/go.o + +# Fourth build: explicit CGO, expect external linking. +exists tmp4/go.o + +# Fifth build: explicit CGO, -linkmode=internal. +! exists tmp5/go.o + +# Sixth build: make sure that "go tool nm" doesn't get confused +# by the presence of the "preferlinkext" sentinel. +go tool nm p.a + +-- go.mod -- + +module cgo.example + +go 1.20 + +-- noUseOfCgo/main.go -- + +package main + +func main() { + println("clean as a whistle") +} + +-- usesInternalCgo/main.go -- + +package main + +import ( + "runtime/cgo" +) + +func main() { + q := "hello" + h := cgo.NewHandle(q) + h.Delete() +} + +-- usesExplicitCgo/main.go -- + +package main + +/* +int meaningOfLife() { return 42; } +*/ +import "C" + +func main() { + println(C.meaningOfLife()) +} + +-- nonMainPackageUsesExplicitCgo/main.go -- + +package p + +/* +int meaningOfLife() { return 42; } +*/ +import "C" + +func PrintIt() { + println(C.meaningOfLife()) +} diff --git a/src/cmd/go/testdata/script/cgo_syso_issue29253.txt b/src/cmd/go/testdata/script/cgo_syso_issue29253.txt new file mode 100644 index 0000000..18526c6 --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_syso_issue29253.txt @@ -0,0 +1,31 @@ +env GO111MODULE=off +[short] skip + +# This test tests that we can link in-package syso files that provides symbols +# for cgo. See issue 29253. +[!cgo] stop +[!compiler:gc] stop +cc -c -o pkg/o.syso ext.c +go build main.go + +-- ext.c -- +// +build ignore + +int f() { return 42; } +-- pkg/pkg.go -- +package pkg + +// extern int f(void); +import "C" + +func init() { + if v := C.f(); v != 42 { + panic(v) + } +} +-- main.go -- +package main + +import _ "pkg" + +func main() {} diff --git a/src/cmd/go/testdata/script/cgo_trimpath_macro.txt b/src/cmd/go/testdata/script/cgo_trimpath_macro.txt new file mode 100644 index 0000000..b5cc116 --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_trimpath_macro.txt @@ -0,0 +1,71 @@ +# This is a test that -trimpath trims the paths of every directory +# of Cgo dependencies in the module, and trims file paths included +# through the __FILE__ macro using --file-prefix-map. + +[!cgo] skip +[short] skip 'links and runs binaries' + +# Test in main module. +go run -trimpath -mod=vendor ./main +stdout '(\\_\\_|/_)[\\/]m[\\/]c[\\/]bar.h' + +# Test in vendored module. +go run -trimpath -mod=vendor v.com/main +stdout '(\\_\\_|/_)[\\/]vendor[\\/]v.com[\\/]c[\\/]bar.h' + +# Test in GOPATH mode. +env GO111MODULE=off +go run -trimpath ./main +stdout '(\\_\\_|/_)[\\/]GOPATH[\\/]src[\\/]c[\\/]bar.h' + +-- go.mod -- +module m + +require v.com v1.0.0 +-- go.sum -- +v.com v1.0.0 h1:xxx +v.com v1.0.0/go.mod h1:xxx +-- vendor/modules.txt -- +# v.com v1.0.0 +## explicit; go 1.20 +v.com/main +-- vendor/v.com/main/main.go -- +package main + +// #cgo CFLAGS: -I../c +// #include "stdio.h" +// void printfile(); +import "C" + +func main() { + C.printfile() + C.fflush(C.stdout) +} +-- vendor/v.com/main/foo.c -- +#include "bar.h" +-- vendor/v.com/c/bar.h -- +#include "stdio.h" + +void printfile() { + printf("%s\n", __FILE__); +} +-- main/main.go -- +package main + +// #cgo CFLAGS: -I../c +// #include "stdio.h" +// void printfile(); +import "C" + +func main() { + C.printfile() + C.fflush(C.stdout) +} +-- main/foo.c -- +#include "bar.h" +-- c/bar.h -- +#include "stdio.h" + +void printfile() { + printf("%s\n", __FILE__); +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/cgo_undef.txt b/src/cmd/go/testdata/script/cgo_undef.txt new file mode 100644 index 0000000..30034fb --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_undef.txt @@ -0,0 +1,68 @@ +# Issue 52863. + +# We manually create a .syso and a .a file in package a, +# such that the .syso file only works when linked against the .a file. +# Package a has #cgo LDFLAGS to make this happen. +# +# Package c imports package a, and uses cgo itself. +# The generation of the _cgo_import.go for package c will fail, +# because it won't know that it has to link against a/libb.a +# (because we don't gather the #cgo LDFLAGS from all transitively +# imported packages). +# +# The _cgo_import.go file is only needed for internal linking. +# When generating _cgo_import.go for package c fails, an ordinary +# external link should still work. But an internal link is expected +# to fail, because the failure to create _cgo_import.go should cause +# the linker to report an inability to internally link. + +[short] skip +[!cgo] skip +[!exec:ar] skip + +cc -c -o a/b.syso b/b.c +cc -c -o b/lib.o b/lib.c +exec ar rc a/libb.a b/lib.o +go build +! go build -ldflags=-linkmode=internal +stderr 'some packages could not be built to support internal linking.*m/c|requires external linking|does not support internal cgo' + +-- go.mod -- +module m + +-- a/a.go -- +package a + +// #cgo LDFLAGS: -L. -lb +// extern int CFn(int); +import "C" + +func GoFn(v int) int { return int(C.CFn(C.int(v))) } + +-- b/b.c -- +extern int LibFn(int); +int CFn(int i) { return LibFn(i); } + +-- b/lib.c -- +int LibFn(int i) { return i; } + +-- c/c.go -- +package c + +// static int D(int i) { return i; } +import "C" + +import "m/a" + +func Fn(i int) (int, int) { + return a.GoFn(i), int(C.D(C.int(i))) +} + +-- main.go -- +package main + +import "m/c" + +func main() { + println(c.Fn(0)) +} diff --git a/src/cmd/go/testdata/script/chdir.txt b/src/cmd/go/testdata/script/chdir.txt new file mode 100644 index 0000000..a6feed6 --- /dev/null +++ b/src/cmd/go/testdata/script/chdir.txt @@ -0,0 +1,35 @@ +env OLD=$PWD + +# basic -C functionality +cd $GOROOT/src/math +go list -C ../strings +stdout strings +! go list -C ../nonexist +stderr 'chdir.*nonexist' + +# check for -C in subcommands with custom flag parsing +# cmd/go/chdir_test.go handles the normal ones more directly. + +# go doc +go doc -C ../strings HasPrefix + +# go env +go env -C $OLD/custom GOMOD +stdout 'custom[\\/]go.mod' +! go env -C ../nonexist +stderr '^go: chdir ../nonexist: ' + +# go test +go test -C ../strings -n +stderr 'strings\.test' + +# go vet +go vet -C ../strings -n +stderr strings_test + +# -C must be first on command line (as of Go 1.21) +! go test -n -C ../strings +stderr '^invalid value "../strings" for flag -C: -C flag must be first flag on command line$' + +-- custom/go.mod -- +module m diff --git a/src/cmd/go/testdata/script/check_goexperiment.txt b/src/cmd/go/testdata/script/check_goexperiment.txt new file mode 100644 index 0000000..3434cb9 --- /dev/null +++ b/src/cmd/go/testdata/script/check_goexperiment.txt @@ -0,0 +1,10 @@ +# Test that [GOEXPERIMENT:x] is accepted. +# Here fieldtrack is picked arbitrarily. + +[GOEXPERIMENT:nofieldtrack] env + +[GOEXPERIMENT:fieldtrack] env + +#[GOEXPERIMENT:crashme] env + + diff --git a/src/cmd/go/testdata/script/clean_binary.txt b/src/cmd/go/testdata/script/clean_binary.txt new file mode 100644 index 0000000..7335f8a --- /dev/null +++ b/src/cmd/go/testdata/script/clean_binary.txt @@ -0,0 +1,78 @@ +# Build something to create the executable, including several cases +[short] skip + +# --------------------- clean executables ------------------------- + +# case1: test file-named executable 'main' +env GO111MODULE=on + +! exists main$GOEXE +go build main.go +exists -exec main$GOEXE +go clean +! exists main$GOEXE + +# case2: test module-named executable 'a.b.c' +! exists a.b.c$GOEXE +go build +exists -exec a.b.c$GOEXE +go clean +! exists a.b.c$GOEXE + +# case3: directory-named executable 'src' +env GO111MODULE=off + +! exists src$GOEXE +go build +exists -exec src$GOEXE +go clean +! exists src$GOEXE + +# --------------------- clean test files ------------------------- + +# case1: test file-named test file +env GO111MODULE=on + +! exists main.test$GOEXE +go test -c main_test.go +exists -exec main.test$GOEXE +go clean +! exists main.test$GOEXE + +# case2: test module-named test file +! exists a.b.c.test$GOEXE +go test -c +exists -exec a.b.c.test$GOEXE +go clean +! exists a.b.c.test$GOEXE + +# case3: test directory-based test file +env GO111MODULE=off + +! exists src.test$GOEXE +go test -c +exists -exec src.test$GOEXE +go clean +! exists src.test$GOEXE + +-- main.go -- +package main + +import "fmt" + +func main() { + fmt.Println("hello!") +} + +-- main_test.go -- +package main + +import "testing" + +func TestSomething(t *testing.T) { +} + +-- go.mod -- +module example.com/a.b.c/v2 + +go 1.12
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/clean_cache_n.txt b/src/cmd/go/testdata/script/clean_cache_n.txt new file mode 100644 index 0000000..72f9abf --- /dev/null +++ b/src/cmd/go/testdata/script/clean_cache_n.txt @@ -0,0 +1,28 @@ +# We're testing cache behavior, so start with a clean GOCACHE. +env GOCACHE=$WORK/cache + +# Build something so that the cache gets populates +go build main.go + +# Check that cache contains directories before running +exists $GOCACHE/00 + +# Run go clean -cache -n and ensure that directories weren't deleted +go clean -cache -n +exists $GOCACHE/00 + +# Re-run go clean cache without the -n flag go ensure that directories were properly removed +go clean -cache +! exists $GOCACHE/00 + +! go clean -cache . +stderr 'go: clean -cache cannot be used with package arguments' + +-- main.go -- +package main + +import "fmt" + +func main() { + fmt.Println("hello!") +} diff --git a/src/cmd/go/testdata/script/clean_testcache.txt b/src/cmd/go/testdata/script/clean_testcache.txt new file mode 100644 index 0000000..3f98602 --- /dev/null +++ b/src/cmd/go/testdata/script/clean_testcache.txt @@ -0,0 +1,28 @@ +env GO111MODULE=off +[short] skip + +# go clean -testcache +# should work (see golang.org/issue/29757). +cd x +go test x_test.go +go clean -testcache +go test x_test.go +! stdout 'cached' +! go clean -testcache ../x +stderr 'go: clean -testcache cannot be used with package arguments' + +# golang.org/issue/29100: 'go clean -testcache' should succeed +# if the cache directory doesn't exist at all. +# It should not write a testexpire.txt file, since there are no +# test results that need to be invalidated in the first place. +env GOCACHE=$WORK/nonexistent +go clean -testcache +! exists $WORK/nonexistent + +-- x/x_test.go -- +package x_test +import ( + "testing" +) +func TestMain(t *testing.T) { +} diff --git a/src/cmd/go/testdata/script/cmd_import_error.txt b/src/cmd/go/testdata/script/cmd_import_error.txt new file mode 100644 index 0000000..89e1dbb --- /dev/null +++ b/src/cmd/go/testdata/script/cmd_import_error.txt @@ -0,0 +1,16 @@ +env GO111MODULE=on + +# Regression test for golang.org/issue/31031: +# Importing or loading a non-existent package in cmd/ should print +# a clear error in module mode. + +! go list cmd/unknown +stderr '^package cmd/unknown is not in std \('$GOROOT'[/\\]src[/\\]cmd[/\\]unknown\)$' + +go list -f '{{range .DepsErrors}}{{.Err}}{{end}}' x.go +stdout '^package cmd/unknown is not in std \('$GOROOT'[/\\]src[/\\]cmd[/\\]unknown\)$' + +-- x.go -- +package x + +import _ "cmd/unknown" diff --git a/src/cmd/go/testdata/script/cover_asm.txt b/src/cmd/go/testdata/script/cover_asm.txt new file mode 100644 index 0000000..c7b7114 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_asm.txt @@ -0,0 +1,33 @@ +[short] skip +[compiler:gccgo] skip # gccgo has no cover tool + +# Test cover for a package that has an assembly function. + +go test -outputdir=$WORK -coverprofile=cover.out coverasm +go tool cover -func=$WORK/cover.out +stdout '\tg\t*100.0%' # Check g is 100% covered. +! stdout '\tf\t*[0-9]' # Check for no coverage on the assembly function + +-- go.mod -- +module coverasm + +go 1.16 +-- p.go -- +package p + +func f() + +func g() { + println("g") +} +-- p.s -- +// empty asm file, +// so go test doesn't complain about declaration of f in p.go. +-- p_test.go -- +package p + +import "testing" + +func Test(t *testing.T) { + g() +} diff --git a/src/cmd/go/testdata/script/cover_atomic_pkgall.txt b/src/cmd/go/testdata/script/cover_atomic_pkgall.txt new file mode 100644 index 0000000..c3bc67d --- /dev/null +++ b/src/cmd/go/testdata/script/cover_atomic_pkgall.txt @@ -0,0 +1,25 @@ +env GO111MODULE=off + +[short] skip + +go test -coverpkg=all -covermode=atomic x +stdout ok[\s\S]+?coverage + +[!race] stop + +go test -coverpkg=all -race x +stdout ok[\s\S]+?coverage + +-- x/x.go -- +package x + +import _ "sync/atomic" + +func F() {} + +-- x/x_test.go -- +package x + +import "testing" + +func TestF(t *testing.T) { F() } diff --git a/src/cmd/go/testdata/script/cover_blank_func_decl.txt b/src/cmd/go/testdata/script/cover_blank_func_decl.txt new file mode 100644 index 0000000..e7d5250 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_blank_func_decl.txt @@ -0,0 +1,35 @@ +[short] skip +go test -cover coverblank +stdout 'coverage: 100.0% of statements' + + +-- go.mod -- +module coverblank + +go 1.16 +-- a.go -- +package coverblank + +func _() { + println("unreachable") +} + +type X int + +func (x X) Print() { + println(x) +} + +func (x X) _() { + println("unreachable") +} + +-- a_test.go -- +package coverblank + +import "testing" + +func TestX(t *testing.T) { + var x X + x.Print() +} diff --git a/src/cmd/go/testdata/script/cover_build_cmdline_pkgs.txt b/src/cmd/go/testdata/script/cover_build_cmdline_pkgs.txt new file mode 100644 index 0000000..e14a078 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_build_cmdline_pkgs.txt @@ -0,0 +1,73 @@ + +# This test is intended to verify that when a user does "go run -cover ..." +# or "go build -cover ...", packages named on the command line are +# always instrumented (but not their dependencies). This rule applies +# inside and outside the standard library. + +[short] skip +[!GOEXPERIMENT:coverageredesign] skip + +# Compile an object. +go tool compile -p tiny tiny/tiny.go tiny/tiny2.go + +# Build a stdlib command with coverage. +go build -o $WORK/nm.exe -cover cmd/nm + +# Save off old GOCOVERDIR setting +env SAVEGOCOVERDIR=$GOCOVERDIR + +# Collect a coverage profile from running 'cmd/nm' on the object. +mkdir $WORK/covdata +env GOCOVERDIR=$WORK/covdata +exec $WORK/nm.exe tiny.o + +# Restore previous GOCOVERDIR setting +env GOCOVERDIR=$SAVEGOCOVERDIR + +# Check to make sure we instrumented just the main package, not +# any dependencies. +go tool covdata pkglist -i=$WORK/covdata +stdout cmd/nm +! stdout cmd/internal/goobj pkglist.txt + +# ... now collect a coverage profile from a Go file +# listed on the command line. +go build -cover -o $WORK/another.exe testdata/another.go +mkdir $WORK/covdata2 +env GOCOVERDIR=$WORK/covdata2 +exec $WORK/another.exe + +# Restore previous GOCOVERDIR setting +env GOCOVERDIR=$SAVEGOCOVERDIR + +# Check to make sure we instrumented just the main package. +go tool covdata pkglist -i=$WORK/covdata2 +stdout command-line-arguments +! stdout fmt + +-- go.mod -- + +module example.prog + +-- testdata/another.go -- + +package main + +import "fmt" + +func main() { + fmt.Println("Hi dad") +} + +-- tiny/tiny.go -- + +package tiny + +var Tvar int + +-- tiny/tiny2.go -- + +package tiny + +var Tvar2 bool + diff --git a/src/cmd/go/testdata/script/cover_build_pkg_select.txt b/src/cmd/go/testdata/script/cover_build_pkg_select.txt new file mode 100644 index 0000000..447ca77 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_build_pkg_select.txt @@ -0,0 +1,114 @@ +# This test checks more of the "go build -cover" functionality, +# specifically which packages get selected when building. + +[short] skip + +# Skip if new coverage is not enabled. +[!GOEXPERIMENT:coverageredesign] skip + +#------------------------------------------- + +# Build for coverage. +go build -mod=mod -o $WORK/modex.exe -cover mod.example/main + +# Save off old GOCOVERDIR setting +env SAVEGOCOVERDIR=$GOCOVERDIR + +# Execute. +mkdir $WORK/covdata +env GOCOVERDIR=$WORK/covdata +exec $WORK/modex.exe + +# Restore previous GOCOVERDIR setting +env GOCOVERDIR=$SAVEGOCOVERDIR + +# Examine the result. +go tool covdata percent -i=$WORK/covdata +stdout 'coverage: 100.0% of statements' + +# By default we want to see packages resident in the module covered, +# but not dependencies. +go tool covdata textfmt -i=$WORK/covdata -o=$WORK/covdata/out.txt +grep 'mode: set' $WORK/covdata/out.txt +grep 'mod.example/main/main.go:' $WORK/covdata/out.txt +grep 'mod.example/sub/sub.go:' $WORK/covdata/out.txt +! grep 'rsc.io' $WORK/covdata/out.txt + +rm $WORK/covdata +rm $WORK/modex.exe + +#------------------------------------------- + +# Repeat the build but with -coverpkg=all + +go build -mod=mod -coverpkg=all -o $WORK/modex.exe -cover mod.example/main + +# Execute. +mkdir $WORK/covdata +env GOCOVERDIR=$WORK/covdata +exec $WORK/modex.exe + +# Restore previous GOCOVERDIR setting +env GOCOVERDIR=$SAVEGOCOVERDIR + +# Examine the result. +go tool covdata percent -i=$WORK/covdata +stdout 'coverage:.*[1-9][0-9.]+%' + +# The whole enchilada. +go tool covdata textfmt -i=$WORK/covdata -o=$WORK/covdata/out.txt +grep 'mode: set' $WORK/covdata/out.txt +grep 'mod.example/main/main.go:' $WORK/covdata/out.txt +grep 'mod.example/sub/sub.go:' $WORK/covdata/out.txt +grep 'rsc.io' $WORK/covdata/out.txt +grep 'bufio/bufio.go:' $WORK/covdata/out.txt + +# Use the covdata tool to select a specific set of module paths +mkdir $WORK/covdata2 +go tool covdata merge -pkg=rsc.io/quote -i=$WORK/covdata -o=$WORK/covdata2 + +# Examine the result. +go tool covdata percent -i=$WORK/covdata2 +stdout 'coverage:.*[1-9][0-9.]+%' + +# Check for expected packages + check that we don't see things from stdlib. +go tool covdata textfmt -i=$WORK/covdata2 -o=$WORK/covdata2/out.txt +grep 'mode: set' $WORK/covdata2/out.txt +! grep 'mod.example/main/main.go:' $WORK/covdata2/out.txt +! grep 'mod.example/sub/sub.go:' $WORK/covdata2/out.txt +grep 'rsc.io' $WORK/covdata2/out.txt +! grep 'bufio/bufio.go:' $WORK/covdata2/out.txt + +#------------------------------------------- +# end of test cmds, start of harness and related files. + +-- go.mod -- +module mod.example + +go 1.20 + +require rsc.io/quote/v3 v3.0.0 + +-- main/main.go -- +package main + +import ( + "fmt" + "mod.example/sub" + + "rsc.io/quote" +) + +func main() { + fmt.Println(quote.Go(), sub.F()) +} + +-- sub/sub.go -- + +package sub + +func F() int { + return 42 +} + + diff --git a/src/cmd/go/testdata/script/cover_build_simple.txt b/src/cmd/go/testdata/script/cover_build_simple.txt new file mode 100644 index 0000000..b61e631 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_build_simple.txt @@ -0,0 +1,149 @@ +# This test checks basic "go build -cover" functionality. + +[short] skip + +# Hard-wire new coverage for this test. +env GOEXPERIMENT=coverageredesign + +# Build for coverage. +go build -gcflags=-m -o example.exe -cover example/main & +[race] go build -o examplewithrace.exe -race -cover example/main & +wait + +# First execute without GOCOVERDIR set... +env GOCOVERDIR= +exec ./example.exe normal +stderr '^warning: GOCOVERDIR not set, no coverage data emitted' + +# ... then with GOCOVERDIR set. +env GOCOVERDIR=data/normal +exec ./example.exe normal +! stderr '^warning: GOCOVERDIR not set, no coverage data emitted' +go tool covdata percent -i=data/normal +stdout 'coverage:.*[1-9][0-9.]+%' + +# Program makes a direct call to os.Exit(0). +env GOCOVERDIR=data/goodexit +exec ./example.exe goodexit +! stderr '^warning: GOCOVERDIR not set, no coverage data emitted' +go tool covdata percent -i=data/goodexit +stdout 'coverage:.*[1-9][0-9.]+%' + +# Program makes a direct call to os.Exit(1). +env GOCOVERDIR=data/badexit +! exec ./example.exe badexit +! stderr '^warning: GOCOVERDIR not set, no coverage data emitted' +go tool covdata percent -i=data/badexit +stdout 'coverage:.*[1-9][0-9.]+%' + +# Program invokes panic. +env GOCOVERDIR=data/panic +! exec ./example.exe panic +! stderr '^warning: GOCOVERDIR not set, no coverage data emitted' +go tool covdata percent -i=data/panic +stdout 'coverage:.*[0-9.]+%' + +# Skip remainder if no race detector support. +[!race] skip + +env GOCOVERDIR=data2/normal +exec ./examplewithrace.exe normal +! stderr '^warning: GOCOVERDIR not set, no coverage data emitted' +go tool covdata percent -i=data2/normal +stdout 'coverage:.*[1-9][0-9.]+%' + +# Program makes a direct call to os.Exit(0). +env GOCOVERDIR=data2/goodexit +exec ./examplewithrace.exe goodexit +! stderr '^warning: GOCOVERDIR not set, no coverage data emitted' +go tool covdata percent -i=data2/goodexit +stdout 'coverage:.*[1-9][0-9.]+%' + +# Program makes a direct call to os.Exit(1). +env GOCOVERDIR=data2/badexit +! exec ./examplewithrace.exe badexit +! stderr '^warning: GOCOVERDIR not set, no coverage data emitted' +go tool covdata percent -i=data2/badexit +stdout 'coverage:.*[1-9][0-9.]+%' + +# Program invokes panic. +env GOCOVERDIR=data2/panic +! exec ./examplewithrace.exe panic +! stderr '^warning: GOCOVERDIR not set, no coverage data emitted' +go tool covdata percent -i=data2/panic +stdout 'coverage:.*[0-9.]+%' + +# end of test cmds, start of harness and related files. + +-- go.mod -- +module example + +go 1.18 + +-- main/example.go -- +package main + +import "example/sub" + +func main() { + sub.S() +} + +-- sub/sub.go -- + +package sub + +import "os" + +func S() { + switch os.Args[1] { + case "normal": + println("hi") + case "goodexit": + os.Exit(0) + case "badexit": + os.Exit(1) + case "panic": + panic("something bad happened") + } +} + +-- data/README.txt -- + +Just a location where we can write coverage profiles. + +-- data/normal/f.txt -- + +X + +-- data/goodexit/f.txt -- + +X + +-- data/badexit/f.txt -- + +X + +-- data/panic/f.txt -- + +X + +-- data2/README.txt -- + +Just a location where we can write coverage profiles. + +-- data2/normal/f.txt -- + +X + +-- data2/goodexit/f.txt -- + +X + +-- data2/badexit/f.txt -- + +X + +-- data2/panic/f.txt -- + +X diff --git a/src/cmd/go/testdata/script/cover_cgo.txt b/src/cmd/go/testdata/script/cover_cgo.txt new file mode 100644 index 0000000..85754b5 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_cgo.txt @@ -0,0 +1,42 @@ +[short] skip +[!cgo] skip +[compiler:gccgo] skip # gccgo has no cover tool + +# Test coverage on cgo code. + +go test -short -cover cgocover +stdout 'coverage:.*[1-9][0-9.]+%' +! stderr '[^0-9]0\.0%' + +-- go.mod -- +module cgocover + +go 1.16 +-- p.go -- +package p + +/* +void +f(void) +{ +} +*/ +import "C" + +var b bool + +func F() { + if b { + for { + } + } + C.f() +} +-- p_test.go -- +package p + +import "testing" + +func TestF(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/script/cover_cgo_extra_file.txt b/src/cmd/go/testdata/script/cover_cgo_extra_file.txt new file mode 100644 index 0000000..afc2178 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_cgo_extra_file.txt @@ -0,0 +1,48 @@ +[short] skip +[!cgo] skip +[compiler:gccgo] skip # gccgo has no cover tool + +# Test coverage on cgo code. This test case includes an +# extra empty non-cgo file in the package being checked. + +go test -short -cover cgocover4 +stdout 'coverage:.*[1-9][0-9.]+%' +! stderr '[^0-9]0\.0%' + +-- go.mod -- +module cgocover4 + +go 1.16 +-- notcgo.go -- +package p +-- p.go -- +package p + +/* +void +f(void) +{ +} +*/ +import "C" + +var b bool + +func F() { + if b { + for { + } + } + C.f() +} +-- x_test.go -- +package p_test + +import ( + . "cgocover4" + "testing" +) + +func TestF(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/script/cover_cgo_extra_test.txt b/src/cmd/go/testdata/script/cover_cgo_extra_test.txt new file mode 100644 index 0000000..ad09bab --- /dev/null +++ b/src/cmd/go/testdata/script/cover_cgo_extra_test.txt @@ -0,0 +1,49 @@ +[short] skip +[!cgo] skip +[compiler:gccgo] skip # gccgo has no cover tool + +# Test coverage on cgo code. This test case has an external +# test that tests the code and an in-package test file with +# no test cases. + +go test -short -cover cgocover3 +stdout 'coverage:.*[1-9][0-9.]+%' +! stderr '[^0-9]0\.0%' + +-- go.mod -- +module cgocover3 + +go 1.16 +-- p.go -- +package p + +/* +void +f(void) +{ +} +*/ +import "C" + +var b bool + +func F() { + if b { + for { + } + } + C.f() +} +-- p_test.go -- +package p +-- x_test.go -- +package p_test + +import ( + . "cgocover3" + "testing" +) + +func TestF(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/script/cover_cgo_xtest.txt b/src/cmd/go/testdata/script/cover_cgo_xtest.txt new file mode 100644 index 0000000..0900a48 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_cgo_xtest.txt @@ -0,0 +1,45 @@ +[short] skip +[!cgo] skip +[compiler:gccgo] skip # gccgo has no cover tool + +# Test cgo coverage with an external test. + +go test -short -cover cgocover2 +stdout 'coverage:.*[1-9][0-9.]+%' +! stderr '[^0-9]0\.0%' + +-- go.mod -- +module cgocover2 + +go 1.16 +-- p.go -- +package p + +/* +void +f(void) +{ +} +*/ +import "C" + +var b bool + +func F() { + if b { + for { + } + } + C.f() +} +-- x_test.go -- +package p_test + +import ( + . "cgocover2" + "testing" +) + +func TestF(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/script/cover_coverpkg_partial.txt b/src/cmd/go/testdata/script/cover_coverpkg_partial.txt new file mode 100644 index 0000000..5240241 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_coverpkg_partial.txt @@ -0,0 +1,141 @@ + +# Testcase related to #58770 and #24570. This is intended to ensure +# that coverage collection works in situations where we're testing a +# collection of packages and supplying a -coverpkg pattern that +# matches some but not all of the collection. In addition, some of the +# packages have Go code but no tests, and other packages have tests +# but no Go code. Package breakdown: +# +# Package Code? Tests? Stmts Imports +# a yes yes 2 f +# b yes yes 1 a, d +# c yes yes 3 --- +# d yes no 1 --- +# e no yes 0 a, b +# f yes no 3 --- +# + +[short] skip +[!GOEXPERIMENT:coverageredesign] skip + +# Test all packages with -coverpkg=./... +go test -coverprofile=cov.p -coverpkg=./... ./... +stdout '^ok\s+M/a\s+\S+\s+coverage: 50.0% of statements in ./...' +stdout '^ok\s+M/b\s+\S+\s+coverage: 60.0% of statements in ./...' +stdout '^ok\s+M/c\s+\S+\s+coverage: 30.0% of statements in ./...' +stdout '^\s*M/d\s+coverage: 0.0% of statements' +stdout '^\s*M/f\s+coverage: 0.0% of statements' + +# Test just the test-only package ./e but with -coverpkg=./... +# Total number of statements should be 7 (e.g. a/b/d/f but not c) +# and covered percent should be 6/7 (we hit everything in the +# coverpkg pattern except the func in "d"). +go test -coverprofile=bar.p -coverpkg=./... ./e +stdout '^ok\s+M/e\s+\S+\s+coverage: 85.7% of statements in ./...' + +# Test b and f with -coverpkg set to a/d/f. Total of 6 statements +# in a/d/f, again we hit everything except DFunc. +go test -coverprofile=baz.p -coverpkg=./a,./d,./f ./b ./f +stdout '^ok\s+M/b\s+\S+\s+coverage: 83.3% of statements in ./a, ./d, ./f' +stdout '^\s*M/f\s+coverage: 0.0% of statements' + +-- a/a.go -- +package a + +import "M/f" + +var G int + +func AFunc() int { + G = 1 + return f.Id() +} +-- a/a_test.go -- +package a + +import "testing" + +func TestA(t *testing.T) { + if AFunc() != 42 { + t.Fatalf("bad!") + } +} +-- b/b.go -- +package b + +import ( + "M/a" + "M/d" +) + +func BFunc() int { + return -d.FortyTwo + a.AFunc() +} +-- b/b_test.go -- +package b + +import "testing" + +func TestB(t *testing.T) { + if BFunc() == 1010101 { + t.Fatalf("bad!") + } +} +-- c/c.go -- +package c + +var G int + +func CFunc(x, y int) int { + G += x + G -= y + return x + y +} +-- c/c_test.go -- +package c + +import "testing" + +func TestC(t *testing.T) { + if CFunc(10, 10) == 1010101 { + t.Fatalf("bad!") + } +} +-- d/d.go -- +package d + +const FortyTwo = 42 + +func DFunc() int { + return FortyTwo +} + +-- e/e_test.go -- +package e + +import ( + "M/a" + "M/b" + "testing" +) + +func TestBlah(t *testing.T) { + if b.BFunc() == 1010101 { + t.Fatalf("bad") + } + a.AFunc() +} +-- f/f.go -- +package f + +var F int + +func Id() int { + F += 9 + F *= 2 + return 42 +} +-- go.mod -- +module M + +go 1.21 diff --git a/src/cmd/go/testdata/script/cover_coverpkg_with_init.txt b/src/cmd/go/testdata/script/cover_coverpkg_with_init.txt new file mode 100644 index 0000000..7a89102 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_coverpkg_with_init.txt @@ -0,0 +1,130 @@ + +# Testcase inspired by issue #58770, intended to verify that we're +# doing the right thing when running "go test -coverpkg=./... ./..." +# on a collection of packages where some have init functions and some +# do not, some have tests and some do not. + +[short] skip +[!GOEXPERIMENT:coverageredesign] skip + +# Verify correct statements percentages. We have a total of 10 +# statements in the packages matched by "./..."; package "a" (for +# example) has two statements so we expect 20.0% stmts covered. Go +# 1.19 would print 50% here (due to force importing of all ./... +# packages); prior to the fix for #58770 Go 1.20 would show 100% +# coverage. For packages "x" and "f" (which have no tests), check for +# 0% stmts covered (as opposed to "no test files"). + +go test -count=1 -coverprofile=cov.dat -coverpkg=./... ./... +stdout '^\s*\?\s+M/n\s+\[no test files\]' +stdout '^\s*M/x\s+coverage: 0.0% of statements' +stdout '^\s*M/f\s+coverage: 0.0% of statements' +stdout '^ok\s+M/a\s+\S+\s+coverage: 30.0% of statements in ./...' +stdout '^ok\s+M/b\s+\S+\s+coverage: 20.0% of statements in ./...' +stdout '^ok\s+M/main\s+\S+\s+coverage: 80.0% of statements in ./...' + +# Check for selected elements in the collected coverprofile as well. + +go tool cover -func=cov.dat +stdout '^M/x/x.go:3:\s+XFunc\s+0.0%' +stdout '^M/b/b.go:7:\s+BFunc\s+100.0%' +stdout '^total:\s+\(statements\)\s+80.0%' + +-- go.mod -- +module M + +go 1.21 +-- a/a.go -- +package a + +import "M/f" + +func init() { + println("package 'a' init: launch the missiles!") +} + +func AFunc() int { + return f.Id() +} +-- a/a_test.go -- +package a + +import "testing" + +func TestA(t *testing.T) { + if AFunc() != 42 { + t.Fatalf("bad!") + } +} +-- b/b.go -- +package b + +func init() { + println("package 'b' init: release the kraken") +} + +func BFunc() int { + return -42 +} +-- b/b_test.go -- +package b + +import "testing" + +func TestB(t *testing.T) { + if BFunc() != -42 { + t.Fatalf("bad!") + } +} +-- f/f.go -- +package f + +func Id() int { + return 42 +} +-- main/main.go -- +package main + +import ( + "M/a" + "M/b" +) + +func MFunc() string { + return "42" +} + +func M2Func() int { + return a.AFunc() + b.BFunc() +} + +func init() { + println("package 'main' init") +} + +func main() { + println(a.AFunc() + b.BFunc()) +} +-- main/main_test.go -- +package main + +import "testing" + +func TestMain(t *testing.T) { + if MFunc() != "42" { + t.Fatalf("bad!") + } + if M2Func() != 0 { + t.Fatalf("also bad!") + } +} +-- n/n.go -- +package n + +type N int +-- x/x.go -- +package x + +func XFunc() int { + return 2 * 2 +} diff --git a/src/cmd/go/testdata/script/cover_coverprofile_multipkg.txt b/src/cmd/go/testdata/script/cover_coverprofile_multipkg.txt new file mode 100644 index 0000000..543626f --- /dev/null +++ b/src/cmd/go/testdata/script/cover_coverprofile_multipkg.txt @@ -0,0 +1,193 @@ + +# Testcase for #63356. In this bug we're doing a "go test -coverprofile" +# run for a collection of packages, mostly independent (hence tests can +# be done in parallel) and in the original bug, temp coverage profile +# files were not being properly qualified and were colliding, resulting +# in a corrupted final profile. Actual content of the packages doesn't +# especially matter as long as we have a mix of packages with tests and +# multiple packages without tests. + +[short] skip + +# Kick off test. +go test -p=10 -vet=off -count=1 -coverprofile=cov.p ./... + +# Make sure resulting profile is digestible. +go tool cover -func=cov.p + +# No extraneous extra files please. +! exists _cover_.out + +-- a/a.go -- +package a + +func init() { + println("package 'a' init: launch the missiles!") +} + +func AFunc() int { + return 42 +} +-- a/a_test.go -- +package a + +import "testing" + +func TestA(t *testing.T) { + if AFunc() != 42 { + t.Fatalf("bad!") + } +} +-- aa/aa.go -- +package aa + +import "M/it" + +func AA(y int) int { + c := it.Conc{} + x := it.Callee(&c) + println(x, y) + return 0 +} +-- aa/aa_test.go -- +package aa + +import "testing" + +func TestMumble(t *testing.T) { + AA(3) +} +-- b/b.go -- +package b + +func init() { + println("package 'b' init: release the kraken") +} + +func BFunc() int { + return -42 +} +-- b/b_test.go -- +package b + +import "testing" + +func TestB(t *testing.T) { + if BFunc() != -42 { + t.Fatalf("bad!") + } +} +-- deadstuff/deadstuff.go -- +package deadstuff + +func downStreamOfPanic(x int) { + panic("bad") + if x < 10 { + println("foo") + } +} +-- deadstuff/deadstuff_test.go -- +package deadstuff + +import "testing" + +func TestMumble(t *testing.T) { + defer func() { + if x := recover(); x != nil { + println("recovered") + } + }() + downStreamOfPanic(10) +} +-- go.mod -- +module M + +go 1.21 +-- it/it.go -- +package it + +type Ctr interface { + Count() int +} + +type Conc struct { + X int +} + +func (c *Conc) Count() int { + return c.X +} + +func DoCall(c *Conc) { + c2 := Callee(c) + println(c2.Count()) +} + +func Callee(ii Ctr) Ctr { + q := ii.Count() + return &Conc{X: q} +} +-- main/main.go -- +package main + +import ( + "M/a" + "M/b" +) + +func MFunc() string { + return "42" +} + +func M2Func() int { + return a.AFunc() + b.BFunc() +} + +func init() { + println("package 'main' init") +} + +func main() { + println(a.AFunc() + b.BFunc()) +} +-- main/main_test.go -- +package main + +import "testing" + +func TestMain(t *testing.T) { + if MFunc() != "42" { + t.Fatalf("bad!") + } + if M2Func() != 0 { + t.Fatalf("also bad!") + } +} +-- n/n.go -- +package n + +type N int +-- onlytest/mumble_test.go -- +package onlytest + +import "testing" + +func TestFoo(t *testing.T) { + t.Logf("Whee\n") +} +-- x/x.go -- +package x + +func XFunc() int { + return 2 * 2 +} +-- xinternal/i.go -- +package i + +func I() int { return 32 } +-- xinternal/q/q.go -- +package q + +func Q() int { + return 42 +} diff --git a/src/cmd/go/testdata/script/cover_dash_c.txt b/src/cmd/go/testdata/script/cover_dash_c.txt new file mode 100644 index 0000000..f28c69e --- /dev/null +++ b/src/cmd/go/testdata/script/cover_dash_c.txt @@ -0,0 +1,31 @@ +[short] skip +[compiler:gccgo] skip + +# Test for issue 24588 + +go test -c -o $WORK/coverdep -coverprofile=$WORK/no/such/dir/cover.out coverdep +exists -exec $WORK/coverdep + +-- go.mod -- +module coverdep + +go 1.16 +-- p.go -- +package p + +import _ "coverdep/p1" + +func F() { +} +-- p1/p1.go -- +package p1 + +import _ "errors" +-- p_test.go -- +package p + +import "testing" + +func Test(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/script/cover_dep_loop.txt b/src/cmd/go/testdata/script/cover_dep_loop.txt new file mode 100644 index 0000000..46748e1 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_dep_loop.txt @@ -0,0 +1,36 @@ +[short] skip +[compiler:gccgo] skip + +# coverdep2/p1's xtest imports coverdep2/p2 which imports coverdep2/p1. +# Make sure that coverage on coverdep2/p2 recompiles coverdep2/p2. + +go test -short -cover coverdep2/p1 +stdout 'coverage: 100.0% of statements' # expect 100.0% coverage + +-- go.mod -- +module coverdep2 + +go 1.16 +-- p1/p.go -- +package p1 + +func F() int { return 1 } +-- p1/p_test.go -- +package p1_test + +import ( + "coverdep2/p2" + "testing" +) + +func Test(t *testing.T) { + p2.F() +} +-- p2/p2.go -- +package p2 + +import "coverdep2/p1" + +func F() { + p1.F() +} diff --git a/src/cmd/go/testdata/script/cover_dot_import.txt b/src/cmd/go/testdata/script/cover_dot_import.txt new file mode 100644 index 0000000..a336b1c --- /dev/null +++ b/src/cmd/go/testdata/script/cover_dot_import.txt @@ -0,0 +1,29 @@ +[short] skip +[compiler:gccgo] skip # gccgo has no cover tool + +go test -coverpkg=coverdot/a,coverdot/b coverdot/b +! stderr '[^0-9]0\.0%' +! stdout '[^0-9]0\.0%' + +-- go.mod -- +module coverdot + +go 1.16 +-- a/a.go -- +package a + +func F() {} +-- b/b.go -- +package b + +import . "coverdot/a" + +func G() { F() } +-- b/b_test.go -- +package b + +import "testing" + +func TestG(t *testing.T) { + G() +} diff --git a/src/cmd/go/testdata/script/cover_error.txt b/src/cmd/go/testdata/script/cover_error.txt new file mode 100644 index 0000000..fa4b58b --- /dev/null +++ b/src/cmd/go/testdata/script/cover_error.txt @@ -0,0 +1,45 @@ +[short] skip +[compiler:gccgo] skip + +# Test line numbers in cover errors. + +# Get errors from a go test into stderr.txt +! go test coverbad +stderr 'p\.go:4:2' # look for error at coverbad/p.go:4 +[cgo] stderr 'p1\.go:6:2' # look for error at coverbad/p.go:6 +! stderr $WORK # make sure temporary directory isn't in error + +cp stderr $WORK/stderr.txt + +# Get errors from coverage into stderr2.txt +! go test -cover coverbad +cp stderr $WORK/stderr2.txt + +wait # for go run above + +cmp $WORK/stderr.txt $WORK/stderr2.txt + +-- go.mod -- +module coverbad + +go 1.16 +-- p.go -- +package p + +func f() { + g() +} +-- p1.go -- +package p + +import "C" + +func h() { + j() +} +-- p_test.go -- +package p + +import "testing" + +func Test(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/cover_import_main_loop.txt b/src/cmd/go/testdata/script/cover_import_main_loop.txt new file mode 100644 index 0000000..36a09c2 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_import_main_loop.txt @@ -0,0 +1,26 @@ +[compiler:gccgo] skip # gccgo has no cover tool + +! go test -n importmain/test +stderr 'not an importable package' # check that import main was detected +! go test -n -cover importmain/test +stderr 'not an importable package' # check that import main was detected + +-- go.mod -- +module importmain + +go 1.16 +-- ismain/main.go -- +package main + +import _ "importmain/test" + +func main() {} +-- test/test.go -- +package test +-- test/test_test.go -- +package test_test + +import "testing" +import _ "importmain/ismain" + +func TestCase(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/cover_list.txt b/src/cmd/go/testdata/script/cover_list.txt new file mode 100644 index 0000000..6b8aaf4 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_list.txt @@ -0,0 +1,65 @@ + +# This test is intended to verify that "go list" accepts coverage related +# build arguments (such as -cover, -covermode). See issue #57785. + +[short] skip +[!GOEXPERIMENT:coverageredesign] skip + +env GOBIN=$WORK/bin + +# Install a target and then do an ordinary staleness check on it. +go install m/example +! stale m/example + +# Run a second staleness check with "-cover" as a build flag. The +# installed target should indeed be stale, since we didn't build it +# with -cover. +stale -cover m/example + +# Collect build ID from for m/example built with -cover. +go list -cover -export -f '{{.BuildID}}' m/example +cp stdout $WORK/listbuildid.txt + +# Now build the m/example binary with coverage. +go build -cover -o $WORK/m.exe m/example + +# Ask for the binary build ID by running "go tool buildid". +go tool buildid $WORK/m.exe +cp stdout $WORK/rawtoolbuildid.txt + +# Make sure that the two build IDs agree with respect to the +# m/example package. Build IDs from binaries are of the form X/Y/Z/W +# where Y/Z is the package build ID; running the program below will +# pick out the parts of the ID that we want. +env GOCOVERDIR=$WORK +exec $WORK/m.exe $WORK/rawtoolbuildid.txt +cp stdout $WORK/toolbuildid.txt + +# Build IDs should match here. +cmp $WORK/toolbuildid.txt $WORK/listbuildid.txt + +-- go.mod -- +module m + +go 1.20 +-- example/main.go -- +package main + +import ( + "fmt" + "os" + "strings" +) + +func main() { + println(os.Args[1]) + content, err := os.ReadFile(os.Args[1]) + if err != nil { + os.Exit(1) + } + fields := strings.Split(strings.TrimSpace(string(content)), "/") + if len(fields) != 4 { + os.Exit(2) + } + fmt.Println(fields[1] + "/" + fields[2]) +} diff --git a/src/cmd/go/testdata/script/cover_main_import_path.txt b/src/cmd/go/testdata/script/cover_main_import_path.txt new file mode 100644 index 0000000..e8696e2 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_main_import_path.txt @@ -0,0 +1,55 @@ + +# This test is intended to verify that coverage reporting is consistent +# between "go test -cover" and "go build -cover" with respect to how +# the "main" package is handled. See issue 57169 for details. + +[short] skip +[!GOEXPERIMENT:coverageredesign] skip + +# Build this program with -cover and run to collect a profile. + +go build -cover -o $WORK/prog.exe . + +# Save off old GOCOVERDIR setting +env SAVEGOCOVERDIR=$GOCOVERDIR + +mkdir $WORK/covdata +env GOCOVERDIR=$WORK/covdata +exec $WORK/prog.exe + +# Restore previous GOCOVERDIR setting +env GOCOVERDIR=$SAVEGOCOVERDIR + +# Report percent lines covered. +go tool covdata percent -i=$WORK/covdata +stdout '\s*mainwithtest\s+coverage:' +! stdout 'main\s+coverage:' + +# Go test -cover should behave the same way. +go test -cover . +stdout 'ok\s+mainwithtest\s+\S+\s+coverage:' +! stdout 'ok\s+main\s+.*' + + +-- go.mod -- +module mainwithtest + +go 1.20 +-- mymain.go -- +package main + +func main() { + println("hi mom") +} + +func Mainer() int { + return 42 +} +-- main_test.go -- +package main + +import "testing" + +func TestCoverage(t *testing.T) { + println(Mainer()) +} diff --git a/src/cmd/go/testdata/script/cover_mod_empty.txt b/src/cmd/go/testdata/script/cover_mod_empty.txt new file mode 100644 index 0000000..3c45243 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_mod_empty.txt @@ -0,0 +1,9 @@ +go tool cover -func=cover.out +stdout total.*statements.*0.0% + +go mod init golang.org/issue/33855 + +go tool cover -func=cover.out +stdout total.*statements.*0.0% + +-- cover.out -- diff --git a/src/cmd/go/testdata/script/cover_modes.txt b/src/cmd/go/testdata/script/cover_modes.txt new file mode 100644 index 0000000..a27296e --- /dev/null +++ b/src/cmd/go/testdata/script/cover_modes.txt @@ -0,0 +1,25 @@ +env GO111MODULE=off + +# Coverage analysis should use 'set' mode by default, +# and should merge coverage profiles correctly. + +[short] skip +[compiler:gccgo] skip # gccgo has no cover tool + +go test -short -cover encoding/binary errors -coverprofile=$WORK/cover.out +! stderr '[^0-9]0\.0%' +! stdout '[^0-9]0\.0%' + +grep -count=1 '^mode: set$' $WORK/cover.out +grep 'errors\.go' $WORK/cover.out +grep 'binary\.go' $WORK/cover.out + +[!race] stop + +go test -short -race -cover encoding/binary errors -coverprofile=$WORK/cover.out +! stderr '[^0-9]0\.0%' +! stdout '[^0-9]0\.0%' + +grep -count=1 '^mode: atomic$' $WORK/cover.out +grep 'errors\.go' $WORK/cover.out +grep 'binary\.go' $WORK/cover.out diff --git a/src/cmd/go/testdata/script/cover_pattern.txt b/src/cmd/go/testdata/script/cover_pattern.txt new file mode 100644 index 0000000..6c79c10 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_pattern.txt @@ -0,0 +1,41 @@ +[compiler:gccgo] skip + +# If coverpkg=m/sleepy... expands by package loading +# (as opposed to pattern matching on deps) +# then it will try to load sleepybad, which does not compile, +# and the test command will fail. +! go list m/sleepy... +go test -c -n -coverprofile=$TMPDIR/cover.out -coverpkg=m/sleepy... -run=^$ m/sleepy1 + +-- go.mod -- +module m + +go 1.16 +-- sleepy1/p_test.go -- +package p + +import ( + "testing" + "time" +) + +func Test1(t *testing.T) { + time.Sleep(200 * time.Millisecond) +} +-- sleepy2/p_test.go -- +package p + +import ( + "testing" + "time" +) + +func Test1(t *testing.T) { + time.Sleep(200 * time.Millisecond) +} +-- sleepybad/p.go -- +package p + +import ^ + +var _ = io.DoesNotExist diff --git a/src/cmd/go/testdata/script/cover_pkgall_imports.txt b/src/cmd/go/testdata/script/cover_pkgall_imports.txt new file mode 100644 index 0000000..4e51726 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_pkgall_imports.txt @@ -0,0 +1,48 @@ +# This test checks that -coverpkg=all can be used +# when the package pattern includes packages +# which only have tests. +# Verifies golang.org/issue/27333, golang.org/issue/43242. + +[short] skip +cd $GOPATH/src/example.com/cov + +env GO111MODULE=on +go test -coverpkg=all ./... + +env GO111MODULE=off +go test -coverpkg=all ./... + +-- $GOPATH/src/example.com/cov/go.mod -- +module example.com/cov + +-- $GOPATH/src/example.com/cov/notest/notest.go -- +package notest + +func Foo() {} + +-- $GOPATH/src/example.com/cov/onlytest/onlytest_test.go -- +package onlytest_test + +import ( + "testing" + + "example.com/cov/notest" +) + +func TestFoo(t *testing.T) { + notest.Foo() +} + +-- $GOPATH/src/example.com/cov/withtest/withtest.go -- +package withtest + +func Bar() {} + +-- $GOPATH/src/example.com/cov/withtest/withtest_test.go -- +package withtest + +import "testing" + +func TestBar(t *testing.T) { + Bar() +} diff --git a/src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt b/src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt new file mode 100644 index 0000000..f21cd8b --- /dev/null +++ b/src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt @@ -0,0 +1,46 @@ +# This test checks that multiple main packages can be tested +# with -coverpkg=all without duplicate symbol errors. +# Verifies golang.org/issue/30374, golang.org/issue/34114. + +[short] skip +cd $GOPATH/src/example.com/cov + +env GO111MODULE=on +go test -coverpkg=all ./... + +env GO111MODULE=off +go test -coverpkg=all ./... + +-- $GOPATH/src/example.com/cov/go.mod -- +module example.com/cov + +-- $GOPATH/src/example.com/cov/mainonly/mainonly.go -- +package main + +func main() {} + +-- $GOPATH/src/example.com/cov/mainwithtest/mainwithtest.go -- +package main + +func main() {} + +func Foo() {} + +-- $GOPATH/src/example.com/cov/mainwithtest/mainwithtest_test.go -- +package main + +import "testing" + +func TestFoo(t *testing.T) { + Foo() +} + +-- $GOPATH/src/example.com/cov/xtest/x.go -- +package x + +-- $GOPATH/src/example.com/cov/xtest/x_test.go -- +package x_test + +import "testing" + +func TestX(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/cover_pkgall_runtime.txt b/src/cmd/go/testdata/script/cover_pkgall_runtime.txt new file mode 100644 index 0000000..9927c30 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_pkgall_runtime.txt @@ -0,0 +1,23 @@ +env GO111MODULE=off + +# Issue 23882 + +[short] skip + +go test -coverpkg=all x +stdout ok[\s\S]+?coverage + +[!race] stop + +go test -coverpkg=all -race x +stdout ok[\s\S]+?coverage + +-- x/x.go -- +package x +import _ "runtime" +func F() {} + +-- x/x_test.go -- +package x +import "testing" +func TestF(t *testing.T) { F() } diff --git a/src/cmd/go/testdata/script/cover_runs.txt b/src/cmd/go/testdata/script/cover_runs.txt new file mode 100644 index 0000000..6df6096 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_runs.txt @@ -0,0 +1,13 @@ +[compiler:gccgo] skip 'gccgo has no cover tool' +[short] skip + +go test -short -coverpkg=strings strings regexp +! stdout '[^0-9]0\.0%' +stdout 'strings.*coverage:.*[1-9][0-9.]+%' +stdout 'regexp.*coverage:.*[1-9][0-9.]+%' + +go test -short -cover strings math regexp +! stdout '[^0-9]0\.0%' +stdout 'strings.*coverage:.*[1-9][0-9.]+%' +stdout 'math.*coverage:.*[1-9][0-9.]+%' +stdout 'regexp.*coverage:.*[1-9][0-9.]+%'
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/cover_statements.txt b/src/cmd/go/testdata/script/cover_statements.txt new file mode 100644 index 0000000..030177c --- /dev/null +++ b/src/cmd/go/testdata/script/cover_statements.txt @@ -0,0 +1,96 @@ +[short] skip + +# Workaround for issue 64014 -- for the portion of this test that +# verifies that caching works correctly, the cache should theoretically +# always behave reliably/deterministically, however if other tests are +# concurrently accessing the cache while this test is running, it can +# lead to cache lookup failures, which manifest as test failures here. +# To avoid such flakes, use a separate isolated GOCACHE for this test. +env GOCACHE=$WORK/cache + +# Initial run with simple coverage. +go test -cover ./pkg1 ./pkg2 ./pkg3 ./pkg4 +[!GOEXPERIMENT:coverageredesign] stdout 'pkg1 \[no test files\]' +[GOEXPERIMENT:coverageredesign] stdout 'pkg1 coverage: 0.0% of statements' +stdout 'pkg2 \S+ coverage: 0.0% of statements \[no tests to run\]' +stdout 'pkg3 \S+ coverage: 100.0% of statements' +stdout 'pkg4 \S+ coverage: \[no statements\]' + +# Second run to make sure that caching works properly. +go test -x -cover ./pkg1 ./pkg2 ./pkg3 ./pkg4 +[!GOEXPERIMENT:coverageredesign] stdout 'pkg1 \[no test files\]' +[GOEXPERIMENT:coverageredesign] stdout 'pkg1 coverage: 0.0% of statements' +stdout 'pkg2 \S+ coverage: 0.0% of statements \[no tests to run\]' +stdout 'pkg3 \S+ coverage: 100.0% of statements' +stdout 'pkg4 \S+ coverage: \[no statements\]' +[GOEXPERIMENT:coverageredesign] ! stderr 'link(\.exe"?)? -' +! stderr 'compile(\.exe"?)? -' +! stderr 'cover(\.exe"?)? -' +[GOEXPERIMENT:coverageredesign] stderr 'covdata(\.exe"?)? percent' + +# Now add in -coverprofile. +go test -cover -coverprofile=cov.dat ./pkg1 ./pkg2 ./pkg3 ./pkg4 +[!GOEXPERIMENT:coverageredesign] stdout 'pkg1 \[no test files\]' +[GOEXPERIMENT:coverageredesign] stdout 'pkg1 coverage: 0.0% of statements' +stdout 'pkg2 \S+ coverage: 0.0% of statements \[no tests to run\]' +stdout 'pkg3 \S+ coverage: 100.0% of statements' +stdout 'pkg4 \S+ coverage: \[no statements\]' + +# Validate +go tool cover -func=cov.dat +[GOEXPERIMENT:coverageredesign] stdout 'pkg1/a.go:5:\s+F\s+0.0%' + +-- go.mod -- +module m + +go 1.16 +-- pkg1/a.go -- +package pkg1 + +import "fmt" + +func F() { + fmt.Println("pkg1") +} +-- pkg2/a.go -- +package pkg2 + +import "fmt" + +func F() { + fmt.Println("pkg2") +} +-- pkg2/a_test.go -- +package pkg2 +-- pkg3/a.go -- +package pkg3 + +import "fmt" + +func F() { + fmt.Println("pkg3") +} +-- pkg3/a_test.go -- +package pkg3 + +import "testing" + +func TestF(t *testing.T) { + F() +} +-- pkg4/a.go -- +package pkg4 + +type T struct { + X bool +} +-- pkg4/a_test.go -- +package pkg4 + +import ( + "testing" +) + +func TestT(t *testing.T) { + _ = T{} +} diff --git a/src/cmd/go/testdata/script/cover_swig.txt b/src/cmd/go/testdata/script/cover_swig.txt new file mode 100644 index 0000000..decb29a --- /dev/null +++ b/src/cmd/go/testdata/script/cover_swig.txt @@ -0,0 +1,72 @@ + +# Testcase for issue 64661. This testcase is intended to verify that +# we don't try to send swig-generated Go files through the cover tool +# for "go test -cover" runs on packages that have *.swig source files. + +[!exec:swig] skip +[!cgo] skip + +go test -v -count=1 -coverprofile=foo.p +stdout 'coverage: 100.0% of statements' + +-- go.mod -- +module simple + +go 1.21 +-- main.c -- +/* A global variable */ +double Foo = 3.0; + +/* Compute the greatest common divisor of positive integers */ +int gcd(int x, int y) { + int g; + g = y; + while (x > 0) { + g = x; + x = y % x; + y = g; + } + return g; +} + + +-- main.go -- +package main + +import ( + "fmt" +) + +func main() { + // Call our gcd() function + x := 42 + y := 105 + g := Gcd(x, y) + fmt.Println("The gcd of", x, "and", y, "is", g) + + // Manipulate the Foo global variable + + // Output its current value + fmt.Println("Foo =", GetFoo()) + + // Change its value + SetFoo(3.1415926) + + // See if the change took effect + fmt.Println("Foo =", GetFoo()) +} +-- main.swig -- +%module main + +%inline %{ +extern int gcd(int x, int y); +extern double Foo; +%} +-- main_test.go -- +package main + +import "testing" + +func TestSwigFuncs(t *testing.T) { + main() +} diff --git a/src/cmd/go/testdata/script/cover_sync_atomic_import.txt b/src/cmd/go/testdata/script/cover_sync_atomic_import.txt new file mode 100644 index 0000000..283db3e --- /dev/null +++ b/src/cmd/go/testdata/script/cover_sync_atomic_import.txt @@ -0,0 +1,44 @@ +[short] skip +[compiler:gccgo] skip # gccgo has no cover tool +[!GOEXPERIMENT:coverageredesign] skip + +go test -short -cover -covermode=atomic -coverpkg=coverdep/p1 coverdep + +# In addition to the above, test to make sure there is no funny +# business if we try "go test -cover" in atomic mode targeting +# sync/atomic itself (see #57445). Just a short test run is needed +# since we're mainly interested in making sure the test builds and can +# execute at least one test. + +go test -short -covermode=atomic -run=TestStoreInt64 sync/atomic +go test -short -covermode=atomic -run=TestAnd8 runtime/internal/atomic + +# Skip remainder if no race detector support. +[!race] skip + +go test -short -cover -race -run=TestStoreInt64 sync/atomic +go test -short -cover -race -run=TestAnd8 runtime/internal/atomic + +-- go.mod -- +module coverdep + +go 1.16 +-- p.go -- +package p + +import _ "coverdep/p1" + +func F() { +} +-- p1/p1.go -- +package p1 + +import _ "errors" +-- p_test.go -- +package p + +import "testing" + +func Test(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/script/cover_test_localpkg_filepath.txt b/src/cmd/go/testdata/script/cover_test_localpkg_filepath.txt new file mode 100644 index 0000000..17c5808 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_test_localpkg_filepath.txt @@ -0,0 +1,40 @@ + +[short] skip + +# collect coverage profile in text format +go test -coverprofile=blah.prof prog.go prog_test.go + +# should not contain cmd-line pseudo-import-path +grep prog.go blah.prof +grep $PWD blah.prof +! grep command-line-arguments blah.prof + +-- prog.go -- +package main + +func Mumble(x int) int { + if x < 0 { + return -x + } + return 42 +} + +func Grumble(y int) int { + return -y +} + +func main() { +} + +-- prog_test.go -- +package main + +import ( + "testing" +) + +func TestMumble(t *testing.T) { + if x := Mumble(10); x != 42 { + t.Errorf("Mumble(%d): got %d want %d", 10, x, 42) + } +} diff --git a/src/cmd/go/testdata/script/cover_test_pkgselect.txt b/src/cmd/go/testdata/script/cover_test_pkgselect.txt new file mode 100644 index 0000000..97a1d2c --- /dev/null +++ b/src/cmd/go/testdata/script/cover_test_pkgselect.txt @@ -0,0 +1,80 @@ + +[short] skip + +# Hard-wire new coverage for this test. +env GOEXPERIMENT=coverageredesign + +# Baseline run. +go test -cover example/foo +stdout 'coverage: 50.0% of statements$' + +# Coverage percentage output should mention -coverpkg selection. +go test -coverpkg=example/foo example/foo +stdout 'coverage: 50.0% of statements in example/foo' + +# Try to ask for coverage of a package that doesn't exist. +go test -coverpkg nonexistent example/bar +stderr 'no packages being tested depend on matches for pattern nonexistent' +stdout 'coverage: \[no statements\]' + +# Ask for foo coverage, but test bar. +go test -coverpkg=example/foo example/bar +stdout 'coverage: 50.0% of statements in example/foo' + +# end of test cmds, start of harness and related files. + +-- go.mod -- +module example + +go 1.18 + +-- foo/foo.go -- +package foo + +func FooFunc() int { + return 42 +} +func FooFunc2() int { + return 42 +} + +-- foo/foo_test.go -- +package foo + +import "testing" + +func TestFoo(t *testing.T) { + if FooFunc() != 42 { + t.Fatalf("bad") + } +} + +-- bar/bar.go -- +package bar + +import "example/foo" + +func BarFunc() int { + return foo.FooFunc2() +} + +-- bar/bar_test.go -- +package bar_test + +import ( + "example/bar" + "testing" +) + +func TestBar(t *testing.T) { + if bar.BarFunc() != 42 { + t.Fatalf("bad") + } +} + +-- baz/baz.go -- +package baz + +func BazFunc() int { + return -42 +} diff --git a/src/cmd/go/testdata/script/cover_test_race_issue56370.txt b/src/cmd/go/testdata/script/cover_test_race_issue56370.txt new file mode 100644 index 0000000..2e55f10 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_test_race_issue56370.txt @@ -0,0 +1,54 @@ +[short] skip +[!race] skip + +go test -race -cover issue.56370/filter + +-- go.mod -- +module issue.56370 + +go 1.20 + +-- filter/filter.go -- + +package filter + +func New() func(error) bool { + return func(error) bool { + return false + } +} + +-- filter/filter_test.go -- + +package filter_test + +import ( + "testing" + + "issue.56370/filter" +) + +func Test1(t *testing.T) { + t.Parallel() + + _ = filter.New() +} + +func Test2(t *testing.T) { + t.Parallel() + + _ = filter.New() +} + +func Test3(t *testing.T) { + t.Parallel() + + _ = filter.New() +} + +func Test4(t *testing.T) { + t.Parallel() + + _ = filter.New() +} + diff --git a/src/cmd/go/testdata/script/cover_var_init_order.txt b/src/cmd/go/testdata/script/cover_var_init_order.txt new file mode 100644 index 0000000..37e07b7 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_var_init_order.txt @@ -0,0 +1,55 @@ +# This test verifies that issue 56293 has been fixed, and that the +# insertion of coverage instrumentation doesn't perturb package +# initialization order. + +[short] skip + +# Skip if new coverage is turned off. +[!GOEXPERIMENT:coverageredesign] skip + +go test -cover example + +-- go.mod -- +module example + +go 1.20 + +-- m.go -- + +package main + +import ( + "flag" +) + +var ( + fooFlag = flag.String("foo", "", "this should be ok") + foo = flag.Lookup("foo") + + barFlag = flag.String("bar", "", "this should be also ok, but is "+notOK()+".") + bar = flag.Lookup("bar") +) + +func notOK() string { + return "not OK" +} + +-- m_test.go -- + +package main + +import ( + "testing" +) + +func TestFoo(t *testing.T) { + if foo == nil { + t.Fatal() + } +} + +func TestBar(t *testing.T) { + if bar == nil { + t.Fatal() + } +} diff --git a/src/cmd/go/testdata/script/cpu_profile_twice.txt b/src/cmd/go/testdata/script/cpu_profile_twice.txt new file mode 100644 index 0000000..38d6439 --- /dev/null +++ b/src/cmd/go/testdata/script/cpu_profile_twice.txt @@ -0,0 +1,22 @@ +env GO111MODULE=off + +# Issue 23150 + +[short] skip + +go test -o=$WORK/x.test -cpuprofile=$WORK/cpu_profile_twice.out x +rm $WORK/cpu_profile_twice.out + +go test -o=$WORK/x.test -cpuprofile=$WORK/cpu_profile_twice.out x +exists $WORK/cpu_profile_twice.out + + +-- x/x_test.go -- +package x_test +import ( + "testing" + "time" +) +func TestSleep(t *testing.T) { + time.Sleep(10 * time.Millisecond) +} diff --git a/src/cmd/go/testdata/script/devnull.txt b/src/cmd/go/testdata/script/devnull.txt new file mode 100644 index 0000000..ccb866a --- /dev/null +++ b/src/cmd/go/testdata/script/devnull.txt @@ -0,0 +1,26 @@ +env GO111MODULE=off + +# Issue 28035: go test -c -o NUL should work. +# Issue 28549: go test -c -o /dev/null should not overwrite /dev/null when run as root. +cd x +cmp $devnull $WORK/empty.txt +go test -o=$devnull -c +! exists x.test$GOEXE +cmp $devnull $WORK/empty.txt + +# Issue 12407: go build -o /dev/null should succeed. +cd .. +go build -o $devnull y +cmp $devnull $WORK/empty.txt + +-- x/x_test.go -- +package x_test +import ( + "testing" +) +func TestNUL(t *testing.T) { +} +-- y/y.go -- +package y +func main() {} +-- $WORK/empty.txt -- diff --git a/src/cmd/go/testdata/script/dist_list_missing.txt b/src/cmd/go/testdata/script/dist_list_missing.txt new file mode 100644 index 0000000..affaa00 --- /dev/null +++ b/src/cmd/go/testdata/script/dist_list_missing.txt @@ -0,0 +1,57 @@ +# Regression test for #60939: when 'go tool dist' is missing, +# 'go tool dist list' should inject its output. + + +# Set GOROOT to a directory that definitely does not include +# a compiled 'dist' tool. 'go tool dist list' should still +# work, because 'cmd/go' itself can impersonate this command. + +mkdir $WORK/goroot/bin +mkdir $WORK/goroot/pkg/tool/${GOOS}_${GOARCH} +env GOROOT=$WORK/goroot + +! go tool -n dist +stderr 'go: no such tool "dist"' + +go tool dist list +stdout linux/amd64 +cp stdout tool.txt + +go tool dist list -v +stdout linux/amd64 +cp stdout tool-v.txt + +go tool dist list -broken +stdout $GOOS/$GOARCH +cp stdout tool-broken.txt + +go tool dist list -json +stdout '"GOOS": "linux",\n\s*"GOARCH": "amd64",\n' +cp stdout tool-json.txt + +go tool dist list -json -broken +stdout '"GOOS": "'$GOOS'",\n\s*"GOARCH": "'$GOARCH'",\n' +cp stdout tool-json-broken.txt + +[short] stop + + +# Check against the real cmd/dist as the source of truth. + +env GOROOT=$TESTGO_GOROOT +go build -o dist.exe cmd/dist + +exec ./dist.exe list +cmp stdout tool.txt + +exec ./dist.exe list -v +cmp stdout tool-v.txt + +exec ./dist.exe list -broken +cmp stdout tool-broken.txt + +exec ./dist.exe list -json +cmp stdout tool-json.txt + +exec ./dist.exe list -json -broken +cmp stdout tool-json-broken.txt diff --git a/src/cmd/go/testdata/script/doc.txt b/src/cmd/go/testdata/script/doc.txt new file mode 100644 index 0000000..3ff1aab --- /dev/null +++ b/src/cmd/go/testdata/script/doc.txt @@ -0,0 +1,75 @@ +# go doc --help +! go doc --help +stderr 'go doc' +stderr 'go doc <pkg>' +stderr 'go doc <sym>\[\.<methodOrField>\]' +stderr 'go doc \[<pkg>\.\]<sym>\[\.<methodOrField>\]' +stderr 'go doc \[<pkg>\.\]\[<sym>\.\]<methodOrField>' +stderr 'go doc <pkg> <sym>\[\.<methodOrField>\]' + +# go help doc +go help doc +stdout 'go doc' +stdout 'go doc <pkg>' +stdout 'go doc <sym>\[\.<methodOrField>\]' +stdout 'go doc \[<pkg>\.\]<sym>\[\.<methodOrField>\]' +stdout 'go doc \[<pkg>\.\]\[<sym>\.\]<methodOrField>' +stdout 'go doc <pkg> <sym>\[\.<methodOrField>\]' + +# go doc <pkg> +go doc p/v2 +stdout . + +# go doc <pkg> <sym> +go doc p/v2 Symbol +stdout . + +# go doc <pkg> <sym> <method> +! go doc p/v2 Symbol Method +stderr . + +# go doc <pkg>.<sym> +go doc p/v2.Symbol +stdout . + +# go doc <pkg>.<sym>.<method> +go doc p/v2.Symbol.Method +stdout . + +# go doc <sym> +go doc Symbol +stdout . + +# go doc <sym> <method> +! go doc Symbol Method +stderr . + +# go doc <sym>.<method> +go doc Symbol.Method +stdout . + +# go doc <pkg>.<method> +go doc p/v2.Method +stdout . + +# go doc <pkg> <method> +go doc p/v2 Method +stdout . + +# go doc <method> +go doc Method +stdout . + +-- go.mod -- +module p/v2 + +go 1.13 + +-- p.go -- +package p + +type Symbol struct{} + +func (Symbol) Method() error { + return nil +} diff --git a/src/cmd/go/testdata/script/embed.txt b/src/cmd/go/testdata/script/embed.txt new file mode 100644 index 0000000..5f7f6ed --- /dev/null +++ b/src/cmd/go/testdata/script/embed.txt @@ -0,0 +1,130 @@ +# go list shows patterns and files +go list -f '{{.EmbedPatterns}}' +stdout '\[x\*t\*t\]' +go list -f '{{.EmbedFiles}}' +stdout '\[x.txt\]' +go list -test -f '{{.TestEmbedPatterns}}' +stdout '\[y\*t\*t\]' +go list -test -f '{{.TestEmbedFiles}}' +stdout '\[y.txt\]' +go list -test -f '{{.XTestEmbedPatterns}}' +stdout '\[z\*t\*t\]' +go list -test -f '{{.XTestEmbedFiles}}' +stdout '\[z.txt\]' + +# build embeds x.txt +go build -x +stderr 'x.txt' + +# build uses cache correctly +go build -x +! stderr 'x.txt' +cp x.txt2 x.txt +go build -x +stderr 'x.txt' + +# build rejects invalid names +cp x.go2 x.go +go build -x +cp x.txt .git +! go build -x +stderr '^x.go:5:12: pattern [*]t: cannot embed file [.]git: invalid name [.]git$' +rm .git + +# build rejects symlinks +[symlink] symlink x.tzt -> x.txt +[symlink] ! go build -x +[symlink] stderr 'pattern [*]t: cannot embed irregular file x.tzt' +[symlink] rm x.tzt + +# build rejects empty directories +mkdir t +! go build -x +stderr '^x.go:5:12: pattern [*]t: cannot embed directory t: contains no embeddable files$' + +# build ignores symlinks and invalid names in directories +cp x.txt t/.git +! go build -x +stderr '^x.go:5:12: pattern [*]t: cannot embed directory t: contains no embeddable files$' +go list -e -f '{{.Incomplete}}' +stdout 'true' +[symlink] symlink t/x.link -> ../x.txt +[symlink] ! go build -x +[symlink] stderr '^x.go:5:12: pattern [*]t: cannot embed directory t: contains no embeddable files$' + +cp x.txt t/x.txt +go build -x + +# build reports errors with positions in imported packages +rm t/x.txt +! go build m/use +stderr '^x.go:5:12: pattern [*]t: cannot embed directory t: contains no embeddable files$' + +# all still ignores .git and symlinks +cp x.go3 x.go +! go build -x +stderr '^x.go:5:12: pattern all:t: cannot embed directory t: contains no embeddable files$' + +# all finds dot files and underscore files +cp x.txt t/.x.txt +go build -x +rm t/.x.txt +cp x.txt t/_x.txt +go build -x + +-- x.go -- +package p + +import "embed" + +//go:embed x*t*t +var X embed.FS + +-- x_test.go -- +package p + +import "embed" + +//go:embed y*t*t +var Y string + +-- x_x_test.go -- +package p_test + +import "embed" + +//go:embed z*t*t +var Z string + +-- x.go2 -- +package p + +import "embed" + +//go:embed *t +var X embed.FS + +-- x.go3 -- +package p + +import "embed" + +//go:embed all:t +var X embed.FS + +-- x.txt -- +hello + +-- y.txt -- +-- z.txt -- +-- x.txt2 -- +not hello + +-- use/use.go -- +package use + +import _ "m" +-- go.mod -- +module m + +go 1.16 diff --git a/src/cmd/go/testdata/script/embed_brackets.txt b/src/cmd/go/testdata/script/embed_brackets.txt new file mode 100644 index 0000000..ec17ff3 --- /dev/null +++ b/src/cmd/go/testdata/script/embed_brackets.txt @@ -0,0 +1,18 @@ +# issue 53314 +[GOOS:windows] skip +cd [pkg] +go build + +-- [pkg]/go.mod -- +module m + +go 1.19 +-- [pkg]/x.go -- +package p + +import _ "embed" + +//go:embed t.txt +var S string + +-- [pkg]//t.txt -- diff --git a/src/cmd/go/testdata/script/embed_fmt.txt b/src/cmd/go/testdata/script/embed_fmt.txt new file mode 100644 index 0000000..8a16afe --- /dev/null +++ b/src/cmd/go/testdata/script/embed_fmt.txt @@ -0,0 +1,22 @@ +# go fmt ignores file not found +go fmt xnofmt.go +cmp xnofmt.go xfmt.ref +! go build xnofmt.go +stderr 'xnofmt.go:5:12: pattern missing.txt: no matching files found' + +-- xnofmt.go -- +package p + +import "embed" + +//go:embed missing.txt +var X embed.FS +-- xfmt.ref -- +package p + +import "embed" + +//go:embed missing.txt +var X embed.FS +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/env_cache.txt b/src/cmd/go/testdata/script/env_cache.txt new file mode 100644 index 0000000..f2af7ee --- /dev/null +++ b/src/cmd/go/testdata/script/env_cache.txt @@ -0,0 +1,5 @@ +# go env should caches compiler results +go env +go env -x +! stdout '\|\| true' + diff --git a/src/cmd/go/testdata/script/env_cross_build.txt b/src/cmd/go/testdata/script/env_cross_build.txt new file mode 100644 index 0000000..91d1cb9 --- /dev/null +++ b/src/cmd/go/testdata/script/env_cross_build.txt @@ -0,0 +1,29 @@ +# Test that the correct default GOEXPERIMENT is used when cross +# building with GOENV (#46815). + +# Unset variables set by the TestScript harness. Users typically won't +# explicitly configure these, and #46815 doesn't repro if they are. +env GOOS= +env GOARCH= +env GOEXPERIMENT= + +env GOENV=windows-amd64 +go build internal/abi + +env GOENV=ios-arm64 +go build internal/abi + +env GOENV=linux-mips +go build internal/abi + +-- windows-amd64 -- +GOOS=windows +GOARCH=amd64 + +-- ios-arm64 -- +GOOS=ios +GOARCH=arm64 + +-- linux-mips -- +GOOS=linux +GOARCH=mips diff --git a/src/cmd/go/testdata/script/env_exp.txt b/src/cmd/go/testdata/script/env_exp.txt new file mode 100644 index 0000000..681512d --- /dev/null +++ b/src/cmd/go/testdata/script/env_exp.txt @@ -0,0 +1,17 @@ +# Test GOEXPERIMENT variable + +# go env shows default empty GOEXPERIMENT +go env +stdout GOEXPERIMENT= + +# go env shows valid experiments +env GOEXPERIMENT=fieldtrack,staticlockranking +go env GOEXPERIMENT +stdout '.*fieldtrack.*staticlockranking.*' +go env +stdout 'GOEXPERIMENT=.*fieldtrack.*staticlockranking.*' + +# go env rejects unknown experiments +env GOEXPERIMENT=bad +! go env GOEXPERIMENT +stderr 'unknown GOEXPERIMENT bad' diff --git a/src/cmd/go/testdata/script/env_issue46807.txt b/src/cmd/go/testdata/script/env_issue46807.txt new file mode 100644 index 0000000..e37bc63 --- /dev/null +++ b/src/cmd/go/testdata/script/env_issue46807.txt @@ -0,0 +1,12 @@ +! go mod tidy +stderr '^go: warning: ignoring go.mod in \$GOPATH' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''' + +go env +stdout 'GOPATH=' +stderr '^go: warning: ignoring go.mod in \$GOPATH' + +-- $GOPATH/go.mod -- +module bug + +go 1.21
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/env_sanitize.txt b/src/cmd/go/testdata/script/env_sanitize.txt new file mode 100644 index 0000000..cc4d23a --- /dev/null +++ b/src/cmd/go/testdata/script/env_sanitize.txt @@ -0,0 +1,5 @@ +env GOFLAGS='$(echo ''cc"''; echo ''OOPS="oops'')' +go env +[GOOS:darwin] stdout 'GOFLAGS=''\$\(echo ''\\''''cc"''\\''''; echo ''\\''''OOPS="oops''\\''''\)''' +[GOOS:linux] stdout 'GOFLAGS=''\$\(echo ''\\''''cc"''\\''''; echo ''\\''''OOPS="oops''\\''''\)''' +[GOOS:windows] stdout 'set GOFLAGS=\$\(echo ''cc"''; echo ''OOPS="oops''\)' diff --git a/src/cmd/go/testdata/script/env_unset.txt b/src/cmd/go/testdata/script/env_unset.txt new file mode 100644 index 0000000..22bc845 --- /dev/null +++ b/src/cmd/go/testdata/script/env_unset.txt @@ -0,0 +1,30 @@ +# Test that we can unset variables, even if initially invalid, +# as long as resulting config is valid. + +env GOENV=badenv +env GOOS= +env GOARCH= +env GOEXPERIMENT= + +! go env +stderr '^go(\.exe)?: unknown GOEXPERIMENT badexp$' + +go env -u GOEXPERIMENT + +! go env +stderr '^go: unsupported GOOS/GOARCH pair bados/badarch$' + +! go env -u GOOS +stderr '^go: unsupported GOOS/GOARCH pair \w+/badarch$' + +! go env -u GOARCH +stderr '^go: unsupported GOOS/GOARCH pair bados/\w+$' + +go env -u GOOS GOARCH + +go env + +-- badenv -- +GOOS=bados +GOARCH=badarch +GOEXPERIMENT=badexp diff --git a/src/cmd/go/testdata/script/env_write.txt b/src/cmd/go/testdata/script/env_write.txt new file mode 100644 index 0000000..5d40949 --- /dev/null +++ b/src/cmd/go/testdata/script/env_write.txt @@ -0,0 +1,206 @@ +env GO111MODULE=off + +# go env should default to the right places +env AppData=$HOME/windowsappdata +env home=$HOME/plan9home +go env GOENV +[GOOS:aix] stdout $HOME/.config/go/env +[GOOS:darwin] stdout $HOME'/Library/Application Support/go/env' +[GOOS:freebsd] stdout $HOME/.config/go/env +[GOOS:linux] stdout $HOME/.config/go/env +[GOOS:netbsd] stdout $HOME/.config/go/env +[GOOS:openbsd] stdout $HOME/.config/go/env +[GOOS:plan9] stdout $HOME/plan9home/lib/go/env +[GOOS:windows] stdout $HOME\\windowsappdata\\go\\env + +# Now override it to something writable. +env GOENV=$WORK/envdir/go/env +go env GOENV +stdout envdir[\\/]go[\\/]env + +# go env shows all variables +go env +stdout GOARCH= +stdout GOOS= +stdout GOROOT= + +# go env ignores invalid flag in GOFLAGS environment variable +env GOFLAGS='=true' +go env + +# checking errors +! go env -w +stderr 'go: no KEY=VALUE arguments given' +! go env -u +stderr 'go: ''go env -u'' requires an argument' + +# go env -w changes default setting +env root= +[GOOS:windows] env root=c: +env GOPATH= +go env -w GOPATH=$root/non-exist/gopath +! stderr .+ +grep GOPATH=$root/non-exist/gopath $WORK/envdir/go/env +go env GOPATH +stdout /non-exist/gopath + +# go env -w does not override OS environment, and warns about that +env GOPATH=$root/other +go env -w GOPATH=$root/non-exist/gopath2 +stderr 'warning: go env -w GOPATH=... does not override conflicting OS environment variable' +go env GOPATH +stdout $root/other + +# but go env -w does do the update, and unsetting the env var exposes the change +env GOPATH= +go env GOPATH +stdout $root/non-exist/gopath2 + +# unsetting with go env -u does not warn about OS environment overrides, +# nor does it warn about variables that haven't been set by go env -w. +env GOPATH=$root/other +go env -u GOPATH +! stderr .+ +go env -u GOPATH +! stderr .+ + +# go env -w rejects unknown or bad variables +! go env -w GODEBUG=gctrace=1 +stderr 'unknown go command variable GODEBUG' +! go env -w GOEXE=.bat +stderr 'GOEXE cannot be modified' +! go env -w GOVERSION=customversion +stderr 'GOVERSION cannot be modified' +! go env -w GOENV=/env +stderr 'GOENV can only be set using the OS environment' + +# go env -w can set multiple variables +env CC= +go env CC +! stdout ^xyc$ +go env -w GOOS=$GOOS CC=xyc +grep CC=xyc $GOENV +# file is maintained in sorted order +grep 'CC=xyc\nGOOS=' $GOENV +go env CC +stdout ^xyc$ + +# go env -u unsets effect of go env -w. +go env -u CC +go env CC +! stdout ^xyc$ + +# go env -w rejects double-set variables +! go env -w GOOS=$GOOS GOOS=$GOOS +stderr 'multiple values for key: GOOS' + +# go env -w rejects missing variables +! go env -w GOOS +stderr 'arguments must be KEY=VALUE: invalid argument: GOOS' + +# go env -w rejects invalid GO111MODULE values, as otherwise cmd/go would break +! go env -w GO111MODULE=badvalue +stderr 'invalid GO111MODULE value "badvalue"' + +# go env -w rejects invalid GOPATH values +! go env -w GOPATH=~/go +stderr 'GOPATH entry cannot start with shell metacharacter' + +! go env -w GOPATH=./go +stderr 'GOPATH entry is relative; must be absolute path' + +# go env -w rejects invalid GOTMPDIR values +! go env -w GOTMPDIR=x +stderr 'go: GOTMPDIR must be an absolute path' + +# go env -w should accept absolute GOTMPDIR value +# and should not create it +[GOOS:windows] go env -w GOTMPDIR=$WORK\x\y\z +[!GOOS:windows] go env -w GOTMPDIR=$WORK/x/y/z +! exists $WORK/x/y/z +# we should be able to clear an env +go env -u GOTMPDIR +go env GOTMPDIR +stdout ^$ + +[GOOS:windows] go env -w GOTMPDIR=$WORK\x\y\z +[!GOOS:windows] go env -w GOTMPDIR=$WORK/x/y/z +go env -w GOTMPDIR= +go env GOTMPDIR +stdout ^$ + +# go env -w rejects relative CC values +[!GOOS:windows] go env -w CC=/usr/bin/clang +go env -w CC=clang +[!GOOS:windows] ! go env -w CC=./clang +[!GOOS:windows] ! go env -w CC=bin/clang +[!GOOS:windows] stderr 'go: CC entry is relative; must be absolute path' + +[GOOS:windows] go env -w CC=$WORK\bin\clang +[GOOS:windows] ! go env -w CC=.\clang +[GOOS:windows] ! go env -w CC=bin\clang +[GOOS:windows] stderr 'go: CC entry is relative; must be absolute path' + +# go env -w rejects relative CXX values +[!GOOS:windows] go env -w CC=/usr/bin/cpp +go env -w CXX=cpp +[!GOOS:windows] ! go env -w CXX=./cpp +[!GOOS:windows] ! go env -w CXX=bin/cpp +[!GOOS:windows] stderr 'go: CXX entry is relative; must be absolute path' + +[GOOS:windows] go env -w CXX=$WORK\bin\cpp +[GOOS:windows] ! go env -w CXX=.\cpp +[GOOS:windows] ! go env -w CXX=bin\cpp +[GOOS:windows] stderr 'go: CXX entry is relative; must be absolute path' + +# go env -w/-u checks validity of GOOS/ARCH combinations +env GOOS= +env GOARCH= +# check -w doesn't allow invalid GOOS +! go env -w GOOS=linuxx +stderr 'unsupported GOOS/GOARCH pair linuxx' +# check -w doesn't allow invalid GOARCH +! go env -w GOARCH=amd644 +stderr 'unsupported GOOS/GOARCH.*/amd644$' +# check -w doesn't allow invalid GOOS with valid GOARCH +! go env -w GOOS=linuxx GOARCH=amd64 +stderr 'unsupported GOOS/GOARCH pair linuxx' +# check a valid GOOS and GOARCH values but an incompatible combinations +! go env -w GOOS=android GOARCH=s390x +stderr 'unsupported GOOS/GOARCH pair android/s390x' +# check that -u considers explicit envs +go env -w GOOS=linux GOARCH=mips +env GOOS=windows +! go env -u GOOS +stderr 'unsupported GOOS/GOARCH.*windows/mips$' +env GOOS= + +# go env -w should reject relative paths in GOMODCACHE environment. +! go env -w GOMODCACHE=~/test +stderr 'go: GOMODCACHE entry is relative; must be absolute path: "~/test"' +! go env -w GOMODCACHE=./test +stderr 'go: GOMODCACHE entry is relative; must be absolute path: "./test"' + +# go env -w checks validity of GOEXPERIMENT +env GOEXPERIMENT= +! go env -w GOEXPERIMENT=badexp +stderr 'unknown GOEXPERIMENT badexp' +go env -w GOEXPERIMENT=fieldtrack + +# go env -w and go env -u work on unknown fields already in the go/env file +cp bad.env $GOENV +go env GOENV +cat $GOENV +go env +! stdout UNKNOWN +go env UNKNOWN +stdout yes +go env -w UNKNOWN=maybe +go env UNKNOWN +stdout maybe +go env -u UNKNOWN +go env UNKNOWN +! stdout . # gone + +-- bad.env -- +UNKNOWN=yes diff --git a/src/cmd/go/testdata/script/fileline.txt b/src/cmd/go/testdata/script/fileline.txt new file mode 100644 index 0000000..5cb35f0 --- /dev/null +++ b/src/cmd/go/testdata/script/fileline.txt @@ -0,0 +1,8 @@ +env GO111MODULE=off + +# look for short, relative file:line in error message +! go run ../../gopath/x/y/z/err.go +stderr ^..[\\/]x[\\/]y[\\/]z[\\/]err.go: + +-- ../x/y/z/err.go -- +package main; import "bar" diff --git a/src/cmd/go/testdata/script/fmt_load_errors.txt b/src/cmd/go/testdata/script/fmt_load_errors.txt new file mode 100644 index 0000000..e3a9034 --- /dev/null +++ b/src/cmd/go/testdata/script/fmt_load_errors.txt @@ -0,0 +1,38 @@ +env GO111MODULE=off + +! go fmt does-not-exist + +go fmt -n exclude +stdout 'exclude[/\\]x\.go' +stdout 'exclude[/\\]x_linux\.go' + +# Test edge cases with gofmt. + +! exec $GOROOT/bin/gofmt does-not-exist + +exec $GOROOT/bin/gofmt gofmt-dir/no-extension +stdout 'package x' + +exec $GOROOT/bin/gofmt gofmt-dir +! stdout 'package x' + +! exec $GOROOT/bin/gofmt empty.go nopackage.go +stderr -count=1 'empty\.go:1:1: expected .package., found .EOF.' +stderr -count=1 'nopackage\.go:1:1: expected .package., found not' + +-- exclude/empty/x.txt -- +-- exclude/ignore/_x.go -- +package x +-- exclude/x.go -- +// +build linux,!linux + +package x +-- exclude/x_linux.go -- +// +build windows + +package x +-- gofmt-dir/no-extension -- +package x +-- empty.go -- +-- nopackage.go -- +not the proper start to a Go file diff --git a/src/cmd/go/testdata/script/fsys_walk.txt b/src/cmd/go/testdata/script/fsys_walk.txt new file mode 100644 index 0000000..9d1a945 --- /dev/null +++ b/src/cmd/go/testdata/script/fsys_walk.txt @@ -0,0 +1,6 @@ +# Test that go list prefix... does not read directories not beginning with prefix. +env GODEBUG=gofsystrace=1 +go list m... +stderr mime +stderr mime[\\/]multipart +! stderr archive diff --git a/src/cmd/go/testdata/script/gccgo_link_c.txt b/src/cmd/go/testdata/script/gccgo_link_c.txt new file mode 100644 index 0000000..d37cb66 --- /dev/null +++ b/src/cmd/go/testdata/script/gccgo_link_c.txt @@ -0,0 +1,20 @@ +# Issue #7573 +# cmd/cgo: undefined reference when linking a C-library using gccgo + +[!cgo] skip +[!exec:gccgo] skip +[cross] skip # gccgo can't necessarily cross-compile, so don't assume it will reach the step where we expect it to fail + +! go build -x -compiler gccgo +stderr 'gccgo.*\-L [^ ]*alibpath \-lalib' # make sure that Go-inline "#cgo LDFLAGS:" ("-L alibpath -lalib") passed to gccgo linking stage +! stderr 'gccgo.*-lalib.*-lalib' # make sure -lalib is only passed once + +-- go.mod -- +module m +-- cgoref.go -- +package main +// #cgo LDFLAGS: -L alibpath -lalib +// void f(void) {} +import "C" + +func main() { C.f() } diff --git a/src/cmd/go/testdata/script/gccgo_link_ldflags.txt b/src/cmd/go/testdata/script/gccgo_link_ldflags.txt new file mode 100644 index 0000000..80526c6 --- /dev/null +++ b/src/cmd/go/testdata/script/gccgo_link_ldflags.txt @@ -0,0 +1,23 @@ +# Test that #cgo LDFLAGS are properly quoted. +# The #cgo LDFLAGS below should pass a string with spaces to -L, +# as though searching a directory with a space in its name. +# It should not pass --nosuchoption to the external linker. + +[!cgo] skip + +go build + +[!exec:gccgo] skip + +# TODO: remove once gccgo on builder is updated +[GOOS:aix] [GOARCH:ppc64] skip + +go build -compiler gccgo + +-- go.mod -- +module m +-- cgo.go -- +package main +// #cgo LDFLAGS: -L "./ -Wl,--nosuchoption" +import "C" +func main() {} diff --git a/src/cmd/go/testdata/script/gccgo_m.txt b/src/cmd/go/testdata/script/gccgo_m.txt new file mode 100644 index 0000000..beb9c50 --- /dev/null +++ b/src/cmd/go/testdata/script/gccgo_m.txt @@ -0,0 +1,20 @@ +# It's absurd, but builds with -compiler=gccgo used to fail to build module m. +# golang.org/issue/34358 + +env GO111MODULE=off + +[short] skip +[cross] skip # gccgo can't necessarily cross-compile + +cd m +go build +exists m$GOEXE +rm m$GOEXE +[exec:gccgo] go build -compiler=gccgo +[exec:gccgo] exists m$GOEXE + +-- m/go.mod -- +module m +-- m/main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/gccgo_mangle.txt b/src/cmd/go/testdata/script/gccgo_mangle.txt new file mode 100644 index 0000000..7a09a80 --- /dev/null +++ b/src/cmd/go/testdata/script/gccgo_mangle.txt @@ -0,0 +1,15 @@ +# Issue 33871. + +cd m/a.0 +go build + +-- m/go.mod -- +module m +-- m/a.0/a.go -- +package a + +type T int + +func (t T) M() int { + return int(t) +} diff --git a/src/cmd/go/testdata/script/gcflags_patterns.txt b/src/cmd/go/testdata/script/gcflags_patterns.txt new file mode 100644 index 0000000..cc7b2fc --- /dev/null +++ b/src/cmd/go/testdata/script/gcflags_patterns.txt @@ -0,0 +1,93 @@ +env GO111MODULE=off + +[!compiler:gc] skip 'using -gcflags and -ldflags' +[short] skip + +# -gcflags=-e applies to named packages, not dependencies +go build -a -n -v -gcflags=-e z1 z2 +stderr 'compile.* -p z1.* -e ' +stderr 'compile.* -p z2.* -e ' +stderr 'compile.* -p y' +! stderr 'compile.* -p [^z].* -e ' + +# -gcflags can specify package=flags, and can be repeated; last match wins +go build -a -n -v -gcflags=-e -gcflags=z1=-N z1 z2 +stderr 'compile.* -p z1.* -N ' +! stderr 'compile.* -p z1.* -e ' +! stderr 'compile.* -p z2.* -N ' +stderr 'compile.* -p z2.* -e ' +stderr 'compile.* -p y' +! stderr 'compile.* -p [^z].* -e ' +! stderr 'compile.* -p [^z].* -N ' + +# -gcflags can have arbitrary spaces around the flags +go build -a -n -v -gcflags=' z1 = -e ' z1 +stderr 'compile.* -p z1.* -e ' + +# -gcflags='all=-e' should apply to all packages, even with go test +go test -a -c -n -gcflags='all=-e' z1 +stderr 'compile.* -p z3.* -e ' + +# this particular -gcflags argument made the compiler crash +! go build -gcflags=-d=ssa/ z1 +stderr 'PhaseOptions usage' + +# check for valid -ldflags parameter +! go build '-ldflags="-X main.X=Hello"' +stderr 'invalid value' + +# -ldflags for implicit test package applies to test binary +go test -a -c -n -gcflags=-N -ldflags=-X=x.y=z z1 +stderr 'compile.* -N .*z_test.go' +stderr 'link.* -X=x.y=z' + +# -ldflags for explicit test package applies to test binary +go test -a -c -n -gcflags=z1=-N -ldflags=z1=-X=x.y=z z1 +stderr 'compile.* -N .*z_test.go' +stderr 'link.* -X=x.y=z' + +# -ldflags applies to link of command +go build -a -n -ldflags=-X=math.pi=3 my/cmd/prog +stderr 'link.* -X=math.pi=3' + +# -ldflags applies to link of command even with strange directory name +go build -a -n -ldflags=-X=math.pi=3 my/cmd/prog/ +stderr 'link.* -X=math.pi=3' + +# -ldflags applies to current directory +cd my/cmd/prog +go build -a -n -ldflags=-X=math.pi=3 +stderr 'link.* -X=math.pi=3' + +# -ldflags applies to current directory even if GOPATH is funny +[!case-sensitive] cd $WORK/GoPath/src/my/cmd/prog +go build -a -n -ldflags=-X=math.pi=3 +stderr 'link.* -X=math.pi=3' + +# cgo.a should not be a dependency of internally-linked go package +go build -ldflags='-linkmode=external -linkmode=internal' -n prog.go +! stderr 'packagefile .*runtime/cgo.a' + +-- z1/z.go -- +package z1 +import _ "y" +import _ "z2" + +-- z1/z_test.go -- +package z1_test +import "testing" +import _ "z3" +func Test(t *testing.T) {} + +-- z2/z.go -- +package z2 + +-- z3/z.go -- +package z3 + +-- y/y.go -- +package y + +-- my/cmd/prog/prog.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/generate.txt b/src/cmd/go/testdata/script/generate.txt new file mode 100644 index 0000000..58777c5 --- /dev/null +++ b/src/cmd/go/testdata/script/generate.txt @@ -0,0 +1,107 @@ +[short] skip + +# Install an echo command because Windows doesn't have it. +env GOBIN=$WORK/tmp/bin +go install echo.go +env PATH=$GOBIN${:}$PATH + +# Test go generate handles a simple command +go generate ./generate/simple.go +stdout 'Success' + +# Test go generate handles a command alias +go generate './generate/alias.go' +stdout 'Now is the time for all good men' + +# Test go generate's variable substitution +go generate './generate/substitution.go' +stdout $GOARCH' substitution.go:7 pabc xyzp/substitution.go/123' + +# Test go generate's run and skip flags +go generate -run y.s './generate/flag.go' +stdout 'yes' # flag.go should select yes +! stdout 'no' # flag.go should not select no + +go generate -skip th..sand './generate/flag.go' +stdout 'yes' # flag.go should select yes +! stdout 'no' # flag.go should not select no + +go generate -run . -skip th..sand './generate/flag.go' +stdout 'yes' # flag.go should select yes +! stdout 'no' # flag.go should not select no + +# Test go generate provides the right "$GOPACKAGE" name in an x_test +go generate './generate/env_test.go' +stdout 'main_test' + +# Test go generate provides the right "$PWD" +go generate './generate/env_pwd.go' +stdout $WORK'[/\\]gopath[/\\]src[/\\]generate' + +-- echo.go -- +package main + +import ( + "fmt" + "os" + "strings" +) + +func main() { + fmt.Println(strings.Join(os.Args[1:], " ")) + fmt.Println() +} +-- generate/simple.go -- +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Simple test for go generate. + +// We include a build tag that go generate should ignore. + +// +build ignore + +//go:generate echo Success + +package p +-- generate/alias.go -- +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test that go generate handles command aliases. + +//go:generate -command run echo Now is the time +//go:generate run for all good men + +package p +-- generate/substitution.go -- +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test go generate variable substitution. + +//go:generate echo $GOARCH $GOFILE:$GOLINE ${GOPACKAGE}abc xyz$GOPACKAGE/$GOFILE/123 + +package p +-- generate/flag.go -- +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test -run flag + +//go:generate echo oh yes my man +//go:generate echo no, no, a thousand times no + +package p +-- generate/env_test.go -- +package main_test + +//go:generate echo $GOPACKAGE +-- generate/env_pwd.go -- +package p + +//go:generate echo $PWD diff --git a/src/cmd/go/testdata/script/generate_bad_imports.txt b/src/cmd/go/testdata/script/generate_bad_imports.txt new file mode 100644 index 0000000..3da391e --- /dev/null +++ b/src/cmd/go/testdata/script/generate_bad_imports.txt @@ -0,0 +1,15 @@ +[GOOS:windows] skip # skip because windows has no echo command + +go generate gencycle +stdout 'hello world' # check go generate gencycle ran the generator + +-- go.mod -- +module gencycle + +go 1.16 +-- gencycle.go -- +//go:generate echo hello world + +package gencycle + +import _ "gencycle" diff --git a/src/cmd/go/testdata/script/generate_env.txt b/src/cmd/go/testdata/script/generate_env.txt new file mode 100644 index 0000000..cb76d30 --- /dev/null +++ b/src/cmd/go/testdata/script/generate_env.txt @@ -0,0 +1,32 @@ +# Install an env command because Windows and plan9 don't have it. +env GOBIN=$WORK/tmp/bin +go install env.go +[GOOS:plan9] env path=$GOBIN${:}$path +[!GOOS:plan9] env PATH=$GOBIN${:}$PATH + +# Test generators have access to the environment +go generate ./printenv.go +stdout '^GOARCH='$GOARCH +stdout '^GOOS='$GOOS +stdout '^GOFILE=' +stdout '^GOLINE=' +stdout '^GOPACKAGE=' +stdout '^DOLLAR=' + +-- env.go -- +package main + +import ( + "fmt" + "os" +) + +func main() { + for _, v := range os.Environ() { + fmt.Println(v) + } +} +-- printenv.go -- +package main + +//go:generate env
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/generate_goroot_PATH.txt b/src/cmd/go/testdata/script/generate_goroot_PATH.txt new file mode 100644 index 0000000..24591f0 --- /dev/null +++ b/src/cmd/go/testdata/script/generate_goroot_PATH.txt @@ -0,0 +1,38 @@ +# https://go.dev/issue/51473: to avoid the need for generators to rely on +# runtime.GOROOT, 'go generate' should run the test with its own GOROOT/bin +# at the beginning of $PATH. + +[short] skip + +[!GOOS:plan9] env PATH= +[GOOS:plan9] env path= +go generate . + +[!GOOS:plan9] env PATH=$WORK${/}bin +[GOOS:plan9] env path=$WORK${/}bin +go generate . + +-- go.mod -- +module example + +go 1.19 +-- main.go -- +//go:generate go run . + +package main + +import ( + "fmt" + "os" + "os/exec" +) + +func main() { + _, err := exec.LookPath("go") + if err != nil { + fmt.Println(err) + os.Exit(1) + } +} +-- $WORK/bin/README.txt -- +This directory contains no executables. diff --git a/src/cmd/go/testdata/script/generate_invalid.txt b/src/cmd/go/testdata/script/generate_invalid.txt new file mode 100644 index 0000000..3bede32 --- /dev/null +++ b/src/cmd/go/testdata/script/generate_invalid.txt @@ -0,0 +1,208 @@ +[short] skip + +# Install an echo command because Windows doesn't have it. +env GOBIN=$WORK/tmp/bin +go install echo.go +env PATH=$GOBIN${:}$PATH + +# Test go generate for directory with no go files +! go generate ./nogo +! stdout 'Fail' +stderr 'no Go files' + +# Test go generate for module which doesn't exist should fail +! go generate foo.bar/nothing +stderr 'no required module provides package foo.bar/nothing' + +# Test go generate for package where all .go files are excluded by build +# constraints +go generate -v ./excluded +! stdout 'Fail' +! stderr 'go' # -v shouldn't list any files + +# Test go generate for "package" with no package clause in any file +go generate ./nopkg +stdout 'Success a' +! stdout 'Fail' + +# Test go generate for package with inconsistent package clauses +# $GOPACKAGE should depend on each file's package clause +go generate ./inconsistent +stdout 'Success a' +stdout 'Success b' +stdout -count=2 'Success c' +! stdout 'Fail' + +# Test go generate for syntax errors before and after package clauses +go generate ./syntax +stdout 'Success a' +stdout 'Success b' +! stdout 'Fail' + +# Test go generate for files importing non-existent packages +go generate ./importerr +stdout 'Success a' +stdout 'Success b' +stdout 'Success c' + +-- echo.go -- +package main + +import ( + "fmt" + "os" + "strings" +) + +func main() { + fmt.Println(strings.Join(os.Args[1:], " ")) + fmt.Println() +} + +-- go.mod -- +module m + +go 1.16 +-- nogo/foo.txt -- +Text file in a directory without go files. +Go generate should ignore this directory. +//go:generate echo Fail nogo + +-- excluded/a.go -- +// Include a build tag that go generate should exclude. +// Go generate should ignore this file. + +// +build a + +//go:generate echo Fail a + +package excluded + +-- excluded/b.go -- +// Include a build tag that go generate should exclude. +// Go generate should ignore this file. + +//go:generate echo Fail b + +// +build b + +package excluded + + +-- nopkg/a.go -- +// Go file with package clause after comment. +// Go generate should process this file. + +/* Pre-comment */ package nopkg +//go:generate echo Success a + +-- nopkg/b.go -- +// Go file with commented package clause. +// Go generate should ignore this file. + +//package nopkg + +//go:generate echo Fail b + +-- nopkg/c.go -- +// Go file with package clause inside multiline comment. +// Go generate should ignore this file. + +/* +package nopkg +*/ + +//go:generate echo Fail c + +-- nopkg/d.go -- +// Go file with package clause inside raw string literal. +// Go generate should ignore this file. + +const foo = ` +package nopkg +` +//go:generate echo Fail d + +-- nopkg/e.go -- +// Go file without package clause. +// Go generate should ignore this file. + +//go:generate echo Fail e + +-- inconsistent/a.go -- +// Valid go file with inconsistent package name. +// Go generate should process this file with GOPACKAGE=a + +package a +//go:generate echo Success $GOPACKAGE + +-- inconsistent/b.go -- +// Valid go file with inconsistent package name. +// Go generate should process this file with GOPACKAGE=b + +//go:generate echo Success $GOPACKAGE +package b + +-- inconsistent/c.go -- +// Go file with two package clauses. +// Go generate should process this file with GOPACKAGE=c + +//go:generate echo Success $GOPACKAGE +package c +// Invalid package clause, should be ignored: +package cinvalid +//go:generate echo Success $GOPACKAGE + +-- inconsistent/d.go -- +// Go file with invalid package name. +// Go generate should ignore this file. + +package +d+ +//go:generate echo Fail $GOPACKAGE + +-- syntax/a.go -- +// Go file with syntax error after package clause. +// Go generate should process this file. + +package syntax +123 +//go:generate echo Success a + +-- syntax/b.go -- +// Go file with syntax error after package clause. +// Go generate should process this file. + +package syntax; 123 +//go:generate echo Success b + +-- syntax/c.go -- +// Go file with syntax error before package clause. +// Go generate should ignore this file. + +foo +package syntax +//go:generate echo Fail c + +-- importerr/a.go -- +// Go file which imports non-existing package. +// Go generate should process this file. + +package importerr +//go:generate echo Success a +import "foo" + +-- importerr/b.go -- +// Go file which imports non-existing package. +// Go generate should process this file. + +//go:generate echo Success b +package importerr +import "bar" + +-- importerr/c.go -- +// Go file which imports non-existing package. +// Go generate should process this file. + +package importerr +import "moo" +//go:generate echo Success c diff --git a/src/cmd/go/testdata/script/generate_workspace.txt b/src/cmd/go/testdata/script/generate_workspace.txt new file mode 100644 index 0000000..5ba2393 --- /dev/null +++ b/src/cmd/go/testdata/script/generate_workspace.txt @@ -0,0 +1,27 @@ +# This is a regression test for Issue #56098: Go generate +# wasn't initializing workspace mode + +[short] skip + +go generate ./mod +cmp ./mod/got.txt want.txt + +-- go.work -- +go 1.22 + +use ./mod +-- mod/go.mod -- +module example.com/mod +-- mod/gen.go -- +//go:generate go run gen.go got.txt + +package main + +import "os" + +func main() { + outfile := os.Args[1] + os.WriteFile(outfile, []byte("Hello World!\n"), 0644) +} +-- want.txt -- +Hello World!
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/get_404_meta.txt b/src/cmd/go/testdata/script/get_404_meta.txt new file mode 100644 index 0000000..7665155 --- /dev/null +++ b/src/cmd/go/testdata/script/get_404_meta.txt @@ -0,0 +1,15 @@ +# golang.org/issue/13037: 'go get' was not parsing <meta> tags in 404 served over HTTPS. + +[!net:bazil.org] skip +[!git] skip + +env GONOSUMDB=bazil.org,github.com,golang.org +env GO111MODULE=on +env GOPROXY=direct +go get bazil.org/fuse/fs/fstestutil + + +-- go.mod -- +module m + +go 1.18 diff --git a/src/cmd/go/testdata/script/get_insecure.txt b/src/cmd/go/testdata/script/get_insecure.txt new file mode 100644 index 0000000..f29ec2d --- /dev/null +++ b/src/cmd/go/testdata/script/get_insecure.txt @@ -0,0 +1,41 @@ +[!net:insecure.go-get-issue-15410.appspot.com] skip +[!git] skip + +env PATH=$WORK/tmp/bin${:}$PATH +go build -o $WORK/tmp/bin/ssh ssh.go + +# Modules: Set up +env GOPATH=$WORK/m/gp +mkdir $WORK/m +cp module_file $WORK/m/go.mod +cd $WORK/m +env GO111MODULE=on +env GOPROXY='' + +# Modules: Try go get -d of HTTP-only repo (should fail). +! go get -d insecure.go-get-issue-15410.appspot.com/pkg/p + +# Modules: Try again with GOINSECURE (should succeed). +env GOINSECURE=insecure.go-get-issue-15410.appspot.com +env GONOSUMDB=insecure.go-get-issue-15410.appspot.com +go get -d insecure.go-get-issue-15410.appspot.com/pkg/p + +# Modules: Try updating without GOINSECURE (should fail). +env GOINSECURE='' +env GONOSUMDB='' +! go get -d -u -f insecure.go-get-issue-15410.appspot.com/pkg/p + +go list -m ... +stdout 'insecure.go-get-issue' + +-- ssh.go -- +// stub out uses of ssh by go get +package main + +import "os" + +func main() { + os.Exit(1) +} +-- module_file -- +module m diff --git a/src/cmd/go/testdata/script/get_insecure_no_longer_supported.txt b/src/cmd/go/testdata/script/get_insecure_no_longer_supported.txt new file mode 100644 index 0000000..00bf32f --- /dev/null +++ b/src/cmd/go/testdata/script/get_insecure_no_longer_supported.txt @@ -0,0 +1,13 @@ +# GOPATH: Set up +env GO111MODULE=off + +# GOPATH: Fetch with insecure, should error +! go get -insecure test +stderr 'go: -insecure flag is no longer supported; use GOINSECURE instead' + +# Modules: Set up +env GO111MODULE=on + +# Modules: Fetch with insecure, should error +! go get -insecure test +stderr 'go: -insecure flag is no longer supported; use GOINSECURE instead' diff --git a/src/cmd/go/testdata/script/get_issue53955.txt b/src/cmd/go/testdata/script/get_issue53955.txt new file mode 100644 index 0000000..685c6fa --- /dev/null +++ b/src/cmd/go/testdata/script/get_issue53955.txt @@ -0,0 +1,79 @@ +# Regression test for https://go.dev/issue/53955. +# New remote tags were erroneously added to the local clone of a repo +# only *after* extracting version information for a locally-cached commit, +# causing the version information to have incomplete Tags and Version fields. + +[short] skip 'constructs a local git repo' +[!git] skip +[!net:github.com] skip 'does not actually use github.com because of insteadOf, but silence network check just in case' + +# Redirect git to a test-specific .gitconfig. +# GIT_CONFIG_GLOBAL suffices for git 2.32.0 and newer. +# For older git versions we also set $HOME. +env GIT_CONFIG_GLOBAL=$WORK${/}home${/}gopher${/}.gitconfig +env HOME=$WORK${/}home${/}gopher +exec git config --global --show-origin user.name +stdout 'Go Gopher' + +# Inject a local repo in place of a remote one, so that we can +# add commits to the repo partway through the test. +env GIT_ALLOW_PROTOCOL=file +env GOPRIVATE=github.com/golang/issue53955 + +[!GOOS:windows] exec git config --global 'url.file://'$WORK'/repo.insteadOf' 'https://github.com/golang/issue53955' +[GOOS:windows] exec git config --global 'url.file:///'$WORK'/repo.insteadOf' 'https://github.com/golang/issue53955' + +cd $WORK/repo + +env GIT_AUTHOR_NAME='Go Gopher' +env GIT_AUTHOR_EMAIL='gopher@golang.org' +env GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME +env GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL + +exec git init + +env GIT_COMMITTER_DATE=2022-07-19T11:07:00-04:00 +env GIT_AUTHOR_DATE=2022-07-19T11:07:00-04:00 +exec git add go.mod issue53955.go +exec git commit -m 'initial commit' +exec git branch -m main +exec git tag v1.0.9 + +env GIT_COMMITTER_DATE=2022-07-19T11:07:01-04:00 +env GIT_AUTHOR_DATE=2022-07-19T11:07:01-04:00 +exec git add extra.go +exec git commit -m 'next commit' +exec git show-ref --tags --heads +cmp stdout $WORK/.git-refs-1 + +cd $WORK/m +go get -x github.com/golang/issue53955@2cb3d49f +stderr '^go: added github.com/golang/issue53955 v1.0.10-0.20220719150701-2cb3d49f8874$' + +cd $WORK/repo +exec git tag v1.0.10 + +cd $WORK/m +go get -x github.com/golang/issue53955@v1.0.10 +! stderr 'v1\.0\.10 is not a tag' +stderr '^go: upgraded github.com/golang/issue53955 v.* => v1\.0\.10$' + +-- $WORK/repo/go.mod -- +module github.com/golang/issue53955 + +go 1.18 +-- $WORK/repo/issue53955.go -- +package issue53955 +-- $WORK/repo/extra.go -- +package issue53955 +-- $WORK/.git-refs-1 -- +2cb3d49f8874b9362ed0ddd2a6512e4108bbf6b1 refs/heads/main +050526ebf5883191e990529eb3cc9345abaf838c refs/tags/v1.0.9 +-- $WORK/m/go.mod -- +module m + +go 1.18 +-- $WORK/home/gopher/.gitconfig -- +[user] + name = Go Gopher + email = gopher@golang.org diff --git a/src/cmd/go/testdata/script/go_badcmd.txt b/src/cmd/go/testdata/script/go_badcmd.txt new file mode 100644 index 0000000..661375a --- /dev/null +++ b/src/cmd/go/testdata/script/go_badcmd.txt @@ -0,0 +1,2 @@ +! go asdf +stderr '^go asdf: unknown command' diff --git a/src/cmd/go/testdata/script/go_version.txt b/src/cmd/go/testdata/script/go_version.txt new file mode 100644 index 0000000..1a787e1 --- /dev/null +++ b/src/cmd/go/testdata/script/go_version.txt @@ -0,0 +1,9 @@ +# test that go version doesn't panic on non-go binaries
+# See Issue #49181
+
+[exec:/bin/true] cp /bin/true true
+[exec:C:\windows\system32\help.exe] cp C:\windows\system32\help.exe help.exe
+
+go version -m .
+! stdout .
+! stderr .
diff --git a/src/cmd/go/testdata/script/godebug_default.txt b/src/cmd/go/testdata/script/godebug_default.txt new file mode 100644 index 0000000..5bb8cac --- /dev/null +++ b/src/cmd/go/testdata/script/godebug_default.txt @@ -0,0 +1,114 @@ +env GO111MODULE=on +env GOTRACEBACK=single + +# Go 1.21 work module should leave panicnil with an implicit default. +cp go.mod.21 go.mod +go list -f '{{.Module.GoVersion}} {{.DefaultGODEBUG}}' +! stdout panicnil +stdout randautoseed=0 + +# Go 1.21 work module should NOT set panicnil=1 in Go 1.20 dependency. +cp go.mod.21 go.mod +go list -f '{{.Module.GoVersion}} {{.DefaultGODEBUG}}' q +! stdout panicnil=1 +! stdout randautoseed + +go mod download rsc.io/panicnil # for go.sum +go list -f '{{.Module.GoVersion}} {{.DefaultGODEBUG}}' rsc.io/panicnil +! stdout panicnil=1 +! stdout randautoseed + +# Go 1.20 work module should set panicnil=1. +cp go.mod.20 go.mod +go list -f '{{.Module.GoVersion}} {{.DefaultGODEBUG}}' +stdout panicnil=1 +stdout randautoseed=0 + +# Go 1.20 work module should set panicnil=1 in Go 1.20 dependency. +cp go.mod.20 go.mod +go list -f '{{.Module.GoVersion}} {{.DefaultGODEBUG}}' q +stdout panicnil=1 +! stdout randautoseed + +# Go 1.21 workspace should leave panicnil with an implicit default. +cat q/go.mod +cp go.work.21 go.work +go list -f '{{.Module.GoVersion}} {{.DefaultGODEBUG}}' +! stdout panicnil +stdout randautoseed=0 +rm go.work + +# Go 1.20 workspace with Go 1.21 module cannot happen. +cp go.work.20 go.work +cp go.mod.21 go.mod +! go list -f '{{.Module.GoVersion}} {{.DefaultGODEBUG}}' +stderr 'go: module . listed in go.work file requires go >= 1.21' +rm go.work + +[short] skip + +# Programs in Go 1.21 work module should trigger run-time error. +cp go.mod.21 go.mod +! go run . +stderr 'panic: panic called with nil argument' + +! go run rsc.io/panicnil +stderr 'panic: panic called with nil argument' + +# Programs in Go 1.20 work module use old panic nil behavior. +cp go.mod.20 go.mod +! go run . +stderr 'panic: nil' + +! go run rsc.io/panicnil +stderr 'panic: nil' + +# Programs in no module at all should use their go.mod file. +rm go.mod +! go run rsc.io/panicnil@v1.0.0 +stderr 'panic: nil' + +rm go.mod +! go run rsc.io/panicnil@v1.1.0 +stderr 'panic: panic called with nil argument' + +-- go.work.21 -- +go 1.21 +use . +use ./q + +-- go.work.20 -- +go 1.20 +use . +use ./q + +-- go.mod.21 -- +go 1.21 +module m +require q v1.0.0 +replace q => ./q +require rsc.io/panicnil v1.0.0 + +-- go.mod.20 -- +go 1.20 +module m +require q v1.0.0 +replace q => ./q +require rsc.io/panicnil v1.0.0 + +-- p.go -- +//go:debug randautoseed=0 + +package main + +func main() { + panic(nil) +} + +-- q/go.mod -- +go 1.20 +module q + +-- q/q.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/godebug_unknown.txt b/src/cmd/go/testdata/script/godebug_unknown.txt new file mode 100644 index 0000000..57dacbc --- /dev/null +++ b/src/cmd/go/testdata/script/godebug_unknown.txt @@ -0,0 +1,9 @@ +! go build +stderr 'p.go:1:1: invalid //go:debug: unknown //go:debug setting "x"' + +-- go.mod -- +module m +-- p.go -- +//go:debug x=y +package main +func main() {} diff --git a/src/cmd/go/testdata/script/goflags.txt b/src/cmd/go/testdata/script/goflags.txt new file mode 100644 index 0000000..1120860 --- /dev/null +++ b/src/cmd/go/testdata/script/goflags.txt @@ -0,0 +1,64 @@ +env GO111MODULE=off + +# GOFLAGS sets flags for commands + +env GOFLAGS='-e -f={{.Dir}} --test.benchtime=1s -count=10' +go list asdfasdfasdf # succeeds because of -e +go list runtime +stdout '[\\/]runtime$' + +env GOFLAGS=-race OLDGOARCH=$GOARCH OLDGOOS=$GOOS GOARCH=386 GOOS=linux +! go list runtime +stderr 'race is not supported on linux/386' + +env GOARCH=$OLDGOARCH GOOS=$OLDGOOS + +# go env succeeds even though -f={{.Dir}} is inappropriate +go env + +# bad flags are diagnosed +env GOFLAGS=-typoflag +! go list runtime +stderr 'unknown flag -typoflag' + +env GOFLAGS=- +! go list runtime +stderr '^go: parsing \$GOFLAGS: non-flag "-"' + +env GOFLAGS=-- +! go list runtime +stderr '^go: parsing \$GOFLAGS: non-flag "--"' + +env GOFLAGS=---oops +! go list runtime +stderr '^go: parsing \$GOFLAGS: non-flag "---oops"' + +env GOFLAGS=-=noname +! go list runtime +stderr '^go: parsing \$GOFLAGS: non-flag "-=noname"' + +env GOFLAGS=-f +! go list runtime +stderr '^go: flag needs an argument: -f \(from (\$GOFLAGS|%GOFLAGS%)\)$' + +env GOFLAGS=-e=asdf +! go list runtime +stderr '^go: invalid boolean value \"asdf\" for flag -e \(from (\$GOFLAGS|%GOFLAGS%)\)' + +# except in go bug (untested) and go env +go env +stdout GOFLAGS + +# Flags listed in GOFLAGS should be safe to duplicate on the command line. +env GOFLAGS=-tags=magic +go list -tags=magic +go test -tags=magic -c -o $devnull +go vet -tags=magic + +# GOFLAGS uses the same quoting rules (quoted.Split) as the rest of +# the go command env variables +env GOFLAGS='"-tags=magic wizardry"' +go list + +-- foo_test.go -- +package foo diff --git a/src/cmd/go/testdata/script/goline_order.txt b/src/cmd/go/testdata/script/goline_order.txt new file mode 100644 index 0000000..6212cd6 --- /dev/null +++ b/src/cmd/go/testdata/script/goline_order.txt @@ -0,0 +1,74 @@ +# Check that go lines are always >= go lines of dependencies. + +# Using too old a release cannot even complete module load. +env TESTGO_VERSION=go1.21.1 +env TESTGO_VERSION_SWITCH=switch +cp go.mod go.mod.orig + +# If the offending module is not imported, it's not detected. +go list +cmp go.mod go.mod.orig + +# Adding the import produces the error. +# Maybe this should auto-switch, but it requires more plumbing to get this error through, +# and it's a misconfigured system that should not arise in practice, so not switching is fine. +! go list -deps -tags usem1 +cmp go.mod go.mod.orig +stderr '^go: module ./m1 requires go >= 1.21.2 \(running go 1.21.1\)$' + +# go get go@1.21.2 fixes the error. +cp go.mod.orig go.mod +go get go@1.21.2 +go list -deps -tags usem1 + +# go get -tags usem1 fixes the error. +cp go.mod.orig go.mod +go get -tags usem1 +go list -deps -tags usem1 + +# go get fixes the error. +cp go.mod.orig go.mod +go get +go list -deps -tags usem1 + +# Using a new enough release reports the error after module load and suggests 'go mod tidy' +env TESTGO_VERSION=go1.21.2 +cp go.mod.orig go.mod +! go list -deps -tags usem1 +stderr 'updates to go.mod needed' +stderr 'go mod tidy' +go mod tidy +go list -deps -tags usem1 + +# go get also works +cp go.mod.orig go.mod +! go list -deps -tags usem1 +stderr 'updates to go.mod needed' +stderr 'go mod tidy' +go get go@1.21.2 +go list -deps -tags usem1 + + +-- go.mod -- +module m +go 1.21.1 + +require m1 v0.0.1 + +replace m1 => ./m1 + +-- m1/go.mod -- +go 1.21.2 + +-- p.go -- +//go:build usem1 + +package p + +import _ "m1" + +-- p1.go -- +package p + +-- m1/p.go -- +package p diff --git a/src/cmd/go/testdata/script/gopath_install.txt b/src/cmd/go/testdata/script/gopath_install.txt new file mode 100644 index 0000000..6c572ea --- /dev/null +++ b/src/cmd/go/testdata/script/gopath_install.txt @@ -0,0 +1,53 @@ +# Regression test for 'go install' locations in GOPATH mode. +env GO111MODULE=off +[short] skip + +# Without $GOBIN set, binaries should be installed into the GOPATH bin directory. +env GOBIN= +rm $GOPATH/bin/go-cmd-test$GOEXE +go install go-cmd-test +exists $GOPATH/bin/go-cmd-test$GOEXE + +# With $GOBIN set, binaries should be installed to $GOBIN. +env GOBIN=$WORK/bin1 +mkdir -p $GOBIN +go install go-cmd-test +exists $GOBIN/go-cmd-test$GOEXE + +# Issue 11065: installing to the current directory should create an executable. +cd go-cmd-test +env GOBIN=$PWD +go install +exists ./go-cmd-test$GOEXE +cd .. + +# Without $GOBIN set, installing a program outside $GOPATH should fail +# (there is nowhere to install it). +env GOPATH= # reset to default ($HOME/go, which does not exist) +env GOBIN= +! go install go-cmd-test/helloworld.go +stderr '^go: no install location for \.go files listed on command line \(GOBIN not set\)$' + +# With $GOBIN set, should install there. +env GOBIN=$WORK/bin1 +go install go-cmd-test/helloworld.go +exists $GOBIN/helloworld$GOEXE + +# We can't assume that we can write to GOROOT, because it may not be writable. +# However, we can check its install location using 'go list'. +# cmd/fix should be installed to GOROOT/pkg, not GOPATH/bin. +env GOPATH=$PWD +go list -f '{{.Target}}' cmd/fix +stdout $GOROOT'[/\\]pkg[/\\]tool[/\\]'$GOOS'_'$GOARCH'[/\\]fix'$GOEXE'$' + +# GOBIN should not affect toolchain install locations. +env GOBIN=$WORK/bin1 +go list -f '{{.Target}}' cmd/fix +stdout $GOROOT'[/\\]pkg[/\\]tool[/\\]'$GOOS'_'$GOARCH'[/\\]fix'$GOEXE'$' + +-- go-cmd-test/helloworld.go -- +package main + +func main() { + println("hello world") +} diff --git a/src/cmd/go/testdata/script/gopath_local.txt b/src/cmd/go/testdata/script/gopath_local.txt new file mode 100644 index 0000000..efde0e7 --- /dev/null +++ b/src/cmd/go/testdata/script/gopath_local.txt @@ -0,0 +1,117 @@ +env GO111MODULE=off # Relative imports only work in GOPATH mode. + +[short] skip + +# Imports should be resolved relative to the source file. +go build testdata/local/easy.go +exec ./easy$GOEXE +stdout '^easysub\.Hello' + +# Ignored files should be able to import the package built from +# non-ignored files in the same directory. +go build -o easysub$GOEXE testdata/local/easysub/main.go +exec ./easysub$GOEXE +stdout '^easysub\.Hello' + +# Files in relative-imported packages should be able to +# use relative imports themselves. +go build testdata/local/hard.go +exec ./hard$GOEXE +stdout '^sub\.Hello' + +# Explicit source files listed on the command line should not install without +# GOBIN set, since individual source files aren't part of the containing GOPATH. +! go install testdata/local/easy.go +stderr '^go: no install location for \.go files listed on command line \(GOBIN not set\)$' + +[GOOS:windows] stop # Windows does not allow the ridiculous directory name we're about to use. + +env BAD_DIR_NAME='#$%:, &()*;<=>?\^{}' + +mkdir -p testdata/$BAD_DIR_NAME/easysub +mkdir -p testdata/$BAD_DIR_NAME/sub/sub + +cp testdata/local/easy.go testdata/$BAD_DIR_NAME/easy.go +cp testdata/local/easysub/easysub.go testdata/$BAD_DIR_NAME/easysub/easysub.go +cp testdata/local/easysub/main.go testdata/$BAD_DIR_NAME/easysub/main.go +cp testdata/local/hard.go testdata/$BAD_DIR_NAME/hard.go +cp testdata/local/sub/sub.go testdata/$BAD_DIR_NAME/sub/sub.go +cp testdata/local/sub/sub/subsub.go testdata/$BAD_DIR_NAME/sub/sub/subsub.go + +# Imports should be resolved relative to the source file. +go build testdata/$BAD_DIR_NAME/easy.go +exec ./easy$GOEXE +stdout '^easysub\.Hello' + +# Ignored files should be able to import the package built from +# non-ignored files in the same directory. +go build -o easysub$GOEXE testdata/$BAD_DIR_NAME/easysub/main.go +exec ./easysub$GOEXE +stdout '^easysub\.Hello' + +# Files in relative-imported packages should be able to +# use relative imports themselves. +go build testdata/$BAD_DIR_NAME/hard.go +exec ./hard$GOEXE +stdout '^sub\.Hello' + +# Explicit source files listed on the command line should not install without +# GOBIN set, since individual source files aren't part of the containing GOPATH. +! go install testdata/$BAD_DIR_NAME/easy.go +stderr '^go: no install location for \.go files listed on command line \(GOBIN not set\)$' + +-- testdata/local/easy.go -- +package main + +import "./easysub" + +func main() { + easysub.Hello() +} +-- testdata/local/easysub/easysub.go -- +package easysub + +import "fmt" + +func Hello() { + fmt.Println("easysub.Hello") +} +-- testdata/local/easysub/main.go -- +// +build ignore + +package main + +import "." + +func main() { + easysub.Hello() +} +-- testdata/local/hard.go -- +package main + +import "./sub" + +func main() { + sub.Hello() +} +-- testdata/local/sub/sub.go -- +package sub + +import ( + "fmt" + + subsub "./sub" +) + +func Hello() { + fmt.Println("sub.Hello") + subsub.Hello() +} +-- testdata/local/sub/sub/subsub.go -- +package subsub + +import "fmt" + +func Hello() { + fmt.Println("subsub.Hello") +} diff --git a/src/cmd/go/testdata/script/gopath_paths.txt b/src/cmd/go/testdata/script/gopath_paths.txt new file mode 100644 index 0000000..04265b1 --- /dev/null +++ b/src/cmd/go/testdata/script/gopath_paths.txt @@ -0,0 +1,43 @@ +# Regression test for GOPATH validation in GOPATH mode. +env GO111MODULE=off + +env ORIG_GOPATH=$GOPATH + +# The literal path '.' in GOPATH should be rejected. +env GOPATH=. +! go build go-cmd-test/helloworld.go +stderr 'GOPATH entry is relative' + +# It should still be rejected if the requested package can be +# found using another entry. +env GOPATH=${:}$ORIG_GOPATH${:}. +! go build go-cmd-test +stderr 'GOPATH entry is relative' + +# GOPATH cannot be a relative subdirectory of the working directory. +env ORIG_GOPATH +stdout 'ORIG_GOPATH='$WORK[/\\]gopath +cd $WORK +env GOPATH=gopath +! go build gopath/src/go-cmd-test/helloworld.go +stderr 'GOPATH entry is relative' + +# Blank paths in GOPATH should be rejected as relative (issue 21928). +env GOPATH=' '${:}$ORIG_GOPATH +! go build go-cmd-test +stderr 'GOPATH entry is relative' + +[short] stop + +# Empty paths in GOPATH should be ignored (issue 21928). +env GOPATH=${:}$ORIG_GOPATH +env GOPATH +go install go-cmd-test +exists $ORIG_GOPATH/bin/go-cmd-test$GOEXE + +-- go-cmd-test/helloworld.go -- +package main + +func main() { + println("hello world") +} diff --git a/src/cmd/go/testdata/script/gopath_std_vendor.txt b/src/cmd/go/testdata/script/gopath_std_vendor.txt new file mode 100644 index 0000000..4aaf46b --- /dev/null +++ b/src/cmd/go/testdata/script/gopath_std_vendor.txt @@ -0,0 +1,44 @@ +env GO111MODULE=off + +[!compiler:gc] skip + +go list -f '{{.Dir}}' vendor/golang.org/x/net/http2/hpack +stdout $GOPATH[/\\]src[/\\]vendor + +# A package importing 'net/http' should resolve its dependencies +# to the package 'vendor/golang.org/x/net/http2/hpack' within GOROOT. +cd importnethttp +go list -deps -f '{{.ImportPath}} {{.Dir}}' +stdout ^vendor/golang.org/x/net/http2/hpack +stdout $GOROOT[/\\]src[/\\]vendor[/\\]golang.org[/\\]x[/\\]net[/\\]http2[/\\]hpack +! stdout $GOPATH[/\\]src[/\\]vendor + +# In the presence of $GOPATH/src/vendor/golang.org/x/net/http2/hpack, +# a package in GOPATH importing 'golang.org/x/net/http2/hpack' should +# resolve its dependencies in GOPATH/src. +cd ../issue16333 +go build . + +go list -deps -f '{{.ImportPath}} {{.Dir}}' . +stdout $GOPATH[/\\]src[/\\]vendor[/\\]golang.org[/\\]x[/\\]net[/\\]http2[/\\]hpack +! stdout $GOROOT[/\\]src[/\\]vendor + +go list -test -deps -f '{{.ImportPath}} {{.Dir}}' . +stdout $GOPATH[/\\]src[/\\]vendor[/\\]golang.org[/\\]x[/\\]net[/\\]http2[/\\]hpack +! stdout $GOROOT[/\\]src[/\\]vendor + +-- issue16333/issue16333.go -- +package vendoring17 + +import _ "golang.org/x/net/http2/hpack" +-- issue16333/issue16333_test.go -- +package vendoring17 + +import _ "testing" +import _ "golang.org/x/net/http2/hpack" +-- importnethttp/http.go -- +package importnethttp + +import _ "net/http" +-- $GOPATH/src/vendor/golang.org/x/net/http2/hpack/hpack.go -- +package hpack diff --git a/src/cmd/go/testdata/script/gopath_vendor_dup_err.txt b/src/cmd/go/testdata/script/gopath_vendor_dup_err.txt new file mode 100644 index 0000000..5f1e09a --- /dev/null +++ b/src/cmd/go/testdata/script/gopath_vendor_dup_err.txt @@ -0,0 +1,24 @@ +env GO111MODULE=off + +# Issue 17119: Test more duplicate load errors. +! go build dupload +! stderr 'duplicate load|internal error' +stderr 'dupload/vendor/p must be imported as p' + +-- dupload/dupload.go -- +package main + +import ( + _ "dupload/p2" + _ "p" +) + +func main() {} +-- dupload/p/p.go -- +package p +-- dupload/p2/p2.go -- +package p2 + +import _ "dupload/vendor/p" +-- dupload/vendor/p/p.go -- +package p diff --git a/src/cmd/go/testdata/script/goroot_executable.txt b/src/cmd/go/testdata/script/goroot_executable.txt new file mode 100644 index 0000000..e20dbd8 --- /dev/null +++ b/src/cmd/go/testdata/script/goroot_executable.txt @@ -0,0 +1,115 @@ +[compiler:gccgo] skip +[short] skip 'builds and links another cmd/go' + +mkdir $WORK/new/bin + +# In this test, we are specifically checking the logic for deriving +# the value of GOROOT from runtime.GOROOT. +# GOROOT_FINAL changes the default behavior of runtime.GOROOT, +# and will thus cause the test to fail if it is set when our +# new cmd/go is built. +env GOROOT_FINAL= + +# $GOROOT/bin/go is whatever the user has already installed +# (using make.bash or similar). We can't make assumptions about what +# options it may have been built with, such as -trimpath or GOROOT_FINAL. +# Instead, we build a fresh copy of the binary with known settings. +go build -o $WORK/new/bin/go$GOEXE cmd/go & +go build -trimpath -o $WORK/bin/check$GOEXE check.go & +wait + +env TESTGOROOT=$GOROOT +env GOROOT= + +# Relocated Executable +exec $WORK/bin/check$GOEXE $WORK/new/bin/go$GOEXE $TESTGOROOT + +# Relocated Tree: +# If the binary is sitting in a bin dir next to ../pkg/tool, that counts as a GOROOT, +# so it should find the new tree. +mkdir $WORK/new/pkg/tool +exec $WORK/bin/check$GOEXE $WORK/new/bin/go$GOEXE $WORK/new + +[!symlink] stop 'The rest of the test cases require symlinks' + +# Symlinked Executable: +# With a symlink into go tree, we should still find the go tree. +mkdir $WORK/other/bin +symlink $WORK/other/bin/go$GOEXE -> $WORK/new/bin/go$GOEXE +exec $WORK/bin/check$GOEXE $WORK/new/bin/go$GOEXE $WORK/new + +rm $WORK/new/pkg + +# Runtime GOROOT: +# Binaries built in the new tree should report the +# new tree when they call runtime.GOROOT. +symlink $WORK/new/src -> $TESTGOROOT/src +symlink $WORK/new/pkg -> $TESTGOROOT/pkg +exec $WORK/new/bin/go$GOEXE run check_runtime_goroot.go $WORK/new + +-- check.go -- +package main + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" +) + +func main() { + exe := os.Args[1] + want := os.Args[2] + cmd := exec.Command(exe, "env", "GOROOT") + out, err := cmd.CombinedOutput() + if err != nil { + fmt.Fprintf(os.Stderr, "%s env GOROOT: %v, %s\n", exe, err, out) + os.Exit(1) + } + goroot, err := filepath.EvalSymlinks(strings.TrimSpace(string(out))) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + want, err = filepath.EvalSymlinks(want) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if !strings.EqualFold(goroot, want) { + fmt.Fprintf(os.Stderr, "go env GOROOT:\nhave %s\nwant %s\n", goroot, want) + os.Exit(1) + } + fmt.Fprintf(os.Stderr, "go env GOROOT: %s\n", goroot) + +} +-- check_runtime_goroot.go -- +package main + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "strings" +) + +func main() { + goroot, err := filepath.EvalSymlinks(runtime.GOROOT()) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + want, err := filepath.EvalSymlinks(os.Args[1]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if !strings.EqualFold(goroot, want) { + fmt.Fprintf(os.Stderr, "go env GOROOT:\nhave %s\nwant %s\n", goroot, want) + os.Exit(1) + } + fmt.Fprintf(os.Stderr, "go env GOROOT: %s\n", goroot) + +} diff --git a/src/cmd/go/testdata/script/goroot_executable_trimpath.txt b/src/cmd/go/testdata/script/goroot_executable_trimpath.txt new file mode 100644 index 0000000..a3f0c39 --- /dev/null +++ b/src/cmd/go/testdata/script/goroot_executable_trimpath.txt @@ -0,0 +1,101 @@ +# Regression test for https://go.dev/issue/62119: +# A 'go' command cross-compiled with a different GOHOSTOS +# should be able to locate its GOROOT using os.Executable. +# +# (This also tests a 'go' command built with -trimpath +# that is not cross-compiled, since we need to build that +# configuration for the test anyway.) + +[short] skip 'builds and links another cmd/go' + +mkdir $WORK/new/bin +mkdir $WORK/new/bin/${GOOS}_${GOARCH} + +# In this test, we are specifically checking the logic for deriving +# the value of GOROOT from os.Executable when runtime.GOROOT is +# trimmed away. +# GOROOT_FINAL changes the default behavior of runtime.GOROOT, +# so we explicitly clear it to remove it as a confounding variable. +env GOROOT_FINAL= + +# $GOROOT/bin/go is whatever the user has already installed +# (using make.bash or similar). We can't make assumptions about what +# options it may have been built with, such as -trimpath or GOROOT_FINAL. +# Instead, we build a fresh copy of the binary with known settings. +go build -trimpath -o $WORK/new/bin/go$GOEXE cmd/go & +go build -trimpath -o $WORK/bin/check$GOEXE check.go & +wait + +env TESTGOROOT=$GOROOT +env GOROOT= + +# Unset GOPATH and any variables that its default may be derived from, +# so that we can check for a spurious warning. +env GOPATH= +env HOME='' +env USERPROFILE='' +env home='' + +# Relocated Executable +# Since we built with -trimpath and the binary isn't installed in a +# normal-looking GOROOT, this command should fail. + +! exec $WORK/new/bin/go$GOEXE env GOROOT +stderr '^go: cannot find GOROOT directory: ''go'' binary is trimmed and GOROOT is not set$' +! stderr 'GOPATH set to GOROOT' + +# Cross-compiled binaries in cmd are installed to a ${GOOS}_${GOARCH} subdirectory, +# so we also want to try a copy there. +# (Note that the script engine's 'exec' engine already works around +# https://go.dev/issue/22315, so we don't have to do that explicitly in the +# 'check' program we use later.) +cp $WORK/new/bin/go$GOEXE $WORK/new/bin/${GOOS}_${GOARCH}/go$GOEXE +! exec $WORK/new/bin/${GOOS}_${GOARCH}/go$GOEXE env GOROOT +stderr '^go: cannot find GOROOT directory: ''go'' binary is trimmed and GOROOT is not set$' +! stderr 'GOPATH set to GOROOT' + +# Relocated Tree: +# If the binary is sitting in a bin dir next to ../pkg/tool, that counts as a GOROOT, +# so it should find the new tree. +mkdir $WORK/new/pkg/tool +exec $WORK/bin/check$GOEXE $WORK/new/bin/go$GOEXE $WORK/new +exec $WORK/bin/check$GOEXE $WORK/new/bin/${GOOS}_${GOARCH}/go$GOEXE $WORK/new +! stderr 'GOPATH set to GOROOT' + +-- check.go -- +package main + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" +) + +func main() { + exe := os.Args[1] + want := os.Args[2] + cmd := exec.Command(exe, "env", "GOROOT") + out, err := cmd.CombinedOutput() + if err != nil { + fmt.Fprintf(os.Stderr, "%s env GOROOT: %v, %s\n", exe, err, out) + os.Exit(1) + } + goroot, err := filepath.EvalSymlinks(strings.TrimSpace(string(out))) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + want, err = filepath.EvalSymlinks(want) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if !strings.EqualFold(goroot, want) { + fmt.Fprintf(os.Stderr, "go env GOROOT:\nhave %s\nwant %s\n", goroot, want) + os.Exit(1) + } + fmt.Fprintf(os.Stderr, "go env GOROOT: %s\n", goroot) + +} diff --git a/src/cmd/go/testdata/script/gotoolchain_local.txt b/src/cmd/go/testdata/script/gotoolchain_local.txt new file mode 100644 index 0000000..db7e082 --- /dev/null +++ b/src/cmd/go/testdata/script/gotoolchain_local.txt @@ -0,0 +1,256 @@ +# This test uses the fake toolchain switch support in cmd/go/internal/toolchain.Switch +# to exercise all the version selection logic without needing actual toolchains. +# See gotoolchain_net.txt and gotoolchain_path.txt for tests of network and PATH toolchains. + +env TESTGO_VERSION=go1.500 +env TESTGO_VERSION_SWITCH=switch + +# GOTOOLCHAIN=auto runs default toolchain without a go.mod or go.work +env GOTOOLCHAIN=auto +go version +stdout go1.500 + +# GOTOOLCHAIN=path runs default toolchain without a go.mod or go.work +env GOTOOLCHAIN=path +go version +stdout go1.500 + +# GOTOOLCHAIN=asdf is a syntax error +env GOTOOLCHAIN=asdf +! go version +stderr '^go: invalid GOTOOLCHAIN "asdf"$' + +# GOTOOLCHAIN=version is used directly. +env GOTOOLCHAIN=go1.600 +go version +stdout go1.600 + +env GOTOOLCHAIN=go1.400 +go version +stdout go1.400 + +# GOTOOLCHAIN=version+auto sets a minimum. +env GOTOOLCHAIN=go1.600+auto +go version +stdout go1.600 + +env GOTOOLCHAIN=go1.400.0+auto +go version +stdout go1.400.0 + +# GOTOOLCHAIN=version+path sets a minimum too. +env GOTOOLCHAIN=go1.600+path +go version +stdout go1.600 + +env GOTOOLCHAIN=go1.400+path +go version +stdout go1.400 + +# Create a go.mod file and test interactions with auto and path. + +# GOTOOLCHAIN=auto uses go line if newer than local toolchain. +env GOTOOLCHAIN=auto +go mod init m +go mod edit -go=1.700 -toolchain=none +go version +stdout 1.700 + +go mod edit -go=1.300 -toolchain=none +go version +stdout 1.500 # local toolchain is newer + +go mod edit -go=1.700 -toolchain=go1.300 +go version +stdout go1.700 # toolchain too old, ignored + +go mod edit -go=1.300 -toolchain=default +go version +stdout go1.500 + +go mod edit -go=1.700 -toolchain=default +go version +stdout go1.500 # toolchain local is like GOTOOLCHAIN=local and wins +! go build +stderr '^go: go.mod requires go >= 1.700 \(running go 1.500; go.mod sets toolchain default\)' + +# GOTOOLCHAIN=path does the same. +env GOTOOLCHAIN=path +go mod edit -go=1.700 -toolchain=none +go version +stdout 1.700 + +go mod edit -go=1.300 -toolchain=none +go version +stdout 1.500 # local toolchain is newer + +go mod edit -go=1.700 -toolchain=go1.300 +go version +stdout go1.700 # toolchain too old, ignored + +go mod edit -go=1.300 -toolchain=default +go version +stdout go1.500 + +go mod edit -go=1.700 -toolchain=default +go version +stdout go1.500 # toolchain default applies even if older than go line +! go build +stderr '^go: go.mod requires go >= 1.700 \(running go 1.500; GOTOOLCHAIN=path; go.mod sets toolchain default\)' + +# GOTOOLCHAIN=min+auto with toolchain default uses min, not local + +env GOTOOLCHAIN=go1.400+auto +go mod edit -go=1.300 -toolchain=default +go version +stdout 1.400 # not 1.500 local toolchain + +env GOTOOLCHAIN=go1.600+auto +go mod edit -go=1.300 -toolchain=default +go version +stdout 1.600 # not 1.500 local toolchain + +# GOTOOLCHAIN names can have -suffix +env GOTOOLCHAIN=go1.800-bigcorp +go version +stdout go1.800-bigcorp + +env GOTOOLCHAIN=auto +go mod edit -go=1.999 -toolchain=go1.800-bigcorp +go version +stdout go1.999 + +go mod edit -go=1.777 -toolchain=go1.800-bigcorp +go version +stdout go1.800-bigcorp + +# go.work takes priority over go.mod +go mod edit -go=1.700 -toolchain=go1.999-wrong +go work init +go work edit -go=1.400 -toolchain=go1.600-right +go version +stdout go1.600-right + +go work edit -go=1.400 -toolchain=default +go version +stdout go1.500 + +# go.work misconfiguration does not break go work edit +# ('go 1.600 / toolchain local' forces use of 1.500 which can't normally load that go.work; allow work edit to fix it.) +go work edit -go=1.600 -toolchain=default +go version +stdout go1.500 + +go work edit -toolchain=none +go version +stdout go1.600 + +rm go.work + +# go.mod misconfiguration does not break go mod edit +go mod edit -go=1.600 -toolchain=default +go version +stdout go1.500 + +go mod edit -toolchain=none +go version +stdout go1.600 + +# toolchain built with a custom version should know how it compares to others + +env TESTGO_VERSION=go1.500-bigcorp +go mod edit -go=1.499 -toolchain=none +go version +stdout go1.500-bigcorp + +go mod edit -go=1.499 -toolchain=go1.499 +go version +stdout go1.500-bigcorp + +go mod edit -go=1.500 -toolchain=none +go version +stdout go1.500-bigcorp + +go mod edit -go=1.500 -toolchain=go1.500 +go version +stdout go1.500-bigcorp + +go mod edit -go=1.501 -toolchain=none +go version +stdout go1.501 + + # If toolchain > go, we must upgrade to the indicated toolchain (not just the go version). +go mod edit -go=1.499 -toolchain=go1.501 +go version +stdout go1.501 + +env TESTGO_VERSION='go1.500 (bigcorp)' +go mod edit -go=1.499 -toolchain=none +go version +stdout 'go1.500 \(bigcorp\)' + +go mod edit -go=1.500 -toolchain=none +go version +stdout 'go1.500 \(bigcorp\)' + +go mod edit -go=1.501 -toolchain=none +go version +stdout go1.501 + +# go install m@v and go run m@v should ignore go.mod and use m@v +env TESTGO_VERSION=go1.2.3 +go mod edit -go=1.999 -toolchain=go1.998 + +! go install rsc.io/fortune/nonexist@v0.0.1 +stderr '^go: rsc.io/fortune@v0.0.1 requires go >= 1.21rc999; switching to go1.22.9$' +stderr '^go: rsc.io/fortune/nonexist@v0.0.1: module rsc.io/fortune@v0.0.1 found, but does not contain package rsc.io/fortune/nonexist' + +! go run rsc.io/fortune/nonexist@v0.0.1 +stderr '^go: rsc.io/fortune@v0.0.1 requires go >= 1.21rc999; switching to go1.22.9$' +stderr '^go: rsc.io/fortune/nonexist@v0.0.1: module rsc.io/fortune@v0.0.1 found, but does not contain package rsc.io/fortune/nonexist' + +# go install should handle unknown flags to find m@v +! go install -unknownflag rsc.io/fortune/nonexist@v0.0.1 +stderr '^go: rsc.io/fortune@v0.0.1 requires go >= 1.21rc999; switching to go1.22.9$' +stderr '^flag provided but not defined: -unknownflag' + +! go install -unknownflag arg rsc.io/fortune/nonexist@v0.0.1 +stderr '^go: rsc.io/fortune@v0.0.1 requires go >= 1.21rc999; switching to go1.22.9$' +stderr '^flag provided but not defined: -unknownflag' + +# go run cannot handle unknown boolean flags +! go run -unknownflag rsc.io/fortune/nonexist@v0.0.1 +! stderr switching +stderr '^flag provided but not defined: -unknownflag' + +! go run -unknownflag oops rsc.io/fortune/nonexist@v0.0.1 +! stderr switching +stderr '^flag provided but not defined: -unknownflag' + +# go run can handle unknown flag with argument. +! go run -unknown=flag rsc.io/fortune/nonexist@v0.0.1 +stderr '^go: rsc.io/fortune@v0.0.1 requires go >= 1.21rc999; switching to go1.22.9$' +stderr '^flag provided but not defined: -unknown' + +# go install m@v should handle queries +! go install rsc.io/fortune/nonexist@v0.0 +stderr '^go: rsc.io/fortune@v0.0.1 requires go >= 1.21rc999; switching to go1.22.9$' +stderr '^go: rsc.io/fortune/nonexist@v0.0: module rsc.io/fortune@v0.0 found \(v0.0.1\), but does not contain package rsc.io/fortune/nonexist' + +# go run m@v should handle queries +! go install rsc.io/fortune/nonexist@v0 +stderr '^go: rsc.io/fortune@v0.0.1 requires go >= 1.21rc999; switching to go1.22.9$' +stderr '^go: rsc.io/fortune/nonexist@v0: module rsc.io/fortune@v0 found \(v0.0.1\), but does not contain package rsc.io/fortune/nonexist' + +# go install m@v should use local toolchain if not upgrading +! go install rsc.io/fortune/nonexist@v1 +! stderr go1.22.9 +! stderr switching +stderr '^go: downloading rsc.io/fortune v1.0.0$' +stderr '^go: rsc.io/fortune/nonexist@v1: module rsc.io/fortune@v1 found \(v1.0.0\), but does not contain package rsc.io/fortune/nonexist' + +# go run m@v should use local toolchain if not upgrading +! go run rsc.io/fortune/nonexist@v1 +! stderr go1.22.9 +! stderr switching +stderr '^go: rsc.io/fortune/nonexist@v1: module rsc.io/fortune@v1 found \(v1.0.0\), but does not contain package rsc.io/fortune/nonexist' diff --git a/src/cmd/go/testdata/script/gotoolchain_loop.txt b/src/cmd/go/testdata/script/gotoolchain_loop.txt new file mode 100644 index 0000000..a803d2e --- /dev/null +++ b/src/cmd/go/testdata/script/gotoolchain_loop.txt @@ -0,0 +1,65 @@ +env GOTOOLCHAIN=auto +env TESTGO_VERSION=go1.21.1 + +# Basic switch should work. +env TESTGO_VERSION_SWITCH=switch +go version +stdout go1.21.99 + +# Toolchain target mismatch should be detected. +env TESTGO_VERSION_SWITCH=mismatch +! go version +stderr '^go: toolchain go1.21.1 invoked to provide go1.21.99$' + +# Toolchain loop should be detected. +env TESTGO_VERSION_SWITCH=loop +! go version +stderr -count=10 '^go: switching from go1.21.1 to go1.21.99 \[depth 9[0-9]\]$' +stderr -count=1 '^go: switching from go1.21.1 to go1.21.99 \[depth 100\]$' +stderr '^go: too many toolchain switches$' + +[short] skip + +# Internal env vars should not leak to go test or go run. +env TESTGO_VERSION_SWITCH=switch +go version +stdout go1.21.99 +go test +stdout clean +go run . +stdout clean + +-- go.mod -- +module m +go 1.21.99 + +-- m_test.go -- +package main + +import "testing" + +func TestEnv(t *testing.T) { + // the check is in func init in m.go +} + +-- m.go -- +package main + +import "os" + +func init() { + envs := []string{ + "GOTOOLCHAIN_INTERNAL_SWITCH_COUNT", + "GOTOOLCHAIN_INTERNAL_SWITCH_VERSION", + } + for _, e := range envs { + if v := os.Getenv(e); v != "" { + panic("$"+e+"="+v) + } + } + os.Stdout.WriteString("clean\n") +} + +func main() { +} + diff --git a/src/cmd/go/testdata/script/gotoolchain_modcmds.txt b/src/cmd/go/testdata/script/gotoolchain_modcmds.txt new file mode 100644 index 0000000..1edd6d8 --- /dev/null +++ b/src/cmd/go/testdata/script/gotoolchain_modcmds.txt @@ -0,0 +1,45 @@ +env TESTGO_VERSION=go1.21.0 +env TESTGO_VERSION_SWITCH=switch + +# If the main module's go.mod file lists a version lower than the version +# required by its dependencies, the commands that fetch and diagnose the module +# graph (such as 'go mod graph' and 'go mod verify') should fail explicitly: +# they can't interpret the graph themselves, and they aren't allowed to update +# the go.mod file to record a specific, stable toolchain version that can. + +! go mod verify +stderr '^go: rsc.io/future@v1.0.0: module rsc.io/future@v1.0.0 requires go >= 1.999 \(running go 1.21.0\)' + +! go mod graph +stderr '^go: rsc.io/future@v1.0.0: module rsc.io/future@v1.0.0 requires go >= 1.999 \(running go 1.21.0\)' + +# TODO(#64008): 'go mod download' without arguments should fail too. + + +# 'go get' should update the main module's go.mod file to a version compatible with the +# go version required for rsc.io/future, not fail. +go get . +stderr '^go: module rsc.io/future@v1.0.0 requires go >= 1.999; switching to go1.999testmod$' +stderr '^go: upgraded go 1.21 => 1.999$' +stderr '^go: added toolchain go1.999testmod$' + + +# Now, the various 'go mod' subcommands should succeed. + +go mod download + +go mod verify + +go mod graph + + +-- go.mod -- +module example + +go 1.21 + +require rsc.io/future v1.0.0 +-- example.go -- +package example + +import _ "rsc.io/future" diff --git a/src/cmd/go/testdata/script/gotoolchain_net.txt b/src/cmd/go/testdata/script/gotoolchain_net.txt new file mode 100644 index 0000000..1d6473c --- /dev/null +++ b/src/cmd/go/testdata/script/gotoolchain_net.txt @@ -0,0 +1,70 @@ +# This test only checks that basic network lookups work. +# The full test of toolchain version selection is in gotoolchain.txt. + +# This test is sensitive to "new" Go experiments, so +# update the environment to remove any existing GOEXPERIMENT +# setting, see #62016 for more on this. +env GOEXPERIMENT='' + +env TESTGO_VERSION=go1.21actual + +# GOTOOLCHAIN from network, does not exist +env GOTOOLCHAIN=go1.9999x +! go version +stderr 'go: download go1.9999x for .*: toolchain not available' + +# GOTOOLCHAIN from network +[!exec:/bin/sh] stop 'the fake proxy serves shell scripts instead of binaries' +env GOTOOLCHAIN=go1.999testmod +go version +stderr 'go: downloading go1.999testmod \(.*/.*\)' + +# GOTOOLCHAIN cached from network +go version +! stderr downloading +stdout go1.999testmod + +# GOTOOLCHAIN with GOSUMDB enabled but at a bad URL should operate in cache and not try badurl +env oldsumdb=$GOSUMDB +env GOSUMDB=$oldsumdb' http://badurl' +go version +! stderr downloading +stdout go1.999testmod + +# GOTOOLCHAIN with GOSUMB=off should fail, because it cannot access even the cached sumdb info +# without the sumdb name. +env GOSUMDB=off +! go version +stderr '^go: golang.org/toolchain@v0.0.1-go1.999testmod.[a-z0-9\-]*: verifying module: checksum database disabled by GOSUMDB=off$' + +# GOTOOLCHAIN with GOSUMDB enabled but at a bad URL should fail if cache is incomplete +env GOSUMDB=$oldsumdb' http://badurl' +rm $GOPATH/pkg/mod/cache/download/sumdb +! go version +! stderr downloading +stderr 'panic: use of network' # test catches network access +env GOSUMDB=$oldsumdb + +# Test a real GOTOOLCHAIN +[short] skip +[!net:golang.org] skip +[!net:sum.golang.org] skip +[!GOOS:darwin] [!GOOS:windows] [!GOOS:linux] skip +[!GOARCH:amd64] [!GOARCH:arm64] skip + +env GOPROXY= +[go-builder] env GOSUMDB= +[!go-builder] env GOSUMDB=sum.golang.org # Set explicitly in case GOROOT/go.env is modified. +env GOTOOLCHAIN=go1.20.1 + + # Avoid resolving a "go1.20.1" from the user's real $PATH. + # That would not only cause the "downloading go1.20.1" message + # to be suppressed, but may spuriously fail: + # golang.org/dl/go1.20.1 expects to find its GOROOT in $HOME/sdk, + # but the script environment sets HOME=/no-home. +env PATH= +env path= + +go version +stderr '^go: downloading go1.20.1 ' +stdout go1.20.1 diff --git a/src/cmd/go/testdata/script/gotoolchain_path.txt b/src/cmd/go/testdata/script/gotoolchain_path.txt new file mode 100644 index 0000000..9628348 --- /dev/null +++ b/src/cmd/go/testdata/script/gotoolchain_path.txt @@ -0,0 +1,86 @@ +# This test only checks that basic PATH lookups work. +# The full test of toolchain version selection is in gotoolchain.txt. + +[short] skip + +env TESTGO_VERSION=go1.21pre3 + +# Compile a fake toolchain to put in the path under various names. +env GOTOOLCHAIN= +mkdir $WORK/bin +go build -o $WORK/bin/ ./fakego.go # adds .exe extension implicitly on Windows +cp $WORK/bin/fakego$GOEXE $WORK/bin/go1.50.0$GOEXE + +[!GOOS:plan9] env PATH=$WORK/bin +[GOOS:plan9] env path=$WORK/bin + +go version +stdout go1.21pre3 + +# GOTOOLCHAIN=go1.50.0 +env GOTOOLCHAIN=go1.50.0 +! go version +stderr 'running go1.50.0 from PATH' + +# GOTOOLCHAIN=path with toolchain line +env GOTOOLCHAIN=local +go mod init m +go mod edit -toolchain=go1.50.0 +grep go1.50.0 go.mod +env GOTOOLCHAIN=path +! go version +stderr 'running go1.50.0 from PATH' + +# GOTOOLCHAIN=path with go line +env GOTOOLCHAIN=local +go mod edit -toolchain=none -go=1.50.0 +grep 'go 1.50.0' go.mod +! grep toolchain go.mod +env GOTOOLCHAIN=path +! go version +stderr 'running go1.50.0 from PATH' + +# GOTOOLCHAIN=auto with toolchain line +env GOTOOLCHAIN=local +go mod edit -toolchain=go1.50.0 -go=1.21 +grep 'go 1.21$' go.mod +grep 'toolchain go1.50.0' go.mod +env GOTOOLCHAIN=auto +! go version +stderr 'running go1.50.0 from PATH' + +# GOTOOLCHAIN=auto with go line +env GOTOOLCHAIN=local +go mod edit -toolchain=none -go=1.50.0 +grep 'go 1.50.0$' go.mod +! grep toolchain go.mod +env GOTOOLCHAIN=auto +! go version +stderr 'running go1.50.0 from PATH' + +# NewerToolchain should find Go 1.50.0. +env GOTOOLCHAIN=local +go mod edit -toolchain=none -go=1.22 +grep 'go 1.22$' go.mod +! grep toolchain go.mod +env GOTOOLCHAIN=path +! go run rsc.io/fortune@v0.0.1 +stderr 'running go1.50.0 from PATH' + +-- fakego.go -- +package main + +import ( + "fmt" + "os" + "path/filepath" + "strings" +) + +func main() { + exe, _ := os.Executable() + name := filepath.Base(exe) + name = strings.TrimSuffix(name, ".exe") + fmt.Fprintf(os.Stderr, "running %s from PATH\n", name) + os.Exit(1) // fail in case we are running this accidentally (like in "go mod edit") +} diff --git a/src/cmd/go/testdata/script/gotoolchain_version.txt b/src/cmd/go/testdata/script/gotoolchain_version.txt new file mode 100644 index 0000000..e0736ff --- /dev/null +++ b/src/cmd/go/testdata/script/gotoolchain_version.txt @@ -0,0 +1,22 @@ +[!net:proxy.golang.org] skip + + # In the Go project's official release GOPROXY defaults to proxy.golang.org, + # but it may be changed in GOROOT/go.env (such as in third-party + # distributions). + # + # Make sure it is in use here, because the server for releases not served + # through the proxy (https://golang.org/toolchain?go-get=1) currently only + # serves the latest patch release for each of the supported stable releases. + +[go-builder] env GOPROXY= +[!go-builder] env GOPROXY=https://proxy.golang.org + +go list -m -versions go +stdout 1.20.1 # among others +stdout 1.19rc2 +! stdout go1.20.1 # no go prefixes +! stdout go1.19rc2 + +go list -m -versions toolchain +stdout go1.20.1 # among others +stdout go1.19rc2 diff --git a/src/cmd/go/testdata/script/govcs.txt b/src/cmd/go/testdata/script/govcs.txt new file mode 100644 index 0000000..876f606 --- /dev/null +++ b/src/cmd/go/testdata/script/govcs.txt @@ -0,0 +1,91 @@ +env GO111MODULE=on +env proxy=$GOPROXY +env GOPROXY=direct + +# GOVCS stops go get +env GOVCS='*:none' +! go get github.com/google/go-cmp +stderr '^go: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$' +env GOPRIVATE='github.com/google' +! go get github.com/google/go-cmp +stderr '^go: GOVCS disallows using git for private github.com/google/go-cmp; see ''go help vcs''$' + +# public pattern works +env GOPRIVATE='github.com/google' +env GOVCS='public:all,private:none' +! go get github.com/google/go-cmp +stderr '^go: GOVCS disallows using git for private github.com/google/go-cmp; see ''go help vcs''$' + +# private pattern works +env GOPRIVATE='hubgit.com/google' +env GOVCS='private:all,public:none' +! go get github.com/google/go-cmp +stderr '^go: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$' + +# other patterns work (for more patterns, see TestGOVCS) +env GOPRIVATE= +env GOVCS='github.com:svn|hg' +! go get github.com/google/go-cmp +stderr '^go: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$' +env GOVCS='github.com/google/go-cmp/inner:git,github.com:svn|hg' +! go get github.com/google/go-cmp +stderr '^go: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$' + +# bad patterns are reported (for more bad patterns, see TestGOVCSErrors) +env GOVCS='git' +! go get github.com/google/go-cmp +stderr '^go: github.com/google/go-cmp: malformed entry in GOVCS \(missing colon\): "git"$' + +env GOVCS=github.com:hg,github.com:git +! go get github.com/google/go-cmp +stderr '^go: github.com/google/go-cmp: unreachable pattern in GOVCS: "github.com:git" after "github.com:hg"$' + +# bad GOVCS patterns do not stop commands that do not need to check VCS +go list +env GOPROXY=$proxy +go get rsc.io/quote # ok because used proxy +env GOPROXY=direct + +# svn is disallowed by default +env GOPRIVATE= +env GOVCS= +! go get rsc.io/nonexist.svn/hello +stderr '^go: rsc.io/nonexist.svn/hello: GOVCS disallows using svn for public rsc.io/nonexist.svn; see ''go help vcs''$' + +# fossil is disallowed by default +env GOPRIVATE= +env GOVCS= +! go get rsc.io/nonexist.fossil/hello +stderr '^go: rsc.io/nonexist.fossil/hello: GOVCS disallows using fossil for public rsc.io/nonexist.fossil; see ''go help vcs''$' + +# bzr is disallowed by default +env GOPRIVATE= +env GOVCS= +! go get rsc.io/nonexist.bzr/hello +stderr '^go: rsc.io/nonexist.bzr/hello: GOVCS disallows using bzr for public rsc.io/nonexist.bzr; see ''go help vcs''$' + +# git is OK by default +env GOVCS= +env GONOSUMDB='*' +[net:rsc.io] [git] [!short] go get rsc.io/sampler + +# hg is OK by default +env GOVCS= +env GONOSUMDB='*' +[exec:hg] [!short] go get vcs-test.golang.org/go/custom-hg-hello + +# git can be disallowed +env GOVCS=public:hg +! go get rsc.io/nonexist.git/hello +stderr '^go: rsc.io/nonexist.git/hello: GOVCS disallows using git for public rsc.io/nonexist.git; see ''go help vcs''$' + +# hg can be disallowed +env GOVCS=public:git +! go get rsc.io/nonexist.hg/hello +stderr '^go: rsc.io/nonexist.hg/hello: GOVCS disallows using hg for public rsc.io/nonexist.hg; see ''go help vcs''$' + +-- go.mod -- +module m + +-- p.go -- +package p diff --git a/src/cmd/go/testdata/script/help.txt b/src/cmd/go/testdata/script/help.txt new file mode 100644 index 0000000..fb15e93 --- /dev/null +++ b/src/cmd/go/testdata/script/help.txt @@ -0,0 +1,51 @@ +env GO111MODULE=off + +# go help shows overview. +go help +stdout 'Go is a tool' +stdout 'bug.*start a bug report' + +# go help bug shows usage for bug +go help bug +stdout 'usage: go bug' +stdout 'bug report' + +# go bug help is an error (bug takes no arguments) +! go bug help +stderr 'bug takes no arguments' + +# go help mod shows mod subcommands +go help mod +stdout 'go mod <command>' +stdout tidy + +# go help mod tidy explains tidy +go help mod tidy +stdout 'usage: go mod tidy' + +# go mod help tidy does too +go mod help tidy +stdout 'usage: go mod tidy' + +# go mod --help doesn't print help but at least suggests it. +! go mod --help +stderr 'Run ''go help mod'' for usage.' + +# Earlier versions of Go printed the same as 'go -h' here. +# Also make sure we print the short help line. +! go vet -h +stderr 'usage: go vet .*' +stderr 'Run ''go help vet'' for details.' +stderr 'Run ''go tool vet help'' for a full list of flags and analyzers.' +stderr 'Run ''go tool vet -help'' for an overview.' + +# Earlier versions of Go printed a large document here, instead of these two +# lines. +! go test -h +stderr 'usage: go test' +stderr 'Run ''go help test'' and ''go help testflag'' for details.' + +# go help get shows usage for get +go help get +stdout 'usage: go get' +stdout 'specific module versions' diff --git a/src/cmd/go/testdata/script/import_cycle.txt b/src/cmd/go/testdata/script/import_cycle.txt new file mode 100644 index 0000000..901f43c --- /dev/null +++ b/src/cmd/go/testdata/script/import_cycle.txt @@ -0,0 +1,12 @@ +env GO111MODULE=off + +! go build selfimport +stderr -count=1 'import cycle not allowed' + +# 'go list' shouldn't hang forever. +go list -e -json selfimport + +-- $GOPATH/src/selfimport/selfimport.go -- +package selfimport + +import "selfimport" diff --git a/src/cmd/go/testdata/script/import_ignore.txt b/src/cmd/go/testdata/script/import_ignore.txt new file mode 100644 index 0000000..83a39a0 --- /dev/null +++ b/src/cmd/go/testdata/script/import_ignore.txt @@ -0,0 +1,11 @@ +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +-- go.mod -- +module m.test + +go 1.16 +-- .ignore.go -- +package p +import _ "golang.org/x/mod/modfile"
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/import_main.txt b/src/cmd/go/testdata/script/import_main.txt new file mode 100644 index 0000000..bc2cc4d --- /dev/null +++ b/src/cmd/go/testdata/script/import_main.txt @@ -0,0 +1,114 @@ +env GO111MODULE=off + +# Test that you cannot import a main package. +# See golang.org/issue/4210 and golang.org/issue/17475. + +[short] skip +cd $WORK + +# Importing package main from that package main's test should work. +go build x +go test -c x + +# Importing package main from another package should fail. +! go build p1 +stderr 'import "x" is a program, not an importable package' + +# ... even in that package's test. +go build p2 +! go test -c p2 +stderr 'import "x" is a program, not an importable package' + +# ... even if that package's test is an xtest. +go build p3 +! go test p3 +stderr 'import "x" is a program, not an importable package' + +# ... even if that package is a package main +go build p4 +! go test -c p4 +stderr 'import "x" is a program, not an importable package' + +# ... even if that package is a package main using an xtest. +go build p5 +! go test -c p5 +stderr 'import "x" is a program, not an importable package' + +-- x/main.go -- +package main + +var X int + +func main() {} +-- x/main_test.go -- +package main_test + +import ( + "testing" + xmain "x" +) + +var _ = xmain.X + +func TestFoo(t *testing.T) {} +-- p1/p.go -- +package p1 + +import xmain "x" + +var _ = xmain.X +-- p2/p.go -- +package p2 +-- p2/p_test.go -- +package p2 + +import ( + "testing" + xmain "x" +) + +var _ = xmain.X + +func TestFoo(t *testing.T) {} +-- p3/p.go -- +package p +-- p3/p_test.go -- +package p_test + +import ( + "testing" + xmain "x" +) + +var _ = xmain.X + +func TestFoo(t *testing.T) {} +-- p4/p.go -- +package main + +func main() {} +-- p4/p_test.go -- +package main + +import ( + "testing" + xmain "x" +) + +var _ = xmain.X + +func TestFoo(t *testing.T) {} +-- p5/p.go -- +package main +func main() {} +-- p5/p_test.go -- +package main_test + +import ( + "testing" + xmain "x" +) + +var _ = xmain.X + +func TestFoo(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/import_unix_tag.txt b/src/cmd/go/testdata/script/import_unix_tag.txt new file mode 100644 index 0000000..b88ca1e --- /dev/null +++ b/src/cmd/go/testdata/script/import_unix_tag.txt @@ -0,0 +1,32 @@ +# Regression test for https://go.dev/issue/54712: the "unix" build constraint +# was not applied consistently during package loading. + +go list -x -f '{{if .Module}}{{.ImportPath}}{{end}}' -deps . +stdout 'example.com/version' + +-- go.mod -- +module example + +go 1.19 + +require example.com/version v1.1.0 +-- go.sum -- +example.com/version v1.1.0 h1:VdPnGmIF1NJrntStkxGrF3L/OfhaL567VzCjncGUgtM= +example.com/version v1.1.0/go.mod h1:S7K9BnT4o5wT4PCczXPfWVzpjD4ud4e7AJMQJEgiu2Q= +-- main_notunix.go -- +//go:build !(aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris) + +package main + +import _ "example.com/version" + +func main() {} + +-- main_unix.go -- +//go:build unix + +package main + +import _ "example.com/version" + +func main() {} diff --git a/src/cmd/go/testdata/script/index.txt b/src/cmd/go/testdata/script/index.txt new file mode 100644 index 0000000..6a2d13c --- /dev/null +++ b/src/cmd/go/testdata/script/index.txt @@ -0,0 +1,6 @@ +# Check that standard library packages are cached. +go list -json math # refresh cache +env GODEBUG=gofsystrace=1,gofsystracelog=fsys.log +go list -json math +! grep math/abs.go fsys.log +grep 'openIndexPackage .*[\\/]math$' fsys.log diff --git a/src/cmd/go/testdata/script/install_cgo_excluded.txt b/src/cmd/go/testdata/script/install_cgo_excluded.txt new file mode 100644 index 0000000..5a2b460 --- /dev/null +++ b/src/cmd/go/testdata/script/install_cgo_excluded.txt @@ -0,0 +1,15 @@ +env CGO_ENABLED=0 + +! go install cgotest +stderr 'build constraints exclude all Go files' + +-- go.mod -- +module cgotest + +go 1.16 +-- m.go -- +package cgotest + +import "C" + +var _ C.int diff --git a/src/cmd/go/testdata/script/install_cleans_build.txt b/src/cmd/go/testdata/script/install_cleans_build.txt new file mode 100644 index 0000000..dc85eb8 --- /dev/null +++ b/src/cmd/go/testdata/script/install_cleans_build.txt @@ -0,0 +1,25 @@ +env GO111MODULE=off +[short] skip + +# 'go install' with no arguments should clean up after go build +cd mycmd +go build +exists mycmd$GOEXE +go install +! exists mycmd$GOEXE + +# 'go install mycmd' does not clean up, even in the mycmd directory +go build +exists mycmd$GOEXE +go install mycmd +exists mycmd$GOEXE + +# 'go install mycmd' should not clean up in an unrelated current directory either +cd .. +cp mycmd/mycmd$GOEXE mycmd$GOEXE +go install mycmd +exists mycmd$GOEXE + +-- mycmd/main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/install_cmd_gobin.txt b/src/cmd/go/testdata/script/install_cmd_gobin.txt new file mode 100644 index 0000000..049bf41 --- /dev/null +++ b/src/cmd/go/testdata/script/install_cmd_gobin.txt @@ -0,0 +1,10 @@ +# Check that commands in cmd are install to $GOROOT/bin, not $GOBIN. +# Verifies golang.org/issue/32674. +env GOBIN=gobin +mkdir gobin +go list -f '{{.Target}}' cmd/go +stdout $GOROOT${/}bin${/}go$GOEXE + +# Check that tools are installed to $GOTOOLDIR, not $GOBIN. +go list -f '{{.Target}}' cmd/compile +stdout $GOROOT${/}pkg${/}tool${/}${GOOS}_${GOARCH}${/}compile$GOEXE diff --git a/src/cmd/go/testdata/script/install_cross_gobin.txt b/src/cmd/go/testdata/script/install_cross_gobin.txt new file mode 100644 index 0000000..7679a7e --- /dev/null +++ b/src/cmd/go/testdata/script/install_cross_gobin.txt @@ -0,0 +1,25 @@ +env GO111MODULE=off +[short] skip # rebuilds std for alternate architecture + +cd mycmd +go build mycmd + +# cross-compile install with implicit GOBIN=$GOPATH/bin can make subdirectory +env GOARCH=386 +[GOARCH:386] env GOARCH=amd64 +env GOOS=linux +go install mycmd +exists $GOPATH/bin/linux_$GOARCH/mycmd + +# cross-compile install with explicit GOBIN cannot make subdirectory +env GOBIN=$WORK/bin +! go install mycmd +! exists $GOBIN/linux_$GOARCH + +# The install directory for a cross-compiled standard command should include GOARCH. +go list -f '{{.Target}}' cmd/pack +stdout ${GOROOT}[/\\]pkg[/\\]tool[/\\]${GOOS}_${GOARCH}[/\\]pack$ + +-- mycmd/x.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/install_dep_version.txt b/src/cmd/go/testdata/script/install_dep_version.txt new file mode 100644 index 0000000..58330e6 --- /dev/null +++ b/src/cmd/go/testdata/script/install_dep_version.txt @@ -0,0 +1,8 @@ +# Regression test for Issue #54908. When running a go install module@version +# with --mod=readonly moduleInfo was not setting the GoVersion for the module +# because the checksumOk function was failing because modfetch.GoSumFile +# was not set when running outside of a module. + +env GOTOOLCHAIN=local + +go install --mod=readonly example.com/depends/on/generics@v1.0.0
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/install_goroot_targets.txt b/src/cmd/go/testdata/script/install_goroot_targets.txt new file mode 100644 index 0000000..f26ee82 --- /dev/null +++ b/src/cmd/go/testdata/script/install_goroot_targets.txt @@ -0,0 +1,27 @@ +[short] skip + +# Packages in std do not have an install target. +go list -f '{{.Target}}' fmt +! stdout . +go list -export -f '{{.Export}}' fmt +stdout $GOCACHE + +# With GODEBUG=installgoroot=all, fmt has a target. +# (Though we can't try installing it without modifying goroot). +env GODEBUG=installgoroot=all +go list -f '{{.Target}}' fmt +stdout fmt\.a + +# However, the fake packages "builtin" and "unsafe" do not. +go list -f '{{.Target}}' builtin unsafe +! stdout . +go install builtin unsafe # Should succeed as no-ops. + +# With CGO_ENABLED=0, packages that would have +# an install target with cgo on no longer do. +env GODEBUG= +env CGO_ENABLED=0 +go list -f '{{.Target}}' runtime/cgo +! stdout . +go list -export -f '{{.Export}}' runtime/cgo +stdout $GOCACHE diff --git a/src/cmd/go/testdata/script/install_modcacherw_issue64282.txt b/src/cmd/go/testdata/script/install_modcacherw_issue64282.txt new file mode 100644 index 0000000..3e1e6e5 --- /dev/null +++ b/src/cmd/go/testdata/script/install_modcacherw_issue64282.txt @@ -0,0 +1,45 @@ +# Regression test for https://go.dev/issue/64282. +# +# 'go install' and 'go run' with pkg@version arguments should make +# a best effort to parse flags relevant to downloading modules +# (currently only -modcacherw) before actually downloading the module +# to identify which toolchain version to use. +# +# However, the best-effort flag parsing should not interfere with +# actual flag parsing if we don't switch toolchains. In particular, +# unrecognized flags should still be diagnosed after the module for +# the requested package has been downloaded and checked for toolchain +# upgrades. + + +! go install -cake=delicious -modcacherw example.com/printversion@v0.1.0 +stderr '^flag provided but not defined: -cake$' + # Because the -modcacherw flag was set, we should be able to modify the contents + # of a directory within the module cache. +cp $WORK/extraneous.txt $GOPATH/pkg/mod/example.com/printversion@v0.1.0/extraneous_file.go +go clean -modcache + + +! go install -unknownflag -tags -modcacherw example.com/printversion@v0.1.0 +stderr '^flag provided but not defined: -unknownflag$' +cp $WORK/extraneous.txt $GOPATH/pkg/mod/example.com/printversion@v0.1.0/extraneous_file.go +go clean -modcache + + +# Also try it with a 'go install' that succeeds. +# (But skip in short mode, because linking a binary is expensive.) +[!short] go install -modcacherw example.com/printversion@v0.1.0 +[!short] cp $WORK/extraneous.txt $GOPATH/pkg/mod/example.com/printversion@v0.1.0/extraneous_file.go +[!short] go clean -modcache + + +# The flag should also be applied if given in GOFLAGS +# instead of on the command line. +env GOFLAGS=-modcacherw +! go install -cake=delicious example.com/printversion@v0.1.0 +stderr '^flag provided but not defined: -cake$' +cp $WORK/extraneous.txt $GOPATH/pkg/mod/example.com/printversion@v0.1.0/extraneous_file.go + + +-- $WORK/extraneous.txt -- +This is not a Go source file. diff --git a/src/cmd/go/testdata/script/install_move_not_stale.txt b/src/cmd/go/testdata/script/install_move_not_stale.txt new file mode 100644 index 0000000..de191cf --- /dev/null +++ b/src/cmd/go/testdata/script/install_move_not_stale.txt @@ -0,0 +1,26 @@ +# Check to see that the distribution is not stale +# even when it's been moved to a different directory. +# Simulate that by creating a symlink to the tree. + +# We use net instead of std because stale std has +# the behavior of checking that all std targets +# are stale rather than any of them. + +[!symlink] skip +[short] skip + +go build net +! stale net + +symlink new -> $GOROOT +env OLDGOROOT=$GOROOT +env GOROOT=$WORK${/}gopath${/}src${/}new +go env GOROOT +stdout $WORK[\\/]gopath[\\/]src[\\/]new +cd new +! stale net + +# Add a control case to check that std is +# stale with an empty cache +env GOCACHE=$WORK${/}gopath${/}cache +stale net diff --git a/src/cmd/go/testdata/script/install_msan_and_race_and_asan_require_cgo.txt b/src/cmd/go/testdata/script/install_msan_and_race_and_asan_require_cgo.txt new file mode 100644 index 0000000..d8f2aba --- /dev/null +++ b/src/cmd/go/testdata/script/install_msan_and_race_and_asan_require_cgo.txt @@ -0,0 +1,22 @@ +# Tests Issue #21895 + +env CGO_ENABLED=0 + +[GOOS:darwin] [!short] [race] go build -race triv.go + +[!GOOS:darwin] [race] ! go install -race triv.go +[!GOOS:darwin] [race] stderr '-race requires cgo' +[!GOOS:darwin] [race] ! stderr '-msan' + +[msan] ! go install -msan triv.go +[msan] stderr '-msan requires cgo' +[msan] ! stderr '-race' + +[asan] ! go install -asan triv.go +[asan] stderr '(-asan: the version of $(go env CC) could not be parsed)|(-asan: C compiler is not gcc or clang)|(-asan is not supported with [A-Za-z]+ compiler (\d+)\.(\d+))|(-asan requires cgo)' +[asan] ! stderr '-msan' + +-- triv.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/install_rebuild_removed.txt b/src/cmd/go/testdata/script/install_rebuild_removed.txt new file mode 100644 index 0000000..5db3778 --- /dev/null +++ b/src/cmd/go/testdata/script/install_rebuild_removed.txt @@ -0,0 +1,44 @@ +env GO111MODULE=off + +# go command should detect package staleness as source file set changes +go install mypkg +! stale mypkg + +# z.go was not compiled; removing it should NOT make mypkg stale +rm mypkg/z.go +! stale mypkg + +# y.go was compiled; removing it should make mypkg stale +rm mypkg/y.go +stale mypkg + +# go command should detect executable staleness too +go install mycmd +! stale mycmd +rm mycmd/z.go +! stale mycmd +rm mycmd/y.go +stale mycmd + +-- mypkg/x.go -- +package mypkg + +-- mypkg/y.go -- +package mypkg + +-- mypkg/z.go -- +// +build missingtag + +package mypkg + +-- mycmd/x.go -- +package main +func main() {} + +-- mycmd/y.go -- +package main + +-- mycmd/z.go -- +// +build missingtag + +package main diff --git a/src/cmd/go/testdata/script/install_relative_gobin_fail.txt b/src/cmd/go/testdata/script/install_relative_gobin_fail.txt new file mode 100644 index 0000000..aa14524 --- /dev/null +++ b/src/cmd/go/testdata/script/install_relative_gobin_fail.txt @@ -0,0 +1,12 @@ +env GOBIN=. +! go install +stderr 'cannot install, GOBIN must be an absolute path' + +-- go.mod -- +module triv + +go 1.16 +-- triv.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/install_shadow_gopath.txt b/src/cmd/go/testdata/script/install_shadow_gopath.txt new file mode 100644 index 0000000..148e6cc --- /dev/null +++ b/src/cmd/go/testdata/script/install_shadow_gopath.txt @@ -0,0 +1,18 @@ +# Tests Issue #3562 +# go get foo.io (not foo.io/subdir) was not working consistently. + +env GO111MODULE=off +env GOPATH=$WORK/gopath1${:}$WORK/gopath2 + +mkdir $WORK/gopath1/src/test +mkdir $WORK/gopath2/src/test +cp main.go $WORK/gopath2/src/test/main.go +cd $WORK/gopath2/src/test + +! go install +stderr 'no install location for.*gopath2.src.test: hidden by .*gopath1.src.test' + +-- main.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/issue36000.txt b/src/cmd/go/testdata/script/issue36000.txt new file mode 100644 index 0000000..4173275 --- /dev/null +++ b/src/cmd/go/testdata/script/issue36000.txt @@ -0,0 +1,6 @@ +# Tests golang.org/issue/36000 + +[!cgo] skip + +# go env with CGO flags should not make NUL file +go env CGO_CFLAGS diff --git a/src/cmd/go/testdata/script/issue53586.txt b/src/cmd/go/testdata/script/issue53586.txt new file mode 100644 index 0000000..db405cd --- /dev/null +++ b/src/cmd/go/testdata/script/issue53586.txt @@ -0,0 +1,18 @@ +[short] skip # sleeps to make mtime cacheable + +go mod init example + +cd subdir +go mod init example/subdir +sleep 2s # allow go.mod mtime to be cached + +go list -f '{{.Dir}}: {{.ImportPath}}' ./pkg +stdout $PWD${/}pkg': example/subdir/pkg$' + +rm go.mod # expose ../go.mod + +go list -f '{{.Dir}}: {{.ImportPath}}' ./pkg +stdout $PWD${/}pkg': example/subdir/pkg$' + +-- subdir/pkg/pkg.go -- +package pkg diff --git a/src/cmd/go/testdata/script/ldflag.txt b/src/cmd/go/testdata/script/ldflag.txt new file mode 100644 index 0000000..6ceb33b --- /dev/null +++ b/src/cmd/go/testdata/script/ldflag.txt @@ -0,0 +1,44 @@ +# Issue #42565 + +[!cgo] skip + +# We can't build package bad, which uses #cgo LDFLAGS. +cd bad +! go build +stderr no-such-warning + +# We can build package ok with the same flags in CGO_LDFLAGS. +env CGO_LDFLAGS=-Wno-such-warning -Wno-unknown-warning-option +cd ../ok +go build + +# Build a main program that actually uses LDFLAGS. +cd .. +go build -ldflags=-v + +# Because we passed -v the Go linker should print the external linker +# command which should include the flag we passed in CGO_LDFLAGS. +stderr no-such-warning + +-- go.mod -- +module ldflag + +-- bad/bad.go -- +package bad + +// #cgo LDFLAGS: -Wno-such-warning -Wno-unknown-warning +import "C" + +func F() {} +-- ok/ok.go -- +package ok + +import "C" + +func F() {} +-- main.go -- +package main + +import _ "ldflag/ok" + +func main() {} diff --git a/src/cmd/go/testdata/script/link_external_undef.txt b/src/cmd/go/testdata/script/link_external_undef.txt new file mode 100644 index 0000000..f320505 --- /dev/null +++ b/src/cmd/go/testdata/script/link_external_undef.txt @@ -0,0 +1,48 @@ + +# Test case for issue 47993, in which the linker crashes +# on a bad input instead of issuing an error and exiting. + +# This test requires external linking, so use cgo as a proxy +[!cgo] skip + +! go build -ldflags='-linkmode=external' . +! stderr 'panic' +stderr '^.*undefined symbol in relocation.*' + +-- go.mod -- + +module issue47993 + +go 1.16 + +-- main.go -- + +package main + +type M struct { + b bool +} + +// Note the body-less func def here. This is what causes the problems. +func (m *M) run(fp func()) + +func doit(m *M) { + InAsm() + m.run(func() { + }) +} + +func main() { + m := &M{true} + doit(m) +} + +func InAsm() + +-- main.s -- + +// Add an assembly function so as to leave open the possibility +// that body-less functions in Go might be defined in assembly. + +// Currently we just need an empty file here. + diff --git a/src/cmd/go/testdata/script/link_matching_actionid.txt b/src/cmd/go/testdata/script/link_matching_actionid.txt new file mode 100644 index 0000000..b8d423d --- /dev/null +++ b/src/cmd/go/testdata/script/link_matching_actionid.txt @@ -0,0 +1,38 @@ +# Checks that an identical binary is built with -trimpath from the same +# source files, with GOROOT in two different locations. +# Verifies golang.org/issue/38989 + +[short] skip +[!symlink] skip + +# Symlink the compiler to a local path +env GOROOT=$WORK/goroot1 +symlink $GOROOT -> $TESTGO_GOROOT + +# Set up fresh GOCACHE +env GOCACHE=$WORK/gocache1 +mkdir $GOCACHE + +# Build a simple binary +go build -o binary1 -trimpath -x main.go + +# Now repeat the same process with the compiler at a different local path +env GOROOT=$WORK/goroot2 +symlink $GOROOT -> $TESTGO_GOROOT + +env GOCACHE=$WORK/gocache2 +mkdir $GOCACHE + +go build -o binary2 -trimpath -x main.go + +# Check that the binaries match exactly +go tool buildid binary1 +cp stdout buildid1 +go tool buildid binary2 +cp stdout buildid2 +cmp buildid1 buildid2 + + +-- main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/link_syso_deps.txt b/src/cmd/go/testdata/script/link_syso_deps.txt new file mode 100644 index 0000000..6bb9005 --- /dev/null +++ b/src/cmd/go/testdata/script/link_syso_deps.txt @@ -0,0 +1,55 @@ +# Test that syso in deps is available to cgo. + +[!compiler:gc] skip 'requires syso support' +[!cgo] skip +[short] skip 'invokes system C compiler' + +# External linking is not supported on linux/ppc64. +# See: https://github.com/golang/go/issues/8912 +[GOOS:linux] [GOARCH:ppc64] skip + +cc -c -o syso/x.syso syso/x.c +cc -c -o syso2/x.syso syso2/x.c +go build m/cgo + +-- go.mod -- +module m + +go 1.18 +-- cgo/x.go -- +package cgo + +// extern void f(void); +// extern void g(void); +import "C" + +func F() { + C.f() +} + +func G() { + C.g() +} + +-- cgo/x2.go -- +package cgo + +import _ "m/syso" + +-- syso/x.c -- +//go:build ignore + +void f() {} + +-- syso/x.go -- +package syso + +import _ "m/syso2" + +-- syso2/x.c -- +//go:build ignore + +void g() {} + +-- syso2/x.go -- +package syso2 diff --git a/src/cmd/go/testdata/script/link_syso_issue33139.txt b/src/cmd/go/testdata/script/link_syso_issue33139.txt new file mode 100644 index 0000000..b0d4a7c --- /dev/null +++ b/src/cmd/go/testdata/script/link_syso_issue33139.txt @@ -0,0 +1,45 @@ +# Test that we can use the external linker with a host syso file that is +# embedded in a package, that is referenced by a Go assembly function. +# See issue 33139. + +[!compiler:gc] skip +[!cgo] skip +[short] skip 'invokes system C compiler' + +# External linking is not supported on linux/ppc64. +# See: https://github.com/golang/go/issues/8912 +[GOOS:linux] [GOARCH:ppc64] skip + +cc -c -o syso/objTestImpl.syso syso/src/objTestImpl.c +go build -ldflags='-linkmode=external' ./cmd/main.go + +-- go.mod -- +module m + +go 1.16 +-- syso/objTest.s -- +#include "textflag.h" + +TEXT ·ObjTest(SB), NOSPLIT, $0 + // We do not actually execute this function in the test above, thus + // there is no stack frame setup here. + // We only care about Go build and/or link errors when referencing + // the objTestImpl symbol in the syso file. + JMP objTestImpl(SB) + +-- syso/pkg.go -- +package syso + +func ObjTest() + +-- syso/src/objTestImpl.c -- +void objTestImpl() { /* Empty */ } + +-- cmd/main.go -- +package main + +import "m/syso" + +func main() { + syso.ObjTest() +} diff --git a/src/cmd/go/testdata/script/linkname.txt b/src/cmd/go/testdata/script/linkname.txt new file mode 100644 index 0000000..36ac8eb --- /dev/null +++ b/src/cmd/go/testdata/script/linkname.txt @@ -0,0 +1,9 @@ +env GO111MODULE=off + +# check for linker name in error message about linker crash +[!compiler:gc] skip +! go build -ldflags=-crash_for_testing x.go +stderr [\\/]tool[\\/].*[\\/]link + +-- x.go -- +package main; func main() {} diff --git a/src/cmd/go/testdata/script/list_all_gobuild.txt b/src/cmd/go/testdata/script/list_all_gobuild.txt new file mode 100644 index 0000000..92ad7d8 --- /dev/null +++ b/src/cmd/go/testdata/script/list_all_gobuild.txt @@ -0,0 +1,42 @@ +# go list all should work with GOOS=linux because all packages build on Linux +env GOOS=linux +env GOARCH=amd64 +go list all + +# go list all should work with GOOS=darwin, but it used to fail because +# in the absence of //go:build support, p looked like it needed q +# (p_test.go was not properly excluded), and q was Linux-only. +# +# Also testing with r and s that +build lines keep working. +env GOOS=darwin +go list all + +-- go.mod -- +go 1.17 +module m + +-- p/p.go -- +package p + +-- p/p_test.go -- +//go:build linux + +package p + +import "m/q" + +-- q/q_linux.go -- +package q + +-- r/r.go -- +package r + +-- r/r_test.go -- +// +build linux + +package r + +import "m/s" + +-- s/s_linux.go -- +package s diff --git a/src/cmd/go/testdata/script/list_ambiguous_path.txt b/src/cmd/go/testdata/script/list_ambiguous_path.txt new file mode 100644 index 0000000..6f22314 --- /dev/null +++ b/src/cmd/go/testdata/script/list_ambiguous_path.txt @@ -0,0 +1,38 @@ +# Ensures that we can correctly list package patterns ending in '.go'. +# See golang.org/issue/34653. + +# A single pattern for a package ending in '.go'. +go list ./foo.go +stdout '^test/foo.go$' + +# Multiple patterns for packages including one ending in '.go'. +go list ./bar ./foo.go +stdout '^test/bar$' +stdout '^test/foo.go$' + +# A single pattern for a Go file. +go list ./a.go +stdout '^command-line-arguments$' + +# A single typo-ed pattern for a Go file. This should +# treat the wrong pattern as if it were a package. +! go list ./foo.go/b.go +stderr '^stat .*[/\\]foo\.go[/\\]b\.go: directory not found$' + +# Multiple patterns for Go files with a typo. This should +# treat the wrong pattern as if it were a nonexistent file. +! go list ./foo.go/a.go ./foo.go/b.go +[GOOS:plan9] stderr 'stat ./foo.go/b.go: ''./foo.go/b.go'' does not exist' +[GOOS:windows] stderr './foo.go/b.go: The system cannot find the file specified' +[!GOOS:plan9] [!GOOS:windows] stderr './foo.go/b.go: no such file or directory' + +-- a.go -- +package main +-- bar/a.go -- +package bar +-- foo.go/a.go -- +package foo.go +-- go.mod -- +module "test" + +go 1.13 diff --git a/src/cmd/go/testdata/script/list_bad_import.txt b/src/cmd/go/testdata/script/list_bad_import.txt new file mode 100644 index 0000000..dbec350 --- /dev/null +++ b/src/cmd/go/testdata/script/list_bad_import.txt @@ -0,0 +1,72 @@ +env GO111MODULE=off +[short] skip + +# This test matches mod_list_bad_import, but in GOPATH mode. +# Please keep them in sync. + +env GO111MODULE=off +cd example.com + +# Without -e, listing an otherwise-valid package with an unsatisfied direct import should fail. +# BUG: Today it succeeds. +go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}} {{range .DepsErrors}}bad dep: {{.Err}}{{end}}' example.com/direct +! stdout ^error +stdout 'incomplete' +stdout 'bad dep: .*example.com[/\\]notfound' + +# Listing with -deps should also fail. +! go list -deps example.com/direct +stderr example.com[/\\]notfound + +# But -e -deps should succeed. +go list -e -deps example.com/direct +stdout example.com/notfound + + +# Listing an otherwise-valid package that imports some *other* package with an +# unsatisfied import should also fail. +# BUG: Today, it succeeds. +go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}} {{range .DepsErrors}}bad dep: {{.Err}}{{end}}' example.com/indirect +! stdout ^error +stdout incomplete +stdout 'bad dep: .*example.com[/\\]notfound' + +# Again, -deps should fail. +! go list -deps example.com/indirect +stderr example.com[/\\]notfound + +# But -deps -e should succeed. +go list -e -deps example.com/indirect +stdout example.com/notfound + + +# Listing the missing dependency directly should fail outright... +! go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound +stderr 'no Go files in .*example.com[/\\]notfound' +! stdout error +! stdout incomplete + +# ...but listing with -e should succeed. +go list -e -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound +stdout error +stdout incomplete + + +# The pattern "all" should match only packages that actually exist, +# ignoring those whose existence is merely implied by imports. +go list -e -f '{{.ImportPath}}' all +stdout example.com/direct +stdout example.com/indirect +! stdout example.com/notfound + + +-- example.com/direct/direct.go -- +package direct +import _ "example.com/notfound" + +-- example.com/indirect/indirect.go -- +package indirect +import _ "example.com/direct" + +-- example.com/notfound/README -- +This directory intentionally left blank. diff --git a/src/cmd/go/testdata/script/list_case_collision.txt b/src/cmd/go/testdata/script/list_case_collision.txt new file mode 100644 index 0000000..181a202 --- /dev/null +++ b/src/cmd/go/testdata/script/list_case_collision.txt @@ -0,0 +1,41 @@ +# Tests golang.org/issue/4773 + +go list -json example/a +stdout 'case-insensitive import collision' + +! go build example/a +stderr 'case-insensitive import collision' + +# List files explicitly on command line, to encounter case-checking +# logic even on case-insensitive filesystems. +cp b/file.go b/FILE.go # no-op on case-insensitive filesystems +! go list b/file.go b/FILE.go +stderr 'case-insensitive file name collision' + +mkdir a/Pkg # no-op on case-insensitive filesystems +cp a/pkg/pkg.go a/Pkg/pkg.go # no-op on case-insensitive filesystems +! go list example/a/pkg example/a/Pkg + +# Test that the path reported with an indirect import is correct. +cp b/file.go b/FILE.go +[case-sensitive] ! go build example/c +[case-sensitive] stderr '^package example/c\n\timports example/b: case-insensitive file name collision: "FILE.go" and "file.go"$' + +-- go.mod -- +module example + +go 1.16 +-- a/a.go -- +package p +import ( + _ "example/a/pkg" + _ "example/a/Pkg" +) +-- a/pkg/pkg.go -- +package pkg +-- b/file.go -- +package b +-- c/c.go -- +package c + +import _ "example/b" diff --git a/src/cmd/go/testdata/script/list_cgo_compiled_importmap.txt b/src/cmd/go/testdata/script/list_cgo_compiled_importmap.txt new file mode 100644 index 0000000..8693339 --- /dev/null +++ b/src/cmd/go/testdata/script/list_cgo_compiled_importmap.txt @@ -0,0 +1,41 @@ +# Regression test for https://golang.org/issue/46462. +# +# The "runtime/cgo" import found in synthesized .go files (reported in +# the CompiledGoFiles field) should have a corresponding entry in the +# ImportMap field when a runtime/cgo variant (such as a test variant) +# will be used. + +[short] skip # -compiled can be slow (because it compiles things) +[!cgo] skip +[GOOS:darwin] skip # net package does not import "C" on Darwin +[GOOS:windows] skip # net package does not import "C" on Windows +[GOOS:plan9] skip # net package does not import "C" on Plan 9 + +env CGO_ENABLED=1 +env GOFLAGS=-tags=netcgo # Force net to use cgo + + +# "runtime/cgo [runtime.test]" appears in the test dependencies of "runtime", +# because "runtime/cgo" itself depends on "runtime" + +go list -deps -test -compiled -f '{{if eq .ImportPath "net [runtime.test]"}}{{printf "%q" .Imports}}{{end}}' runtime + + # Control case: the explicitly-imported package "sync" is a test variant, + # because "sync" depends on "runtime". +stdout '"sync \[runtime\.test\]"' +! stdout '"sync"' + + # Experiment: the implicitly-imported package "runtime/cgo" is also a test variant, + # because "runtime/cgo" also depends on "runtime". +stdout '"runtime/cgo \[runtime\.test\]"' +! stdout '"runtime/cgo"' + + +# Because the import of "runtime/cgo" in the cgo-generated file actually refers +# to "runtime/cgo [runtime.test]", the latter should be listed in the ImportMap. +# BUG(#46462): Today, it is not. + +go list -deps -test -compiled -f '{{if eq .ImportPath "net [runtime.test]"}}{{printf "%q" .ImportMap}}{{end}}' runtime + +stdout '"sync":"sync \[runtime\.test\]"' # control +stdout '"runtime/cgo":"runtime/cgo \[runtime\.test\]"' # experiment diff --git a/src/cmd/go/testdata/script/list_compiled_files_issue28749.txt b/src/cmd/go/testdata/script/list_compiled_files_issue28749.txt new file mode 100644 index 0000000..e0fb977 --- /dev/null +++ b/src/cmd/go/testdata/script/list_compiled_files_issue28749.txt @@ -0,0 +1,10 @@ +go list -compiled -f {{.CompiledGoFiles}} . +! stdout 'foo.s' + +-- go.mod -- +module example.com/foo + +go 1.20 +-- foo.go -- +package foo +-- foo.s -- diff --git a/src/cmd/go/testdata/script/list_compiled_imports.txt b/src/cmd/go/testdata/script/list_compiled_imports.txt new file mode 100644 index 0000000..7780b07 --- /dev/null +++ b/src/cmd/go/testdata/script/list_compiled_imports.txt @@ -0,0 +1,31 @@ +env GO111MODULE=off + +[!cgo] skip + +# go list should report import "C" +cd x +go list -f '{{.Imports}}' +! stdout runtime/cgo +! stdout unsafe +! stdout syscall +stdout C +stdout unicode +stdout unicode/utf16 + +# go list -compiled should report imports in compiled files as well, +# adding "runtime/cgo", "unsafe", and "syscall" but not dropping "C". +go list -compiled -f '{{.Imports}}' +stdout runtime/cgo +stdout unsafe +stdout syscall +stdout C +stdout unicode +stdout unicode/utf16 + +-- x/x.go -- +package x +import "C" +import "unicode" // does not use unsafe, syscall, runtime/cgo, unicode/utf16 +-- x/x1.go -- +package x +import "unicode/utf16" // does not use unsafe, syscall, runtime/cgo, unicode diff --git a/src/cmd/go/testdata/script/list_compiler_output.txt b/src/cmd/go/testdata/script/list_compiler_output.txt new file mode 100644 index 0000000..5230bab --- /dev/null +++ b/src/cmd/go/testdata/script/list_compiler_output.txt @@ -0,0 +1,16 @@ +[short] skip + +go install -gcflags=-m . +stderr 'can inline main' +go list -gcflags=-m -f '{{.Stale}}' . +stdout 'false' +! stderr 'can inline main' + +-- go.mod -- +module example.com/foo + +go 1.20 +-- main.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/list_constraints.txt b/src/cmd/go/testdata/script/list_constraints.txt new file mode 100644 index 0000000..7115c36 --- /dev/null +++ b/src/cmd/go/testdata/script/list_constraints.txt @@ -0,0 +1,86 @@ +# Check that files and their imports are not included in 'go list' output +# when they are excluded by build constraints. + +# Linux and cgo files should be included when building in that configuration. +env GOOS=linux +env GOARCH=amd64 +env CGO_ENABLED=1 +go list -f '{{range .GoFiles}}{{.}} {{end}}' +stdout '^cgotag.go empty.go suffix_linux.go tag.go $' +go list -f '{{range .CgoFiles}}{{.}} {{end}}' +stdout '^cgoimport.go $' +go list -f '{{range .Imports}}{{.}} {{end}}' +stdout '^C cgoimport cgotag suffix tag $' + +# Disabling cgo should exclude cgo files and their imports. +env CGO_ENABLED=0 +go list -f '{{range .GoFiles}}{{.}} {{end}}' +stdout 'empty.go suffix_linux.go tag.go' +go list -f '{{range .CgoFiles}}{{.}} {{end}}' +! stdout . +go list -f '{{range .Imports}}{{.}} {{end}}' +stdout '^suffix tag $' + +# Changing OS should exclude linux sources. +env GOOS=darwin +go list -f '{{range .GoFiles}}{{.}} {{end}}' +stdout '^empty.go $' +go list -f '{{range .Imports}}{{.}} {{end}}' +stdout '^$' + +# Enabling a tag should include files that require it. +go list -tags=extra -f '{{range .GoFiles}}{{.}} {{end}}' +stdout '^empty.go extra.go $' +go list -tags=extra -f '{{range .Imports}}{{.}} {{end}}' +stdout '^extra $' + +# Packages that require a tag should not be listed unless the tag is on. +! go list ./tagonly +go list -tags=extra ./tagonly +stdout m/tagonly + +-- go.mod -- +module m + +go 1.13 + +-- empty.go -- +package p + +-- extra.go -- +// +build extra + +package p + +import _ "extra" + +-- suffix_linux.go -- +package p + +import _ "suffix" + +-- tag.go -- +// +build linux + +package p + +import _ "tag" + +-- cgotag.go -- +// +build cgo + +package p + +import _ "cgotag" + +-- cgoimport.go -- +package p + +import "C" + +import _ "cgoimport" + +-- tagonly/tagonly.go -- +// +build extra + +package tagonly diff --git a/src/cmd/go/testdata/script/list_dedup_packages.txt b/src/cmd/go/testdata/script/list_dedup_packages.txt new file mode 100644 index 0000000..30c68dd --- /dev/null +++ b/src/cmd/go/testdata/script/list_dedup_packages.txt @@ -0,0 +1,31 @@ +# Setup +env GO111MODULE=off +mkdir $WORK/tmp/testdata/src/xtestonly +cp f.go $WORK/tmp/testdata/src/xtestonly/f.go +cp f_test.go $WORK/tmp/testdata/src/xtestonly/f_test.go +env GOPATH=$WORK/tmp/testdata +cd $WORK + +# Check output of go list to ensure no duplicates +go list xtestonly ./tmp/testdata/src/xtestonly/... +cmp stdout $WORK/gopath/src/wantstdout + +-- wantstdout -- +xtestonly +-- f.go -- +package xtestonly + +func F() int { return 42 } +-- f_test.go -- +package xtestonly_test + +import ( + "testing" + "xtestonly" +) + +func TestF(t *testing.T) { + if x := xtestonly.F(); x != 42 { + t.Errorf("f.F() = %d, want 42", x) + } +} diff --git a/src/cmd/go/testdata/script/list_empty_import.txt b/src/cmd/go/testdata/script/list_empty_import.txt new file mode 100644 index 0000000..4d76f09 --- /dev/null +++ b/src/cmd/go/testdata/script/list_empty_import.txt @@ -0,0 +1,9 @@ +! go list a.go +! stdout . +stderr 'invalid import path' +! stderr panic + +-- a.go -- +package a + +import "" diff --git a/src/cmd/go/testdata/script/list_err_cycle.txt b/src/cmd/go/testdata/script/list_err_cycle.txt new file mode 100644 index 0000000..44b82a6 --- /dev/null +++ b/src/cmd/go/testdata/script/list_err_cycle.txt @@ -0,0 +1,15 @@ +# Check that we don't get infinite recursion when loading a package with +# an import cycle and another error. Verifies #25830. +! go list +stderr 'found packages a \(a.go\) and b \(b.go\)' + +-- go.mod -- +module errcycle + +go 1.16 +-- a.go -- +package a + +import _ "errcycle" +-- b.go -- +package b
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/list_err_stack.txt b/src/cmd/go/testdata/script/list_err_stack.txt new file mode 100644 index 0000000..a7be9fd --- /dev/null +++ b/src/cmd/go/testdata/script/list_err_stack.txt @@ -0,0 +1,27 @@ + +# golang.org/issue/40544: regression in error stacks for parse errors + +env GO111MODULE=off +cd sandbox/foo +go list -e -json . +stdout '"sandbox/foo"' +stdout '"sandbox/bar"' +stdout '"Pos": "..(/|\\\\)bar(/|\\\\)bar.go:1:1"' +stdout '"Err": "expected ''package'', found ackage"' + +env GO111MODULE=on +go list -e -json . +stdout '"sandbox/foo"' +stdout '"sandbox/bar"' +stdout '"Pos": "..(/|\\\\)bar(/|\\\\)bar.go:1:1"' +stdout '"Err": "expected ''package'', found ackage"' + +-- sandbox/go.mod -- +module sandbox + +-- sandbox/foo/foo.go -- +package pkg + +import "sandbox/bar" +-- sandbox/bar/bar.go -- +ackage bar
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/list_export_e.txt b/src/cmd/go/testdata/script/list_export_e.txt new file mode 100644 index 0000000..6d5dd39 --- /dev/null +++ b/src/cmd/go/testdata/script/list_export_e.txt @@ -0,0 +1,30 @@ +! go list -export ./... +stderr '^# example.com/p2\np2'${/}'main\.go:7:.*' +! stderr '^go build ' + +go list -f '{{with .Error}}{{.}}{{end}}' -e -export ./... +! stderr '.' +stdout '^# example.com/p2\np2'${/}'main\.go:7:.*' + +go list -export -e -f '{{.ImportPath}} -- {{.Incomplete}} -- {{.Error}}' ./... +stdout 'example.com/p1 -- false -- <nil>' +stdout 'example.com/p2 -- true -- # example.com/p2' + +go list -e -export -json=Error ./... +stdout '"Err": "# example.com/p2' + +-- go.mod -- +module example.com +-- p1/p1.go -- +package p1 + +const Name = "p1" +-- p2/main.go -- +package main + +import "fmt" +import "example.com/p1" + +func main() { + fmt.Println(p1.Name == 5) +} diff --git a/src/cmd/go/testdata/script/list_export_embed.txt b/src/cmd/go/testdata/script/list_export_embed.txt new file mode 100644 index 0000000..da74998 --- /dev/null +++ b/src/cmd/go/testdata/script/list_export_embed.txt @@ -0,0 +1,17 @@ +# Regression test for https://go.dev/issue/58885: +# 'go list -json=Export' should not fail due to missing go:embed metadata. + +[short] skip 'runs the compiler to produce export data' + +go list -json=Export -export . + +-- go.mod -- +module example +go 1.20 +-- example.go -- +package example + +import _ "embed" + +//go:embed example.go +var src string diff --git a/src/cmd/go/testdata/script/list_find.txt b/src/cmd/go/testdata/script/list_find.txt new file mode 100644 index 0000000..d450fc9 --- /dev/null +++ b/src/cmd/go/testdata/script/list_find.txt @@ -0,0 +1,22 @@ +env GO111MODULE=off + +# go list -find should not report imports + +go list -f {{.Incomplete}} x/y/z... # should probably exit non-zero but never has +stdout true +go list -find -f '{{.Incomplete}} {{.Imports}}' x/y/z... +stdout '^false \[\]' + +# go list -find -compiled should use cached sources the second time it's run. +# It might not find the same cached sources as "go build", but the sources +# should be identical. "go build" derives action IDs (which are used as cache +# keys) from dependencies' action IDs. "go list -find" won't know what the +# dependencies are, so it's can't construct the same action IDs. +[short] skip +go list -find -compiled net +go list -find -compiled -x net +! stderr 'cgo' + +-- x/y/z/z.go -- +package z +import "does/not/exist" diff --git a/src/cmd/go/testdata/script/list_find_nodeps.txt b/src/cmd/go/testdata/script/list_find_nodeps.txt new file mode 100644 index 0000000..e08ce78 --- /dev/null +++ b/src/cmd/go/testdata/script/list_find_nodeps.txt @@ -0,0 +1,49 @@ +# Issue #46092 +# go list -find should always return a package with an empty Deps list + +# The linker loads implicit dependencies +go list -find -f {{.Deps}} ./cmd +stdout '\[\]' + +# Cgo translation may add imports of "unsafe", "runtime/cgo" and "syscall" +go list -find -f {{.Deps}} ./cgo +stdout '\[\]' + +# SWIG adds imports of some standard packages +go list -find -f {{.Deps}} ./swig +stdout '\[\]' + +-- go.mod -- +module listfind + +-- cmd/main.go -- +package main + +func main() {} + +-- cgo/pkg.go -- +package cgopkg + +/* +#include <limits.h> +*/ +import "C" + +func F() { + println(C.INT_MAX) +} + +-- cgo/pkg_notcgo.go -- +//go:build !cgo +// +build !cgo + +package cgopkg + +func F() { + println(0) +} + +-- swig/pkg.go -- +package swigpkg + +-- swig/a.swigcxx -- diff --git a/src/cmd/go/testdata/script/list_gofile_in_goroot.txt b/src/cmd/go/testdata/script/list_gofile_in_goroot.txt new file mode 100644 index 0000000..b4ff3cb --- /dev/null +++ b/src/cmd/go/testdata/script/list_gofile_in_goroot.txt @@ -0,0 +1,76 @@ +# Return an error if the user tries to list a go source file directly in $GOROOT/src. +# Tests golang.org/issue/36587 + +env GOROOT=$WORK/goroot +env GOPATH=$WORK/gopath + +go env GOROOT +stdout $WORK[/\\]goroot + +# switch to GOROOT/src +cd $GOROOT/src + +# In module mode, 'go list ./...' should not treat .go files in GOROOT/src as an +# importable package, since that directory has no valid import path. +env GO111MODULE=on +go list ... +stdout -count=1 '^.+$' +stdout '^fmt$' +! stdout foo + +go list ./... +stdout -count=1 '^.+$' +stdout '^fmt$' +! stdout foo + +go list std +stdout -count=1 '^.+$' +stdout '^fmt$' + +! go list . +stderr '^GOROOT/src is not an importable package$' + +# In GOPATH mode, 'go list ./...' should synthesize a legacy GOPATH-mode path — +# not a standard-library or empty path — for the errant package. +env GO111MODULE=off +go list ./... +stdout -count=2 '^.+$' # Both 'fmt' and GOROOT/src should be listed. +stdout '^fmt$' +[!GOOS:windows] stdout ^_$WORK/goroot/src$ +[GOOS:windows] stdout goroot/src$ # On windows the ":" in the volume name is mangled + +go list ... +! stdout goroot/src + +go list std +! stdout goroot/src + +go list . +[!GOOS:windows] stdout ^_$WORK/goroot/src$ +[GOOS:windows] stdout goroot/src$ + +# switch to GOPATH/src +cd $GOPATH/src + +# GO111MODULE=off,GOPATH +env GO111MODULE=off +go list ./... +[!GOOS:windows] stdout ^_$WORK/gopath/src$ +[GOOS:windows] stdout gopath/src$ + +go list all +! stdout gopath/src + +-- $WORK/goroot/src/go.mod -- +module std + +go 1.14 +-- $WORK/goroot/src/foo.go -- +package foo +-- $WORK/goroot/src/fmt/fmt.go -- +package fmt +-- $WORK/goroot/src/cmd/README -- +This directory must exist in order for the 'cmd' pattern to have something to +match against. +-- $GOPATH/src/foo.go -- +package foo diff --git a/src/cmd/go/testdata/script/list_gomod_in_gopath.txt b/src/cmd/go/testdata/script/list_gomod_in_gopath.txt new file mode 100644 index 0000000..064f33a --- /dev/null +++ b/src/cmd/go/testdata/script/list_gomod_in_gopath.txt @@ -0,0 +1,23 @@ +# Issue 46119 + +# When a module is inside a GOPATH workspace, Package.Root should be set to +# Module.Dir instead of $GOPATH/src. + +env GOPATH=$WORK/tmp +cd $WORK/tmp/src/test + +go list -f {{.Root}} +stdout ^$PWD$ + +# Were we really inside a GOPATH workspace? +env GO111MODULE=off +go list -f {{.Root}} +stdout ^$WORK/tmp$ + +-- $WORK/tmp/src/test/go.mod -- +module test + +-- $WORK/tmp/src/test/main.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/list_goroot_symlink.txt b/src/cmd/go/testdata/script/list_goroot_symlink.txt new file mode 100644 index 0000000..041ae55 --- /dev/null +++ b/src/cmd/go/testdata/script/list_goroot_symlink.txt @@ -0,0 +1,62 @@ +# Regression test for https://go.dev/issue/57754: 'go list' failed if ../src +# relative to the location of the go executable was a symlink to the real src +# directory. (cmd/go expects that ../src is GOROOT/src, but it appears that the +# Debian build of the Go toolchain is attempting to split GOROOT into binary and +# source artifacts in different parent directories.) + +[short] skip 'copies the cmd/go binary' +[!symlink] skip 'tests symlink-specific behavior' +[GOOS:darwin] skip 'Lstat on darwin does not conform to POSIX pathname resolution; see #59586' +[GOOS:ios] skip 'Lstat on ios does not conform to POSIX pathname resolution; see #59586' + +# Ensure that the relative path to $WORK/lib/goroot/src from $PWD is a different +# number of ".." hops than the relative path to it from $WORK/share/goroot/src. + +cd $WORK + +# Construct a fake GOROOT in $WORK/lib/goroot whose src directory is a symlink +# to a subdirectory of $WORK/share. This mimics the directory structure reported +# in https://go.dev/issue/57754. +# +# Symlink everything else to the original $GOROOT to avoid needless copying work. + +mkdir $WORK/lib/goroot +mkdir $WORK/share/goroot +symlink $WORK/share/goroot/src -> $GOROOT${/}src +symlink $WORK/lib/goroot/src -> ../../share/goroot/src +symlink $WORK/lib/goroot/pkg -> $GOROOT${/}pkg + +# Verify that our symlink shenanigans don't prevent cmd/go from finding its +# GOROOT using os.Executable. +# +# To do so, we copy the actual cmd/go executable — which is implemented as the +# cmd/go test binary instead of the original $GOROOT/bin/go, which may be +# arbitrarily stale — into the bin subdirectory of the fake GOROOT, causing +# os.Executable to report a path in that directory. + +mkdir $WORK/lib/goroot/bin +cp $TESTGO_EXE $WORK/lib/goroot/bin/go$GOEXE + +env GOROOT='' # Clear to force cmd/go to find GOROOT itself. +exec $WORK/lib/goroot/bin/go env GOROOT +stdout $WORK${/}lib${/}goroot + +# Now verify that 'go list' can find standard-library packages in the symlinked +# source tree, with paths matching the one reported by 'go env GOROOT'. + +exec $WORK/lib/goroot/bin/go list -f '{{.ImportPath}}: {{.Dir}}' encoding/binary +stdout '^encoding/binary: '$WORK${/}lib${/}goroot${/}src${/}encoding${/}binary'$' + +exec $WORK/lib/goroot/bin/go list -f '{{.ImportPath}}: {{.Dir}}' std +stdout '^encoding/binary: '$WORK${/}lib${/}goroot${/}src${/}encoding${/}binary'$' + +# Most path lookups in GOROOT are not sensitive to symlinks. However, patterns +# involving '...' wildcards must use Walk to check the GOROOT tree, which makes +# them more sensitive to symlinks (because Walk doesn't follow them). +# +# So we check such a pattern to confirm that it works and reports a path relative +# to $GOROOT/src (and not the symlink target). + +exec $WORK/lib/goroot/bin/go list -f '{{.ImportPath}}: {{.Dir}}' .../binary +stdout '^encoding/binary: '$WORK${/}lib${/}goroot${/}src${/}encoding${/}binary'$' +! stderr . diff --git a/src/cmd/go/testdata/script/list_import_cycle_deps_errors.txt b/src/cmd/go/testdata/script/list_import_cycle_deps_errors.txt new file mode 100644 index 0000000..e2c5cf9 --- /dev/null +++ b/src/cmd/go/testdata/script/list_import_cycle_deps_errors.txt @@ -0,0 +1,75 @@ +go list -e -deps -json=ImportPath,Error,DepsErrors m/a +cmp stdout want + +-- want -- +{ + "ImportPath": "m/c", + "DepsErrors": [ + { + "ImportStack": [ + "m/a", + "m/b", + "m/c", + "m/a" + ], + "Pos": "", + "Err": "import cycle not allowed" + } + ] +} +{ + "ImportPath": "m/b", + "DepsErrors": [ + { + "ImportStack": [ + "m/a", + "m/b", + "m/c", + "m/a" + ], + "Pos": "", + "Err": "import cycle not allowed" + } + ] +} +{ + "ImportPath": "m/a", + "Error": { + "ImportStack": [ + "m/a", + "m/b", + "m/c", + "m/a" + ], + "Pos": "", + "Err": "import cycle not allowed" + }, + "DepsErrors": [ + { + "ImportStack": [ + "m/a", + "m/b", + "m/c", + "m/a" + ], + "Pos": "", + "Err": "import cycle not allowed" + } + ] +} +-- go.mod -- +module m + +go 1.21 +-- a/a.go -- +package a + +import _ "m/b" +-- b/b.go -- +package b + +import _ "m/c" +-- c/c.go -- +package c + +import _ "m/a"
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/list_import_err.txt b/src/cmd/go/testdata/script/list_import_err.txt new file mode 100644 index 0000000..c2b7d7c --- /dev/null +++ b/src/cmd/go/testdata/script/list_import_err.txt @@ -0,0 +1,22 @@ +# Test that errors importing packages are reported on the importing package, +# not the imported package. + +env GO111MODULE=off # simplify vendor layout for test + +go list -e -deps -f '{{.ImportPath}}: {{.Error}}' ./importvendor +stdout 'importvendor: importvendor[\\/]p.go:2:8: vendor/p must be imported as p' +stdout 'vendor/p: <nil>' + +go list -e -deps -f '{{.ImportPath}}: {{.Error}}' ./importinternal +stdout 'importinternal: package importinternal\n\timportinternal[\\/]p.go:2:8: use of internal package other/internal/p not allowed' +stdout 'other/internal/p: <nil>' +-- importvendor/p.go -- +package importvendor +import "vendor/p" +-- importinternal/p.go -- +package importinternal +import "other/internal/p" +-- other/internal/p/p.go -- +package p +-- vendor/p/p.go -- +package p
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/list_importmap.txt b/src/cmd/go/testdata/script/list_importmap.txt new file mode 100644 index 0000000..3c59cfd --- /dev/null +++ b/src/cmd/go/testdata/script/list_importmap.txt @@ -0,0 +1,27 @@ +env GO111MODULE=off + +# gccgo does not have standard packages. +[compiler:gccgo] skip + +# fmt should have no rewritten imports. +# The import from a/b should map c/d to a's vendor directory. +go list -f '{{.ImportPath}}: {{.ImportMap}}' fmt a/b +stdout 'fmt: map\[\]' +stdout 'a/b: map\[c/d:a/vendor/c/d\]' + +# flag [fmt.test] should import fmt [fmt.test] as fmt +# fmt.test should import testing [fmt.test] as testing +# fmt.test should not import a modified os +go list -deps -test -f '{{.ImportPath}} MAP: {{.ImportMap}}{{"\n"}}{{.ImportPath}} IMPORT: {{.Imports}}' fmt +stdout '^flag \[fmt\.test\] MAP: map\[fmt:fmt \[fmt\.test\]\]' +stdout '^fmt\.test MAP: map\[(.* )?testing:testing \[fmt\.test\]' +! stdout '^fmt\.test MAP: map\[(.* )?os:' +stdout '^fmt\.test IMPORT: \[fmt \[fmt\.test\] fmt_test \[fmt\.test\] os reflect testing \[fmt\.test\] testing/internal/testdeps \[fmt\.test\]\]' + + +-- a/b/b.go -- +package b + +import _ "c/d" +-- a/vendor/c/d/d.go -- +package d diff --git a/src/cmd/go/testdata/script/list_issue_56509.txt b/src/cmd/go/testdata/script/list_issue_56509.txt new file mode 100644 index 0000000..b402b2b --- /dev/null +++ b/src/cmd/go/testdata/script/list_issue_56509.txt @@ -0,0 +1,35 @@ +# Test that a directory with an .s file that has a comment that can't +# be parsed isn't matched as a go directory. (This was happening because +# non-go files with unparsable comments were being added to InvalidGoFiles +# leading the package matching code to think there were Go files in the +# directory.) + +cd bar +go list ./... +! stdout . +cd .. + +[short] skip + +# Test that an unparsable .s file is completely ignored when its name +# has build tags that cause it to be filtered out, but produces an error +# when it is included + +env GOARCH=arm64 +env GOOS=linux +go build ./baz + +env GOARCH=amd64 +env GOOS=linux +! go build ./baz + +-- go.mod -- +module example.com/foo + +go 1.20 +-- bar/bar.s -- +;/ +-- baz/baz.go -- +package bar +-- baz/baz_amd64.s -- +;/ diff --git a/src/cmd/go/testdata/script/list_issue_59905.txt b/src/cmd/go/testdata/script/list_issue_59905.txt new file mode 100644 index 0000000..48c40d0 --- /dev/null +++ b/src/cmd/go/testdata/script/list_issue_59905.txt @@ -0,0 +1,88 @@ +# Expect no panic +go list -f '{{if .DepsErrors}}{{.DepsErrors}}{{end}}' -export -e -deps +cmpenv stdout wanterr_59905 + +# Expect no panic (Issue 61816) +cp level1b_61816.txt level1b/pkg.go +go list -f '{{if .DepsErrors}}{{.DepsErrors}}{{end}}' -export -e -deps +cmpenv stdout wanterr_61816 + +-- wanterr_59905 -- +[# test/main/level1a +level1a${/}pkg.go:5:2: level2x redeclared in this block + level1a${/}pkg.go:4:2: other declaration of level2x +level1a${/}pkg.go:5:2: "test/main/level1a/level2y" imported as level2x and not used +level1a${/}pkg.go:8:39: undefined: level2y + # test/main/level1b +level1b${/}pkg.go:5:2: level2x redeclared in this block + level1b${/}pkg.go:4:2: other declaration of level2x +level1b${/}pkg.go:5:2: "test/main/level1b/level2y" imported as level2x and not used +level1b${/}pkg.go:8:39: undefined: level2y +] +-- wanterr_61816 -- +[level1b${/}pkg.go:4:2: package foo is not in std ($GOROOT${/}src${/}foo)] +[# test/main/level1a +level1a${/}pkg.go:5:2: level2x redeclared in this block + level1a${/}pkg.go:4:2: other declaration of level2x +level1a${/}pkg.go:5:2: "test/main/level1a/level2y" imported as level2x and not used +level1a${/}pkg.go:8:39: undefined: level2y + level1b${/}pkg.go:4:2: package foo is not in std ($GOROOT${/}src${/}foo)] +-- level1b_61816.txt -- +package level1b + +import ( + "foo" +) + +func Print() { println(level2x.Value, level2y.Value) } + +-- go.mod -- +module test/main + +go 1.20 +-- main.go -- +package main + +import ( + "test/main/level1a" + "test/main/level1b" +) + +func main() { + level1a.Print() + level1b.Print() +} +-- level1a/pkg.go -- +package level1a + +import ( + "test/main/level1a/level2x" + "test/main/level1a/level2y" +) + +func Print() { println(level2x.Value, level2y.Value) } +-- level1a/level2x/pkg.go -- +package level2x + +var Value = "1a/2x" +-- level1a/level2y/pkg.go -- +package level2x + +var Value = "1a/2y" +-- level1b/pkg.go -- +package level1b + +import ( + "test/main/level1b/level2x" + "test/main/level1b/level2y" +) + +func Print() { println(level2x.Value, level2y.Value) } +-- level1b/level2x/pkg.go -- +package level2x + +var Value = "1b/2x" +-- level1b/level2y/pkg.go -- +package level2x + +var Value = "1b/2y"
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/list_json_fields.txt b/src/cmd/go/testdata/script/list_json_fields.txt new file mode 100644 index 0000000..7e008ea --- /dev/null +++ b/src/cmd/go/testdata/script/list_json_fields.txt @@ -0,0 +1,113 @@ +# Test using -json flag to specify specific fields. + +# Test -json produces "full" output by looking for multiple fields present. +go list -json . +stdout '"Name": "a"' +stdout '"Stale": true' +# Same thing for -json=true +go list -json=true . +stdout '"Name": "a"' +stdout '"Stale": true' + +# Test -json=false produces non-json output. +go list -json=false +cmp stdout want-non-json.txt + +# Test -json=<field> keeps only that field. +go list -json=Name +cmp stdout want-json-name.txt + +# Test -json=<field> with multiple fields. +go list -json=ImportPath,Name,GoFiles,Imports +cmp stdout want-json-multiple.txt + +# Test -json=<field> with Deps outputs the Deps field. +go list -json=Deps +stdout '"Deps": \[' +stdout '"errors",' + +# Test -json=<field> with *EmbedPatterns outputs embed patterns. +cd embed +go list -json=EmbedPatterns,TestEmbedPatterns,XTestEmbedPatterns +stdout '"EmbedPatterns": \[' +stdout '"TestEmbedPatterns": \[' +stdout '"XTestEmbedPatterns": \[' +# Test -json=<field> with *EmbedFiles fails due to broken file reference. +! go list -json=EmbedFiles +stderr 'no matching files found' +! go list -json=TestEmbedFiles +stderr 'no matching files found' +! go list -json=XTestEmbedFiles +stderr 'no matching files found' +cd .. + +[!git] skip + +# Test -json=<field> without Stale skips computing buildinfo +cd repo +exec git init +# Control case: with -json=Stale cmd/go executes git status to compute buildinfo +go list -json=Stale -x +stderr 'git status' +# Test case: without -json=Stale cmd/go skips git status +go list -json=Name -x +! stderr 'git status' + +-- go.mod -- +module example.com/a + +go 1.18 +-- a.go -- +package a + +import "fmt" + +func F() { + fmt.Println("hey there") +} +-- want-non-json.txt -- +example.com/a +-- want-json-name.txt -- +{ + "Name": "a" +} +-- want-json-multiple.txt -- +{ + "ImportPath": "example.com/a", + "Name": "a", + "GoFiles": [ + "a.go" + ], + "Imports": [ + "fmt" + ] +} +-- repo/go.mod -- +module example.com/repo +-- repo/main.go -- +package main + +func main() {} +-- embed/go.mod -- +module example.com/embed +-- embed/embed.go -- +package embed + +import _ "embed" + +//go:embed non-existing-file.txt +var s string +-- embed/embed_test.go -- +package embed + +import _ "embed" + +//go:embed non-existing-file.txt +var s string +-- embed/embed_xtest_test.go -- +package embed_test + +import _ "embed" + +//go:embed non-existing-file.txt +var s string diff --git a/src/cmd/go/testdata/script/list_json_with_f.txt b/src/cmd/go/testdata/script/list_json_with_f.txt new file mode 100644 index 0000000..2011a6e --- /dev/null +++ b/src/cmd/go/testdata/script/list_json_with_f.txt @@ -0,0 +1,20 @@ +[short] skip + +# list -json should generate output on stdout +go list -json ./... +stdout . +# list -f should generate output on stdout +go list -f '{{.}}' ./... +stdout . + +# test passing first -json then -f +! go list -json -f '{{.}}' ./... +stderr '^go list -f cannot be used with -json$' + +# test passing first -f then -json +! go list -f '{{.}}' -json ./... +stderr '^go list -f cannot be used with -json$' +-- go.mod -- +module m +-- list_test.go -- +package list_test diff --git a/src/cmd/go/testdata/script/list_legacy_mod.txt b/src/cmd/go/testdata/script/list_legacy_mod.txt new file mode 100644 index 0000000..ab901d7 --- /dev/null +++ b/src/cmd/go/testdata/script/list_legacy_mod.txt @@ -0,0 +1,48 @@ +# In GOPATH mode, module legacy support does path rewriting very similar to vendoring. + +env GO111MODULE=off + +go list -f '{{range .Imports}}{{.}}{{"\n"}}{{end}}' old/p1 +stdout ^new/p1$ + +go list -f '{{range .Imports}}{{.}}{{"\n"}}{{end}}' new/p1 +stdout ^new/p2$ # not new/v2/p2 +! stdout ^new/v2 +stdout ^new/sub/x/v1/y$ # not new/sub/v2/x/v1/y +! stdout ^new/sub/v2 +stdout ^new/sub/inner/x # not new/sub/v2/inner/x + +go build old/p1 new/p1 + +-- new/go.mod -- +module "new/v2" +-- new/new.go -- +package new + +import _ "new/v2/p2" +-- new/p1/p1.go -- +package p1 + +import _ "old/p2" +import _ "new/v2" +import _ "new/v2/p2" +import _ "new/sub/v2/x/v1/y" // v2 is module, v1 is directory in module +import _ "new/sub/inner/x" // new/sub/inner/go.mod overrides new/sub/go.mod +-- new/p2/p2.go -- +package p2 +-- new/sub/go.mod -- +module new/sub/v2 +-- new/sub/inner/go.mod -- +module new/sub/inner +-- new/sub/inner/x/x.go -- +package x +-- new/sub/x/v1/y/y.go -- +package y +-- old/p1/p1.go -- +package p1 + +import _ "old/p2" +import _ "new/p1" +import _ "new" +-- old/p2/p2.go -- +package p2 diff --git a/src/cmd/go/testdata/script/list_linkshared.txt b/src/cmd/go/testdata/script/list_linkshared.txt new file mode 100644 index 0000000..baae1e2 --- /dev/null +++ b/src/cmd/go/testdata/script/list_linkshared.txt @@ -0,0 +1,16 @@ +env GO111MODULE=on + +# golang.org/issue/35759: 'go list -linkshared' +# panicked if invoked on a test-only package. + +[!buildmode:shared] skip + +go list -f '{{.ImportPath}}: {{.Target}} {{.Shlib}}' -linkshared . +stdout '^example.com: $' + +-- go.mod -- +module example.com + +go 1.14 +-- x.go -- +package x diff --git a/src/cmd/go/testdata/script/list_load_err.txt b/src/cmd/go/testdata/script/list_load_err.txt new file mode 100644 index 0000000..f1b9205 --- /dev/null +++ b/src/cmd/go/testdata/script/list_load_err.txt @@ -0,0 +1,95 @@ +# go list -e -deps should list imports from any file it can read, even if +# other files in the same package cause go/build.Import to return an error. +# Verifies golang.org/issue/38568 + +go list -e -deps ./scan +stdout m/want + +go list -e -deps ./multi +stdout m/want + +go list -e -deps ./constraint +stdout m/want + +[cgo] go list -e -test -deps ./cgotest +[cgo] stdout m/want + +[cgo] go list -e -deps ./cgoflag +[cgo] stdout m/want + + +# go list -e should include files with errors in GoFiles, TestGoFiles, and +# other lists, assuming they match constraints. +# Verifies golang.org/issue/39986 +go list -e -f '{{range .GoFiles}}{{.}},{{end}}' ./scan +stdout '^good.go,scan.go,$' + +go list -e -f '{{range .GoFiles}}{{.}},{{end}}' ./multi +stdout '^a.go,b.go,$' + +go list -e -f '{{range .GoFiles}}{{.}},{{end}}' ./constraint +stdout '^good.go,$' +go list -e -f '{{range .IgnoredGoFiles}}{{.}},{{end}}' ./constraint +stdout '^constraint.go,$' + +[cgo] go list -e -f '{{range .XTestGoFiles}}{{.}},{{end}}' ./cgotest +[cgo] stdout '^cgo_test.go,$' + +[cgo] go list -e -f '{{range .GoFiles}}{{.}},{{end}}' ./cgoflag +[cgo] stdout '^cgoflag.go,$' + +-- go.mod -- +module m + +go 1.14 + +-- want/want.go -- +package want + +-- scan/scan.go -- +// scan error +ʕ◔ϖ◔ʔ + +-- scan/good.go -- +package scan + +import _ "m/want" + +-- multi/a.go -- +package a + +-- multi/b.go -- +package b + +import _ "m/want" + +-- constraint/constraint.go -- +// +build !!nope + +package constraint + +-- constraint/good.go -- +package constraint + +import _ "m/want" + +-- cgotest/cgo_test.go -- +package cgo_test + +// cgo is not allowed in tests. +// See golang.org/issue/18647 + +import "C" +import ( + "testing" + _ "m/want" +) + +func Test(t *testing.T) {} + +-- cgoflag/cgoflag.go -- +package cgoflag + +// #cgo ʕ◔ϖ◔ʔ: + +import _ "m/want" diff --git a/src/cmd/go/testdata/script/list_module_when_error.txt b/src/cmd/go/testdata/script/list_module_when_error.txt new file mode 100644 index 0000000..844164c --- /dev/null +++ b/src/cmd/go/testdata/script/list_module_when_error.txt @@ -0,0 +1,19 @@ +# The Module field should be populated even if there is an error loading the package. + +env GO111MODULE=on + +go list -e -f {{.Module}} +stdout '^mod.com$' + +-- go.mod -- +module mod.com + +go 1.16 + +-- blah.go -- +package blah + +import _ "embed" + +//go:embed README.md +var readme string diff --git a/src/cmd/go/testdata/script/list_overlay.txt b/src/cmd/go/testdata/script/list_overlay.txt new file mode 100644 index 0000000..1153975 --- /dev/null +++ b/src/cmd/go/testdata/script/list_overlay.txt @@ -0,0 +1,63 @@ +# Test listing with overlays + +# Overlay in an existing directory +go list -overlay overlay.json -f '{{.GoFiles}}' . +stdout '^\[f.go\]$' + +# Overlays in a non-existing directory +go list -overlay overlay.json -f '{{.GoFiles}}' ./dir +stdout '^\[g.go\]$' + +# Overlays in an existing directory with already existing files +go list -overlay overlay.json -f '{{.GoFiles}}' ./dir2 +stdout '^\[h.go i.go\]$' + +# Overlay that removes a file from a directory +! go list ./dir3 # contains a file without a package statement +go list -overlay overlay.json -f '{{.GoFiles}}' ./dir3 # overlay removes that file + +# Walking through an overlay +go list -overlay overlay.json ./... +cmp stdout want-list.txt + +# TODO(#39958): assembly files, C files, files that require cgo preprocessing + +-- want-list.txt -- +m +m/dir +m/dir2 +m/dir3 +-- go.mod -- +// TODO(#39958): Support and test overlays including go.mod itself (especially if mod=readonly) +module m + +go 1.16 + +-- dir2/h.go -- +package dir2 + +-- dir3/good.go -- +package dir3 +-- dir3/bad.go -- +// no package statement +-- overlay.json -- +{ + "Replace": { + "f.go": "overlay/f_go", + "dir/g.go": "overlay/dir_g_go", + "dir2/i.go": "overlay/dir2_i_go", + "dir3/bad.go": "" + } +} +-- overlay/f_go -- +package m + +func f() { +} +-- overlay/dir_g_go -- +package m + +func g() { +} +-- overlay/dir2_i_go -- +package dir2 diff --git a/src/cmd/go/testdata/script/list_parse_err.txt b/src/cmd/go/testdata/script/list_parse_err.txt new file mode 100644 index 0000000..0a3eb02 --- /dev/null +++ b/src/cmd/go/testdata/script/list_parse_err.txt @@ -0,0 +1,45 @@ +# 'go list' without -e should fail and print errors on stderr. +! go list ./p +stderr '^p[/\\]b.go:2:2: expected ''package'', found ''EOF''$' +! go list -f '{{range .Imports}}{{.}} {{end}}' ./p +stderr '^p[/\\]b.go:2:2: expected ''package'', found ''EOF''$' +! go list -test ./t +stderr '^go: can''t load test package: t[/\\]t_test.go:8:1: expected declaration, found ʕ' +! go list -test -f '{{range .Imports}}{{.}} {{end}}' ./t +stderr '^go: can''t load test package: t[/\\]t_test.go:8:1: expected declaration, found ʕ' + +# 'go list -e' should report imports, even if some files have parse errors +# before the import block. +go list -e -f '{{range .Imports}}{{.}} {{end}}' ./p +stdout '^fmt ' + +# 'go list' should report the position of the error if there's only one. +go list -e -f '{{.Error.Pos}} => {{.Error.Err}}' ./p +stdout 'b.go:[0-9:]+ => expected ''package'', found ''EOF''' + +# 'go test' should report the position of the error if there's only one. +go list -e -test -f '{{if .Error}}{{.Error.Pos}} => {{.Error.Err}}{{end}}' ./t +stdout 't_test.go:[0-9:]+ => expected declaration, found ʕ' + +-- go.mod -- +module m + +go 1.13 + +-- p/a.go -- +package a + +import "fmt" + +-- p/b.go -- +// no package statement + +-- t/t_test.go -- +package t + +import "testing" + +func Test(t *testing.T) {} + +// scan error +ʕ◔ϖ◔ʔ diff --git a/src/cmd/go/testdata/script/list_perm.txt b/src/cmd/go/testdata/script/list_perm.txt new file mode 100644 index 0000000..14d6f72 --- /dev/null +++ b/src/cmd/go/testdata/script/list_perm.txt @@ -0,0 +1,83 @@ +env GO111MODULE=on + +# Establish baseline behavior, before mucking with file permissions. + +go list ./noread/... +stdout '^example.com/noread$' + +go list example.com/noread/... +stdout '^example.com/noread$' + +go list ./empty/... +stderr 'matched no packages' + +# Make the directory ./noread unreadable, and verify that 'go list' reports an +# explicit error for a pattern that should match it (rather than treating it as +# equivalent to an empty directory). + +[root] stop # Root typically ignores file permissions. +[GOOS:windows] skip # Does not have Unix-style directory permissions. +[GOOS:plan9] skip # Might not have Unix-style directory permissions. + +chmod 000 noread + +# Check explicit paths. + +! go list ./noread +! stdout '^example.com/noread$' +! stderr 'matched no packages' + +! go list example.com/noread +! stdout '^example.com/noread$' +! stderr 'matched no packages' + +# Check filesystem-relative patterns. + +! go list ./... +! stdout '^example.com/noread$' +! stderr 'matched no packages' +stderr '^pattern ./...: ' + +! go list ./noread/... +! stdout '^example.com/noread$' +! stderr 'matched no packages' +stderr '^pattern ./noread/...: ' + + +# Check module-prefix patterns. + +! go list example.com/... +! stdout '^example.com/noread$' +! stderr 'matched no packages' +stderr '^pattern example.com/...: ' + +! go list example.com/noread/... +! stdout '^example.com/noread$' +! stderr 'matched no packages' +stderr '^pattern example.com/noread/...: ' + + +[short] stop + +# Check global patterns, which should still +# fail due to errors in the local module. + +! go list all +! stdout '^example.com/noread$' +! stderr 'matched no packages' +stderr '^pattern all: ' + +! go list ... +! stdout '^example.com/noread$' +! stderr 'matched no packages' +stderr '^pattern ...: ' + + +-- go.mod -- +module example.com +go 1.15 +-- noread/noread.go -- +// Package noread exists, but will be made unreadable. +package noread +-- empty/README.txt -- +This directory intentionally left empty. diff --git a/src/cmd/go/testdata/script/list_pkgconfig_error.txt b/src/cmd/go/testdata/script/list_pkgconfig_error.txt new file mode 100644 index 0000000..f554d2a --- /dev/null +++ b/src/cmd/go/testdata/script/list_pkgconfig_error.txt @@ -0,0 +1,16 @@ +[!cgo] skip 'test verifies cgo pkg-config errors' +[!exec:pkg-config] skip 'test requires pkg-config tool' + +! go list -export . +stderr '^# example\n# \[pkg-config .*\]\n(.*\n)*Package .* not found' + +-- go.mod -- +module example +go 1.20 +-- example.go -- +package example + +// #cgo pkg-config: libnot-a-valid-cgo-library +import "C" + +package main() {} diff --git a/src/cmd/go/testdata/script/list_replace_absolute_windows.txt b/src/cmd/go/testdata/script/list_replace_absolute_windows.txt new file mode 100644 index 0000000..8b71921 --- /dev/null +++ b/src/cmd/go/testdata/script/list_replace_absolute_windows.txt @@ -0,0 +1,38 @@ +# Test a replacement with an absolute path (so the path isn't +# cleaned by having filepath.Abs called on it). This checks +# whether the modindex logic cleans the modroot path before using +# it. + +[!GOOS:windows] skip +[short] skip + +go run print_go_mod.go # use this program to write a go.mod with an absolute path +cp stdout go.mod + +go list -modfile=go.mod all +-- print_go_mod.go -- +//go:build ignore +package main + +import ( + "fmt" + "os" +) + +func main() { + work := os.Getenv("WORK") +fmt.Printf(`module example.com/mod + +require b.com v0.0.0 + +replace b.com => %s\gopath\src/modb +`, work) +} +-- a.go -- +package a + +import _ "b.com/b" +-- modb/go.mod -- +module b.com +-- modb/b/b.go -- +package b diff --git a/src/cmd/go/testdata/script/list_reserved.txt b/src/cmd/go/testdata/script/list_reserved.txt new file mode 100644 index 0000000..b9c5361 --- /dev/null +++ b/src/cmd/go/testdata/script/list_reserved.txt @@ -0,0 +1,7 @@ +# https://golang.org/issue/37641: the paths "example" and "test" are reserved +# for end users, and must never exist in the standard library. + +go list example/... test/... +stderr 'go: warning: "example/..." matched no packages$' +stderr 'go: warning: "test/..." matched no packages$' +! stdout . diff --git a/src/cmd/go/testdata/script/list_shadow.txt b/src/cmd/go/testdata/script/list_shadow.txt new file mode 100644 index 0000000..660508d --- /dev/null +++ b/src/cmd/go/testdata/script/list_shadow.txt @@ -0,0 +1,25 @@ +env GO111MODULE=off +env GOPATH=$WORK/gopath/src/shadow/root1${:}$WORK/gopath/src/shadow/root2 + +# The math in root1 is not "math" because the standard math is. +go list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./shadow/root1/src/math +stdout '^\(.*(\\|/)src(\\|/)shadow(\\|/)root1(\\|/)src(\\|/)math\) \('$GOROOT'(\\|/)?src(\\|/)math\)$' + +# The foo in root1 is "foo". +go list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./shadow/root1/src/foo +stdout '^\(foo\) \(\)$' + +# The foo in root2 is not "foo" because the foo in root1 got there first. +go list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./shadow/root2/src/foo +stdout '^\(.*gopath(\\|/)src(\\|/)shadow(\\|/)root2(\\|/)src(\\|/)foo\) \('$WORK'(\\|/)?gopath(\\|/)src(\\|/)shadow(\\|/)root1(\\|/)src(\\|/)foo\)$' + +# The error for go install should mention the conflicting directory. +! go install -n ./shadow/root2/src/foo +stderr 'go: no install location for '$WORK'(\\|/)?gopath(\\|/)src(\\|/)shadow(\\|/)root2(\\|/)src(\\|/)foo: hidden by '$WORK'(\\|/)?gopath(\\|/)src(\\|/)shadow(\\|/)root1(\\|/)src(\\|/)foo' + +-- shadow/root1/src/foo/foo.go -- +package foo +-- shadow/root1/src/math/math.go -- +package math +-- shadow/root2/src/foo/foo.go -- +package foo
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/list_split_main.txt b/src/cmd/go/testdata/script/list_split_main.txt new file mode 100644 index 0000000..74e7d5d --- /dev/null +++ b/src/cmd/go/testdata/script/list_split_main.txt @@ -0,0 +1,25 @@ +# This test checks that a "main" package with an external test package +# is recompiled only once. +# Verifies golang.org/issue/34321. + +env GO111MODULE=off + +go list -e -test -deps -f '{{if not .Standard}}{{.ImportPath}}{{end}}' pkg +cmp stdout want + +-- $GOPATH/src/pkg/pkg.go -- +package main + +func main() {} + +-- $GOPATH/src/pkg/pkg_test.go -- +package main + +import "testing" + +func Test(t *testing.T) {} + +-- want -- +pkg +pkg [pkg.test] +pkg.test diff --git a/src/cmd/go/testdata/script/list_std.txt b/src/cmd/go/testdata/script/list_std.txt new file mode 100644 index 0000000..64c4766 --- /dev/null +++ b/src/cmd/go/testdata/script/list_std.txt @@ -0,0 +1,25 @@ +env GO111MODULE=off + +[!compiler:gc] skip +[short] skip + +# Listing GOROOT should only find standard packages. +cd $GOROOT/src +go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' ./... +! stdout . + +# Standard packages should include cmd, but not cmd/vendor. +go list ./... +stdout cmd/compile +! stdout vendor/golang.org +! stdout cmd/vendor + +# In GOPATH mode, packages vendored into GOROOT should be reported as standard. +go list -f '{{if .Standard}}{{.ImportPath}}{{end}}' std cmd +stdout golang.org/x/net/http2/hpack +stdout cmd/vendor/golang\.org/x/arch/x86/x86asm + +# However, vendored packages should not match wildcard patterns beginning with cmd. +go list cmd/... +stdout cmd/compile +! stdout cmd/vendor diff --git a/src/cmd/go/testdata/script/list_std_vendor.txt b/src/cmd/go/testdata/script/list_std_vendor.txt new file mode 100644 index 0000000..834babe --- /dev/null +++ b/src/cmd/go/testdata/script/list_std_vendor.txt @@ -0,0 +1,33 @@ +# https://golang.org/issue/44725: packages in std should have the same +# dependencies regardless of whether they are listed from within or outside +# GOROOT/src. + +# Control case: net, viewed from outside the 'std' module, +# should depend on vendor/golang.org/… instead of golang.org/…. + +go list -deps net +stdout '^vendor/golang.org/x/net' +! stdout '^golang.org/x/net' +cp stdout $WORK/net-deps.txt + + +# It should still report the same package dependencies when viewed from +# within GOROOT/src. + +cd $GOROOT/src + +go list -deps net +stdout '^vendor/golang.org/x/net' +! stdout '^golang.org/x/net' +cmp stdout $WORK/net-deps.txt + + +# However, 'go mod' and 'go get' subcommands should report the original module +# dependencies, not the vendored packages. + +[!net:golang.org] stop + +env GOPROXY= +env GOWORK=off +go mod why -m golang.org/x/net +stdout '^# golang.org/x/net\nnet\ngolang.org/x/net' diff --git a/src/cmd/go/testdata/script/list_swigcxx.txt b/src/cmd/go/testdata/script/list_swigcxx.txt new file mode 100644 index 0000000..731c1e5 --- /dev/null +++ b/src/cmd/go/testdata/script/list_swigcxx.txt @@ -0,0 +1,30 @@ +# go list should not report SWIG-generated C++ files in CompiledGoFiles. + +[!exec:swig] skip +[!exec:g++] skip +[!cgo] skip + +# CompiledGoFiles should contain 4 files: +# a.go +# _cgo_import.go [gc only] +# _cgo_gotypes.go +# a.cgo1.go +# +# These names we see here, other than a.go, will be from the build cache, +# so we just count them. + +go list -f '{{.CompiledGoFiles}}' -compiled=true example/swig + +stdout a\.go +[compiler:gc] stdout -count=3 $GOCACHE +[compiler:gccgo] stdout -count=2 $GOCACHE + +-- go.mod -- +module example + +go 1.16 + +-- swig/a.go -- +package swig + +-- swig/a.swigcxx -- diff --git a/src/cmd/go/testdata/script/list_symlink.txt b/src/cmd/go/testdata/script/list_symlink.txt new file mode 100644 index 0000000..f74ca86 --- /dev/null +++ b/src/cmd/go/testdata/script/list_symlink.txt @@ -0,0 +1,12 @@ +[!symlink] skip +env GO111MODULE=off + +mkdir $WORK/tmp/src +symlink $WORK/tmp/src/dir1 -> $WORK/tmp +cp p.go $WORK/tmp/src/dir1/p.go +env GOPATH=$WORK/tmp +go list -f '{{.Root}}' dir1 +stdout '^'$WORK/tmp'$' + +-- p.go -- +package p diff --git a/src/cmd/go/testdata/script/list_symlink_dotdotdot.txt b/src/cmd/go/testdata/script/list_symlink_dotdotdot.txt new file mode 100644 index 0000000..8df1982 --- /dev/null +++ b/src/cmd/go/testdata/script/list_symlink_dotdotdot.txt @@ -0,0 +1,20 @@ +[!symlink] skip + +symlink $WORK/gopath/src/sym -> $WORK/gopath/src/tree +symlink $WORK/gopath/src/tree/squirrel -> $WORK/gopath/src/dir2 # this symlink should not be followed +cd sym +go list ./... +cmp stdout $WORK/gopath/src/want_list.txt +-- tree/go.mod -- +module example.com/tree + +go 1.20 +-- tree/tree.go -- +package tree +-- tree/branch/branch.go -- +package branch +-- dir2/squirrel.go -- +package squirrel +-- want_list.txt -- +example.com/tree +example.com/tree/branch diff --git a/src/cmd/go/testdata/script/list_symlink_internal.txt b/src/cmd/go/testdata/script/list_symlink_internal.txt new file mode 100644 index 0000000..f756a56 --- /dev/null +++ b/src/cmd/go/testdata/script/list_symlink_internal.txt @@ -0,0 +1,27 @@ +[!symlink] skip +env GO111MODULE=off + +mkdir $WORK/tmp/gopath/src/dir1/internal/v +cp p.go $WORK/tmp/gopath/src/dir1/p.go +cp v.go $WORK/tmp/gopath/src/dir1/internal/v/v.go +symlink $WORK/tmp/symdir1 -> $WORK/tmp/gopath/src/dir1 +env GOPATH=$WORK/tmp/gopath +cd $WORK/tmp/symdir1 +go list -f '{{.Root}}' . +stdout '^'$WORK/tmp/gopath'$' + +# All of these should succeed, not die in internal-handling code. +go run p.go & +go build & +go install & + +wait + +-- p.go -- +package main + +import _ `dir1/internal/v` + +func main() {} +-- v.go -- +package v diff --git a/src/cmd/go/testdata/script/list_symlink_issue35941.txt b/src/cmd/go/testdata/script/list_symlink_issue35941.txt new file mode 100644 index 0000000..eb12bde --- /dev/null +++ b/src/cmd/go/testdata/script/list_symlink_issue35941.txt @@ -0,0 +1,18 @@ +[!symlink] skip +env GO111MODULE=off + +# Issue 35941: suppress symlink warnings when running 'go list all'. +symlink goproj/css -> $GOPATH/src/css + +go list all +! stderr 'warning: ignoring symlink' + +# Show symlink warnings when patterns contain '...'. +go list goproj/... +stderr 'warning: ignoring symlink' + +-- goproj/a.go -- +package a + +-- css/index.css -- +body {} diff --git a/src/cmd/go/testdata/script/list_symlink_vendor_issue14054.txt b/src/cmd/go/testdata/script/list_symlink_vendor_issue14054.txt new file mode 100644 index 0000000..8e63a5a --- /dev/null +++ b/src/cmd/go/testdata/script/list_symlink_vendor_issue14054.txt @@ -0,0 +1,28 @@ +[!symlink] skip +env GO111MODULE=off + +mkdir $WORK/tmp/gopath/src/dir1/vendor/v +cp p.go $WORK/tmp/gopath/src/dir1/p.go +cp v.go $WORK/tmp/gopath/src/dir1/vendor/v/v.go +symlink $WORK/tmp/symdir1 -> $WORK/tmp/gopath/src/dir1 +env GOPATH=$WORK/tmp/gopath +cd $WORK/tmp/symdir1 + +go list -f '{{.Root}}' . +stdout '^'$WORK/tmp/gopath'$' + +# All of these should succeed, not die in vendor-handling code. +go run p.go & +go build & +go install & + +wait + +-- p.go -- +package main + +import _ `v` + +func main () {} +-- v.go -- +package v diff --git a/src/cmd/go/testdata/script/list_symlink_vendor_issue15201.txt b/src/cmd/go/testdata/script/list_symlink_vendor_issue15201.txt new file mode 100644 index 0000000..19f2138 --- /dev/null +++ b/src/cmd/go/testdata/script/list_symlink_vendor_issue15201.txt @@ -0,0 +1,21 @@ +[!symlink] skip +env GO111MODULE=off + +mkdir $WORK/tmp/gopath/src/x/y/_vendor/src/x +symlink $WORK/tmp/gopath/src/x/y/_vendor/src/x/y -> ../../.. +mkdir $WORK/tmp/gopath/src/x/y/_vendor/src/x/y/w +cp w.go $WORK/tmp/gopath/src/x/y/w/w.go +symlink $WORK/tmp/gopath/src/x/y/w/vendor -> ../_vendor/src +mkdir $WORK/tmp/gopath/src/x/y/_vendor/src/x/y/z +cp z.go $WORK/tmp/gopath/src/x/y/z/z.go + +env GOPATH=$WORK/tmp/gopath/src/x/y/_vendor${:}$WORK/tmp/gopath +cd $WORK/tmp/gopath/src +go list ./... + +-- w.go -- +package w + +import "x/y/z" +-- z.go -- +package z diff --git a/src/cmd/go/testdata/script/list_test_cycle.txt b/src/cmd/go/testdata/script/list_test_cycle.txt new file mode 100644 index 0000000..67edf18 --- /dev/null +++ b/src/cmd/go/testdata/script/list_test_cycle.txt @@ -0,0 +1,34 @@ +go list ./p +stdout 'example/p' + +! go list -json=ImportPath -test ./p +cmp stderr wanterr.txt + +! go list -json=ImportPath,Deps -test ./p +cmp stderr wanterr.txt + +! go list -json=ImportPath,Deps -deps -test ./p +cmp stderr wanterr.txt + +! go list -json=ImportPath -deps -test ./p +cmp stderr wanterr.txt + +-- wanterr.txt -- +go: can't load test package: package example/p + imports example/q + imports example/r + imports example/p: import cycle not allowed in test +-- go.mod -- +module example +go 1.20 +-- p/p.go -- +package p +-- p/p_test.go -- +package p +import "example/q" +-- q/q.go -- +package q +import "example/r" +-- r/r.go -- +package r +import "example/p" diff --git a/src/cmd/go/testdata/script/list_test_e.txt b/src/cmd/go/testdata/script/list_test_e.txt new file mode 100644 index 0000000..263892b --- /dev/null +++ b/src/cmd/go/testdata/script/list_test_e.txt @@ -0,0 +1,11 @@ +env GO111MODULE=off + +# issue 25980: crash in go list -e -test +go list -e -test -deps -f '{{.Error}}' p +stdout '^p[/\\]d_test.go:2:8: cannot find package "d" in any of:' + +-- p/d.go -- +package d +-- p/d_test.go -- +package d_test +import _ "d" diff --git a/src/cmd/go/testdata/script/list_test_err.txt b/src/cmd/go/testdata/script/list_test_err.txt new file mode 100644 index 0000000..02bd6a1 --- /dev/null +++ b/src/cmd/go/testdata/script/list_test_err.txt @@ -0,0 +1,118 @@ +env GO111MODULE=off + +# issue 28491: errors in test source files should not prevent +# "go list -test" from returning useful information. + +# go list -e prints information for all test packages. +# The syntax error is shown in the package error field. +go list -e -test -deps -f '{{.ImportPath}} {{.Error | printf "%q"}}' syntaxerr +stdout 'pkgdep <nil>' +stdout 'testdep_a <nil>' +stdout 'testdep_b <nil>' +stdout 'syntaxerr <nil>' +stdout 'syntaxerr \[syntaxerr.test\] <nil>' +stdout 'syntaxerr_test \[syntaxerr.test\] <nil>' +stdout 'syntaxerr\.test "[^"]*expected declaration' +! stderr 'expected declaration' + +[short] stop + +go list -e -test -deps -f '{{.ImportPath}} {{.Error | printf "%q"}}' nameerr +stdout 'pkgdep <nil>' +stdout 'testdep_a <nil>' +stdout 'testdep_b <nil>' +stdout 'nameerr\.test "[^"]*wrong signature for TestBad' +! stderr 'wrong signature for TestBad' + +# go list prints a useful error for generic test functions +! go list -test -deps genericerr +stderr 'wrong signature for TestGeneric, test functions cannot have type parameters' + +go list -e -test -deps -f '{{.ImportPath}} {{.Error | printf "%q"}}' cycleerr +stdout 'cycleerr <nil>' +stdout 'testdep_a <nil>' +stdout 'testdep_cycle \[cycleerr.test\] <nil>' +stdout 'cycleerr \[cycleerr.test\] "[^"]*import cycle not allowed in test' +! stderr 'import cycle not allowed in test' + +-- syntaxerr/syntaxerr.go -- +package syntaxerr + +import _ "pkgdep" + +-- syntaxerr/syntaxerr_ie_test.go -- +package syntaxerr + +!!!syntax error + +-- syntaxerr/syntaxerr_xe_test.go -- +package syntaxerr_test + +!!!syntax error + +-- syntaxerr/syntaxerr_i_test.go -- +package syntaxerr + +import _ "testdep_a" + +-- syntaxerr/syntaxerr_x_test.go -- +package syntaxerr + +import _ "testdep_b" + +-- nameerr/nameerr.go -- +package nameerr + +import _ "pkgdep" + +-- nameerr/nameerr_i_test.go -- +package nameerr + +import ( + _ "testdep_a" + "testing" +) + +func TestBad(t *testing.B) {} + +-- nameerr/nameerr_x_test.go -- +package nameerr_test + +import ( + _ "testdep_b" + "testing" +) + +func TestBad(t *testing.B) {} + +-- genericerr/genericerr.go -- +package genericerr + +-- genericerr/genericerr_test.go -- +package genericerr + +import "testing" + +func TestGeneric[T any](t *testing.T) {} + +-- cycleerr/cycleerr_test.go -- +package cycleerr + +import ( + _ "testdep_a" + _ "testdep_cycle" +) + +-- pkgdep/pkgdep.go -- +package pkgdep + +-- testdep_a/testdep_a.go -- +package testdep_a + +-- testdep_b/testdep_b.go -- +package testdep_b + +-- testdep_cycle/testdep_cycle.go -- +package testdep_cycle + +import _ "cycleerr" diff --git a/src/cmd/go/testdata/script/list_test_imports.txt b/src/cmd/go/testdata/script/list_test_imports.txt new file mode 100644 index 0000000..0342eba --- /dev/null +++ b/src/cmd/go/testdata/script/list_test_imports.txt @@ -0,0 +1,21 @@ +env GO111MODULE=off + +# issue 26880: list with tests has wrong variant in imports +go list -test -f '{{.ImportPath}}:{{with .Imports}} {{join . ", "}}{{end}}' a b +cmp stdout imports.txt + +-- a/a.go -- +package a; import _ "b" +-- b/b.go -- +package b +-- b/b_test.go -- +package b +-- b/b_x_test.go -- +package b_test; import _ "a" + +-- imports.txt -- +a: b +b: +b.test: b [b.test], b_test [b.test], os, reflect, testing, testing/internal/testdeps +b [b.test]: +b_test [b.test]: a [b.test] diff --git a/src/cmd/go/testdata/script/list_test_non_go_files.txt b/src/cmd/go/testdata/script/list_test_non_go_files.txt new file mode 100644 index 0000000..6b2b633 --- /dev/null +++ b/src/cmd/go/testdata/script/list_test_non_go_files.txt @@ -0,0 +1,13 @@ +env GO111MODULE=off + +# issue 29899: handling files with non-Go extension +go list -e -test -json -- c.c x.go +stdout '"Err": "named files must be .go files: c.c"' + +! go list -test -json -- c.c x.go +stderr '^named files must be \.go files: c\.c$' + +-- x.go -- +package main +-- c.c -- +package c diff --git a/src/cmd/go/testdata/script/list_test_simple.txt b/src/cmd/go/testdata/script/list_test_simple.txt new file mode 100644 index 0000000..954897c --- /dev/null +++ b/src/cmd/go/testdata/script/list_test_simple.txt @@ -0,0 +1,67 @@ +[short] skip + +# Test +go test -list=Test +stdout TestSimple + +# Benchmark +go test -list=Benchmark +stdout BenchmarkSimple + +# Examples +go test -list=Example +stdout ExampleSimple +stdout ExampleWithEmptyOutput + +-- go.mod -- +module m + +go 1.16 +-- bench_test.go -- +package testlist + +import ( + "fmt" + "testing" +) + +func BenchmarkSimplefunc(b *testing.B) { + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + _ = fmt.Sprint("Test for bench") + } +} +-- example_test.go -- +package testlist + +import ( + "fmt" +) + +func ExampleSimple() { + fmt.Println("Test with Output.") + + // Output: Test with Output. +} + +func ExampleWithEmptyOutput() { + fmt.Println("") + + // Output: +} + +func ExampleNoOutput() { + _ = fmt.Sprint("Test with no output") +} +-- test_test.go -- +package testlist + +import ( + "fmt" + "testing" +) + +func TestSimple(t *testing.T) { + _ = fmt.Sprint("Test simple") +} diff --git a/src/cmd/go/testdata/script/list_wildcard_skip_nonmatching.txt b/src/cmd/go/testdata/script/list_wildcard_skip_nonmatching.txt new file mode 100644 index 0000000..02b1088 --- /dev/null +++ b/src/cmd/go/testdata/script/list_wildcard_skip_nonmatching.txt @@ -0,0 +1,17 @@ +# Test that wildcards don't look in useless directories. + +# First make sure that badpkg fails the list of '...'. +! go list ./... +stderr badpkg + +# Check that the list of './goodpkg...' succeeds. That implies badpkg was skipped. +go list ./goodpkg... + +-- go.mod -- +module m + +go 1.16 +-- goodpkg/x.go -- +package goodpkg +-- badpkg/x.go -- +pkg badpkg diff --git a/src/cmd/go/testdata/script/load_test_pkg_err.txt b/src/cmd/go/testdata/script/load_test_pkg_err.txt new file mode 100644 index 0000000..d088ee4 --- /dev/null +++ b/src/cmd/go/testdata/script/load_test_pkg_err.txt @@ -0,0 +1,30 @@ +# Tests issue 37971. Check that tests are still loaded even when the package has an error. + +go list -e -test d +cmp stdout want_stdout + +go list -e -test -deps d +stdout golang.org/fake/d + +-- want_stdout -- +d +d.test +d_test [d.test] +-- go.mod -- +module d + +go 1.16 +-- d.go -- +package d + +import "net/http" + +const d = http.MethodGet +func Get() string { return d; } +-- d2.go -- +-- d_test.go -- +package d_test + +import "testing" +import "golang.org/fake/d" +func TestD(t *testing.T) { d.Get(); } diff --git a/src/cmd/go/testdata/script/malformed_gosum_issue62345.txt b/src/cmd/go/testdata/script/malformed_gosum_issue62345.txt new file mode 100644 index 0000000..23c41be --- /dev/null +++ b/src/cmd/go/testdata/script/malformed_gosum_issue62345.txt @@ -0,0 +1,51 @@ +! go mod download +stderr '^malformed go.sum:\n.*go.sum:3: wrong number of fields 5\n$' + +go mod tidy +cmp go.sum go.sum.after-tidy + +-- go.mod -- +module m + +go 1.20 + +require rsc.io/quote v1.5.2 + +require ( + golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect + rsc.io/sampler v1.3.0 // indirect + rsc.io/testonly v1.0.0 // indirect +) + +-- go.sum -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2 # invalid line +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= + +-- main.go -- +package main + +import ( + "fmt" + + "rsc.io/quote" +) + +func main() { + fmt.Println(quote.Hello()) +} + +-- go.sum.after-tidy -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= diff --git a/src/cmd/go/testdata/script/mod_all.txt b/src/cmd/go/testdata/script/mod_all.txt new file mode 100644 index 0000000..b71a920 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_all.txt @@ -0,0 +1,531 @@ +# This test illustrates the relationship between the 'all' pattern and +# the dependencies of the main module. + +# The package import graph used in this test looks like: +# +# main --------- a --------- b +# | | +# | a_test ---- c +# | | +# | c_test ---- d +# | +# main_test ---- t --------- u +# | +# t_test ---- w +# | +# w_test ---- x +# +# main/testonly_test ---- q --------- r +# | +# q_test ---- s +# +# And the module dependency graph looks like: +# +# main --- a.1 ---- b.1 +# \ \ \ +# \ \ c.1 -- d.1 +# \ \ +# \ t.1 ---- u.1 +# \ \ +# \ w.1 -- x.1 +# \ +# q.1 ---- r.1 +# \ +# s.1 + +env PKGFMT='{{if .Module}}{{.ImportPath}}{{end}}' +env MODFMT='{{.Path}}' + + +# 'go list -deps' lists packages and tests in the main module, +# along with their transitive dependencies. + +go list -f $PKGFMT -deps ./... +stdout -count=4 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/main$' +stdout '^example.com/main/testonly' + + +# 'go list -deps -test' lists transitive imports of tests and non-tests in the +# main module. + +go list -f $PKGFMT -deps -test ./... +stdout -count=13 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/main$' +stdout '^example.com/main.test$' +stdout '^example.com/main \[example.com/main.test\]$' +stdout '^example.com/main_test \[example.com/main.test\]$' +stdout '^example.com/main/testonly$' +stdout '^example.com/main/testonly.test$' +stdout '^example.com/main/testonly_test \[example.com/main/testonly.test\]$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/t$' +stdout '^example.com/u$' + + +# 'go list all' lists the fixpoint of iterating 'go list -deps -test' starting +# with the packages in the main module, then reducing to only the non-test +# variants of those packages. + +go list -f $PKGFMT all +stdout -count=13 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/c$' +stdout '^example.com/d$' +stdout '^example.com/main$' +stdout '^example.com/main/testonly$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/s$' +stdout '^example.com/t$' +stdout '^example.com/u$' +stdout '^example.com/w$' +stdout '^example.com/x$' + + +# 'go list -test all' is equivalent to 'go list -test $(go list all)' +# and both should include tests for every package in 'all'. + +go list -test -f $PKGFMT example.com/a example.com/b example.com/c example.com/d example.com/main example.com/main/testonly example.com/q example.com/r example.com/s example.com/t example.com/u example.com/w example.com/x +cp stdout list-test-explicit.txt + +go list -test -f $PKGFMT all +cmp stdout list-test-explicit.txt +stdout -count=36 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/c$' +stdout '^example.com/d$' +stdout '^example.com/main$' +stdout '^example.com/main/testonly$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/s$' +stdout '^example.com/t$' +stdout '^example.com/u$' +stdout '^example.com/w$' +stdout '^example.com/x$' +stdout '^example.com/a.test$' +stdout '^example.com/a_test \[example.com/a.test\]$' +stdout '^example.com/b.test$' +stdout '^example.com/b_test \[example.com/b.test\]$' +stdout '^example.com/c.test$' +stdout '^example.com/c_test \[example.com/c.test\]$' +stdout '^example.com/main.test$' +stdout '^example.com/main \[example.com/main.test\]$' +stdout '^example.com/main_test \[example.com/main.test\]$' +stdout '^example.com/main/testonly.test$' +stdout '^example.com/main/testonly_test \[example.com/main/testonly.test\]$' +stdout '^example.com/q.test$' +stdout '^example.com/q_test \[example.com/q.test\]$' +stdout '^example.com/r.test$' +stdout '^example.com/r_test \[example.com/r.test\]$' +stdout '^example.com/s.test$' +stdout '^example.com/s_test \[example.com/s.test\]$' +stdout '^example.com/t.test$' +stdout '^example.com/t_test \[example.com/t.test\]$' +stdout '^example.com/u.test$' +stdout '^example.com/u_test \[example.com/u.test\]$' +stdout '^example.com/w.test$' +stdout '^example.com/w_test \[example.com/w.test\]$' + + +# 'go list -m all' covers the packages in 'go list -test -deps all'. + +go list -m -f $MODFMT all +stdout -count=12 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/c$' +stdout '^example.com/d$' +stdout '^example.com/main$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/s$' +stdout '^example.com/t$' +stdout '^example.com/u$' +stdout '^example.com/w$' +stdout '^example.com/x$' + + +# 'go mod vendor' copies in only the packages transitively imported by the main +# module, and omits their tests. As a result, the 'all' and '...' patterns +# report fewer packages when using '-mod=vendor'. + +go mod vendor + +go list -f $PKGFMT -mod=vendor all +stdout -count=8 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/main$' +stdout '^example.com/main/testonly$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/t$' +stdout '^example.com/u$' + +go list -test -f $PKGFMT -mod=vendor all +stdout -count=13 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/main$' +stdout '^example.com/main/testonly$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/t$' +stdout '^example.com/u$' +stdout '^example.com/main.test$' +stdout '^example.com/main \[example.com/main.test\]$' +stdout '^example.com/main_test \[example.com/main.test\]$' +stdout '^example.com/main/testonly.test$' +stdout '^example.com/main/testonly_test \[example.com/main/testonly.test\]$' + +rm vendor + +# Convert all modules to go 1.17 to enable lazy loading. +go mod edit -go=1.17 a/go.mod +go mod edit -go=1.17 b/go.mod +go mod edit -go=1.17 c/go.mod +go mod edit -go=1.17 d/go.mod +go mod edit -go=1.17 q/go.mod +go mod edit -go=1.17 r/go.mod +go mod edit -go=1.17 s/go.mod +go mod edit -go=1.17 t/go.mod +go mod edit -go=1.17 u/go.mod +go mod edit -go=1.17 w/go.mod +go mod edit -go=1.17 x/go.mod +go mod edit -go=1.17 +cmp go.mod go.mod.beforetidy +go mod tidy +cmp go.mod go.mod.aftertidy + +# With lazy loading, 'go list all' with neither -mod=vendor nor -test should +# match -mod=vendor without -test in 1.15. + +go list -f $PKGFMT all +stdout -count=8 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/main$' +stdout '^example.com/main/testonly$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/t$' +stdout '^example.com/u$' + +# 'go list -test all' should expand that to include the test variants of the +# packages in 'all', but not the dependencies of outside tests. + +go list -test -f $PKGFMT all +stdout -count=25 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/main$' +stdout '^example.com/main/testonly$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/t$' +stdout '^example.com/u$' +stdout '^example.com/a.test$' +stdout '^example.com/a_test \[example.com/a.test\]$' +stdout '^example.com/b.test$' +stdout '^example.com/b_test \[example.com/b.test\]$' +stdout '^example.com/main.test$' +stdout '^example.com/main \[example.com/main.test\]$' +stdout '^example.com/main_test \[example.com/main.test\]$' +stdout '^example.com/main/testonly.test$' +stdout '^example.com/main/testonly_test \[example.com/main/testonly.test\]$' +stdout '^example.com/q.test$' +stdout '^example.com/q_test \[example.com/q.test\]$' +stdout '^example.com/r.test$' +stdout '^example.com/r_test \[example.com/r.test\]$' +stdout '^example.com/t.test$' +stdout '^example.com/t_test \[example.com/t.test\]$' +stdout '^example.com/u.test$' +stdout '^example.com/u_test \[example.com/u.test\]$' + +# 'go list -test -deps all' should include the dependencies of those tests, +# but not the tests of the dependencies of outside tests. + +go list -test -deps -f $PKGFMT all +stdout -count=28 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/c$' +stdout '^example.com/main$' +stdout '^example.com/main/testonly$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/s$' +stdout '^example.com/t$' +stdout '^example.com/u$' +stdout '^example.com/w$' +stdout '^example.com/a.test$' +stdout '^example.com/a_test \[example.com/a.test\]$' +stdout '^example.com/b.test$' +stdout '^example.com/b_test \[example.com/b.test\]$' +stdout '^example.com/main.test$' +stdout '^example.com/main \[example.com/main.test\]$' +stdout '^example.com/main_test \[example.com/main.test\]$' +stdout '^example.com/main/testonly.test$' +stdout '^example.com/main/testonly_test \[example.com/main/testonly.test\]$' +stdout '^example.com/q.test$' +stdout '^example.com/q_test \[example.com/q.test\]$' +stdout '^example.com/r.test$' +stdout '^example.com/r_test \[example.com/r.test\]$' +stdout '^example.com/t.test$' +stdout '^example.com/t_test \[example.com/t.test\]$' +stdout '^example.com/u.test$' +stdout '^example.com/u_test \[example.com/u.test\]$' + +# 'go list -m all' should cover all of the modules providing packages in +# 'go list -test -deps all', but should exclude modules d and x, +# which are not relevant to the main module and are outside of the +# lazy-loading horizon. + +go list -m -f $MODFMT all +stdout -count=10 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/c$' +! stdout '^example.com/d$' +stdout '^example.com/main$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/s$' +stdout '^example.com/t$' +stdout '^example.com/u$' +stdout '^example.com/w$' +! stdout '^example.com/x$' + +-- go.mod -- +module example.com/main + +// Note: this go.mod file initially specifies go 1.15, +// but includes some redundant roots so that it +// also already obeys the 1.17 lazy loading invariants. +go 1.15 + +require ( + example.com/a v0.1.0 + example.com/b v0.1.0 // indirect + example.com/q v0.1.0 + example.com/r v0.1.0 // indirect + example.com/t v0.1.0 + example.com/u v0.1.0 // indirect +) + +replace ( + example.com/a v0.1.0 => ./a + example.com/b v0.1.0 => ./b + example.com/c v0.1.0 => ./c + example.com/d v0.1.0 => ./d + example.com/q v0.1.0 => ./q + example.com/r v0.1.0 => ./r + example.com/s v0.1.0 => ./s + example.com/t v0.1.0 => ./t + example.com/u v0.1.0 => ./u + example.com/w v0.1.0 => ./w + example.com/x v0.1.0 => ./x +) +-- main.go -- +package main + +import _ "example.com/a" + +func main() {} +-- main_test.go -- +package main_test + +import _ "example.com/t" +-- testonly/testonly_test.go -- +package testonly_test + +import _ "example.com/q" +-- a/go.mod -- +module example.com/a + +go 1.15 + +require ( + example.com/b v0.1.0 + example.com/c v0.1.0 +) +-- a/a.go -- +package a + +import _ "example.com/b" +-- a/a_test.go -- +package a_test + +import _ "example.com/c" +-- b/go.mod -- +module example.com/b + +go 1.15 +-- b/b.go -- +package b +-- b/b_test.go -- +package b_test +-- c/go.mod -- +module example.com/c + +go 1.15 + +require example.com/d v0.1.0 +-- c/c.go -- +package c +-- c/c_test.go -- +package c_test + +import _ "example.com/d" +-- d/go.mod -- +module example.com/d + +go 1.15 +-- d/d.go -- +package d +-- q/go.mod -- +module example.com/q + +go 1.15 + +require ( + example.com/r v0.1.0 + example.com/s v0.1.0 +) +-- q/q.go -- +package q +import _ "example.com/r" +-- q/q_test.go -- +package q_test +import _ "example.com/s" +-- r/go.mod -- +module example.com/r + +go 1.15 +-- r/r.go -- +package r +-- r/r_test.go -- +package r_test +-- s/go.mod -- +module example.com/s + +go 1.15 +-- s/s.go -- +package s +-- s/s_test.go -- +package s_test +-- t/go.mod -- +module example.com/t + +go 1.15 + +require ( + example.com/u v0.1.0 + example.com/w v0.1.0 +) +-- t/t.go -- +package t + +import _ "example.com/u" +-- t/t_test.go -- +package t_test + +import _ "example.com/w" +-- u/go.mod -- +module example.com/u + +go 1.15 +-- u/u.go -- +package u +-- u/u_test.go -- +package u_test +-- w/go.mod -- +module example.com/w + +go 1.15 + +require example.com/x v0.1.0 +-- w/w.go -- +package w +-- w/w_test.go -- +package w_test + +import _ "example.com/x" +-- x/go.mod -- +module example.com/x + +go 1.15 +-- x/x.go -- +package x +-- go.mod.beforetidy -- +module example.com/main + +// Note: this go.mod file initially specifies go 1.15, +// but includes some redundant roots so that it +// also already obeys the 1.17 lazy loading invariants. +go 1.17 + +require ( + example.com/a v0.1.0 + example.com/b v0.1.0 // indirect + example.com/q v0.1.0 + example.com/r v0.1.0 // indirect + example.com/t v0.1.0 + example.com/u v0.1.0 // indirect +) + +replace ( + example.com/a v0.1.0 => ./a + example.com/b v0.1.0 => ./b + example.com/c v0.1.0 => ./c + example.com/d v0.1.0 => ./d + example.com/q v0.1.0 => ./q + example.com/r v0.1.0 => ./r + example.com/s v0.1.0 => ./s + example.com/t v0.1.0 => ./t + example.com/u v0.1.0 => ./u + example.com/w v0.1.0 => ./w + example.com/x v0.1.0 => ./x +) +-- go.mod.aftertidy -- +module example.com/main + +// Note: this go.mod file initially specifies go 1.15, +// but includes some redundant roots so that it +// also already obeys the 1.17 lazy loading invariants. +go 1.17 + +require ( + example.com/a v0.1.0 + example.com/q v0.1.0 + example.com/t v0.1.0 +) + +require ( + example.com/b v0.1.0 // indirect + example.com/r v0.1.0 // indirect + example.com/u v0.1.0 // indirect +) + +replace ( + example.com/a v0.1.0 => ./a + example.com/b v0.1.0 => ./b + example.com/c v0.1.0 => ./c + example.com/d v0.1.0 => ./d + example.com/q v0.1.0 => ./q + example.com/r v0.1.0 => ./r + example.com/s v0.1.0 => ./s + example.com/t v0.1.0 => ./t + example.com/u v0.1.0 => ./u + example.com/w v0.1.0 => ./w + example.com/x v0.1.0 => ./x +) diff --git a/src/cmd/go/testdata/script/mod_alt_goroot.txt b/src/cmd/go/testdata/script/mod_alt_goroot.txt new file mode 100644 index 0000000..32f94c5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_alt_goroot.txt @@ -0,0 +1,20 @@ +env GO111MODULE=on + +# If the working directory is a different GOROOT, then the 'std' module should be +# treated as an ordinary module (with an ordinary module prefix). +# It should not override packages in GOROOT, but should not fail the command. +# See golang.org/issue/30756. +go list -e -deps -f '{{.ImportPath}} {{.Dir}}' ./bytes +stdout ^std/bytes.*$PWD[/\\]bytes +stdout '^bytes/modified' + +-- go.mod -- +module std + +go 1.12 +-- bytes/bytes.go -- +package bytes + +import _"bytes/modified" +-- bytes/modified/modified.go -- +package modified diff --git a/src/cmd/go/testdata/script/mod_ambiguous_import.txt b/src/cmd/go/testdata/script/mod_ambiguous_import.txt new file mode 100644 index 0000000..feaf5d2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_ambiguous_import.txt @@ -0,0 +1,48 @@ +env GO111MODULE=on + +cd $WORK + +# An import provided by two different modules should be flagged as an error. +! go build ./importx +stderr '^importx[/\\]importx.go:2:8: ambiguous import: found package example.com/a/x in multiple modules:\n\texample.com/a v0.1.0 \('$WORK'[/\\]a[/\\]x\)\n\texample.com/a/x v0.1.0 \('$WORK'[/\\]ax\)$' + +# However, it should not be an error if that import is unused. +go build ./importy + +# An import provided by both the main module and the vendor directory +# should be flagged as an error only when -mod=vendor is set. +mkdir vendor/example.com/m/importy +cp $WORK/importy/importy.go vendor/example.com/m/importy/importy.go +go build example.com/m/importy +! go build -mod=vendor example.com/m/importy +stderr '^ambiguous import: found package example.com/m/importy in multiple directories:\n\t'$WORK'[/\\]importy\n\t'$WORK'[/\\]vendor[/\\]example.com[/\\]m[/\\]importy$' + +-- $WORK/go.mod -- +module example.com/m +go 1.13 +require ( + example.com/a v0.1.0 + example.com/a/x v0.1.0 +) +replace ( + example.com/a v0.1.0 => ./a + example.com/a/x v0.1.0 => ./ax +) +-- $WORK/importx/importx.go -- +package importx +import _ "example.com/a/x" +-- $WORK/importy/importy.go -- +package importy +import _ "example.com/a/y" +-- $WORK/a/go.mod -- +module example.com/a +go 1.14 +-- $WORK/a/x/x.go -- +package x +-- $WORK/a/y/y.go -- +package y +-- $WORK/ax/go.mod -- +module example.com/a/x +go 1.14 +-- $WORK/ax/x.go -- +package x diff --git a/src/cmd/go/testdata/script/mod_auth.txt b/src/cmd/go/testdata/script/mod_auth.txt new file mode 100644 index 0000000..5e2b7a9 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_auth.txt @@ -0,0 +1,35 @@ +[short] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off +env GOVCS='*:off' + +# Without credentials, downloading a module from a path that requires HTTPS +# basic auth should fail. +env NETRC=$WORK/empty +! go mod tidy +stderr '^\tserver response: ACCESS DENIED, buddy$' +stderr '^\tserver response: File\? What file\?$' + +# With credentials from a netrc file, it should succeed. +env NETRC=$WORK/netrc +go mod tidy +go list all +stdout vcs-test.golang.org/auth/or401 +stdout vcs-test.golang.org/auth/or404 + +-- go.mod -- +module private.example.com +-- main.go -- +package useprivate + +import ( + _ "vcs-test.golang.org/auth/or401" + _ "vcs-test.golang.org/auth/or404" +) +-- $WORK/empty -- +-- $WORK/netrc -- +machine vcs-test.golang.org + login aladdin + password opensesame diff --git a/src/cmd/go/testdata/script/mod_bad_domain.txt b/src/cmd/go/testdata/script/mod_bad_domain.txt new file mode 100644 index 0000000..86aa96e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_bad_domain.txt @@ -0,0 +1,47 @@ +env GO111MODULE=on + +# explicit get should report errors about bad names +! go get appengine +stderr '^go: malformed module path "appengine": missing dot in first path element$' +! go get x/y.z +stderr 'malformed module path "x/y.z": missing dot in first path element' + + +# 'go list -m' should report errors about module names, never GOROOT. +! go list -m -versions appengine +stderr 'malformed module path "appengine": missing dot in first path element' +! go list -m -versions x/y.z +stderr 'malformed module path "x/y.z": missing dot in first path element' + + +# build should report all unsatisfied imports, +# but should be more definitive about non-module import paths +! go build ./useappengine +stderr '^useappengine[/\\]x.go:2:8: cannot find package$' +! go build ./usenonexistent +stderr '^usenonexistent[/\\]x.go:2:8: no required module provides package nonexistent.rsc.io; to add it:\n\tgo get nonexistent.rsc.io$' + + +# 'get -d' should be similarly definitive + +go get ./useappengine # TODO(#41315): This should fail. + # stderr '^useappengine[/\\]x.go:2:8: cannot find package$' + +! go get ./usenonexistent +stderr '^go: x/usenonexistent imports\n\tnonexistent.rsc.io: cannot find module providing package nonexistent.rsc.io$' + + +# go mod vendor and go mod tidy should ignore appengine imports. +rm usenonexistent/x.go +go mod tidy +go mod vendor + +-- go.mod -- +module x + +-- useappengine/x.go -- +package useappengine +import _ "appengine" // package does not exist +-- usenonexistent/x.go -- +package usenonexistent +import _ "nonexistent.rsc.io" // domain does not exist diff --git a/src/cmd/go/testdata/script/mod_bad_filenames.txt b/src/cmd/go/testdata/script/mod_bad_filenames.txt new file mode 100644 index 0000000..eb556f4 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_bad_filenames.txt @@ -0,0 +1,11 @@ +env GO111MODULE=on + +! go get rsc.io/badfile1 rsc.io/badfile2 rsc.io/badfile3 rsc.io/badfile4 rsc.io/badfile5 +! stderr 'unzip.*badfile1' +stderr 'unzip.*badfile2[\\/]@v[\\/]v1.0.0.zip:.*malformed file path "☺.go": invalid char ''☺''' +stderr 'unzip.*badfile3[\\/]@v[\\/]v1.0.0.zip: rsc.io[\\/]badfile3@v1.0.0[\\/]x\?y.go: malformed file path "x\?y.go": invalid char ''\?''' +stderr 'unzip.*badfile4[\\/]@v[\\/]v1.0.0.zip: rsc.io[\\/]badfile4@v1.0.0[\\/]x[\\/]y.go: case-insensitive file name collision: "x/Y.go" and "x/y.go"' +stderr 'unzip.*badfile5[\\/]@v[\\/]v1.0.0.zip: rsc.io[\\/]badfile5@v1.0.0[\\/]x[\\/]Y[\\/]zz[\\/]ww.go: case-insensitive file name collision: "x/y" and "x/Y"' + +-- go.mod -- +module x diff --git a/src/cmd/go/testdata/script/mod_build_info_err.txt b/src/cmd/go/testdata/script/mod_build_info_err.txt new file mode 100644 index 0000000..8d7bd0c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_build_info_err.txt @@ -0,0 +1,33 @@ +# This test verifies that line numbers are included in module import errors. +# Verifies golang.org/issue/34393. + +go list -e -mod=mod -deps -f '{{with .Error}}{{.Pos}}: {{.Err}}{{end}}' ./main +stdout '^bad[/\\]bad.go:3:8: malformed import path "🐧.example.com/string": invalid char ''🐧''$' + +# TODO(#26909): This should include an import stack. +# (Today it includes only a file and line.) +! go build ./main +stderr '^bad[/\\]bad.go:3:8: malformed import path "🐧.example.com/string": invalid char ''🐧''$' + +# TODO(#41688): This should include a file and line, and report the reason for the error.. +# (Today it includes only an import stack.) +! go get ./main +stderr '^go: m/main imports\n\tm/bad imports\n\t🐧.example.com/string: malformed import path "🐧.example.com/string": invalid char ''🐧''$' + + +-- go.mod -- +module m + +go 1.13 + +-- main/main.go -- +package main + +import _ "m/bad" + +func main() {} + +-- bad/bad.go -- +package bad + +import _ "🐧.example.com/string" diff --git a/src/cmd/go/testdata/script/mod_build_tags.txt b/src/cmd/go/testdata/script/mod_build_tags.txt new file mode 100644 index 0000000..ae1d605 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_build_tags.txt @@ -0,0 +1,33 @@ +# Test that build tags are used. +# golang.org/issue/24053. + +env GO111MODULE=on + +cd x +! go list -f {{.GoFiles}} +stderr 'build constraints exclude all Go files' + +go list -f {{.GoFiles}} -tags tag1 +stdout '\[x.go\]' + +go list -f {{.GoFiles}} -tags tag2 +stdout '\[y\.go\]' + +go list -f {{.GoFiles}} -tags 'tag1 tag2' +stdout '\[x\.go y\.go\]' + +go list -f {{.GoFiles}} -tags tag1,tag2 # commas allowed as of Go 1.13 +stdout '\[x\.go y\.go\]' + +-- x/go.mod -- +module x + +-- x/x.go -- +// +build tag1 + +package y + +-- x/y.go -- +// +build tag2 + +package y diff --git a/src/cmd/go/testdata/script/mod_build_trimpath_issue48557.txt b/src/cmd/go/testdata/script/mod_build_trimpath_issue48557.txt new file mode 100644 index 0000000..859eafc --- /dev/null +++ b/src/cmd/go/testdata/script/mod_build_trimpath_issue48557.txt @@ -0,0 +1,52 @@ +# Regression test for issue #48557. +# Since builds in module mode do not support relative imports at all, the build +# ID for (and other contents of) a binary built with -trimpath in module mode +# should not depend on its working directory, even if the binary is specified as +# a list of relative source files. + +[short] skip # links and runs binaries + +env GOFLAGS=-trimpath +env GOCACHE=$WORK/gocache + + +# When we build a binary in module mode with -trimpath, the -D flag (for the +# "local import prefix") should not be passed to it. + +cd $WORK/tmp/foo +go build -x -o a.exe main.go +stderr ${/}compile$GOEXE.*' -nolocalimports' +! stderr ${/}compile$GOEXE.*' -D[ =]' + +go tool buildid a.exe +cp stdout ../foo-buildid.txt +go version a.exe +cp stdout ../foo-version.txt +cd .. + + +# On the second build — in a different directory but with -trimpath — the +# compiler should not be invoked, since the cache key should be identical. +# Only the linker and buildid tool should be needed. + +mkdir bar +cp foo/main.go bar/main.go +cd bar +go build -x -o a.exe main.go +! stderr ${/}compile$GOEXE + +go tool buildid a.exe +cp stdout ../bar-buildid.txt +go version a.exe +cp stdout ../bar-version.txt +cd .. + +cmp bar-buildid.txt foo-buildid.txt +cmp bar-version.txt foo-version.txt +cmp bar/a.exe foo/a.exe + + +-- $WORK/tmp/foo/main.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/mod_build_versioned.txt b/src/cmd/go/testdata/script/mod_build_versioned.txt new file mode 100644 index 0000000..f550418 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_build_versioned.txt @@ -0,0 +1,17 @@ +env GO111MODULE=on +[short] skip + +go get rsc.io/fortune/v2 + +# The default executable name shouldn't be v2$GOEXE +go build rsc.io/fortune/v2 +! exists v2$GOEXE +exists fortune$GOEXE + +# The default test binary name shouldn't be v2.test$GOEXE +go test -c rsc.io/fortune/v2 +! exists v2.test$GOEXE +exists fortune.test$GOEXE + +-- go.mod -- +module scratch diff --git a/src/cmd/go/testdata/script/mod_cache_dir.txt b/src/cmd/go/testdata/script/mod_cache_dir.txt new file mode 100644 index 0000000..4045928 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_cache_dir.txt @@ -0,0 +1,11 @@ +env GO111MODULE=on + +# Go should reject relative paths in GOMODCACHE environment. + +env GOMODCACHE="~/test" +! go install example.com/tools/cmd/hello@latest +stderr 'must be absolute path' + +env GOMODCACHE="./test" +! go install example.com/tools/cmd/hello@latest +stderr 'must be absolute path' diff --git a/src/cmd/go/testdata/script/mod_cache_rw.txt b/src/cmd/go/testdata/script/mod_cache_rw.txt new file mode 100644 index 0000000..87f27e8 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_cache_rw.txt @@ -0,0 +1,49 @@ +# Regression test for golang.org/issue/31481. + +env GO111MODULE=on + +# golang.org/issue/31481: an explicit flag should make directories in the module +# cache writable in order to work around the historical inability of 'rm -rf' to +# forcibly remove files in unwritable directories. +go get -modcacherw rsc.io/quote@v1.5.2 +cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/extraneous_file.go + +# After adding an extraneous file, 'go mod verify' should fail. +! go mod verify + +# However, files within those directories should still be read-only to avoid +# accidental mutations. +[!root] ! cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod + +# If all 'go' commands ran with the flag, the system's 'rm' binary +# should be able to remove the module cache if the '-rf' flags are set. +[!GOOS:windows] [exec:rm] exec rm -rf $GOPATH/pkg/mod +[!GOOS:windows] [!exec:rm] go clean -modcache +[GOOS:windows] [exec:cmd.exe] exec cmd.exe /c rmdir /s /q $GOPATH\pkg\mod +[GOOS:windows] [!exec:cmd.exe] go clean -modcache +! exists $GOPATH/pkg/mod + +# The directories in the module cache should by default be unwritable, +# so that tests and tools will not accidentally add extraneous files to them. +# Windows does not respect FILE_ATTRIBUTE_READONLY on directories, according +# to MSDN, so there we disable testing whether the directory itself is +# unwritable. +go get rsc.io/quote@latest +[!root] ! cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod +[!GOOS:windows] [!root] ! cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/extraneous_file.go +! exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/extraneous_file.go + + +# Repeat part of the test with 'go mod download' instead of 'go get' to verify +# -modcacherw is supported on 'go mod' subcommands. +go clean -modcache +go mod download -modcacherw rsc.io/quote +cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/extraneous_file.go +! go mod verify +[!root] ! cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod + + +-- $WORK/extraneous.txt -- +module oops +-- go.mod -- +module golang.org/issue/31481 diff --git a/src/cmd/go/testdata/script/mod_case.txt b/src/cmd/go/testdata/script/mod_case.txt new file mode 100644 index 0000000..d3fb11d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_case.txt @@ -0,0 +1,25 @@ +env GO111MODULE=on + +go get +go list -m all +stdout '^rsc.io/quote v1.5.2' +stdout '^rsc.io/QUOTE v1.5.2' + +go list -f 'DIR {{.Dir}} DEPS {{.Deps}}' rsc.io/QUOTE/QUOTE +stdout 'DEPS.*rsc.io/quote' +stdout 'DIR.*!q!u!o!t!e' + +go get rsc.io/QUOTE@v1.5.3-PRE +go list -m all +stdout '^rsc.io/QUOTE v1.5.3-PRE' + +go list -f '{{.Dir}}' rsc.io/QUOTE/QUOTE +stdout '!q!u!o!t!e@v1.5.3-!p!r!e' + +-- go.mod -- +module x + +-- use.go -- +package use + +import _ "rsc.io/QUOTE/QUOTE" diff --git a/src/cmd/go/testdata/script/mod_case_cgo.txt b/src/cmd/go/testdata/script/mod_case_cgo.txt new file mode 100644 index 0000000..7c768a0 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_case_cgo.txt @@ -0,0 +1,11 @@ +[!cgo] skip + +env GO111MODULE=on + +go get rsc.io/CGO +[short] stop + +go build rsc.io/CGO + +-- go.mod -- +module x diff --git a/src/cmd/go/testdata/script/mod_clean_cache.txt b/src/cmd/go/testdata/script/mod_clean_cache.txt new file mode 100644 index 0000000..2b8e820 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_clean_cache.txt @@ -0,0 +1,61 @@ +env GO111MODULE=on + +# 'mod download' should download the module to the cache. +go mod download rsc.io/quote@v1.5.0 +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.mod +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.zip + +# '-n' should print commands but not actually execute them. +go clean -modcache -n +stdout '^rm -rf .*pkg.mod$' +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.mod +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.zip + +# 'go clean -modcache' should actually delete the files. +go clean -modcache +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.info +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.mod +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.zip + +# 'go clean -r -modcache' should clean only the dependencies that are within the +# main module. +# BUG(golang.org/issue/28680): Today, it cleans across module boundaries. +cd r +exists ./test.out +exists ../replaced/test.out +go clean -r -modcache +! exists ./test.out +! exists ../replaced/test.out # BUG: should still exist + +# 'go clean -modcache' should not download anything before cleaning. +go mod edit -require rsc.io/quote@v1.99999999.0-not-a-real-version +go clean -modcache +! stderr 'finding rsc.io' +go mod edit -droprequire rsc.io/quote + +! go clean -modcache m +stderr 'go: clean -modcache cannot be used with package arguments' + +-- go.mod -- +module m +-- m.go -- +package m + +-- r/go.mod -- +module example.com/r +require example.com/r/replaced v0.0.0 +replace example.com/r/replaced => ../replaced +-- r/r.go -- +package r +import _ "example.com/r/replaced" +-- r/test.out -- +DELETE ME + +-- replaced/go.mod -- +module example.com/r/replaced +-- replaced/replaced.go -- +package replaced +-- replaced/test.out -- +DO NOT DELETE diff --git a/src/cmd/go/testdata/script/mod_concurrent.txt b/src/cmd/go/testdata/script/mod_concurrent.txt new file mode 100644 index 0000000..e2224d6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_concurrent.txt @@ -0,0 +1,32 @@ +env GO111MODULE=on + +# Concurrent builds should succeed, even if they need to download modules. +go get ./x ./y +go build ./x & +go build ./y +wait + +# Concurrent builds should update go.sum to the union of the hashes for the +# modules they read. +cmp go.sum go.sum.want + +-- go.mod -- +module golang.org/issue/26794 + +require ( + golang.org/x/text v0.3.0 + rsc.io/sampler v1.0.0 +) +-- x/x.go -- +package x + +import _ "golang.org/x/text/language" +-- y/y.go -- +package y + +import _ "rsc.io/sampler" +-- go.sum.want -- +golang.org/x/text v0.3.0 h1:ivTorhoiROmZ1mcs15mO2czVF0uy0tnezXpBVNzgrmA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/sampler v1.0.0 h1:SRJnjyQ07sAtq6G4RcfJEmz8JxqLyj3PoGXG2VhbDWo= +rsc.io/sampler v1.0.0/go.mod h1:cqxpM3ZVz9VtirqxZPmrWzkQ+UkiNiGtkrN+B+i8kx8= diff --git a/src/cmd/go/testdata/script/mod_convert_git.txt b/src/cmd/go/testdata/script/mod_convert_git.txt new file mode 100644 index 0000000..6ff1eb5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_git.txt @@ -0,0 +1,40 @@ +env GO111MODULE=on + +# We should not create a go.mod file unless the user ran 'go mod init' explicitly. +# However, we should suggest 'go mod init' if we can find an alternate config file. +cd $WORK/test/x +! go list . +stderr 'found .git/config in .*[/\\]test' +stderr '\s*cd \.\. && go mod init' + +# The command we suggested should succeed. +cd .. +go mod init +go list -m all +stdout '^m$' + +# We should not suggest creating a go.mod file in $GOROOT, even though there may be a .git/config there. +cd $GOROOT +! go list . +! stderr 'go mod init' + +# We should also not suggest creating a go.mod file in $GOROOT if its own +# .git/config has been stripped away and we find one in a parent directory. +# (https://golang.org/issue/34191) +env GOROOT=$WORK/parent/goroot +cd $GOROOT +! go list . +! stderr 'go mod init' + +cd $GOROOT/doc +! go list . +! stderr 'go mod init' + +-- $WORK/test/.git/config -- +-- $WORK/test/x/x.go -- +package x // import "m/x" +-- $WORK/parent/.git/config -- +-- $WORK/parent/goroot/README -- +This directory isn't really a GOROOT, but let's pretend that it is. +-- $WORK/parent/goroot/doc/README -- +This is a subdirectory of our fake GOROOT. diff --git a/src/cmd/go/testdata/script/mod_deprecate_message.txt b/src/cmd/go/testdata/script/mod_deprecate_message.txt new file mode 100644 index 0000000..1fb1246 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_deprecate_message.txt @@ -0,0 +1,73 @@ +# When there is a short single-line message, 'go get' should print it all. +go get short +stderr '^go: module short is deprecated: short$' +go list -m -u -f '{{.Deprecated}}' short +stdout '^short$' + +# When there is a multi-line message, 'go get' should print the first line. +go get multiline +stderr '^go: module multiline is deprecated: first line$' +! stderr 'second line' +go list -m -u -f '{{.Deprecated}}' multiline +stdout '^first line\nsecond line.$' + +# When there is a long message, 'go get' should print a placeholder. +go get long +stderr '^go: module long is deprecated: \(message omitted: too long\)$' +go list -m -u -f '{{.Deprecated}}' long +stdout '^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa$' + +# When a message contains unprintable characters, 'go get' should say that +# without printing the message. +go get unprintable +stderr '^go: module unprintable is deprecated: \(message omitted: contains non-printable characters\)$' +go list -m -u -f '{{.Deprecated}}' unprintable +stdout '^message contains ASCII BEL\x07$' + +-- go.mod -- +module use + +go 1.16 + +require ( + short v0.0.0 + multiline v0.0.0 + long v0.0.0 + unprintable v0.0.0 +) + +replace ( + short v0.0.0 => ./short + multiline v0.0.0 => ./multiline + long v0.0.0 => ./long + unprintable v0.0.0 => ./unprintable +) +-- short/go.mod -- +// Deprecated: short +module short + +go 1.16 +-- short/short.go -- +package short +-- multiline/go.mod -- +// Deprecated: first line +// second line. +module multiline + +go 1.16 +-- multiline/multiline.go -- +package multiline +-- long/go.mod -- +// Deprecated: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +module long + +go 1.16 +-- long/long.go -- +package long +-- unprintable/go.mod -- +// Deprecated: message contains ASCII BEL +module unprintable + +go 1.16 +-- unprintable/unprintable.go -- +package unprintable diff --git a/src/cmd/go/testdata/script/mod_dir.txt b/src/cmd/go/testdata/script/mod_dir.txt new file mode 100644 index 0000000..05548f6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_dir.txt @@ -0,0 +1,20 @@ +# The directory named go.mod should be ignored + +env GO111MODULE=on + +cd $WORK/sub + +go list . +stdout 'x/sub' + +mkdir go.mod +exists go.mod + +go list . +stdout 'x/sub' + +-- $WORK/go.mod -- +module x + +-- $WORK/sub/x.go -- +package x
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/mod_doc.txt b/src/cmd/go/testdata/script/mod_doc.txt new file mode 100644 index 0000000..bf0a19d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_doc.txt @@ -0,0 +1,90 @@ +# go doc should find module documentation + +env GO111MODULE=on +env GOFLAGS=-mod=mod +[short] skip + +# Check when module x is inside GOPATH/src. +go doc y +stdout 'Package y is.*alphabet' +stdout 'import "x/y"' +go doc x/y +stdout 'Package y is.*alphabet' +! go doc quote.Hello +stderr 'doc: symbol quote is not a type' # because quote is not in local cache +go list rsc.io/quote # now it is +go doc quote.Hello +stdout 'Hello returns a greeting' +go doc quote +stdout 'Package quote collects pithy sayings.' + +# Double-check when module x is outside GOPATH/src. +env GOPATH=$WORK/emptygopath +go doc x/y +stdout 'Package y is.*alphabet' +go doc y +stdout 'Package y is.*alphabet' + +# Triple-check when module x is outside GOPATH/src, +# but other packages with same import paths are in GOPATH/src. +# Since go doc is running in module mode here, packages in active module +# should be preferred over packages in GOPATH. See golang.org/issue/28992. +env GOPATH=$WORK/gopath2 +go doc x/y +! stdout 'Package y is.*GOPATH' +stdout 'Package y is.*alphabet' +go doc rsc.io/quote +! stdout 'Package quote is located in a GOPATH workspace.' +stdout 'Package quote collects pithy sayings.' + +# Check that a sensible error message is printed when a package is not found. +env GOPROXY=off +! go doc example.com/hello +stderr '^doc: cannot find module providing package example.com/hello: module lookup disabled by GOPROXY=off$' + +# When in a module with a vendor directory, doc should use the vendored copies +# of the packages. 'std' and 'cmd' are convenient examples of such modules. +# +# When in those modules, the "// import" comment should refer to the same import +# path used in source code, not to the absolute path relative to GOROOT. + +cd $GOROOT/src +env GOFLAGS= +env GOWORK=off +go doc cryptobyte +stdout '// import "golang.org/x/crypto/cryptobyte"' + +cd $GOROOT/src/cmd/go +go doc modfile +stdout '// import "golang.org/x/mod/modfile"' + +# When outside of the 'std' module, its vendored packages +# remain accessible using the 'vendor/' prefix, but report +# the correct "// import" comment as used within std. +cd $GOPATH +go doc vendor/golang.org/x/crypto/cryptobyte +stdout '// import "vendor/golang.org/x/crypto/cryptobyte"' + +go doc cmd/vendor/golang.org/x/mod/modfile +stdout '// import "cmd/vendor/golang.org/x/mod/modfile"' + +-- go.mod -- +module x +require rsc.io/quote v1.5.2 + +-- y/y.go -- +// Package y is the next to last package of the alphabet. +package y + +-- x.go -- +package x + +-- $WORK/gopath2/src/x/y/y.go -- +// Package y is located in a GOPATH workspace. +package y +-- $WORK/gopath2/src/rsc.io/quote/quote.go -- +// Package quote is located in a GOPATH workspace. +package quote + +// Hello is located in a GOPATH workspace. +func Hello() string { return "" } diff --git a/src/cmd/go/testdata/script/mod_doc_path.txt b/src/cmd/go/testdata/script/mod_doc_path.txt new file mode 100644 index 0000000..83d5392 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_doc_path.txt @@ -0,0 +1,30 @@ +# cmd/doc should use GOROOT to locate the 'go' command, +# not use whatever is in $PATH. + +# Remove 'go' from $PATH. (It can still be located via $GOROOT/bin/go, and the +# test script's built-in 'go' command still knows where to find it.) +env PATH='' +[GOOS:plan9] env path='' + +go doc p.X + +-- go.mod -- +module example + +go 1.19 + +require example.com/p v0.1.0 + +replace example.com/p => ./pfork +-- example.go -- +package example + +import _ "example.com/p" +-- pfork/go.mod -- +module example.com/p + +go 1.19 +-- pfork/p.go -- +package p + +const X = 42 diff --git a/src/cmd/go/testdata/script/mod_domain_root.txt b/src/cmd/go/testdata/script/mod_domain_root.txt new file mode 100644 index 0000000..c13029d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_domain_root.txt @@ -0,0 +1,12 @@ +# Module paths that are domain roots should resolve. +# (example.com not example.com/something) + +env GO111MODULE=on +go get + +-- go.mod -- +module x + +-- x.go -- +package x +import _ "example.com" diff --git a/src/cmd/go/testdata/script/mod_dot.txt b/src/cmd/go/testdata/script/mod_dot.txt new file mode 100644 index 0000000..aa24986 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_dot.txt @@ -0,0 +1,132 @@ +env GOWORK=off +env GO111MODULE=on + +# golang.org/issue/32917 and golang.org/issue/28459: 'go build' and 'go test' +# in an empty directory should refer to the path '.' and should not attempt +# to resolve an external module. +cd dir +! go get +stderr '^go: no package to get in current directory$' +! go get . +stderr '^go: .: no package to get in current directory$' +! go get ./subdir +stderr '^go: \.[/\\]subdir \('$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]subdir\) is not a package in module rooted at '$WORK'[/\\]gopath[/\\]src[/\\]dir$' +! go list +! stderr 'cannot find module providing package' +stderr '^no Go files in '$WORK'[/\\]gopath[/\\]src[/\\]dir$' + +cd subdir +! go list +! stderr 'cannot find module providing package' +stderr '^no Go files in '$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]subdir$' +cd .. + +# golang.org/issue/30590: if a package is found in the filesystem +# but is not in the main module, the error message should not say +# "cannot find module providing package", and we shouldn't try +# to find a module providing the package. +! go list ./othermodule +! stderr 'cannot find module providing package' +stderr '^main module \(example\.com\) does not contain package example.com/othermodule$' + +# golang.org/issue/27122: 'go build' of a nonexistent directory should produce +# a helpful "no Go files" error message, not a generic "unknown import path". +! go list ./subdir +stderr '^no Go files in '$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]subdir$' + +# golang.org/issue/29280: 'go list -e' for a nonexistent directory should +# report a nonexistent package with an error. +go list -e -json ./subdir +stdout '"Incomplete": true' + +# golang.org/issue/28155: 'go list ./testdata' should not synthesize underscores. +go list ./testdata +stdout '^example.com/testdata' + +# golang.org/issue/32921: vendor directories should only be accepted as directories +# if the directory would actually be used to load the package. +! go list ./vendor/nonexist +stderr '^no Go files in '$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]vendor[/\\]nonexist$' + +! go list ./vendor/pkg +stderr '^without -mod=vendor, directory '$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]vendor[/\\]pkg has no package path$' + +! go list -mod=vendor ./vendor/nonexist +stderr '^no Go files in '$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]vendor[/\\]nonexist$' + +! go list -mod=vendor ./vendor/unlisted +stderr '^directory '$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]vendor[/\\]unlisted is not a package listed in vendor/modules.txt$' + +go list -mod=vendor ./vendor/pkg +stdout '^pkg$' + +# Packages within GOROOT should resolve as in any other module, +# except that -mod=vendor is implied by default. +cd $GOROOT/src +! go list . +stderr '^no Go files in '$GOROOT'[/\\]src$' + +! go list ./builtin +stderr '^"builtin" is a pseudo-package, not an importable package$' + +! go list ./debug +! stderr 'cannot find module providing package' +stderr '^no Go files in '$GOROOT'[/\\]src[/\\]debug$' + +! go list ./golang.org/x/tools/cmd/goimports +! stderr 'cannot find module providing package' +stderr '^stat '$GOROOT'[/\\]src[/\\]golang.org[/\\]x[/\\]tools[/\\]cmd[/\\]goimports: directory not found' + +go list ./vendor/golang.org/x/net/http2/hpack +stdout '^golang.org/x/net/http2/hpack$' + +# golang.org/issue/30756: packages in other GOROOTs should not get the special +# prefixless treatment of GOROOT itself. +cd $WORK/othergoroot/src +! go list . +stderr '^no Go files in '$WORK'[/\\]othergoroot[/\\]src$' + +go list ./builtin +stdout '^std/builtin$' # Only the "std" in actual $GOROOT is special, and only its "builtin" is special. + +! go list ./bytes +! stderr 'cannot find module providing package' +stderr '^no Go files in '$WORK'[/\\]othergoroot[/\\]src[/\\]bytes$' + +! go list ./vendor/golang.org/x/net/http2/hpack +stderr '^without -mod=vendor, directory '$WORK'[/\\]othergoroot[/\\]src[/\\]vendor[/\\]golang.org[/\\]x[/\\]net[/\\]http2[/\\]hpack has no package path$' + +-- dir/go.mod -- +module example.com +go 1.13 +-- dir/subdir/README -- +There are no Go source files in this directory. +-- dir/othermodule/go.mod -- +module example.com/othermodule +go 1.13 +-- dir/othermodule/om.go -- +package othermodule +-- dir/testdata/td.go -- +package testdata +-- dir/vendor/modules.txt -- +# pkg v0.0.0 +pkg +-- dir/vendor/nonexist/README -- +There are no Go source files here either. +-- dir/vendor/pkg/pkg.go -- +package pkg +-- dir/vendor/unlisted/unlisted.go -- +package unlisted +-- emptyroot/go.mod -- +module example.com/emptyroot +-- emptyroot/pkg/pkg.go -- +package pkg +-- $WORK/othergoroot/src/go.mod -- +module std +go 1.13 +-- $WORK/othergoroot/src/builtin/builtin.go -- +package builtin +-- $WORK/othergoroot/src/bytes/README -- +There are no Go source files in this directory. +-- $WORK/othergoroot/src/vendor/golang.org/x/net/http2/hpack -- +package hpack diff --git a/src/cmd/go/testdata/script/mod_download.txt b/src/cmd/go/testdata/script/mod_download.txt new file mode 100644 index 0000000..154e683 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download.txt @@ -0,0 +1,214 @@ +env GO111MODULE=on + +# download with version should print nothing. +# It should not load retractions from the .mod file from the latest version. +go mod download rsc.io/quote@v1.5.0 +! stdout . +! stderr . +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.mod +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.zip +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.info +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod + +# download of an invalid path should report the error +[short] skip +! go mod download this.domain.is.invalid/somemodule@v1.0.0 +stderr 'this.domain.is.invalid' +! go mod download -json this.domain.is.invalid/somemodule@v1.0.0 +stdout '"Error": ".*this.domain.is.invalid.*"' + +# download -json with version should print JSON +go mod download -json 'rsc.io/quote@<=v1.5.0' +stdout '^\t"Path": "rsc.io/quote"' +stdout '^\t"Version": "v1.5.0"' +stdout '^\t"Info": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.0.info"' +stdout '^\t"GoMod": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.0.mod"' +stdout '^\t"Zip": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.0.zip"' +stdout '^\t"Sum": "h1:6fJa6E\+wGadANKkUMlZ0DhXFpoKlslOQDCo259XtdIE="' # hash of testdata/mod version, not real version! +stdout '^\t"GoModSum": "h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe\+TKr0="' +! stdout '"Error"' + +# download queries above should not have added to go.mod. +go list -m all +! stdout rsc.io + +# download query should have downloaded go.mod for the highest release version +# in order to find retractions when resolving the query '@<=v1.5.0'. +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip + +# add to go.mod so we can test non-query downloads +go mod edit -require rsc.io/quote@v1.5.3-pre1 +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.info +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.mod +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.zip + +# module loading will page in the info and mod files +go list -m -mod=mod all +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.mod +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.zip + +# download will fetch and unpack the zip file +go mod download +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.mod +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.zip +exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.3-pre1 + +# download repopulates deleted files and directories independently. +rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.info +go mod download +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.info +rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.mod +go mod download +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.mod +rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.zip +go mod download +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.zip +rm -r $GOPATH/pkg/mod/rsc.io/quote@v1.5.3-pre1 +go mod download +exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.3-pre1 + +# download reports the locations of downloaded files +go mod download -json +stdout '^\t"Path": "rsc.io/quote"' +stdout '^\t"Version": "v1.5.3-pre1"' +stdout '^\t"Info": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.3-pre1.info"' +stdout '^\t"GoMod": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.3-pre1.mod"' +stdout '^\t"Zip": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.3-pre1.zip"' +stdout '^\t"Dir": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)rsc.io(\\\\|/)quote@v1.5.3-pre1"' + +# download will follow replacements +go mod edit -require rsc.io/quote@v1.5.1 -replace rsc.io/quote@v1.5.1=rsc.io/quote@v1.5.2 +go mod download +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.1.zip +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip + +# download will not follow replacements for explicit module queries +go mod download -json rsc.io/quote@v1.5.1 +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.1.zip + +# download reports errors encountered when locating modules +! go mod download bad/path +stderr '^go: module bad/path: not a known dependency$' +! go mod download bad/path@latest +stderr '^go: bad/path@latest: malformed module path "bad/path": missing dot in first path element$' +! go mod download rsc.io/quote@v1.999.999 +stderr '^go: rsc.io/quote@v1.999.999: reading .*/v1.999.999.info: 404 Not Found$' +! go mod download -json bad/path +stdout '^\t"Error": "module bad/path: not a known dependency"' + +# download main module produces a warning or error +go mod download m +stderr '^go: skipping download of m that resolves to the main module\n' +! go mod download m@latest +stderr '^go: m@latest: malformed module path "m": missing dot in first path element$' + +# download without arguments updates go.mod and go.sum after loading the +# build list, but does not save sums for downloaded zips. +cd update +cp go.mod.orig go.mod +! exists go.sum +go mod download +cmp go.mod.update go.mod +cmp go.sum.update go.sum +cp go.mod.orig go.mod +rm go.sum + +# download with arguments (even "all") does update go.mod and go.sum. +go mod download rsc.io/sampler +cmp go.mod.update go.mod +grep '^rsc.io/sampler v1.3.0 ' go.sum +cp go.mod.orig go.mod +rm go.sum + +go mod download all +cmp go.mod.update go.mod +grep '^rsc.io/sampler v1.3.0 ' go.sum + +# https://golang.org/issue/44435: At go 1.17 or higher, 'go mod download' +# (without arguments) should only download the modules explicitly required in +# the go.mod file, not (presumed-irrelevant) transitive dependencies. +# +# (If the go.mod file is inconsistent, the version downloaded should be the +# selected version from the broader graph, but the go.mod file will also be +# updated to list the correct versions. If at some point we change 'go mod +# download' to stop updating for consistency, then it should fail if the +# requirements are inconsistent.) + +rm go.sum +cp go.mod.orig go.mod +go mod edit -go=1.17 +cp go.mod.update go.mod.go117 +go mod edit -go=1.17 go.mod.go117 + +go clean -modcache +go mod download +cmp go.mod go.mod.go117 + +go list -e -m all +stdout '^rsc.io/quote v1.5.2$' +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip +stdout '^rsc.io/sampler v1.3.0$' +! exists $GOPATH/pkg/mod/cache/download/rsc.io/sampler/@v/v1.2.1.zip +exists $GOPATH/pkg/mod/cache/download/rsc.io/sampler/@v/v1.3.0.zip +stdout '^golang\.org/x/text v0.0.0-20170915032832-14c0d48ead0c$' +! exists $GOPATH/pkg/mod/cache/download/golang.org/x/text/@v/v0.0.0-20170915032832-14c0d48ead0c.zip +cmp go.mod go.mod.go117 + +# However, 'go mod download all' continues to download the selected version +# of every module reported by 'go list -m all'. + +cp go.mod.orig go.mod +go mod edit -go=1.17 +go clean -modcache +go mod download all +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip +! exists $GOPATH/pkg/mod/cache/download/rsc.io/sampler/@v/v1.2.1.zip +exists $GOPATH/pkg/mod/cache/download/rsc.io/sampler/@v/v1.3.0.zip +exists $GOPATH/pkg/mod/cache/download/golang.org/x/text/@v/v0.0.0-20170915032832-14c0d48ead0c.zip +cmp go.mod go.mod.go117 + +cd .. + +# allow go mod download without go.mod +env GO111MODULE=auto +rm go.mod +rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.2.1.zip +go mod download rsc.io/quote@v1.2.1 +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.2.1.zip + +# download -x with version should print +# the underlying commands such as contacting GOPROXY. +go mod download -x rsc.io/quote@v1.0.0 +! stdout . +stderr 'get '$GOPROXY + +-- go.mod -- +module m + +-- update/go.mod.orig -- +module m + +go 1.16 + +require ( + rsc.io/quote v1.5.2 + rsc.io/sampler v1.2.1 // older version than in build list +) +-- update/go.mod.update -- +module m + +go 1.16 + +require ( + rsc.io/quote v1.5.2 + rsc.io/sampler v1.3.0 // older version than in build list +) +-- update/go.sum.update -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/src/cmd/go/testdata/script/mod_download_concurrent_read.txt b/src/cmd/go/testdata/script/mod_download_concurrent_read.txt new file mode 100644 index 0000000..c2c8b18 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_concurrent_read.txt @@ -0,0 +1,110 @@ +# This test simulates a process watching for changes and reading files in +# module cache as a module is extracted. +# +# Before Go 1.16, we extracted each module zip to a temporary directory with +# a random name, then renamed that into place with os.Rename. On Windows, +# this failed with ERROR_ACCESS_DENIED when another process (usually an +# anti-virus scanner) opened files in the temporary directory. This test +# simulates that behavior, verifying golang.org/issue/36568. +# +# Since 1.16, we extract to the final directory, but we create a .partial file +# so that if we crash, other processes know the directory is incomplete. + +[!GOOS:windows] skip +[short] skip + +go run downloader.go + +-- go.mod -- +module example.com/m + +go 1.14 + +-- downloader.go -- +package main + +import ( + "fmt" + "log" + "os" + "os/exec" + "path/filepath" +) + +func main() { + if err := run(); err != nil { + log.Fatal(err) + } +} + +// run repeatedly downloads a module while opening files in the module cache +// in a background goroutine. +// +// run uses a different temporary module cache in each iteration so that we +// don't need to clean the cache or synchronize closing files after each +// iteration. +func run() (err error) { + tmpDir, err := os.MkdirTemp("", "") + if err != nil { + return err + } + defer func() { + if rmErr := os.RemoveAll(tmpDir); err == nil && rmErr != nil { + err = rmErr + } + }() + for i := 0; i < 10; i++ { + gopath := filepath.Join(tmpDir, fmt.Sprintf("gopath%d", i)) + var err error + done := make(chan struct{}) + go func() { + err = download(gopath) + close(done) + }() + readCache(gopath, done) + if err != nil { + return err + } + } + return nil +} + +// download downloads a module into the given cache using 'go mod download'. +func download(gopath string) error { + cmd := exec.Command("go", "mod", "download", "-modcacherw", "rsc.io/quote@v1.5.2") + cmd.Stderr = os.Stderr + cmd.Env = append(os.Environ(), "GOPATH="+gopath) + return cmd.Run() +} + +// readCache repeatedly globs for go.mod files in the given cache, then opens +// those files for reading. When the done chan is closed, readCache closes +// files and returns. +func readCache(gopath string, done <-chan struct{}) { + files := make(map[string]*os.File) + defer func() { + for _, f := range files { + f.Close() + } + }() + + pattern := filepath.Join(gopath, "pkg/mod/rsc.io/quote@v1.5.2*/go.mod") + for { + select { + case <-done: + return + default: + } + + names, _ := filepath.Glob(pattern) + for _, name := range names { + if files[name] != nil { + continue + } + f, _ := os.Open(name) + if f != nil { + files[name] = f + } + } + } +} diff --git a/src/cmd/go/testdata/script/mod_download_exec_toolchain.txt b/src/cmd/go/testdata/script/mod_download_exec_toolchain.txt new file mode 100644 index 0000000..6cf863b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_exec_toolchain.txt @@ -0,0 +1,107 @@ +env TESTGO_VERSION=go1.21 +env TESTGO_VERSION_SWITCH=switch + +# First, test 'go mod download' outside of a module. +# +# There is no go.mod file into which we can record the selected toolchain, +# so unfortunately these version switches won't be as reproducible as other +# go commands, but that's still preferable to failing entirely or downloading +# a module zip that we don't understand. + +# GOTOOLCHAIN=auto should run the newer toolchain +env GOTOOLCHAIN=auto +go mod download rsc.io/needgo121@latest rsc.io/needgo122@latest rsc.io/needgo123@latest rsc.io/needall@latest +stderr '^go: rsc.io/needall@v0.0.1 requires go >= 1.23; switching to go1.23.9$' +! stderr '\(running' + +# GOTOOLCHAIN=min+auto should run the newer toolchain +env GOTOOLCHAIN=go1.21+auto +go mod download rsc.io/needgo121@latest rsc.io/needgo122@latest rsc.io/needgo123@latest rsc.io/needall@latest +stderr '^go: rsc.io/needall@v0.0.1 requires go >= 1.23; switching to go1.23.9$' +! stderr '\(running' + +# GOTOOLCHAIN=go1.21 should NOT run the newer toolchain +env GOTOOLCHAIN=go1.21 +! go mod download rsc.io/needgo121@latest rsc.io/needgo122@latest rsc.io/needgo123@latest rsc.io/needall@latest +! stderr switching +stderr 'rsc.io/needgo122@v0.0.1 requires go >= 1.22' +stderr 'rsc.io/needgo123@v0.0.1 requires go >= 1.23' +stderr 'rsc.io/needall@v0.0.1 requires go >= 1.23' +stderr 'requires go >= 1.23' +! stderr 'requires go >= 1.21' # that's us! + + +# JSON output should be emitted exactly once, +# and non-JSON output should go to stderr instead of stdout. +env GOTOOLCHAIN=auto +go mod download -json rsc.io/needgo121@latest rsc.io/needgo122@latest rsc.io/needgo123@latest rsc.io/needall@latest +stderr '^go: rsc.io/needall@v0.0.1 requires go >= 1.23; switching to go1.23.9$' +! stderr '\(running' +stdout -count=1 '"Path": "rsc.io/needgo121",' +stdout -count=1 '"Path": "rsc.io/needgo122",' +stdout -count=1 '"Path": "rsc.io/needgo123",' +stdout -count=1 '"Path": "rsc.io/needall",' + +# GOTOOLCHAIN=go1.21 should write the errors in the JSON Error fields, not to stderr. +env GOTOOLCHAIN=go1.21 +! go mod download -json rsc.io/needgo121@latest rsc.io/needgo122@latest rsc.io/needgo123@latest rsc.io/needall@latest +! stderr switching +stdout -count=1 '"Error": "rsc.io/needgo122@v0.0.1 requires go .*= 1.22 \(running go 1.21; GOTOOLCHAIN=go1.21\)"' +stdout -count=1 '"Error": "rsc.io/needgo123@v0.0.1 requires go .*= 1.23 \(running go 1.21; GOTOOLCHAIN=go1.21\)"' +stdout -count=1 '"Error": "rsc.io/needall@v0.0.1 requires go .*= 1.23 \(running go 1.21; GOTOOLCHAIN=go1.21\)"' +! stdout '"Error": "rsc.io/needgo121' # We can handle this one. +! stderr . + + +# Within a module, 'go mod download' of explicit versions should upgrade if +# needed to perform the download, but should not change the main module's +# toolchain version (because the downloaded modules are still not required by +# the main module). + +cd example +cp go.mod go.mod.orig + +env GOTOOLCHAIN=auto +go mod download rsc.io/needgo121@latest rsc.io/needgo122@latest rsc.io/needgo123@latest rsc.io/needall@latest +stderr '^go: rsc.io/needall@v0.0.1 requires go >= 1.23; switching to go1.23.9$' +! stderr '\(running' +cmp go.mod go.mod.orig + + +# However, 'go mod download' without arguments should fix up the +# 'go' and 'toolchain' lines to be consistent with the existing +# requirements in the module graph. + +go mod edit -require=rsc.io/needall@v0.0.1 +cp go.mod go.mod.121 + +# If an upgrade is needed, GOTOOLCHAIN=go1.21 should cause +# the command to fail without changing go.mod. + +env GOTOOLCHAIN=go1.21 +! go mod download +stderr 'rsc.io/needall@v0.0.1 requires go >= 1.23' +! stderr switching +cmp go.mod go.mod.121 + +# If an upgrade is needed, GOTOOLCHAIN=auto should perform +# the upgrade and record the resulting toolchain version. + +env GOTOOLCHAIN=auto +go mod download +stderr '^go: module rsc.io/needall@v0.0.1 requires go >= 1.23; switching to go1.23.9$' +cmp go.mod go.mod.final + + +-- example/go.mod -- +module example + +go 1.21 +-- example/go.mod.final -- +module example + +go 1.23 + +toolchain go1.23.9 + +require rsc.io/needall v0.0.1 diff --git a/src/cmd/go/testdata/script/mod_download_git_bareRepository.txt b/src/cmd/go/testdata/script/mod_download_git_bareRepository.txt new file mode 100644 index 0000000..a61283c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_git_bareRepository.txt @@ -0,0 +1,28 @@ +[short] skip +[!git] skip + +# Redirect git to a test-specific .gitconfig. +# GIT_CONFIG_GLOBAL suffices for git 2.32.0 and newer. +# For older git versions we also set $HOME. +env GIT_CONFIG_GLOBAL=$WORK${/}home${/}gopher${/}.gitconfig +env HOME=$WORK${/}home${/}gopher +exec git config --global --show-origin user.name +stdout 'Go Gopher' + +env GOPRIVATE=vcs-test.golang.org + +go mod download -x + +-- go.mod -- +module test + +go 1.18 + +require vcs-test.golang.org/git/gitrepo1.git v1.2.3 + +-- $WORK/home/gopher/.gitconfig -- +[user] + name = Go Gopher + email = gopher@golang.org +[safe] + bareRepository = explicit diff --git a/src/cmd/go/testdata/script/mod_download_git_decorate_full.txt b/src/cmd/go/testdata/script/mod_download_git_decorate_full.txt new file mode 100644 index 0000000..9afd347 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_git_decorate_full.txt @@ -0,0 +1,34 @@ +env GO111MODULE=on + +[short] skip +[!git] skip + +# Redirect git to a test-specific .gitconfig. +# GIT_CONFIG_GLOBAL suffices for git 2.32.0 and newer. +# For older git versions we also set $HOME. +env GIT_CONFIG_GLOBAL=$WORK${/}home${/}gopher${/}.gitconfig +env HOME=$WORK${/}home${/}gopher +exec git config --global --show-origin user.name +stdout 'Go Gopher' + +env GOPROXY=direct + +exec git config --get log.decorate +stdout 'full' + +# Test that Git log with user's global config '~/gitconfig' has log.decorate=full +# go mod download has an error 'v1.x.y is not a tag' +# with go1.16.14: +# `go1.16.14 list -m vcs-test.golang.org/git/gitrepo1.git@v1.2.3` +# will output with error: +# go list -m: vcs-test.golang.org/git/gitrepo1.git@v1.2.3: invalid version: unknown revision v1.2.3 +# See golang/go#51312. +go list -m vcs-test.golang.org/git/gitrepo1.git@v1.2.3 +stdout 'vcs-test.golang.org/git/gitrepo1.git v1.2.3' + +-- $WORK/home/gopher/.gitconfig -- +[user] + name = Go Gopher + email = gopher@golang.org +[log] + decorate = full diff --git a/src/cmd/go/testdata/script/mod_download_hash.txt b/src/cmd/go/testdata/script/mod_download_hash.txt new file mode 100644 index 0000000..5677e69 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_hash.txt @@ -0,0 +1,24 @@ +env GO111MODULE=on + +# Testing mod download with non semantic versions; turn off proxy. +[!net:rsc.io] skip +[!git] skip +env GOPROXY=direct +env GOSUMDB=off + +go mod download rsc.io/quote@a91498bed0a73d4bb9c1fb2597925f7883bc40a7 +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-0.20180709162918-a91498bed0a7.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-0.20180709162918-a91498bed0a7.mod +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-0.20180709162918-a91498bed0a7.zip + +go mod download rsc.io/quote@master +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-0.20180709162918-a91498bed0a7.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-0.20180709162918-a91498bed0a7.mod +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-0.20180709162918-a91498bed0a7.zip + + +-- go.mod -- +module m + +-- m.go -- +package m diff --git a/src/cmd/go/testdata/script/mod_download_insecure_redirect.txt b/src/cmd/go/testdata/script/mod_download_insecure_redirect.txt new file mode 100644 index 0000000..20a6ac2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_insecure_redirect.txt @@ -0,0 +1,32 @@ +# golang.org/issue/29591: 'go get' was following plain-HTTP redirects even without -insecure (now replaced by GOINSECURE). + +[short] skip +[!git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +! go mod download vcs-test.golang.org/insecure/go/insecure@latest +stderr 'redirected .* to insecure URL' + +# insecure host +env GOINSECURE=vcs-test.golang.org +go clean -modcache +go mod download vcs-test.golang.org/insecure/go/insecure@latest + +# insecure glob host +env GOINSECURE=*.golang.org +go clean -modcache +go mod download vcs-test.golang.org/insecure/go/insecure@latest + +# insecure multiple host +env GOINSECURE=somewhere-else.com,*.golang.org +go clean -modcache +go mod download vcs-test.golang.org/insecure/go/insecure@latest + +# different insecure host does not fetch +env GOINSECURE=somewhere-else.com +go clean -modcache +! go mod download vcs-test.golang.org/insecure/go/insecure@latest +stderr 'redirected .* to insecure URL' diff --git a/src/cmd/go/testdata/script/mod_download_issue51114.txt b/src/cmd/go/testdata/script/mod_download_issue51114.txt new file mode 100644 index 0000000..a28d467 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_issue51114.txt @@ -0,0 +1,29 @@ +[!net:github.com] skip +[!git] skip + +# Redirect git to a test-specific .gitconfig. +# GIT_CONFIG_GLOBAL suffices for git 2.32.0 and newer. +# For older git versions we also set $HOME. +env GIT_CONFIG_GLOBAL=$WORK${/}home${/}gopher${/}.gitconfig +env HOME=$WORK${/}home${/}gopher +exec git config --global --show-origin user.name +stdout 'Go Gopher' + +env GOPROXY=direct + +! go mod download +stderr '^go: github\.com/golang/notexist/subdir@v0.1.0: reading github\.com/golang/notexist/subdir/go\.mod at revision subdir/v0\.1\.0: ' + +-- go.mod -- +module test + +go 1.18 + +require github.com/golang/notexist/subdir v0.1.0 + +-- $WORK/home/gopher/.gitconfig -- +[user] + name = Go Gopher + email = gopher@golang.org +[url "git@github.com:"] + insteadOf = https://github.com/ diff --git a/src/cmd/go/testdata/script/mod_download_json.txt b/src/cmd/go/testdata/script/mod_download_json.txt new file mode 100644 index 0000000..9555adf --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_json.txt @@ -0,0 +1,9 @@ +env GO111MODULE=on +env GOSUMDB=$sumdb' '$proxy/sumdb-wrong + +# download -json with version should print JSON on sumdb failure +! go mod download -json 'rsc.io/quote@<=v1.5.0' +stdout '"Error": ".*verifying (module|go.mod)' + +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/mod_download_partial.txt b/src/cmd/go/testdata/script/mod_download_partial.txt new file mode 100644 index 0000000..617b1fd --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_partial.txt @@ -0,0 +1,69 @@ +# Download modules and populate go.sum. +go get -modcacherw +exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod + +# 'go mod verify' should fail if we delete a file. +go mod verify +rm $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod +! go mod verify + +# Create a .partial file to simulate an failure extracting the zip file. +cp empty $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.partial + +# 'go mod verify' should not fail, since the module hasn't been completely +# ingested into the cache. +go mod verify + +# 'go list' should not load packages from the directory. +# NOTE: the message "directory $dir outside main module or its selected dependencies" +# is reported for directories not in the main module, active modules in the +# module cache, or local replacements. In this case, the directory is in the +# right place, but it's incomplete, so 'go list' acts as if it's not an +# active module. +! go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 +stderr 'outside main module or its selected dependencies' + +# 'go list -m' should not print the directory. +go list -m -f '{{.Dir}}' rsc.io/quote +! stdout . + +# 'go mod download' should re-extract the module and remove the .partial file. +go mod download -modcacherw rsc.io/quote +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.partial +exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod + +# 'go list' should succeed. +go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 +stdout '^rsc.io/quote$' + +# 'go list -m' should print the directory. +go list -m -f '{{.Dir}}' rsc.io/quote +stdout 'pkg[/\\]mod[/\\]rsc.io[/\\]quote@v1.5.2' + +# go mod verify should fail if we delete a file. +go mod verify +rm $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod +! go mod verify + +# 'go mod download' should not leave behind a directory or a .partial file +# if there is an error extracting the zip file. +rm $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 +cp empty $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip +! go mod download +stderr 'not a valid zip file' +! exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.partial + +-- go.mod -- +module m + +go 1.14 + +require rsc.io/quote v1.5.2 + +-- use.go -- +package use + +import _ "rsc.io/quote" + +-- empty -- diff --git a/src/cmd/go/testdata/script/mod_download_private_vcs.txt b/src/cmd/go/testdata/script/mod_download_private_vcs.txt new file mode 100644 index 0000000..5c8d93a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_private_vcs.txt @@ -0,0 +1,48 @@ +env GO111MODULE=on + +# Testing stderr for git ls-remote; turn off proxy. +[!net:github.com] skip +[!git] skip +env GOPROXY=direct + +# Redirect git to a test-specific .gitconfig. +# GIT_CONFIG_GLOBAL suffices for git 2.32.0 and newer. +# For older git versions we also set $HOME. +env GIT_CONFIG_GLOBAL=$WORK${/}home${/}gopher${/}.gitconfig +env HOME=$WORK${/}home${/}gopher +exec git config --global --show-origin user.name +stdout 'Go Gopher' + +! go mod download github.com/golang/nonexist@latest +stderr 'Confirm the import path was entered correctly.' +stderr 'If this is a private repository, see https://golang.org/doc/faq#git_https for additional information.' +! stdout . + +# Fetching a nonexistent commit should return an "unknown revision" +# error message. +! go mod download github.com/golang/term@86186f3aba07ed0212cfb944f3398997d2d07c6b +stderr '^go: github.com/golang/term@86186f3aba07ed0212cfb944f3398997d2d07c6b: invalid version: unknown revision 86186f3aba07ed0212cfb944f3398997d2d07c6b$' +! stdout . + +! go mod download github.com/golang/nonexist@master +stderr '^Confirm the import path was entered correctly.$' +stderr '^If this is a private repository, see https://golang.org/doc/faq#git_https for additional information.$' +! stderr 'unknown revision' +! stdout . + +[!exec:false] stop + +# Test that Git clone errors will be shown to the user instead of a generic +# "unknown revision" error. To do this we want to force git ls-remote to return +# an error we don't already have special handling for. See golang/go#42751. +exec git config --global url.git@github.com.insteadOf https://github.com/ +env GIT_SSH_COMMAND=false +! go install github.com/golang/nonexist@master +stderr 'fatal: Could not read from remote repository.' +! stderr 'unknown revision' +! stdout . + +-- $WORK/home/gopher/.gitconfig -- +[user] + name = Go Gopher + email = gopher@golang.org diff --git a/src/cmd/go/testdata/script/mod_download_replace_file.txt b/src/cmd/go/testdata/script/mod_download_replace_file.txt new file mode 100644 index 0000000..f6ab4fe --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_replace_file.txt @@ -0,0 +1,16 @@ +# This test checks that 'go mod download' produces no output for +# the main module (when specified implicitly) and for a module replaced +# with a file path. +# Verifies golang.org/issue/35505. +go mod download -json all +cmp stdout no-output + +-- go.mod -- +module example.com/a + +require example.com/b v1.0.0 + +replace example.com/b => ./local/b +-- local/b/go.mod -- +module example.com/b +-- no-output -- diff --git a/src/cmd/go/testdata/script/mod_download_svn.txt b/src/cmd/go/testdata/script/mod_download_svn.txt new file mode 100644 index 0000000..c11b4f9 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_svn.txt @@ -0,0 +1,29 @@ +[short] skip +[!exec:svn] skip + +# 'go mod download' will fall back to svn+ssh once svn fails over protocols like https. +# If vcs-test.golang.org isn't in the user's known_hosts file, this will result +# in an ssh prompt, which will stop 'go test' entirely +# +# Unfortunately, there isn't a way to globally disable host checking for ssh, +# without modifying the real system's or user's configs. Changing $HOME won't +# affect ssh either, as it ignores the environment variable entirely. +# +# However, a useful trick is pointing SVN_SSH to a program that doesn't exist, +# resulting in svn skipping ssh entirely. Alternatives like +# SVN_SSH="ssh -o StrictHostKeyChecking=no" didn't avoid the prompt. +env SVN_SSH="svn_do_not_use_ssh" + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +# Attempting to get a module zip using svn should succeed. +go mod download vcs-test.golang.org/svn/hello.svn@000000000001 +exists $GOPATH/pkg/mod/cache/download/vcs-test.golang.org/svn/hello.svn/@v/v0.0.0-20170922011245-000000000001.zip + +# Attempting to get a nonexistent module using svn should fail with a +# reasonable message instead of a panic. +! go mod download vcs-test.golang.org/svn/nonexistent.svn@latest +! stderr panic +stderr 'go: module vcs-test.golang.org/svn/nonexistent.svn: no matching versions for query "latest"$' diff --git a/src/cmd/go/testdata/script/mod_download_too_many_redirects.txt b/src/cmd/go/testdata/script/mod_download_too_many_redirects.txt new file mode 100644 index 0000000..a6b5a59 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_too_many_redirects.txt @@ -0,0 +1,10 @@ +env GO111MODULE=on +env GOPROXYBASE=$GOPROXY +env GOPROXY=$GOPROXYBASE/redirect/11 +env GOSUMDB=off + +! go mod download rsc.io/quote@v1.2.0 +stderr 'stopped after 10 redirects' + +env GOPROXY=$GOPROXYBASE/redirect/9 +go mod download rsc.io/quote@v1.2.0 diff --git a/src/cmd/go/testdata/script/mod_e.txt b/src/cmd/go/testdata/script/mod_e.txt new file mode 100644 index 0000000..6497e6c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_e.txt @@ -0,0 +1,96 @@ +cp go.mod go.mod.orig + + +# If a dependency cannot be resolved, 'go mod tidy' fails with an error message +# explaining the problem and does not update the go.mod file. +# TODO(bcmills): Ideally, with less redundancy than these error messages! + +! go mod tidy + +stderr '^go: example.com/untidy imports\n\texample.net/directnotfound: cannot find module providing package example.net/directnotfound: module example.net/directnotfound: reading http://.*: 404 Not Found$' + +stderr '^go: example.com/untidy imports\n\texample.net/m imports\n\texample.net/indirectnotfound: cannot find module providing package example.net/indirectnotfound: module example.net/indirectnotfound: reading http://.*: 404 Not Found$' + +stderr '^go: example.com/untidy tested by\n\texample.com/untidy.test imports\n\texample.net/directtestnotfound: cannot find module providing package example.net/directtestnotfound: module example.net/directtestnotfound: reading http://.*: 404 Not Found$' + +stderr '^go: example.com/untidy imports\n\texample.net/m tested by\n\texample.net/m.test imports\n\texample.net/indirecttestnotfound: cannot find module providing package example.net/indirecttestnotfound: module example.net/indirecttestnotfound: reading http://.*: 404 Not Found$' + +cmp go.mod.orig go.mod + + +# If a dependency cannot be resolved, 'go mod vendor' fails with an error message +# explaining the problem, does not update the go.mod file, and does not create +# the vendor directory. + +! go mod vendor + +stderr '^go: example.com/untidy imports\n\texample.net/directnotfound: no required module provides package example.net/directnotfound; to add it:\n\tgo get example.net/directnotfound$' + +stderr '^go: example.com/untidy imports\n\texample.net/m: module example.net/m provides package example.net/m and is replaced but not required; to add it:\n\tgo get example.net/m@v0.1.0$' + +stderr '^go: example.com/untidy tested by\n\texample.com/untidy.test imports\n\texample.net/directtestnotfound: no required module provides package example.net/directtestnotfound; to add it:\n\tgo get example.net/directtestnotfound$' + +! stderr 'indirecttestnotfound' # Vendor prunes test dependencies. + +cmp go.mod.orig go.mod +! exists vendor + + +# 'go mod tidy' still logs the errors, but succeeds and updates go.mod. + +go mod tidy -e +stderr -count=4 'cannot find module providing package' +cmp go.mod.final go.mod + + +# 'go mod vendor -e' still logs the errors, but creates a vendor directory +# and exits with status 0. +# 'go mod vendor -e' does not update go.mod and will not vendor packages that +# would require changing go.mod, for example, by adding a requirement. +cp go.mod.orig go.mod +go mod vendor -e +stderr -count=2 'no required module provides package' +stderr '^go: example.com/untidy imports\n\texample.net/m: module example.net/m provides package example.net/m and is replaced but not required; to add it:\n\tgo get example.net/m@v0.1.0$' +exists vendor/modules.txt +! exists vendor/example.net + +go mod edit -require example.net/m@v0.1.0 +go mod vendor -e +stderr -count=3 'no required module provides package' +exists vendor/modules.txt +exists vendor/example.net/m/m.go + +-- go.mod -- +module example.com/untidy +go 1.16 +replace example.net/m v0.1.0 => ./m +-- go.mod.final -- +module example.com/untidy + +go 1.16 + +replace example.net/m v0.1.0 => ./m + +require example.net/m v0.1.0 +-- untidy.go -- +package untidy + +import ( + _ "example.net/m" + _ "example.net/directnotfound" +) +-- untidy_test.go -- +package untidy_test + +import _ "example.net/directtestnotfound" +-- m/go.mod -- +module example.net/m +go 1.16 +-- m/m.go -- +package m + +import _ "example.net/indirectnotfound" +-- m/m_test.go -- +package m_test + +import _ "example.net/indirecttestnotfound" diff --git a/src/cmd/go/testdata/script/mod_edit.txt b/src/cmd/go/testdata/script/mod_edit.txt new file mode 100644 index 0000000..2d09b06 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_edit.txt @@ -0,0 +1,340 @@ +env GO111MODULE=on + +# Test that go mod edits and related mod flags work. +# Also test that they can use a dummy name that isn't resolvable. golang.org/issue/24100 + +# go mod init +! go mod init +stderr 'cannot determine module path' +! exists go.mod + +go mod init x.x/y/z +stderr 'creating new go.mod: module x.x/y/z' +cmpenv go.mod $WORK/go.mod.init + +! go mod init +cmpenv go.mod $WORK/go.mod.init + +# go mod edits +go mod edit -droprequire=x.1 -require=x.1@v1.0.0 -require=x.2@v1.1.0 -droprequire=x.2 -exclude='x.1 @ v1.2.0' -exclude=x.1@v1.2.1 -exclude=x.1@v2.0.0+incompatible -replace=x.1@v1.3.0=y.1@v1.4.0 -replace='x.1@v1.4.0 = ../z' -retract=v1.6.0 -retract=[v1.1.0,v1.2.0] -retract=[v1.3.0,v1.4.0] -retract=v1.0.0 +cmpenv go.mod $WORK/go.mod.edit1 +go mod edit -droprequire=x.1 -dropexclude=x.1@v1.2.1 -dropexclude=x.1@v2.0.0+incompatible -dropreplace=x.1@v1.3.0 -require=x.3@v1.99.0 -dropretract=v1.0.0 -dropretract=[v1.1.0,v1.2.0] +cmpenv go.mod $WORK/go.mod.edit2 + +# -exclude and -retract reject invalid versions. +! go mod edit -exclude=example.com/m@bad +stderr '^go: -exclude=example.com/m@bad: version "bad" invalid: must be of the form v1.2.3$' +! go mod edit -retract=bad +stderr '^go: -retract=bad: version "bad" invalid: must be of the form v1.2.3$' + +! go mod edit -exclude=example.com/m@v2.0.0 +stderr '^go: -exclude=example.com/m@v2\.0\.0: version "v2\.0\.0" invalid: should be v2\.0\.0\+incompatible \(or module example\.com/m/v2\)$' + +! go mod edit -exclude=example.com/m/v2@v1.0.0 +stderr '^go: -exclude=example.com/m/v2@v1\.0\.0: version "v1\.0\.0" invalid: should be v2, not v1$' + +! go mod edit -exclude=gopkg.in/example.v1@v2.0.0 +stderr '^go: -exclude=gopkg\.in/example\.v1@v2\.0\.0: version "v2\.0\.0" invalid: should be v1, not v2$' + +cmpenv go.mod $WORK/go.mod.edit2 + +# go mod edit -json +go mod edit -json +cmpenv stdout $WORK/go.mod.json + +# go mod edit -json (retractions with rationales) +go mod edit -json $WORK/go.mod.retractrationale +cmp stdout $WORK/go.mod.retractrationale.json + +# go mod edit -json (deprecation) +go mod edit -json $WORK/go.mod.deprecation +cmp stdout $WORK/go.mod.deprecation.json + +# go mod edit -json (empty mod file) +go mod edit -json $WORK/go.mod.empty +cmp stdout $WORK/go.mod.empty.json + +# go mod edit -replace +go mod edit -replace=x.1@v1.3.0=y.1/v2@v2.3.5 -replace=x.1@v1.4.0=y.1/v2@v2.3.5 +cmpenv go.mod $WORK/go.mod.edit3 +go mod edit -replace=x.1=y.1/v2@v2.3.6 +cmpenv go.mod $WORK/go.mod.edit4 +go mod edit -dropreplace=x.1 +cmpenv go.mod $WORK/go.mod.edit5 +go mod edit -replace=x.1=../y.1/@v2 +cmpenv go.mod $WORK/go.mod.edit6 +! go mod edit -replace=x.1=y.1/@v2 +stderr '^go: -replace=x.1=y.1/@v2: invalid new path: malformed import path "y.1/": trailing slash$' + +# go mod edit -fmt +cp $WORK/go.mod.badfmt go.mod +go mod edit -fmt -print # -print should avoid writing file +cmpenv stdout $WORK/go.mod.goodfmt +cmp go.mod $WORK/go.mod.badfmt +go mod edit -fmt # without -print, should write file (and nothing to stdout) +! stdout . +cmpenv go.mod $WORK/go.mod.goodfmt + +# go mod edit -module +cd $WORK/m +go mod init a.a/b/c +go mod edit -module x.x/y/z +cmpenv go.mod go.mod.edit + +# golang.org/issue/30513: don't require go-gettable module paths. +cd $WORK/local +go mod init foo +go mod edit -module local-only -require=other-local@v1.0.0 -replace other-local@v1.0.0=./other +cmpenv go.mod go.mod.edit + +-- x.go -- +package x + +-- w/w.go -- +package w + +-- $WORK/go.mod.init -- +module x.x/y/z + +go $goversion +-- $WORK/go.mod.edit1 -- +module x.x/y/z + +go $goversion + +require x.1 v1.0.0 + +exclude ( + x.1 v1.2.0 + x.1 v1.2.1 + x.1 v2.0.0+incompatible +) + +replace ( + x.1 v1.3.0 => y.1 v1.4.0 + x.1 v1.4.0 => ../z +) + +retract ( + v1.6.0 + [v1.3.0, v1.4.0] + [v1.1.0, v1.2.0] + v1.0.0 +) +-- $WORK/go.mod.edit2 -- +module x.x/y/z + +go $goversion + +exclude x.1 v1.2.0 + +replace x.1 v1.4.0 => ../z + +retract ( + v1.6.0 + [v1.3.0, v1.4.0] +) + +require x.3 v1.99.0 +-- $WORK/go.mod.json -- +{ + "Module": { + "Path": "x.x/y/z" + }, + "Go": "$goversion", + "Require": [ + { + "Path": "x.3", + "Version": "v1.99.0" + } + ], + "Exclude": [ + { + "Path": "x.1", + "Version": "v1.2.0" + } + ], + "Replace": [ + { + "Old": { + "Path": "x.1", + "Version": "v1.4.0" + }, + "New": { + "Path": "../z" + } + } + ], + "Retract": [ + { + "Low": "v1.6.0", + "High": "v1.6.0" + }, + { + "Low": "v1.3.0", + "High": "v1.4.0" + } + ] +} +-- $WORK/go.mod.edit3 -- +module x.x/y/z + +go $goversion + +exclude x.1 v1.2.0 + +replace ( + x.1 v1.3.0 => y.1/v2 v2.3.5 + x.1 v1.4.0 => y.1/v2 v2.3.5 +) + +retract ( + v1.6.0 + [v1.3.0, v1.4.0] +) + +require x.3 v1.99.0 +-- $WORK/go.mod.edit4 -- +module x.x/y/z + +go $goversion + +exclude x.1 v1.2.0 + +replace x.1 => y.1/v2 v2.3.6 + +retract ( + v1.6.0 + [v1.3.0, v1.4.0] +) + +require x.3 v1.99.0 +-- $WORK/go.mod.edit5 -- +module x.x/y/z + +go $goversion + +exclude x.1 v1.2.0 + +retract ( + v1.6.0 + [v1.3.0, v1.4.0] +) + +require x.3 v1.99.0 +-- $WORK/go.mod.edit6 -- +module x.x/y/z + +go $goversion + +exclude x.1 v1.2.0 + +retract ( + v1.6.0 + [v1.3.0, v1.4.0] +) + +require x.3 v1.99.0 + +replace x.1 => ../y.1/@v2 +-- $WORK/local/go.mod.edit -- +module local-only + +go $goversion + +require other-local v1.0.0 + +replace other-local v1.0.0 => ./other +-- $WORK/go.mod.badfmt -- +module x.x/y/z + +go 1.10 + +exclude x.1 v1.2.0 + +replace x.1 => y.1/v2 v2.3.6 + +require x.3 v1.99.0 + +retract [ "v1.8.1" , "v1.8.2" ] +-- $WORK/go.mod.goodfmt -- +module x.x/y/z + +go 1.10 + +exclude x.1 v1.2.0 + +replace x.1 => y.1/v2 v2.3.6 + +require x.3 v1.99.0 + +retract [v1.8.1, v1.8.2] +-- $WORK/m/go.mod.edit -- +module x.x/y/z + +go $goversion +-- $WORK/go.mod.retractrationale -- +module x.x/y/z + +go 1.15 + +// a +retract v1.0.0 + +// b +retract ( + v1.0.1 + v1.0.2 // c +) +-- $WORK/go.mod.retractrationale.json -- +{ + "Module": { + "Path": "x.x/y/z" + }, + "Go": "1.15", + "Require": null, + "Exclude": null, + "Replace": null, + "Retract": [ + { + "Low": "v1.0.0", + "High": "v1.0.0", + "Rationale": "a" + }, + { + "Low": "v1.0.1", + "High": "v1.0.1", + "Rationale": "b" + }, + { + "Low": "v1.0.2", + "High": "v1.0.2", + "Rationale": "c" + } + ] +} +-- $WORK/go.mod.deprecation -- +// Deprecated: and the new one is not ready yet +module m +-- $WORK/go.mod.deprecation.json -- +{ + "Module": { + "Path": "m", + "Deprecated": "and the new one is not ready yet" + }, + "Require": null, + "Exclude": null, + "Replace": null, + "Retract": null +} +-- $WORK/go.mod.empty -- +-- $WORK/go.mod.empty.json -- +{ + "Module": { + "Path": "" + }, + "Require": null, + "Exclude": null, + "Replace": null, + "Retract": null +} diff --git a/src/cmd/go/testdata/script/mod_edit_go.txt b/src/cmd/go/testdata/script/mod_edit_go.txt new file mode 100644 index 0000000..ec04f40 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_edit_go.txt @@ -0,0 +1,26 @@ +# Test support for go mod edit -go to set language version. + +env GO111MODULE=on +! go build +stderr ' type aliases requires' +go mod edit -go=1.9 +grep 'go 1.9' go.mod +go build + +# Reverting the version should force a rebuild and error instead of using +# the cached 1.9 build. (https://golang.org/issue/37804) +go mod edit -go=1.8 +! go build +stderr 'type aliases requires' + +# go=none should drop the line +go mod edit -go=none +! grep go go.mod + +-- go.mod -- +module m +go 1.8 + +-- alias.go -- +package alias +type T = int diff --git a/src/cmd/go/testdata/script/mod_edit_no_modcache.txt b/src/cmd/go/testdata/script/mod_edit_no_modcache.txt new file mode 100644 index 0000000..ced15bb --- /dev/null +++ b/src/cmd/go/testdata/script/mod_edit_no_modcache.txt @@ -0,0 +1,15 @@ +# 'go mod edit' opportunistically locks the side-lock file in the module cache, +# for compatibility with older versions of the 'go' command. +# It does not otherwise depend on the module cache, so it should not +# fail if the module cache directory cannot be created. + +[root] skip + +mkdir $WORK/readonly +chmod 0555 $WORK/readonly +env GOPATH=$WORK/readonly/nonexist + +go mod edit -go=1.17 + +-- go.mod -- +module example.com/m diff --git a/src/cmd/go/testdata/script/mod_edit_toolchain.txt b/src/cmd/go/testdata/script/mod_edit_toolchain.txt new file mode 100644 index 0000000..bb544be --- /dev/null +++ b/src/cmd/go/testdata/script/mod_edit_toolchain.txt @@ -0,0 +1,18 @@ +# Test support for go mod edit -toolchain to set toolchain to use + +env GOTOOLCHAIN=local +env GO111MODULE=on + +! grep toolchain go.mod +go mod edit -toolchain=go1.9 +grep 'toolchain go1.9' go.mod + +go mod edit -toolchain=default +grep 'toolchain default' go.mod + +go mod edit -toolchain=none +! grep toolchain go.mod + +-- go.mod -- +module m +go 1.8 diff --git a/src/cmd/go/testdata/script/mod_empty_err.txt b/src/cmd/go/testdata/script/mod_empty_err.txt new file mode 100644 index 0000000..4b4a007 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_empty_err.txt @@ -0,0 +1,36 @@ +# This test checks error messages for non-existent packages in module mode. +# Veries golang.org/issue/35414 +env GO111MODULE=on +cd $WORK + +go list -e -f {{.Error}} . +stdout 'no Go files in '$WORK + +go list -e -f {{.Error}} ./empty +stdout 'no Go files in '$WORK${/}'empty' + +go list -e -f {{.Error}} ./exclude +stdout 'build constraints exclude all Go files in '$WORK${/}'exclude' + +go list -e -f {{.Error}} ./missing +stdout 'stat '$WORK'[/\\]missing: directory not found' + +# use 'go build -n' because 'go list' reports no error. +! go build -n ./testonly +stderr 'example.com/m/testonly: no non-test Go files in '$WORK${/}'testonly' + +-- $WORK/go.mod -- +module example.com/m + +go 1.14 + +-- $WORK/empty/empty.txt -- +-- $WORK/exclude/exclude.go -- +// +build exclude + +package exclude +-- $WORK/testonly/testonly_test.go -- +package testonly_test +-- $WORK/excluded-stdout -- +package ./excluded: cannot find package "." in: + $WORK/excluded diff --git a/src/cmd/go/testdata/script/mod_enabled.txt b/src/cmd/go/testdata/script/mod_enabled.txt new file mode 100644 index 0000000..39f1ece --- /dev/null +++ b/src/cmd/go/testdata/script/mod_enabled.txt @@ -0,0 +1,93 @@ +# GO111MODULE=auto should trigger any time a go.mod exists in a parent directory. +env GO111MODULE=auto + +cd $GOPATH/src/x/y/z +go env GOMOD +stdout $GOPATH[/\\]src[/\\]x[/\\]y[/\\]z[/\\]go.mod +go list -m -f {{.GoMod}} +stdout $GOPATH[/\\]src[/\\]x[/\\]y[/\\]z[/\\]go.mod + +cd $GOPATH/src/x/y/z/w +go env GOMOD +stdout $GOPATH[/\\]src[/\\]x[/\\]y[/\\]z[/\\]go.mod + +cd $GOPATH/src/x/y +go env GOMOD +! stdout . + +cd $GOPATH/foo +go env GOMOD +stdout foo[/\\]go.mod +go list -m -f {{.GoMod}} +stdout foo[/\\]go.mod + +cd $GOPATH/foo/bar/baz +go env GOMOD +stdout foo[/\\]go.mod + +# GO111MODULE unset should be equivalent to on. +env GO111MODULE= + +cd $GOPATH/src/x/y/z +go env GOMOD +stdout $GOPATH[/\\]src[/\\]x[/\\]y[/\\]z[/\\]go.mod + +cd $GOPATH/src/x/y +go env GOMOD +stdout 'NUL|/dev/null' + +# GO111MODULE=on should trigger everywhere +env GO111MODULE=on + +cd $GOPATH/src/x/y/z +go env GOMOD +stdout z[/\\]go.mod + +cd $GOPATH/src/x/y/z/w +go env GOMOD +stdout z[/\\]go.mod + +cd $GOPATH/src/x/y +go env GOMOD +stdout 'NUL|/dev/null' +go list -m +stdout '^command-line-arguments$' + +cd $GOPATH/foo +go env GOMOD +stdout foo[/\\]go.mod + +cd $GOPATH/foo/bar/baz +go env GOMOD +stdout foo[/\\]go.mod + +# GO111MODULE=off should trigger nowhere +env GO111MODULE=off + +cd $GOPATH/src/x/y/z +go env GOMOD +! stdout .+ + +cd $GOPATH/foo +go env GOMOD +! stdout .+ + +cd $GOPATH/foo/bar/baz +go env GOMOD +! stdout .+ + +# GO111MODULE=auto should ignore and warn about /tmp/go.mod +env GO111MODULE=auto +cp $GOPATH/src/x/y/z/go.mod $WORK/tmp/go.mod +mkdir $WORK/tmp/mydir +cd $WORK/tmp/mydir +go env GOMOD +! stdout .+ +stderr '^go: warning: ignoring go.mod in system temp root ' + +-- $GOPATH/src/x/y/z/go.mod -- +module x/y/z +-- $GOPATH/src/x/y/z/w/w.txt -- +-- $GOPATH/foo/go.mod -- +module example.com/mod +-- $GOPATH/foo/bar/baz/quux.txt -- diff --git a/src/cmd/go/testdata/script/mod_exclude_go121.txt b/src/cmd/go/testdata/script/mod_exclude_go121.txt new file mode 100644 index 0000000..51c8a00 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_exclude_go121.txt @@ -0,0 +1,34 @@ +# go.dev/issue/60028: use semver sort in exclude block in 1.21 +cp $WORK/go.mod.badfmtexclude go.mod +go mod edit -go=1.20 +cmp go.mod $WORK/go.mod.goodfmtexclude120 +go mod edit -go=1.21 +cmp go.mod $WORK/go.mod.goodfmtexclude121 + +-- $WORK/go.mod.badfmtexclude -- +module x.x/y/z +exclude ( + x.1 v1.11.0 + x.1 v1.10.0 + x.1 v1.9.0 +) +-- $WORK/go.mod.goodfmtexclude120 -- +module x.x/y/z + +go 1.20 + +exclude ( + x.1 v1.10.0 + x.1 v1.11.0 + x.1 v1.9.0 +) +-- $WORK/go.mod.goodfmtexclude121 -- +module x.x/y/z + +go 1.21 + +exclude ( + x.1 v1.9.0 + x.1 v1.10.0 + x.1 v1.11.0 +) diff --git a/src/cmd/go/testdata/script/mod_file_proxy.txt b/src/cmd/go/testdata/script/mod_file_proxy.txt new file mode 100644 index 0000000..ebc28a0 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_file_proxy.txt @@ -0,0 +1,36 @@ +[short] skip + +# Allow (cached) downloads for -mod=readonly. +env GO111MODULE=on +env GOPATH=$WORK/gopath1 +cd $WORK/x +go mod edit -fmt +go list -mod=readonly +env GOPROXY=file:///nonexist +go list +grep v1.5.1 $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/list + +# Use download cache as file:/// proxy. +env GOPATH=$WORK/gopath2 +[GOOS:windows] env GOPROXY=file:///C:/nonexist +[!GOOS:windows] env GOPROXY=file:///nonexist +! go list +[GOOS:windows] env GOPROXY=file:///$WORK/gopath1/pkg/mod/cache/download +[!GOOS:windows] env GOPROXY=file://$WORK/gopath1/pkg/mod/cache/download +go list +grep v1.5.1 $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/list + +-- $WORK/x/go.mod -- +module x +go 1.13 +require rsc.io/quote v1.5.1 +-- $WORK/x/x.go -- +package x +import _ "rsc.io/quote" +-- $WORK/x/go.sum -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.1 h1:ZE3OgnVGrhXtFkGw90HwW992ZRqcdli/33DLqEYsoxA= +rsc.io/quote v1.5.1/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/src/cmd/go/testdata/script/mod_fileproxy_vcs_missing_issue51589.txt b/src/cmd/go/testdata/script/mod_fileproxy_vcs_missing_issue51589.txt new file mode 100644 index 0000000..633bd8b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_fileproxy_vcs_missing_issue51589.txt @@ -0,0 +1,42 @@ +# This test checks that "go mod tidy -e" do not panic when +# using a file goproxy that is missing some modules. +# Verifies golang.org/issue/51589 + +# download the modules first +env GO111MODULE=on +env GOPATH=$WORK/gopath +cd $WORK/x +go mod tidy + +# Use download cache as file:/// proxy. +[GOOS:windows] env GOPROXY=file:///$WORK/gopath/pkg/mod/cache/download +[!GOOS:windows] env GOPROXY=file://$WORK/gopath/pkg/mod/cache/download +rm $WORK/gopath/pkg/mod/cache/download/golang.org/x/text/ +go mod tidy -e +stderr '^go: rsc.io/sampler@v1.3.0 requires\n\tgolang.org/x/text@.*: reading file://.*/pkg/mod/cache/download/golang.org/x/text/.*' +! stderr 'signal SIGSEGV: segmentation violation' + +-- $WORK/x/go.mod -- +module example.com/mod + +go 1.17 + +require rsc.io/quote v1.5.2 + +require ( + golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect + rsc.io/sampler v1.3.0 // indirect +) + +-- $WORK/x/x.go -- +package mod + +import ( + "fmt" + + "rsc.io/quote" +) + +func Echo() { + fmt.Println(quote.Hello()) +} diff --git a/src/cmd/go/testdata/script/mod_find.txt b/src/cmd/go/testdata/script/mod_find.txt new file mode 100644 index 0000000..9c2037b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_find.txt @@ -0,0 +1,104 @@ +env GO111MODULE=on + +# Derive module path from import comment. +cd $WORK/x +exists x.go +go mod init +stderr 'module x' + +# Import comment works even with CRLF line endings. +rm go.mod +replace '\n' '\r\n' x.go +go mod init +stderr 'module x' + +# Derive module path from location inside GOPATH. +# 'go mod init' should succeed if modules are not explicitly disabled. +cd $GOPATH/src/example.com/x/y +go mod init +stderr 'module example.com/x/y$' +rm go.mod + +# go mod init rejects a zero-length go.mod file +cp $devnull go.mod # can't use touch to create it because Windows +! go mod init +stderr 'go.mod already exists' + +# Module path from Godeps/Godeps.json overrides GOPATH. +cd $GOPATH/src/example.com/x/y/z +go mod init +stderr 'unexpected.com/z' +rm go.mod + +# Empty directory outside GOPATH fails. +mkdir $WORK/empty +cd $WORK/empty +! go mod init +stderr 'cannot determine module path for source directory' +rm go.mod + +# Empty directory inside GOPATH/src uses location inside GOPATH. +mkdir $GOPATH/src/empty +cd $GOPATH/src/empty +go mod init +stderr 'empty' +rm go.mod + +# In Plan 9, directories are automatically created in /n. +# For example, /n/go.mod always exist, but it's a directory. +# Test that we ignore directories when trying to find go.mod. +cd $WORK/gomoddir +! go list . +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +[!symlink] stop + +# gplink1/src/empty where gopathlink -> GOPATH +symlink $WORK/gopathlink -> gopath +cd $WORK/gopathlink/src/empty +go mod init +rm go.mod + +# GOPATH/src/link where link -> out of GOPATH +symlink $GOPATH/src/link -> $WORK/empty +cd $WORK/empty +! go mod init +cd $GOPATH/src/link +go mod init +stderr link +rm go.mod + +# GOPATH/src/empty where GOPATH itself is a symlink +env GOPATH=$WORK/gopathlink +cd $GOPATH/src/empty +go mod init +rm go.mod +cd $WORK/gopath/src/empty +go mod init +rm go.mod + +# GOPATH/src/link where GOPATH and link are both symlinks +cd $GOPATH/src/link +go mod init +stderr link +rm go.mod + +# Too hard: doesn't match unevaluated nor completely evaluated. (Only partially evaluated.) +# Whether this works depends on which OS we are running on. +# cd $WORK/gopath/src/link +# ! go mod init + +-- $WORK/x/x.go -- +package x // import "x" + +-- $GOPATH/src/example.com/x/y/y.go -- +package y +-- $GOPATH/src/example.com/x/y/z/z.go -- +package z +-- $GOPATH/src/example.com/x/y/z/Godeps/Godeps.json -- +{"ImportPath": "unexpected.com/z"} + +-- $WORK/gomoddir/go.mod/README.txt -- +../go.mod is a directory, not a file. +-- $WORK/gomoddir/p.go -- +package p diff --git a/src/cmd/go/testdata/script/mod_fs_patterns.txt b/src/cmd/go/testdata/script/mod_fs_patterns.txt new file mode 100644 index 0000000..c834ce8 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_fs_patterns.txt @@ -0,0 +1,97 @@ +env GO111MODULE=on + +# File system pattern searches should skip sub-modules and vendor directories. +cd x + +# all packages +go list all +stdout ^m$ +stdout ^m/vendor$ +! stdout vendor/ +stdout ^m/y$ +! stdout ^m/y/z + +# path pattern +go list m/... +stdout ^m$ +stdout ^m/vendor$ +! stdout vendor/ +stdout ^m/y$ +! stdout ^m/y/z + +# directory pattern +go list ./... +stdout ^m$ +stdout ^m/vendor$ +! stdout vendor/ +stdout ^m/y$ +! stdout ^m/y/z + +# non-existent directory should not prompt lookups +! go build -mod=readonly example.com/nonexist +stderr 'import lookup disabled' + +! go build -mod=readonly ./nonexist +! stderr 'import lookup disabled' +stderr '^stat '$GOPATH'[/\\]src[/\\]x[/\\]nonexist: directory not found' + +! go build -mod=readonly ./go.mod +! stderr 'import lookup disabled' +stderr 'main module \(m\) does not contain package m/go.mod' + + +# File system paths and patterns should allow the '@' character. +cd ../@at +go list $PWD +stdout '^at$' +go list $PWD/... +stdout '^at$' + +# The '@' character is not allowed in directory paths that are part of +# a package path. +cd ../badat/bad@ +! go list . +stderr 'current directory outside main module or its selected dependencies' +! go list $PWD +stderr 'current directory outside main module or its selected dependencies' +! go list $PWD/... +stderr 'current directory outside main module or its selected dependencies' + +-- x/go.mod -- +module m + +-- x/x.go -- +package x + +-- x/vendor/v/v.go -- +package v +import _ "golang.org/x/crypto" + +-- x/vendor/v.go -- +package main + +-- x/y/y.go -- +package y + +-- x/y/z/go.mod -- +syntax error! + +-- x/y/z/z.go -- +package z + +-- x/y/z/w/w.go -- +package w + +-- @at/go.mod -- +module at + +go 1.14 +-- @at/at.go -- +package at + +-- badat/go.mod -- +module badat + +go 1.14 +-- badat/bad@/bad.go -- +package bad diff --git a/src/cmd/go/testdata/script/mod_get_ambiguous_arg.txt b/src/cmd/go/testdata/script/mod_get_ambiguous_arg.txt new file mode 100644 index 0000000..9214993 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_ambiguous_arg.txt @@ -0,0 +1,107 @@ +go mod tidy +cp go.mod go.mod.orig + +# If there is no sensible *package* meaning for 'm/p', it should refer +# to *module* m/p. + +go get m/p # @latest +go list -m all +stdout '^m/p v0.3.0 ' +! stdout '^m ' + +cp go.mod.orig go.mod + +go get m/p@v0.1.0 +go list -m all +stdout '^m/p v0.1.0 ' +! stdout '^m ' + +# When feasible, the argument 'm/p' in 'go get m/p' refers to *package* m/p, +# which is in module m. +# +# (It only refers to *module* m/p if there is no such package at the +# requested version.) + +go get m/p@v0.2.0 +go list -m all +stdout '^m v0.2.0 ' +stdout '^m/p v0.1.0 ' # unchanged from the previous case + +# Repeating the above with module m/p already in the module graph does not +# change its meaning. + +go get m/p@v0.2.0 +go list -m all +stdout '^m v0.2.0 ' +stdout '^m/p v0.1.0 ' + +-- go.mod -- +module example.com + +go 1.16 + +replace ( + m v0.1.0 => ./m01 + m v0.2.0 => ./m02 + m v0.3.0 => ./m03 + m/p v0.1.0 => ./mp01 + m/p v0.2.0 => ./mp02 + m/p v0.3.0 => ./mp03 +) +-- m01/go.mod -- +module m + +go 1.16 +-- m01/README.txt -- +Module m at v0.1.0 does not yet contain package p. + +-- m02/go.mod -- +module m + +go 1.16 + +require m/p v0.1.0 +-- m02/p/p.go -- +// Package p is present in module m, but not module m/p. +package p + +-- m03/go.mod -- +module m + +go 1.16 + +require m/p v0.1.0 +-- m03/README.txt -- +Module m at v0.3.0 no longer contains package p. + +-- mv2/go.mod -- +module m/v2 + +go 1.16 +-- mv2/README.txt -- +This module is m/v2. It doesn't actually need to exist, +but it explains how module m could plausibly exist +and still contain package p at 'latest' even when module +m/p also exists. + +-- mp01/go.mod -- +module m/p + +go 1.16 +-- mp01/README.txt -- +This module is m/p. +Package m/p does not exist in this module. +-- mp02/go.mod -- +module m/p + +go 1.16 +-- mp02/README.txt -- +This module is m/p. +Package m/p does not exist in this module. +-- mp03/go.mod -- +module m/p + +go 1.16 +-- mp03/README.txt -- +This module is m/p. +Package m/p does not exist in this module. diff --git a/src/cmd/go/testdata/script/mod_get_ambiguous_import.txt b/src/cmd/go/testdata/script/mod_get_ambiguous_import.txt new file mode 100644 index 0000000..f08e540 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_ambiguous_import.txt @@ -0,0 +1,60 @@ +go list -m all +stdout '^example.net/m v0.1.0 ' +! stdout '^example.net/m/p ' +cp go.mod go.mod.orig + +# Upgrading example.net/m/p without also upgrading example.net/m +# causes the import of package example.net/m/p to be ambiguous. +# +# TODO(#27899): Should we automatically upgrade example.net/m to v0.2.0 +# to resolve the conflict? +! go get example.net/m/p@v1.0.0 +stderr '^go: example.net/m/p: ambiguous import: found package example.net/m/p in multiple modules:\n\texample.net/m v0.1.0 \(.*[/\\]m1[/\\]p\)\n\texample.net/m/p v1.0.0 \(.*[/\\]p0\)\n\z' +cmp go.mod go.mod.orig + +# Upgrading both modules simultaneously resolves the ambiguous upgrade. +# Note that this command line mixes a module path (example.net/m) +# and a package path (example.net/m/p) in the same command. +go get example.net/m@v0.2.0 example.net/m/p@v1.0.0 + +go list -m all +stdout '^example.net/m v0.2.0 ' +stdout '^example.net/m/p v1.0.0 ' + +-- go.mod -- +module example.net/importer + +go 1.16 + +require ( + example.net/m v0.1.0 +) + +replace ( + example.net/m v0.1.0 => ./m1 + example.net/m v0.2.0 => ./m2 + example.net/m/p v1.0.0 => ./p0 +) +-- importer.go -- +package importer +import _ "example.net/m/p" +-- m1/go.mod -- +module example.net/m + +go 1.16 +-- m1/p/p.go -- +package p +-- m2/go.mod -- +module example.net/m + +go 1.16 +-- m2/README.txt -- +Package p has been moved to module …/m/p. +Module …/m/p does not require any version of module …/m. + +-- p0/go.mod -- +module example.net/m/p + +go 1.16 +-- p0/p.go -- +package p diff --git a/src/cmd/go/testdata/script/mod_get_ambiguous_pkg.txt b/src/cmd/go/testdata/script/mod_get_ambiguous_pkg.txt new file mode 100644 index 0000000..1641196 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_ambiguous_pkg.txt @@ -0,0 +1,87 @@ +# Both example.net/ambiguous v0.1.0 and example.net/ambiguous/pkg v0.1.0 exist. +# 'go mod tidy' would arbitrarily choose the one with the longer path, +# but 'go mod tidy' also arbitrarily chooses the latest version. + +cp go.mod go.mod.orig + + +# From a clean slate, 'go get' currently does the same thing as 'go mod tidy': +# it resolves the package from the module with the longest matching prefix. + +go get example.net/ambiguous/nested/pkg@v0.1.0 +go list -m all +stdout '^example.net/ambiguous/nested v0.1.0$' +! stdout '^example.net/ambiguous ' + + +# From an initial state that already depends on the shorter path, +# the same 'go get' command should (somewhat arbitrarily) keep the +# existing path, since it is a valid interpretation of the command. + +cp go.mod.orig go.mod +go mod edit -require=example.net/ambiguous@v0.1.0 + +go get example.net/ambiguous/nested/pkg@v0.1.0 +go list -m all +stdout '^example.net/ambiguous v0.1.0$' +! stdout '^example.net/ambiguous/nested ' + + +# The user should be able to make the command unambiguous by explicitly +# upgrading the conflicting module... + +go get example.net/ambiguous@v0.2.0 example.net/ambiguous/nested/pkg@v0.1.0 +go list -m all +stdout '^example.net/ambiguous/nested v0.1.0$' +stdout '^example.net/ambiguous v0.2.0$' + + +# ...or by explicitly NOT adding the conflicting module. + +cp go.mod.orig go.mod +go mod edit -require=example.net/ambiguous@v0.1.0 + +go get example.net/ambiguous/nested/pkg@v0.1.0 example.net/ambiguous/nested@none +go list -m all +! stdout '^example.net/ambiguous/nested ' +stdout '^example.net/ambiguous v0.1.0$' + + +# The user should also be able to fix it by *downgrading* the conflicting module +# away. + +cp go.mod.orig go.mod +go mod edit -require=example.net/ambiguous@v0.1.0 + +go get example.net/ambiguous@none example.net/ambiguous/nested/pkg@v0.1.0 +go list -m all +stdout '^example.net/ambiguous/nested v0.1.0$' +! stdout '^example.net/ambiguous ' + + +# In contrast, if we do the same thing tacking a wildcard pattern ('/...') on +# the end of the package path, we get different behaviors depending on the +# initial state, and no error. (This seems to contradict the “same meaning +# regardless of the initial state” point above, but maybe that's ok?) + +cp go.mod.orig go.mod + +go get example.net/ambiguous/nested/pkg/...@v0.1.0 +go list -m all +stdout '^example.net/ambiguous/nested v0.1.0$' +! stdout '^example.net/ambiguous ' + + +cp go.mod.orig go.mod +go mod edit -require=example.net/ambiguous@v0.1.0 + +go get example.net/ambiguous/nested/pkg/...@v0.1.0 +go list -m all +! stdout '^example.net/ambiguous/nested ' +stdout '^example.net/ambiguous v0.1.0$' + + +-- go.mod -- +module test + +go 1.16 diff --git a/src/cmd/go/testdata/script/mod_get_boost.txt b/src/cmd/go/testdata/script/mod_get_boost.txt new file mode 100644 index 0000000..105dc2e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_boost.txt @@ -0,0 +1,96 @@ +# If 'go get -u' finds an upgrade candidate that isn't viable, +# but some other upgraded module's requirement moves past it +# (for example, to a higher prerelease), then we should accept +# the transitive upgrade instead of trying lower roots. + +go get -v -u . example.net/b@v0.1.0 +cmp go.mod go.mod.want + +-- go.mod -- +module example + +go 1.17 + +require ( + example.net/a v0.1.0 + example.net/b v0.1.0 + example.net/c v0.1.0 +) + +replace ( + example.net/a v0.1.0 => ./a1 + example.net/a v0.2.0-pre => ./a2p + example.net/b v0.1.0 => ./b + example.net/b v0.2.0 => ./b + example.net/c v0.1.0 => ./c1 + example.net/c v0.2.0 => ./c2 +) +-- go.mod.want -- +module example + +go 1.17 + +require ( + example.net/a v0.2.0-pre + example.net/b v0.1.0 + example.net/c v0.2.0 +) + +replace ( + example.net/a v0.1.0 => ./a1 + example.net/a v0.2.0-pre => ./a2p + example.net/b v0.1.0 => ./b + example.net/b v0.2.0 => ./b + example.net/c v0.1.0 => ./c1 + example.net/c v0.2.0 => ./c2 +) +-- example.go -- +package example + +import ( + _ "example.net/a" + _ "example.net/b" + _ "example.net/c" +) +-- a1/go.mod -- +module example.net/a + +go 1.17 + +require example.net/b v0.2.0 +-- a1/a.go -- +package a + +import _ "example.net/b" +-- a2p/go.mod -- +module example.net/a + +go 1.17 +-- a2p/a.go -- +package a +-- b/go.mod -- +module example.net/b + +go 1.17 +-- b/b.go -- +package b +-- c1/go.mod -- +module example.net/c + +go 1.17 + +require example.net/a v0.1.0 +-- c1/c.go -- +package c + +import _ "example.net/a" +-- c2/go.mod -- +module example.net/c + +go 1.17 + +require example.net/a v0.2.0-pre +-- c2/c.go -- +package c + +import _ "example.net/c" diff --git a/src/cmd/go/testdata/script/mod_get_changes.txt b/src/cmd/go/testdata/script/mod_get_changes.txt new file mode 100644 index 0000000..12a112b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_changes.txt @@ -0,0 +1,70 @@ +# When adding a requirement, 'go get' prints a message for the requirement +# and for changed explicit dependencies. 'go get' does not print messages +# for changed indirect dependencies. +go list -m all +! stdout golang.org/x/text +go get rsc.io/quote@v1.5.2 +stderr '^go: added rsc.io/quote v1.5.2$' +stderr '^go: upgraded rsc.io/sampler v1.0.0 => v1.3.0$' +! stderr '^go get.*golang.org/x/text' +go list -m all +stdout golang.org/x/text +cmp go.mod go.mod.upgrade + +# When removing a requirement, 'go get' prints a message for the requiremnent +# and for changed explicit dependencies. 'go get' does not print messages +# for changed indirect dependencies. +go get rsc.io/sampler@none +stderr '^go: downgraded rsc.io/quote v1.5.2 => v1.3.0$' +stderr '^go: removed rsc.io/sampler v1.3.0$' +! stderr '^go get.*golang.org/x/text' +cmp go.mod go.mod.downgrade + +# When removing or downgrading a requirement, 'go get' also prints a message +# for explicit dependencies removed as a consequence. +cp go.mod.usequote go.mod +go get rsc.io/quote@v1.5.1 +stderr '^go: downgraded rsc.io/quote v1.5.2 => v1.5.1$' +stderr '^go: removed usequote v0.0.0$' + +-- go.mod -- +module m + +go 1.16 + +require rsc.io/sampler v1.0.0 +-- go.sum -- +rsc.io/sampler v1.0.0 h1:SRJnjyQ07sAtq6G4RcfJEmz8JxqLyj3PoGXG2VhbDWo= +rsc.io/sampler v1.0.0/go.mod h1:cqxpM3ZVz9VtirqxZPmrWzkQ+UkiNiGtkrN+B+i8kx8= +-- go.mod.upgrade -- +module m + +go 1.16 + +require ( + rsc.io/quote v1.5.2 // indirect + rsc.io/sampler v1.3.0 +) +-- go.mod.downgrade -- +module m + +go 1.16 + +require ( + golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect + rsc.io/quote v1.3.0 // indirect +) +-- go.mod.usequote -- +module m + +go 1.16 + +require usequote v0.0.0 + +replace usequote => ./usequote +-- usequote/go.mod -- +module usequote + +go 1.16 + +require rsc.io/quote v1.5.2 diff --git a/src/cmd/go/testdata/script/mod_get_commit.txt b/src/cmd/go/testdata/script/mod_get_commit.txt new file mode 100644 index 0000000..76650f3 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_commit.txt @@ -0,0 +1,50 @@ +env GO111MODULE=on +[short] skip + +# @commit should resolve + +# golang.org/x/text/language@commit should resolve. +# Because of -d, the compiler should not run. +go get -x golang.org/x/text/language@14c0d48 +! stderr 'compile|cp|gccgo .*language\.a$' + +# go get should skip build with no Go files in root +go get golang.org/x/text@14c0d48 + +# dropping -d, we should see a build. +[short] skip + +env GOCACHE=$WORK/gocache # Looking for compile commands, so need a clean cache. + +go build -x golang.org/x/text/language +stderr 'compile|cp|gccgo .*language\.a$' + +go list -f '{{.Stale}}' golang.org/x/text/language +stdout ^false + +# install after build should not run the compiler again. +go install -x golang.org/x/text/language +! stderr 'compile|cp|gccgo .*language\.a$' + +# we should see an error for unknown packages. +! go get -x golang.org/x/text/foo@14c0d48 +stderr '^go: module golang.org/x/text@14c0d48 found \(v0.3.0\), but does not contain package golang.org/x/text/foo$' + +# get pseudo-version should record that version +go get rsc.io/quote@v0.0.0-20180214005840-23179ee8a569 +grep 'rsc.io/quote v0.0.0-20180214005840-23179ee8a569' go.mod + +# but as commit should record as v1.5.1 +go get rsc.io/quote@23179ee8 +grep 'rsc.io/quote v1.5.1' go.mod + +# go mod edit -require does not interpret commits +go mod edit -require rsc.io/quote@23179ee +grep 'rsc.io/quote 23179ee' go.mod + +# but other commands fix them +go list -m -mod=mod all +grep 'rsc.io/quote v1.5.1' go.mod + +-- go.mod -- +module x diff --git a/src/cmd/go/testdata/script/mod_get_deprecate_install.txt b/src/cmd/go/testdata/script/mod_get_deprecate_install.txt new file mode 100644 index 0000000..03258f5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_deprecate_install.txt @@ -0,0 +1,42 @@ +[short] skip + +env GO111MODULE=on + +# 'go get' outside a module prints an error. +! go get example.com/cmd/a +stderr '^go: go.mod file not found in current directory or any parent directory.$' +stderr '^\t''go get'' is no longer supported outside a module.$' + +cp go.mod.orig go.mod + +# 'go get' inside a module with a non-main package does not print a message. +# This will stop building in the future, but it's the command we want to use. +go get rsc.io/quote +! stderr deprecated +! stderr 'no longer installs' +cp go.mod.orig go.mod + +# 'go get' inside a module with an executable does not print a message. +# In 1.16 and 1.17, 'go get' did print a message in this case suggesting the +# use of -d. In 1.18, -d is a no-op, and we'd like to begin discouraging +# its use. +go get example.com/cmd/a +! stderr deprecated +! stderr 'no longer installs' +cp go.mod.orig go.mod + +# 'go get' should not print a warning for a main package inside the main module. +# The intent is most likely to update the dependencies of that package. +# 'go install' would be used otherwise. +go get m +! stderr . +cp go.mod.orig go.mod + +-- go.mod.orig -- +module m + +go 1.17 +-- main.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/mod_get_deprecated.txt b/src/cmd/go/testdata/script/mod_get_deprecated.txt new file mode 100644 index 0000000..ec7bcfd --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_deprecated.txt @@ -0,0 +1,66 @@ +# 'go get pkg' should not show a deprecation message for an unrelated module. +go get ./use/nothing +! stderr 'module.*is deprecated' + +# 'go get pkg' should show a deprecation message for the module providing pkg. +go get example.com/deprecated/a +stderr '^go: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$' +go get example.com/deprecated/a@v1.0.0 +stderr '^go: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$' + +# 'go get pkg' should show a deprecation message for a module providing +# packages directly imported by pkg. +go get ./use/a +stderr '^go: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$' + +# 'go get pkg' may show a deprecation message for an indirectly required module +# if it provides a package named on the command line. +go get ./use/b +! stderr 'module.*is deprecated' +go get local/use +! stderr 'module.*is deprecated' +go get example.com/deprecated/b +stderr '^go: module example.com/deprecated/b is deprecated: in example.com/deprecated/b@v1.9.0$' + +# 'go get pkg' does not show a deprecation message for a module providing a +# directly imported package if the module is no longer deprecated in its +# latest version, even if the module is deprecated in its current version. +go get ./use/undeprecated +! stderr 'module.*is deprecated' + +-- go.mod -- +module m + +go 1.17 + +require ( + example.com/deprecated/a v1.0.0 + example.com/undeprecated v1.0.0 + local v0.0.0 +) + +replace local v0.0.0 => ./local +-- use/nothing/nothing.go -- +package nothing +-- use/a/a.go -- +package a + +import _ "example.com/deprecated/a" +-- use/b/b.go -- +package b + +import _ "local/use" +-- use/undeprecated/undeprecated.go -- +package undeprecated + +import _ "example.com/undeprecated" +-- local/go.mod -- +module local + +go 1.17 + +require example.com/deprecated/b v1.0.0 +-- local/use/use.go -- +package use + +import _ "example.com/deprecated/b" diff --git a/src/cmd/go/testdata/script/mod_get_direct.txt b/src/cmd/go/testdata/script/mod_get_direct.txt new file mode 100644 index 0000000..02b10ab --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_direct.txt @@ -0,0 +1,19 @@ +# Regression test for golang.org/issue/34092: with an empty module cache, +# 'GOPROXY=direct go get golang.org/x/tools/gopls@master' did not correctly +# resolve the pseudo-version for its dependency on golang.org/x/tools. + +[!net:cloud.google.com] skip +[!git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +go list -m cloud.google.com/go@main +! stdout 'v0.0.0-' + +-- go.mod -- +module example.com + +go 1.14 +-- go.sum -- diff --git a/src/cmd/go/testdata/script/mod_get_downadd_indirect.txt b/src/cmd/go/testdata/script/mod_get_downadd_indirect.txt new file mode 100644 index 0000000..0f5ba99 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_downadd_indirect.txt @@ -0,0 +1,81 @@ +# This test illustrates a case where downgrading one module may upgrade another. +# Compare to the downcross2 test case in cmd/go/internal/mvs/mvs_test.go. + +# The initial package import graph used in this test looks like: +# +# a ---- b ---- d +# +# The module dependency graph originally looks like: +# +# a ---- b.2 ---- d.2 +# +# b.1 ---- c.1 +# +# If we downgrade module d to version 1, we must downgrade b as well. +# If that downgrade selects b version 1, we will add a new dependency on module c. + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod.orig go.mod + +go get example.com/d@v0.1.0 +go list -m all +stdout '^example.com/b v0.1.0 ' +stdout '^example.com/c v0.1.0 ' +stdout '^example.com/d v0.1.0 ' + +-- go.mod -- +module example.com/a + +go 1.15 + +require example.com/b v0.2.0 + +replace ( + example.com/b v0.1.0 => ./b1 + example.com/b v0.2.0 => ./b2 + example.com/c v0.1.0 => ./c + example.com/d v0.1.0 => ./d + example.com/d v0.2.0 => ./d +) +-- a.go -- +package a + +import _ "example.com/b" + +-- b1/go.mod -- +module example.com/b + +go 1.15 + +require example.com/c v0.1.0 +-- b1/b.go -- +package b + +import _ "example.com/c" + +-- b2/go.mod -- +module example.com/b + +go 1.15 + +require example.com/d v0.2.0 +-- b2/b.go -- +package b + +import _ "example.com/d" + +-- c/go.mod -- +module example.com/c + +go 1.15 + +-- c/c.go -- +package c + +-- d/go.mod -- +module example.com/d + +go 1.15 +-- d/d.go -- +package d diff --git a/src/cmd/go/testdata/script/mod_get_downgrade.txt b/src/cmd/go/testdata/script/mod_get_downgrade.txt new file mode 100644 index 0000000..2eed56d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_downgrade.txt @@ -0,0 +1,56 @@ +env GO111MODULE=on +[short] skip + +# downgrade sampler should downgrade quote +cp go.mod.orig go.mod +go get rsc.io/sampler@v1.0.0 +go list -m all +stdout 'rsc.io/quote v1.4.0' +stdout 'rsc.io/sampler v1.0.0' + +# downgrade sampler away should downgrade quote further +go get rsc.io/sampler@none +go list -m all +stdout 'rsc.io/quote v1.3.0' + +# downgrade should report inconsistencies and not change go.mod +go get rsc.io/quote@v1.5.1 +go list -m all +stdout 'rsc.io/quote v1.5.1' +stdout 'rsc.io/sampler v1.3.0' + +! go get rsc.io/sampler@v1.0.0 rsc.io/quote@v1.5.2 golang.org/x/text@none +! stderr add|remove|upgrad|downgrad +stderr '^go: rsc.io/quote@v1.5.2 requires rsc.io/sampler@v1.3.0, not rsc.io/sampler@v1.0.0$' + +go list -m all +stdout 'rsc.io/quote v1.5.1' +stdout 'rsc.io/sampler v1.3.0' + +# go get -u args should limit upgrades +cp go.mod.empty go.mod +go get -u rsc.io/quote@v1.4.0 rsc.io/sampler@v1.0.0 +go list -m all +stdout 'rsc.io/quote v1.4.0' +stdout 'rsc.io/sampler v1.0.0' +! stdout golang.org/x/text + +# downgrading away quote should also downgrade away latemigrate/v2, +# since there are no older versions. v2.0.0 is incompatible. +cp go.mod.orig go.mod +go list -m -versions example.com/latemigrate/v2 +stdout v2.0.0 # proxy may serve incompatible versions +go get rsc.io/quote@none +go list -m all +! stdout 'example.com/latemigrate/v2' + +-- go.mod.orig -- +module x +require ( + rsc.io/quote v1.5.1 + example.com/latemigrate/v2 v2.0.1 +) +-- go.mod.empty -- +module x +-- x.go -- +package x diff --git a/src/cmd/go/testdata/script/mod_get_downgrade_missing.txt b/src/cmd/go/testdata/script/mod_get_downgrade_missing.txt new file mode 100644 index 0000000..4486a67 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_downgrade_missing.txt @@ -0,0 +1,43 @@ +cp go.mod go.mod.orig + +# getting a specific version of a module along with a pattern +# not yet present in that module should report the version mismatch +# rather than a "matched no packages" warning. + +! go get example.net/pkgadded@v1.1.0 example.net/pkgadded/subpkg/... +stderr '^go: example.net/pkgadded@v1.1.0 conflicts with example.net/pkgadded/subpkg/...@upgrade \(v1.2.0\)$' +! stderr 'matched no packages' +cmp go.mod.orig go.mod + + +# A wildcard pattern should match the pattern with that path. + +go get example.net/pkgadded/...@v1.0.0 +go list -m all +stdout '^example.net/pkgadded v1.0.0' +cp go.mod.orig go.mod + + +# If we need to resolve a transitive dependency of a package, +# and another argument constrains away the version that provides that +# package, then 'go get' should fail with a useful error message. + +! go get example.net/pkgadded@v1.0.0 . +stderr '^go: example.com/m imports\n\texample.net/pkgadded/subpkg: cannot find module providing package example.net/pkgadded/subpkg$' +! stderr 'example.net/pkgadded v1\.2\.0' +cmp go.mod.orig go.mod + +go get example.net/pkgadded@v1.0.0 +! go list -deps -mod=readonly . +stderr '^m.go:3:8: cannot find module providing package example\.net/pkgadded/subpkg: ' + +-- go.mod -- +module example.com/m + +go 1.16 + +require example.net/pkgadded v1.2.0 +-- m.go -- +package m + +import _ "example.net/pkgadded/subpkg" diff --git a/src/cmd/go/testdata/script/mod_get_downup_artifact.txt b/src/cmd/go/testdata/script/mod_get_downup_artifact.txt new file mode 100644 index 0000000..111a54f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_downup_artifact.txt @@ -0,0 +1,159 @@ +# This test illustrates a case where an upgrade–downgrade–upgrade cycle can +# result in upgrades of otherwise-irrelevant dependencies. +# +# This case has no corresponding test in the mvs package, because it is an +# artifact that results from the composition of *multiple* MVS operations. + +# The initial package import graph used in the test looks like: +# +# m ---- a +# | | +# +----- b +# | | +# +----- c +# | +# +----- d +# +# b version 2 adds its own import of package d. +# +# The module dependency graph initially looks like: +# +# m ---- a.1 +# | | +# +----- b.1 +# | | +# +----- c.1 +# | +# +----- d.1 +# +# b.2 ---- c.2 +# | +# +------ d.2 +# | +# +------ e.1 +# +# If we upgrade module b to version 2, we will upgrade c and d and add a new +# dependency on e. If b version 2 is disallowed because of any of those +# dependencies, the other dependencies should not be upgraded as a side-effect. + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +go list -m all +stdout '^example.com/a v0.1.0 ' +stdout '^example.com/b v0.1.0 ' +stdout '^example.com/c v0.1.0 ' +stdout '^example.com/d v0.1.0 ' +! stdout '^example.com/e ' + +# b is imported by a, so the -u flag would normally upgrade it to v0.2.0. +# However, that would conflict with the explicit c@v0.1.0 constraint, +# so b must remain at v0.1.0. +# +# If we're not careful, we might temporarily add b@v0.2.0 and pull in its +# upgrades of module d and addition of module e, which are not relevant to +# b@v0.1.0 and should not be added to the main module's dependencies. + +go get -u example.com/a@latest example.com/c@v0.1.0 + +go list -m all +stdout '^example.com/a v0.1.0 ' +stdout '^example.com/b v0.1.0 ' +stdout '^example.com/c v0.1.0 ' +stdout '^example.com/d v0.1.0 ' +! stdout '^example.com/e ' + +-- go.mod -- +module example.com/m + +go 1.16 + +require ( + example.com/a v0.1.0 + example.com/b v0.1.0 + example.com/c v0.1.0 + example.com/d v0.1.0 +) + +replace ( + example.com/a v0.1.0 => ./a1 + example.com/b v0.1.0 => ./b1 + example.com/b v0.2.0 => ./b2 + example.com/c v0.1.0 => ./c + example.com/c v0.2.0 => ./c + example.com/d v0.1.0 => ./d + example.com/d v0.2.0 => ./d + example.com/e v0.1.0 => ./e +) +-- m.go -- +package m + +import ( + _ "example.com/a" + _ "example.com/b" + _ "example.com/c" + _ "example.com/d" +) + +-- a1/go.mod -- +module example.com/a + +go 1.16 + +require example.com/b v0.1.0 +-- a1/a.go -- +package a + +import _ "example.com/b" + +-- b1/go.mod -- +module example.com/b + +go 1.16 + +require example.com/c v0.1.0 +-- b1/b.go -- +package b + +import _ "example.com/c" + +-- b2/go.mod -- +module example.com/b + +go 1.16 + +require ( + example.com/c v0.2.0 + example.com/d v0.2.0 + example.com/e v0.1.0 +) +-- b2/b.go -- +package b + +import ( + "example.com/c" + "example.com/d" + "example.com/e" +) + +-- c/go.mod -- +module example.com/c + +go 1.16 +-- c/c.go -- +package c + +-- d/go.mod -- +module example.com/d + +go 1.16 +-- d/d.go -- +package d + +-- e/go.mod -- +module example.com/e + +go 1.16 +-- e/e.go -- +package e diff --git a/src/cmd/go/testdata/script/mod_get_downup_indirect.txt b/src/cmd/go/testdata/script/mod_get_downup_indirect.txt new file mode 100644 index 0000000..432e626 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_downup_indirect.txt @@ -0,0 +1,149 @@ +# This test illustrates a case where downgrading one module may upgrade another. +# Compare to the downcross1 test case in cmd/go/internal/mvs/mvs_test.go. + +# The package import graph used in this test looks like: +# +# a ---- b +# \ \ +# \ \ +# ----- c ---- d +# +# The module dependency graph originally looks like: +# +# a ---- b.2 +# \ \ +# \ \ +# ----- c.1 ---- d.2 +# +# b.1 ---- c.2 +# +# If we downgrade module d to version 1, we must downgrade b as well. +# If that downgrade selects b version 1, we will upgrade module c to version 2. + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod.orig go.mod + +# Downgrading d to version 1 downgrades b, which upgrades c. +go get example.com/d@v0.1.0 +go list -m all +stdout '^example.com/b v0.1.0 ' +stdout '^example.com/c v0.2.0 ' +stdout '^example.com/d v0.1.0 ' +cmp go.mod go.mod.down1 + +# Restoring c to version 1 upgrades d to meet c's requirements. +go get example.com/c@v0.1.0 +go list -m all +! stdout '^example.com/b ' +stdout '^example.com/c v0.1.0 ' +stdout '^example.com/d v0.2.0 ' +cmp go.mod go.mod.down2 + +# If a user explicitly requests the incompatible versions together, +# 'go get' should explain why they are not compatible. +! go get example.com/c@v0.1.0 example.com/d@v0.1.0 +stderr '^go: example\.com/c@v0\.1\.0 requires example\.com/d@v0\.2\.0, not example\.com/d@v0\.1\.0' + +-- go.mod -- +module example.com/a + +go 1.15 + +require ( + example.com/b v0.2.0 + example.com/c v0.1.0 +) + +replace ( + example.com/b v0.1.0 => ./b1 + example.com/b v0.2.0 => ./b2 + example.com/c v0.1.0 => ./c1 + example.com/c v0.2.0 => ./c2 + example.com/d v0.1.0 => ./d + example.com/d v0.2.0 => ./d +) +-- go.mod.down1 -- +module example.com/a + +go 1.15 + +require ( + example.com/b v0.1.0 + example.com/c v0.2.0 + example.com/d v0.1.0 // indirect +) + +replace ( + example.com/b v0.1.0 => ./b1 + example.com/b v0.2.0 => ./b2 + example.com/c v0.1.0 => ./c1 + example.com/c v0.2.0 => ./c2 + example.com/d v0.1.0 => ./d + example.com/d v0.2.0 => ./d +) +-- go.mod.down2 -- +module example.com/a + +go 1.15 + +require example.com/c v0.1.0 + +replace ( + example.com/b v0.1.0 => ./b1 + example.com/b v0.2.0 => ./b2 + example.com/c v0.1.0 => ./c1 + example.com/c v0.2.0 => ./c2 + example.com/d v0.1.0 => ./d + example.com/d v0.2.0 => ./d +) +-- a.go -- +package a + +import ( + _ "example.com/b" + _ "example.com/c" +) + +-- b1/go.mod -- +module example.com/b + +go 1.15 + +require example.com/c v0.2.0 +-- b1/b.go -- +package b + +import _ "example.com/c" + +-- b2/go.mod -- +module example.com/b + +go 1.15 + +require example.com/c v0.1.0 +-- b2/b.go -- +package b + +import _ "example.com/c" + +-- c1/go.mod -- +module example.com/c + +go 1.15 + +require example.com/d v0.2.0 +-- c1/c.go -- +package c + +-- c2/go.mod -- +module example.com/c + +go 1.15 +-- c2/c.go -- +package c + +-- d/go.mod -- +module example.com/d + +go 1.15 diff --git a/src/cmd/go/testdata/script/mod_get_downup_indirect_pruned.txt b/src/cmd/go/testdata/script/mod_get_downup_indirect_pruned.txt new file mode 100644 index 0000000..cac6b96 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_downup_indirect_pruned.txt @@ -0,0 +1,154 @@ +# This test illustrates a case where downgrading one module may upgrade another. +# This is the same as mod_get_downup_indirect, but using modules +# with graph pruning enabled (go ≥ 1.17). +# Compare to the downcross1 test case in cmd/go/internal/mvs/mvs_test.go. + +# The package import graph used in this test looks like: +# +# a ---- b +# \ \ +# \ \ +# ----- c ---- d +# +# The module dependency graph originally looks like: +# +# a ---- b.2 +# \ \ +# \ \ +# ----- c.1 ---- d.2 +# +# b.1 ---- c.2 +# +# If we downgrade module d to version 1, we must downgrade b as well. +# If that downgrade selects b version 1, we will upgrade module c to version 2. + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod.orig go.mod + +# Downgrading d to version 1 downgrades b, which upgrades c. +go get -v example.com/d@v0.1.0 +go list -m all +stdout '^example.com/b v0.1.0 ' +stdout '^example.com/c v0.2.0 ' +stdout '^example.com/d v0.1.0 ' +cmp go.mod go.mod.down1 + +# Restoring c to version 1 upgrades d to meet c's requirements. +go get example.com/c@v0.1.0 +go list -m all +! stdout '^example.com/b ' +stdout '^example.com/c v0.1.0 ' +stdout '^example.com/d v0.2.0 ' +cmp go.mod go.mod.down2 + +# If a user explicitly requests the incompatible versions together, +# 'go get' should explain why they are not compatible. +! go get example.com/c@v0.1.0 example.com/d@v0.1.0 +stderr '^go: example\.com/c@v0\.1\.0 requires example\.com/d@v0\.2\.0, not example\.com/d@v0\.1\.0' + +-- go.mod -- +module example.com/a + +go 1.17 + +require ( + example.com/b v0.2.0 + example.com/c v0.1.0 +) + +replace ( + example.com/b v0.1.0 => ./b1 + example.com/b v0.2.0 => ./b2 + example.com/c v0.1.0 => ./c1 + example.com/c v0.2.0 => ./c2 + example.com/d v0.1.0 => ./d + example.com/d v0.2.0 => ./d +) +-- go.mod.down1 -- +module example.com/a + +go 1.17 + +require ( + example.com/b v0.1.0 + example.com/c v0.2.0 +) + +require example.com/d v0.1.0 // indirect + +replace ( + example.com/b v0.1.0 => ./b1 + example.com/b v0.2.0 => ./b2 + example.com/c v0.1.0 => ./c1 + example.com/c v0.2.0 => ./c2 + example.com/d v0.1.0 => ./d + example.com/d v0.2.0 => ./d +) +-- go.mod.down2 -- +module example.com/a + +go 1.17 + +require example.com/c v0.1.0 + +require example.com/d v0.2.0 // indirect + +replace ( + example.com/b v0.1.0 => ./b1 + example.com/b v0.2.0 => ./b2 + example.com/c v0.1.0 => ./c1 + example.com/c v0.2.0 => ./c2 + example.com/d v0.1.0 => ./d + example.com/d v0.2.0 => ./d +) +-- a.go -- +package a + +import ( + _ "example.com/b" + _ "example.com/c" +) + +-- b1/go.mod -- +module example.com/b + +go 1.17 + +require example.com/c v0.2.0 +-- b1/b.go -- +package b + +import _ "example.com/c" + +-- b2/go.mod -- +module example.com/b + +go 1.17 + +require example.com/c v0.1.0 +-- b2/b.go -- +package b + +import _ "example.com/c" + +-- c1/go.mod -- +module example.com/c + +go 1.17 + +require example.com/d v0.2.0 +-- c1/c.go -- +package c + +-- c2/go.mod -- +module example.com/c + +go 1.17 +-- c2/c.go -- +package c + +-- d/go.mod -- +module example.com/d + +go 1.17 diff --git a/src/cmd/go/testdata/script/mod_get_downup_pseudo_artifact.txt b/src/cmd/go/testdata/script/mod_get_downup_pseudo_artifact.txt new file mode 100644 index 0000000..b678a17 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_downup_pseudo_artifact.txt @@ -0,0 +1,129 @@ +# This test illustrates a case where an upgrade–downgrade–upgrade cycle could +# add extraneous dependencies due to another module depending on an +# otherwise-unlisted version (such as a pseudo-version). +# +# This case corresponds to the "downhiddenartifact" test in the mvs package. + +# The initial package import graph used in the test looks like: +# +# a --- b +# \ \ +# \ \ +# c --- d +# +# The module dependency graph initially looks like: +# +# a --- b.3 +# \ \ +# \ \ +# c.2 --- d.2 +# +# c.1 --- b.2 (pseudo) +# +# b.1 --- e.1 + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod.orig go.mod + +# When we downgrade d.2 to d.1, no dependency on e should be added +# because nothing else in the module or import graph requires it. +go get example.net/d@v0.1.0 + +go list -m all +stdout '^example.net/b v0.2.1-0.20210219000000-000000000000 ' +stdout '^example.net/c v0.1.0 ' +stdout '^example.net/d v0.1.0 ' +! stdout '^example.net/e ' + +-- go.mod -- +module example.net/a + +go 1.16 + +require ( + example.net/b v0.3.0 + example.net/c v0.2.0 +) + +replace ( + example.net/b v0.1.0 => ./b1 + example.net/b v0.2.1-0.20210219000000-000000000000 => ./b2 + example.net/b v0.3.0 => ./b3 + example.net/c v0.1.0 => ./c1 + example.net/c v0.2.0 => ./c2 + example.net/d v0.1.0 => ./d + example.net/d v0.2.0 => ./d + example.net/e v0.1.0 => ./e +) +-- a.go -- +package a + +import ( + _ "example.net/b" + _ "example.net/c" +) + +-- b1/go.mod -- +module example.net/b + +go 1.16 + +require example.net/e v0.1.0 +-- b1/b.go -- +package b + +import _ "example.net/e" + +-- b2/go.mod -- +module example.net/b + +go 1.16 +-- b2/b.go -- +package b + +-- b3/go.mod -- +module example.net/b + +go 1.16 + +require example.net/d v0.2.0 +-- b3/b.go -- +package b + +import _ "example.net/d" +-- c1/go.mod -- +module example.net/c + +go 1.16 + +require example.net/b v0.2.1-0.20210219000000-000000000000 +-- c1/c.go -- +package c + +import _ "example.net/b" + +-- c2/go.mod -- +module example.net/c + +go 1.16 + +require example.net/d v0.2.0 +-- c2/c.go -- +package c + +import _ "example.net/d" + +-- d/go.mod -- +module example.net/d + +go 1.16 +-- d/d.go -- +package d + +-- e/go.mod -- +module example.net/e + +go 1.16 +-- e/e.go -- +package e diff --git a/src/cmd/go/testdata/script/mod_get_errors.txt b/src/cmd/go/testdata/script/mod_get_errors.txt new file mode 100644 index 0000000..981d6f0 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_errors.txt @@ -0,0 +1,57 @@ +cp go.mod go.mod.orig + + +# 'go get' should fail, without updating go.mod, if the transitive dependencies +# of the requested package (by default, the package in the current directory) +# cannot be resolved. + +! go get +stderr '^go: example.com/m imports\n\texample.com/badimport imports\n\texample.net/oops: cannot find module providing package example.net/oops$' +cmp go.mod.orig go.mod + +cd importsyntax + + +# A syntax error in a dependency prevents the compiler from needing that +# dependency's imports, so 'go get' should not report an error when those +# imports cannot be resolved: it has all of the dependencies that the compiler +# needs, and the user did not request to run the compiler. + +go get +cmp ../go.mod.syntax-d ../go.mod + + +-- go.mod -- +module example.com/m + +go 1.16 + +replace example.com/badimport v0.1.0 => ./badimport +-- go.mod.syntax-d -- +module example.com/m + +go 1.16 + +replace example.com/badimport v0.1.0 => ./badimport + +require example.com/badimport v0.1.0 +-- m.go -- +package m + +import _ "example.com/badimport" +-- importsyntax/importsyntax.go -- +package importsyntax + +import _ "example.com/badimport/syntaxerror" +-- badimport/go.mod -- +module example.com/badimport + +go 1.16 +-- badimport/badimport.go -- +package badimport + +import "example.net/oops" +-- badimport/syntaxerror/syntaxerror.go -- +pack-age syntaxerror // sic + +import "example.net/oops" diff --git a/src/cmd/go/testdata/script/mod_get_exec_toolchain.txt b/src/cmd/go/testdata/script/mod_get_exec_toolchain.txt new file mode 100644 index 0000000..497fe36 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_exec_toolchain.txt @@ -0,0 +1,145 @@ +env TESTGO_VERSION=go1.21 +env TESTGO_VERSION_SWITCH=switch + +# GOTOOLCHAIN=auto should run the newer toolchain +env GOTOOLCHAIN=auto +cp go.mod.new go.mod +go get rsc.io/needgo121 rsc.io/needgo122 rsc.io/needgo123 rsc.io/needall +stderr '^go: rsc.io/needall@v0.0.1 requires go >= 1.23; switching to go1.23.9$' +! stderr '\(running' +stderr '^go: added rsc.io/needall v0.0.1' +grep 'go 1.23' go.mod +grep 'toolchain go1.23.9' go.mod + +# GOTOOLCHAIN=min+auto should run the newer toolchain +env GOTOOLCHAIN=go1.21+auto +cp go.mod.new go.mod +go get rsc.io/needgo121 rsc.io/needgo122 rsc.io/needgo123 rsc.io/needall +stderr '^go: rsc.io/needall@v0.0.1 requires go >= 1.23; switching to go1.23.9$' +! stderr '\(running' +stderr '^go: added rsc.io/needall v0.0.1' +grep 'go 1.23' go.mod +grep 'toolchain go1.23.9' go.mod + +# GOTOOLCHAIN=go1.21 should NOT run the newer toolchain +env GOTOOLCHAIN=go1.21 +cp go.mod.new go.mod +! go get rsc.io/needgo121 rsc.io/needgo122 rsc.io/needgo123 rsc.io/needall +! stderr switching +stderr 'rsc.io/needgo122@v0.0.1 requires go >= 1.22' +stderr 'rsc.io/needgo123@v0.0.1 requires go >= 1.23' +stderr 'rsc.io/needall@v0.0.1 requires go >= 1.23' +stderr 'requires go >= 1.23' +! stderr 'requires go >= 1.21' # that's us! +cmp go.mod go.mod.new + +# GOTOOLCHAIN=local should NOT run the newer toolchain +env GOTOOLCHAIN=local +cp go.mod.new go.mod +! go get rsc.io/needgo121 rsc.io/needgo122 rsc.io/needgo123 rsc.io/needall +! stderr switching +stderr 'rsc.io/needgo122@v0.0.1 requires go >= 1.22' +stderr 'rsc.io/needgo123@v0.0.1 requires go >= 1.23' +stderr 'rsc.io/needall@v0.0.1 requires go >= 1.23' +stderr 'requires go >= 1.23' +! stderr 'requires go >= 1.21' # that's us! +cmp go.mod go.mod.new + +# go get go@1.22 should resolve to the latest 1.22 +env GOTOOLCHAIN=local +cp go.mod.new go.mod +! go get go@1.22 +stderr '^go: updating go.mod requires go >= 1.22.9 \(running go 1.21; GOTOOLCHAIN=local\)' + +env GOTOOLCHAIN=auto +cp go.mod.new go.mod +go get go@1.22 +stderr '^go: updating go.mod requires go >= 1.22.9; switching to go1.22.9$' + +# go get go@1.22rc1 should use 1.22rc1 exactly, not a later release. +env GOTOOLCHAIN=local +cp go.mod.new go.mod +! go get go@1.22rc1 +stderr '^go: updating go.mod requires go >= 1.22rc1 \(running go 1.21; GOTOOLCHAIN=local\)' + +env GOTOOLCHAIN=auto +cp go.mod.new go.mod +go get go@1.22rc1 +stderr '^go: updating go.mod requires go >= 1.22rc1; switching to go1.22.9$' +stderr '^go: upgraded go 1.1 => 1.22rc1$' +stderr '^go: added toolchain go1.22.9$' + +# go get go@1.22.1 should use 1.22.1 exactly, not a later release. +env GOTOOLCHAIN=local +cp go.mod.new go.mod +! go get go@1.22.1 +stderr '^go: updating go.mod requires go >= 1.22.1 \(running go 1.21; GOTOOLCHAIN=local\)' + +env GOTOOLCHAIN=auto +cp go.mod.new go.mod +go get go@1.22.1 +stderr '^go: updating go.mod requires go >= 1.22.1; switching to go1.22.9$' +stderr '^go: upgraded go 1.1 => 1.22.1$' +stderr '^go: added toolchain go1.22.9$' + +# go get needgo122 (says 'go 1.22') should use 1.22.0, the earliest release we have available +# (ignoring prereleases). +env GOTOOLCHAIN=local +cp go.mod.new go.mod +! go get rsc.io/needgo122 +stderr '^go: rsc.io/needgo122@v0.0.1 requires go >= 1.22 \(running go 1.21; GOTOOLCHAIN=local\)' + +env GOTOOLCHAIN=auto +cp go.mod.new go.mod +go get rsc.io/needgo122 +stderr '^go: upgraded go 1.1 => 1.22$' +stderr '^go: rsc.io/needgo122@v0.0.1 requires go >= 1.22; switching to go1.22.9$' +stderr '^go: added toolchain go1.22.9$' + +# go get needgo1223 (says 'go 1.22.3') should use go 1.22.3 +env GOTOOLCHAIN=local +cp go.mod.new go.mod +! go get rsc.io/needgo1223 +stderr '^go: rsc.io/needgo1223@v0.0.1 requires go >= 1.22.3 \(running go 1.21; GOTOOLCHAIN=local\)' + +env GOTOOLCHAIN=auto +cp go.mod.new go.mod +go get rsc.io/needgo1223 +stderr '^go: upgraded go 1.1 => 1.22.3$' +stderr '^go: rsc.io/needgo1223@v0.0.1 requires go >= 1.22.3; switching to go1.22.9$' +stderr '^go: added toolchain go1.22.9$' + +# go get needgo124 (says 'go 1.24') should use go 1.24rc1, the only version available +env GOTOOLCHAIN=local +cp go.mod.new go.mod +! go get rsc.io/needgo124 +stderr '^go: rsc.io/needgo124@v0.0.1 requires go >= 1.24 \(running go 1.21; GOTOOLCHAIN=local\)' + +env GOTOOLCHAIN=auto +cp go.mod.new go.mod +go get rsc.io/needgo124 +stderr '^go: rsc.io/needgo124@v0.0.1 requires go >= 1.24; switching to go1.24rc1$' +stderr '^go: upgraded go 1.1 => 1.24$' +stderr '^go: added toolchain go1.24rc1$' + +# The -C flag should not happen more than once due to switching. +mkdir dir dir/dir +cp go.mod.new go.mod +cp go.mod.new dir/go.mod +cp go.mod.new dir/dir/go.mod +cp p.go dir/p.go +cp p.go dir/dir/p.go +go get -C dir rsc.io/needgo124 +stderr '^go: rsc.io/needgo124@v0.0.1 requires go >= 1.24; switching to go1.24rc1$' +stderr '^go: upgraded go 1.1 => 1.24$' +stderr '^go: added toolchain go1.24rc1$' +cmp go.mod.new go.mod +cmp go.mod.new dir/dir/go.mod +grep 'go 1.24$' dir/go.mod + +-- go.mod.new -- +module m +go 1.1 + +-- p.go -- +package p diff --git a/src/cmd/go/testdata/script/mod_get_extra.txt b/src/cmd/go/testdata/script/mod_get_extra.txt new file mode 100644 index 0000000..083e036 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_extra.txt @@ -0,0 +1,69 @@ +cp go.mod go.mod.orig + +# The -u flag should not (even temporarily) upgrade modules whose versions are +# determined by explicit queries to any version other than the explicit one. +# Otherwise, 'go get -u' could introduce spurious dependencies. + +go get -u example.net/a@v0.1.0 example.net/b@v0.1.0 +go list -m all +stdout '^example.net/a v0.1.0 ' +stdout '^example.net/b v0.1.0 ' +! stdout '^example.net/c ' + + +# TODO(bcmills): This property does not yet hold for modules added for +# missing packages when the newly-added module matches a wildcard. + +cp go.mod.orig go.mod + +go get -u example.net/a@v0.1.0 example.net/b/...@v0.1.0 +go list -m all +stdout '^example.net/a v0.1.0 ' +stdout '^example.net/b v0.1.0 ' +stdout '^example.net/c ' # BUG, but a minor and rare one + + +-- go.mod -- +module example + +go 1.15 + +replace ( + example.net/a v0.1.0 => ./a1 + example.net/b v0.1.0 => ./b1 + example.net/b v0.2.0 => ./b2 + example.net/c v0.1.0 => ./c1 + example.net/c v0.2.0 => ./c1 +) + +-- a1/go.mod -- +module example.net/a + +go 1.15 + +// example.net/a needs a dependency on example.net/b, but lacks a requirement +// on it (perhaps due to a missed file in a VCS commit). +-- a1/a.go -- +package a +import _ "example.net/b" + +-- b1/go.mod -- +module example.net/b + +go 1.15 +-- b1/b.go -- +package b + +-- b2/go.mod -- +module example.net/b + +go 1.15 + +require example.net/c v0.1.0 +-- b2/b.go -- +package b + +-- c1/go.mod -- +module example.net/c + +go 1.15 diff --git a/src/cmd/go/testdata/script/mod_get_fallback.txt b/src/cmd/go/testdata/script/mod_get_fallback.txt new file mode 100644 index 0000000..a5119b6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_fallback.txt @@ -0,0 +1,16 @@ +env GO111MODULE=on + +[!net:golang.org] skip +[!net:proxy.golang.org] skip + +env GOPROXY=https://proxy.golang.org,direct +env GOSUMDB=off + +go get -x -v golang.org/x/tools/cmd/goimports +stderr '# get https://proxy.golang.org/golang.org/x/tools/@v/list' +! stderr '# get https://golang.org' + +-- go.mod -- +module m + +go 1.18 diff --git a/src/cmd/go/testdata/script/mod_get_fossil.txt b/src/cmd/go/testdata/script/mod_get_fossil.txt new file mode 100644 index 0000000..830e0de --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_fossil.txt @@ -0,0 +1,28 @@ +[short] skip +[!exec:fossil] skip + +# Regression test for 'go get' to ensure repositories +# provided by fossil v2.12 and up are able to be fetched +# and parsed correctly. +# Verifies golang.org/issue/42323. + + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +# 'go get' for the fossil repo will fail if fossil +# is unable to determine your fossil user. Easiest +# way to set it for use by 'go get' is specifying +# a any non-empty $USER; the value doesn't otherwise matter. +env USER=fossiluser +env FOSSIL_HOME=$WORK/home + +# Attempt to get the latest version of a fossil repo. +go get vcs-test.golang.org/fossil/hello.fossil +! stderr 'unexpected response from fossil info' +grep 'vcs-test.golang.org/fossil/hello.fossil' go.mod + +-- go.mod -- +module x +-- $WORK/home/.fossil -- diff --git a/src/cmd/go/testdata/script/mod_get_future.txt b/src/cmd/go/testdata/script/mod_get_future.txt new file mode 100644 index 0000000..3f1c777 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_future.txt @@ -0,0 +1,13 @@ +env TESTGO_VERSION=go1.21 +env GOTOOLCHAIN=local +! go mod download rsc.io/future@v1.0.0 +stderr '^go: rsc.io/future@v1.0.0 requires go >= 1.999 \(running go 1.21; GOTOOLCHAIN=local\)$' + +-- go.mod -- +module m +go 1.21 + +-- x.go -- +package p + +import "rsc.io/future/foo" diff --git a/src/cmd/go/testdata/script/mod_get_go_file.txt b/src/cmd/go/testdata/script/mod_get_go_file.txt new file mode 100644 index 0000000..c81e491 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_go_file.txt @@ -0,0 +1,73 @@ +# Tests Issue #38478 +# Tests that go get in GOMOD mode returns a specific error if the argument +# ends with '.go', has no version, and either has no slash or refers to an +# existing file. + +env GO111MODULE=on + +# argument doesn't have .go suffix and has no version +! go get test +! stderr 'arguments must be package or module paths' +! stderr 'exists as a file, but ''go get'' requires package arguments' + +# argument has .go suffix and has version +! go get test.go@v1.0.0 +! stderr 'arguments must be package or module paths' +! stderr 'exists as a file, but ''go get'' requires package arguments' + +# argument has .go suffix, is a file and exists +! go get test.go +stderr 'go: test.go: arguments must be package or module paths' + +# argument has .go suffix, doesn't exist and has no slashes +! go get test_missing.go +stderr 'arguments must be package or module paths' + +# argument has .go suffix, is a file and exists in sub-directory +! go get test/test.go +stderr 'go: test/test.go exists as a file, but ''go get'' requires package arguments' + +# argument has .go suffix, doesn't exist and has slashes +! go get test/test_missing.go +! stderr 'arguments must be package or module paths' +! stderr 'exists as a file, but ''go get'' requires package arguments' + +# argument has .go suffix, is a symlink and exists +[symlink] symlink test_sym.go -> test.go +[symlink] ! go get test_sym.go +[symlink] stderr 'go: test_sym.go: arguments must be package or module paths' +[symlink] rm test_sym.go + +# argument has .go suffix, is a symlink and exists in sub-directory +[symlink] symlink test/test_sym.go -> test.go +[symlink] ! go get test/test_sym.go +[symlink] stderr 'go: test/test_sym.go exists as a file, but ''go get'' requires package arguments' +[symlink] rm test_sym.go + +# argument has .go suffix, is a directory and exists +mkdir test_dir.go +! go get test_dir.go +stderr 'go: test_dir.go: arguments must be package or module paths' +rm test_dir.go + +# argument has .go suffix, is a directory and exists in sub-directory +mkdir test/test_dir.go +! go get test/test_dir.go +! stderr 'arguments must be package or module paths' +! stderr 'exists as a file, but ''go get'' requires package arguments' +rm test/test_dir.go + + +-- go.mod -- +module m + +go 1.18 + +-- test.go -- +package main +func main() {println("test")} + + +-- test/test.go -- +package main +func main() {println("test")} diff --git a/src/cmd/go/testdata/script/mod_get_hash.txt b/src/cmd/go/testdata/script/mod_get_hash.txt new file mode 100644 index 0000000..ec5549d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_hash.txt @@ -0,0 +1,19 @@ +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off +[!net:golang.org] skip +[!git] skip + +# fetch commit hash reachable from refs/heads/* and refs/tags/* is OK +go list -m golang.org/x/time@8be79e1e0910c292df4e79c241bb7e8f7e725959 # on master branch + +# fetch other commit hash, even with a non-standard ref, is not OK +! go list -m golang.org/x/time@334d83c35137ac2b376c1dc3e4c7733791855a3a # refs/changes/24/41624/3 +stderr 'unknown revision' +! go list -m golang.org/x/time@v0.0.0-20170424233410-334d83c35137 +stderr 'unknown revision' +! go list -m golang.org/x/time@334d83c35137 +stderr 'unknown revision' + +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/mod_get_incompatible.txt b/src/cmd/go/testdata/script/mod_get_incompatible.txt new file mode 100644 index 0000000..5a7d706 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_incompatible.txt @@ -0,0 +1,26 @@ +env GO111MODULE=on + +go get x +go list -m all +stdout 'rsc.io/breaker v2.0.0\+incompatible' + +cp go.mod2 go.mod +go get rsc.io/breaker@7307b30 +go list -m all +stdout 'rsc.io/breaker v2.0.0\+incompatible' + +go get rsc.io/breaker@v2.0.0 +go list -m all +stdout 'rsc.io/breaker v2.0.0\+incompatible' + +-- go.mod -- +module x + +-- go.mod2 -- +module x +require rsc.io/breaker v1.0.0 + +-- x.go -- +package x +import "rsc.io/breaker" +var _ = breaker.XX diff --git a/src/cmd/go/testdata/script/mod_get_indirect.txt b/src/cmd/go/testdata/script/mod_get_indirect.txt new file mode 100644 index 0000000..fa7edf2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_indirect.txt @@ -0,0 +1,59 @@ +env GO111MODULE=on +[short] skip + +# get -u should not upgrade anything, since the package +# in the current directory doesn't import anything. +go get -u +go list -m all +stdout 'quote v1.5.1$' +grep 'rsc.io/quote v1.5.1$' go.mod + +# get -u should find quote v1.5.2 once there is a use. +cp $WORK/tmp/usequote.go x.go +go get -u +go list -m all +stdout 'quote v1.5.2$' +grep 'rsc.io/quote v1.5.2$' go.mod + +# it should also update x/text later than requested by v1.5.2 +go list -m -f '{{.Path}} {{.Version}}{{if .Indirect}} // indirect{{end}}' all +stdout '^golang.org/x/text [v0-9a-f\.-]+ // indirect' +grep 'golang.org/x/text [v0-9a-f\.-]+ // indirect' go.mod + +# importing an empty module root as a package does not remove indirect tag. +cp $WORK/tmp/usetext.go x.go +go list -e +grep 'golang.org/x/text v0.3.0 // indirect$' go.mod + +# indirect tag should be removed upon seeing direct import. +cp $WORK/tmp/uselang.go x.go +go get +grep 'rsc.io/quote v1.5.2$' go.mod +grep 'golang.org/x/text [v0-9a-f\.-]+$' go.mod + +# indirect tag should be added by go mod tidy +cp $WORK/tmp/usequote.go x.go +go mod tidy +grep 'rsc.io/quote v1.5.2$' go.mod +grep 'golang.org/x/text [v0-9a-f\.-]+ // indirect' go.mod + +# requirement should be dropped entirely if not needed +cp $WORK/tmp/uselang.go x.go +go mod tidy +! grep rsc.io/quote go.mod +grep 'golang.org/x/text [v0-9a-f\.-]+$' go.mod + +-- go.mod -- +module x +require rsc.io/quote v1.5.1 +-- x.go -- +package x +-- $WORK/tmp/usetext.go -- +package x +import _ "golang.org/x/text" +-- $WORK/tmp/uselang.go -- +package x +import _ "golang.org/x/text/language" +-- $WORK/tmp/usequote.go -- +package x +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_get_insecure_redirect.txt b/src/cmd/go/testdata/script/mod_get_insecure_redirect.txt new file mode 100644 index 0000000..a503c91 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_insecure_redirect.txt @@ -0,0 +1,19 @@ +# golang.org/issue/29591: 'go get' was following plain-HTTP redirects even without -insecure (now replaced by GOINSECURE). +# golang.org/issue/61877: 'go get' would panic in case of an insecure redirect in module mode + +[!git] skip + +env GOPRIVATE=vcs-test.golang.org + +! go get -d vcs-test.golang.org/insecure/go/insecure +stderr 'redirected .* to insecure URL' + +[short] stop 'builds a git repo' + +env GOINSECURE=vcs-test.golang.org/insecure/go/insecure +go get -d vcs-test.golang.org/insecure/go/insecure + +-- go.mod -- +module example +go 1.21 + diff --git a/src/cmd/go/testdata/script/mod_get_issue37438.txt b/src/cmd/go/testdata/script/mod_get_issue37438.txt new file mode 100644 index 0000000..9392e73 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_issue37438.txt @@ -0,0 +1,37 @@ +# Regression test for https://golang.org/issue/37438. +# +# If a path exists at the requested version, but does not exist at the +# version of the module that is already required and does not exist at +# the version that would be selected by 'go mod tidy', then +# 'go get foo@requested' should resolve the requested version, +# not error out on the (unrelated) latest one. + +go get example.net/a/p@v0.2.0 + +-- go.mod -- +module example + +go 1.15 + +require example.net/a v0.1.0 + +replace ( + example.net/a v0.1.0 => ./a1 + example.net/a v0.2.0 => ./a2 + example.net/a v0.3.0 => ./a1 +) + +-- a1/go.mod -- +module example.net/a + +go 1.15 +-- a1/README -- +package example.net/a/p does not exist at this version. + +-- a2/go.mod -- +module example.net/a + +go 1.15 +-- a2/p/p.go -- +// Package p exists only at v0.2.0. +package p diff --git a/src/cmd/go/testdata/script/mod_get_issue47650.txt b/src/cmd/go/testdata/script/mod_get_issue47650.txt new file mode 100644 index 0000000..8561b21 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_issue47650.txt @@ -0,0 +1,29 @@ +# Regression test for https://go.dev/issue/47650: +# 'go get' with a pseudo-version of a non-root package within a module +# erroneously rejected the pseudo-version as invalid, because it did not fetch +# enough commit history to validate the pseudo-version base. + +[short] skip 'creates and uses a git repository' +[!git] skip + +env GOPRIVATE=vcs-test.golang.org + +# If we request a package in a subdirectory of a module by commit hash, we +# successfully resolve it to a pseudo-version derived from a tag on the parent +# commit. +cp go.mod go.mod.orig +go get -x vcs-test.golang.org/git/issue47650.git/cmd/issue47650@21535ef346c3 +stderr '^go: added vcs-test.golang.org/git/issue47650.git v0.1.1-0.20210811175200-21535ef346c3$' + +# Explicitly requesting that same version should succeed, fetching additional +# history for the requested commit as needed in order to validate the +# pseudo-version base. +go clean -modcache +cp go.mod.orig go.mod +go get -x vcs-test.golang.org/git/issue47650.git/cmd/issue47650@v0.1.1-0.20210811175200-21535ef346c3 +stderr '^go: added vcs-test.golang.org/git/issue47650.git v0.1.1-0.20210811175200-21535ef346c3$' + +-- go.mod -- +module example + +go 1.20 diff --git a/src/cmd/go/testdata/script/mod_get_issue47979.txt b/src/cmd/go/testdata/script/mod_get_issue47979.txt new file mode 100644 index 0000000..848ee3a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_issue47979.txt @@ -0,0 +1,117 @@ +# Regression test for https://golang.org/issue/47979: +# +# An argument to 'go get' that results in an upgrade to a different existing +# root should be allowed, and should not panic the 'go' command. + +cp go.mod go.mod.orig + + +# Transitive upgrades from upgraded roots should not prevent +# 'go get -u' from performing upgrades. + +cp go.mod.orig go.mod +go get -u . +cmp go.mod go.mod.want + + +# 'go get' of a specific version should allow upgrades of +# every dependency (transitively) required by that version, +# including dependencies that are pulled into the module +# graph by upgrading other root requirements +# (in this case, example.net/indirect). + +cp go.mod.orig go.mod +go get example.net/a@v0.2.0 +cmp go.mod go.mod.want + + +-- go.mod -- +module golang.org/issue47979 + +go 1.17 + +replace ( + example.net/a v0.1.0 => ./a1 + example.net/a v0.2.0 => ./a2 + example.net/indirect v0.1.0 => ./indirect1 + example.net/indirect v0.2.0 => ./indirect2 + example.net/other v0.1.0 => ./other + example.net/other v0.2.0 => ./other +) + +require ( + example.net/a v0.1.0 + example.net/other v0.1.0 +) + +require example.net/indirect v0.1.0 // indirect +-- go.mod.want -- +module golang.org/issue47979 + +go 1.17 + +replace ( + example.net/a v0.1.0 => ./a1 + example.net/a v0.2.0 => ./a2 + example.net/indirect v0.1.0 => ./indirect1 + example.net/indirect v0.2.0 => ./indirect2 + example.net/other v0.1.0 => ./other + example.net/other v0.2.0 => ./other +) + +require ( + example.net/a v0.2.0 + example.net/other v0.2.0 +) + +require example.net/indirect v0.2.0 // indirect +-- issue.go -- +package issue + +import _ "example.net/a" +-- useother/useother.go -- +package useother + +import _ "example.net/other" +-- a1/go.mod -- +module example.net/a + +go 1.17 + +require example.net/indirect v0.1.0 +-- a1/a.go -- +package a +-- a2/go.mod -- +module example.net/a + +go 1.17 + +require example.net/indirect v0.2.0 +-- a2/a.go -- +package a + +import "example.net/indirect" +-- indirect1/go.mod -- +module example.net/indirect + +go 1.17 + +require example.net/other v0.1.0 +-- indirect1/indirect.go -- +package indirect +-- indirect2/go.mod -- +module example.net/indirect + +go 1.17 + +require example.net/other v0.2.0 +-- indirect2/indirect.go -- +package indirect + +import "example.net/other" +-- other/go.mod -- +module example.net/other + +go 1.17 +-- other/other.go -- +package other diff --git a/src/cmd/go/testdata/script/mod_get_issue48511.txt b/src/cmd/go/testdata/script/mod_get_issue48511.txt new file mode 100644 index 0000000..0ba486d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_issue48511.txt @@ -0,0 +1,68 @@ +# Regression test for https://golang.org/issue/48511: +# requirement minimization was accidentally replacing previous +# versions of the main module, causing dependencies to be +# spuriously dropping during requirement minimization and +# leading to an infinite loop. + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +go get -u=patch ./... +cmp go.mod go.mod.want + +-- go.mod -- +module example.net/m + +go 1.16 + +replace ( + example.net/a v0.1.0 => ./a + example.net/b v0.1.0 => ./b + example.net/b v0.1.1 => ./b + example.net/m v0.1.0 => ./m1 +) + +require example.net/a v0.1.0 +-- go.mod.want -- +module example.net/m + +go 1.16 + +replace ( + example.net/a v0.1.0 => ./a + example.net/b v0.1.0 => ./b + example.net/b v0.1.1 => ./b + example.net/m v0.1.0 => ./m1 +) + +require ( + example.net/a v0.1.0 + example.net/b v0.1.1 // indirect +) +-- m.go -- +package m + +import "example.net/a" +-- m1/go.mod -- +module example.net/m + +go 1.16 + +require example.net/b v0.1.0 +-- a/go.mod -- +module example.net/a + +go 1.16 + +require example.net/m v0.1.0 +-- a/a.go -- +package a + +import "example.net/b" +-- b/go.mod -- +module example.net/b + +go 1.16 +-- b/b.go -- +package b diff --git a/src/cmd/go/testdata/script/mod_get_issue56494.txt b/src/cmd/go/testdata/script/mod_get_issue56494.txt new file mode 100644 index 0000000..3e4d4af --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_issue56494.txt @@ -0,0 +1,134 @@ +# Regression test for https://go.dev/issue/56494: +# 'go get' in module mode was failing to prune out dependencies +# through modules whose versions are too low to be selected. + +# Initially, modules "a", "b", and "c" are unrelated. +# +# The package import graph at v1 of everything looks like: +# +# m --- a +# | +# + --- b +# | +# + --- c +# +# At v2, package "a" adds imports of "b" and "c" +# (and a requirement on "c" v2): +# +# a --- b +# | +# + --- c +# +# And "b" adds an import of "a/sub" (in module "a"): +# +# b --- a/sub +# +# At v3, "a" no longer imports (nor requires) "c": +# +# a --- b + +# So upgrading to a3 adds a dependency on b2, +# b2 adds a dependency on a2 (for "a/sub"), +# and a2 (but not a3) would add a dependency on c2. +# Since a2 is lower than a3 it cannot possibly be selected when +# upgrading to a3: normally a2 is pruned out of a3's module graph, +# so 'go get' should prune it out too, and c should remain at c1 +# without error. + +go get a@v0.3.0 + +go list -m c +stdout '^c v0.1.0 ' + +-- go.mod -- +module m + +go 1.19 + +require ( + a v0.1.0 + b v0.1.0 + c v0.1.0 +) + +replace ( + a v0.1.0 => ./a1 + a v0.2.0 => ./a2 + a v0.3.0 => ./a3 + b v0.1.0 => ./b1 + b v0.2.0 => ./b2 + c v0.1.0 => ./c1 + c v0.2.0 => ./c2 +) +-- m.go -- +package m + +import ( + _ "a" + _ "b" + _ "c" +) +-- a1/go.mod -- +module a + +go 1.19 +-- a1/a.go -- +package a +-- a2/go.mod -- +module a + +go 1.19 + +require ( + b v0.1.0 + c v0.2.0 +) +-- a2/a.go -- +package a + +import ( + _ "b" + _ "c" +) +-- a2/sub/sub.go -- +package sub +-- a3/go.mod -- +module a + +go 1.19 + +require b v0.2.0 +-- a3/a.go -- +package a + +import _ "b" +-- a3/sub/sub.go -- +package sub +-- b1/go.mod -- +module b + +go 1.19 +-- b1/b.go -- +package b +-- b2/go.mod -- +module b + +go 1.19 + +require a v0.2.0 +-- b2/b.go -- +package b + +import "a/sub" +-- c1/go.mod -- +module c + +go 1.19 +-- c1/c.go -- +package c +-- c2/go.mod -- +module c + +go 1.19 +-- c2/c.go -- +package c diff --git a/src/cmd/go/testdata/script/mod_get_issue60490.txt b/src/cmd/go/testdata/script/mod_get_issue60490.txt new file mode 100644 index 0000000..e0ac26a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_issue60490.txt @@ -0,0 +1,48 @@ +# Regression test for https://go.dev/issue/60490: 'go get' should not cause an +# infinite loop for cycles introduced in the pruned module graph. + +go get example.net/c@v0.1.0 + +-- go.mod -- +module example + +go 1.19 + +require ( + example.net/a v0.1.0 + example.net/b v0.1.0 +) + +replace ( + example.net/a v0.1.0 => ./a1 + example.net/a v0.2.0 => ./a2 + example.net/b v0.1.0 => ./b1 + example.net/b v0.2.0 => ./b2 + example.net/c v0.1.0 => ./c1 +) +-- a1/go.mod -- +module example.net/a + +go 1.19 +-- a2/go.mod -- +module example.net/a + +go 1.19 + +require example.net/b v0.2.0 +-- b1/go.mod -- +module example.net/b + +go 1.19 +-- b2/go.mod -- +module example.net/b + +go 1.19 + +require example.net/a v0.2.0 +-- c1/go.mod -- +module example.net/c + +go 1.19 + +require example.net/a v0.2.0 diff --git a/src/cmd/go/testdata/script/mod_get_latest_pseudo.txt b/src/cmd/go/testdata/script/mod_get_latest_pseudo.txt new file mode 100644 index 0000000..00da0c3 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_latest_pseudo.txt @@ -0,0 +1,10 @@ +# Check that we can build a module with no tagged versions by querying +# "@latest" through a proxy. +# Verifies golang.org/issue/32636 + +env GO111MODULE=on + +go mod init m +go get example.com/notags +go list -m all +stdout '^example.com/notags v0.0.0-20190507143103-cc8cbe209b64$' diff --git a/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt b/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt new file mode 100644 index 0000000..1cef9d1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_lazy_indirect.txt @@ -0,0 +1,44 @@ +# https://golang.org/issue/45979: after 'go get' on a package, +# that package should be importable without error. + + +# We start out with an unresolved dependency. +# 'go list' suggests that we run 'go get' on that dependency. + +! go list -deps . +stderr '^m.go:3:8: no required module provides package rsc\.io/quote; to add it:\n\tgo get rsc.io/quote$' + + +# When we run the suggested 'go get' command, the new dependency can be used +# immediately. +# +# 'go get' marks the new dependency as 'indirect', because it doesn't scan +# enough source code to know whether it is direct, and it is easier and less +# invasive to remove an incorrect indirect mark (e.g. using 'go get') than to +# add one that is missing ('go mod tidy' or 'go mod vendor'). + +go get rsc.io/quote +grep 'rsc.io/quote v\d+\.\d+\.\d+ // indirect$' go.mod +! grep 'rsc.io/quote v\d+\.\d+\.\d+$' go.mod + +go list -deps . +! stderr . +[!short] go build . +[!short] ! stderr . + + +# 'go get .' (or 'go mod tidy') removes the indirect mark. + +go get . +grep 'rsc.io/quote v\d+\.\d+\.\d+$' go.mod +! grep 'rsc.io/quote v\d+\.\d+\.\d+ // indirect$' go.mod + + +-- go.mod -- +module example.com/m + +go 1.17 +-- m.go -- +package m + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_get_lazy_upgrade_lazy.txt b/src/cmd/go/testdata/script/mod_get_lazy_upgrade_lazy.txt new file mode 100644 index 0000000..3dae383 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_lazy_upgrade_lazy.txt @@ -0,0 +1,68 @@ +# Check that 'go get -u' will upgrade a dependency (direct or indirect) +# when the main module and the dependency are both lazy. +# Verifies #47768. + +# Check that go.mod is tidy, and an upgrade is available. +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +go list -m -u example.com/lazyupgrade +stdout '^example.com/lazyupgrade v0.1.0 \[v0.1.1\] => ./lazyupgrade@v0.1.0$' + +# 'go get -u' on a package that directly imports the dependency should upgrade. +go get -u ./usedirect +go list -m example.com/lazyupgrade +stdout '^example.com/lazyupgrade v0.1.1 => ./lazyupgrade@v0.1.1$' +cp go.mod.orig go.mod + +# 'go get -u' on a package that indirectly imports the dependency should upgrade. +go get -u ./useindirect +go list -m example.com/lazyupgrade +stdout '^example.com/lazyupgrade v0.1.1 => ./lazyupgrade@v0.1.1$' + +-- go.mod -- +module use + +go 1.17 + +require ( + direct v0.0.0 + example.com/lazyupgrade v0.1.0 +) + +replace ( + direct => ./direct + example.com/lazyupgrade v0.1.0 => ./lazyupgrade@v0.1.0 + example.com/lazyupgrade v0.1.1 => ./lazyupgrade@v0.1.1 +) +-- usedirect/usedirect.go -- +package use + +import _ "example.com/lazyupgrade" +-- useindirect/useindirect.go -- +package use + +import _ "direct" +-- direct/go.mod -- +module direct + +go 1.17 + +require example.com/lazyupgrade v0.1.0 +-- direct/direct.go -- +package direct + +import _ "example.com/lazyupgrade" +-- lazyupgrade@v0.1.0/go.mod -- +module example.com/lazyupgrade + +go 1.17 +-- lazyupgrade@v0.1.0/lazyupgrade.go -- +package lazyupgrade +-- lazyupgrade@v0.1.1/go.mod -- +module example.com/lazyupgrade + +go 1.17 +-- lazyupgrade@v0.1.1/lazyupgrade.go -- +package lazyupgrade diff --git a/src/cmd/go/testdata/script/mod_get_local.txt b/src/cmd/go/testdata/script/mod_get_local.txt new file mode 100644 index 0000000..4c81d16 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_local.txt @@ -0,0 +1,62 @@ +# Test 'go get' with a local module with a name that is not valid for network lookup. +[short] skip + +env GO111MODULE=on +go mod edit -fmt +cp go.mod go.mod.orig + +# 'go get -u' within the main module should work, even if it has a local-only name. +cp go.mod.orig go.mod +go get -u ./... +grep 'rsc.io/quote.*v1.5.2' go.mod +grep 'golang.org/x/text.*v0.3.0' go.mod +cp go.mod go.mod.implicitmod + +# 'go get -u local/...' should be equivalent to 'go get -u ./...' +# (assuming no nested modules) +cp go.mod.orig go.mod +go get -u local/... +cmp go.mod go.mod.implicitmod + +# For the main module, @patch should be a no-op. +cp go.mod.orig go.mod +go get -u local/...@patch +cmp go.mod go.mod.implicitmod + +# 'go get -u' in the empty root of the main module should fail. +# 'go get -u .' should also fail. +cp go.mod.orig go.mod +! go get -u +! go get -u . + +# 'go get -u .' within a package in the main module updates the dependencies +# of that package. +cp go.mod.orig go.mod +cd uselang +go get -u . +cd .. +grep 'rsc.io/quote.*v1.3.0' go.mod +grep 'golang.org/x/text.*v0.3.0' go.mod +cp go.mod go.mod.dotpkg + +# 'go get -u' with an explicit package in the main module updates the +# dependencies of that package. +cp go.mod.orig go.mod +go get -u local/uselang +cmp go.mod go.mod.dotpkg + +-- go.mod -- +module local + +require ( + golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c + rsc.io/quote v1.3.0 +) + +-- uselang/uselang.go -- +package uselang +import _ "golang.org/x/text/language" + +-- usequote/usequote.go -- +package usequote +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_get_main.txt b/src/cmd/go/testdata/script/mod_get_main.txt new file mode 100644 index 0000000..cddd5f7 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_main.txt @@ -0,0 +1,51 @@ +env GO111MODULE=on +cp go.mod.orig go.mod + +# relative and absolute paths must be within the main module. +! go get .. +stderr '^go: \.\. \('$WORK'[/\\]gopath\) is not within module rooted at '$WORK'[/\\]gopath[/\\]src$' +! go get $WORK +stderr '^go: '$WORK' is not within module rooted at '$WORK'[/\\]gopath[/\\]src$' +! go get ../... +stderr '^go: \.\./\.\.\. \('$WORK'[/\\]gopath([/\\]...)?\) is not within module rooted at '$WORK'[/\\]gopath[/\\]src$' +! go get $WORK/... +stderr '^go: '$WORK'[/\\]\.\.\. is not within module rooted at '$WORK'[/\\]gopath[/\\]src$' + +# @patch and @latest within the main module refer to the current version. +# The main module won't be upgraded, but missing dependencies will be added. +go get rsc.io/x +grep 'rsc.io/quote v1.5.2' go.mod +go get rsc.io/x@upgrade +grep 'rsc.io/quote v1.5.2' go.mod +cp go.mod.orig go.mod +go get rsc.io/x@patch +grep 'rsc.io/quote v1.5.2' go.mod +cp go.mod.orig go.mod + + +# Upgrading a package pattern not contained in the main module should not +# attempt to upgrade the main module. +go get rsc.io/quote/...@v1.5.1 +grep 'rsc.io/quote v1.5.1' go.mod + + +# The main module cannot be updated to a specific version. +! go get rsc.io@v0.1.0 +stderr '^go: can''t request version "v0.1.0" of the main module \(rsc.io\)$' + +# A package in the main module can't be upgraded either. +! go get rsc.io/x@v0.1.0 +stderr '^go: package rsc.io/x is in the main module, so can''t request version v0.1.0$' + +# Nor can a pattern matching packages in the main module. +! go get rsc.io/x/...@latest +stderr '^go: pattern rsc.io/x/... matches package rsc.io/x in the main module, so can''t request version latest$' + +-- go.mod.orig -- +module rsc.io + +go 1.13 +-- x/x.go -- +package x + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_get_major.txt b/src/cmd/go/testdata/script/mod_get_major.txt new file mode 100644 index 0000000..4e0febb --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_major.txt @@ -0,0 +1,23 @@ +[short] skip +[!git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +# golang.org/issue/34383: if a module path ends in a major-version suffix, +# ensure that 'direct' mode can resolve the package to a module. + +go get vcs-test.golang.org/git/v3pkg.git/v3@v3.0.0 + +go list -m vcs-test.golang.org/git/v3pkg.git/v3 +stdout '^vcs-test.golang.org/git/v3pkg.git/v3 v3.0.0$' + +go get vcs-test.golang.org/git/empty-v2-without-v1.git/v2@v2.0.0 + +go list -m vcs-test.golang.org/git/empty-v2-without-v1.git/v2 +stdout '^vcs-test.golang.org/git/empty-v2-without-v1.git/v2 v2.0.0$' + +-- go.mod -- +module example.com +go 1.13 diff --git a/src/cmd/go/testdata/script/mod_get_missing_ziphash.txt b/src/cmd/go/testdata/script/mod_get_missing_ziphash.txt new file mode 100644 index 0000000..5934251 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_missing_ziphash.txt @@ -0,0 +1,55 @@ +# Test that if the module cache contains an extracted source directory but not +# a ziphash, 'go build' complains about a missing sum, and 'go get' adds +# the sum. Verifies #44749. + +# With a tidy go.sum, go build succeeds. This also populates the module cache. +cp go.sum.tidy go.sum +go build -n use +env GOPROXY=off +env GOSUMDB=off + +# Control case: if we delete the hash for rsc.io/quote v1.5.2, +# 'go build' reports an error. 'go get' adds the sum. +cp go.sum.bug go.sum +! go build -n use +stderr '^use.go:3:8: missing go.sum entry for module providing package rsc.io/quote \(imported by use\); to add:\n\tgo get use$' +go get use +cmp go.sum go.sum.tidy +go build -n use + +# If we delete the hash *and* the ziphash file, we should see the same behavior. +cp go.sum.bug go.sum +rm $WORK/gopath/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.ziphash +! go build -n use +stderr '^use.go:3:8: missing go.sum entry for module providing package rsc.io/quote \(imported by use\); to add:\n\tgo get use$' +go get use +cmp go.sum go.sum.tidy +go build -n use + +-- go.mod -- +module use + +go 1.16 + +require rsc.io/quote v1.5.2 +-- go.sum.tidy -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= +-- go.sum.bug -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= +-- use.go -- +package use + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_get_moved.txt b/src/cmd/go/testdata/script/mod_get_moved.txt new file mode 100644 index 0000000..cc35b4c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_moved.txt @@ -0,0 +1,40 @@ +env GO111MODULE=on +[short] skip + +# A 'go get' that worked at a previous version should continue to work at that version, +# even if the package was subsequently moved into a submodule. +go mod init example.com/foo +go get example.com/split/subpkg@v1.0.0 +go list -m all +stdout 'example.com/split v1.0.0' + +# A 'go get' that simultaneously upgrades away conflicting package definitions is not ambiguous. +go get example.com/split/subpkg@v1.1.0 + +# A 'go get' without an upgrade should find the package. +rm go.mod +go mod init example.com/foo +go get example.com/split/subpkg +go list -m all +stdout 'example.com/split/subpkg v1.1.0' + + +# A 'go get' that worked at a previous version should continue to work at that version, +# even if the package was subsequently moved into a parent module. +rm go.mod +go mod init example.com/foo +go get example.com/join/subpkg@v1.0.0 +go list -m all +stdout 'example.com/join/subpkg v1.0.0' + +# A 'go get' that simultaneously upgrades away conflicting package definitions is not ambiguous. +# (A wildcard pattern applies to both packages and modules, +# because we define wildcard matching to apply after version resolution.) +go get example.com/join/subpkg/...@v1.1.0 + +# A 'go get' without an upgrade should find the package. +rm go.mod +go mod init example.com/foo +go get example.com/join/subpkg@v1.1.0 +go list -m all +stdout 'example.com/join v1.1.0' diff --git a/src/cmd/go/testdata/script/mod_get_newcycle.txt b/src/cmd/go/testdata/script/mod_get_newcycle.txt new file mode 100644 index 0000000..4f5229e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_newcycle.txt @@ -0,0 +1,14 @@ +env GO111MODULE=on + +# Download modules to avoid stderr chatter +go mod download example.com@v1.0.0 +go mod download example.com/newcycle/a@v1.0.0 +go mod download example.com/newcycle/a@v1.0.1 +go mod download example.com/newcycle/b@v1.0.0 + +go mod init m +! go get example.com/newcycle/a@v1.0.0 +cmp stderr stderr-expected + +-- stderr-expected -- +go: example.com/newcycle/a@v1.0.0 indirectly requires example.com/newcycle/a@v1.0.1, not example.com/newcycle/a@v1.0.0 diff --git a/src/cmd/go/testdata/script/mod_get_none.txt b/src/cmd/go/testdata/script/mod_get_none.txt new file mode 100644 index 0000000..5aec209 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_none.txt @@ -0,0 +1,12 @@ +env GO111MODULE=on + +go mod init example.com/foo + +# 'go get bar@none' should be a no-op if module bar is not active. +go get example.com/bar@none +go list -m all +! stdout example.com/bar + +go get example.com/bar@none +go list -m all +! stdout example.com/bar diff --git a/src/cmd/go/testdata/script/mod_get_nopkgs.txt b/src/cmd/go/testdata/script/mod_get_nopkgs.txt new file mode 100644 index 0000000..14176a7 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_nopkgs.txt @@ -0,0 +1,40 @@ +cd subdir + +# 'go get' on empty patterns that are necessarily local to the module +# should warn that the patterns are empty, exactly once. + +go get ./... +stderr -count=1 'matched no packages' + +go get ./... +stderr -count=1 'matched no packages' + +# 'go get' on patterns that could conceivably match nested modules +# should report a module resolution error. + +go get example.net/emptysubdir/... # control case + +! go get example.net/emptysubdir/subdir/... +! stderr 'matched no packages' +stderr '^go: example\.net/emptysubdir/subdir/\.\.\.: module example\.net/emptysubdir/subdir: reading http://.*: 404 Not Found\n\tserver response: 404 page not found\n\z' + +# It doesn't make sense to 'go get' a path in the standard library, +# since the standard library necessarily can't have unresolved imports. +# +# TODO(#30241): Maybe that won't always be the case? +# +# For that case, we emit a "malformed module path" error message, +# which isn't ideal either. + +! go get builtin/... # in GOROOT/src, but contains no packages +stderr '^go: builtin/...: malformed module path "builtin": missing dot in first path element$' + +-- go.mod -- +module example.net/emptysubdir + +go 1.16 +-- emptysubdir.go -- +// Package emptysubdir has a subdirectory containing no packages. +package emptysubdir +-- subdir/README.txt -- +This module intentionally does not contain any p diff --git a/src/cmd/go/testdata/script/mod_get_patch.txt b/src/cmd/go/testdata/script/mod_get_patch.txt new file mode 100644 index 0000000..35cc276 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_patch.txt @@ -0,0 +1,130 @@ +# This test examines the behavior of 'go get …@patch' +# See also mod_upgrade_patch.txt (focused on "-u=patch" specifically) +# and mod_get_patchmod.txt (focused on module/package ambiguities). + +cp go.mod go.mod.orig + +# example.net/b@patch refers to the patch for the version of b that was selected +# at the start of 'go get', not the version after applying other changes. + +! go get example.net/a@v0.2.0 example.net/b@patch +stderr '^go: example.net/a@v0.2.0 requires example.net/b@v0.2.0, not example.net/b@patch \(v0.1.1\)$' +cmp go.mod go.mod.orig + + +# -u=patch changes the default version for other arguments to '@patch', +# but they continue to be resolved against the originally-selected version, +# not the updated one. +# +# TODO(#42360): Reconsider the change in defaults. + +! go get -u=patch example.net/a@v0.2.0 example.net/b +stderr '^go: example.net/a@v0.2.0 requires example.net/b@v0.2.0, not example.net/b@patch \(v0.1.1\)$' +cmp go.mod go.mod.orig + + +# -u=patch refers to the patches for the selected versions of dependencies *after* +# applying other version changes, not the versions that were selected at the start. +# However, it should not patch versions determined by explicit arguments. + +go get -u=patch example.net/a@v0.2.0 +go list -m all +stdout '^example.net/a v0.2.0 ' +stdout '^example.net/b v0.2.1 ' + + +# "-u=patch all" should be equivalent to "all@patch", and should fail if the +# patched versions result in a higher-than-patch upgrade. + +cp go.mod.orig go.mod +! go get -u=patch all +stderr '^go: example.net/a@v0.1.1 \(matching all@patch\) requires example.net/b@v0.2.0, not example.net/b@v0.1.1 \(matching all@patch\)$' +cmp go.mod go.mod.orig + + +# On the other hand, "-u=patch ./..." should patch-upgrade dependencies until +# they reach a fixed point, even if that results in higher-than-patch upgrades. + +go get -u=patch ./... +go list -m all +stdout '^example.net/a v0.1.1 ' +stdout '^example.net/b v0.2.1 ' + + +-- go.mod -- +module example + +go 1.16 + +require ( + example.net/a v0.1.0 + example.net/b v0.1.0 // indirect +) + +replace ( + example.net/a v0.1.0 => ./a10 + example.net/a v0.1.1 => ./a11 + example.net/a v0.2.0 => ./a20 + example.net/a v0.2.1 => ./a21 + example.net/b v0.1.0 => ./b + example.net/b v0.1.1 => ./b + example.net/b v0.2.0 => ./b + example.net/b v0.2.1 => ./b + example.net/b v0.3.0 => ./b + example.net/b v0.3.1 => ./b +) +-- example.go -- +package example + +import _ "example.net/a" + +-- a10/go.mod -- +module example.net/a + +go 1.16 + +require example.net/b v0.1.0 +-- a10/a.go -- +package a + +import _ "example.net/b" + +-- a11/go.mod -- +module example.net/a + +go 1.16 + +require example.net/b v0.2.0 // upgraded +-- a11/a.go -- +package a + +import _ "example.net/b" + +-- a20/go.mod -- +module example.net/a + +go 1.16 + +require example.net/b v0.2.0 +-- a20/a.go -- +package a + +import _ "example.net/b" + +-- a21/go.mod -- +module example.net/a + +go 1.16 + +require example.net/b v0.2.0 // not upgraded +-- a21/a.go -- +package a + +import _ "example.net/b" + +-- b/go.mod -- +module example.net/b + +go 1.16 +-- b/b.go -- +package b diff --git a/src/cmd/go/testdata/script/mod_get_patchbound.txt b/src/cmd/go/testdata/script/mod_get_patchbound.txt new file mode 100644 index 0000000..e4d3c49 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_patchbound.txt @@ -0,0 +1,84 @@ +# -u=patch will patch dependencies as far as possible, but not so far that they +# conflict with other command-line arguments. + +go list -m all +stdout '^example.net/a v0.1.0 ' +stdout '^example.net/b v0.1.0 ' + +go get -u=patch example.net/a@v0.2.0 +go list -m all +stdout '^example.net/a v0.2.0 ' +stdout '^example.net/b v0.1.1 ' # not v0.1.2, which requires …/a v0.3.0. + +-- go.mod -- +module example + +go 1.16 + +require ( + example.net/a v0.1.0 + example.net/b v0.1.0 // indirect +) + +replace ( + example.net/a v0.1.0 => ./a + example.net/a v0.2.0 => ./a + example.net/a v0.3.0 => ./a + example.net/b v0.1.0 => ./b10 + example.net/b v0.1.1 => ./b11 + example.net/b v0.1.2 => ./b12 +) +-- example.go -- +package example + +import _ "example.net/a" + +-- a/go.mod -- +module example.net/a + +go 1.16 + +require example.net/b v0.1.0 +-- a/a.go -- +package a + +import _ "example.net/b" + +-- b10/go.mod -- +module example.net/b + +go 1.16 + +require example.net/a v0.1.0 +-- b10/b.go -- +package b +-- b10/b_test.go -- +package b_test + +import _ "example.net/a" + +-- b11/go.mod -- +module example.net/b + +go 1.16 + +require example.net/a v0.2.0 +-- b11/b.go -- +package b +-- b11/b_test.go -- +package b_test + +import _ "example.net/a" + +-- b12/go.mod -- +module example.net/b + +go 1.16 + +require example.net/a v0.3.0 +-- b12/b.go -- +package b +-- b12/b_test.go -- +package b_test + +import _ "example.net/a" diff --git a/src/cmd/go/testdata/script/mod_get_patchcycle.txt b/src/cmd/go/testdata/script/mod_get_patchcycle.txt new file mode 100644 index 0000000..9f180d6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_patchcycle.txt @@ -0,0 +1,64 @@ +# If a patch of a module requires a higher version of itself, +# it should be reported as its own conflict. +# +# This case is weird and unlikely to occur often at all, but it should not +# spuriously succeed. +# (It used to print v0.1.1 but then silently upgrade to v0.2.0.) + +! go get example.net/a@patch +stderr '^go: example.net/a@patch \(v0.1.1\) indirectly requires example.net/a@v0.2.0, not example.net/a@patch \(v0.1.1\)$' # TODO: A mention of b v0.1.0 would be nice. + +-- go.mod -- +module example + +go 1.16 + +require example.net/a v0.1.0 + +replace ( + example.net/a v0.1.0 => ./a10 + example.net/a v0.1.1 => ./a11 + example.net/a v0.2.0 => ./a20 + example.net/b v0.1.0 => ./b10 +) +-- example.go -- +package example + +import _ "example.net/a" + +-- a10/go.mod -- +module example.net/a + +go 1.16 +-- a10/a.go -- +package a + +-- a11/go.mod -- +module example.net/a + +go 1.16 + +require example.net/b v0.1.0 +-- a11/a.go -- +package a + +import _ "example.net/b" + +-- a20/go.mod -- +module example.net/a + +go 1.16 +-- a20/a.go -- +package a + + +-- b10/go.mod -- +module example.net/b + +go 1.16 + +require example.net/a v0.2.0 +-- b10/b.go -- +package b + +import _ "example.net/a" diff --git a/src/cmd/go/testdata/script/mod_get_patchmod.txt b/src/cmd/go/testdata/script/mod_get_patchmod.txt new file mode 100644 index 0000000..2827731 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_patchmod.txt @@ -0,0 +1,82 @@ +# example.net/pkgremoved@v0.1.0 refers to a package. +go get example.net/pkgremoved@v0.1.0 + +go list example.net/pkgremoved +stdout '^example.net/pkgremoved' + +cp go.mod go.mod.orig + + +# When we resolve a new dependency on example.net/other, +# it will change the meaning of the path "example.net/pkgremoved" +# from a package (at v0.1.0) to only a module (at v0.2.0). +# +# If we simultaneously 'get' that module at the query "patch", the module should +# be constrained to the latest patch of its originally-selected version (v0.1.0), +# not upgraded to the latest patch of the new transitive dependency. + +! go get example.net/pkgremoved@patch example.net/other@v0.1.0 +stderr '^go: example.net/other@v0.1.0 requires example.net/pkgremoved@v0.2.0, not example.net/pkgremoved@patch \(v0.1.1\)$' +cmp go.mod.orig go.mod + + +# However, we should be able to patch from a package to a module and vice-versa. + +# Package to module ... + +go get example.net/pkgremoved@v0.3.0 +go list example.net/pkgremoved +stdout 'example.net/pkgremoved' + +go get example.net/pkgremoved@patch +! go list example.net/pkgremoved + +# ... and module to package. + +go get example.net/pkgremoved@v0.4.0 +! go list example.net/pkgremoved + +go get example.net/pkgremoved@patch +go list example.net/pkgremoved +stdout 'example.net/pkgremoved' + + +-- go.mod -- +module example + +go 1.16 + +replace ( + example.net/other v0.1.0 => ./other + + example.net/pkgremoved v0.1.0 => ./prpkg + example.net/pkgremoved v0.1.1 => ./prpkg + + example.net/pkgremoved v0.2.0 => ./prmod + example.net/pkgremoved v0.2.1 => ./prmod + + example.net/pkgremoved v0.3.0 => ./prpkg + example.net/pkgremoved v0.3.1 => ./prmod + + example.net/pkgremoved v0.4.0 => ./prmod + example.net/pkgremoved v0.4.1 => ./prpkg +) +-- other/go.mod -- +module example.net/other + +go 1.16 + +require example.net/pkgremoved v0.2.0 +-- other/other.go -- +package other +-- prpkg/go.mod -- +module example.net/pkgremoved + +go 1.16 +-- prpkg/pkgremoved.go -- +package pkgremoved +-- prmod/go.mod -- +module example.net/pkgremoved +-- prmod/README.txt -- +Package pkgremoved was removed in v0.2.0 and v0.3.1, +and added in v0.1.0 and v0.4.1. diff --git a/src/cmd/go/testdata/script/mod_get_patterns.txt b/src/cmd/go/testdata/script/mod_get_patterns.txt new file mode 100644 index 0000000..891353f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_patterns.txt @@ -0,0 +1,42 @@ +env GO111MODULE=on +[short] skip + +# If a pattern doesn't match any packages provided by modules +# in the build list, we assume the pattern matches a single module +# whose path is a prefix of the part of the pattern before "...". +cp go.mod.orig go.mod +go get rsc.io/quote/... +grep 'require rsc.io/quote' go.mod + +cp go.mod.orig go.mod +! go get rsc.io/quote/x... +stderr 'go: module rsc.io/quote@upgrade found \(v1.5.2\), but does not contain packages matching rsc.io/quote/x...' +! grep 'require rsc.io/quote' go.mod + +! go get rsc.io/quote/x/... +stderr 'go: module rsc.io/quote@upgrade found \(v1.5.2\), but does not contain packages matching rsc.io/quote/x/...' +! grep 'require rsc.io/quote' go.mod + +# If a pattern matches no packages within a module, the module should not +# be upgraded, even if the module path is a prefix of the pattern. +cp go.mod.orig go.mod +go mod edit -require example.com/nest@v1.0.0 +go get example.com/nest/sub/y... +grep 'example.com/nest/sub v1.0.0' go.mod +grep 'example.com/nest v1.0.0' go.mod + +# However, if the pattern matches the module path itself, the module +# should be upgraded even if it contains no matching packages. +go get example.com/n...t +grep 'example.com/nest v1.1.0' go.mod +grep 'example.com/nest/sub v1.0.0' go.mod + +-- go.mod.orig -- +module m + +go 1.13 + +-- use/use.go -- +package use + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_get_pkgtags.txt b/src/cmd/go/testdata/script/mod_get_pkgtags.txt new file mode 100644 index 0000000..8cb41ad --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_pkgtags.txt @@ -0,0 +1,130 @@ +# https://golang.org/issue/44106 +# 'go get' should fetch the transitive dependencies of packages regardless of +# tags, but shouldn't error out if the package is missing tag-guarded +# dependencies. + +# Control case: just adding the top-level module to the go.mod file does not +# fetch its dependencies. + +go mod edit -require example.net/tools@v0.1.0 +! go list -deps example.net/cmd/tool +stderr '^module example\.net/cmd provides package example\.net/cmd/tool and is replaced but not required; to add it:\n\tgo get example\.net/cmd@v0\.1\.0$' +go mod edit -droprequire example.net/tools + + +# 'go get' makes a best effort to fetch those dependencies, but shouldn't +# error out if dependencies of tag-guarded files are missing. + +go get example.net/tools@v0.1.0 +! stderr 'no Go source files' + +! go list example.net/tools +stderr '^package example.net/tools: build constraints exclude all Go files in .*[/\\]tools$' + +go list -tags=tools -e -deps example.net/tools +stdout '^example.net/cmd/tool$' +stdout '^example.net/missing$' + +go list -deps example.net/cmd/tool + +! go list example.net/missing +stderr '^no required module provides package example.net/missing; to add it:\n\tgo get example.net/missing$' + + +# https://golang.org/issue/33526: 'go get' without '-d' should succeed +# for a module whose root is a constrained-out package. +# +# Ideally it should silently succeed, but today it logs the "no Go source files" +# error and succeeds anyway. + +go get example.net/tools@v0.1.0 +! stderr . + +! go build example.net/tools +stderr '^package example.net/tools: build constraints exclude all Go files in .*[/\\]tools$' + + +# https://golang.org/issue/29268 +# 'go get' should fetch modules whose roots contain test-only packages, but +# without the -t flag shouldn't error out if the test has missing dependencies. + +go get example.net/testonly@v0.1.0 + +# With the -t flag, the test dependencies must resolve successfully. +! go get -t example.net/testonly@v0.1.0 +stderr '^go: example.net/testonly tested by\n\texample.net/testonly\.test imports\n\texample.net/missing: cannot find module providing package example.net/missing$' + + +# 'go get' should succeed for a module path that does not contain a package, +# but fail for a non-package subdirectory of a module. + +! go get example.net/missing/subdir@v0.1.0 +stderr '^go: module example.net/missing@v0.1.0 found \(replaced by ./missing\), but does not contain package example.net/missing/subdir$' + +go get example.net/missing@v0.1.0 + + +# Getting the subdirectory should continue to fail even if the corresponding +# module is already present in the build list. + +! go get example.net/missing/subdir@v0.1.0 +stderr '^go: module example.net/missing@v0.1.0 found \(replaced by ./missing\), but does not contain package example.net/missing/subdir$' + + +-- go.mod -- +module example.net/m + +go 1.15 + +replace ( + example.net/tools v0.1.0 => ./tools + example.net/cmd v0.1.0 => ./cmd + example.net/testonly v0.1.0 => ./testonly + example.net/missing v0.1.0 => ./missing +) + +-- tools/go.mod -- +module example.net/tools + +go 1.15 + +// Requirements intentionally omitted. + +-- tools/tools.go -- +// +build tools + +package tools + +import ( + _ "example.net/cmd/tool" + _ "example.net/missing" +) + +-- cmd/go.mod -- +module example.net/cmd + +go 1.16 +-- cmd/tool/tool.go -- +package main + +func main() {} + +-- testonly/go.mod -- +module example.net/testonly + +go 1.15 +-- testonly/testonly_test.go -- +package testonly_test + +import _ "example.net/missing" + +func Test(t *testing.T) {} + +-- missing/go.mod -- +module example.net/missing + +go 1.15 +-- missing/README.txt -- +There are no Go source files here. +-- missing/subdir/README.txt -- +There are no Go source files here either. diff --git a/src/cmd/go/testdata/script/mod_get_prefer_incompatible.txt b/src/cmd/go/testdata/script/mod_get_prefer_incompatible.txt new file mode 100644 index 0000000..06e2fc6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_prefer_incompatible.txt @@ -0,0 +1,29 @@ +# Verifies golang.org/issue/37574. + +# If we are already using an +incompatible version, we shouldn't look up +# a lower compatible version when upgrading. +cp go.mod go.mod.orig +go mod tidy +cmp go.mod.orig go.mod +grep '^example.com/incompatiblewithsub v2\.0\.0\+incompatible' go.sum +! grep '^example.com/incompatiblewithsub v1.0.0' go.sum + +go get example.com/incompatiblewithsub/sub +cmp go.mod.orig go.mod +! grep '^example.com/incompatiblewithsub v1.0.0' go.sum + +# TODO(golang.org/issue/31580): the 'go get' command above should not change +# go.sum. However, as part of the query above, we download example.com@v1.0.0, +# an unrelated module, since it's a possible prefix. The sum for that module +# should not be written to go.sum. + +-- go.mod -- +module m + +go 1.15 + +require example.com/incompatiblewithsub v2.0.0+incompatible +-- use.go -- +package use + +import _ "example.com/incompatiblewithsub/sub" diff --git a/src/cmd/go/testdata/script/mod_get_promote_implicit.txt b/src/cmd/go/testdata/script/mod_get_promote_implicit.txt new file mode 100644 index 0000000..03f6810 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_promote_implicit.txt @@ -0,0 +1,92 @@ +cp go.mod.orig go.mod + +# If we list a package in an implicit dependency imported from the main module, +# we should get an error because the dependency should have an explicit +# requirement. +go list -m indirect-with-pkg +stdout '^indirect-with-pkg v1.0.0 => ./indirect-with-pkg$' +! go list ./use-indirect +stderr '^package m/use-indirect imports indirect-with-pkg from implicitly required module; to add missing requirements, run:\n\tgo get indirect-with-pkg@v1.0.0$' + +# We can promote the implicit requirement by getting the importing package. +# NOTE: the hint recommends getting the imported package (tested below) since +# it's more obvious and doesn't require -d. However, that adds an '// indirect' +# comment on the requirement. +go get m/use-indirect +cmp go.mod go.mod.use +cp go.mod.orig go.mod + +# We can also promote implicit requirements using 'go get' on them, or their +# packages. This gives us "// indirect" requirements, since 'go get' doesn't +# know they're needed by the main module. See #43131 for the rationale. +# The hint above recommends this because it's more obvious usage and doesn't +# require the -d flag. +go get indirect-with-pkg indirect-without-pkg +cmp go.mod go.mod.indirect + +-- go.mod.orig -- +module m + +go 1.16 + +require direct v1.0.0 + +replace ( + direct v1.0.0 => ./direct + indirect-with-pkg v1.0.0 => ./indirect-with-pkg + indirect-without-pkg v1.0.0 => ./indirect-without-pkg +) +-- go.mod.use -- +module m + +go 1.16 + +require ( + direct v1.0.0 + indirect-with-pkg v1.0.0 +) + +replace ( + direct v1.0.0 => ./direct + indirect-with-pkg v1.0.0 => ./indirect-with-pkg + indirect-without-pkg v1.0.0 => ./indirect-without-pkg +) +-- go.mod.indirect -- +module m + +go 1.16 + +require ( + direct v1.0.0 + indirect-with-pkg v1.0.0 // indirect + indirect-without-pkg v1.0.0 // indirect +) + +replace ( + direct v1.0.0 => ./direct + indirect-with-pkg v1.0.0 => ./indirect-with-pkg + indirect-without-pkg v1.0.0 => ./indirect-without-pkg +) +-- use-indirect/use-indirect.go -- +package use + +import _ "indirect-with-pkg" +-- direct/go.mod -- +module direct + +go 1.16 + +require ( + indirect-with-pkg v1.0.0 + indirect-without-pkg v1.0.0 +) +-- indirect-with-pkg/go.mod -- +module indirect-with-pkg + +go 1.16 +-- indirect-with-pkg/p.go -- +package p +-- indirect-without-pkg/go.mod -- +module indirect-without-pkg + +go 1.16 diff --git a/src/cmd/go/testdata/script/mod_get_pseudo.txt b/src/cmd/go/testdata/script/mod_get_pseudo.txt new file mode 100644 index 0000000..47ad54e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_pseudo.txt @@ -0,0 +1,82 @@ +env GO111MODULE=on + +# Testing git->module converter's generation of +incompatible tags; turn off proxy. +[!net:github.com] skip +[!git] skip +env GOPROXY=direct +env GOSUMDB=off + +# We can resolve the @master branch without unshallowing the local repository +# (even with older gits), so try that before we do anything else. +# (This replicates https://golang.org/issue/26713 with git 2.7.4.) +go get github.com/rsc/legacytest@master +go list -m all +stdout '^github.com/rsc/legacytest v2\.0\.1-0\.\d{14}-7303f7796364\+incompatible$' + +# get should include incompatible tags in "latest" calculation. +go mod edit -droprequire github.com/rsc/legacytest +go get github.com/rsc/legacytest@latest +go list +go list -m all +stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$' + +# v2.0.1-0.pseudo+incompatible +go get ...test@7303f77 +go list -m all +stdout '^github.com/rsc/legacytest v2\.0\.1-0\.\d{14}-7303f7796364\+incompatible$' + +# v2.0.0+incompatible by tag+incompatible +go get ...test@v2.0.0+incompatible +go list -m all +stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$' + +# v2.0.0+incompatible by tag +go get ...test@v2.0.0 +go list -m all +stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$' + +# v2.0.0+incompatible by hash (back on master) +go get ...test@d7ae1e4 +go list -m all +stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$' + +# v1.2.1-0.pseudo +go get ...test@d2d4c3e +go list -m all +stdout '^github.com/rsc/legacytest v1\.2\.1-0\.\d{14}-d2d4c3ea6623$' + +# v1.2.0 +go get ...test@9f6f860 +go list -m all +stdout '^github.com/rsc/legacytest v1\.2\.0$' + +# v1.1.0-pre.0.pseudo +go get ...test@fb3c628 +go list -m all +stdout '^github.com/rsc/legacytest v1\.1\.0-pre\.0\.\d{14}-fb3c628075e3$' + +# v1.1.0-pre (no longer on master) +go get ...test@731e3b1 +go list -m all +stdout '^github.com/rsc/legacytest v1\.1\.0-pre$' + +# v1.0.1-0.pseudo +go get ...test@fa4f5d6 +go list -m all +stdout '^github.com/rsc/legacytest v1\.0\.1-0\.\d{14}-fa4f5d6a71c6$' + +# v1.0.0 +go get ...test@7fff7f3 +go list -m all +stdout '^github.com/rsc/legacytest v1\.0\.0$' + +# v0.0.0-pseudo +go get ...test@52853eb +go list -m all +stdout '^github.com/rsc/legacytest v0\.0\.0-\d{14}-52853eb7b552$' + +-- go.mod -- +module x +-- x.go -- +package x +import "github.com/rsc/legacytest" diff --git a/src/cmd/go/testdata/script/mod_get_pseudo_other_branch.txt b/src/cmd/go/testdata/script/mod_get_pseudo_other_branch.txt new file mode 100644 index 0000000..6019b45 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_pseudo_other_branch.txt @@ -0,0 +1,67 @@ +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +# Testing that a pseudo-version is based on the semantically-latest +# tag that appears in any commit that is a (transitive) parent of the commit +# supplied to 'go get', regardless of branches + +[short] skip +[!git] skip + +# For this test repository: +# tag v0.2.1 is most recent tag on master itself +# tag v0.2.2 is on branch2, which was then merged to master +# master is a merge commit with both tags as parents +# +# The pseudo-version hence sorts immediately after v0.2.2 rather +# than v0.2.1, even though the v0.2.2 tag is not on master. + +go get vcs-test.golang.org/git/tagtests.git@master +go list -m all +stdout '^vcs-test.golang.org/git/tagtests.git v0.2.3-0\.' + +-- go.mod -- +module x + +go 1.12 +-- x.go -- +package x + +import _ "vcs-test.golang.org/git/tagtests.git" +-- gen_testtags.sh -- +#!/bin/bash + +# This is not part of the test. +# Run this to generate and update the repository on vcs-test.golang.org. + +set -euo pipefail +cd "$(dirname "$0")" +rm -rf tagtests +mkdir tagtests +cd tagtests + +git init +echo module vcs-test.golang.org/git/tagtests.git >go.mod +echo package tagtests >tagtests.go +git add go.mod tagtests.go +git commit -m 'create module tagtests' + +git branch b + +echo v0.2.1 >v0.2.1 +git add v0.2.1 +git commit -m v0.2.1 +git tag v0.2.1 + +git checkout b +echo v0.2.2 >v0.2.2 +git add v0.2.2 +git commit -m v0.2.2 +git tag v0.2.2 + +git checkout master +git merge b -m merge + +zip -r ../tagtests.zip . +gsutil cp ../tagtests.zip gs://vcs-test/git/tagtests.zip diff --git a/src/cmd/go/testdata/script/mod_get_pseudo_prefix.txt b/src/cmd/go/testdata/script/mod_get_pseudo_prefix.txt new file mode 100644 index 0000000..ac3233e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_pseudo_prefix.txt @@ -0,0 +1,64 @@ +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +# Testing that a pseudo-version is based on the semantically-latest +# prefixed tag in any commit that is a parent of the commit supplied +# to 'go get', when using a repo with go.mod in a sub directory. + +[short] skip +[!git] skip + +# For this test repository go.mod resides in sub/ (only): +# master is not tagged +# tag v0.2.0 is most recent tag before master +# tag sub/v0.0.10 is most recent tag before v0.2.0 +# +# The pseudo-version is based on sub/v0.0.10, since v0.2.0 doesn't +# contain the prefix. +go get vcs-test.golang.org/git/prefixtagtests.git/sub +go list -m all +stdout '^vcs-test.golang.org/git/prefixtagtests.git/sub v0.0.10$' + +go get -u vcs-test.golang.org/git/prefixtagtests.git/sub@master +go list -m all +stdout '^vcs-test.golang.org/git/prefixtagtests.git/sub v0.0.11-0\.' + +-- go.mod -- +module x + +go 1.12 +-- x.go -- +package x + +import _ "vcs-test.golang.org/prefixtagtests.git/sub" +-- gen_prefixtagtests.sh -- +#!/bin/bash + +# This is not part of the test. +# Run this to generate and update the repository on vcs-test.golang.org. + +set -euo pipefail +cd "$(dirname "$0")" +rm -rf prefixtagtests +mkdir prefixtagtests +cd prefixtagtests + +git init +mkdir sub +echo module vcs-test.golang.org/git/prefixtagtests.git/sub >sub/go.mod +echo package sub >sub/sub.go +git add sub +git commit -m 'create module sub' +for i in v0.1.0 sub/v0.0.9 sub/v0.0.10 v0.2.0; do + echo $i >status + git add status + git commit -m $i + git tag $i +done +echo 'after last tag' >status +git add status +git commit -m 'after last tag' + +zip -r ../prefixtagtests.zip . +gsutil cp ../prefixtagtests.zip gs://vcs-test/git/prefixtagtests.zip diff --git a/src/cmd/go/testdata/script/mod_get_replaced.txt b/src/cmd/go/testdata/script/mod_get_replaced.txt new file mode 100644 index 0000000..c31d5be --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_replaced.txt @@ -0,0 +1,111 @@ +cp go.mod go.mod.orig + +env oldGOPROXY=$GOPROXY + +# If a wildcard replacement exists for an otherwise-nonexistent module, +# 'go get' should resolve it to the minimum valid pseudo-version. + +go mod edit -replace=example.com/x=./x +go get example.com/x + +go list -m example.com/x +stdout '^example.com/x v0.0.0-00010101000000-000000000000 ' + +# If specific-version replacements exist, the highest matching version should be used. +go mod edit -replace=example.com/x@v0.1.0=./x +go mod edit -replace=example.com/x@v0.2.0=./x + +go get example.com/x +go list -m example.com/x +stdout '^example.com/x v0.2.0 ' + +go get example.com/x@<v0.2.0 +go list -m example.com/x +stdout '^example.com/x v0.1.0 ' + + +# The same should work with GOPROXY=off. + +env GOPROXY=off +cp go.mod.orig go.mod + +go mod edit -replace=example.com/x=./x +go get example.com/x + +go list -m example.com/x +stdout '^example.com/x v0.0.0-00010101000000-000000000000 ' + +# If specific-version replacements exist, the highest matching version should be used. +go mod edit -replace=example.com/x@v0.1.0=./x +go mod edit -replace=example.com/x@v0.2.0=./x + +go get example.com/x +go list -m example.com/x +stdout '^example.com/x v0.2.0 ' + +go get example.com/x@<v0.2.0 +go list -m example.com/x +stdout '^example.com/x v0.1.0 ' + + +# Replacements should also be listed as known versions, and 'go get' should sort +# them in with ordinary versions. + +env GOPROXY=$oldGOPROXY + +cp go.mod.orig go.mod +go list -versions -m rsc.io/quote +stdout 'v1.3.0 v1.4.0' + +go get rsc.io/quote@v1.3 +go list -m rsc.io/quote +stdout '^rsc.io/quote v1.3.0' + +go mod edit -replace rsc.io/quote@v1.3.1=rsc.io/quote@v1.4.0 + +go list -versions -m rsc.io/quote +stdout 'v1.3.0 v1.3.1 v1.4.0' + +go get rsc.io/quote@v1.3 +go list -m rsc.io/quote +stdout '^rsc.io/quote v1.3.1 ' + +go get rsc.io/quote@>v1.3.1 +go list -m rsc.io/quote +stdout '^rsc.io/quote v1.4.0' + + +# Replacements should allow 'go get' to work even with dotless module paths. + +cp go.mod.orig go.mod + +! go list example +stderr '^package example is not in std \(.*\)$' +! go get example +stderr '^go: malformed module path "example": missing dot in first path element$' + +go mod edit -replace example@v0.1.0=./example + +! go list example +stderr '^module example provides package example and is replaced but not required; to add it:\n\tgo get example@v0.1.0$' + +go get example +go list -m example +stdout '^example v0.1.0 ' + + +-- go.mod -- +module example.com + +go 1.16 +-- x/go.mod -- +module example.com/x + +go 1.16 +-- x/x.go -- +package x +-- example/go.mod -- +module example +go 1.16 +-- example/example.go -- +package example diff --git a/src/cmd/go/testdata/script/mod_get_retract.txt b/src/cmd/go/testdata/script/mod_get_retract.txt new file mode 100644 index 0000000..9757989 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_retract.txt @@ -0,0 +1,59 @@ +# 'go get pkg' should not upgrade to a retracted version. +cp go.mod.orig go.mod +go mod edit -require example.com/retract/self/prev@v1.1.0 +go get example.com/retract/self/prev +go list -m example.com/retract/self/prev +stdout '^example.com/retract/self/prev v1.1.0$' + +# 'go get pkg' should not downgrade from a retracted version when no higher +# version is available. +cp go.mod.orig go.mod +go mod edit -require example.com/retract/self/prev@v1.9.0 +go get example.com/retract/self/prev +stderr '^go: warning: example.com/retract/self/prev@v1.9.0: retracted by module author: self$' +stderr '^go: to switch to the latest unretracted version, run:\n\tgo get example.com/retract/self/prev@latest\n$' +go list -m example.com/retract/self/prev +stdout '^example.com/retract/self/prev v1.9.0$' + +# 'go get pkg@latest' should downgrade from a retracted version. +cp go.mod.orig go.mod +go mod edit -require example.com/retract/self/prev@v1.9.0 +go get example.com/retract/self/prev@latest +go list -m example.com/retract/self/prev +stdout '^example.com/retract/self/prev v1.1.0$' + +# 'go get pkg@version' should update to a specific version, even if that +# version is retracted. +cp go.mod.orig go.mod +go get example.com/retract@v1.0.0-bad +stderr '^go: warning: example.com/retract@v1.0.0-bad: retracted by module author: bad$' +go list -m example.com/retract +stdout '^example.com/retract v1.0.0-bad$' + +# 'go get -u' should not downgrade from a retracted version when no higher +# version is available. +cp go.mod.orig go.mod +go mod edit -require example.com/retract/self/prev@v1.9.0 +go get -u ./use +stderr '^go: warning: example.com/retract/self/prev@v1.9.0: retracted by module author: self$' +go list -m example.com/retract/self/prev +stdout '^example.com/retract/self/prev v1.9.0$' + +# 'go get' should warn if a module needed to build named packages is retracted. +# 'go get' should not warn about unrelated modules. +go get ./empty +! stderr retracted +go get ./use +stderr '^go: warning: example.com/retract/self/prev@v1.9.0: retracted by module author: self$' + +-- go.mod.orig -- +module example.com/use + +go 1.15 + +-- use/use.go -- +package use + +import _ "example.com/retract/self/prev" +-- empty/empty.go -- +package empty diff --git a/src/cmd/go/testdata/script/mod_get_retract_ambiguous.txt b/src/cmd/go/testdata/script/mod_get_retract_ambiguous.txt new file mode 100644 index 0000000..4b4f5da --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_retract_ambiguous.txt @@ -0,0 +1,10 @@ +! go get example.com/retract/ambiguous/other +stderr 'ambiguous import: found package example.com/retract/ambiguous/nested in multiple modules:' +stderr '^go: warning: example.com/retract/ambiguous/nested@v1.9.0-bad: retracted by module author: nested modules are bad$' + +-- go.mod -- +module example.com/use + +go 1.16 + +require example.com/retract/ambiguous/nested v1.9.0-bad diff --git a/src/cmd/go/testdata/script/mod_get_split.txt b/src/cmd/go/testdata/script/mod_get_split.txt new file mode 100644 index 0000000..6c2f00d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_split.txt @@ -0,0 +1,157 @@ +cp go.mod go.mod.orig + + +# 'go get' on a package already provided by the build list should update +# the module already in the build list, not fail with an ambiguous import error. + +go get example.net/split/nested@patch +go list -m all +stdout '^example.net/split v0.2.1 ' +! stdout '^example.net/split/nested' + +# We should get the same behavior if we use a pattern that matches only that package. + +cp go.mod.orig go.mod + +go get example.net/split/nested/...@patch +go list -m all +stdout '^example.net/split v0.2.1 ' +! stdout '^example.net/split/nested' + + +# If we request a version for which the package only exists in one particular module, +# we should add that one particular module but not resolve import ambiguities. +# +# In particular, if the module that previously provided the package has a +# matching version, but does not itself match the pattern and contains no +# matching packages, we should not change its version. (We should *not* downgrade +# module example.net/split to v0.1.0, despite the fact that +# example.net/split v0.2.0 currently provides the package with the requested path.) +# +# TODO(#27899): Maybe we should resolve the ambiguities by upgrading. + +cp go.mod.orig go.mod + +! go get example.net/split/nested@v0.1.0 +stderr '^go: example.net/split/nested: ambiguous import: found package example.net/split/nested in multiple modules:\n\texample.net/split v0.2.0 \(.*split.2[/\\]nested\)\n\texample.net/split/nested v0.1.0 \(.*nested.1\)$' + +# A wildcard that matches packages in some module at its selected version +# but not at the requested version should fail. +# +# We can't set the module to the selected version, because that version doesn't +# even match the query: if we ran the same query twice, we wouldn't consider the +# module to match the wildcard during the second call, so why should we consider +# it to match during the first one? ('go get' should be idempotent, and if we +# did that then it would not be.) +# +# But we also can't leave it where it is: the user requested that we set everything +# matching the pattern to the given version, and right now we have packages +# that match the pattern but *not* the version. +# +# That only leaves two options: we can set the module to an arbitrary version +# (perhaps 'latest' or 'none'), or we can report an error and the let the user +# disambiguate. We would rather not choose arbitrarily, so we do the latter. +# +# TODO(#27899): Should we instead upgrade or downgrade to an arbitrary version? + +! go get example.net/split/nested/...@v0.1.0 +stderr '^go: example.net/split/nested/\.\.\.@v0.1.0 matches packages in example.net/split@v0.2.0 but not example.net/split@v0.1.0: specify a different version for module example.net/split$' + +cmp go.mod go.mod.orig + + +# If another argument resolves the ambiguity, we should be ok again. + +go get example.net/split@none example.net/split/nested@v0.1.0 +go list -m all +! stdout '^example.net/split ' +stdout '^example.net/split/nested v0.1.0 ' + +cp go.mod.orig go.mod + +go get example.net/split@v0.3.0 example.net/split/nested@v0.1.0 +go list -m all +stdout '^example.net/split v0.3.0 ' +stdout '^example.net/split/nested v0.1.0 ' + + +# If a pattern applies to modules and to packages, we should set all matching +# modules to the version indicated by the pattern, and also resolve packages +# to match the pattern if possible. + +cp go.mod.orig go.mod +go get example.net/split/nested@v0.0.0 + +go get example.net/...@v0.1.0 +go list -m all +stdout '^example.net/split v0.1.0 ' +stdout '^example.net/split/nested v0.1.0 ' + +go get example.net/... +go list -m all +stdout '^example.net/split v0.3.0 ' +stdout '^example.net/split/nested v0.2.0 ' + + +# @none applies to all matching module paths, +# regardless of whether they contain any packages. + +go get example.net/...@none +go list -m all +! stdout '^example.net' + +# Starting from no dependencies, a wildcard can resolve to an empty module with +# the same prefix even if it contains no packages. + +go get example.net/...@none +go get example.net/split/...@v0.1.0 +go list -m all +stdout '^example.net/split v0.1.0 ' + + +-- go.mod -- +module m + +go 1.16 + +require example.net/split v0.2.0 + +replace ( + example.net/split v0.1.0 => ./split.1 + example.net/split v0.2.0 => ./split.2 + example.net/split v0.2.1 => ./split.2 + example.net/split v0.3.0 => ./split.3 + example.net/split/nested v0.0.0 => ./nested.0 + example.net/split/nested v0.1.0 => ./nested.1 + example.net/split/nested v0.2.0 => ./nested.2 +) +-- split.1/go.mod -- +module example.net/split + +go 1.16 +-- split.2/go.mod -- +module example.net/split + +go 1.16 +-- split.2/nested/nested.go -- +package nested +-- split.3/go.mod -- +module example.net/split + +go 1.16 +-- nested.0/go.mod -- +module example.net/split/nested + +go 1.16 +-- nested.1/go.mod -- +module example.net/split/nested + +go 1.16 +-- nested.1/nested.go -- +package nested +-- nested.2/go.mod -- +module example.net/split/nested + +go 1.16 +-- nested.2/nested.go -- +package nested diff --git a/src/cmd/go/testdata/script/mod_get_sum_noroot.txt b/src/cmd/go/testdata/script/mod_get_sum_noroot.txt new file mode 100644 index 0000000..0d9a840 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_sum_noroot.txt @@ -0,0 +1,11 @@ +# When 'go get' is invoked on a module without a package in the root directory, +# it should add sums for the module's go.mod file and its content to go.sum. +# Verifies golang.org/issue/41103. +go mod init m +go get rsc.io/QUOTE +grep '^rsc.io/QUOTE v1.5.2/go.mod ' go.sum +grep '^rsc.io/QUOTE v1.5.2 ' go.sum + +# Double-check rsc.io/QUOTE does not have a root package. +! go list -mod=readonly rsc.io/QUOTE +stderr '^cannot find module providing package rsc.io/QUOTE: import lookup disabled by -mod=readonly$' diff --git a/src/cmd/go/testdata/script/mod_get_tags.txt b/src/cmd/go/testdata/script/mod_get_tags.txt new file mode 100644 index 0000000..e4fb6c4 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_tags.txt @@ -0,0 +1,34 @@ +env GO111MODULE=on + +# get should add modules needed to build packages, even if those +# dependencies are in sources excluded by build tags. +# All build tags are considered true except "ignore". +go mod init m +go get . +go list -m all +stdout 'example.com/version v1.1.0' +stdout 'rsc.io/quote v1.5.2' + +-- empty.go -- +package m + +-- excluded.go -- +// +build windows,mips + +package m + +import _ "example.com/version" + +-- tools.go -- +// +build tools + +package tools + +import _ "rsc.io/quote" + +-- ignore.go -- +// +build ignore + +package ignore + +import _ "example.com/doesnotexist" diff --git a/src/cmd/go/testdata/script/mod_get_test.txt b/src/cmd/go/testdata/script/mod_get_test.txt new file mode 100644 index 0000000..0fa7cd9 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_test.txt @@ -0,0 +1,58 @@ +env GO111MODULE=on + +# By default, 'go get' should ignore tests +cp go.mod.empty go.mod +go get m/a +! grep rsc.io/quote go.mod + +# 'go get -t' should consider test dependencies of the named package. +cp go.mod.empty go.mod +go get -t m/a +grep 'rsc.io/quote v1.5.2$' go.mod + +# 'go get -t' should not consider test dependencies of imported packages, +# including packages imported from tests. +cp go.mod.empty go.mod +go get -t m/b +! grep rsc.io/quote go.mod + +# 'go get -t -u' should update test dependencies of the named package. +cp go.mod.empty go.mod +go mod edit -require=rsc.io/quote@v1.5.1 +go get -t -u m/a +grep 'rsc.io/quote v1.5.2$' go.mod + +# 'go get -t -u' should not add or update test dependencies +# of imported packages, including packages imported from tests. +cp go.mod.empty go.mod +go get -t -u m/b +! grep rsc.io/quote go.mod +go mod edit -require=rsc.io/quote@v1.5.1 +go get -t -u m/b +grep 'rsc.io/quote v1.5.1$' go.mod + +# 'go get all' should consider test dependencies with or without -t. +cp go.mod.empty go.mod +go get all +grep 'rsc.io/quote v1.5.2$' go.mod + +-- go.mod.empty -- +module m + +-- a/a.go -- +package a + +-- a/a_test.go -- +package a_test + +import _ "rsc.io/quote" + +-- b/b.go -- +package b + +import _ "m/a" + +-- b/b_test.go -- +package b_test + +import _ "m/a" diff --git a/src/cmd/go/testdata/script/mod_get_toolchain.txt b/src/cmd/go/testdata/script/mod_get_toolchain.txt new file mode 100644 index 0000000..758142d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_toolchain.txt @@ -0,0 +1,129 @@ +# setup +env TESTGO_VERSION=go1.99rc1 +env TESTGO_VERSION_SWITCH=switch + +# go get go should use the latest Go 1.23 +cp go.mod.orig go.mod +go get go +stderr '^go: upgraded go 1.21 => 1.23.9$' +grep 'go 1.23.9' go.mod +grep 'toolchain go1.99rc1' go.mod + +# go get go@1.23 should use the latest Go 1.23 +cp go.mod.orig go.mod +go get go@1.23 +stderr '^go: upgraded go 1.21 => 1.23.9$' +grep 'go 1.23.9' go.mod +grep 'toolchain go1.99rc1' go.mod + +# go get go@1.22 should use the latest Go 1.22 +cp go.mod.orig go.mod +go get go@1.22 +stderr '^go: upgraded go 1.21 => 1.22.9$' +grep 'go 1.22.9' go.mod +grep 'toolchain go1.99rc1' go.mod + +# go get go@patch should use the latest patch release +go get go@1.22.1 +go get go@patch +stderr '^go: upgraded go 1.22.1 => 1.22.9$' +grep 'go 1.22.9' go.mod +grep 'toolchain go1.99rc1' go.mod + +# go get go@1.24 does NOT find the release candidate +cp go.mod.orig go.mod +! go get go@1.24 +stderr '^go: go@1.24: no matching versions for query "1.24"$' + +# go get go@1.24rc1 works +cp go.mod.orig go.mod +go get go@1.24rc1 +stderr '^go: upgraded go 1.21 => 1.24rc1$' +grep 'go 1.24rc1' go.mod +grep 'toolchain go1.99rc1' go.mod + +# go get go@latest finds the latest Go 1.23 +cp go.mod.orig go.mod +go get go@latest +stderr '^go: upgraded go 1.21 => 1.23.9$' +grep 'go 1.23.9' go.mod +grep 'toolchain go1.99rc1' go.mod + +# Again, with toolchains. + +# go get toolchain should find go1.999testmod. +go get toolchain +stderr '^go: upgraded toolchain go1.99rc1 => go1.999testmod$' +grep 'go 1.23.9' go.mod +grep 'toolchain go1.999testmod' go.mod + +# go get toolchain@go1.23 should use the latest Go 1.23 +go get toolchain@go1.23 +stderr '^go: removed toolchain go1.999testmod$' +grep 'go 1.23.9' go.mod +! grep 'toolchain go1.23.9' go.mod # implied + +# go get toolchain@go1.22 should use the latest Go 1.22 and downgrade go. +go get toolchain@go1.22 +stderr '^go: downgraded go 1.23.9 => 1.22.9$' +grep 'go 1.22.9' go.mod +! grep 'toolchain go1.22.9' go.mod # implied + +# go get toolchain@patch should use the latest patch release +go get toolchain@go1.22.1 +go get toolchain@patch +stderr '^go: added toolchain go1.22.9$' +grep 'go 1.22.1' go.mod +grep 'toolchain go1.22.9' go.mod +go get go@1.22.9 toolchain@none +grep 'go 1.22.9' go.mod +! grep 'toolchain go1.22.9' go.mod + +# go get toolchain@go1.24 does NOT find the release candidate +! go get toolchain@go1.24 +stderr '^go: toolchain@go1.24: no matching versions for query "go1.24"$' + +# go get toolchain@go1.24rc1 works +go get toolchain@go1.24rc1 +stderr '^go: added toolchain go1.24rc1$' +grep 'go 1.22.9' go.mod # no longer implied +grep 'toolchain go1.24rc1' go.mod + +# go get toolchain@latest finds go1.999testmod. +cp go.mod.orig go.mod +go get toolchain@latest +stderr '^go: added toolchain go1.999testmod$' +grep 'go 1.21' go.mod +grep 'toolchain go1.999testmod' go.mod + +# Bug fixes. + +# go get go@garbage should fail but not crash +! go get go@garbage +! stderr panic +stderr '^go: invalid go version garbage$' + +# go get go@go1.21.0 is OK - we silently correct to 1.21.0 +go get go@1.19 +go get go@go1.21.0 +stderr '^go: upgraded go 1.19 => 1.21.0' + +# go get toolchain@1.24rc1 is OK too. +go get toolchain@1.24rc1 +stderr '^go: downgraded toolchain go1.999testmod => go1.24rc1$' + +# go get go@1.21 should work if we are the Go 1.21 language version, +# even though there's no toolchain for it. +# (Older versions resolve to the latest release in that version, so for example +# go get go@1.20 might resolve to 1.20.9, but if we're the devel copy of +# Go 1.21, there's no release yet to resolve to, so we resolve to ourselves.) +env TESTGO_VERSION=go1.21 +go get go@1.19 toolchain@none +go get go@1.21 +grep 'go 1.21$' go.mod +! grep toolchain go.mod + +-- go.mod.orig -- +module m + +go 1.21 diff --git a/src/cmd/go/testdata/script/mod_get_trailing_slash.txt b/src/cmd/go/testdata/script/mod_get_trailing_slash.txt new file mode 100644 index 0000000..7b46900 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_trailing_slash.txt @@ -0,0 +1,30 @@ +# go list should succeed to load a package ending with ".go" if the path does +# not correspond to an existing local file. Listing a pattern ending with +# ".go/" should try to list a package regardless of whether a file exists at the +# path without the suffixed "/" or not. +go list example.com/dotgo.go +stdout ^example.com/dotgo.go$ +go list example.com/dotgo.go/ +stdout ^example.com/dotgo.go$ + +# go get should succeed in either case, with or without a version. +# Arguments are interpreted as packages or package patterns with versions, +# not source files. +go get example.com/dotgo.go +go get example.com/dotgo.go/ +go get example.com/dotgo.go@v1.0.0 +go get example.com/dotgo.go/@v1.0.0 + +-- go.mod -- +module m + +go 1.13 + +require example.com/dotgo.go v1.0.0 +-- go.sum -- +example.com/dotgo.go v1.0.0 h1:XKJfs0V8x2PvY2tX8bJBCEbCDLnt15ma2onwhVpew/I= +example.com/dotgo.go v1.0.0/go.mod h1:Qi6z/X3AC5vHiuMt6HF2ICx3KhIBGrMdrA7YoPDKqR0= +-- use.go -- +package use + +import _ "example.com/dotgo.go" diff --git a/src/cmd/go/testdata/script/mod_get_update_unrelated_sum.txt b/src/cmd/go/testdata/script/mod_get_update_unrelated_sum.txt new file mode 100644 index 0000000..a5651e9 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_update_unrelated_sum.txt @@ -0,0 +1,120 @@ +# Check that 'go get' adds sums for updated modules if we had sums before, +# even if we didn't load packages from them. +# Verifies #44129. + +env fmt='{{.ImportPath}}: {{if .Error}}{{.Error.Err}}{{else}}ok{{end}}' + +# Control case: before upgrading, we have the sums we need. +# go list -deps -e -f $fmt . +# stdout '^rsc.io/quote: ok$' +# ! stdout rsc.io/sampler # not imported by quote in this version +cp go.mod.orig go.mod +cp go.sum.orig go.sum +go mod tidy +cmp go.mod.orig go.mod +cmp go.sum.orig go.sum + + +# Upgrade a module. This also upgrades rsc.io/quote, and though we didn't load +# a package from it, we had the sum for its old version, so we need the +# sum for the new version, too. +go get example.com/upgrade@v0.0.2 +grep '^rsc.io/quote v1.5.2 ' go.sum + +# The upgrade still breaks the build because the new version of quote imports +# rsc.io/sampler, and we don't have its zip sum. +go list -deps -e -f $fmt +stdout 'rsc.io/quote: ok' +stdout 'rsc.io/sampler: missing go.sum entry for module providing package rsc.io/sampler' +cp go.mod.orig go.mod +cp go.sum.orig go.sum + + +# Replace the old version with a directory before upgrading. +# We didn't need a sum for it before (even though we had one), so we won't +# fetch a new sum. +go mod edit -replace rsc.io/quote@v1.0.0=./dummy +go get example.com/upgrade@v0.0.2 +! grep '^rsc.io/quote v1.5.2 ' go.sum +cp go.mod.orig go.mod +cp go.sum.orig go.sum + + +# Replace the new version with a directory before upgrading. +# We can't get a sum for a directory. +go mod edit -replace rsc.io/quote@v1.5.2=./dummy +go get example.com/upgrade@v0.0.2 +! grep '^rsc.io/quote v1.5.2 ' go.sum +cp go.mod.orig go.mod +cp go.sum.orig go.sum + + +# Replace the new version with a different version. +# We should get a sum for that version. +go mod edit -replace rsc.io/quote@v1.5.2=rsc.io/quote@v1.5.1 +go get example.com/upgrade@v0.0.2 +! grep '^rsc.io/quote v1.5.2 ' go.sum +grep '^rsc.io/quote v1.5.1 ' go.sum +cp go.mod.orig go.mod +cp go.sum.orig go.sum + + +# Delete the new version's zip (but not mod) from the cache and go offline. +# 'go get' should fail when fetching the zip. +rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip +env GOPROXY=off +! go get example.com/upgrade@v0.0.2 +stderr '^go: upgraded rsc.io/quote v1.0.0 => v1.5.2: error finding sum for rsc.io/quote@v1.5.2: module lookup disabled by GOPROXY=off$' + +-- go.mod.orig -- +module m + +go 1.16 + +require ( + example.com/upgrade v0.0.1 + rsc.io/quote v1.0.0 +) + +replace ( + example.com/upgrade v0.0.1 => ./upgrade1 + example.com/upgrade v0.0.2 => ./upgrade2 +) +-- go.sum.orig -- +rsc.io/quote v1.0.0 h1:kQ3IZQzPTiDJxSZI98YaWgxFEhlNdYASHvh+MplbViw= +rsc.io/quote v1.0.0/go.mod h1:v83Ri/njykPcgJltBc/gEkJTmjTsNgtO1Y7vyIK1CQA= +-- go.sum.want -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.0.0 h1:kQ3IZQzPTiDJxSZI98YaWgxFEhlNdYASHvh+MplbViw= +rsc.io/quote v1.0.0/go.mod h1:v83Ri/njykPcgJltBc/gEkJTmjTsNgtO1Y7vyIK1CQA= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +-- use.go -- +package use + +import ( + _ "example.com/upgrade" + _ "rsc.io/quote" +) +-- upgrade1/go.mod -- +module example.com/upgrade + +go 1.16 +-- upgrade1/upgrade.go -- +package upgrade +-- upgrade2/go.mod -- +module example.com/upgrade + +go 1.16 + +require rsc.io/quote v1.5.2 // indirect +-- upgrade2/upgrade.go -- +package upgrade +-- dummy/go.mod -- +module rsc.io/quote + +go 1.16 +-- dummy/quote.go -- +package quote + diff --git a/src/cmd/go/testdata/script/mod_get_upgrade.txt b/src/cmd/go/testdata/script/mod_get_upgrade.txt new file mode 100644 index 0000000..51d5990 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_upgrade.txt @@ -0,0 +1,46 @@ +env GO111MODULE=on + +go get rsc.io/quote@v1.5.1 +go list -m all +stdout 'rsc.io/quote v1.5.1' +grep 'rsc.io/quote v1.5.1$' go.mod + +# get -u should update dependencies of the package in the current directory +go get -u +grep 'rsc.io/quote v1.5.2$' go.mod +grep 'golang.org/x/text [v0-9a-f\.-]+ // indirect' go.mod + +# get -u rsc.io/sampler should update only sampler's dependencies +cp go.mod-v1.5.1 go.mod +go get -u rsc.io/sampler +grep 'rsc.io/quote v1.5.1$' go.mod +grep 'golang.org/x/text [v0-9a-f\.-]+ // indirect' go.mod + +# move to a pseudo-version after any tags +go get rsc.io/quote@dd9747d +grep 'rsc.io/quote v0.0.0-20180628003336-dd9747d19b04' go.mod + +# get -u should not jump off newer pseudo-version to earlier tag +go get -u +grep 'rsc.io/quote v0.0.0-20180628003336-dd9747d19b04' go.mod + +# move to earlier pseudo-version +go get rsc.io/quote@e7a685a342 +grep 'rsc.io/quote v0.0.0-20180214005133-e7a685a342c0' go.mod + +# get -u should jump off earlier pseudo-version to newer tag +go get -u +grep 'rsc.io/quote v1.5.2' go.mod + +-- go.mod -- +module x +require rsc.io/quote v1.1.0 + +-- go.mod-v1.5.1 -- +module x +require rsc.io/quote v1.5.1 + +-- use.go -- +package use + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_get_upgrade_pseudo.txt b/src/cmd/go/testdata/script/mod_get_upgrade_pseudo.txt new file mode 100644 index 0000000..deff935 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_upgrade_pseudo.txt @@ -0,0 +1,70 @@ +env GO111MODULE=on + +# For this test module there are three versions: +# * v0.1.1-0.20190429073117-b5426c86b553 +# * v0.1.0 +# * v0.0.0-20190430073000-30950c05d534 +# Only v0.1.0 is tagged. +# +# The v0.1.1 pseudo-version is semantically higher than the latest tag. +# The v0.0.0 pseudo-version is chronologically newer. + +# Start at v0.1.1-0.20190429073117-b5426c86b553 +go get example.com/pseudoupgrade@b5426c8 +go list -m -u all +stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$' + +# 'get -u' should not downgrade to the (lower) tagged version. +go get -u +go list -m -u all +stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$' + +# 'get example.com/pseudoupgrade@upgrade' should not downgrade. +go get example.com/pseudoupgrade@upgrade +go list -m all +stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$' + +# 'get example.com/pseudoupgrade' should not downgrade. +# This is equivalent to 'get example.com/pseudoupgrade@upgrade'. +go get example.com/pseudoupgrade +go list -m all +stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$' + +# 'get example.com/pseudoupgrade@latest' should downgrade. +# @latest should not consider the current version. +go get example.com/pseudoupgrade@latest +go list -m all +stdout '^example.com/pseudoupgrade v0.1.0$' + +# We should observe the same behavior with the newer pseudo-version. +go get example.com/pseudoupgrade@v0.0.0-20190430073000-30950c05d534 + +# 'get -u' should not downgrade to the chronologically older tagged version. +go get -u +go list -m -u all +stdout '^example.com/pseudoupgrade v0.0.0-20190430073000-30950c05d534$' + +# 'get example.com/pseudoupgrade@upgrade should not downgrade. +go get example.com/pseudoupgrade@upgrade +go list -m -u all +stdout '^example.com/pseudoupgrade v0.0.0-20190430073000-30950c05d534$' + +# 'get example.com/pseudoupgrade' should not downgrade. +go get example.com/pseudoupgrade +go list -m -u all +stdout '^example.com/pseudoupgrade v0.0.0-20190430073000-30950c05d534$' + +# 'get example.com/pseudoupgrade@latest' should downgrade. +go get example.com/pseudoupgrade@latest +go list -m -u all +stdout '^example.com/pseudoupgrade v0.1.0$' + +-- go.mod -- +module x + +go 1.12 + +-- main.go -- +package x + +import _ "example.com/pseudoupgrade" diff --git a/src/cmd/go/testdata/script/mod_get_wild.txt b/src/cmd/go/testdata/script/mod_get_wild.txt new file mode 100644 index 0000000..06f9973 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_wild.txt @@ -0,0 +1,95 @@ +# This test covers a crazy edge-case involving wildcards and multiple passes of +# patch-upgrades, but if we get it right we probably get many other edge-cases +# right too. + +go list -m all +stdout '^example.net/a v0.1.0 ' +! stdout '^example.net/b ' + + +# Requesting pattern example.../b by itself fails: there is no such module +# already in the build list, and the wildcard in the first element prevents us +# from attempting to resolve a new module whose path is a prefix of the pattern. + +! go get -u=patch example.../b@upgrade +stderr '^go: no modules to query for example\.\.\./b@upgrade because first path element contains a wildcard$' + + +# Patching . causes a patch to example.net/a, which introduces a new match +# for example.net/b/..., which is itself patched and causes another upgrade to +# example.net/a, which is then patched again. + +go get -u=patch . example.../b@upgrade +go list -m all +stdout '^example.net/a v0.2.1 ' # upgraded by dependency of b and -u=patch +stdout '^example.net/b v0.2.0 ' # introduced by patch of a and upgraded by wildcard + + +-- go.mod -- +module example + +go 1.16 + +require example.net/a v0.1.0 + +replace ( + example.net/a v0.1.0 => ./a10 + example.net/a v0.1.1 => ./a11 + example.net/a v0.2.0 => ./a20 + example.net/a v0.2.1 => ./a20 + example.net/b v0.1.0 => ./b1 + example.net/b v0.1.1 => ./b1 + example.net/b v0.2.0 => ./b2 +) +-- example.go -- +package example + +import _ "example.net/a" + +-- a10/go.mod -- +module example.net/a + +go 1.16 +-- a10/a.go -- +package a + +-- a11/go.mod -- +module example.net/a + +go 1.16 + +require example.net/b v0.1.0 +-- a11/a.go -- +package a +-- a11/unimported/unimported.go -- +package unimported + +import _ "example.net/b" + + +-- a20/go.mod -- +module example.net/a + +go 1.16 +-- a20/a.go -- +package a + +-- b1/go.mod -- +module example.net/b + +go 1.16 +-- b1/b.go -- +package b + +-- b2/go.mod -- +module example.net/b + +go 1.16 + +require example.net/a v0.2.0 +-- b2/b.go -- +package b +-- b2/b_test.go -- +package b_test + +import _ "example.net/a" diff --git a/src/cmd/go/testdata/script/mod_getmode_vendor.txt b/src/cmd/go/testdata/script/mod_getmode_vendor.txt new file mode 100644 index 0000000..aaf526b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_getmode_vendor.txt @@ -0,0 +1,31 @@ +env GO111MODULE=on + +go get rsc.io/quote@v1.5.1 +go mod vendor +env GOPATH=$WORK/empty +env GOPROXY=file:///nonexist + +go list -mod=vendor +go list -mod=vendor -f '{{with .Module}}{{.Path}} {{.Version}}{{end}} {{.Dir}}' all +stdout '^rsc.io/quote v1.5.1 .*vendor[\\/]rsc.io[\\/]quote$' +stdout '^golang.org/x/text v0.0.0.* .*vendor[\\/]golang.org[\\/]x[\\/]text[\\/]language$' + +! go list -mod=vendor -m rsc.io/quote@latest +stderr 'go: rsc.io/quote@latest: cannot query module due to -mod=vendor' +! go get -mod=vendor -u +stderr 'flag provided but not defined: -mod' + +# Since we don't have a complete module graph, 'go list -m' queries +# that require the complete graph should fail with a useful error. +! go list -mod=vendor -m all +stderr 'go: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)' +! go list -mod=vendor -m ... +stderr 'go: can''t match module patterns using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)' + +-- go.mod -- +module x + +go 1.16 +-- x.go -- +package x +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_getx.txt b/src/cmd/go/testdata/script/mod_getx.txt new file mode 100644 index 0000000..46bb95b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_getx.txt @@ -0,0 +1,18 @@ +[!net:golang.org] skip +[!git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +# 'go get -x' should log URLs with an HTTP or HTTPS scheme. +# A bug had caused us to log schemeless URLs instead. +go get -x golang.org/x/text@v0.1.0 +stderr '^# get https://golang.org/x/text\?go-get=1$' +stderr '^# get https://golang.org/x/text\?go-get=1: 200 OK \([0-9.]+s\)$' +! stderr '^# get //.*' + +-- go.mod -- +module m + +go 1.18 diff --git a/src/cmd/go/testdata/script/mod_git_export_subst.txt b/src/cmd/go/testdata/script/mod_git_export_subst.txt new file mode 100644 index 0000000..740ccbd --- /dev/null +++ b/src/cmd/go/testdata/script/mod_git_export_subst.txt @@ -0,0 +1,21 @@ +env GO111MODULE=on +env GOPROXY=direct + +# Testing that git export-subst is disabled +[!net:github.com] skip +[!git] skip +go build + +-- x.go -- +package x + +import _ "github.com/jasonkeene/export-subst" + +-- go.mod -- +module x + +require github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626 + +-- go.sum -- +github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626 h1:AUkXi/xFnm7lH2pgtvVkGb7buRn1ywFHw+xDpZ29Rz0= +github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626/go.mod h1:DwJXqVtrgrQkv3Giuf2Jh4YyubVe7y41S1eOIaysTJw= diff --git a/src/cmd/go/testdata/script/mod_go_version.txt b/src/cmd/go/testdata/script/mod_go_version.txt new file mode 100644 index 0000000..82b55d8 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_go_version.txt @@ -0,0 +1,29 @@ +# Test support for declaring needed Go version in module. + +env GO111MODULE=on +env TESTGO_VERSION=go1.21 + +! go list +stderr -count=1 '^go: sub@v1.0.0: module ./sub requires go >= 1.999 \(running go 1.21\)$' +! go build sub +stderr -count=1 '^go: sub@v1.0.0: module ./sub requires go >= 1.999 \(running go 1.21\)$' + +-- go.mod -- +module m +go 1.1 +require ( + sub v1.0.0 +) +replace ( + sub => ./sub +) + +-- x.go -- +package x + +-- sub/go.mod -- +module sub +go 1.999 + +-- sub/x.go -- +package x diff --git a/src/cmd/go/testdata/script/mod_go_version_missing.txt b/src/cmd/go/testdata/script/mod_go_version_missing.txt new file mode 100644 index 0000000..e9a8e72 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_go_version_missing.txt @@ -0,0 +1,122 @@ +cp go.mod go.mod.orig + +# For modules whose go.mod file does not include a 'go' directive, +# we assume the language and dependency semantics of Go 1.16, +# but do not trigger “automatic vendoring” mode (-mod=vendor), +# which was added in Go 1.14 and was not triggered +# under the same conditions in Go 1.16 (which would instead +# default to -mod=readonly when no 'go' directive is present). + +# For Go 1.16 modules, 'all' should prune out dependencies of tests, +# even if the 'go' directive is missing. + +go list -mod=readonly all +stdout '^example.com/dep$' +! stdout '^example.com/testdep$' +cp stdout list-1.txt +cmp go.mod go.mod.orig + +# We should only default to -mod=vendor if the 'go' directive is explicit in the +# go.mod file. Otherwise, we don't actually know whether the module was written +# against Go 1.11 or 1.16. We would have to update the go.mod file to clarify, +# and as of Go 1.16 we don't update the go.mod file by default. +# +# If we set -mod=vendor explicitly, we shouldn't apply the Go 1.14 +# consistency check, because — again — we don't know whether we're in a 1.11 +# module or a bad-script-edited 1.16 module. + +! go list -mod=vendor all +! stderr '^go: inconsistent vendoring' +stderr 'cannot find module providing package example.com/badedit: import lookup disabled by -mod=vendor' + +# When we set -mod=mod, the go version should be updated immediately, +# to the current version, converting the requirements from eager to lazy. +# +# Since we don't know which requirements are actually relevant to the main +# module, all requirements are added as roots, making the requirements untidy. + +go list -mod=mod all +! stdout '^example.com/testdep$' +cmp stdout list-1.txt +cmpenv go.mod go.mod.untidy + +go mod tidy +cmpenv go.mod go.mod.tidy + +# On the other hand, if we jump straight to 'go mod tidy', +# the requirements remain tidy from the start. + +cp go.mod.orig go.mod +go mod tidy +cmpenv go.mod go.mod.tidy + + +# The updated version should have been written back to go.mod, so now the 'go' +# directive is explicit. -mod=vendor should trigger by default, and the stronger +# Go 1.14 consistency check should apply. +! go list all +stderr '^go: inconsistent vendoring' +! stderr badedit + + +-- go.mod -- +module example.com/m + +require example.com/dep v0.1.0 + +replace ( + example.com/dep v0.1.0 => ./dep + example.com/testdep v0.1.0 => ./testdep +) +-- go.mod.untidy -- +module example.com/m + +go $goversion + +require example.com/dep v0.1.0 + +require example.com/testdep v0.1.0 // indirect + +replace ( + example.com/dep v0.1.0 => ./dep + example.com/testdep v0.1.0 => ./testdep +) +-- go.mod.tidy -- +module example.com/m + +go $goversion + +require example.com/dep v0.1.0 + +replace ( + example.com/dep v0.1.0 => ./dep + example.com/testdep v0.1.0 => ./testdep +) +-- vendor/example.com/dep/dep.go -- +package dep +import _ "example.com/badedit" +-- vendor/modules.txt -- +HAHAHA this is broken. + +-- m.go -- +package m + +import _ "example.com/dep" + +const x = 1_000 + +-- dep/go.mod -- +module example.com/dep + +require example.com/testdep v0.1.0 +-- dep/dep.go -- +package dep +-- dep/dep_test.go -- +package dep_test + +import _ "example.com/testdep" + +-- testdep/go.mod -- +module example.com/testdep +-- testdep/testdep.go -- +package testdep diff --git a/src/cmd/go/testdata/script/mod_go_version_mixed.txt b/src/cmd/go/testdata/script/mod_go_version_mixed.txt new file mode 100644 index 0000000..d6216ae --- /dev/null +++ b/src/cmd/go/testdata/script/mod_go_version_mixed.txt @@ -0,0 +1,43 @@ +# Test that dependencies can use Go language features newer than the +# Go version specified by the main module. + +env GO111MODULE=on + +go build + +-- go.mod -- +module m +go 1.12 +require ( + sub.1 v1.0.0 +) +replace ( + sub.1 => ./sub +) + +-- x.go -- +package x + +import "sub.1" + +func F() { sub.F(0, 0) } + +var A sub.Alias +var D sub.Defined + +-- sub/go.mod -- +module m +go 1.14 + +-- sub/sub.go -- +package sub + +// signed shift counts added in Go 1.13 +func F(l, r int) int { return l << r } + +type m1 interface { M() } +type m2 interface { M() } + +// overlapping interfaces added in Go 1.14 +type Alias = interface { m1; m2; M() } +type Defined interface { m1; m2; M() } diff --git a/src/cmd/go/testdata/script/mod_gobuild_import.txt b/src/cmd/go/testdata/script/mod_gobuild_import.txt new file mode 100644 index 0000000..70af331 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_gobuild_import.txt @@ -0,0 +1,133 @@ +[short] skip + +# go/build's Import should find modules by invoking the go command + +go build -o $WORK ./testimport ./testfindonly + +# GO111MODULE=off +env GO111MODULE=off +! exec $WORK/testimport$GOEXE gobuild.example.com/x/y/z/w . + +# GO111MODULE=auto in GOPATH/src +env GO111MODULE=auto +exec $WORK/testimport$GOEXE gobuild.example.com/x/y/z/w . + +# GO111MODULE=auto outside GOPATH/src +cd $GOPATH/other +env GO111MODULE=auto +exec $WORK/testimport$GOEXE other/x/y/z/w . +stdout w2.go + +! exec $WORK/testimport$GOEXE gobuild.example.com/x/y/z/w . +stderr 'no required module provides package gobuild.example.com/x/y/z/w; to add it:\n\tgo get gobuild.example.com/x/y/z/w' + +cd z +exec $WORK/testimport$GOEXE other/x/y/z/w . +stdout w2.go + +# GO111MODULE=on outside GOPATH/src +env GO111MODULE= +exec $WORK/testimport$GOEXE other/x/y/z/w . +stdout w2.go +env GO111MODULE=on +exec $WORK/testimport$GOEXE other/x/y/z/w . +stdout w2.go + +# GO111MODULE=on in GOPATH/src +cd $GOPATH/src +env GO111MODULE= +exec $WORK/testimport$GOEXE gobuild.example.com/x/y/z/w . +stdout w1.go +env GO111MODULE=on +exec $WORK/testimport$GOEXE gobuild.example.com/x/y/z/w . +stdout w1.go +cd w +exec $WORK/testimport$GOEXE gobuild.example.com/x/y/z/w .. +stdout w1.go + +# go/build's Import in FindOnly mode should find directories by invoking the go command +# +# Calling build.Import in build.FindOnly mode on an import path of a Go package +# that produces errors when loading (e.g., due to build constraints not matching +# the current build context) should return the package directory and nil error. + +# Issue 31603: Import with non-empty srcDir should work. +env GO111MODULE=on +exec $WORK/testfindonly$GOEXE gobuild.example.com/x/y/z/i $WORK +! stdout 'build constraints' +stdout '^dir='$WORK'.+i err=<nil>$' + +# Issue 37153: Import with empty srcDir should work. +env GO111MODULE=on +exec $WORK/testfindonly$GOEXE gobuild.example.com/x/y/z/i '' +! stdout 'build constraints' +stdout '^dir='$WORK'.+i err=<nil>$' + +-- go.mod -- +module gobuild.example.com/x/y/z + +-- z.go -- +package z + +-- w/w1.go -- +package w + +-- i/i.go -- +// +build i + +package i + +-- testimport/x.go -- +package main + +import ( + "fmt" + "go/build" + "log" + "os" + "path/filepath" + "strings" +) + +func main() { + // build.Import should support relative and absolute source dir paths. + path := os.Args[1] + srcDir := os.Args[2] + p1, err := build.Import(path, srcDir, 0) + if err != nil { + log.Fatal(err) + } + absSrcDir, err := filepath.Abs(srcDir) + if err != nil { + log.Fatal(err) + } + p2, err := build.Import(path, absSrcDir, 0) + if err != nil { + log.Fatal(err) + } + if p1.Dir != p2.Dir { + log.Fatalf("different packages loaded with relative and absolute paths:\n\t%s\n\t%s", p1.Dir, p2.Dir) + } + + fmt.Printf("%s\n%s\n", p1.Dir, strings.Join(p1.GoFiles, " ")) +} + +-- testfindonly/x.go -- +package main + +import ( + "fmt" + "go/build" + "os" +) + +func main() { + p, err := build.Import(os.Args[1], os.Args[2], build.FindOnly) + fmt.Printf("dir=%s err=%v\n", p.Dir, err) +} + +-- $GOPATH/other/go.mod -- +module other/x/y + +-- $GOPATH/other/z/w/w2.go -- +package w diff --git a/src/cmd/go/testdata/script/mod_gofmt_invalid.txt b/src/cmd/go/testdata/script/mod_gofmt_invalid.txt new file mode 100644 index 0000000..21edc7d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_gofmt_invalid.txt @@ -0,0 +1,13 @@ +# Test for a crash in go fmt on invalid input when using modules. +# Issue 26792. + +env GO111MODULE=on +! go fmt x.go +! stderr panic + +-- go.mod -- +module x + +-- x.go -- +// Missing package declaration. +var V int diff --git a/src/cmd/go/testdata/script/mod_goline.txt b/src/cmd/go/testdata/script/mod_goline.txt new file mode 100644 index 0000000..6b2eab0 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_goline.txt @@ -0,0 +1,117 @@ +env TESTGO_VERSION=go1.99 + +! go list -f '{{.Module.GoVersion}}' +stderr 'go: updates to go.mod needed' +stderr 'go mod tidy' + +go mod tidy +cat go.mod +go list -f '{{.Module.GoVersion}}' +stdout 1.22 + +# Adding a@v1.0.01 should upgrade to Go 1.23rc1. +cp go.mod go.mod1 +go get example.com/a@v1.0.1 +stderr '^go: upgraded go 1.22 => 1.23rc1\ngo: upgraded example.com/a v1.0.0 => v1.0.1\ngo: upgraded example.com/b v1.0.0 => v1.0.1$' +go list -f '{{.Module.GoVersion}}' +stdout 1.23rc1 + +# Repeating the update with go@1.24.0 should use that Go version. +cp go.mod1 go.mod +go get example.com/a@v1.0.1 go@1.24.0 +go list -f '{{.Module.GoVersion}}' +stdout 1.24.0 + +# Go version-constrained updates should report the problems. +cp go.mod1 go.mod +! go get example.com/a@v1.0.2 go@1.24.2 +stderr '^go: example.com/a@v1.0.2 requires go@1.25, not go@1.24.2$' +! go get example.com/a@v1.0.2 go@1.26.3 +stderr '^go: example.com/a@v1.0.2 indirectly requires go@1.27, not go@1.26.3$' +go get example.com/a@v1.0.2 go@1.28rc1 +go list -f '{{.Module.GoVersion}}' +stdout 1.28rc1 +go get go@1.24.2 +stderr '^go: downgraded go 1.28rc1 => 1.24.2$' +stderr '^go: downgraded example.com/a v1.0.2 => v1.0.1$' +stderr '^go: downgraded example.com/b v1.0.2 => v1.0.1$' +go list -f '{{.Module.GoVersion}}' +stdout 1.24.2 + +-- go.mod -- +module m +go 1.21 + +require ( + example.com/a v1.0.0 + example.com/b v0.9.0 +) + +replace example.com/a v1.0.0 => ./a100 +replace example.com/a v1.0.1 => ./a101 +replace example.com/a v1.0.2 => ./a102 +replace example.com/b v1.0.1 => ./b101 +replace example.com/b v1.0.2 => ./b102 +replace example.com/b v1.0.0 => ./b100 +replace example.com/b v0.9.0 => ./b100 + +-- x.go -- +package m + +import ( + _ "example.com/a" + _ "example.com/b" +) + +-- a100/go.mod -- +module example.com/a +go 1.22 + +require example.com/b v1.0.0 + +-- a100/a.go -- +package a + +-- a101/go.mod -- +// this module is technically invalid, since the dep example.com/b has a newer go line than this module, +// but we should still be able to handle it. +module example.com/a +go 1.22 + +require example.com/b v1.0.1 + +-- a101/a.go -- +package a + +-- a102/go.mod -- +// this module is technically invalid, since the dep example.com/b has a newer go line than this module, +// but we should still be able to handle it. +module example.com/a +go 1.25 + +require example.com/b v1.0.2 + +-- a102/a.go -- +package a + +-- b100/go.mod -- +module example.com/b +go 1.22 + +-- b100/b.go -- +package b + +-- b101/go.mod -- +module example.com/b +go 1.23rc1 + +-- b101/b.go -- +package b + +-- b102/go.mod -- +module example.com/b +go 1.27 + +-- b102/b.go -- +package b + diff --git a/src/cmd/go/testdata/script/mod_goline_old.txt b/src/cmd/go/testdata/script/mod_goline_old.txt new file mode 100644 index 0000000..bbe611b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_goline_old.txt @@ -0,0 +1,72 @@ +env TESTGO_VERSION=go1.24 + +go list -f '{{.Module.GoVersion}}' +stdout 1.15 + +go mod tidy +go list -f '{{.Module.GoVersion}}' +stdout 1.15 + +go get example.com/a@v1.0.1 +go list -f '{{.Module.GoVersion}}' +stdout 1.15 + +go get example.com/a@v1.0.1 go@1.16 +go list -f '{{.Module.GoVersion}}' +stdout 1.16 + +-- go.mod -- +module m +go 1.15 + +require ( + example.com/a v1.0.0 + example.com/b v1.0.0 +) + +replace example.com/a v1.0.0 => ./a100 +replace example.com/a v1.0.1 => ./a101 +replace example.com/b v1.0.1 => ./b101 +replace example.com/b v1.0.0 => ./b100 +replace example.com/b v0.9.0 => ./b100 + +-- x.go -- +package m + +import ( + _ "example.com/a" + _ "example.com/b" +) + +-- a100/go.mod -- +module example.com/a +go 1.16 + +require example.com/b v1.0.0 + +-- a100/a.go -- +package a + +-- a101/go.mod -- +module example.com/a +go 1.17 + +require example.com/b v1.0.1 + +-- a101/a.go -- +package a + +-- b100/go.mod -- +module example.com/b +go 1.18 + +-- b100/b.go -- +package b + +-- b101/go.mod -- +module example.com/b +go 1.19 + +-- b101/b.go -- +package b + diff --git a/src/cmd/go/testdata/script/mod_goline_too_new.txt b/src/cmd/go/testdata/script/mod_goline_too_new.txt new file mode 100644 index 0000000..6d26679 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_goline_too_new.txt @@ -0,0 +1,50 @@ +# Go should refuse to build code that is too new according to go.mod. + +# go.mod too new +env GOTOOLCHAIN=local +! go build . +stderr '^go: go.mod requires go >= 1.99999 \(running go 1\..+\)$' + +# go.mod referenced from go.work too new +cp go.work.old go.work +! go build . +stderr '^go: module . listed in go.work file requires go >= 1.99999, but go.work lists go 1.10; to update it:\n\tgo work use$' + +! go work sync +stderr '^go: cannot load module . listed in go.work file: go.mod requires go >= 1.99999 \(running go 1\..+\)$' + +# go.work too new +cp go.work.new go.work +cp go.mod.old go.mod +! go build . +stderr '^go: go.work requires go >= 1.99999 \(running go 1\..+\)$' + +# vendor too new +rm go.work +mv notvendor vendor +! go build -mod=vendor . +stderr '^go: golang.org/x/text in vendor'${/}'modules.txt requires go >= 1.99999 \(running go 1\..+\)$' + +-- go.mod -- +module example +go 1.99999 + +-- p.go -- +package p + +-- go.mod.old -- +module example +go 1.10 + +-- go.work.new -- +go 1.99999 +use . + +-- go.work.old -- +go 1.10 +use . + +-- notvendor/modules.txt -- +# golang.org/x/text v0.9.0 +## explicit; go 1.99999 +golang.org/x/text/internal/language diff --git a/src/cmd/go/testdata/script/mod_gomodcache.txt b/src/cmd/go/testdata/script/mod_gomodcache.txt new file mode 100644 index 0000000..bfc6cb1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_gomodcache.txt @@ -0,0 +1,74 @@ +# Test GOMODCACHE +env GO111MODULE=on + +# Explicitly set GOMODCACHE +env GOMODCACHE=$WORK/modcache +go env GOMODCACHE +stdout $WORK[/\\]modcache +go get rsc.io/quote@v1.0.0 +exists $WORK/modcache/cache/download/rsc.io/quote/@v/v1.0.0.info +grep '{"Version":"v1.0.0","Time":"2018-02-14T00:45:20Z"}' $WORK/modcache/cache/download/rsc.io/quote/@v/v1.0.0.info + +# Ensure GOMODCACHE doesn't affect location of sumdb, but $GOMODCACHE/cache/download/sumdb is still written +exists $GOPATH/pkg/sumdb +! exists $WORK/modcache/sumdb +exists $WORK/modcache/cache/download/sumdb + +# Test that the default GOMODCACHE is $GOPATH[0]/pkg/mod +env GOMODCACHE= +go env GOMODCACHE +stdout $GOPATH[/\\]pkg[/\\]mod +go get rsc.io/quote@v1.0.0 +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.0.0.info +grep '{"Version":"v1.0.0","Time":"2018-02-14T00:45:20Z"}' $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.0.0.info + +# If neither GOMODCACHE or GOPATH are set, GOPATH defaults to the user's $HOME/go, so GOMODCACHE becomes $HOME/go/pkg/mod +[GOOS:windows] env USERPROFILE=$WORK/home # Ensure USERPROFILE is a valid path (rather than /no-home/ so we don't run into the logic that "uninfers" GOPATH in cmd/go/main.go +[GOOS:plan9] env home=$WORK/home +[!GOOS:windows] [!GOOS:plan9] env HOME=$WORK/home +env GOMODCACHE= +env GOPATH= +go env GOMODCACHE +stdout $HOME[/\\]go[/\\]pkg[/\\]mod + +# If GOMODCACHE isn't set and GOPATH starts with the path list separator, +# GOMODCACHE is empty and any command that needs it errors out. +env GOMODCACHE= +env GOPATH=${:}$WORK/this/is/ignored + +go env GOMODCACHE +stdout '^$' +! stdout . +! stderr . + +! go mod download rsc.io/quote@v1.0.0 +stderr '^go: module cache not found: neither GOMODCACHE nor GOPATH is set$' + +# If GOMODCACHE isn't set and GOPATH has multiple elements only the first is used. +env GOMODCACHE= +env GOPATH=$WORK/first/path${:}$WORK/this/is/ignored +go env GOMODCACHE +stdout $WORK[/\\]first[/\\]path[/\\]pkg[/\\]mod + +env GOMODCACHE=$WORK/modcache +go mod download rsc.io/quote@v1.0.0 +exists $WORK/modcache/cache/download/rsc.io/quote/@v/v1.0.0.info + +# Test error when cannot create GOMODCACHE directory +env GOMODCACHE=$WORK/modcachefile +! go install example.com/cmd/a@v1.0.0 +stderr 'go: could not create module cache' + +# Test that the following work even with GO111MODULE=off +env GO111MODULE=off + +# Cleaning modcache +exists $WORK/modcache +env GOMODCACHE=$WORK/modcache +go clean -modcache +! exists $WORK/modcache + +-- go.mod -- +module m + +-- $WORK/modcachefile -- diff --git a/src/cmd/go/testdata/script/mod_gonoproxy.txt b/src/cmd/go/testdata/script/mod_gonoproxy.txt new file mode 100644 index 0000000..94d03f2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_gonoproxy.txt @@ -0,0 +1,55 @@ +env GO111MODULE=on +env sumdb=$GOSUMDB +env proxy=$GOPROXY +env GOPRIVATE GOPROXY GONOPROXY GOSUMDB GONOSUMDB +env dbname=localhost.localdev/sumdb + +# disagree with sumdb fails +cp go.mod.orig go.mod +env GOSUMDB=$sumdb' '$proxy/sumdb-wrong +! go get rsc.io/quote +stderr 'SECURITY ERROR' + +# GONOSUMDB bypasses sumdb, for rsc.io/quote, rsc.io/sampler, golang.org/x/text +env GONOSUMDB='*/quote,*/*mple*,golang.org/x' +go get rsc.io/quote +rm go.sum +env GOPRIVATE='*/quote,*/*mple*,golang.org/x' +env GONOPROXY=none # that is, proxy all despite GOPRIVATE +go get rsc.io/quote + +# Download .info files needed for 'go list -m all' later. +# TODO(#42723): either 'go list -m' should not read these files, +# or 'go get' and 'go mod tidy' should download them. +go list -m all +stdout '^golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c$' + +# When GOPROXY is not empty but contains no entries, an error should be reported. +env GOPROXY=',' +! go get golang.org/x/text +stderr '^go: golang.org/x/text: GOPROXY list is not the empty string, but contains no entries$' + +# When GOPROXY=off, fetching modules not matched by GONOPROXY fails. +env GONOPROXY=*/fortune +env GOPROXY=off +! go get golang.org/x/text +stderr '^go: golang.org/x/text: module lookup disabled by GOPROXY=off$' + +# GONOPROXY bypasses proxy +[!net:rsc.io] skip +[!git] skip +env GOPRIVATE=none +env GONOPROXY='*/fortune' +! go get rsc.io/fortune # does not exist in real world, only on test proxy +stderr 'git ls-remote' + +[!net:golang.org] skip +env GOSUMDB= +env GONOPROXY= +env GOPRIVATE='*/x' +go get golang.org/x/text +go list -m all +! stdout 'text.*v0.0.0-2017' # should not have the version from the proxy + +-- go.mod.orig -- +module m diff --git a/src/cmd/go/testdata/script/mod_gopkg_unstable.txt b/src/cmd/go/testdata/script/mod_gopkg_unstable.txt new file mode 100644 index 0000000..856f493 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_gopkg_unstable.txt @@ -0,0 +1,26 @@ +env GO111MODULE=on + +cp go.mod.empty go.mod +go get gopkg.in/dummy.v2-unstable + +cp x.go.txt x.go +cp go.mod.empty go.mod +go list + +[!net:gopkg.in] skip +[!git] skip + +skip # TODO(#54503): redirect gopkg.in requests to a local server and re-enable. + +env GOPROXY=direct +env GOSUMDB=off +go get gopkg.in/macaroon-bakery.v2-unstable/bakery +go list -m all +stdout 'gopkg.in/macaroon-bakery.v2-unstable v2.0.0-[0-9]+-[0-9a-f]+$' + +-- go.mod.empty -- +module m + +-- x.go.txt -- +package x +import _ "gopkg.in/dummy.v2-unstable" diff --git a/src/cmd/go/testdata/script/mod_goroot_errors.txt b/src/cmd/go/testdata/script/mod_goroot_errors.txt new file mode 100644 index 0000000..110a196 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_goroot_errors.txt @@ -0,0 +1,53 @@ +env GO111MODULE=on + +# Regression test for https://golang.org/issue/34769. +# Missing standard-library imports should refer to GOROOT rather than +# complaining about a malformed module path. +# This is especially important when GOROOT is set incorrectly, +# since such an error will occur for every package in std. + +# Building a nonexistent std package directly should fail usefully. + +! go build -mod=readonly nonexist +! stderr 'import lookup disabled' +! stderr 'missing dot' +stderr '^package nonexist is not in std \('$GOROOT'[/\\]src[/\\]nonexist\)$' + +! go build nonexist +! stderr 'import lookup disabled' +! stderr 'missing dot' +stderr '^package nonexist is not in std \('$GOROOT'[/\\]src[/\\]nonexist\)$' + +# Building a nonexistent std package indirectly should also fail usefully. + +! go build -mod=readonly ./importnonexist +! stderr 'import lookup disabled' +! stderr 'missing dot' +stderr '^importnonexist[/\\]x.go:2:8: package nonexist is not in std \('$GOROOT'[/\\]src[/\\]nonexist\)$' + +! go build ./importnonexist +! stderr 'import lookup disabled' +! stderr 'missing dot' +stderr '^importnonexist[/\\]x.go:2:8: package nonexist is not in std \('$GOROOT'[/\\]src[/\\]nonexist\)$' + +# Building an *actual* std package should fail if GOROOT is set to something bogus. + +[!short] go build ./importjson # Prove that it works when GOROOT is valid. + +env GOROOT=$WORK/not-a-valid-goroot +! go build ./importjson +! stderr 'import lookup disabled' +! stderr 'missing dot' +stderr 'importjson[/\\]x.go:2:8: package encoding/json is not in std \('$WORK'[/\\]not-a-valid-goroot[/\\]src[/\\]encoding[/\\]json\)$' + +-- go.mod -- +module example.com +go 1.14 +-- importnonexist/x.go -- +package importnonexist +import _ "nonexist" +-- importjson/x.go -- +package importjson +import _ "encoding/json" +-- $WORK/not-a-valid-goroot/README -- +This directory is not a valid GOROOT. diff --git a/src/cmd/go/testdata/script/mod_graph.txt b/src/cmd/go/testdata/script/mod_graph.txt new file mode 100644 index 0000000..8d51439 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_graph.txt @@ -0,0 +1,15 @@ +env GO111MODULE=on + +go mod graph +stdout '^m rsc.io/quote@v1.5.2$' +stdout '^rsc.io/quote@v1.5.2 rsc.io/sampler@v1.3.0$' +! stdout '^m rsc.io/sampler@v1.3.0$' +! stderr 'get '$GOPROXY + +rm $GOPATH/pkg/mod/cache/download/rsc.io/quote +go mod graph -x +stderr 'get '$GOPROXY + +-- go.mod -- +module m +require rsc.io/quote v1.5.2 diff --git a/src/cmd/go/testdata/script/mod_graph_version.txt b/src/cmd/go/testdata/script/mod_graph_version.txt new file mode 100644 index 0000000..ed7e399 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_graph_version.txt @@ -0,0 +1,101 @@ +# For this module, Go 1.17 prunes out a (transitive and otherwise-irrelevant) +# requirement on a retracted higher version of a dependency. +# However, when Go 1.16 reads the same requirements from the go.mod file, +# it does not prune out that requirement, and selects the retracted version. +# +# The Go 1.16 module graph looks like: +# +# m ---- lazy v0.1.0 ---- requireincompatible v0.1.0 ---- incompatible v2.0.0+incompatible +# | | +# + -------+------------- incompatible v1.0.0 +# +# The Go 1.17 module graph is the same except that the dependencies of +# requireincompatible are pruned out (because the module that requires +# it — lazy v0.1.0 — specifies 'go 1.17', and it is not otherwise relevant to +# the main module). + +cp go.mod go.mod.orig + +go mod graph +cp stdout graph-1.17.txt +stdout '^example\.com/m example\.com/retract/incompatible@v1\.0\.0$' +stdout '^example\.net/lazy@v0\.1\.0 example\.com/retract/incompatible@v1\.0\.0$' +! stdout 'example\.com/retract/incompatible@v2\.0\.0\+incompatible' + +go mod graph -go=1.17 +cmp stdout graph-1.17.txt + +cmp go.mod go.mod.orig + + +# Setting -go=1.16 should report the graph as viewed by Go 1.16, +# but should not edit the go.mod file. + +go mod graph -go=1.16 +cp stdout graph-1.16.txt +stdout '^example\.com/m example\.com/retract/incompatible@v1\.0\.0$' +stdout '^example\.net/lazy@v0\.1\.0 example.com/retract/incompatible@v1\.0\.0$' +stdout '^example.net/requireincompatible@v0.1.0 example.com/retract/incompatible@v2\.0\.0\+incompatible$' + +cmp go.mod go.mod.orig + + +# If we actually update the go.mod file to the requested go version, +# we should get the same selected versions, but the roots of the graph +# may be updated. +# +# TODO(#45551): The roots should not be updated. + +go mod edit -go=1.16 +go mod graph +! stdout '^example\.com/m example\.com/retract/incompatible@v1\.0\.0$' +stdout '^example\.net/lazy@v0.1.0 example.com/retract/incompatible@v1\.0\.0$' +stdout '^example.net/requireincompatible@v0.1.0 example.com/retract/incompatible@v2\.0\.0\+incompatible$' + # TODO(#45551): cmp stdout graph-1.16.txt + + +# Unsupported go versions should be rejected, since we don't know +# what versions they would report. +! go mod graph -go=1.99999999999 +stderr '^invalid value "1\.99999999999" for flag -go: maximum supported Go version is '$goversion'\nusage: go mod graph \[-go=version\] \[-x\]\nRun ''go help mod graph'' for details.$' + + +-- go.mod -- +// Module m indirectly imports a package from +// example.com/retract/incompatible. Its selected version of +// that module is lower under Go 1.17 semantics than under Go 1.16. +module example.com/m + +go 1.17 + +replace ( + example.net/lazy v0.1.0 => ./lazy + example.net/requireincompatible v0.1.0 => ./requireincompatible +) + +require ( + example.com/retract/incompatible v1.0.0 // indirect + example.net/lazy v0.1.0 +) +-- lazy/go.mod -- +// Module lazy requires example.com/retract/incompatible v1.0.0. +// +// When viewed from the outside it also has a transitive dependency +// on v2.0.0+incompatible, but in lazy mode that transitive dependency +// is pruned out. +module example.net/lazy + +go 1.17 + +exclude example.com/retract/incompatible v2.0.0+incompatible + +require ( + example.com/retract/incompatible v1.0.0 + example.net/requireincompatible v0.1.0 +) +-- requireincompatible/go.mod -- +module example.net/requireincompatible + +go 1.15 + +require example.com/retract/incompatible v2.0.0+incompatible diff --git a/src/cmd/go/testdata/script/mod_help.txt b/src/cmd/go/testdata/script/mod_help.txt new file mode 100644 index 0000000..b5cd30c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_help.txt @@ -0,0 +1,6 @@ +env GO111MODULE=on + +# go help get shows usage for get +go help get +stdout 'usage: go get' +stdout 'get using modules to manage source'
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/mod_import.txt b/src/cmd/go/testdata/script/mod_import.txt new file mode 100644 index 0000000..07714e9 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_import.txt @@ -0,0 +1,18 @@ +env GO111MODULE=on + +# latest rsc.io/quote should be v1.5.2 not v1.5.3-pre1 +go get +go list -m all +stdout 'rsc.io/quote v1.5.2' + +# but v1.5.3-pre1 should be a known version +go list -m -versions rsc.io/quote +stdout '^rsc.io/quote v1.0.0 v1.1.0 v1.2.0 v1.2.1 v1.3.0 v1.4.0 v1.5.0 v1.5.1 v1.5.2 v1.5.3-pre1$' + +-- go.mod -- +module x + +-- x.go -- +package x +import _ "rsc.io/quote" + diff --git a/src/cmd/go/testdata/script/mod_import_cycle.txt b/src/cmd/go/testdata/script/mod_import_cycle.txt new file mode 100644 index 0000000..7be0749 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_import_cycle.txt @@ -0,0 +1,40 @@ +env GO111MODULE=on + +# 'go list all' should fail with a reasonable error message +! go list all +stderr '^package m\n\timports m/a\n\timports m/b\n\timports m/a: import cycle not allowed' + +# 'go list -e' should not print to stderr, but should mark all three +# packages (m, m/a, and m/b) as Incomplete. +go list -e -json all +! stderr . +stdout -count=3 '"Incomplete": true,' + +-- go.mod -- +module m + +require ( + m/a v0.0.0 + m/b v0.0.0 +) + +replace ( + m/a => ./a + m/b => ./b +) +-- m.go -- +package m +import ( + _ "m/a" + _ "m/b" +) +-- a/go.mod -- +module m/a +-- a/a.go -- +package a +import _ "m/b" +-- b/go.mod -- +module m/b +-- b/b.go -- +package b +import _ "m/a" diff --git a/src/cmd/go/testdata/script/mod_import_issue41113.txt b/src/cmd/go/testdata/script/mod_import_issue41113.txt new file mode 100644 index 0000000..fed2510 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_import_issue41113.txt @@ -0,0 +1,28 @@ +# Regression test for https://golang.org/issue/41113. +# +# When resolving a missing import path, the inability to add the package from +# one module path should not interfere with adding a nested path. + +# Initially, our module depends on split-incompatible v2.1.0-pre+incompatible, +# from which an imported package has been removed (and relocated to the nested +# split-incompatible/subpkg module). modload.QueryPattern will suggest +# split-incompatible v2.0.0+incompatible, which we cannot use (because it would +# be an implicit downgrade), and split-incompatible/subpkg v0.1.0, which we +# *should* use. + +go mod tidy + +go list -m all +stdout '^example.com/split-incompatible/subpkg v0\.1\.0$' +! stdout '^example.com/split-incompatible .*' + +-- go.mod -- +module golang.org/issue/41113 + +go 1.16 + +require example.com/split-incompatible v2.1.0-pre+incompatible +-- x.go -- +package issue41113 + +import _ "example.com/split-incompatible/subpkg" diff --git a/src/cmd/go/testdata/script/mod_import_issue42891.txt b/src/cmd/go/testdata/script/mod_import_issue42891.txt new file mode 100644 index 0000000..a78cab2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_import_issue42891.txt @@ -0,0 +1,14 @@ +# If an import declaration is an absolute path, most commands should report +# an error instead of going into an infinite loop. +# Verifies golang.org/issue/42891. +go list . +stdout '^m$' + +-- go.mod -- +module m + +go 1.16 +-- m.go -- +package m + +import "/" diff --git a/src/cmd/go/testdata/script/mod_import_meta.txt b/src/cmd/go/testdata/script/mod_import_meta.txt new file mode 100644 index 0000000..0e469d0 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_import_meta.txt @@ -0,0 +1,45 @@ +# The loader should not attempt to resolve imports of the "all", "std", and "cmd" meta-packages. + +! go list -deps ./importall +! stderr 'internal error' +stderr '^importall[/\\]x.go:3:8: "all" is not an importable package; see ''go help packages''$' + +! go list -deps ./importcmd +! stderr 'internal error' +stderr '^importcmd[/\\]x.go:3:8: "cmd" is not an importable package; see ''go help packages''$' + +! go list -deps ./importstd +! stderr 'internal error' +stderr '^importstd[/\\]x.go:3:8: "std" is not an importable package; see ''go help packages''$' + + +# Not even if such a path is theoretically provided by a (necessarily replaced) module. + +go mod edit -replace std@v0.1.0=./modstd +go mod edit -require std@v0.1.0 + +! go list -deps ./importstd +stderr '^importstd[/\\]x.go:3:8: "std" is not an importable package; see ''go help packages''$' + + +-- go.mod -- +module example.com +go 1.16 +-- importall/x.go -- +package importall + +import _ "all" +-- importcmd/x.go -- +package importcmd + +import _ "cmd" +-- importstd/x.go -- +package importstd + +import _ "std" +-- modstd/go.mod -- +module std +go 1.16 +-- modstd/std.go -- +// Package std is an incredibly confusingly-named package. +package std diff --git a/src/cmd/go/testdata/script/mod_import_mod.txt b/src/cmd/go/testdata/script/mod_import_mod.txt new file mode 100644 index 0000000..b035e3d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_import_mod.txt @@ -0,0 +1,7 @@ +# Test that GOPATH/pkg/mod is excluded +env GO111MODULE=off +! go list mod/foo +stderr 'disallowed import path' + +-- mod/foo/foo.go -- +package foo diff --git a/src/cmd/go/testdata/script/mod_import_toolchain.txt b/src/cmd/go/testdata/script/mod_import_toolchain.txt new file mode 100644 index 0000000..42c12c1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_import_toolchain.txt @@ -0,0 +1,192 @@ +# This test verifies that 'go get' and 'go mod tidy' switch to a newer toolchain +# if needed to process newly-reolved imports. + +env TESTGO_VERSION=go1.21.0 +env TESTGO_VERSION_SWITCH=switch + +cp go.mod go.mod.orig + +# tidy reports needing 1.22.0 for b1 +env GOTOOLCHAIN=local +! go mod tidy +stderr '^go: example imports\n\texample.net/b: module ./b1 requires go >= 1.22.0 \(running go 1.21.0; GOTOOLCHAIN=local\)$' +env GOTOOLCHAIN=auto +go mod tidy + +cmp stderr tidy-stderr.want +cmp go.mod go.mod.tidy + +cp go.mod.orig go.mod +env GOTOOLCHAIN=local +! go get -v . +stderr '^go: example.net/b@v0.1.0: module ./b1 requires go >= 1.22.0 \(running go 1.21.0; GOTOOLCHAIN=local\)$' +env GOTOOLCHAIN=auto +go get -v . +cmp stderr get-v-stderr.want +cmp go.mod go.mod.tidy + +cp go.mod.orig go.mod +env GOTOOLCHAIN=local +! go get -u -v . +stderr '^go: example.net/a@v0.2.0: module ./a2 requires go >= 1.22.0 \(running go 1.21.0; GOTOOLCHAIN=local\)$' +env GOTOOLCHAIN=auto +go get -u -v . +cmp stderr get-u-v-stderr.want +cmp go.mod go.mod.upgraded + +-- tidy-stderr.want -- +go: found example.net/b in example.net/b v0.1.0 +go: module ./b1 requires go >= 1.22.0; switching to go1.22.9 +go: found example.net/b in example.net/b v0.1.0 +go: found example.net/c in example.net/c v0.1.0 +-- get-v-stderr.want -- +go: trying upgrade to example.net/b@v0.1.0 +go: module ./b1 requires go >= 1.22.0; switching to go1.22.9 +go: trying upgrade to example.net/b@v0.1.0 +go: accepting indirect upgrade from go@1.20 to 1.22.0 +go: trying upgrade to example.net/c@v0.1.0 +go: upgraded go 1.20 => 1.22.0 +go: added toolchain go1.22.9 +go: added example.net/b v0.1.0 +go: added example.net/c v0.1.0 +go: added example.net/d v0.1.0 +-- get-u-v-stderr.want -- +go: trying upgrade to example.net/a@v0.2.0 +go: trying upgrade to example.net/b@v0.1.0 +go: module ./a2 requires go >= 1.22.0; switching to go1.22.9 +go: trying upgrade to example.net/a@v0.2.0 +go: trying upgrade to example.net/b@v0.1.0 +go: accepting indirect upgrade from go@1.20 to 1.22.0 +go: trying upgrade to example.net/c@v0.1.0 +go: trying upgrade to example.net/d@v0.2.0 +go: module ./d2 requires go >= 1.23.0; switching to go1.23.9 +go: trying upgrade to example.net/a@v0.2.0 +go: trying upgrade to example.net/b@v0.1.0 +go: accepting indirect upgrade from go@1.20 to 1.22.0 +go: trying upgrade to example.net/c@v0.1.0 +go: trying upgrade to example.net/d@v0.2.0 +go: accepting indirect upgrade from go@1.22.0 to 1.23.0 +go: upgraded go 1.20 => 1.23.0 +go: added toolchain go1.23.9 +go: upgraded example.net/a v0.1.0 => v0.2.0 +go: added example.net/b v0.1.0 +go: added example.net/c v0.1.0 +go: added example.net/d v0.2.0 +-- go.mod -- +module example + +go 1.20 + +require example.net/a v0.1.0 + +replace ( + example.net/a v0.1.0 => ./a1 + example.net/a v0.2.0 => ./a2 + example.net/b v0.1.0 => ./b1 + example.net/c v0.1.0 => ./c1 + example.net/d v0.1.0 => ./d1 + example.net/d v0.2.0 => ./d2 +) +-- go.mod.tidy -- +module example + +go 1.22.0 + +toolchain go1.22.9 + +require ( + example.net/a v0.1.0 + example.net/b v0.1.0 +) + +require ( + example.net/c v0.1.0 // indirect + example.net/d v0.1.0 // indirect +) + +replace ( + example.net/a v0.1.0 => ./a1 + example.net/a v0.2.0 => ./a2 + example.net/b v0.1.0 => ./b1 + example.net/c v0.1.0 => ./c1 + example.net/d v0.1.0 => ./d1 + example.net/d v0.2.0 => ./d2 +) +-- go.mod.upgraded -- +module example + +go 1.23.0 + +toolchain go1.23.9 + +require ( + example.net/a v0.2.0 + example.net/b v0.1.0 +) + +require ( + example.net/c v0.1.0 // indirect + example.net/d v0.2.0 // indirect +) + +replace ( + example.net/a v0.1.0 => ./a1 + example.net/a v0.2.0 => ./a2 + example.net/b v0.1.0 => ./b1 + example.net/c v0.1.0 => ./c1 + example.net/d v0.1.0 => ./d1 + example.net/d v0.2.0 => ./d2 +) +-- example.go -- +package example + +import ( + _ "example.net/a" + _ "example.net/b" +) +-- a1/go.mod -- +module example.net/a + +go 1.20 +-- a1/a.go -- +package a +-- a2/go.mod -- +module example.net/a + +go 1.22.0 + +toolchain go1.23.0 +-- a2/a.go -- +package a +-- b1/go.mod -- +module example.net/b + +go 1.22.0 + +toolchain go1.23.0 +-- b1/b.go -- +package b + +import _ "example.net/c" // Note: module b is intentionally untidy, as if due to a bad git merge +-- c1/go.mod -- +module example.net/c + +go 1.22.0 + +require example.net/d v0.1.0 +-- c1/c.go -- +package c + +import _ "example.net/d" +-- d1/go.mod -- +module example.net/d + +go 1.22.0 +-- d1/d.go -- +package d +-- d2/go.mod -- +module example.net/d + +go 1.23.0 +-- d2/d.go -- +package d diff --git a/src/cmd/go/testdata/script/mod_import_v1suffix.txt b/src/cmd/go/testdata/script/mod_import_v1suffix.txt new file mode 100644 index 0000000..75b3374 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_import_v1suffix.txt @@ -0,0 +1,11 @@ +env GO111MODULE=on + +! go get example.com/invalidpath/v1 +! go install . + +-- go.mod -- +module example.com +-- main.go -- +package main +import _ "example.com/invalidpath/v1" +func main() {} diff --git a/src/cmd/go/testdata/script/mod_in_testdata_dir.txt b/src/cmd/go/testdata/script/mod_in_testdata_dir.txt new file mode 100644 index 0000000..866f784 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_in_testdata_dir.txt @@ -0,0 +1,45 @@ +# Regression test for golang.org/issue/28481: +# 'mod tidy' removed dependencies if the module root was +# within a directory named 'testdata' or '_foo'. + +env GO111MODULE=on + +# A module should be allowed in a directory named testdata. +cd $WORK/testdata +go mod init testdata.tld/foo + +# Getting a package within that module should resolve its dependencies. +go get +grep 'rsc.io/quote' go.mod + +# Tidying the module should preserve those dependencies. +go mod tidy +grep 'rsc.io/quote' go.mod + +[short] stop + +# Vendoring the module's dependencies should work too. +go mod vendor +exists vendor/rsc.io/quote + +# The same should work in directories with names starting with underscores. +cd $WORK/_ignored +go mod init testdata.tld/foo + +go get +grep 'rsc.io/quote' go.mod + +go mod tidy +grep 'rsc.io/quote' go.mod + +go mod vendor +exists vendor/rsc.io/quote + +-- $WORK/testdata/main.go -- +package foo + +import _ "rsc.io/quote" +-- $WORK/_ignored/main.go -- +package foo + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_indirect.txt b/src/cmd/go/testdata/script/mod_indirect.txt new file mode 100644 index 0000000..6ea1cae --- /dev/null +++ b/src/cmd/go/testdata/script/mod_indirect.txt @@ -0,0 +1,81 @@ +env GO111MODULE=on + +# golang.org/issue/31248: required modules imposed by dependency versions +# older than the selected version must still be taken into account. + +env GOFLAGS=-mod=readonly + +# Indirect dependencies required via older-than-selected versions must exist in +# the module graph, but do not need to be listed explicitly in the go.mod file +# (since they are implied). +go mod graph +stdout i@v0.1.0 + +# The modules must also appear in the build list, not just the graph. +go list -m all +stdout '^i v0.1.0' + +# The packages provided by those dependencies must resolve. +go list all +stdout '^i$' + +-- go.mod -- +module main + +go 1.13 + +require ( + a v0.0.0 + b v0.0.0 + c v0.0.0 +) + +// Apply replacements so that the test can be self-contained. +// (It's easier to see all of the modules here than to go +// rooting around in testdata/mod.) +replace ( + a => ./a + b => ./b + c => ./c + x v0.1.0 => ./x1 + x v0.2.0 => ./x2 + i => ./i +) +-- main.go -- +package main + +import ( + _ "a" + _ "b" + _ "c" +) + +func main() {} +-- a/go.mod -- +module a +go 1.13 +require x v0.1.0 +-- a/a.go -- +package a +-- b/go.mod -- +module b +go 1.13 +require x v0.2.0 +-- b/b.go -- +package b +-- c/go.mod -- +module c +go 1.13 +-- c/c.go -- +package c +import _ "i" +-- x1/go.mod -- +module x +go1.13 +require i v0.1.0 +-- x2/go.mod -- +module x +go1.13 +-- i/go.mod -- +-- i/i.go -- +package i diff --git a/src/cmd/go/testdata/script/mod_indirect_main.txt b/src/cmd/go/testdata/script/mod_indirect_main.txt new file mode 100644 index 0000000..e84eb9c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_indirect_main.txt @@ -0,0 +1,66 @@ +env GO111MODULE=on + +# Regression test for golang.org/issue/29773: 'go list -m' was not following +# dependencies through older versions of the main module. + +go list -f '{{with .Module}}{{.Path}}{{with .Version}} {{.}}{{end}}{{end}}' all +cmp stdout pkgmods.txt + +go list -m all +cmp stdout mods.txt + +go mod graph +cmp stdout graph.txt + +-- go.mod -- +module golang.org/issue/root + +go 1.12 + +replace ( + golang.org/issue/mirror v0.1.0 => ./mirror-v0.1.0 + golang.org/issue/pkg v0.1.0 => ./pkg-v0.1.0 + golang.org/issue/root v0.1.0 => ./root-v0.1.0 +) + +require golang.org/issue/mirror v0.1.0 + +-- root.go -- +package root + +import _ "golang.org/issue/mirror" + +-- mirror-v0.1.0/go.mod -- +module golang.org/issue/mirror + +require golang.org/issue/root v0.1.0 + +-- mirror-v0.1.0/mirror.go -- +package mirror + +import _ "golang.org/issue/pkg" + +-- pkg-v0.1.0/go.mod -- +module golang.org/issue/pkg + +-- pkg-v0.1.0/pkg.go -- +package pkg + +-- root-v0.1.0/go.mod -- +module golang.org/issue/root + +require golang.org/issue/pkg v0.1.0 + +-- pkgmods.txt -- +golang.org/issue/mirror v0.1.0 +golang.org/issue/pkg v0.1.0 +golang.org/issue/root +-- mods.txt -- +golang.org/issue/root +golang.org/issue/mirror v0.1.0 => ./mirror-v0.1.0 +golang.org/issue/pkg v0.1.0 => ./pkg-v0.1.0 +-- graph.txt -- +golang.org/issue/root go@1.12 +golang.org/issue/root golang.org/issue/mirror@v0.1.0 +golang.org/issue/mirror@v0.1.0 golang.org/issue/root@v0.1.0 +golang.org/issue/root@v0.1.0 golang.org/issue/pkg@v0.1.0 diff --git a/src/cmd/go/testdata/script/mod_indirect_nospace.txt b/src/cmd/go/testdata/script/mod_indirect_nospace.txt new file mode 100644 index 0000000..f4fb6a8 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_indirect_nospace.txt @@ -0,0 +1,32 @@ +# https://golang.org/issue/45932: "indirect" comments missing spaces +# should not be corrupted when the comment is removed. + +go mod tidy +cmp go.mod go.mod.direct + +-- go.mod -- +module example.net/m + +go 1.16 + +require example.net/x v0.1.0 //indirect + +replace example.net/x v0.1.0 => ./x +-- go.mod.direct -- +module example.net/m + +go 1.16 + +require example.net/x v0.1.0 + +replace example.net/x v0.1.0 => ./x +-- m.go -- +package m +import _ "example.net/x" + +-- x/go.mod -- +module example.net/x + +go 1.16 +-- x/x.go -- +package x diff --git a/src/cmd/go/testdata/script/mod_indirect_tidy.txt b/src/cmd/go/testdata/script/mod_indirect_tidy.txt new file mode 100644 index 0000000..a12b35c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_indirect_tidy.txt @@ -0,0 +1,60 @@ +env GO111MODULE=on + +# golang.org/issue/31248: loading the build list must not add explicit entries +# for indirect dependencies already implied by older-than-selected versions +# already in the build list. + +cp go.mod.orig go.mod +go mod tidy +cmp go.mod go.mod.orig + +cp go.mod.orig go.mod +go list -m all +cmp go.mod go.mod.orig + +-- go.mod.orig -- +module main + +go 1.13 + +require a v0.0.0 + +replace ( + a v0.0.0 => ./a + b v0.0.0 => ./b + i v0.0.0 => ./i + x v0.1.0 => ./x1 + x v0.2.0 => ./x2 +) +-- main.go -- +package main + +import _ "a" + +func main() {} +-- a/go.mod -- +module a +go 1.13 +require ( + x v0.2.0 + b v0.0.0 +) +-- a/a.go -- +package a +-- b/go.mod -- +module b +go 1.13 +require x v0.1.0 +-- x1/go.mod -- +module x +go 1.13 +require ( + b v0.0.0 + i v0.0.0 +) +-- x2/go.mod -- +module x +go 1.13 +-- i/go.mod -- +module i +go 1.13 diff --git a/src/cmd/go/testdata/script/mod_init_empty.txt b/src/cmd/go/testdata/script/mod_init_empty.txt new file mode 100644 index 0000000..d197a79 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_init_empty.txt @@ -0,0 +1,21 @@ +env GO111MODULE=on + +env GOPATH=$WORK${/}invalid-gopath + +go list -m +stdout '^example.com$' + +go list +stdout '^example.com$' + +-- go.mod -- +module example.com + +go 1.13 +-- main.go -- +package main + +func main() {} + +-- $WORK/invalid-gopath +This is a text file, not a directory. diff --git a/src/cmd/go/testdata/script/mod_init_invalid_major.txt b/src/cmd/go/testdata/script/mod_init_invalid_major.txt new file mode 100644 index 0000000..ae93e70 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_init_invalid_major.txt @@ -0,0 +1,82 @@ +env GO111MODULE=on +env GOFLAGS=-mod=mod + +! go mod init example.com/user/repo/v0 +stderr '(?s)^go: invalid module path "example.com/user/repo/v0": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$' + +! go mod init example.com/user/repo/v02 +stderr '(?s)^go: invalid module path "example.com/user/repo/v02": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$' + +! go mod init example.com/user/repo/v023 +stderr '(?s)^go: invalid module path "example.com/user/repo/v023": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v23$' + +! go mod init example.com/user/repo/v1 +stderr '(?s)^go: invalid module path "example.com/user/repo/v1": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$' + +! go mod init example.com/user/repo/v2.0 +stderr '(?s)^go: invalid module path "example.com/user/repo/v2.0": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$' + +! go mod init example.com/user/repo/v2.1.4 +stderr '(?s)^go: invalid module path "example.com/user/repo/v2.1.4": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$' + +! go mod init example.com/user/repo/v3.5 +stderr '(?s)^go: invalid module path "example.com/user/repo/v3.5": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v3$' + +! go mod init example.com/user/repo/v4.1.4 +stderr '(?s)^go: invalid module path "example.com/user/repo/v4.1.4": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v4$' + +! go mod init example.com/user/repo/v.2.3 +stderr '(?s)^go: invalid module path "example.com/user/repo/v.2.3": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$' + +! go mod init example.com/user/repo/v.5.3 +stderr '(?s)^go: invalid module path "example.com/user/repo/v.5.3": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v5$' + +! go mod init gopkg.in/pkg +stderr '(?s)^go: invalid module path "gopkg.in/pkg": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/pkg.v1$' + +! go mod init gopkg.in/user/pkg +stderr '(?s)^go: invalid module path "gopkg.in/user/pkg": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$' + +! go mod init gopkg.in/user/pkg/v0 +stderr '(?s)^go: invalid module path "gopkg.in/user/pkg/v0": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$' + +! go mod init gopkg.in/user/pkg/v1 +stderr '(?s)^go: invalid module path "gopkg.in/user/pkg/v1": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$' + +! go mod init gopkg.in/user/pkg/v2 +stderr '(?s)^go: invalid module path "gopkg.in/user/pkg/v2": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v2$' + +! go mod init gopkg.in/user/pkg.v +stderr '(?s)^go: invalid module path "gopkg.in/user/pkg.v": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$' + +! go mod init gopkg.in/user/pkg.v0.1 +stderr '(?s)^go: invalid module path "gopkg.in/user/pkg.v0.1": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$' + +! go mod init gopkg.in/user/pkg.v.1 +stderr '(?s)^go: invalid module path "gopkg.in/user/pkg.v.1": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$' + +! go mod init gopkg.in/user/pkg.v01 +stderr '(?s)^go: invalid module path "gopkg.in/user/pkg.v01": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$' + +! go mod init gopkg.in/user/pkg.v.2.3 +stderr '(?s)^go: invalid module path "gopkg.in/user/pkg.v.2.3": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v2$' + +# module paths with a trailing dot are rejected as invalid import paths +! go mod init example.com/user/repo/v2. +stderr '(?s)^go: malformed module path "example.com/user/repo/v2.": trailing dot in path element$' + +! go mod init example.com/user/repo/v2.. +stderr '(?s)^go: malformed module path "example.com/user/repo/v2..": trailing dot in path element$' + +! go mod init gopkg.in/user/pkg.v.2. +stderr '(?s)^go: malformed module path "gopkg.in/user/pkg.v.2.": trailing dot in path element$' + +! go mod init gopkg.in/user/pkg.v.2.. +stderr '(?s)^go: malformed module path "gopkg.in/user/pkg.v.2..": trailing dot in path element$' + +# module paths with spaces are also rejected +! go mod init 'foo bar' +stderr '(?s)^go: malformed module path "foo bar": invalid char '' ''$' + +! go mod init 'foo bar baz' +stderr '(?s)^go: malformed module path "foo bar baz": invalid char '' ''$' diff --git a/src/cmd/go/testdata/script/mod_init_path.txt b/src/cmd/go/testdata/script/mod_init_path.txt new file mode 100644 index 0000000..e5fd4dd --- /dev/null +++ b/src/cmd/go/testdata/script/mod_init_path.txt @@ -0,0 +1,20 @@ +env GO111MODULE=on + +! go mod init . +stderr '^go: malformed module path ".": is a local import path$' + +cd x +go mod init example.com/x + +cd ../y +go mod init m + +-- x/main.go -- +package main + +func main() {} + +-- y/main.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/mod_init_tidy.txt b/src/cmd/go/testdata/script/mod_init_tidy.txt new file mode 100644 index 0000000..4a52590 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_init_tidy.txt @@ -0,0 +1,30 @@ +# 'go mod init' should not recommend 'go mod tidy' in an empty directory +# (one that contains no non-hidden .go files or subdirectories). +cd empty +go mod init m +! stderr tidy +cd .. + +# 'go mod init' should recommend 'go mod tidy' if the directory has a .go file. +cd pkginroot +go mod init m +stderr '^go: to add module requirements and sums:\n\tgo mod tidy$' +cd .. + +# 'go mod init' should recommend 'go mod tidy' if the directory has a +# subdirectory. We don't walk the tree to see if it has .go files. +cd subdir +go mod init m +stderr '^go: to add module requirements and sums:\n\tgo mod tidy$' +cd .. + +-- empty/empty.txt -- +Not a .go file. Still counts as an empty project. +-- empty/.hidden/empty.go -- +File in hidden directory. Still as an empty project. +-- empty/_hidden/empty.go -- +File in hidden directory. Still as an empty project. +-- pkginroot/hello.go -- +package vendorimport +-- subdir/sub/empty.txt -- +Subdirectory doesn't need to contain a package. diff --git a/src/cmd/go/testdata/script/mod_insecure_issue63845.txt b/src/cmd/go/testdata/script/mod_insecure_issue63845.txt new file mode 100644 index 0000000..c051c05 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_insecure_issue63845.txt @@ -0,0 +1,28 @@ +# Regression test for https://go.dev/issue/63845: +# If 'git ls-remote' fails for all secure protocols, +# we should fail instead of falling back to an arbitrary protocol. +# +# Note that this test does not use the local vcweb test server +# (vcs-test.golang.org), because the hook for redirecting to that +# server bypasses the "ping to determine protocol" logic +# in cmd/go/internal/vcs. + +[!net:golang.org] skip +[!git] skip +[short] skip 'tries to access a nonexistent external Git repo' + +env GOPRIVATE=golang.org +env CURLOPT_TIMEOUT_MS=100 +env GIT_SSH_COMMAND=false + +! go get -x golang.org/nonexist.git@latest +stderr '^git ls-remote https://golang.org/nonexist$' +stderr '^git ls-remote git\+ssh://golang.org/nonexist' +stderr '^git ls-remote ssh://golang.org/nonexist$' +! stderr 'git://' +stderr '^go: golang.org/nonexist.git@latest: no secure protocol found for repository$' + +-- go.mod -- +module example + +go 1.19 diff --git a/src/cmd/go/testdata/script/mod_install_hint.txt b/src/cmd/go/testdata/script/mod_install_hint.txt new file mode 100644 index 0000000..ab02840 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_install_hint.txt @@ -0,0 +1,5 @@ +# Module is replaced but not required. No hint appears as no module is suggested.
+go mod init m
+go mod edit -replace=github.com/notrequired@v0.5.0=github.com/doesnotexist@v0.5.0
+! go install github.com/notrequired
+! stderr 'to add it:'
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/mod_install_pkg_version.txt b/src/cmd/go/testdata/script/mod_install_pkg_version.txt new file mode 100644 index 0000000..89dfc14 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_install_pkg_version.txt @@ -0,0 +1,204 @@ +# 'go install pkg@version' works outside a module. +env GO111MODULE=auto +go install example.com/cmd/a@v1.0.0 +exists $GOPATH/bin/a$GOEXE +rm $GOPATH/bin + + +# 'go install pkg@version' reports an error if modules are disabled. +env GO111MODULE=off +! go install example.com/cmd/a@v1.0.0 +stderr '^go: modules disabled by GO111MODULE=off; see ''go help modules''$' +env GO111MODULE=auto + + +# 'go install pkg@version' ignores go.mod in current directory. +cd m +cp go.mod go.mod.orig +! go list -m all +stderr '^go: example.com/cmd@v1.1.0-doesnotexist: reading http.*/mod/example.com/cmd/@v/v1.1.0-doesnotexist.info: 404 Not Found\n\tserver response: 404 page not found$' +stderr '^go: example.com/cmd@v1.1.0-doesnotexist: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/cmd$' +go install example.com/cmd/a@latest +cmp go.mod go.mod.orig +exists $GOPATH/bin/a$GOEXE +go version -m $GOPATH/bin/a$GOEXE +stdout '^\tmod\texample.com/cmd\tv1.0.0\t' # "latest", not from go.mod +rm $GOPATH/bin/a +cd .. + + +# 'go install -modfile=x.mod pkg@version' reports an error, but only if +# -modfile is specified explicitly on the command line. +cd m +env GOFLAGS=-modfile=go.mod +go install example.com/cmd/a@latest # same as above +env GOFLAGS= +! go install -modfile=go.mod example.com/cmd/a@latest +stderr '^go: -modfile cannot be used with commands that ignore the current module$' +cd .. + + +# Every test case requires linking, so we only cover the most important cases +# when -short is set. +[short] stop + + +# 'go install pkg@version' works on a module that doesn't have a go.mod file +# and with a module whose go.mod file has missing requirements. +# With a proxy, the two cases are indistinguishable. +go install rsc.io/fortune@v1.0.0 +stderr '^go: found rsc.io/quote in rsc.io/quote v1.5.2$' +exists $GOPATH/bin/fortune$GOEXE +! exists $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0/go.mod # no go.mod file +go version -m $GOPATH/bin/fortune$GOEXE +stdout '^\tdep\trsc.io/quote\tv1.5.2\t' # latest version of fortune's dependency +rm $GOPATH/bin + + +# 'go install dir@version' works like a normal 'go install' command if +# dir is a relative or absolute path. +env GO111MODULE=on +go mod download rsc.io/fortune@v1.0.0 +! go install $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0 +stderr '^go: go\.mod file not found in current directory or any parent directory; see ''go help modules''$' +! go install ../pkg/mod/rsc.io/fortune@v1.0.0 +stderr '^go: go\.mod file not found in current directory or any parent directory; see ''go help modules''$' +mkdir tmp +cd tmp +go mod init tmp +go mod edit -require=rsc.io/fortune@v1.0.0 +! go install -mod=readonly $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0 +stderr '^missing go\.sum entry for module providing package rsc\.io/fortune; to add:\n\tgo mod download rsc\.io/fortune$' +! go install -mod=readonly ../../pkg/mod/rsc.io/fortune@v1.0.0 +stderr '^missing go\.sum entry for module providing package rsc\.io/fortune; to add:\n\tgo mod download rsc\.io/fortune$' +go get rsc.io/fortune@v1.0.0 +go install -mod=readonly $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0 +exists $GOPATH/bin/fortune$GOEXE +cd .. +rm tmp +rm $GOPATH/bin +env GO111MODULE=auto + +# 'go install pkg@version' reports errors for meta packages, std packages, +# and directories. +! go install std@v1.0.0 +stderr '^go: std@v1.0.0: argument must be a package path, not a meta-package$' +! go install fmt@v1.0.0 +stderr '^go: fmt@v1.0.0: argument must not be a package in the standard library$' +! go install example.com//cmd/a@v1.0.0 +stderr '^go: example.com//cmd/a@v1.0.0: argument must be a clean package path$' +! go install example.com/cmd/a@v1.0.0 ./x@v1.0.0 +stderr '^go: ./x@v1.0.0: argument must be a package path, not a relative path$' +! go install example.com/cmd/a@v1.0.0 $GOPATH/src/x@v1.0.0 +stderr '^go: '$WORK'[/\\]gopath/src/x@v1.0.0: argument must be a package path, not an absolute path$' +! go install example.com/cmd/a@v1.0.0 cmd/...@v1.0.0 +stderr '^package cmd/go not provided by module example.com/cmd@v1.0.0$' + +# 'go install pkg@version' should accept multiple arguments but report an error +# if the version suffixes are different, even if they refer to the same version. +go install example.com/cmd/a@v1.0.0 example.com/cmd/b@v1.0.0 +exists $GOPATH/bin/a$GOEXE +exists $GOPATH/bin/b$GOEXE +rm $GOPATH/bin + +env GO111MODULE=on +go list -m example.com/cmd@latest +stdout '^example.com/cmd v1.0.0$' +env GO111MODULE=auto + +! go install example.com/cmd/a@v1.0.0 example.com/cmd/b@latest +stderr '^go: example.com/cmd/b@latest: all arguments must refer to packages in the same module at the same version \(@v1.0.0\)$' + + +# 'go install pkg@version' should report an error if the arguments are in +# different modules. +! go install example.com/cmd/a@v1.0.0 rsc.io/fortune@v1.0.0 +stderr '^package rsc.io/fortune provided by module rsc.io/fortune@v1.0.0\n\tAll packages must be provided by the same module \(example.com/cmd@v1.0.0\).$' + + +# 'go install pkg@version' should report an error if an argument is not +# a main package. +! go install example.com/cmd/a@v1.0.0 example.com/cmd/err@v1.0.0 +stderr '^package example.com/cmd/err is not a main package$' + +# Wildcards should match only main packages. This module has a non-main package +# with an error, so we'll know if that gets built. +mkdir tmp +cd tmp +go mod init m +go get example.com/cmd@v1.0.0 +! go build example.com/cmd/... +stderr 'err[/\\]err.go:3:9: undefined: DoesNotCompile( .*)?$' +cd .. + +go install example.com/cmd/...@v1.0.0 +exists $GOPATH/bin/a$GOEXE +exists $GOPATH/bin/b$GOEXE +rm $GOPATH/bin + +# If a wildcard matches no packages, we should see a warning. +! go install example.com/cmd/nomatch...@v1.0.0 +stderr '^go: example.com/cmd/nomatch\.\.\.@v1.0.0: module example.com/cmd@v1.0.0 found, but does not contain packages matching example.com/cmd/nomatch\.\.\.$' +go install example.com/cmd/a@v1.0.0 example.com/cmd/nomatch...@v1.0.0 +stderr '^go: warning: "example.com/cmd/nomatch\.\.\." matched no packages$' + +# If a wildcard matches only non-main packages, we should see a different warning. +go install example.com/cmd/err...@v1.0.0 +stderr '^go: warning: "example.com/cmd/err\.\.\." matched only non-main packages$' + + +# 'go install pkg@version' should report errors if the module contains +# replace or exclude directives. +go mod download example.com/cmd@v1.0.0-replace +! go install example.com/cmd/a@v1.0.0-replace +cmp stderr replace-err + +go mod download example.com/cmd@v1.0.0-exclude +! go install example.com/cmd/a@v1.0.0-exclude +cmp stderr exclude-err + +# 'go install pkg@version' should report an error if the module requires a +# higher version of itself. +! go install example.com/cmd/a@v1.0.0-newerself +stderr '^go: example.com/cmd/a@v1.0.0-newerself: version constraints conflict:\n\texample.com/cmd@v1.0.0-newerself requires example.com/cmd@v1.0.0, but v1.0.0-newerself is requested$' + + +# 'go install pkg@version' will only match a retracted version if it's +# explicitly requested. +env GO111MODULE=on +go list -m -versions example.com/cmd +! stdout v1.9.0 +go list -m -versions -retracted example.com/cmd +stdout v1.9.0 +go install example.com/cmd/a@latest +go version -m $GOPATH/bin/a$GOEXE +stdout '^\tmod\texample.com/cmd\tv1.0.0\t' +go install example.com/cmd/a@v1.9.0 +go version -m $GOPATH/bin/a$GOEXE +stdout '^\tmod\texample.com/cmd\tv1.9.0\t' +env GO111MODULE= + +# 'go install pkg@version' succeeds when -mod=readonly is set explicitly. +# Verifies #43278. +go install -mod=readonly example.com/cmd/a@v1.0.0 + +-- m/go.mod -- +module m + +go 1.16 + +require example.com/cmd v1.1.0-doesnotexist +-- x/x.go -- +package main + +func main() {} +-- replace-err -- +go: example.com/cmd/a@v1.0.0-replace (in example.com/cmd@v1.0.0-replace): + The go.mod file for the module providing named packages contains one or + more replace directives. It must not contain directives that would cause + it to be interpreted differently than if it were the main module. +-- exclude-err -- +go: example.com/cmd/a@v1.0.0-exclude (in example.com/cmd@v1.0.0-exclude): + The go.mod file for the module providing named packages contains one or + more exclude directives. It must not contain directives that would cause + it to be interpreted differently than if it were the main module. diff --git a/src/cmd/go/testdata/script/mod_install_versioned.txt b/src/cmd/go/testdata/script/mod_install_versioned.txt new file mode 100644 index 0000000..627a9a8 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_install_versioned.txt @@ -0,0 +1,14 @@ +env GO111MODULE=on + +go get rsc.io/fortune +go list -f '{{.Target}}' rsc.io/fortune +! stdout fortune@v1 +stdout 'fortune(\.exe)?$' + +go get rsc.io/fortune/v2 +go list -f '{{.Target}}' rsc.io/fortune/v2 +! stdout v2 +stdout 'fortune(\.exe)?$' + +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/mod_internal.txt b/src/cmd/go/testdata/script/mod_internal.txt new file mode 100644 index 0000000..787b21f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_internal.txt @@ -0,0 +1,96 @@ +env GO111MODULE=on +[short] skip + +# golang.org/x/internal should be importable from other golang.org/x modules. +go mod edit -module=golang.org/x/anything +go get . + +# ...and their tests... +go test +stdout PASS + +# ...but that should not leak into other modules. +go get ./baddep +! go build ./baddep +stderr golang.org[/\\]notx[/\\]useinternal +stderr 'use of internal package golang.org/x/.* not allowed' + +# Internal packages in the standard library should not leak into modules. +go get ./fromstd +! go build ./fromstd +stderr 'use of internal package internal/testenv not allowed' + +# Dependencies should be able to use their own internal modules... +go mod edit -module=golang.org/notx +go get ./throughdep + +# ... but other modules should not, even if they have transitive dependencies. +go get . +! go build . +stderr 'use of internal package golang.org/x/.* not allowed' + +# And transitive dependencies still should not leak. +go get ./baddep +! go build ./baddep +stderr golang.org[/\\]notx[/\\]useinternal +stderr 'use of internal package golang.org/x/.* not allowed' + +# Replacing an internal module should keep it internal to the same paths. +go mod edit -module=golang.org/notx +go mod edit -replace golang.org/x/internal=./replace/golang.org/notx/internal +go get ./throughdep + +go get ./baddep +! go build ./baddep +stderr golang.org[/\\]notx[/\\]useinternal +stderr 'use of internal package golang.org/x/.* not allowed' + +go mod edit -replace golang.org/x/internal=./vendor/golang.org/x/internal +go get ./throughdep + +go get ./baddep +! go build ./baddep +stderr golang.org[/\\]notx[/\\]useinternal +stderr 'use of internal package golang.org/x/.* not allowed' + +-- go.mod -- +module TBD +go 1.12 +-- useinternal.go -- +package useinternal +import _ "golang.org/x/internal/subtle" + +-- useinternal_test.go -- +package useinternal_test +import ( + "testing" + _ "golang.org/x/internal/subtle" +) + +func Test(*testing.T) {} + +-- throughdep/useinternal.go -- +package throughdep +import _ "golang.org/x/useinternal" + +-- baddep/useinternal.go -- +package baddep +import _ "golang.org/notx/useinternal" + +-- fromstd/useinternal.go -- +package fromstd +import _ "internal/testenv" + +-- replace/golang.org/notx/internal/go.mod -- +module golang.org/x/internal + +-- replace/golang.org/notx/internal/subtle/subtle.go -- +package subtle +// Ha ha! Nothing here! + +-- vendor/golang.org/x/internal/go.mod -- +module golang.org/x/internal + +-- vendor/golang.org/x/internal/subtle/subtle.go -- +package subtle +// Ha ha! Nothing here! diff --git a/src/cmd/go/testdata/script/mod_invalid_path.txt b/src/cmd/go/testdata/script/mod_invalid_path.txt new file mode 100644 index 0000000..975de5e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_invalid_path.txt @@ -0,0 +1,61 @@ +# Test that mod files with invalid or missing paths produce an error. + +# Test that go list fails on a go.mod with no module declaration. +cd $WORK/gopath/src/mod +! go list . +stderr '^go: error reading go.mod: missing module declaration. To specify the module path:\n\tgo mod edit -module=example.com/mod$' + +# Test that go mod init in GOPATH doesn't add a module declaration +# with a path that can't possibly be a module path, because +# it isn't even a valid import path. +# The single quote and backtick are the only characters which are not allowed +# but are a valid Windows file name. +cd $WORK/'gopath/src/m''d' +! go mod init +stderr 'cannot determine module path' + +# Test that a go.mod file is rejected when its module declaration has a path that can't +# possibly be a module path, because it isn't even a valid import path +cd $WORK/gopath/src/badname +! go list . +stderr 'malformed module path' + +# Test that an import path containing an element with a leading dot is valid, +# but such a module path is not. +# Verifies #43985. +cd $WORK/gopath/src/dotname +go list ./.dot +stdout '^example.com/dotname/.dot$' +go list ./use +stdout '^example.com/dotname/use$' +! go list -m example.com/dotname/.dot@latest +stderr '^go: example.com/dotname/.dot@latest: malformed module path "example.com/dotname/.dot": leading dot in path element$' +go get example.com/dotname/.dot +go get example.com/dotname/use +go mod tidy + +-- mod/go.mod -- + +-- mod/foo.go -- +package foo + +-- m'd/foo.go -- +package mad + +-- badname/go.mod -- + +module .\. + +-- badname/foo.go -- +package badname + +-- dotname/go.mod -- +module example.com/dotname + +go 1.16 +-- dotname/.dot/dot.go -- +package dot +-- dotname/use/use.go -- +package use + +import _ "example.com/dotname/.dot" diff --git a/src/cmd/go/testdata/script/mod_invalid_path_dotname.txt b/src/cmd/go/testdata/script/mod_invalid_path_dotname.txt new file mode 100644 index 0000000..484c208 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_invalid_path_dotname.txt @@ -0,0 +1,46 @@ +# Test that an import path containing an element with a leading dot +# in another module is valid. + +# 'go get' works with no version query. +cp go.mod.empty go.mod +go get example.com/dotname/.dot +go list -m example.com/dotname +stdout '^example.com/dotname v1.0.0$' + +# 'go get' works with a version query. +cp go.mod.empty go.mod +go get example.com/dotname/.dot@latest +go list -m example.com/dotname +stdout '^example.com/dotname v1.0.0$' + +# 'go get' works on an importing package. +cp go.mod.empty go.mod +go get . +go list -m example.com/dotname +stdout '^example.com/dotname v1.0.0$' + +# 'go list' works on the dotted package. +go list example.com/dotname/.dot +stdout '^example.com/dotname/.dot$' + +# 'go list' works on an importing package. +go list . +stdout '^m$' + +# 'go mod tidy' works. +cp go.mod.empty go.mod +go mod tidy +go list -m example.com/dotname +stdout '^example.com/dotname v1.0.0$' + +-- go.mod.empty -- +module m + +go 1.16 +-- go.sum -- +example.com/dotname v1.0.0 h1:Q0JMAn464CnwFVCshs1n4+f5EFiW/eRhnx/fTWjw2Ag= +example.com/dotname v1.0.0/go.mod h1:7K4VLT7QylRI8H7yZwUkeDH2s19wQnyfp/3oBlItWJ0= +-- use.go -- +package use + +import _ "example.com/dotname/.dot" diff --git a/src/cmd/go/testdata/script/mod_invalid_path_plus.txt b/src/cmd/go/testdata/script/mod_invalid_path_plus.txt new file mode 100644 index 0000000..dd59eb1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_invalid_path_plus.txt @@ -0,0 +1,36 @@ +# https://golang.org/issue/44776 +# The '+' character should be disallowed in module paths, but allowed in package +# paths within valid modules. + +# 'go list' accepts package paths with pluses. +cp go.mod.orig go.mod +go get example.net/cmd +go list example.net/cmd/x++ + +# 'go list -m' rejects module paths with pluses. +! go list -versions -m 'example.net/bad++' +stderr '^go: malformed module path "example.net/bad\+\+": invalid char ''\+''$' + +# 'go get' accepts package paths with pluses. +cp go.mod.orig go.mod +go get example.net/cmd/x++ +go list -m example.net/cmd +stdout '^example.net/cmd v0.0.0-00010101000000-000000000000 => ./cmd$' + +-- go.mod.orig -- +module example.com/m + +go 1.16 + +replace ( + example.net/cmd => ./cmd +) + +-- cmd/go.mod -- +module example.net/cmd + +go 1.16 +-- cmd/x++/main.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/mod_invalid_version.txt b/src/cmd/go/testdata/script/mod_invalid_version.txt new file mode 100644 index 0000000..a0427b3 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_invalid_version.txt @@ -0,0 +1,253 @@ +[!net:golang.org] skip +[!git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off +env GOFLAGS=-mod=mod + +# Regression test for golang.org/issue/27173: if the user (or go.mod file) +# requests a pseudo-version that does not match both the module path and commit +# metadata, reject it with a helpful error message. +# +# TODO(bcmills): Replace the github.com/pierrec/lz4 examples with something +# equivalent on vcs-test.golang.org. + +# An incomplete commit hash is not a valid semantic version, +# but can appear in the main go.mod file anyway and should be resolved. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ..[/\\]go.mod: '$WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "14c0d48ead0c" invalid: must be of the form v1.2.3' +cd .. +go list -m golang.org/x/text +stdout 'golang.org/x/text v0.1.1-0.20170915032832-14c0d48ead0c' +grep 'golang.org/x/text v0.1.1-0.20170915032832-14c0d48ead0c' go.mod + +# A module path below the repo root that does not contain a go.mod file is invalid. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text/unicode@v0.0.0-20170915032832-14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text/unicode@v0.0.0-20170915032832-14c0d48ead0c: invalid version: missing golang.org/x/text/unicode/go.mod at revision 14c0d48ead0c' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text/unicode@v0.0.0-20170915032832-14c0d48ead0c: invalid version: missing golang.org/x/text/unicode/go.mod at revision 14c0d48ead0c' + +# However, arguments to 'go get' can name packages above the root. +cp go.mod.orig go.mod +go get golang.org/x/text/unicode@v0.0.0-20170915032832-14c0d48ead0c +go list -m golang.org/x/text/... +stdout 'golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c' +! stdout 'golang.org/x/text/unicode' + +# A major version that does not match the module path is invalid. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v2.1.1-0.20170915032832-14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ..[/\\]go.mod: '$WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2' +cd .. +! go list -m golang.org/x/text +stderr '^go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2' + +# A pseudo-version with fewer than 12 digits of SHA-1 prefix is invalid. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0 +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0: invalid pseudo-version: revision is shorter than canonical \(expected 14c0d48ead0c\)' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0: invalid pseudo-version: revision is shorter than canonical \(expected 14c0d48ead0c\)' + +# A pseudo-version with more than 12 digits of SHA-1 prefix is invalid. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0cd47e3104ada247d91be04afc7a5a +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0cd47e3104ada247d91be04afc7a5a: invalid pseudo-version: revision is longer than canonical \(expected 14c0d48ead0c\)' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0cd47e3104ada247d91be04afc7a5a: invalid pseudo-version: revision is longer than canonical \(expected 14c0d48ead0c\)' + +# A pseudo-version that does not match the commit timestamp is invalid. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(expected 20170915032832\)' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(expected 20170915032832\)' + +# A 'replace' directive in the main module can replace an invalid timestamp +# with a valid one. +go mod edit -replace golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c=golang.org/x/text@14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(expected 20170915032832\)' +cd .. +go list -m golang.org/x/text +stdout 'golang.org/x/text v0.1.1-0.20190915032832-14c0d48ead0c => golang.org/x/text v0.1.1-0.20170915032832-14c0d48ead0c' + +# A pseudo-version that is not derived from a tag is invalid. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v1.999.999-0.20170915032832-14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v1.999.999-0.20170915032832-14c0d48ead0c: invalid pseudo-version: preceding tag \(v1.999.998\) not found' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v1.999.999-0.20170915032832-14c0d48ead0c: invalid pseudo-version: preceding tag \(v1.999.998\) not found' + +# A v1.0.0- pseudo-version that is not derived from a tag is invalid: +# v1.0.0- implies no tag, but the correct no-tag prefix for a module path +# without a major-version suffix is v0.0.0-. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v1.0.0-20170915032832-14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v1.0.0-20170915032832-14c0d48ead0c: invalid pseudo-version: major version without preceding tag must be v0, not v1' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v1.0.0-20170915032832-14c0d48ead0c: invalid pseudo-version: major version without preceding tag must be v0, not v1' + +# A pseudo-version vX.Y.Z+1 cannot have Z+1 == 0, since that would +# imply a base tag with a negative patch field. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c: invalid pseudo-version: version before v0.0.0 would have negative patch number' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c: invalid pseudo-version: version before v0.0.0 would have negative patch number' + +# A 'replace' directive in the main module can replace an +# invalid pseudo-version base with a valid one. +go mod edit -replace golang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c=golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c: invalid pseudo-version: version before v0.0.0 would have negative patch number' +cd .. +go list -m golang.org/x/text +stdout 'golang.org/x/text v0.0.0-0.20170915032832-14c0d48ead0c => golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c' + +# A 'replace' directive can replace an invalid 'latest' version, and +# should suppress errors for that version in 'go get -u' +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v1.999999.0 +go mod edit -replace golang.org/x/text@v1.999999.0=golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c +cd outside +! go get golang.org/x/text@upgrade +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v1.999999.0: reading golang.org/x/text/go.mod at revision v1.999999.0: unknown revision v1.999999.0' +cd .. +go get golang.org/x/text@upgrade +go list -m golang.org/x/text +stdout 'golang.org/x/text v1.999999.0 => golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c' + +# A pseudo-version derived from a non-ancestor tag is invalid. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v0.2.1-0.20170915032832-14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.2.1-0.20170915032832-14c0d48ead0c: invalid pseudo-version: revision 14c0d48ead0c is not a descendent of preceding tag \(v0.2.0\)' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v0.2.1-0.20170915032832-14c0d48ead0c: invalid pseudo-version: revision 14c0d48ead0c is not a descendent of preceding tag \(v0.2.0\)' + +# A pseudo-version derived from a canonical tag on the same revision is invalid. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v0.2.1-0.20171213102548-c4d099d611ac +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.2.1-0.20171213102548-c4d099d611ac: invalid pseudo-version: tag \(v0.2.0\) found on revision c4d099d611ac is already canonical, so should not be replaced with a pseudo-version derived from that tag' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v0.2.1-0.20171213102548-c4d099d611ac: invalid pseudo-version: tag \(v0.2.0\) found on revision c4d099d611ac is already canonical, so should not be replaced with a pseudo-version derived from that tag' + +# A +incompatible suffix is not allowed on a version that is actually compatible. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0c+incompatible +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0c\+incompatible: invalid version: \+incompatible suffix not allowed: major version v0 is compatible' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0c\+incompatible: invalid version: \+incompatible suffix not allowed: major version v0 is compatible' + +[!net:github.com] stop + +# The pseudo-version for a commit after a tag with a non-matching major version +# should instead be based on the last matching tag. +cp go.mod.orig go.mod +go mod edit -require github.com/pierrec/lz4@473cd7ce01a1 +go list -m github.com/pierrec/lz4 +stdout 'github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1' +cd outside +go list -m github.com/pierrec/lz4 +stdout 'github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1' +cd .. + +# A +incompatible pseudo-version for a module that has an explicit go.mod file is invalid. +cp go.mod.orig go.mod +go mod edit -require github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d+incompatible +cd outside +! go list -m github.com/pierrec/lz4 +stderr '^go: example.com@v0.0.0 requires\n\tgithub.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$' +cd .. +! go list -m github.com/pierrec/lz4 +stderr '^go: github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$' + +# A +incompatible pseudo-version is valid for a revision of the module +# that lacks a go.mod file. +cp go.mod.orig go.mod +go mod edit -require github.com/pierrec/lz4@v2.0.4-0.20180826165652-dbe9298ce099+incompatible +cd outside +go list -m github.com/pierrec/lz4 +stdout 'github.com/pierrec/lz4 v2.0.4-0.20180826165652-dbe9298ce099\+incompatible' +cd .. +go list -m github.com/pierrec/lz4 +stdout 'github.com/pierrec/lz4 v2.0.4-0.20180826165652-dbe9298ce099\+incompatible' + +# 'go get' for a mismatched major version without a go.mod file should resolve +# to the equivalent +incompatible version, not a pseudo-version with a different +# major version. +cp go.mod.orig go.mod +go get github.com/pierrec/lz4@v2.0.5 +go list -m github.com/pierrec/lz4 +stdout 'github.com/pierrec/lz4 v2.0.5\+incompatible' + +# 'go get' for a mismatched major version with a go.mod file should error out, +# not resolve to a pseudo-version with a different major version. +cp go.mod.orig go.mod +! go get github.com/pierrec/lz4@v2.0.8 +stderr 'go: github.com/pierrec/lz4@v2.0.8: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$' + +# An invalid +incompatible suffix for a canonical version should error out, +# not resolve to a pseudo-version. +# +# TODO(bcmills): The "outside" view for this failure mode is missing its import stack. +# Figure out why and fix it. +cp go.mod.orig go.mod +go mod edit -require github.com/pierrec/lz4@v2.0.8+incompatible +cd outside +! go list -m github.com/pierrec/lz4 +stderr '^go: github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$' +cd .. +! go list -m github.com/pierrec/lz4 +stderr '^go: github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$' + +-- go.mod.orig -- +module example.com + +go 1.13 +-- outside/go.mod -- +module example.com/outside + +go 1.13 + +require example.com v0.0.0 +replace example.com v0.0.0 => ./.. diff --git a/src/cmd/go/testdata/script/mod_issue35270.txt b/src/cmd/go/testdata/script/mod_issue35270.txt new file mode 100644 index 0000000..27b9226 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_issue35270.txt @@ -0,0 +1,57 @@ + +cd a +! go build +stderr '^ambiguous import: found package image in multiple modules:\s+image\s+.+\s.+image.+\s$' + + +cd ../b +! go build -mod=vendor +stderr '^main.go:4:5: ambiguous import: found package image in multiple directories:\s+.+image\s+.+image\s+$' + +cd ../c +! go build -mod=vendor +stderr 'main.go:4:5: package p is not in std' + +-- a/go.mod -- +module image + +-- a/main.go -- +package main + +func main() { + println("hello world!") +} + +-- b/go.mod -- +module test + +-- b/vendor/image/b.go -- +package image +func Add(a, b int) int { + return a + b +} + +-- b/main.go -- +package main + +import ( + "image" +) + +func main() { + println(image.Add(1,1)) +} + +-- c/go.mod -- +module test + +-- c/main.go -- +package main + +import ( + "p" +) + +func main() { + println(p.Add(1,1)) +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/mod_issue35317.txt b/src/cmd/go/testdata/script/mod_issue35317.txt new file mode 100644 index 0000000..92416a5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_issue35317.txt @@ -0,0 +1,8 @@ +# Regression test for golang.org/issue/35317: +# 'go get' with multiple module-only arguments was racy. + +env GO111MODULE=on +[short] skip + +go mod init example.com +go get golang.org/x/text@v0.3.0 golang.org/x/internal@v0.1.0 golang.org/x/exp@none diff --git a/src/cmd/go/testdata/script/mod_lazy_consistency.txt b/src/cmd/go/testdata/script/mod_lazy_consistency.txt new file mode 100644 index 0000000..1bf3e31 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_lazy_consistency.txt @@ -0,0 +1,95 @@ +# If the root requirements in a lazy module are inconsistent +# (for example, due to a bad hand-edit or git merge), +# they can go unnoticed as long as the module with the violated +# requirement is not used. +# When we load a package from that module, we should spot-check its +# requirements and either emit an error or update the go.mod file. + +cp go.mod go.mod.orig + + +# If we load package x from x.1, we only check the requirements of x, +# which are fine: loading succeeds. + +go list -deps ./usex +stdout '^example.net/x$' +cmp go.mod go.mod.orig + + +# However, if we load needx2, we should load the requirements of needx2. +# Those requirements indicate x.2, not x.1, so the module graph is +# inconsistent and needs to be fixed. + +! go list -deps ./useneedx2 +stderr '^go: updates to go.mod needed; to update it:\n\tgo mod tidy$' + +! go list -deps example.net/needx2 +stderr '^go: updates to go.mod needed; to update it:\n\tgo mod tidy$' + + +# The command printed in the error message should fix the problem. + +go mod tidy +go list -deps ./useneedx2 +stdout '^example.net/m/useneedx2$' +stdout '^example.net/needx2$' +stdout '^example.net/x$' + +go list -m all +stdout '^example.net/needx2 v0\.1\.0 ' +stdout '^example.net/x v0\.2\.0 ' + + +-- go.mod -- +module example.net/m + +go 1.17 + +require ( + example.net/needx2 v0.1.0 + example.net/x v0.1.0 +) + +replace ( + example.net/needx2 v0.1.0 => ./needx2.1 + example.net/x v0.1.0 => ./x.1 + example.net/x v0.2.0 => ./x.2 +) +-- useneedx2/useneedx2.go -- +package useneedx2 + +import _ "example.net/needx2" +-- usex/usex.go -- +package usex + +import _ "example.net/x" + +-- x.1/go.mod -- +module example.com/x + +go 1.17 +-- x.1/x.go -- +package x + +-- x.2/go.mod -- +module example.com/x + +go 1.17 +-- x.2/x.go -- +package x + +const AddedInV2 = true + +-- needx2.1/go.mod -- +module example.com/x + +go 1.17 + +require example.net/x v0.2.0 +-- needx2.1/needx2.go -- +// Package needx2 needs x v0.2.0 or higher. +package needx2 + +import "example.net/x" + +var _ = x.AddedInV2 diff --git a/src/cmd/go/testdata/script/mod_lazy_downgrade.txt b/src/cmd/go/testdata/script/mod_lazy_downgrade.txt new file mode 100644 index 0000000..eb69d2e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_lazy_downgrade.txt @@ -0,0 +1,183 @@ +# This test illustrates the interaction between lazy loading and downgrading in +# 'go get'. + +# The package import graph used in this test looks like: +# +# lazy ---- a +# | +# a_test ---- b +# b_test ---- c +# +# The module dependency graph initially looks like: +# +# lazy ---- a.1 ---- b.1 ---- c.1 +# \ / +# b.3 ---- c.2 b.2 +# +# (Note that lazy loading will prune out the dependency from b.1 on c.1.) + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod.orig go.mod + +go list -m all +stdout '^example.com/a v0.1.0 ' +stdout '^example.com/b v0.3.0 ' +stdout '^example.com/c v0.2.0 ' + +# Downgrading c should also downgrade the b that requires it. + +go get example.com/c@v0.1.0 +go list -m all +stdout '^example.com/a v0.1.0 ' +stdout '^example.com/b v0.2.0 ' +stdout '^example.com/c v0.1.0 ' + +# Removing c entirely should also remove the a and b that require it. + +go get example.com/c@none +go list -m all +! stdout '^example.com/a ' +! stdout '^example.com/b ' +! stdout '^example.com/c ' + + +# With lazy loading, downgrading c should work the same way, but dependencies +# outside of the deepening scan should not affect the downgrade. + +cp go.mod.orig go.mod +go mod edit -go=1.17 + +go list -m all +stdout '^example.com/a v0.1.0 ' +stdout '^example.com/b v0.3.0 ' +stdout '^example.com/c v0.2.0 ' + +go get example.com/c@v0.1.0 +go list -m all +stdout '^example.com/a v0.1.0 ' +stdout '^example.com/b v0.2.0 ' +stdout '^example.com/c v0.1.0 ' + +# At this point, b.2 is still an explicit root, so its dependency on c +# is still tracked, and it will still be downgraded away if we remove c. +# ('go get' never makes a root into a non-root. Only 'go mod tidy' does that.) + +go get example.com/c@none +go list -m all +! stdout '^example.com/a ' +! stdout '^example.com/b ' +! stdout '^example.com/c ' + + +# This time, we drop the explicit 'b' root by downgrading it to v0.1.0 +# (the version required by a.1) and running 'go mod tidy'. +# It is still selected at v0.1.0 (as a dependency of a), +# but its dependency on c is now pruned from the module graph, so it doesn't +# result in any downgrades to b or a if we run 'go get c@none'. + +cp go.mod.orig go.mod +go mod edit -go=1.17 + +go list -m all +stdout '^example.com/a v0.1.0 ' +stdout '^example.com/b v0.3.0 ' +stdout '^example.com/c v0.2.0 ' + +go get example.com/c@v0.1.0 example.com/b@v0.1.0 +go list -m all +stdout '^example.com/a v0.1.0 ' +stdout '^example.com/b v0.1.0 ' +stdout '^example.com/c v0.1.0 ' + +go mod tidy +go list -m all +stdout '^example.com/a v0.1.0 ' +stdout '^example.com/b v0.1.0 ' +! stdout '^example.com/c ' + +go get example.com/c@none +go list -m all +stdout '^example.com/a v0.1.0' +stdout '^example.com/b v0.1.0' +! stdout '^example.com/c ' + + +-- go.mod -- +module example.com/lazy + +go 1.15 + +require ( + example.com/a v0.1.0 + example.com/b v0.3.0 // indirect +) + +replace ( + example.com/a v0.1.0 => ./a + example.com/b v0.1.0 => ./b1 + example.com/b v0.2.0 => ./b2 + example.com/b v0.3.0 => ./b3 + example.com/c v0.1.0 => ./c + example.com/c v0.2.0 => ./c +) +-- lazy.go -- +package lazy + +import _ "example.com/a" + +-- a/go.mod -- +module example.com/a + +go 1.17 + +require example.com/b v0.1.0 +-- a/a.go -- +package a +-- a/a_test.go -- +package a_test + +import _ "example.com/b" + +-- b1/go.mod -- +module example.com/b + +go 1.17 + +require example.com/c v0.1.0 +-- b1/b.go -- +package b +-- b1/b_test.go -- +package b_test +import _ "example.com/c" + +-- b2/go.mod -- +module example.com/b + +go 1.17 + +require example.com/c v0.1.0 +-- b2/b.go -- +package b +-- b2/b_test.go -- +package b_test +import _ "example.com/c" + +-- b3/go.mod -- +module example.com/b + +go 1.17 + +require example.com/c v0.2.0 +-- b3/b.go -- +package b +-- b3/b_test.go -- +package b_test +import _ "example.com/c" + +-- c/go.mod -- +module example.com/c + +go 1.17 +-- c/c.go -- +package c diff --git a/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt b/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt new file mode 100644 index 0000000..60d4187 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt @@ -0,0 +1,191 @@ +# This test demonstrates dependency resolution when the main module imports a +# new package from a previously-test-only dependency. +# +# When lazy loading is active, the loader will not load dependencies of any +# module whose packages are *only* imported by tests outside the main module. If +# the main module is changed to import a package from such a module, the +# dependencies of that module will need to be reloaded. + +# The import graph used in this test looks like: +# +# m ---- a +# \ | +# \ a_test ---- b/x +# \ +# --------------b/y (new) ---- c +# +# Where b/x and b/y are disjoint packages, but both contained in module b. +# +# The module dependency graph initially looks like: +# +# m ---- a.1 ---- b.1 ---- c.1 +# +# This configuration is similar to that used in mod_lazy_new_import, +# but the new import is from what is initially a test-only dependency. + +# Control case: in Go 1.14, the original go.mod is tidy, +# and the dependency on c is eagerly loaded. + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod.orig go.mod + +go list -m all +stdout '^a v0.1.0 ' +stdout '^b v0.1.0 ' +stdout '^c v0.1.0 ' + +# After adding a new import of b/y, +# the import of c from b/y should resolve to the version required by b. + +cp m.go m.go.orig +cp m.go.new m.go +go mod tidy +cmp go.mod.new go.mod + +go list -m all +stdout '^a v0.1.0 ' +stdout '^b v0.1.0 ' +stdout '^c v0.1.0 ' + +# With lazy loading, the go.mod requirements are the same, +# but the dependency on c is initially pruned out. + +cp m.go.orig m.go +cp go.mod.orig go.mod +go mod edit -go=1.17 +go mod edit -go=1.17 go.mod.new + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod.orig go.mod + +go list -m all +stdout '^a v0.1.0 ' +stdout '^b v0.1.0 ' +! stdout '^c ' + +# After adding a new direct import of b/y, +# the existing version of b should be promoted to a root, +# bringing the version of c required by b into the build list. + +cp m.go.new m.go +go mod tidy +cmp go.mod.lazy go.mod + +go list -m all +stdout '^a v0.1.0 ' +stdout '^b v0.1.0 ' +stdout '^c v0.1.0 ' + +-- m.go -- +package main + +import ( + "fmt" + + _ "a" // a_test imports b/x. +) + +func main() { +} +-- m.go.new -- +package main + +import ( + "fmt" + + _ "a" // a_test imports b/x. + "b/y" // This is a new import, not yet reflected in the go.mod file. +) + +func main() { + fmt.Println(b.CVersion()) +} +-- go.mod -- +module m + +go 1.14 + +require a v0.1.0 + +replace ( + a v0.1.0 => ./a1 + b v0.1.0 => ./b1 + c v0.1.0 => ./c1 + c v0.2.0 => ./c2 +) +-- go.mod.new -- +module m + +go 1.14 + +require ( + a v0.1.0 + b v0.1.0 +) + +replace ( + a v0.1.0 => ./a1 + b v0.1.0 => ./b1 + c v0.1.0 => ./c1 + c v0.2.0 => ./c2 +) +-- go.mod.lazy -- +module m + +go 1.17 + +require ( + a v0.1.0 + b v0.1.0 +) + +require c v0.1.0 // indirect + +replace ( + a v0.1.0 => ./a1 + b v0.1.0 => ./b1 + c v0.1.0 => ./c1 + c v0.2.0 => ./c2 +) +-- a1/go.mod -- +module a + +go 1.17 + +require b v0.1.0 +-- a1/a.go -- +package a +-- a1/a_test.go -- +package a_test + +import _ "b/x" +-- b1/go.mod -- +module b + +go 1.17 + +require c v0.1.0 +-- b1/x/x.go -- +package x +-- b1/y/y.go -- +package y + +import "c" + +func CVersion() string { + return c.Version +} +-- c1/go.mod -- +module c + +go 1.17 +-- c1/c.go -- +package c + +const Version = "v0.1.0" +-- c2/go.mod -- +This file should be unused. +-- c2/c.go -- +This file should be unused. diff --git a/src/cmd/go/testdata/script/mod_lazy_new_import.txt b/src/cmd/go/testdata/script/mod_lazy_new_import.txt new file mode 100644 index 0000000..520d845 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_lazy_new_import.txt @@ -0,0 +1,155 @@ +# This test illustrates the use of a deepening scan to resolve transitive +# imports of imports of new packages from within existing dependencies. + +# The package import graph used in this test looks like: +# +# lazy ---- a/x ---- b +# \ +# ---- a/y (new) ---- c +# +# Where a/x and a/y are disjoint packages, but both contained in module a. +# +# The module dependency graph initially looks like: +# +# lazy ---- a.1 ---- b.1 +# \ +# c.1 + + +cp go.mod go.mod.old +cp lazy.go lazy.go.old +go mod tidy +cmp go.mod go.mod.old + +# Before adding a new import, the go.mod file should +# enumerate modules for all packages already imported. +go list all +cmp go.mod go.mod.old + +# When we add a new import of a package in an existing dependency, +# and that dependency is already tidy, its transitive dependencies +# should already be present. +cp lazy.go.new lazy.go +go list all +go list -m all +stdout '^example.com/c v0.1.0' # not v0.2.0 as would be resolved by 'latest' +cmp go.mod go.mod.old + +# Now, we repeat the test with a lazy main module. +cp lazy.go.old lazy.go +cp go.mod.117 go.mod + +# Before adding a new import, the go.mod file should +# enumerate modules for all packages already imported. +go list all +cmp go.mod go.mod.117 + +# When a new import is found, we should perform a deepening scan of the existing +# dependencies and add a requirement on the version required by those +# dependencies — not re-resolve 'latest'. +cp lazy.go.new lazy.go + +! go list all +stderr '^go: updates to go.mod needed; to update it:\n\tgo mod tidy$' + +go mod tidy +go list all +go list -m all +stdout '^example.com/c v0.1.0' # not v0.2.0 as would be resolved by 'latest' + +cmp go.mod go.mod.new + + +-- go.mod -- +module example.com/lazy + +go 1.15 + +require example.com/a v0.1.0 + +replace ( + example.com/a v0.1.0 => ./a + example.com/b v0.1.0 => ./b + example.com/c v0.1.0 => ./c1 + example.com/c v0.2.0 => ./c2 +) +-- go.mod.117 -- +module example.com/lazy + +go 1.17 + +require example.com/a v0.1.0 + +require example.com/b v0.1.0 // indirect + +replace ( + example.com/a v0.1.0 => ./a + example.com/b v0.1.0 => ./b + example.com/c v0.1.0 => ./c1 + example.com/c v0.2.0 => ./c2 +) +-- go.mod.new -- +module example.com/lazy + +go 1.17 + +require example.com/a v0.1.0 + +require ( + example.com/b v0.1.0 // indirect + example.com/c v0.1.0 // indirect +) + +replace ( + example.com/a v0.1.0 => ./a + example.com/b v0.1.0 => ./b + example.com/c v0.1.0 => ./c1 + example.com/c v0.2.0 => ./c2 +) +-- lazy.go -- +package lazy + +import ( + _ "example.com/a/x" +) +-- lazy.go.new -- +package lazy + +import ( + _ "example.com/a/x" + _ "example.com/a/y" +) +-- a/go.mod -- +module example.com/a + +go 1.15 + +require ( + example.com/b v0.1.0 + example.com/c v0.1.0 +) +-- a/x/x.go -- +package x +import _ "example.com/b" +-- a/y/y.go -- +package y +import _ "example.com/c" +-- b/go.mod -- +module example.com/b + +go 1.15 +-- b/b.go -- +package b +-- c1/go.mod -- +module example.com/c + +go 1.15 +-- c1/c.go -- +package c +-- c2/go.mod -- +module example.com/c + +go 1.15 +-- c2/c.go -- +package c +This file should not be used, so this syntax error should be ignored. diff --git a/src/cmd/go/testdata/script/mod_lazy_test_horizon.txt b/src/cmd/go/testdata/script/mod_lazy_test_horizon.txt new file mode 100644 index 0000000..7d07eb6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_lazy_test_horizon.txt @@ -0,0 +1,131 @@ +# This file demonstrates the effect of lazy loading on the selected +# versions of test dependencies. + +# The package import graph used in this test looks like: +# +# m ---- a +# \ | +# \ a_test ---- b +# \ | +# x b_test +# | \ +# x_test -------------- c +# +# And the module dependency graph looks like: +# +# m -- a.1 -- b.1 -- c.2 +# \ +# x.1 ------------ c.1 + +# Control case: in Go 1.15, the version of c imported by 'go test x' is the +# version required by module b, even though b_test is not relevant to the main +# module. (The main module imports a, and a_test imports b, but all of the +# packages and tests in the main module can be built without b.) + +go list -m c +stdout '^c v0.2.0 ' + +[!short] go test -v x +[!short] stdout ' c v0.2.0$' + +# With lazy loading, the go.mod requirements are the same, +# but the irrelevant dependency on c v0.2.0 should be pruned out, +# leaving only the relevant dependency on c v0.1.0. + +go mod edit -go=1.17 +go list -m c +stdout '^c v0.1.0' + +[!short] go test -v x +[!short] stdout ' c v0.1.0$' + +-- m.go -- +package m + +import ( + _ "a" + _ "x" +) +-- go.mod -- +module m + +go 1.15 + +require ( + a v0.1.0 + x v0.1.0 +) + +replace ( + a v0.1.0 => ./a1 + b v0.1.0 => ./b1 + c v0.1.0 => ./c1 + c v0.2.0 => ./c2 + x v0.1.0 => ./x1 +) +-- a1/go.mod -- +module a + +go 1.17 + +require b v0.1.0 +-- a1/a.go -- +package a +-- a1/a_test.go -- +package a_test + +import _ "b" +-- b1/go.mod -- +module b + +go 1.17 + +require c v0.2.0 +-- b1/b.go -- +package b +-- b1/b_test.go -- +package b_test + +import ( + "c" + "testing" +) + +func TestCVersion(t *testing.T) { + t.Log(c.Version) +} +-- c1/go.mod -- +module c + +go 1.17 +-- c1/c.go -- +package c + +const Version = "v0.1.0" +-- c2/go.mod -- +module c + +go 1.17 +-- c2/c.go -- +package c + +const Version = "v0.2.0" +-- x1/go.mod -- +module x + +go 1.17 + +require c v0.1.0 +-- x1/x.go -- +package x +-- x1/x_test.go -- +package x_test + +import ( + "c" + "testing" +) + +func TestCVersion(t *testing.T) { + t.Log("c", c.Version) +} diff --git a/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt b/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt new file mode 100644 index 0000000..68a5b6d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt @@ -0,0 +1,224 @@ +# This file demonstrates the effect of lazy loading on the reproducibility of +# tests (and tests of test dependencies) outside the main module. +# +# It is similar to the cases in mod_all.txt and mod_lazy_test_horizon.txt, but +# focuses on the effect of "go test" on specific packages instead of the "all" +# pattern. + +# The package import graph used in this test looks like: +# +# lazy ---- a +# | +# a_test ---- b +# | +# b_test ---- c +# +# And the non-lazy module dependency graph looks like: +# +# lazy ---- a.1 ---- b.1 ---- c.1 + +cp go.mod go.mod.old +go mod tidy +cmp go.mod go.mod.old + + +# In Go 1.15 mode, 'go list -m all' includes modules needed by the +# transitive closure of tests of dependencies of tests of dependencies of …. + +go list -m all +stdout '^example.com/b v0.1.0 ' +stdout '^example.com/c v0.1.0 ' +cmp go.mod go.mod.old + +# 'go test' (or equivalent) of any such dependency, no matter how remote, does +# not update the go.mod file. + +go list -test -deps example.com/a +stdout example.com/b +! stdout example.com/c + +[!short] go test -c -o $devnull example.com/a +[!short] cmp go.mod go.mod.old + +go list -test -deps example.com/b +stdout example.com/c + +[!short] go test -c -o $devnull example.com/b +[!short] cmp go.mod go.mod.old + +go mod edit -go=1.17 a/go.mod +go mod edit -go=1.17 b1/go.mod +go mod edit -go=1.17 b2/go.mod +go mod edit -go=1.17 c1/go.mod +go mod edit -go=1.17 c2/go.mod +go mod edit -go=1.17 + + +# After changing to 'go 1.17` uniformly, 'go list -m all' should prune out +# example.com/c, because it is not imported by any package (or test of a package) +# transitively imported by the main module. +# +# example.com/a is imported, +# and example.com/b is needed in order to run 'go test example.com/a', +# but example.com/c is not needed because we don't expect the user to need to run +# 'go test example.com/b'. + +# If we skip directly to adding a new import of c, the dependency is too far +# away for a deepening scan to find, which is fine because the package whose +# test imported it wasn't even it "all". It should resolve from the latest +# version of its module. + +# However, if we reach c by running successive tests starting from the main +# module, we should end up with exactly the version required by b, with an update +# to the go.mod file as soon as we test a test dependency that is not itself in +# "all". + +cp go.mod go.mod.117 +go mod tidy +cmp go.mod go.mod.117 + +go list -m all +stdout '^example.com/b v0.1.0 ' +! stdout '^example.com/c ' + +# 'go test' of a package (transitively) imported by the main module +# should work without changes to the go.mod file. + +go list -test -deps example.com/a +stdout example.com/b +! stdout example.com/c + +[!short] go test -c -o $devnull example.com/a + +# However, 'go test' of a package that is itself a dependency should require an +# update to the go.mod file. +! go list -test -deps example.com/b + + # TODO(#36460): The hint here is wrong. We should suggest + # 'go get -t example.com/b@v0.1.0' instead of 'go mod tidy'. +stderr '^go: updates to go\.mod needed; to update it:\n\tgo mod tidy$' + +[!short] ! go test -c -o $devnull example.com/b +[!short] stderr '^go: updates to go\.mod needed; to update it:\n\tgo mod tidy$' + +go get -t example.com/b@v0.1.0 +go list -test -deps example.com/b +stdout example.com/c + +[!short] go test -c -o $devnull example.com/b + +# The update should bring the version required by b, not the latest version of c. + +go list -m example.com/c +stdout '^example.com/c v0.1.0 ' + +cmp go.mod go.mod.b + + +# We should reach the same state if we arrive at it via `go test -mod=mod`. + +cp go.mod.117 go.mod + +[short] go list -mod=mod -test -deps example.com/a +[!short] go test -mod=mod -c -o $devnull example.com/a + +[short] go list -mod=mod -test -deps example.com/b +[!short] go test -mod=mod -c -o $devnull example.com/b + +cmp go.mod go.mod.b + + + +-- go.mod -- +module example.com/lazy + +go 1.15 + +require example.com/a v0.1.0 + +replace ( + example.com/a v0.1.0 => ./a + example.com/b v0.1.0 => ./b1 + example.com/b v0.2.0 => ./b2 + example.com/c v0.1.0 => ./c1 + example.com/c v0.2.0 => ./c2 +) +-- go.mod.b -- +module example.com/lazy + +go 1.17 + +require example.com/a v0.1.0 + +require example.com/b v0.1.0 // indirect + +replace ( + example.com/a v0.1.0 => ./a + example.com/b v0.1.0 => ./b1 + example.com/b v0.2.0 => ./b2 + example.com/c v0.1.0 => ./c1 + example.com/c v0.2.0 => ./c2 +) +-- lazy.go -- +package lazy + +import ( + _ "example.com/a" +) +-- a/go.mod -- +module example.com/a + +go 1.15 + +require example.com/b v0.1.0 +-- a/a.go -- +package a +-- a/a_test.go -- +package a + +import ( + "testing" + + _ "example.com/b" +) + +func TestUsingB(t *testing.T) { + // … +} +-- b1/go.mod -- +module example.com/b + +go 1.15 + +require example.com/c v0.1.0 +-- b1/b.go -- +package b +-- b1/b_test.go -- +package b + +import _ "example.com/c" +-- b2/go.mod -- +module example.com/b + +go 1.15 + +require example.com/c v0.1.0 +-- b2/b.go -- +package b +This file should not be used, so this syntax error should be ignored. +-- b2/b_test.go -- +package b +This file should not be used, so this syntax error should be ignored. +-- c1/go.mod -- +module example.com/c + +go 1.15 +-- c1/c.go -- +package c +-- c2/go.mod -- +module example.com/c + +go 1.15 +-- c2/c.go -- +package c +This file should not be used, so this syntax error should be ignored. diff --git a/src/cmd/go/testdata/script/mod_list.txt b/src/cmd/go/testdata/script/mod_list.txt new file mode 100644 index 0000000..06316cc --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list.txt @@ -0,0 +1,62 @@ +env GO111MODULE=on +[short] skip + +# list {{.Dir}} shows main module and go.mod but not not-yet-downloaded dependency dir. +go list -mod=mod -m -f '{{.Path}} {{.Main}} {{.GoMod}} {{.Dir}}' all +stdout '^x true .*[\\/]src[\\/]go.mod .*[\\/]src$' +stdout '^rsc.io/quote false .*[\\/]v1.5.2.mod $' + +# list {{.Dir}} shows dependency after download (and go list without -m downloads it) +go list -mod=mod -f '{{.Dir}}' rsc.io/quote +stdout '.*mod[\\/]rsc.io[\\/]quote@v1.5.2$' + +# downloaded dependencies are read-only +exists -readonly $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 +exists -readonly $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/buggy + +# go clean -modcache can delete read-only dependencies +go clean -modcache +! exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 + +# list {{.Dir}} shows replaced directories +cp go.mod2 go.mod +go list -mod=mod -f {{.Dir}} rsc.io/quote +go list -m -f '{{.Path}} {{.Version}} {{.Dir}}{{with .Replace}} {{.GoMod}} => {{.Version}} {{.Dir}} {{.GoMod}}{{end}}' all +stdout 'mod[\\/]rsc.io[\\/]quote@v1.5.1' +stdout 'v1.3.0.*mod[\\/]rsc.io[\\/]sampler@v1.3.1 .*[\\/]v1.3.1.mod => v1.3.1.*sampler@v1.3.1 .*[\\/]v1.3.1.mod' + +# list std should work +go list std +stdout ^math/big + +# rsc.io/quote/buggy should be listable as a package, +# even though it is only a test. +go list -mod=mod rsc.io/quote/buggy + +# rsc.io/quote/buggy should not be listable as a module +go list -m -e -f '{{.Error.Err}}' nonexist rsc.io/quote/buggy +stdout '^module nonexist: not a known dependency$' +stdout '^module rsc.io/quote/buggy: not a known dependency$' + +! go list -m nonexist rsc.io/quote/buggy +stderr '^go: module nonexist: not a known dependency' +stderr '^go: module rsc.io/quote/buggy: not a known dependency' + +# Module loader does not interfere with list -e (golang.org/issue/24149). +go list -e -f '{{.Error.Err}}' database +stdout 'no Go files in ' +! go list database +stderr 'no Go files in ' + +-- go.mod -- +module x +require rsc.io/quote v1.5.2 + +-- go.mod2 -- +module x +require rsc.io/quote v1.5.1 +replace rsc.io/sampler v1.3.0 => rsc.io/sampler v1.3.1 + +-- x.go -- +package x +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_list_bad_import.txt b/src/cmd/go/testdata/script/mod_list_bad_import.txt new file mode 100644 index 0000000..b128408 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_bad_import.txt @@ -0,0 +1,75 @@ +# This test matches list_bad_import, but in module mode. +# Please keep them in sync. + +env GO111MODULE=on +cd example.com + +# Without -e, listing an otherwise-valid package with an unsatisfied direct import should fail. +# BUG: Today it succeeds. +go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}} {{range .DepsErrors}}bad dep: {{.Err}}{{end}}' example.com/direct +! stdout ^error +stdout 'incomplete' +stdout 'bad dep: .*example.com/notfound' + +# Listing with -deps should also fail. +! go list -deps example.com/direct +stderr example.com/notfound + +# But -e -deps should succeed. +go list -e -deps example.com/direct +stdout example.com/notfound + + +# Listing an otherwise-valid package that imports some *other* package with an +# unsatisfied import should also fail. +# BUG: Today, it succeeds. +go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}} {{range .DepsErrors}}bad dep: {{.Err}}{{end}}' example.com/indirect +! stdout ^error +stdout incomplete +stdout 'bad dep: .*example.com/notfound' + +# Again, -deps should fail. +! go list -deps example.com/indirect +stderr example.com/notfound + +# But -e -deps should succeed. +go list -e -deps example.com/indirect +stdout example.com/notfound + + +# Listing the missing dependency directly should fail outright... +! go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound +stderr 'no required module provides package example.com/notfound; to add it:\n\tgo get example.com/notfound' +! stdout error +! stdout incomplete + +# ...but listing with -e should succeed. +go list -e -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound +stdout error +stdout incomplete + + +# The pattern "all" should match only packages that actually exist, +# ignoring those whose existence is merely implied by imports. +go list -e -f '{{.ImportPath}} {{.Error}}' all +stdout example.com/direct +stdout example.com/indirect +# TODO: go list creates a dummy package with the import-not-found +# but really the Error belongs on example.com/direct, and this package +# should not be printed. +# ! stdout example.com/notfound + + +-- example.com/go.mod -- +module example.com + +-- example.com/direct/direct.go -- +package direct +import _ "example.com/notfound" + +-- example.com/indirect/indirect.go -- +package indirect +import _ "example.com/direct" + +-- example.com/notfound/README -- +This directory intentionally left blank. diff --git a/src/cmd/go/testdata/script/mod_list_command_line_arguments.txt b/src/cmd/go/testdata/script/mod_list_command_line_arguments.txt new file mode 100644 index 0000000..25c68c5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_command_line_arguments.txt @@ -0,0 +1,35 @@ +# The command-line-arguments package does not belong to a module... +cd a +go list -f '{{.Module}}' ../b/b.go +stdout '^<nil>$' + +# ... even if the arguments are sources from that module +go list -f '{{.Module}}' a.go +stdout '^<nil>$' + +[short] skip + +# check that the version of command-line-arguments doesn't include a module +go build -o a.exe a.go +go version -m a.exe +stdout '^\tpath\tcommand-line-arguments$' +stdout '^\tdep\ta\t\(devel\)\t$' +! stdout mod[^e] + +-- a/go.mod -- +module a +go 1.17 +-- a/a.go -- +package main + +import "a/dep" + +func main() { + dep.D() +} +-- a/dep/dep.go -- +package dep + +func D() {} +-- b/b.go -- +package b
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/mod_list_compiled_concurrent.txt b/src/cmd/go/testdata/script/mod_list_compiled_concurrent.txt new file mode 100644 index 0000000..195f7b1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_compiled_concurrent.txt @@ -0,0 +1,21 @@ +env GO111MODULE=on + +[short] skip +[!cgo] skip + +# Regression test for golang.org/issue/29667: +# spurious 'failed to cache compiled Go files' errors. + +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +wait + +-- go.mod -- +module sandbox/bar +-- bar.go -- +package bar + +import "C" diff --git a/src/cmd/go/testdata/script/mod_list_deprecated.txt b/src/cmd/go/testdata/script/mod_list_deprecated.txt new file mode 100644 index 0000000..ee985cc --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_deprecated.txt @@ -0,0 +1,52 @@ +# 'go list pkg' does not show deprecation. +go list example.com/deprecated/a +stdout '^example.com/deprecated/a$' + +# 'go list -m' does not show deprecation. +go list -m example.com/deprecated/a +stdout '^example.com/deprecated/a v1.9.0$' + +# 'go list -m -versions' does not show deprecation. +go list -m -versions example.com/deprecated/a +stdout '^example.com/deprecated/a v1.0.0 v1.9.0$' + +# 'go list -m -u' shows deprecation. +go list -m -u example.com/deprecated/a +stdout '^example.com/deprecated/a v1.9.0 \(deprecated\)$' + +# 'go list -m -u -f' exposes the deprecation message. +go list -m -u -f {{.Deprecated}} example.com/deprecated/a +stdout '^in example.com/deprecated/a@v1.9.0$' + +# This works even if we use an old version that does not have the deprecation +# message in its go.mod file. +go get example.com/deprecated/a@v1.0.0 +! grep Deprecated: $WORK/gopath/pkg/mod/cache/download/example.com/deprecated/a/@v/v1.0.0.mod +go list -m -u -f {{.Deprecated}} example.com/deprecated/a +stdout '^in example.com/deprecated/a@v1.9.0$' + +# 'go list -m -u' does not show deprecation for the main module. +go list -m -u +! stdout deprecated +go list -m -u -f '{{if not .Deprecated}}ok{{end}}' +stdout ok + +# 'go list -m -u' does not show a deprecation message for a module that is not +# deprecated at the latest version, even if it is deprecated at the current +# version. +go list -m -u example.com/undeprecated +stdout '^example.com/undeprecated v1.0.0 \[v1.0.1\]$' +-- go.mod -- +// Deprecated: main module is deprecated, too! +module example.com/use + +go 1.17 + +require ( + example.com/deprecated/a v1.9.0 + example.com/undeprecated v1.0.0 +) +-- go.sum -- +example.com/deprecated/a v1.9.0 h1:pRyvBIZheJpQVVnNW4Fdg8QuoqDgtkCreqZZbASV3BE= +example.com/deprecated/a v1.9.0/go.mod h1:Z1uUVshSY9kh6l/2hZ8oA9SBviX2yfaeEpcLDz6AZwY= +example.com/undeprecated v1.0.0/go.mod h1:1qiRbdA9VzJXDqlG26Y41O5Z7YyO+jAD9do8XCZQ+Gg= diff --git a/src/cmd/go/testdata/script/mod_list_deprecated_replace.txt b/src/cmd/go/testdata/script/mod_list_deprecated_replace.txt new file mode 100644 index 0000000..48b991f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_deprecated_replace.txt @@ -0,0 +1,68 @@ +# When all versions are replaced, we should not look up a deprecation message. +# We will still look up a deprecation message for the replacement. +cp go.mod.allreplaced go.mod +go list -m -u -f '{{.Path}}@{{.Version}} <{{.Deprecated}}>{{with .Replace}} => {{.Path}}@{{.Version}} <{{.Deprecated}}>{{end}}' all +stdout '^example.com/deprecated/a@v1.0.0 <> => example.com/deprecated/b@v1.0.0 <in example.com/deprecated/b@v1.9.0>$' + +# When one version is replaced, we should see a deprecation message. +cp go.mod.onereplaced go.mod +go list -m -u -f '{{.Path}}@{{.Version}} <{{.Deprecated}}>{{with .Replace}} => {{.Path}}@{{.Version}} <{{.Deprecated}}>{{end}}' all +stdout '^example.com/deprecated/a@v1.0.0 <in example.com/deprecated/a@v1.9.0> => example.com/deprecated/b@v1.0.0 <in example.com/deprecated/b@v1.9.0>$' + +# If the replacement is a directory, we won't look that up. +cp go.mod.dirreplacement go.mod +go list -m -u -f '{{.Path}}@{{.Version}} <{{.Deprecated}}>{{with .Replace}} => {{.Path}}@{{.Version}} <{{.Deprecated}}>{{end}}' all +stdout '^example.com/deprecated/a@v1.0.0 <> => ./a@ <>$' + +# If the latest version of the replacement is replaced, we'll use the content +# from that replacement. +cp go.mod.latestreplaced go.mod +go list -m -u -f '{{.Path}}@{{.Version}} <{{.Deprecated}}>{{with .Replace}} => {{.Path}}@{{.Version}} <{{.Deprecated}}>{{end}}' all +stdout '^example.com/deprecated/a@v1.0.0 <> => example.com/deprecated/b@v1.0.0 <in ./b>$' + +-- go.mod.allreplaced -- +module m + +go 1.17 + +require example.com/deprecated/a v1.0.0 + +replace example.com/deprecated/a => example.com/deprecated/b v1.0.0 +-- go.mod.onereplaced -- +module m + +go 1.17 + +require example.com/deprecated/a v1.0.0 + +replace example.com/deprecated/a v1.0.0 => example.com/deprecated/b v1.0.0 +-- go.mod.dirreplacement -- +module m + +go 1.17 + +require example.com/deprecated/a v1.0.0 + +replace example.com/deprecated/a => ./a +-- go.mod.latestreplaced -- +module m + +go 1.17 + +require example.com/deprecated/a v1.0.0 + +replace ( + example.com/deprecated/a => example.com/deprecated/b v1.0.0 + example.com/deprecated/b v1.9.0 => ./b +) +-- go.sum -- +example.com/deprecated/b v1.0.0/go.mod h1:b19J9ywRGviY7Nq4aJ1WBJ+A7qUlEY9ihp22yI4/F6M= +-- a/go.mod -- +module example.com/deprecated/a + +go 1.17 +-- b/go.mod -- +// Deprecated: in ./b +module example.com/deprecated/b + +go 1.17 diff --git a/src/cmd/go/testdata/script/mod_list_dir.txt b/src/cmd/go/testdata/script/mod_list_dir.txt new file mode 100644 index 0000000..157d3b6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_dir.txt @@ -0,0 +1,36 @@ +[short] skip + +# go list with path to directory should work + +# populate go.sum +go get + +env GO111MODULE=off +go list -f '{{.ImportPath}}' $GOROOT/src/math +stdout ^math$ + +env GO111MODULE=on +go list -f '{{.ImportPath}}' $GOROOT/src/math +stdout ^math$ +go list -f '{{.ImportPath}}' . +stdout ^x$ + +go mod download rsc.io/quote@v1.5.2 +go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 +stdout '^rsc.io/quote$' +go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/sampler@v1.3.0 +stdout '^rsc.io/sampler$' +go get rsc.io/sampler@v1.3.1 +go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/sampler@v1.3.1 +stdout '^rsc.io/sampler$' +! go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/sampler@v1.3.0 +stderr 'outside main module or its selected dependencies' + +-- go.mod -- +module x +require rsc.io/quote v1.5.2 + +-- x.go -- +package x + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_list_direct.txt b/src/cmd/go/testdata/script/mod_list_direct.txt new file mode 100644 index 0000000..8bab330 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_direct.txt @@ -0,0 +1,24 @@ +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +[short] skip +[!git] skip + +# golang.org/issue/33099: if an import path ends in a major-version suffix, +# ensure that 'direct' mode can resolve the package to the module. +# For a while, (*modfetch.codeRepo).Stat was not checking for a go.mod file, +# which would produce a hard error at the subsequent call to GoMod. + +go get -v + +-- go.mod -- +module example.com +go 1.13 + +-- main.go -- +package main + +import _ "vcs-test.golang.org/git/v3pkg.git/v3" + +func main() {} diff --git a/src/cmd/go/testdata/script/mod_list_e_readonly.txt b/src/cmd/go/testdata/script/mod_list_e_readonly.txt new file mode 100644 index 0000000..4969434 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_e_readonly.txt @@ -0,0 +1,15 @@ +# 'go list -mod=readonly -e should attribute errors +# to individual missing packages. +# Verifies golang.org/issue/34829. +go list -mod=readonly -e -deps -f '{{if .Error}}{{.ImportPath}}: {{.Error}}{{end}}' . +stdout 'example.com/missing: use.go:3:8: cannot find module providing package example.com/missing: import lookup disabled by -mod=readonly' + +-- go.mod -- +module example.com/m + +go 1.14 + +-- use.go -- +package use + +import _ "example.com/missing" diff --git a/src/cmd/go/testdata/script/mod_list_issue61415.txt b/src/cmd/go/testdata/script/mod_list_issue61415.txt new file mode 100644 index 0000000..e763fae --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_issue61415.txt @@ -0,0 +1,76 @@ +[short] skip 'generates a vcstest git repo' +[!git] skip + +env GOPROXY=direct + +# Control case: fetching a nested module at a tag that exists should +# emit Origin metadata for that tag and commit, and the origin should +# be reusable for that tag. + +go list -json -m --versions -e vcs-test.golang.org/git/issue61415.git/nested@has-nested +cp stdout has-nested.json +stdout '"Origin":' +stdout '"VCS": "git"' +stdout '"URL":' # randomly-chosen vcweb localhost URL +stdout '"Subdir": "nested"' +stdout '"TagPrefix": "nested/"' +stdout '"TagSum": "t1:47DEQpj8HBSa\+/TImW\+5JCeuQeRkm5NMpJWZG3hSuFU="' +stdout '"Ref": "refs/tags/has-nested"' +stdout '"Hash": "08a4fa6bb9c04ffba03b26ae427b0d6335d90a2a"' + +go list -reuse=has-nested.json -json -m --versions -e vcs-test.golang.org/git/issue61415.git/nested@has-nested +stdout '"Origin":' +stdout '"VCS": "git"' +stdout '"URL":' # randomly-chosen vcweb localhost URL +stdout '"Subdir": "nested"' +stdout '"TagPrefix": "nested/"' +stdout '"TagSum": "t1:47DEQpj8HBSa\+/TImW\+5JCeuQeRkm5NMpJWZG3hSuFU="' +stdout '"Ref": "refs/tags/has-nested"' +stdout '"Hash": "08a4fa6bb9c04ffba03b26ae427b0d6335d90a2a"' +stdout '"Reuse": true' + + +# Experiment case: if the nested module doesn't exist at "latest", +# the Origin metadata should include the ref that we tried to resolve +# (HEAD for a repo without version tags) and the hash to which it refers, +# so that changing the HEAD ref will invalidate the result. + +go list -json -m --versions -e vcs-test.golang.org/git/issue61415.git/nested@latest +cp stdout no-nested.json +stdout '"Err": "module vcs-test.golang.org/git/issue61415.git/nested: no matching versions for query \\"latest\\""' +stdout '"URL":' # randomly-chosen vcweb localhost URL +stdout '"Subdir": "nested"' +stdout '"TagPrefix": "nested/"' +stdout '"TagSum": "t1:47DEQpj8HBSa\+/TImW\+5JCeuQeRkm5NMpJWZG3hSuFU="' + +stdout '"Ref": "HEAD"' +stdout '"Hash": "f213069baa68ec26412fb373c7cf6669db1f8e69"' + +# The error result should be reusable. + +go list -reuse=no-nested.json -json -m --versions -e vcs-test.golang.org/git/issue61415.git/nested@latest + +stdout '"Err": "module vcs-test.golang.org/git/issue61415.git/nested: no matching versions for query \\"latest\\""' +stdout '"URL":' # randomly-chosen vcweb localhost URL +stdout '"Subdir": "nested"' +stdout '"TagPrefix": "nested/"' +stdout '"TagSum": "t1:47DEQpj8HBSa\+/TImW\+5JCeuQeRkm5NMpJWZG3hSuFU="' +stdout '"Ref": "HEAD"' +stdout '"Hash": "f213069baa68ec26412fb373c7cf6669db1f8e69"' +stdout '"Reuse": true' + + +# If the hash refers to some other commit instead, the +# result should not be reused. + +replace f213069baa68ec26412fb373c7cf6669db1f8e69 08a4fa6bb9c04ffba03b26ae427b0d6335d90a2a no-nested.json + +go list -reuse=no-nested.json -json -m --versions -e vcs-test.golang.org/git/issue61415.git/nested@latest +stdout '"Err": "module vcs-test.golang.org/git/issue61415.git/nested: no matching versions for query \\"latest\\""' +stdout '"URL":' # randomly-chosen vcweb localhost URL +stdout '"Subdir": "nested"' +stdout '"TagPrefix": "nested/"' +stdout '"TagSum": "t1:47DEQpj8HBSa\+/TImW\+5JCeuQeRkm5NMpJWZG3hSuFU="' +stdout '"Ref": "HEAD"' +stdout '"Hash": "f213069baa68ec26412fb373c7cf6669db1f8e69"' +! stdout '"Reuse"' diff --git a/src/cmd/go/testdata/script/mod_list_issue61423.txt b/src/cmd/go/testdata/script/mod_list_issue61423.txt new file mode 100644 index 0000000..2888391 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_issue61423.txt @@ -0,0 +1,100 @@ +[short] skip 'generates a vcstest git repo' +[!git] skip + +mkdir $WORK/mod1 +mkdir $WORK/mod2 +env GONOSUMDB=vcs-test.golang.org + +env GOPROXY=direct +env GOMODCACHE=$WORK/mod1 + + +# If we query a module version from a git repo, we expect its +# Origin data to be reusable. + +go list -m -json vcs-test.golang.org/git/issue61415.git@latest +cp stdout git-latest.json +stdout '"Version": "v0.0.0-20231114180001-f213069baa68"' +stdout '"Origin":' +stdout '"VCS": "git"' +stdout '"Hash": "f213069baa68ec26412fb373c7cf6669db1f8e69"' +stdout '"Ref": "HEAD"' +stdout '"TagSum": "t1:47DEQpj8HBSa\+/TImW\+5JCeuQeRkm5NMpJWZG3hSuFU="' + +go list -reuse=git-latest.json -m -json vcs-test.golang.org/git/issue61415.git@latest +stdout '"Version": "v0.0.0-20231114180001-f213069baa68"' +stdout '"Origin":' +stdout '"VCS": "git"' +stdout '"Hash": "f213069baa68ec26412fb373c7cf6669db1f8e69"' +stdout '"Ref": "HEAD"' +stdout '"TagSum": "t1:47DEQpj8HBSa\+/TImW\+5JCeuQeRkm5NMpJWZG3hSuFU="' +stdout '"Reuse": true' + + +# Now we construct a filesystem-based module proxy that +# contains only an older commit. + +go clean -modcache + +go mod download -json vcs-test.golang.org/git/issue61415.git@08a4fa6bb9c04ffba03b26ae427b0d6335d90a2a +stdout '"Version": "v0.0.0-20231114180000-08a4fa6bb9c0"' +stdout '"Origin":' +stdout '"VCS": "git"' +stdout '"Hash": "08a4fa6bb9c04ffba03b26ae427b0d6335d90a2a"' + +[GOOS:windows] env GOPROXY=file:///$WORK/mod1/cache/download +[!GOOS:windows] env GOPROXY=file://$WORK/mod1/cache/download +env GOMODCACHE=$WORK/modcache2 + + +# If we resolve the "latest" version query using a proxy, +# it is only going to have Git origin information about the one +# commit — not the other tags that would go into resolving +# the underlying version list. +# 'go list' should not emit the partial information, +# since it isn't enough to reconstruct the result. + +go list -m -json vcs-test.golang.org/git/issue61415.git@latest +cp stdout proxy-latest.json +stdout '"Version": "v0.0.0-20231114180000-08a4fa6bb9c0"' +! stdout '"Origin":' + +# However, if we list a specific, stable version, we should get +# whatever origin metadata the proxy has for the version. + +go list -m -json vcs-test.golang.org/git/issue61415.git@v0.0.0-20231114180000-08a4fa6bb9c0 +cp stdout proxy-version.json +stdout '"Version": "v0.0.0-20231114180000-08a4fa6bb9c0"' +stdout '"Origin":' +stdout '"VCS": "git"' +stdout '"Hash": "08a4fa6bb9c04ffba03b26ae427b0d6335d90a2a"' +! stdout '"Ref":' +! stdout '"TagSum":' + +# The -reuse flag has no effect with a proxy, since the proxy can serve +# metadata about a given module version cheaply anyway. + +go list -reuse=proxy-version.json -m -json vcs-test.golang.org/git/issue61415.git@v0.0.0-20231114180000-08a4fa6bb9c0 +stdout '"Version": "v0.0.0-20231114180000-08a4fa6bb9c0"' +stdout '"Origin":' +stdout '"VCS": "git"' +stdout '"Hash": "08a4fa6bb9c04ffba03b26ae427b0d6335d90a2a"' +! stdout '"Ref":' +! stdout '"TagSum":' +! stdout '"Reuse":' + + +# With GOPROXY=direct, the -reuse flag has an effect, but +# the Origin data from the proxy should not be sufficient +# for the proxy response to be reused. + +env GOPROXY=direct + +go list -reuse=proxy-latest.json -m -json vcs-test.golang.org/git/issue61415.git@latest +stdout '"Version": "v0.0.0-20231114180001-f213069baa68"' +stdout '"Origin":' +stdout '"VCS": "git"' +stdout '"Hash": "f213069baa68ec26412fb373c7cf6669db1f8e69"' +stdout '"Ref": "HEAD"' +stdout '"TagSum": "t1:47DEQpj8HBSa\+/TImW\+5JCeuQeRkm5NMpJWZG3hSuFU="' +! stdout '"Reuse":' diff --git a/src/cmd/go/testdata/script/mod_list_odd_tags.txt b/src/cmd/go/testdata/script/mod_list_odd_tags.txt new file mode 100644 index 0000000..232754e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_odd_tags.txt @@ -0,0 +1,12 @@ +[short] skip +[!git] skip + +env GOPROXY=direct + +go list -m vcs-test.golang.org/git/odd-tags.git@latest +stdout -count=1 '^.' +stdout '^vcs-test.golang.org/git/odd-tags.git v0.1.1-0.20220223184835-9d863d525bbf$' + +go list -m -versions vcs-test.golang.org/git/odd-tags.git +stdout -count=1 '^.' +stdout '^vcs-test.golang.org/git/odd-tags.git$' # No versions listed — the odd tags are filtered out. diff --git a/src/cmd/go/testdata/script/mod_list_pseudo.txt b/src/cmd/go/testdata/script/mod_list_pseudo.txt new file mode 100644 index 0000000..056c093 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_pseudo.txt @@ -0,0 +1,39 @@ +env GO111MODULE=on + +# Regression test for golang.org/issue/32715. + +# When using $GOPATH/pkg/mod/cache/download as a proxy, +# 'latest' queries should prefer tagged versions over pseudo-versions. + +go mod download github.com/dmitshur-test/modtest5@v0.0.0-20190619020302-197a620e0c9a +go mod download github.com/dmitshur-test/modtest5@v0.5.0-alpha +go mod download github.com/dmitshur-test/modtest5@v0.5.0-alpha.0.20190619023908-3da23a9deb9e +cmp $GOPATH/pkg/mod/cache/download/github.com/dmitshur-test/modtest5/@v/list $WORK/modtest5.list + +env GOSUMDB=off # don't verify go.mod files when loading retractions +env GOPROXY=file:///$GOPATH/pkg/mod/cache/download +env GOPATH=$WORK/gopath2 +mkdir $GOPATH + +go list -m -f '{{.Path}} {{.Version}} {{.Time.Format "2006-01-02"}}' github.com/dmitshur-test/modtest5@latest +stdout '^github.com/dmitshur-test/modtest5 v0.5.0-alpha 2019-06-18$' + +# If the module proxy contains only pseudo-versions, 'latest' should stat +# the version with the most recent timestamp — not the highest semantic +# version — and return its metadata. +env GOPROXY=file:///$WORK/tinyproxy +go list -m -f '{{.Path}} {{.Version}} {{.Time.Format "2006-01-02"}}' dmitri.shuralyov.com/test/modtest3@latest +stdout '^dmitri.shuralyov.com/test/modtest3 v0.0.0-20181023043359-a85b471d5412 2018-10-22$' + +-- $WORK/modtest5.list -- +v0.0.0-20190619020302-197a620e0c9a +v0.5.0-alpha +v0.5.0-alpha.0.20190619023908-3da23a9deb9e +-- $WORK/tinyproxy/dmitri.shuralyov.com/test/modtest3/@v/list -- +v0.1.0-0.20161023043300-000000000000 +v0.0.0-20181023043359-a85b471d5412 +-- $WORK/tinyproxy/dmitri.shuralyov.com/test/modtest3/@v/v0.0.0-20181023043359-a85b471d5412.info -- +{ + "Version": "v0.0.0-20181023043359-a85b471d5412", + "Time": "2018-10-22T21:33:59-07:00" +} diff --git a/src/cmd/go/testdata/script/mod_list_replace_dir.txt b/src/cmd/go/testdata/script/mod_list_replace_dir.txt new file mode 100644 index 0000000..b446543 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_replace_dir.txt @@ -0,0 +1,27 @@ +# Test that "go list" succeeds when given a directory in a replacement +# module within the module cache. +# Verifies golang.org/issue/29548 + +# Populate go.sum and download dependencies. +go get + +# Ensure v1.5.2 is also in the cache so we can list it. +go mod download rsc.io/quote@v1.5.2 + +! go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 +stderr '^directory ..[/\\]pkg[/\\]mod[/\\]rsc.io[/\\]quote@v1.5.2 outside main module or its selected dependencies$' + +go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.1 +stdout 'rsc.io/quote' + +-- go.mod -- +module example.com/quoter + +require rsc.io/quote v1.5.2 + +replace rsc.io/quote => rsc.io/quote v1.5.1 + +-- use.go -- +package use + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_list_retract.txt b/src/cmd/go/testdata/script/mod_list_retract.txt new file mode 100644 index 0000000..b7147aa --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_retract.txt @@ -0,0 +1,110 @@ +# 'go list -mod=vendor -retracted' reports an error. +go mod vendor +! go list -m -retracted -mod=vendor +stderr '^go list -retracted cannot be used when vendoring is enabled$' +rm vendor + +# 'go list -retracted' reports an error in GOPATH mode. +env GO111MODULE=off +! go list -retracted +stderr '^go list -retracted can only be used in module-aware mode$' +env GO111MODULE= + +# 'go list pkg' does not show retraction. +go list -f '{{with .Module}}{{with .Retracted}}retracted{{end}}{{end}}' example.com/retract +! stdout . + +# 'go list -retracted pkg' shows retraction. +go list -retracted -f '{{with .Module}}{{with .Retracted}}retracted{{end}}{{end}}' example.com/retract +stdout retracted + +# 'go list -m' does not show retraction. +go list -m -f '{{with .Retracted}}retracted{{end}}' example.com/retract +! stdout . + +# 'go list -m -retracted' shows retraction. +go list -m -retracted -f '{{with .Retracted}}retracted{{end}}' example.com/retract + +# 'go list -m mod@version' does not show retraction. +go list -m -f '{{with .Retracted}}retracted{{end}}' example.com/retract@v1.0.0-unused +! stdout . + +# 'go list -m -retracted mod@version' does not show an error if the module +# that would contain the retraction is unavailable. See #45305. +go list -m -retracted -f '{{.Path}} {{.Version}} {{.Error}}' example.com/retract/missingmod@v1.0.0 +stdout '^example.com/retract/missingmod v1.0.0 <nil>$' +exists $GOPATH/pkg/mod/cache/download/example.com/retract/missingmod/@v/v1.9.0.info +! exists $GOPATH/pkg/mod/cache/download/example.com/retract/missingmod/@v/v1.9.0.mod + +# 'go list -m -retracted mod@version' shows retractions. +go list -m -retracted example.com/retract@v1.0.0-unused +stdout '^example.com/retract v1.0.0-unused \(retracted\)$' +go list -m -retracted -f '{{with .Retracted}}retracted{{end}}' example.com/retract@v1.0.0-unused +stdout retracted + +# 'go list -m mod@latest' selects a previous release version, not self-retracted latest. +go list -m -f '{{.Version}}{{with .Retracted}} retracted{{end}}' example.com/retract/self/prev@latest +stdout '^v1.1.0$' + +# 'go list -m -retracted mod@latest' selects the self-retracted latest version. +go list -m -retracted -f '{{.Version}}{{with .Retracted}} retracted{{end}}' example.com/retract/self/prev@latest +stdout '^v1.9.0 retracted$' + +# 'go list -m mod@latest' selects a pre-release version if all release versions are retracted. +go list -m -f '{{.Version}}{{with .Retracted}} retracted{{end}}' example.com/retract/self/prerelease@latest +stdout '^v1.9.1-pre$' + +# 'go list -m -retracted mod@latest' selects the self-retracted latest version. +go list -m -retracted -f '{{.Version}}{{with .Retracted}} retracted{{end}}' example.com/retract/self/prerelease@latest +stdout '^v1.9.0 retracted$' + +# 'go list -m mod@latest' selects a pseudo-version if all versions are retracted. +# TODO(golang.org/issue/24031): the proxy does not expose the pseudo-version, +# even if all release versions are retracted. +go list -m -e -f '{{.Error.Err}}' example.com/retract/self/pseudo@latest +stdout '^module example.com/retract/self/pseudo: no matching versions for query "latest"$' + +# 'go list -m mod@latest' reports an error if all versions are retracted. +go list -m -e -f '{{.Error.Err}}' example.com/retract/self/all@latest +stdout '^module example.com/retract/self/all: no matching versions for query "latest"$' + +# 'go list -m mod@<v1.10' selects a previous release version, not self-retracted latest. +# The @latest query is not special with respect to retractions. +go list -m -f '{{.Version}}{{with .Retracted}} retracted{{end}}' example.com/retract/self/prev@<v1.10 +stdout '^v1.1.0$' + +# 'go list -m -versions' hides retracted versions. +go list -m -versions example.com/retract +stdout '^example.com/retract v1.0.0-good v1.1.0$' + +# 'go list -m -retracted -versions' shows retracted versions. +go list -m -retracted -versions example.com/retract +stdout '^example.com/retract v1.0.0-bad v1.0.0-good v1.0.0-unused v1.1.0$' + +# 'go list -m -u -versions' loads retractions and does not show retracted versions. +go list -m -u -versions example.com/retract +stdout '^example.com/retract v1.0.0-good v1.1.0$' +go list -m -u -versions -f '{{with .Retracted}}retracted{{end}}' example.com/retract +stdout retracted + +# 'go list -m -u' shows retraction. +go list -m -u -f '{{with .Retracted}}retracted{{end}}' example.com/retract +stdout retracted + +# 'go list -m -u' does not suggest an update to a self-retracted latest version. +go list -m -u -f '{{with .Update}}{{.Version}}{{with .Retracted}} retracted{{end}}{{end}}' example.com/retract/self/prev@v1.0.0-bad +stdout '^v1.1.0$' + +-- go.mod -- +module example.com/use + +go 1.15 + +require example.com/retract v1.0.0-bad +-- go.sum -- +example.com/retract v1.0.0-bad h1:liAW69rbtjY67x2CcNzat668L/w+YGgNX3lhJsWIJis= +example.com/retract v1.0.0-bad/go.mod h1:0DvGGofJ9hr1q63cBrOY/jSY52OwhRGA0K47NE80I5Y= +-- use.go -- +package use + +import _ "example.com/retract" diff --git a/src/cmd/go/testdata/script/mod_list_std.txt b/src/cmd/go/testdata/script/mod_list_std.txt new file mode 100644 index 0000000..7a4fe21 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_std.txt @@ -0,0 +1,93 @@ +env GO111MODULE=on +env GOPROXY=off + +[!compiler:gc] skip +[short] skip + +# Outside of GOROOT, our vendored packages should be reported as part of the standard library. +go list -f '{{if .Standard}}{{.ImportPath}}{{end}}' std cmd +stdout ^vendor/golang\.org/x/net/http2/hpack +stdout ^cmd/vendor/golang\.org/x/arch/x86/x86asm +! stdout ^golang\.org/x/ + +# The dependencies of those packages should also be vendored. +go list -deps vendor/golang.org/x/crypto/chacha20 +stdout ^vendor/golang\.org/x/crypto/internal/alias + +# cmd/... should match the same packages it used to match in GOPATH mode. +go list cmd/... +stdout ^cmd/compile +! stdout ^cmd/vendor/golang\.org/x/arch/x86/x86asm + +# GOROOT/src/... should list the packages in std as if it were a module +# dependency: omitting vendored dependencies and stopping at the 'cmd' module +# boundary. + +go list $GOROOT/src/... +stdout ^bytes$ +! stdout ^builtin$ +! stdout ^cmd/ +! stdout ^vendor/ +! stdout ^golang\.org/x/ + + +# Vendored dependencies should appear with their 'vendor/' paths in std (they're +# in GOROOT/src, but not in the 'std' module following the usual module-boundary +# rules). + +cd $GOROOT/src +env GOWORK=off + +go list std +stdout ^vendor/golang.org/x/net/http2/hpack +! stdout ^golang\.org/x + +# The dependencies of packages with an explicit 'vendor/' prefix should +# still themselves resolve to vendored packages. +go list -deps vendor/golang.org/x/crypto/chacha20 +stdout ^vendor/golang.org/x/crypto/internal/alias +! stdout ^golang\.org/x + +# Within the std module, the dependencies of the non-vendored packages within +# std should appear to be packages beginning with 'vendor/', not 'golang.org/…' +# module dependencies. + +go list all +! stdout ^golang.org/x/ +! stdout ^std/ +! stdout ^cmd/ +stdout ^vendor/ + +go list -deps -f '{{if not .Standard}}{{.ImportPath}}{{end}}' std +! stdout . + +# However, the 'golang.org/…' module dependencies should resolve to those same +# directories. + +go list -f '{{.Dir}}' golang.org/x/net/http2/hpack +stdout $GOROOT[/\\]src[/\\]vendor + +# Within the std module, the packages within the module should omit the 'std/' +# prefix (they retain their own identities), but should respect normal module +# boundaries (vendored packages are not included in the module, even though they +# are included in the 'std' pattern). + +go list ./... +stdout ^bytes$ +! stdout ^builtin$ +! stdout ^cmd/ +! stdout ^vendor/ +! stdout ^golang\.org/x/ + + +# Within std, the vendored dependencies of cmd should still appear to be part of cmd. + +go list -f '{{if .Standard}}{{.ImportPath}}{{end}}' cmd +stdout ^cmd/vendor/golang\.org/x/arch/x86/x86asm + +go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' cmd +! stdout . + +go list cmd/... +stdout ^cmd/compile +! stdout ^cmd/vendor/golang\.org/x/arch/x86/x86asm diff --git a/src/cmd/go/testdata/script/mod_list_sums.txt b/src/cmd/go/testdata/script/mod_list_sums.txt new file mode 100644 index 0000000..cf1c18b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_sums.txt @@ -0,0 +1,32 @@ +# https://golang.org/issue/41297: 'go list -m' should not require go.sum with +# -versions or when all args are version queries. + +go mod init m +go mod edit -require=rsc.io/quote@v1.5.1 + +go list -m -mod=readonly rsc.io/quote@latest +stdout '^rsc\.io/quote v1\.5\.2$' +! stderr . + +go list -m -mod=readonly -versions rsc.io/quote +stdout 'rsc\.io/quote v1\.0\.0 .* v1\.5\.3-pre1$' +! stderr . + +# Incidentally fetching the required version of a module records its checksum, +# just because it happens to be in the build list, and recording the checksum +# triggers an error under -mod=readonly. +# +# TODO(#41297): This should not be an error. +! go list -m -mod=readonly rsc.io/quote@<v1.5.2 +stderr '^go: updates to go.sum needed, disabled by -mod=readonly$' +! stderr 'missing go.sum entry' + +# Attempting to list the versions of a module that is not a root dependency +# causes the build list to be resolved (so that the selected version can *also* +# be identified, even though it is not relevant to this particular output). +# That, in turn, causes us to need checksums for the go.sum files for the +# modules in the module graph. +# +# TODO(#41297): This should not be an error either. +! go list -m -mod=readonly -versions rsc.io/sampler +stderr '^go: rsc\.io/quote@v1\.5\.1: missing go\.sum entry for go.mod file; to add it:\n\tgo mod download rsc\.io/quote$' diff --git a/src/cmd/go/testdata/script/mod_list_test.txt b/src/cmd/go/testdata/script/mod_list_test.txt new file mode 100644 index 0000000..f697af6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_test.txt @@ -0,0 +1,30 @@ +env GO111MODULE=on + +# go list -compiled -test must handle test-only packages +# golang.org/issue/27097. +go list -compiled -test +stdout -count=4 '^.' # 4 lines +stdout '^m$' +stdout '^m\.test$' +stdout '^m \[m\.test\]$' +stdout '^m_test \[m\.test\]$' + +# https://golang.org/issue/39974: test packages should have the Module field populated. +go list -test -f '{{.ImportPath}}{{with .Module}}: {{.Path}}{{end}}' +stdout -count=4 '^.' # 4 lines +stdout '^m: m$' +stdout '^m\.test: m$' +stdout '^m \[m\.test\]: m$' +stdout '^m_test \[m\.test\]: m$' + +-- go.mod -- +module m + +-- x_test.go -- +package x +import "testing" +func Test(t *testing.T) {} +-- x_x_test.go -- +package x_test +import "testing" +func Test(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/mod_list_test_cycle.txt b/src/cmd/go/testdata/script/mod_list_test_cycle.txt new file mode 100644 index 0000000..755e50b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_test_cycle.txt @@ -0,0 +1,23 @@ +# https://golang.org/issue/45863: a typo in a test package leading to an +# import cycle should be diagnosed, instead of causing an infinite loop. +# The failure mode of this test prior to the fix was a timeout or OOM crash. + +go list -e -test -deps ./datastore/sql + +-- go.mod -- +module golang.org/issue45863 + +go 1.17 +-- datastore/datastore_health.go -- +package datastore + +import ( + "golang.org/issue45863/datastore" + "golang.org/issue45863/datastore/sql" +) +-- datastore/sql/sql.go -- +package sql +-- datastore/sql/sql_test.go -- +package sql + +import _ "golang.org/issue45863/datastore" diff --git a/src/cmd/go/testdata/script/mod_list_update_nolatest.txt b/src/cmd/go/testdata/script/mod_list_update_nolatest.txt new file mode 100644 index 0000000..7eebe26 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_update_nolatest.txt @@ -0,0 +1,55 @@ +# Check that if a proxy does not have a version of a module that could be +# an upgrade, 'go list -m -u' still succeeds. +# We use a local file proxy, since our test proxy doesn't have the behavior +# we want to test, and we don't want it to be too clever. +# Verifies #45305, where proxy.golang.org serves an empty /@v/list (200) +# but has no /@latest (410) because the go.mod at the tip of the default +# branch has a different major version suffix. +env testproxy=$GOPROXY +env GOPROXY=file:///$WORK/proxy +env GOSUMDB=off + +# If the proxy does not return a list of versions (404/410) +# or a latest version (404/410), we should see no error. +go list -m example.com/noversion +stdout '^example.com/noversion v0.0.0$' +go list -m -u example.com/noversion +stdout '^example.com/noversion v0.0.0$' + +# If the proxy returns an empty list of versions (200, not 404/410) +# but does not have a latest version (404/410), we should see no error. +go list -m example.com/nolatest +stdout '^example.com/nolatest v0.0.0$' +go list -m -u example.com/nolatest +stdout '^example.com/nolatest v0.0.0$' + +# If proxy returns an invalid response, we should see an error. +env GOPROXY=$testproxy/invalid +! go list -m -u example.com/nolatest +stderr '^go: loading module retractions for example.com/nolatest@v0.0.0: invalid response from proxy "[^"]*": invalid character ''i'' looking for beginning of value$' + +-- go.mod -- +module m + +go 1.17 + +require ( + example.com/nolatest v0.0.0 + example.com/noversion v0.0.0 +) +-- go.sum -- +example.com/nolatest v0.0.0/go.mod h1:HnLrCt6SJga5tCtJ7IzG9dOOCniY3G5C0VT7jfMdS0M= +example.com/noversion v0.0.0/go.mod h1:2RUfWiCYsygSXPM2Igxx0FD3Kq33OnVdxm34eDDhXbQ= +-- $WORK/proxy/example.com/nolatest/@v/list -- +-- $WORK/proxy/example.com/nolatest/@v/v0.0.0.info -- +{"Version":"v0.0.0"} +-- $WORK/proxy/example.com/nolatest/@v/v0.0.0.mod -- +module example.com/nolatest + +go 1.17 +-- $WORK/proxy/example.com/noversion/@v/v0.0.0.info -- +{"Version":"v0.0.0"} +-- $WORK/proxy/example.com/noversion/@v/v0.0.0.mod -- +module example.com/noversion + +go 1.17 diff --git a/src/cmd/go/testdata/script/mod_list_upgrade.txt b/src/cmd/go/testdata/script/mod_list_upgrade.txt new file mode 100644 index 0000000..0cef04b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_upgrade.txt @@ -0,0 +1,12 @@ +env GO111MODULE=on + +# Populate go.sum +go list -m -mod=mod all + +# Check for upgrades. +go list -m -u all +stdout 'rsc.io/quote v1.2.0 \[v1\.5\.2\]' + +-- go.mod -- +module x +require rsc.io/quote v1.2.0 diff --git a/src/cmd/go/testdata/script/mod_list_upgrade_pseudo.txt b/src/cmd/go/testdata/script/mod_list_upgrade_pseudo.txt new file mode 100644 index 0000000..8e51dfc --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_upgrade_pseudo.txt @@ -0,0 +1,26 @@ +env GO111MODULE=on + +# For this test module there are three versions: +# * v0.1.1-0.20190429073117-b5426c86b553 +# * v0.1.0 +# * v0.0.0-20190430073000-30950c05d534 +# Only v0.1.0 is tagged. +# +# The v0.1.1 pseudo-version is semantically higher than the latest tag. +# The v0.0.0 pseudo-version is chronologically newer. + +# The latest pseudo-version is semantically higher than the latest tag. +# 'list -u' should not suggest a lower version as an upgrade. + +go get example.com/pseudoupgrade@b5426c8 +go list -m -u all +stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$' + +go get example.com/pseudoupgrade@v0.0.0-20190430073000-30950c05d534 +go list -m -u all +stdout '^example.com/pseudoupgrade v0.0.0-20190430073000-30950c05d534$' + +-- go.mod -- +module x + +go 1.12 diff --git a/src/cmd/go/testdata/script/mod_load_badchain.txt b/src/cmd/go/testdata/script/mod_load_badchain.txt new file mode 100644 index 0000000..500a954 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_load_badchain.txt @@ -0,0 +1,110 @@ +[short] skip +env GO111MODULE=on + +# Download everything to avoid "finding" messages in stderr later. +cp go.mod.orig go.mod +go mod download +go mod download example.com@v1.0.0 +go mod download example.com/badchain/a@v1.1.0 +go mod download example.com/badchain/b@v1.1.0 +go mod download example.com/badchain/c@v1.1.0 + +# Try to update example.com/badchain/a (and its dependencies). +! go get example.com/badchain/a +cmp stderr update-a-expected +cmp go.mod go.mod.orig + +# Try to update the main module. This updates everything, including +# modules that aren't direct requirements, so the error stack is shorter. +go get -u ./... +cmp stderr update-main-expected +cmp go.mod go.mod.withc + +# Update manually. Listing modules should produce an error. +cp go.mod.orig go.mod +go mod edit -require=example.com/badchain/a@v1.1.0 +! go list -m all +cmp stderr list-expected + +# Try listing a package that imports a package +# in a module without a requirement. +go mod edit -droprequire example.com/badchain/a +! go list -mod=mod m/use +cmp stderr list-missing-expected + +! go list -mod=mod -test m/testuse +cmp stderr list-missing-test-expected + +-- go.mod.orig -- +module m + +go 1.13 + +require example.com/badchain/a v1.0.0 +-- go.mod.withc -- +module m + +go 1.13 + +require ( + example.com/badchain/a v1.0.0 + example.com/badchain/c v1.0.0 +) +-- go.sum -- +example.com/badchain/a v1.0.0 h1:iJDLiHLmpQgr9Zrv+44UqywAE2IG6WkHnH4uG08vf+s= +example.com/badchain/a v1.0.0/go.mod h1:6/gnCYHdVrs6mUgatUYUSbuHxEY+/yWedmTggLz23EI= +example.com/badchain/a v1.1.0 h1:cPxQpsOjaIrn05yDfl4dFFgGSbjYmytLqtIIBfTsEqA= +example.com/badchain/a v1.1.0/go.mod h1:T15b2BEK+RY7h7Lr2dgS38p1pgH5/t7Kf5nQXBlcW/A= +example.com/badchain/b v1.0.0 h1:kjDVlBxpjQavYxHE7ECCyyXhfwsfhWIqvghfRgPktSA= +example.com/badchain/b v1.0.0/go.mod h1:sYsH934pMc3/A2vQZh019qrWmp4+k87l3O0VFUYqL+I= +example.com/badchain/b v1.1.0 h1:iEALV+DRN62FArnYylBR4YwCALn/hCdITvhdagHa0L4= +example.com/badchain/b v1.1.0/go.mod h1:mlCgKO7lRZ+ijwMFIBFRPCGt5r5oqCcHdhSSE0VL4uY= +example.com/badchain/c v1.0.0 h1:lOeUHQKR7SboSH7Bj6eIDWoNHaDQXI0T2GfaH2x9fNA= +example.com/badchain/c v1.0.0/go.mod h1:4U3gzno17SaQ2koSVNxITu9r60CeLSgye9y4/5LnfOE= +example.com/badchain/c v1.1.0 h1:VtTg1g7fOutWKHQf+ag04KLRpdMGSfQ9s9tagVtGW14= +example.com/badchain/c v1.1.0/go.mod h1:tyoJj5qh+qtb48sflwdVvk4R+OjPQEY2UJOoibsVLPk= +-- use/use.go -- +package use + +import _ "example.com/badchain/c" +-- testuse/testuse.go -- +package testuse +-- testuse/testuse_test.go -- +package testuse + +import ( + "testing" + _ "example.com/badchain/c" +) + +func Test(t *testing.T) {} +-- update-main-expected -- +go: example.com/badchain/c@v1.1.0: parsing go.mod: + module declares its path as: badchain.example.com/c + but was required as: example.com/badchain/c + restoring example.com/badchain/c@v1.0.0 +-- update-a-expected -- +go: example.com/badchain/a@upgrade (v1.1.0) indirectly requires example.com/badchain/c@v1.1.0: parsing go.mod: + module declares its path as: badchain.example.com/c + but was required as: example.com/badchain/c +-- list-expected -- +go: example.com/badchain/a@v1.1.0 requires + example.com/badchain/b@v1.1.0 requires + example.com/badchain/c@v1.1.0: parsing go.mod: + module declares its path as: badchain.example.com/c + but was required as: example.com/badchain/c +-- list-missing-expected -- +go: finding module for package example.com/badchain/c +go: found example.com/badchain/c in example.com/badchain/c v1.1.0 +go: m/use imports + example.com/badchain/c: example.com/badchain/c@v1.1.0: parsing go.mod: + module declares its path as: badchain.example.com/c + but was required as: example.com/badchain/c +-- list-missing-test-expected -- +go: finding module for package example.com/badchain/c +go: found example.com/badchain/c in example.com/badchain/c v1.1.0 +go: m/testuse tested by + m/testuse.test imports + example.com/badchain/c: example.com/badchain/c@v1.1.0: parsing go.mod: + module declares its path as: badchain.example.com/c + but was required as: example.com/badchain/c diff --git a/src/cmd/go/testdata/script/mod_load_badmod.txt b/src/cmd/go/testdata/script/mod_load_badmod.txt new file mode 100644 index 0000000..fa22e18 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_load_badmod.txt @@ -0,0 +1,25 @@ +# Unknown lines should be ignored in dependency go.mod files. +go list -m -mod=mod all + +# ... and in replaced dependency go.mod files. +cp go.mod go.mod.usesub +go list -m -mod=mod all + +# ... but not in the main module. +cp go.mod.bad go.mod +! go list -m -mod=mod all +stderr 'unknown directive: hello' + +-- go.mod -- +module m +require rsc.io/badmod v1.0.0 +-- go.mod.bad -- +module m +hello world +-- go.mod.usesub -- +module m +require rsc.io/badmod v1.0.0 +replace rsc.io/badmod v1.0.0 => ./sub +-- sub/go.mod -- +module sub +hello world diff --git a/src/cmd/go/testdata/script/mod_load_badzip.txt b/src/cmd/go/testdata/script/mod_load_badzip.txt new file mode 100644 index 0000000..58160b4 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_load_badzip.txt @@ -0,0 +1,13 @@ +# Zip files with unexpected file names inside should be rejected. +env GO111MODULE=on + +! go get rsc.io/badzip +stderr 'zip for rsc.io/badzip@v1.0.0 has unexpected file rsc.io/badzip@v1.0.0.txt' +! grep rsc.io/badzip go.mod + +go mod edit -require rsc.io/badzip@v1.0.0 +! go build -mod=mod rsc.io/badzip +stderr 'zip for rsc.io/badzip@v1.0.0 has unexpected file rsc.io/badzip@v1.0.0.txt' + +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/mod_load_replace_mismatch.txt b/src/cmd/go/testdata/script/mod_load_replace_mismatch.txt new file mode 100644 index 0000000..2ca8b3c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_load_replace_mismatch.txt @@ -0,0 +1,23 @@ +# If a replacement module declares a module path different from both +# the original module and its location, report an error with all three paths. +# In particular, the "required as" path should be the original. +# Verifies golang.org/issue/38220. +! go mod download +cmp stderr want + +-- go.mod -- +module m + +require rsc.io/quote v1.5.2 + +replace rsc.io/quote v1.5.2 => example.com/quote v1.5.2 + +-- use.go -- +package use + +import _ "rsc.io/quote" + +-- want -- +go: rsc.io/quote@v1.5.2 (replaced by example.com/quote@v1.5.2): parsing go.mod: + module declares its path as: rsc.io/Quote + but was required as: rsc.io/quote diff --git a/src/cmd/go/testdata/script/mod_local_replace.txt b/src/cmd/go/testdata/script/mod_local_replace.txt new file mode 100644 index 0000000..19bc8f3 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_local_replace.txt @@ -0,0 +1,23 @@ +# Test that local replacements work even with dummy module names. +# golang.org/issue/24100. + +env GO111MODULE=on + +cd x/y +go list -f '{{.Dir}}' zz +stdout x[/\\]z$ + +-- x/y/go.mod -- +module x/y +require zz v1.0.0 +replace zz v1.0.0 => ../z + +-- x/y/y.go -- +package y +import _ "zz" + +-- x/z/go.mod -- +module x/z + +-- x/z/z.go -- +package z diff --git a/src/cmd/go/testdata/script/mod_missing_repo.txt b/src/cmd/go/testdata/script/mod_missing_repo.txt new file mode 100644 index 0000000..d0076f7 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_missing_repo.txt @@ -0,0 +1,15 @@ +# Regression test for golang.org/issue/34094: modules hosted within gitlab.com +# subgroups could not be fetched because the server returned bogus go-import +# tags for prefixes of the module path. + +[short] skip +[!git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +! go mod download vcs-test.golang.org/go/missingrepo/missingrepo-git@latest +stderr 'vcs-test.golang.org/go/missingrepo/missingrepo-git: git ls-remote .*: exit status .*' + +go mod download vcs-test.golang.org/go/missingrepo/missingrepo-git/notmissing@latest diff --git a/src/cmd/go/testdata/script/mod_missingpkg_prerelease.txt b/src/cmd/go/testdata/script/mod_missingpkg_prerelease.txt new file mode 100644 index 0000000..9c250e7 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_missingpkg_prerelease.txt @@ -0,0 +1,17 @@ +env GO111MODULE=on + +! go list -mod=mod -deps use.go +stderr '^use.go:4:2: package example.com/missingpkg/deprecated provided by example.com/missingpkg at latest version v1.0.0 but not at required version v1.0.1-beta$' + +-- go.mod -- +module m + +go 1.14 + +-- use.go -- +package use + +import ( + _ "example.com/missingpkg/deprecated" + _ "example.com/usemissingpre" +) diff --git a/src/cmd/go/testdata/script/mod_modinfo.txt b/src/cmd/go/testdata/script/mod_modinfo.txt new file mode 100644 index 0000000..8d77e22 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_modinfo.txt @@ -0,0 +1,89 @@ +# Test to ensure runtime/debug.ReadBuildInfo parses +# the modinfo embedded in a binary by the go tool +# when module is enabled. +env GO111MODULE=on + +cd x +go mod edit -require=rsc.io/quote@v1.5.2 +go mod edit -replace=rsc.io/quote@v1.5.2=rsc.io/quote@v1.0.0 +go mod tidy # populate go.sum + +# Build a binary and ensure that it can output its own debug info. +# The debug info should be accessible before main starts (golang.org/issue/29628). +go build +exec ./x$GOEXE +stderr 'mod\s+x\s+\(devel\)' +stderr 'dep\s+rsc.io/quote\s+v1.5.2\s+' +stderr '=>\s+rsc.io/quote\s+v1.0.0\s+h1:' +stderr 'Hello, world.' + +[short] skip + +# Build a binary that accesses its debug info by reading the binary directly +# (rather than through debug.ReadBuildInfo). +# The debug info should still be present (golang.org/issue/28753). +cd unused +go build +exec ./unused$GOEXE + +-- x/go.mod -- +module x + +-- x/lib/lib.go -- +// Package lib accesses runtime/debug.modinfo before package main's init +// functions have run. +package lib + +import "runtime/debug" + +func init() { + m, ok := debug.ReadBuildInfo() + if !ok { + panic("failed debug.ReadBuildInfo") + } + println("mod", m.Main.Path, m.Main.Version) + for _, d := range m.Deps { + println("dep", d.Path, d.Version, d.Sum) + if r := d.Replace; r != nil { + println("=>", r.Path, r.Version, r.Sum) + } + } +} + +-- x/main.go -- +package main + +import ( + "rsc.io/quote" + _ "x/lib" +) + +func main() { + println(quote.Hello()) +} + +-- x/unused/main.go -- +// The unused binary does not access runtime/debug.modinfo. +package main + +import ( + "bytes" + "encoding/hex" + "log" + "os" + + _ "rsc.io/quote" +) + +func main() { + b, err := os.ReadFile(os.Args[0]) + if err != nil { + log.Fatal(err) + } + + infoStart, _ := hex.DecodeString("3077af0c9274080241e1c107e6d618e6") + if !bytes.Contains(b, infoStart) { + log.Fatal("infoStart not found in binary") + } + log.Println("ok") +} diff --git a/src/cmd/go/testdata/script/mod_multirepo.txt b/src/cmd/go/testdata/script/mod_multirepo.txt new file mode 100644 index 0000000..bbefb78 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_multirepo.txt @@ -0,0 +1,41 @@ +env GO111MODULE=on + +# initial standalone module should use no downloaded modules +go list -deps -f {{.Dir}} +! stdout 'pkg[\\/]mod' + +# v2 import should use a downloaded module +# both without an explicit go.mod entry ... +cp tmp/use_v2.go x.go +go get . +go list -deps -f {{.Dir}} +stdout 'pkg[\\/]mod[\\/]rsc.io[\\/]quote[\\/]v2@v2.0.1$' + +# ... and with one ... +cp tmp/use_v2.mod go.mod +go list -deps -f {{.Dir}} +stdout 'pkg[\\/]mod[\\/]rsc.io[\\/]quote[\\/]v2@v2.0.1$' + +# ... and even if there is a v2 module in a subdirectory. +mkdir v2 +cp x.go v2/x.go +cp tmp/v2.mod v2/go.mod +go list -deps -f {{.Dir}} +stdout 'pkg[\\/]mod[\\/]rsc.io[\\/]quote[\\/]v2@v2.0.1$' + +-- go.mod -- +module rsc.io/quote + +-- x.go -- +package quote + +-- tmp/use_v2.go -- +package quote +import _ "rsc.io/quote/v2" + +-- tmp/use_v2.mod -- +module rsc.io/quote +require rsc.io/quote/v2 v2.0.1 + +-- tmp/v2.mod -- +package rsc.io/quote/v2 diff --git a/src/cmd/go/testdata/script/mod_no_gopath.txt b/src/cmd/go/testdata/script/mod_no_gopath.txt new file mode 100644 index 0000000..ed91f5d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_no_gopath.txt @@ -0,0 +1,15 @@ +# https://golang.org/issue/43938: 'go build' should succeed +# if GOPATH and the variables needed for its default value +# are all unset but not relevant to the specific command. + +env HOME='' +env home='' +env GOPATH='' + +go list -deps main.go +stdout '^io$' + +-- main.go -- +package main + +import _ "io" diff --git a/src/cmd/go/testdata/script/mod_nomod.txt b/src/cmd/go/testdata/script/mod_nomod.txt new file mode 100644 index 0000000..7e0f55a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_nomod.txt @@ -0,0 +1,43 @@ +# Test go commands with no module. +env GO111MODULE=on + +# go mod edit fails unless given explicit mod file argument +! go mod edit -json +go mod edit -json x.mod + +# bug succeeds +[exec:echo] env BROWSER=echo +[exec:echo] go bug + +# commands that load the package in the current directory fail +! go build +! go fmt +! go generate +! go get +! go install +! go list +! go run +! go test +! go vet + +# clean succeeds, even with -modcache +go clean -modcache + +# doc succeeds for standard library +go doc unsafe + +# env succeeds +go env + +# tool succeeds +go tool -n test2json + +# version succeeds +go version + +-- x.mod -- +module m + +-- x.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/mod_notall.txt b/src/cmd/go/testdata/script/mod_notall.txt new file mode 100644 index 0000000..1657c8d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_notall.txt @@ -0,0 +1,99 @@ +# This test demonstrates go commands that combine the 'all' pattern +# with packages outside of 'all'. + +# With -deps, 'all' should include test dependencies of packages in the main +# module, but not should not include test dependencies of packages imported only +# by other root patterns. + +env GOFLAGS=-mod=mod +cp go.mod go.mod.orig + +go list -deps all x/otherroot + +stdout '^x/inall$' +stdout '^x/inall/fromtest$' +stdout '^x/inall/fromtestinall$' +stdout '^x/otherroot$' +stdout '^x/otherdep$' + +! stdout '^x/fromotherroottest$' +! stdout '^y/fromotherdeptest$' + +cmp go.mod go.mod.orig + +# With -deps -test, test dependencies of other roots should be included, +# but test dependencies of non-roots should not. + +go list -deps -test all x/otherroot +stdout '^x/inall$' +stdout '^x/inall/fromtest$' +stdout '^x/inall/fromtestinall$' +stdout '^x/otherroot$' +stdout '^x/otherdep$' + +stdout '^x/fromotherroottest$' +! stdout '^y/fromotherdeptest$' + +cmp go.mod go.mod.orig + +-- m.go -- +package m + +import _ "x/inall" +-- m_test.go -- +package m_test + +import _ "x/inall/fromtest" +-- go.mod -- +module m + +go 1.15 + +require x v0.1.0 + +replace ( + x v0.1.0 => ./x + y v0.1.0 => ./y +) +-- x/go.mod -- +module x + +go 1.15 +-- x/inall/inall.go -- +package inall +-- x/inall/inall_test.go -- +package inall_test + +import _ "x/inall/fromtestinall" +-- x/inall/fromtest/fromtest.go -- +package fromtest +-- x/inall/fromtestinall/fromtestinall.go -- +package fromtestinall +-- x/otherroot/otherroot.go -- +package otherroot + +import _ "x/otherdep" +-- x/otherroot/otherroot_test.go -- +package otherroot_test + +import _ "x/fromotherroottest" +-- x/fromotherroottest/fromotherroottest.go -- +package fromotherroottest +-- x/otherdep/otherdep.go -- +package otherdep +-- x/otherdep/otherdep_test.go -- +package otherdep_test + +import _ "y/fromotherdeptest" +-- x/otherroot/testonly/testonly.go -- +package testonly +-- y/go.mod -- +module y + +go 1.15 +-- y/fromotherdeptest/fromotherdeptest.go -- +// Package fromotherdeptest is a test dependency of x/otherdep that is +// not declared in x/go.mod. If the loader resolves this package, +// it will add this module to the main module's go.mod file, +// and we can detect the mistake. +package fromotherdeptest diff --git a/src/cmd/go/testdata/script/mod_off.txt b/src/cmd/go/testdata/script/mod_off.txt new file mode 100644 index 0000000..a73a58d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_off.txt @@ -0,0 +1,35 @@ +env GO111MODULE=off + +# This script tests that running go mod with +# GO111MODULE=off when outside of GOPATH will fatal +# with an error message, even with some source code in the directory and a go.mod. +! go mod init +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' +! go mod graph +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' +! go mod verify +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' +! go mod download +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' + +# Same result in an empty directory +mkdir z +cd z +! go mod init +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' +! go mod graph +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' +! go mod verify +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' +! go mod download +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' + +-- sample.go -- +package sample + +func main() {} + +-- go.mod -- +module sample + +go 1.12 diff --git a/src/cmd/go/testdata/script/mod_off_init.txt b/src/cmd/go/testdata/script/mod_off_init.txt new file mode 100644 index 0000000..2aec0b3 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_off_init.txt @@ -0,0 +1,5 @@ +# 'go mod init' should refuse to initialize a module if it will be +# ignored anyway due to GO111MODULE=off. +env GO111MODULE=off +! go mod init +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' diff --git a/src/cmd/go/testdata/script/mod_outside.txt b/src/cmd/go/testdata/script/mod_outside.txt new file mode 100644 index 0000000..7a0dc9f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_outside.txt @@ -0,0 +1,315 @@ +env GO111MODULE=on +[short] skip + +# This script tests commands in module mode outside of any module. +# +# First, ensure that we really are in module mode, and that we really don't have +# a go.mod file. +go env GOMOD +stdout 'NUL|/dev/null' + + +# 'go list' without arguments implicitly operates on the current directory, +# which is not in a module. +! go list +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' +go list -m +stdout '^command-line-arguments$' +# 'go list' in the working directory should fail even if there is a a 'package +# main' present: without a main module, we do not know its package path. +! go list ./needmod +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go list all' lists the transitive import graph of the main module, +# which is empty if there is no main module. +go list all +! stdout . +stderr 'warning: "all" matched no packages' + +# 'go list' on standard-library packages should work, since they do not depend +# on the contents of any module. +go list -deps cmd +stdout '^fmt$' +stdout '^cmd/go$' + +go list $GOROOT/src/fmt +stdout '^fmt$' + +# 'go list' should work with file arguments. +go list ./needmod/needmod.go +stdout 'command-line-arguments' + +# 'go list' on a package from a module should fail. +! go list example.com/printversion +stderr '^no required module provides package example.com/printversion: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + + +# 'go list -m' with an explicit version should resolve that version. +go list -m example.com/version@latest +stdout 'example.com/version v1.1.0' + +# 'go list -m -versions' should succeed even without an explicit version. +go list -m -versions example.com/version +stdout 'v1.0.0\s+v1.0.1\s+v1.1.0' + +# 'go list -m all' should fail. "all" is not meaningful outside of a module. +! go list -m all +stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go list -m <mods> all' should also fail. +! go list -m example.com/printversion@v1.0.0 all +stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$' +! stdout 'example.com/version' + +# 'go list -m <mods>' should fail if any of the mods lacks an explicit version. +! go list -m example.com/printversion +stderr 'go: cannot match "example.com/printversion" without -versions or an explicit version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' +! stdout 'example.com/version' + +# 'go list -m' with wildcards should fail. Wildcards match modules in the +# build list, so they aren't meaningful outside a module. +! go list -m ... +stderr 'go: cannot match "...": go.mod file not found in current directory or any parent directory; see ''go help modules''$' +! go list -m rsc.io/quote/... +stderr 'go: cannot match "rsc.io/quote/...": go.mod file not found in current directory or any parent directory; see ''go help modules''$' + + +# 'go clean' should skip the current directory if it isn't in a module. +go clean -n +! stdout . +! stderr . + +# 'go mod graph' should fail, since there's no module graph. +! go mod graph +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go mod why' should fail, since there is no main module to depend on anything. +! go mod why -m example.com/version +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go mod edit', 'go mod tidy', and 'go mod fmt' should fail: +# there is no go.mod file to edit. +! go mod tidy +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' +! go mod edit -fmt +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' +! go mod edit -require example.com/version@v1.0.0 +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + + +# 'go mod download' without arguments should report an error. +! go mod download +stderr 'no modules specified' + +# 'go mod download' should download exactly the requested module without dependencies. +rm -r $GOPATH/pkg/mod/cache/download/example.com +go mod download example.com/printversion@v1.0.0 +exists $GOPATH/pkg/mod/cache/download/example.com/printversion/@v/v1.0.0.zip +! exists $GOPATH/pkg/mod/cache/download/example.com/version/@v/v1.0.0.zip + +# 'go mod download all' should fail. "all" is not meaningful outside of a module. +! go mod download all +stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$' + + +# 'go mod vendor' should fail: it starts by clearing the existing vendor +# directory, and we don't know where that is. +! go mod vendor +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + + +# 'go mod verify' should fail: we have no modules to verify. +! go mod verify +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + + +# 'go get' has no go.mod file to update outside a module and should fail. +! go get +stderr '^go: go.mod file not found in current directory or any parent directory.$' +stderr '^\t''go get'' is no longer supported outside a module.$' +! go get -u +stderr '^go: go.mod file not found in current directory or any parent directory.$' +stderr '^\t''go get'' is no longer supported outside a module.$' +! go get -u ./needmod +stderr '^go: go.mod file not found in current directory or any parent directory.$' +stderr '^\t''go get'' is no longer supported outside a module.$' +! go get -u all +stderr '^go: go.mod file not found in current directory or any parent directory.$' +stderr '^\t''go get'' is no longer supported outside a module.$' +! go get example.com/printversion@v1.0.0 example.com/version@none +stderr '^go: go.mod file not found in current directory or any parent directory.$' +stderr '^\t''go get'' is no longer supported outside a module.$' + +# 'go get' should not download anything. +go clean -modcache +! go get example.com/printversion@v1.0.0 +stderr '^go: go.mod file not found in current directory or any parent directory.$' +stderr '^\t''go get'' is no longer supported outside a module.$' +! exists $GOPATH/pkg/mod/example.com/printversion@v1.0.0 +! exists $GOPATH/pkg/mod/example.com/version@v1.0.0 + + +# 'go build' without arguments implicitly operates on the current directory, and should fail. +cd needmod +! go build +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' +cd .. + +# 'go build' of a non-module directory should fail too. +! go build ./needmod +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go build' of source files should fail if they import anything outside std. +! go build -n ./needmod/needmod.go +stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go build' of source files should succeed if they do not import anything outside std. +go build -n -o ignore ./stdonly/stdonly.go + +# 'go build' should succeed for standard-library packages. +go build -n fmt + +# 'go build' should use the latest version of the Go language. +go build ./newgo/newgo.go + +# 'go doc' without arguments implicitly operates on the current directory, and should fail. +# TODO(golang.org/issue/32027): currently, it succeeds. +cd needmod +go doc +cd .. + +# 'go doc' of a non-module directory should also succeed. +go doc ./needmod + +# 'go doc' should succeed for standard-library packages. +go doc fmt + +# 'go doc' should fail for a package path outside a module. +! go doc example.com/version +stderr 'doc: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go install' with a version should succeed if all constraints are met. +# See mod_install_pkg_version. +rm $GOPATH/bin +go install example.com/printversion@v0.1.0 +exists $GOPATH/bin/printversion$GOEXE + +# 'go install' should fail if a package argument must be resolved to a module. +! go install example.com/printversion +stderr '^go: ''go install'' requires a version when current directory is not in a module\n\tTry ''go install example.com/printversion@latest'' to install the latest version$' + +# 'go install' should fail if a source file imports a package that must be +# resolved to a module. +! go install ./needmod/needmod.go +stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go run' should fail if a package argument must be resolved to a module. +! go run example.com/printversion +stderr '^no required module provides package example.com/printversion: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go run' should fail if a source file imports a package that must be +# resolved to a module. +! go run ./needmod/needmod.go +stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + + +# 'go fmt' should be able to format files outside of a module. +go fmt needmod/needmod.go + + +# The remainder of the test checks dependencies by linking and running binaries. + +# 'go run' should work with file arguments if they don't import anything +# outside std. +go run ./stdonly/stdonly.go +stdout 'path is command-line-arguments$' +stdout 'main is $' + +# 'go generate' should work with file arguments. +[exec:touch] go generate ./needmod/needmod.go +[exec:touch] exists ./needmod/gen.txt + +# 'go install' should work with file arguments. +go install ./stdonly/stdonly.go + +# 'go test' should work with file arguments. +go test -v ./stdonly/stdonly_test.go +stdout 'stdonly was tested' + +# 'go vet' should work with file arguments. +go vet ./stdonly/stdonly.go + + +-- README.txt -- +There is no go.mod file in the working directory. + +-- needmod/needmod.go -- +//go:generate touch gen.txt + +package main + +import ( + "fmt" + "os" + "runtime/debug" + + _ "example.com/version" +) + +func main() { + info, ok := debug.ReadBuildInfo() + if !ok { + panic("missing build info") + } + fmt.Fprintf(os.Stdout, "path is %s\n", info.Path) + fmt.Fprintf(os.Stdout, "main is %s %s\n", info.Main.Path, info.Main.Version) + for _, m := range info.Deps { + fmt.Fprintf(os.Stdout, "using %s %s\n", m.Path, m.Version) + } +} + +-- stdonly/stdonly.go -- +package main + +import ( + "fmt" + "os" + "runtime/debug" +) + +func main() { + info, ok := debug.ReadBuildInfo() + if !ok { + panic("missing build info") + } + fmt.Fprintf(os.Stdout, "path is %s\n", info.Path) + fmt.Fprintf(os.Stdout, "main is %s %s\n", info.Main.Path, info.Main.Version) + for _, m := range info.Deps { + fmt.Fprintf(os.Stdout, "using %s %s\n", m.Path, m.Version) + } +} + +-- stdonly/stdonly_test.go -- +package main + +import ( + "fmt" + "testing" +) + +func Test(t *testing.T) { + fmt.Println("stdonly was tested") +} + +-- newgo/newgo.go -- +// Package newgo requires Go 1.14 or newer. +package newgo + +import "io" + +const C = 299_792_458 + +type ReadWriteCloser interface { + io.ReadCloser + io.WriteCloser +} diff --git a/src/cmd/go/testdata/script/mod_overlay.txt b/src/cmd/go/testdata/script/mod_overlay.txt new file mode 100644 index 0000000..da35be6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_overlay.txt @@ -0,0 +1,254 @@ +# Test overlays that affect go.mod files + +# The go.mod file can exist only in the overlay. +cd $WORK/gopath/src/no-go-mod +go list -overlay overlay.json . +stdout example.com/simple + +# Check content of overlaid go.mod is used. +cd $WORK/gopath/src/overlay-go-mod +go list -overlay overlay.json . +stdout use.this/module/name + +# Check content of overlaid go.mod in a replacement module is used. +# The go.mod in the replacement module is missing a requirement +# that the overlay has, so it will fail to list without the overlay. +cd $WORK/gopath/src/overlay-replaced-go-mod +! go list -deps . +go list -deps -overlay overlay.json . + +# Overlaid go.mod is not rewritten by 'go get'. +cd $WORK/gopath/src/get-doesnt-add-dep +cp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod +! go get -overlay overlay.json . +stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$' +cmp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod + +# Content of overlaid go.sum is used. +# The go.sum in the module directory has garbage values for its +# hashes, but the overlaid file has the correct values. If +# the correct go.sum is used with the overlay, 'go get .' should +# not report a security error. +cd $WORK/gopath/src/overlay-sum-used +! go get . +stderr 'SECURITY ERROR' +! go mod verify +stderr 'SECURITY ERROR' +go get -overlay overlay.json . +go mod verify -overlay overlay.json +# Overlaid go.sum is not rewritten. +# Copy an incomplete file to the overlay file, and expect an error +# attempting to update the file +cp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums +! go get -overlay overlay.json . +stderr '^go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay$' +cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums +! go mod tidy -overlay overlay.json +stderr '^go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay$' +cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums + +# -overlay works with -modfile. +# There's an empty go.mod file in the directory, and the file alternate.mod is +# overlaid to the true go.mod file, so the -modfile flag and the overlay +# mechanism need to work together to determine the name of the module. +cd $WORK/gopath/src/overlay-and-dash-modfile +go list -modfile=alternate.mod -overlay overlay.json . +stdout 'found.the/module' +# Even with -modfile, overlaid files can't be opened for write. +! go get -modfile=alternate.mod -overlay overlay.json rsc.io/quote +stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$' + +# Carving out a module by adding an overlaid go.mod file +cd $WORK/gopath/src/carve +go list ./... # without an overlay, hasmod is carved out and nomod isn't +stdout carve/nomod +! stdout carve/hasmod +go list -overlay overlay_carve_module.json ./... # The overlay carves out nomod, leaving nothing +! stdout . +stderr 'matched no packages' +go list -overlay overlay_uncarve_module.json ./... # The overlay uncarves out hasmod +stdout carve/nomod +stdout carve/hasmod + +# Carving out a module by adding an overlaid go.mod file and using +# -modfile to write to that file. +cd $WORK/gopath/src/carve2/nomod +go list -overlay overlay.json all +! stdout ^carve2$ +stdout ^carve2/nomod$ +# Editing go.mod file fails because overlay is read only +! go get -overlay overlay.json rsc.io/quote +stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$' +! grep rsc.io/quote $WORK/overlay/carve2-nomod-go.mod +# Editing go.mod file succeeds because we use -modfile to redirect to same file +go get -overlay overlay.json -modfile $WORK/overlay/carve2-nomod-go.mod rsc.io/quote +grep rsc.io/quote $WORK/overlay/carve2-nomod-go.mod + +-- no-go-mod/file.go -- +package simple +-- no-go-mod/overlay.json -- +{ + "Replace": { + "go.mod": "../../../overlay/simple_go_mod" + } +} +-- $WORK/overlay/simple_go_mod -- +module example.com/simple +-- overlay-go-mod/file.go -- +package name +-- overlay-go-mod/go.mod -- +module dont.use/this/module/name +-- overlay-go-mod/overlay.json -- +{ + "Replace": { + "go.mod": "../../../overlay/use_this_go_mod" + } +} +-- $WORK/overlay/use_this_go_mod -- +module use.this/module/name +-- overlay-replaced-go-mod/go.mod -- +module m + +go 1.15 + +require replaced/mod v1.0.0 +replace replaced/mod v1.0.0 => ../replaced-mod +replace dep/mod v1.0.0 => ../dep-mod +-- overlay-replaced-go-mod/source.go -- +package m + +import "replaced/mod/foo" + +func main() { + foo.f() +} +-- overlay-replaced-go-mod/overlay.json -- +{ + "Replace": { + "../replaced-mod/go.mod": "../../../overlay/replacement_module_go_mod" + } +} +-- replaced-mod/go.mod -- +module replaced/mod +-- replaced-mod/foo/foo.go -- +package foo + +import "dep/mod/foo" + +func f() { foo.g() } +-- dep-mod/go.mod -- +invalid +-- dep-mod/foo/foo.go -- +package foo + +func g() { fmt.Println("hello") } +-- $WORK/overlay/replacement_module_go_mod -- +module replaced/mod + +require dep/mod v1.0.0 + +-- get-doesnt-add-dep/overlay.json -- +{ + "Replace": { + "go.mod": "../../../overlay/get_doesnt_add_dep_go_mod" + } +} +-- get-doesnt-add-dep/p.go -- +package p + +import "dependency/mod" + +func f() { mod.G() } +-- get-doesnt-add-dep-dependency/go.mod -- +module dependency/mod +-- get-doesnt-add-dep-dependency/mod.go -- +package mod + +func G() {} +-- $WORK/overlay/get_doesnt_add_dep_go_mod -- +module get.doesnt/add/dep + +replace dependency/mod v1.0.0 => ../get-doesnt-add-dep-dependency +-- overlay-sum-used/go.mod -- +module overlay.sum/used + +require rsc.io/quote v1.5.0 +-- overlay-sum-used/p.go -- +package p + +import "rsc.io/quote" + +func f() string { + return quote.Hello() +} +-- overlay-sum-used/incomplete-sum-file -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +rsc.io/quote v1.5.0 h1:6fJa6E+wGadANKkUMlZ0DhXFpoKlslOQDCo259XtdIE= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +-- overlay-sum-used/overlay.json -- +{ + "Replace": { + "go.sum": "../../../overlay/overlay-sum-used-correct-sums" + } +} +-- overlay-sum-used/go.sum -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:garbage+hash +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:garbage+hash +rsc.io/quote v1.5.0 h1:garbage+hash +rsc.io/quote v1.5.0/go.mod h1:garbage+hash +rsc.io/sampler v1.3.0 h1:garbage+hash +rsc.io/sampler v1.3.0/go.mod h1:garbage+hash +-- $WORK/overlay/overlay-sum-used-correct-sums -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.0 h1:6fJa6E+wGadANKkUMlZ0DhXFpoKlslOQDCo259XtdIE= +rsc.io/quote v1.5.0/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +-- overlay-and-dash-modfile/p.go -- +package module +-- overlay-and-dash-modfile/go.mod -- +-- overlay-and-dash-modfile/overlay.json -- +{ + "Replace": { + "alternate.mod": "../../../overlay/overlay-and-dash-modfile-alternate-mod" + } +} +-- $WORK/overlay/overlay-and-dash-modfile-alternate-mod -- +module found.the/module +-- carve/go.mod -- +module carve +-- carve/overlay_carve_module.json -- +{ + "Replace": { + "nomod/go.mod": "../../../overlay/carve-nomod-go-mod" + } +} +-- carve/overlay_uncarve_module.json -- +{ + "Replace": { + "hasmod/go.mod": "" + } +} +-- carve/hasmod/a.go -- +package hasmod +-- carve/hasmod/go.mod -- +module carve/hasmod +-- carve/nomod/b.go -- +package nomod +-- $WORK/overlay/carve-nomod-go-mod -- +module carve/nomod +-- carve2/go.mod -- +module carve2 +-- carve2/p.go -- +package p +-- carve2/nomod/overlay.json -- +{ + "Replace": { + "go.mod": "../../../../overlay/carve2-nomod-go.mod" + } +} +-- carve2/nomod/b.go -- +package nomod +-- $WORK/overlay/carve2-nomod-go.mod -- +module carve2/nomod diff --git a/src/cmd/go/testdata/script/mod_patterns.txt b/src/cmd/go/testdata/script/mod_patterns.txt new file mode 100644 index 0000000..1b4b438 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_patterns.txt @@ -0,0 +1,78 @@ +env GO111MODULE=on +[short] skip + +cd m + +# 'go list all' should list all of the packages used (directly or indirectly) by +# the packages in the main module, but no other packages from the standard +# library or active modules. +# +# 'go list ...' should list packages in all active modules and the standard library. +# +# 'go list example.com/m/...' should list packages in all modules that begin with 'example.com/m/'. +# +# 'go list ./...' should list only packages in the current module, not other active modules. +# +# Warnings about unmatched patterns should only be printed once. +# +# And the go command should be able to keep track of all this! +go list -f '{{.ImportPath}}: {{.Match}}' all ... example.com/m/... ./... ./xyz... +stdout 'example.com/m/useunicode: \[all \.\.\. example.com/m/... ./...\]' +stdout 'example.com/m/useunsafe: \[all \.\.\. example.com/m/... ./...\]' +[cgo] stdout 'example.com/m/useC: \[all \.\.\. example.com/m/... ./...\]' +[!cgo] ! stdout example.com/m/useC +stdout 'example.com/unused/useerrors: \[\.\.\.\]' # but not "all" +stdout 'example.com/m/nested/useencoding: \[\.\.\. example.com/m/...\]' # but NOT "all" or "./..." +stdout '^unicode: \[all \.\.\.\]' +stdout '^unsafe: \[all \.\.\.\]' +stdout 'index/suffixarray: \[\.\.\.\]' +stdout 'cmd/pprof: \[\.\.\.\]' + +stderr -count=1 '^go: warning: "./xyz..." matched no packages$' + +# 'go list ./...' should not try to resolve the main module. +cd ../empty +go list -deps ./... +! stdout . +! stderr 'finding' +stderr -count=1 '^go: warning: "./..." matched no packages' + +# disabling cgo should drop useC +[short] skip +env CGO_ENABLED=0 +go list -f '{{.ImportPath}}: {{.Match}}' all ... example.com/m/... ./... ./xyz... +! stdout example.com/m/useC + +-- m/go.mod -- +module example.com/m + +require example.com/unused v0.0.0 // indirect +replace example.com/unused => ../unused + +require example.com/m/nested v0.0.0 // indirect +replace example.com/m/nested => ../nested + +-- m/useC/useC.go -- +package useC +import _ "C" // "C" is a pseudo-package, not an actual one +-- m/useunicode/useunicode.go -- +package useunicode +import _ "unicode" +-- m/useunsafe/useunsafe.go -- +package useunsafe +import _ "unsafe" + +-- unused/go.mod -- +module example.com/unused +-- unused/useerrors/useerrors.go -- +package useerrors +import _ "errors" + +-- nested/go.mod -- +module example.com/m/nested +-- nested/useencoding/useencoding.go -- +package useencoding +import _ "encoding" + +-- empty/go.mod -- +module example.com/empty diff --git a/src/cmd/go/testdata/script/mod_patterns_vendor.txt b/src/cmd/go/testdata/script/mod_patterns_vendor.txt new file mode 100644 index 0000000..b4dc401 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_patterns_vendor.txt @@ -0,0 +1,28 @@ +env GO111MODULE=on + +go list -mod=vendor example.com/... +stdout ^example.com/x$ +stdout ^example.com/x/y$ +! stdout ^example.com/x/vendor + +-- go.mod -- +module example.com/m + +-- vendor/modules.txt -- +# example.com/x v0.0.0 +example.com/x +# example.com/x/y v0.1.0 +example.com/x/y + +-- vendor/example.com/x/go.mod -- +module example.com/x +-- vendor/example.com/x/x.go -- +package x + +-- vendor/example.com/x/y/go.mod -- +module example.com/x/y +-- vendor/example.com/x/y/y.go -- +package y + +-- vendor/example.com/x/vendor/z/z.go -- +package z diff --git a/src/cmd/go/testdata/script/mod_perm.txt b/src/cmd/go/testdata/script/mod_perm.txt new file mode 100644 index 0000000..2972f46 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_perm.txt @@ -0,0 +1,23 @@ +# go list should work in ordinary conditions. +go list ./... +! stdout _data + +# skip in conditions where chmod 0 may not work. +# plan9 should be fine, but copied from list_perm.txt unchanged. +[root] skip +[GOOS:windows] skip +[GOOS:plan9] skip + +# go list should work with unreadable _data directory. +chmod 0 _data +go list ./... +! stdout _data + +-- go.mod -- +module m + +-- x.go -- +package m + +-- _data/x.go -- +package p diff --git a/src/cmd/go/testdata/script/mod_permissions.txt b/src/cmd/go/testdata/script/mod_permissions.txt new file mode 100644 index 0000000..b523e6a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_permissions.txt @@ -0,0 +1,57 @@ +# Regression test for golang.org/issue/34634: permissions for the go.sum and +# go.mod files should be preserved when overwriting them. + +env GO111MODULE=on +[short] skip + +# Skip platforms that do not have Unix-style file permissions. +[GOOS:windows] skip +[GOOS:plan9] skip + +chmod 0640 go.mod +chmod 0604 go.sum +go mod edit -module=golang.org/issue/34634 + +go get +cmp go.mod go.mod.want +cmp go.sum go.sum.want + +go run . +stdout 'go.mod: 0640' +stdout 'go.sum: 0604' + +-- read_perm.go -- +package main + +import ( + "fmt" + "os" + _ "rsc.io/sampler" +) + +func main() { + for _, name := range []string{"go.mod", "go.sum"} { + fi, err := os.Stat(name) + if err != nil { + fmt.Fprintf(os.Stderr, "%s: %v\n", err) + continue + } + fmt.Printf("%s: 0%o\n", name, fi.Mode().Perm()) + } +} +-- go.mod -- +module TODO + +go 1.14 +-- go.sum -- +-- go.mod.want -- +module golang.org/issue/34634 + +go 1.14 + +require rsc.io/sampler v1.99.99 +-- go.sum.want -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/sampler v1.99.99 h1:iMG9lbEG/8MdeR4lgL+Q8IcwbLNw7ijW7fTiK8Miqts= +rsc.io/sampler v1.99.99/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/src/cmd/go/testdata/script/mod_prefer_compatible.txt b/src/cmd/go/testdata/script/mod_prefer_compatible.txt new file mode 100644 index 0000000..4d583ff --- /dev/null +++ b/src/cmd/go/testdata/script/mod_prefer_compatible.txt @@ -0,0 +1,80 @@ +# Regression test for golang.org/issue/34189 and golang.org/issue/34165: +# @latest, @upgrade, and @patch should prefer compatible versions over +# +incompatible ones, even if offered by a proxy. + +[!net:github.com] skip +[!net:proxy.golang.org] skip + +env GO111MODULE=on +env GOPROXY= +env GOSUMDB= + +# github.com/russross/blackfriday v2.0.0+incompatible exists, +# and should be resolved if we ask for it explicitly. + +go list -m github.com/russross/blackfriday@v2.0.0+incompatible +stdout '^github.com/russross/blackfriday v2\.0\.0\+incompatible$' + +# blackfriday v1.5.2 has a go.mod file, so v1.5.2 should be preferred over +# v2.0.0+incompatible when resolving latest, upgrade, and patch. + +go list -m github.com/russross/blackfriday@latest +stdout '^github.com/russross/blackfriday v1\.' + +go list -m github.com/russross/blackfriday@upgrade +stdout '^github.com/russross/blackfriday v1\.' + +! go list -m github.com/russross/blackfriday@patch +stderr '^go: github.com/russross/blackfriday@patch: can''t query version "patch" of module github.com/russross/blackfriday: no existing version is required$' + + +# If we're fetching directly from version control, ignored +incompatible +# versions should also be omitted by 'go list'. + +# (Note that they may still be included in results from a proxy: in proxy mode, +# we would need to fetch the whole zipfile for the latest compatible version in +# order to determine whether it contains a go.mod file, and part of the point of +# the proxy is to avoid fetching unnecessary data.) + +[!git] stop +env GOPROXY=direct + +go list -versions -m github.com/russross/blackfriday +stdout '^github.com/russross/blackfriday v1\.5\.1 v1\.5\.2' # and possibly others +! stdout ' v2\.' + +# For this module, v2.1.0 exists and has a go.mod file. +# 'go list -m github.com/russross/blackfriday@v2.0' will check +# the latest v2.0 tag, discover that it isn't the right module, and stop there +# (instead of spending the time to check O(N) previous tags). + +! go list -m github.com/russross/blackfriday@v2.0 +stderr '^go: module github.com/russross/blackfriday: no matching versions for query "v2\.0\"' + +# (But asking for exactly v2.0.0+incompatible should still succeed.) +go list -m github.com/russross/blackfriday@v2.0.0+incompatible +stdout '^github.com/russross/blackfriday v2\.0\.0\+incompatible$' + + +# However, if the latest compatible version does not include a go.mod file, +# +incompatible versions should still be listed, as they may still reflect the +# intent of the module author. + +go list -versions -m github.com/rsc/legacytest +stdout '^github.com/rsc/legacytest v1\.0\.0 v1\.1\.0-pre v1\.2\.0 v2\.0\.0\+incompatible' + +# If we're fetching directly from version control, asking for a commit hash +# corresponding to a +incompatible version should continue to produce the +# +incompatible version tagged for that commit, even if it is no longer listed. + +go list -m github.com/russross/blackfriday@cadec560ec52 +stdout '^github.com/russross/blackfriday v2\.0\.0\+incompatible$' + +# Similarly, requesting an untagged commit should continue to produce a +incompatible +# pseudo-version. + +go list -m github.com/rsc/legacytest@7303f7796364 +stdout '^github.com/rsc/legacytest v2\.0\.1-0\.20180717164253-7303f7796364\+incompatible$' + +-- go.mod -- +module github.com/golang.org/issue/34165 diff --git a/src/cmd/go/testdata/script/mod_proxy_errors.txt b/src/cmd/go/testdata/script/mod_proxy_errors.txt new file mode 100644 index 0000000..99a4ef1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_proxy_errors.txt @@ -0,0 +1,19 @@ +[short] skip + +env GO111MODULE=on +env GOSUMDB=off +env GOPROXY=direct + +# Server responses should be truncated to some reasonable number of lines. +# (For now, exactly eight.) +! go list -m vcs-test.golang.org/auth/ormanylines@latest +stderr '\tserver response:\n(.|\n)*\tline 8\n\t\[Truncated: too many lines.\]$' + +# Server responses should be truncated to some reasonable number of characters. +! go list -m vcs-test.golang.org/auth/oronelongline@latest +! stderr 'blah{40}' +stderr '\tserver response: \[Truncated: too long\.\]$' + +# Responses from servers using the 'mod' protocol should be propagated. +! go list -m vcs-test.golang.org/go/modauth404@latest +stderr '\tserver response: File\? What file\?' diff --git a/src/cmd/go/testdata/script/mod_proxy_https.txt b/src/cmd/go/testdata/script/mod_proxy_https.txt new file mode 100644 index 0000000..c87a0d9 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_proxy_https.txt @@ -0,0 +1,20 @@ +env GO111MODULE=on + +# GOPROXY file paths must provide the "file://" prefix explicitly. +env GOPROXY=$WORK/proxydir +! go list -versions -m golang.org/x/text +stderr 'invalid proxy URL.*proxydir' + +[!net:proxy.golang.org] stop + +# GOPROXY HTTPS paths may elide the "https://" prefix. +# (See golang.org/issue/32191.) +env GOPROXY=proxy.golang.org +env GOSUMDB= +go list -versions -m golang.org/x/text + +-- go.mod -- +module example.com +go 1.13 +-- $WORK/proxydir/README.md -- +This proxy contains no data. diff --git a/src/cmd/go/testdata/script/mod_proxy_invalid.txt b/src/cmd/go/testdata/script/mod_proxy_invalid.txt new file mode 100644 index 0000000..63980b8 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_proxy_invalid.txt @@ -0,0 +1,8 @@ +env GO111MODULE=on +env GOPROXY=$GOPROXY/invalid + +! go list -m rsc.io/quote@latest +stderr '^go: module rsc.io/quote: invalid response from proxy "'$GOPROXY'": invalid character ''i'' looking for beginning of value$' + +! go list -m rsc.io/quote@1.5.2 +stderr '^go: rsc.io/quote@1.5.2: invalid version: invalid response from proxy "'$GOPROXY'": invalid character ''i'' looking for beginning of value$' diff --git a/src/cmd/go/testdata/script/mod_proxy_list.txt b/src/cmd/go/testdata/script/mod_proxy_list.txt new file mode 100644 index 0000000..849cf2c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_proxy_list.txt @@ -0,0 +1,37 @@ +env GO111MODULE=on +env proxy=$GOPROXY + +# Proxy that can't serve should fail. +env GOPROXY=$proxy/404 +! go get rsc.io/quote@v1.0.0 +stderr '404 Not Found' + +# get should walk down the proxy list past 404 and 410 responses. +env GOPROXY=$proxy/404,$proxy/410,$proxy +go get rsc.io/quote@v1.1.0 + +# get should not walk past other 4xx errors if proxies are separated with ','. +env GOPROXY=$proxy/403,$proxy +! go get rsc.io/quote@v1.2.0 +stderr 'reading.*/403/rsc.io/.*: 403 Forbidden' + +# get should not walk past non-4xx errors if proxies are separated with ','. +env GOPROXY=$proxy/500,$proxy +! go get rsc.io/quote@v1.3.0 +stderr 'reading.*/500/rsc.io/.*: 500 Internal Server Error' + +# get should walk past other 4xx errors if proxies are separated with '|'. +env GOPROXY=$proxy/403|https://0.0.0.0|$proxy +go get rsc.io/quote@v1.2.0 + +# get should walk past non-4xx errors if proxies are separated with '|'. +env GOPROXY=$proxy/500|https://0.0.0.0|$proxy +go get rsc.io/quote@v1.3.0 + +# get should return the final error if that's all we have. +env GOPROXY=$proxy/404,$proxy/410 +! go get rsc.io/quote@v1.4.0 +stderr 'reading.*/410/rsc.io/.*: 410 Gone' + +-- go.mod -- +module x diff --git a/src/cmd/go/testdata/script/mod_pseudo_cache.txt b/src/cmd/go/testdata/script/mod_pseudo_cache.txt new file mode 100644 index 0000000..bcaefa2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_pseudo_cache.txt @@ -0,0 +1,29 @@ +[!net:golang.org] skip +[!git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +# Regression test for golang.org/issue/27171: after resolving an older +# pseudo-version of a commit, future resolution of that commit by hash should +# choose the highest appropriate pseudo-version instead of the cached one. + +go mod download -json golang.org/x/text@v0.0.0-20171215141712-a1b916ed6726 +stdout '"Version": "v0.0.0-20171215141712-a1b916ed6726",' + +# If GOPROXY is 'off', lookups should use whatever pseudo-version is available. +env GOPROXY=off +go mod download -json golang.org/x/text@a1b916ed6726 +stdout '"Version": "v0.0.0-20171215141712-a1b916ed6726",' + +# If we can re-resolve the commit to a pseudo-version, fetching the commit by +# hash should use the highest such pseudo-version appropriate to the commit. +env GOPROXY=direct +go mod download -json golang.org/x/text@a1b916ed6726 +stdout '"Version": "v0.3.1-0.20171215141712-a1b916ed6726",' + +# If GOPROXY is 'off', lookups should use the highest pseudo-version in the cache. +env GOPROXY=off +go mod download -json golang.org/x/text@a1b916ed6726 +stdout '"Version": "v0.3.1-0.20171215141712-a1b916ed6726",' diff --git a/src/cmd/go/testdata/script/mod_query.txt b/src/cmd/go/testdata/script/mod_query.txt new file mode 100644 index 0000000..3758732 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_query.txt @@ -0,0 +1,43 @@ +env GO111MODULE=on + +# TODO(golang.org/issue/41297): we shouldn't need go.sum. None of the commands +# below depend on the build list. + +go list -m -versions rsc.io/quote +stdout '^rsc.io/quote v1.0.0 v1.1.0 v1.2.0 v1.2.1 v1.3.0 v1.4.0 v1.5.0 v1.5.1 v1.5.2 v1.5.3-pre1$' + +# Latest rsc.io/quote should be v1.5.2, not v1.5.3-pre1. +go list -m rsc.io/quote@latest +stdout 'rsc.io/quote v1.5.2$' + +# Same for rsc.io/quote@v1 and rsc.io/quote@v1.5 (with no patch version). +go list -m rsc.io/quote@v1 +stdout 'rsc.io/quote v1.5.2$' +go list -m rsc.io/quote@v1.5 +stdout 'rsc.io/quote v1.5.2$' + +# We should fall back to prereleases if no release tags match... +go list -m rsc.io/quote@>v1.5.2 +stdout 'rsc.io/quote v1.5.3-pre1$' + +# ...but prefer release versions when given the option. +go list -m rsc.io/quote@<v1.5.4 +stdout 'rsc.io/quote v1.5.2$' + +! go list -m rsc.io/quote@>v1.5.3 +stderr 'go: module rsc.io/quote: no matching versions for query ">v1.5.3"' + +go list -m -e -f '{{.Error.Err}}' rsc.io/quote@>v1.5.3 +stdout 'no matching versions for query ">v1.5.3"' + +-- go.mod -- +module x +require rsc.io/quote v1.0.0 + +-- go.sum -- +rsc.io/quote v1.0.0 h1:kQ3IZQzPTiDJxSZI98YaWgxFEhlNdYASHvh+MplbViw= +rsc.io/quote v1.0.0/go.mod h1:v83Ri/njykPcgJltBc/gEkJTmjTsNgtO1Y7vyIK1CQA= +-- use.go -- +package use + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_query_empty.txt b/src/cmd/go/testdata/script/mod_query_empty.txt new file mode 100644 index 0000000..1c39eae --- /dev/null +++ b/src/cmd/go/testdata/script/mod_query_empty.txt @@ -0,0 +1,73 @@ +env GO111MODULE=on +env GOSUMDB=off + +go mod download example.com/join@v1.1.0 + +# If the proxy serves a bogus result for the @latest version, +# reading that version should cause 'go get' to fail. +env GOPROXY=file:///$WORK/badproxy +cp go.mod.orig go.mod +! go get example.com/join/subpkg +stderr 'go: example.com/join/subpkg@v0.0.0-20190624000000-123456abcdef: .*' + +# If @v/list is empty, the 'go' command should still try to resolve +# other module paths. +env GOPROXY=file:///$WORK/emptysub +cp go.mod.orig go.mod +go get example.com/join/subpkg +go list -m example.com/join/... +! stdout 'example.com/join/subpkg' +stdout 'example.com/join v1.1.0' + +# If @v/list includes a version that the proxy does not actually serve, +# that version is treated as nonexistent. +env GOPROXY=file:///$WORK/notfound +cp go.mod.orig go.mod +go get example.com/join/subpkg +go list -m example.com/join/... +! stdout 'example.com/join/subpkg' +stdout 'example.com/join v1.1.0' + +# If the proxy provides an empty @v/list but rejects @latest with +# some other explicit error (for example, a "permission denied" error), +# that error should be reported to the user (and override a successful +# result for other possible module paths). +# +# Depending on how the specific platform enforces permissions, the 'go get' may +# fail either due to the intended permission error or due to a parse error. +# We accept either failure message. +env GOPROXY=file:///$WORK/gatekeeper +chmod 0000 $WORK/gatekeeper/example.com/join/subpkg/@latest +cp go.mod.orig go.mod +! go get example.com/join/subpkg +stderr 'go: module example.com/join/subpkg: (invalid response from proxy ".+": invalid character .+|reading file://.*/gatekeeper/example.com/join/subpkg/@latest: .+)' + +-- go.mod.orig -- +module example.com/othermodule +go 1.13 +-- $WORK/badproxy/example.com/join/subpkg/@v/list -- +v0.0.0-20190624000000-123456abcdef +-- $WORK/badproxy/example.com/join/subpkg/@v/v0.0.0-20190624000000-123456abcdef.info -- +This file is not valid JSON. +-- $WORK/badproxy/example.com/join/@v/list -- +v1.1.0 +-- $WORK/badproxy/example.com/join/@v/v1.1.0.info -- +{"Version": "v1.1.0"} +-- $WORK/emptysub/example.com/join/subpkg/@v/list -- +-- $WORK/emptysub/example.com/join/@v/list -- +v1.1.0 +-- $WORK/emptysub/example.com/join/@v/v1.1.0.info -- +{"Version": "v1.1.0"} +-- $WORK/notfound/example.com/join/subpkg/@v/list -- +v1.0.0-does-not-exist +-- $WORK/notfound/example.com/join/@v/list -- +v1.1.0 +-- $WORK/notfound/example.com/join/@v/v1.1.0.info -- +{"Version": "v1.1.0"} +-- $WORK/gatekeeper/example.com/join/subpkg/@v/list -- +-- $WORK/gatekeeper/example.com/join/subpkg/@latest -- +ERROR: Latest version is forbidden. +-- $WORK/gatekeeper/example.com/join/@v/list -- +v1.1.0 +-- $WORK/gatekeeper/example.com/join/@v/v1.1.0.info -- +{"Version": "v1.1.0"} diff --git a/src/cmd/go/testdata/script/mod_query_exclude.txt b/src/cmd/go/testdata/script/mod_query_exclude.txt new file mode 100644 index 0000000..f76b20c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_query_exclude.txt @@ -0,0 +1,46 @@ +env GO111MODULE=on + +# list excluded version +go list -modfile=go.exclude.mod -m rsc.io/quote@v1.5.0 +stdout '^rsc.io/quote v1.5.0$' + +# list versions should not print excluded versions +go list -m -versions rsc.io/quote +stdout '\bv1.5.0\b' +go list -modfile=go.exclude.mod -m -versions rsc.io/quote +! stdout '\bv1.5.0\b' + +# list query with excluded version +go list -m rsc.io/quote@>=v1.5 +stdout '^rsc.io/quote v1.5.0$' +go list -modfile=go.exclude.mod -m rsc.io/quote@>=v1.5 +stdout '^rsc.io/quote v1.5.1$' + +# get excluded version +cp go.exclude.mod go.exclude.mod.orig +! go get -modfile=go.exclude.mod rsc.io/quote@v1.5.0 +stderr '^go: rsc.io/quote@v1.5.0: excluded by go.mod$' + +# get non-excluded version +cp go.exclude.mod.orig go.exclude.mod +go get -modfile=go.exclude.mod rsc.io/quote@v1.5.1 +stderr 'rsc.io/quote v1.5.1' + +# get query with excluded version +cp go.exclude.mod.orig go.exclude.mod +go get -modfile=go.exclude.mod rsc.io/quote@>=v1.5 +go list -modfile=go.exclude.mod -m ...quote +stdout 'rsc.io/quote v1.5.[1-9]' + +-- go.mod -- +module x + +-- go.exclude.mod -- +module x + +exclude rsc.io/quote v1.5.0 + +-- x.go -- +package x +import _ "rsc.io/quote" + diff --git a/src/cmd/go/testdata/script/mod_query_main.txt b/src/cmd/go/testdata/script/mod_query_main.txt new file mode 100644 index 0000000..2a2fa42 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_query_main.txt @@ -0,0 +1,43 @@ +# 'go mod download' can download specific versions of the main module. +go mod download rsc.io/quote@5d9f230b +go mod download rsc.io/quote@v1.5.2 +go mod download rsc.io/quote@latest + +# 'go mod download' will not download @upgrade or @patch, since they always +# resolve to the main module. +go mod download rsc.io/quote@upgrade +stderr '^go: skipping download of rsc.io/quote@upgrade that resolves to the main module$' +go mod download rsc.io/quote@patch +stderr '^go: skipping download of rsc.io/quote@patch that resolves to the main module$' + +# 'go list -m' can show a version of the main module. +go list -m rsc.io/quote@5d9f230b +stdout '^rsc.io/quote v0.0.0-20180710144737-5d9f230bcfba$' +go list -m rsc.io/quote@v1.5.2 +stdout '^rsc.io/quote v1.5.2$' +go list -m rsc.io/quote@latest +stdout '^rsc.io/quote v1.5.2$' + +# 'go list -m -versions' shows available versions. +go list -m -versions rsc.io/quote +stdout '^rsc.io/quote.*v1.5.2' + +# 'go list -m' resolves @upgrade and @patch to the main module. +go list -m rsc.io/quote@upgrade +stdout '^rsc.io/quote$' +go list -m rsc.io/quote@patch +stdout '^rsc.io/quote$' + +# 'go get' will not attempt to upgrade the main module to any specific version. +# See also: mod_get_main.txt. +! go get rsc.io/quote@5d9f230b +stderr '^go: can''t request version "5d9f230b" of the main module \(rsc.io/quote\)$' +! go get rsc.io/quote@v1.5.2 +stderr '^go: can''t request version "v1.5.2" of the main module \(rsc.io/quote\)$' +! go get rsc.io/quote@latest +stderr '^go: can''t request version "latest" of the main module \(rsc.io/quote\)$' + +-- go.mod -- +module rsc.io/quote + +go 1.16 diff --git a/src/cmd/go/testdata/script/mod_readonly.txt b/src/cmd/go/testdata/script/mod_readonly.txt new file mode 100644 index 0000000..9e950c3 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_readonly.txt @@ -0,0 +1,131 @@ +env GO111MODULE=on +[short] skip + +# -mod=readonly must not resolve missing modules nor update go.mod +env GOFLAGS=-mod=readonly +go mod edit -fmt +cp go.mod go.mod.empty +! go list all +stderr '^x.go:2:8: cannot find module providing package rsc\.io/quote: import lookup disabled by -mod=readonly' +! stderr '\(\)' # If we don't have a reason for -mod=readonly, don't log an empty one. +cmp go.mod go.mod.empty + +# -mod=readonly should be set by default. +env GOFLAGS= +! go list all +stderr '^x.go:2:8: no required module provides package rsc\.io/quote; to add it:\n\tgo get rsc\.io/quote$' +cmp go.mod go.mod.empty + +env GOFLAGS=-mod=readonly + +# update go.mod - go get allowed +go get rsc.io/quote +grep rsc.io/quote go.mod + +# update go.mod - go mod tidy allowed +cp go.mod.empty go.mod +go mod tidy +cp go.mod go.mod.tidy + +# -mod=readonly must succeed once go.mod is up-to-date... +go list all + +# ... even if it needs downloads +go clean -modcache +go list all + +# -mod=readonly must not cause 'go list -m' to fail. +# (golang.org/issue/36478) +go list -m all +! stderr 'cannot query module' + +# -mod=readonly should reject inconsistent go.mod files +# (ones that would be rewritten). +go get rsc.io/sampler@v1.2.0 +go mod edit -require rsc.io/quote@v1.5.2 +cp go.mod go.mod.inconsistent +! go list +stderr 'go: updates to go.mod needed, disabled by -mod=readonly' +cmp go.mod go.mod.inconsistent + +# We get a different message when -mod=readonly is used by default. +env GOFLAGS= +! go list +stderr '^go: updates to go.mod needed; to update it:\n\tgo mod tidy' + +# However, it should not reject files missing a 'go' directive, +# since that was not always required. +cp go.mod.nogo go.mod +go list all +cmp go.mod go.mod.nogo + +# Nor should it reject files with redundant (not incorrect) +# requirements. +cp go.mod.redundant go.mod +go list all +cmp go.mod go.mod.redundant + +cp go.mod.indirect go.mod +go list all +cmp go.mod go.mod.indirect + + +# If we identify a missing package as a dependency of some other package in the +# main module, we should suggest 'go mod tidy' instead of resolving it. + +cp go.mod.untidy go.mod +! go list all +stderr '^x.go:2:8: no required module provides package rsc.io/quote; to add it:\n\tgo get rsc.io/quote$' + +! go list -deps . +stderr '^x.go:2:8: no required module provides package rsc.io/quote; to add it:\n\tgo get rsc.io/quote$' + +# However, if we didn't see an import from the main module, we should suggest +# 'go get' instead, because we don't know whether 'go mod tidy' would add it. +! go list rsc.io/quote +stderr '^no required module provides package rsc.io/quote; to add it:\n\tgo get rsc.io/quote$' + + +-- go.mod -- +module m + +go 1.16 + +-- x.go -- +package x +import _ "rsc.io/quote" +-- go.mod.nogo -- +module m + +require ( + rsc.io/quote v1.5.2 + rsc.io/testonly v1.0.0 // indirect +) +-- go.mod.redundant -- +module m + +go 1.16 + +require ( + rsc.io/quote v1.5.2 + rsc.io/sampler v1.3.0 // indirect + rsc.io/testonly v1.0.0 // indirect +) +-- go.mod.indirect -- +module m + +go 1.16 + +require ( + rsc.io/quote v1.5.2 // indirect + rsc.io/sampler v1.3.0 // indirect + rsc.io/testonly v1.0.0 // indirect +) +-- go.mod.untidy -- +module m + +go 1.16 + +require ( + rsc.io/sampler v1.3.0 // indirect +) diff --git a/src/cmd/go/testdata/script/mod_replace.txt b/src/cmd/go/testdata/script/mod_replace.txt new file mode 100644 index 0000000..26b1551 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_replace.txt @@ -0,0 +1,129 @@ +env GO111MODULE=on +[short] skip + +cp go.mod go.mod.orig + +# Make sure the test builds without replacement. +go build -mod=mod -o a1.exe . +exec ./a1.exe +stdout 'Don''t communicate by sharing memory' + +# Modules can be replaced by local packages. +cp go.mod.orig go.mod +go mod edit -replace=rsc.io/quote/v3=./local/rsc.io/quote/v3 +go build -o a2.exe . +exec ./a2.exe +stdout 'Concurrency is not parallelism.' + +# The module path of the replacement doesn't need to match. +# (For example, it could be a long-running fork with its own import path.) +cp go.mod.orig go.mod +go mod edit -replace=rsc.io/quote/v3=./local/not-rsc.io/quote/v3 +go build -o a3.exe . +exec ./a3.exe +stdout 'Clear is better than clever.' + +# However, the same module can't be used as two different paths. +cp go.mod.orig go.mod +go mod edit -replace=not-rsc.io/quote/v3@v3.0.0=rsc.io/quote/v3@v3.0.0 -require=not-rsc.io/quote/v3@v3.0.0 +! go build -o a4.exe . +stderr 'rsc.io/quote/v3@v3.0.0 used for two different module paths \(not-rsc.io/quote/v3 and rsc.io/quote/v3\)' + +# Modules that do not (yet) exist upstream can be replaced too. +cp go.mod.orig go.mod +go mod edit -replace=not-rsc.io/quote/v3@v3.1.0=./local/rsc.io/quote/v3 +go build -mod=mod -o a5.exe ./usenewmodule +! stderr 'finding not-rsc.io/quote/v3' +grep 'not-rsc.io/quote/v3 v3.1.0' go.mod +exec ./a5.exe +stdout 'Concurrency is not parallelism.' + +# Error messages for modules not found in replacements should +# indicate the replacement module. +cp go.mod.orig go.mod +go mod edit -replace=rsc.io/quote/v3=./local/rsc.io/quote/v3 +! go get rsc.io/quote/v3/missing-package +stderr 'module rsc.io/quote/v3@upgrade found \(v3.0.0, replaced by ./local/rsc.io/quote/v3\), but does not contain package' + +# The reported Dir and GoMod for a replaced module should be accurate. +cp go.mod.orig go.mod +go mod edit -replace=rsc.io/quote/v3=not-rsc.io/quote@v0.1.0-nomod +go mod download rsc.io/quote/v3 +go list -m -f '{{.Path}} {{.Version}} {{.Dir}} {{.GoMod}}{{with .Replace}} => {{.Path}} {{.Version}} {{.Dir}} {{.GoMod}}{{end}}' rsc.io/quote/v3 +stdout '^rsc.io/quote/v3 v3.0.0 '$GOPATH'[/\\]pkg[/\\]mod[/\\]not-rsc.io[/\\]quote@v0.1.0-nomod '$GOPATH'[/\\]pkg[/\\]mod[/\\]cache[/\\]download[/\\]not-rsc.io[/\\]quote[/\\]@v[/\\]v0.1.0-nomod.mod => not-rsc.io/quote v0.1.0-nomod '$GOPATH'[/\\]pkg[/\\]mod[/\\]not-rsc.io[/\\]quote@v0.1.0-nomod '$GOPATH'[/\\]pkg[/\\]mod[/\\]cache[/\\]download[/\\]not-rsc.io[/\\]quote[/\\]@v[/\\]v0.1.0-nomod.mod$' + +-- go.mod -- +module quoter + +require rsc.io/quote/v3 v3.0.0 + +-- main.go -- +package main + +import ( + "fmt" + "rsc.io/quote/v3" +) + +func main() { + fmt.Println(quote.GoV3()) +} + +-- usenewmodule/main.go -- +package main + +import ( + "fmt" + "not-rsc.io/quote/v3" +) + +func main() { + fmt.Println(quote.GoV3()) +} + +-- local/rsc.io/quote/v3/go.mod -- +module rsc.io/quote/v3 + +require rsc.io/sampler v1.3.0 + +-- local/rsc.io/quote/v3/quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote + +import "rsc.io/sampler" + +// Hello returns a greeting. +func HelloV3() string { + return sampler.Hello() +} + +// Glass returns a useful phrase for world travelers. +func GlassV3() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a REPLACED Go proverb. +func GoV3() string { + return "Concurrency is not parallelism." +} + +// Opt returns a optimization truth. +func OptV3() string { + // Wisdom from ken. + return "If a program is too slow, it must have a loop." +} + +-- local/not-rsc.io/quote/v3/go.mod -- +module not-rsc.io/quote/v3 + +-- local/not-rsc.io/quote/v3/quote.go -- +package quote + +func GoV3() string { + return "Clear is better than clever." +} diff --git a/src/cmd/go/testdata/script/mod_replace_gopkgin.txt b/src/cmd/go/testdata/script/mod_replace_gopkgin.txt new file mode 100644 index 0000000..91008f9 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_replace_gopkgin.txt @@ -0,0 +1,82 @@ +# Regression test for golang.org/issue/34254: +# a clone of gopkg.in/[…].vN should be replaceable by +# a fork hosted at corp.example.com/[…]/vN, +# even if there is an explicit go.mod file containing the +# gopkg.in path. + +skip 'skipping test that depends on an unreliable third-party server; see https://go.dev/issue/54503' + # TODO(#54043): Make this test hermetic and re-enable it. + +[!net:gopkg.in] skip +[!git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off +env GOFLAGS=-mod=mod + +# Replacing gopkg.in/[…].vN with a repository with a root go.mod file +# specifying […].vN and a compatible version should succeed, even if +# the replacement path is not a gopkg.in path. +cd 4-to-4 +go list -m gopkg.in/src-d/go-git.v4 + +# Previous versions of the "go" command accepted v0 and v1 pseudo-versions +# as replacements for gopkg.in/[…].v4. +# As a special case, we continue to accept those. + +cd ../4-to-0 +go list -m gopkg.in/src-d/go-git.v4 + +cd ../4-to-1 +go list -m gopkg.in/src-d/go-git.v4 + +cd ../4-to-incompatible +go list -m gopkg.in/src-d/go-git.v4 + +# A mismatched gopkg.in path should not be able to replace a different major version. +cd ../3-to-gomod-4 +! go list -m gopkg.in/src-d/go-git.v3 +stderr '^go: gopkg\.in/src-d/go-git\.v3@v3\.2\.0 \(replaced by gopkg\.in/src-d/go-git\.v3@v3\.0\.0-20190801152248-0d1a009cbb60\): version "v3\.0\.0-20190801152248-0d1a009cbb60" invalid: go\.mod has non-\.\.\.\.v3 module path "gopkg\.in/src-d/go-git\.v4" at revision 0d1a009cbb60$' + +-- 4-to-4/go.mod -- +module golang.org/issue/34254 + +go 1.13 + +require gopkg.in/src-d/go-git.v4 v4.13.1 + +replace gopkg.in/src-d/go-git.v4 v4.13.1 => github.com/src-d/go-git/v4 v4.13.1 +-- 4-to-1/go.mod -- +module golang.org/issue/34254 + +go 1.13 + +require gopkg.in/src-d/go-git.v4 v4.13.1 + +replace gopkg.in/src-d/go-git.v4 v4.13.1 => github.com/src-d/go-git v1.0.1-0.20190801152248-0d1a009cbb60 +-- 4-to-0/go.mod -- +module golang.org/issue/34254 + +go 1.13 + +require gopkg.in/src-d/go-git.v4 v4.13.1 + +replace gopkg.in/src-d/go-git.v4 v4.13.1 => github.com/src-d/go-git v0.0.0-20190801152248-0d1a009cbb60 +-- 4-to-incompatible/go.mod -- +module golang.org/issue/34254 + +go 1.13 + +require gopkg.in/src-d/go-git.v4 v4.13.1 + +replace gopkg.in/src-d/go-git.v4 v4.13.1 => github.com/src-d/go-git v4.6.0+incompatible +-- 3-to-gomod-4/go.mod -- +module golang.org/issue/34254 +go 1.13 + +require gopkg.in/src-d/go-git.v3 v3.2.0 + +// This replacement has a go.mod file declaring its path to be +// gopkg.in/src-d/go-git.v4, so it cannot be used as a replacement for v3. +replace gopkg.in/src-d/go-git.v3 v3.2.0 => gopkg.in/src-d/go-git.v3 v3.0.0-20190801152248-0d1a009cbb60 diff --git a/src/cmd/go/testdata/script/mod_replace_import.txt b/src/cmd/go/testdata/script/mod_replace_import.txt new file mode 100644 index 0000000..753071f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_replace_import.txt @@ -0,0 +1,144 @@ +env GO111MODULE=on + +# 'go list' should not add requirements even if they can be resolved locally. +cp go.mod go.mod.orig +! go list all +cmp go.mod go.mod.orig + +# 'go list' should resolve imports using replacements. +go get +go list all +stdout 'example.com/a/b$' +stdout 'example.com/x/v3$' +stdout 'example.com/y/z/w$' +stdout 'example.com/v' + +# The selected modules should prefer longer paths, +# but should try shorter paths if needed. +# Modules with a major-version suffix should have a corresponding pseudo-version. +# Replacements that specify a version should use the latest such version. +go list -m all +stdout 'example.com/a/b v0.0.0-00010101000000-000000000000 => ./b' +stdout 'example.com/y v0.0.0-00010101000000-000000000000 => ./y' +stdout 'example.com/x/v3 v3.0.0-00010101000000-000000000000 => ./v3' +stdout 'example.com/v v1.12.0 => ./v12' + +# The go command should print an informative error when the matched +# module does not contain a package. +# TODO(#26909): Ideally these errors should include line numbers for the imports within the main module. +cd fail +! go mod tidy +stderr '^go: localhost.fail imports\n\tw: module w@latest found \(v0.0.0-00010101000000-000000000000, replaced by ../w\), but does not contain package w$' +stderr '^go: localhost.fail imports\n\tnonexist: nonexist@v0.1.0: replacement directory ../nonexist does not exist$' + +-- go.mod -- +module example.com/m + +replace ( + example.com/a => ./a + example.com/a/b => ./b +) + +replace ( + example.com/x => ./x + example.com/x/v3 => ./v3 +) + +replace ( + example.com/y/z/w => ./w + example.com/y => ./y +) + +replace ( + example.com/v v1.11.0 => ./v11 + example.com/v v1.12.0 => ./v12 + example.com/v => ./v +) + +replace ( + example.com/i v2.0.0+incompatible => ./i2 +) + +-- m.go -- +package main +import ( + _ "example.com/a/b" + _ "example.com/x/v3" + _ "example.com/y/z/w" + _ "example.com/v" + _ "example.com/i" +) +func main() {} + +-- a/go.mod -- +module a.localhost +-- a/a.go -- +package a +-- a/b/b.go-- +package b + +-- b/go.mod -- +module a.localhost/b +-- b/b.go -- +package b + +-- x/go.mod -- +module x.localhost +-- x/x.go -- +package x +-- x/v3.go -- +package v3 +import _ "x.localhost/v3" + +-- v3/go.mod -- +module x.localhost/v3 +-- v3/x.go -- +package x + +-- w/go.mod -- +module w.localhost +-- w/skip/skip.go -- +// Package skip is nested below nonexistent package w. +package skip + +-- y/go.mod -- +module y.localhost +-- y/z/w/w.go -- +package w + +-- v12/go.mod -- +module v.localhost +-- v12/v.go -- +package v + +-- v11/go.mod -- +module v.localhost +-- v11/v.go -- +package v + +-- v/go.mod -- +module v.localhost +-- v/v.go -- +package v + +-- i2/go.mod -- +module example.com/i +-- i2/i.go -- +package i + +-- fail/m.go -- +package main + +import ( + _ "w" + _ "nonexist" +) + +func main() {} + +-- fail/go.mod -- +module localhost.fail + +replace w => ../w + +replace nonexist v0.1.0 => ../nonexist diff --git a/src/cmd/go/testdata/script/mod_replace_readonly.txt b/src/cmd/go/testdata/script/mod_replace_readonly.txt new file mode 100644 index 0000000..5c1226b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_replace_readonly.txt @@ -0,0 +1,62 @@ +# Check that with -mod=readonly, when we load a package in a module that is +# replaced but not required, we emit an error with the command to add the +# requirement. +# Verifies golang.org/issue/41416, golang.org/issue/41577. +cp go.mod go.mod.orig + +# Replace all versions of a module without requiring it. +# With -mod=mod, we'd add a requirement for a "zero" pseudo-version, but we +# can't in readonly mode, since its go.mod may alter the build list. +go mod edit -replace rsc.io/quote=./quote +! go list rsc.io/quote +stderr '^module rsc.io/quote provides package rsc.io/quote and is replaced but not required; to add it:\n\tgo get rsc.io/quote$' +go get rsc.io/quote +cmp go.mod go.mod.latest +go list rsc.io/quote +cp go.mod.orig go.mod + +# Same test with a specific version. +go mod edit -replace rsc.io/quote@v1.0.0-doesnotexist=./quote +! go list rsc.io/quote +stderr '^module rsc.io/quote provides package rsc.io/quote and is replaced but not required; to add it:\n\tgo get rsc.io/quote@v1.0.0-doesnotexist$' +go get rsc.io/quote@v1.0.0-doesnotexist +cmp go.mod go.mod.specific +go list rsc.io/quote +cp go.mod.orig go.mod + +# If there are multiple versions, the highest is suggested. +go mod edit -replace rsc.io/quote@v1.0.0-doesnotexist=./quote +go mod edit -replace rsc.io/quote@v1.1.0-doesnotexist=./quote +! go list rsc.io/quote +stderr '^module rsc.io/quote provides package rsc.io/quote and is replaced but not required; to add it:\n\tgo get rsc.io/quote@v1.1.0-doesnotexist$' + +-- go.mod -- +module m + +go 1.16 +-- go.mod.latest -- +module m + +go 1.16 + +replace rsc.io/quote => ./quote + +require rsc.io/quote v1.5.2 // indirect +-- go.mod.specific -- +module m + +go 1.16 + +replace rsc.io/quote v1.0.0-doesnotexist => ./quote + +require rsc.io/quote v1.0.0-doesnotexist // indirect +-- use.go -- +package use + +import _ "rsc.io/quote" +-- quote/go.mod -- +module rsc.io/quote + +go 1.16 +-- quote/quote.go -- +package quote diff --git a/src/cmd/go/testdata/script/mod_require_exclude.txt b/src/cmd/go/testdata/script/mod_require_exclude.txt new file mode 100644 index 0000000..0946dbf --- /dev/null +++ b/src/cmd/go/testdata/script/mod_require_exclude.txt @@ -0,0 +1,96 @@ +# build with no newer version to satisfy exclude +env GO111MODULE=on +cp go.mod go.mod.orig + +# With the selected version excluded, commands that query that version without +# updating go.mod should fail. + +! go list -mod=readonly -m all +stderr '^go: ignoring requirement on excluded version rsc.io/sampler v1\.99\.99$' +stderr '^go: updates to go.mod needed, disabled by -mod=readonly; to update it:\n\tgo mod tidy$' +! stdout '^rsc.io/sampler v1.99.99' +cmp go.mod go.mod.orig + +! go list -mod=vendor -m rsc.io/sampler +stderr '^go: ignoring requirement on excluded version rsc.io/sampler v1\.99\.99$' +stderr '^go: updates to go.mod needed, disabled by -mod=vendor; to update it:\n\tgo mod tidy$' +! stdout '^rsc.io/sampler v1.99.99' +cmp go.mod go.mod.orig + +# The failure message should be clear when -mod=vendor is implicit. + +go mod edit -go=1.14 +! go list -m rsc.io/sampler +stderr '^go: ignoring requirement on excluded version rsc.io/sampler v1\.99\.99$' +stderr '^go: updates to go.mod needed, disabled by -mod=vendor\n\t\(Go version in go.mod is at least 1.14 and vendor directory exists\.\)\n\tto update it:\n\tgo mod tidy$' +! stdout '^rsc.io/sampler v1.99.99' +go mod edit -go=1.13 +cmp go.mod go.mod.orig + + +# With the selected version excluded, commands that load only modules should +# drop the excluded module. + +go list -m -mod=mod all +stderr '^go: dropping requirement on excluded version rsc.io/sampler v1\.99\.99$' +stdout '^x$' +! stdout '^rsc.io/sampler' +cmp go.mod go.moddrop + +# With the latest version excluded, 'go list' should resolve needed packages +# from the next-highest version. + +cp go.mod.orig go.mod +go list -mod=mod -f '{{with .Module}}{{.Path}} {{.Version}}{{end}}' all +stderr '^go: dropping requirement on excluded version rsc.io/sampler v1\.99\.99$' +stdout '^x $' +! stdout '^rsc.io/sampler v1.99.99' +stdout '^rsc.io/sampler v1.3.0' + +# build with newer version available +cp go.mod2 go.mod +go list -mod=mod -f '{{with .Module}}{{.Path}} {{.Version}}{{end}}' all +stderr '^go: dropping requirement on excluded version rsc.io/quote v1\.5\.1$' +stdout 'rsc.io/quote v1.5.2' + +# build with excluded newer version +cp go.mod3 go.mod +go list -mod=mod -f '{{with .Module}}{{.Path}} {{.Version}}{{end}}' all +! stderr '^go: dropping requirement' +stdout 'rsc.io/quote v1.5.1' + +-- x.go -- +package x +import _ "rsc.io/quote" + +-- go.mod -- +module x + +go 1.13 + +exclude rsc.io/sampler v1.99.99 + +require rsc.io/sampler v1.99.99 +-- vendor/modules.txt -- +# rsc.io/sampler v1.99.99 +## explicit +-- go.moddrop -- +module x + +go 1.13 + +exclude rsc.io/sampler v1.99.99 +-- go.mod2 -- +module x + +go 1.13 + +exclude rsc.io/quote v1.5.1 +require rsc.io/quote v1.5.1 +-- go.mod3 -- +module x + +go 1.13 + +exclude rsc.io/quote v1.5.2 +require rsc.io/quote v1.5.1 diff --git a/src/cmd/go/testdata/script/mod_retention.txt b/src/cmd/go/testdata/script/mod_retention.txt new file mode 100644 index 0000000..9d30026 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retention.txt @@ -0,0 +1,150 @@ +# Regression test for golang.org/issue/34822: the 'go' command should prefer not +# to update the go.mod file if the changes only affect formatting, and should only +# remove redundant requirements in 'go mod tidy'. + +env GO111MODULE=on +[short] skip + +# Control case: verify that go.mod.tidy is actually tidy. +cp go.mod.tidy go.mod +go list -mod=mod all +cmp go.mod go.mod.tidy + + +# If the only difference in the go.mod file is the line endings, +# it should not be overwritten automatically. +cp go.mod.crlf go.mod +go list all +cmp go.mod go.mod.crlf + +# However, 'go mod tidy' should fix whitespace even if there are no other changes. +go mod tidy +cmp go.mod go.mod.tidy + + +# Out-of-order requirements should not be overwritten automatically... +cp go.mod.unsorted go.mod +go list all +cmp go.mod go.mod.unsorted + +# ...but 'go mod edit -fmt' should sort them. +go mod edit -fmt +cmp go.mod go.mod.tidy + + +# "// indirect" comments should be removed if direct dependencies are seen. +# changes. +cp go.mod.indirect go.mod +go list -mod=mod all +cmp go.mod go.mod.tidy + +# "// indirect" comments should be added if appropriate. +# TODO(#42504): add case for 'go list -mod=mod -tags=any all' when -tags=any +# is supported. Only a command that loads "all" without build constraints +# (except "ignore") has enough information to add "// indirect" comments. +# 'go mod tidy' and 'go mod vendor' are the only commands that do that, +# but 'go mod vendor' cannot write go.mod. +cp go.mod.toodirect go.mod +go list all +cmp go.mod go.mod.toodirect + + +# Redundant requirements should be preserved... +cp go.mod.redundant go.mod +go list all +cmp go.mod go.mod.redundant +go mod vendor +cmp go.mod go.mod.redundant +rm -r vendor + +# ...except by 'go mod tidy'. +go mod tidy +cmp go.mod go.mod.tidy + + +# A missing "go" version directive should be added. +# However, that should not remove other redundant requirements. +# In fact, it may *add* redundant requirements due to activating lazy loading. +cp go.mod.nogo go.mod +go list -mod=mod all +cmpenv go.mod go.mod.addedgo + + +-- go.mod.tidy -- +module m + +go 1.14 + +require ( + rsc.io/quote v1.5.2 + rsc.io/testonly v1.0.0 // indirect +) +-- x.go -- +package x +import _ "rsc.io/quote" +-- go.mod.crlf -- +module m + +go 1.14 + +require ( + rsc.io/quote v1.5.2 + rsc.io/testonly v1.0.0 // indirect +) +-- go.mod.unsorted -- +module m + +go 1.14 + +require ( + rsc.io/testonly v1.0.0 // indirect + rsc.io/quote v1.5.2 +) +-- go.mod.indirect -- +module m + +go 1.14 + +require ( + rsc.io/quote v1.5.2 // indirect + rsc.io/testonly v1.0.0 // indirect +) +-- go.mod.toodirect -- +module m + +go 1.14 + +require ( + rsc.io/quote v1.5.2 + rsc.io/testonly v1.0.0 +) +-- go.mod.redundant -- +module m + +go 1.14 + +require ( + rsc.io/quote v1.5.2 + rsc.io/sampler v1.3.0 // indirect + rsc.io/testonly v1.0.0 // indirect +) +-- go.mod.nogo -- +module m + +require ( + rsc.io/quote v1.5.2 + rsc.io/sampler v1.3.0 // indirect + rsc.io/testonly v1.0.0 // indirect +) +-- go.mod.addedgo -- +module m + +go $goversion + +require rsc.io/quote v1.5.2 + +require ( + golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect + rsc.io/sampler v1.3.0 // indirect + rsc.io/testonly v1.0.0 // indirect +) diff --git a/src/cmd/go/testdata/script/mod_retract.txt b/src/cmd/go/testdata/script/mod_retract.txt new file mode 100644 index 0000000..37aae48 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract.txt @@ -0,0 +1,45 @@ +cp go.mod go.mod.orig + +# 'go list pkg' does not report an error when a retracted version is used. +go list -e -f '{{if .Error}}{{.Error}}{{end}}' ./use +! stdout . +cmp go.mod go.mod.orig + +# Nor does 'go build'. +[!short] go build ./use +[!short] ! stderr . +[!short] cmp go.mod go.mod.orig + +# Neither 'go list' nor 'go build' should download go.mod from the version +# that would list retractions. +exists $GOPATH/pkg/mod/cache/download/example.com/retract/@v/v1.0.0-bad.mod +! exists $GOPATH/pkg/mod/cache/download/example.com/retract/@v/v1.1.0.mod + +# Importing a package from a module with a retracted latest version will +# select the latest non-retracted version. +go get ./use_self_prev +go list -m example.com/retract/self/prev +stdout '^example.com/retract/self/prev v1.1.0$' +exists $GOPATH/pkg/mod/cache/download/example.com/retract/self/prev/@v/v1.9.0.mod + +-- go.mod -- +module example.com/use + +go 1.15 + +require example.com/retract v1.0.0-bad + +-- go.sum -- +example.com/retract v1.0.0-bad h1:liAW69rbtjY67x2CcNzat668L/w+YGgNX3lhJsWIJis= +example.com/retract v1.0.0-bad/go.mod h1:0DvGGofJ9hr1q63cBrOY/jSY52OwhRGA0K47NE80I5Y= +example.com/retract/self/prev v1.1.0 h1:0/8I/GTG+1eJTFeDQ/fUbgrMsVHHyKhh3Z8DSZp1fuA= +example.com/retract/self/prev v1.1.0/go.mod h1:xl2EcklWuZZHVtHWcpzfSJQmnzAGpKZYpA/Wto7SZN4= +-- use/use.go -- +package use + +import _ "example.com/retract" + +-- use_self_prev/use.go -- +package use_self_prev + +import _ "example.com/retract/self/prev" diff --git a/src/cmd/go/testdata/script/mod_retract_fix_version.txt b/src/cmd/go/testdata/script/mod_retract_fix_version.txt new file mode 100644 index 0000000..9ae49f5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract_fix_version.txt @@ -0,0 +1,48 @@ +# retract must not be used without a module directive. +! go list -m all +stderr 'go.mod:3: no module directive found, so retract cannot be used$' + +# Commands that update go.mod should fix non-canonical versions in +# retract directives. +# Verifies #44494. +go mod edit -module=rsc.io/quote/v2 +! go list -m all +stderr '^go: updates to go.mod needed; to update it:\n\tgo mod tidy$' +go mod tidy +go list -m all +cmp go.mod go.mod.want + +# If a retracted version doesn't match the module's major version suffx, +# an error should be reported. +! go mod edit -retract=v3.0.1 +stderr '^go: -retract=v3.0.1: version "v3.0.1" invalid: should be v2, not v3$' +cp go.mod.mismatch-v2 go.mod +! go list -m all +stderr 'go.mod:3: retract rsc.io/quote/v2: version "v3.0.1" invalid: should be v2, not v3$' + +cp go.mod.mismatch-v1 go.mod +! go list -m all +stderr 'go.mod:3: retract rsc.io/quote: version "v3.0.1" invalid: should be v0 or v1, not v3$' + +-- go.mod -- +go 1.16 + +retract latest +-- go.mod.want -- +go 1.16 + +retract v2.0.1 + +module rsc.io/quote/v2 +-- go.mod.mismatch-v2 -- +go 1.16 + +retract v3.0.1 + +module rsc.io/quote/v2 +-- go.mod.mismatch-v1 -- +go 1.16 + +retract v3.0.1 + +module rsc.io/quote diff --git a/src/cmd/go/testdata/script/mod_retract_incompatible.txt b/src/cmd/go/testdata/script/mod_retract_incompatible.txt new file mode 100644 index 0000000..5d09532 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract_incompatible.txt @@ -0,0 +1,15 @@ +# The current version of a module should not be considered when loading +# retractions. If the current version is +incompatible, we should not prefer +# +incompatible versions when looking for retractions. +# Verifies #42601. + +go mod init m + +# Request a +incompatible version retracted in v1.0.0. +go get example.com/retract/incompatible@v2.0.0+incompatible +stderr '^go: warning: example.com/retract/incompatible@v2.0.0\+incompatible: retracted by module author$' + +# We should still see a warning if the +incompatible was previously in the +# build list. +go get example.com/retract/incompatible@v2.0.0+incompatible +stderr '^go: warning: example.com/retract/incompatible@v2.0.0\+incompatible: retracted by module author$' diff --git a/src/cmd/go/testdata/script/mod_retract_noupgrade.txt b/src/cmd/go/testdata/script/mod_retract_noupgrade.txt new file mode 100644 index 0000000..67de79f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract_noupgrade.txt @@ -0,0 +1,11 @@ +go list -m -u example.com/retract/noupgrade +stdout '^example.com/retract/noupgrade v1.0.0 \(retracted\)$' + +-- go.mod -- +module use + +go 1.19 + +require example.com/retract/noupgrade v1.0.0 +-- go.sum -- +example.com/retract/noupgrade v1.0.0/go.mod h1:q2/HnBejUQ83RcUo4stf2U++/Zr9R/Ky3BsodjKBkQ4= diff --git a/src/cmd/go/testdata/script/mod_retract_pseudo_base.txt b/src/cmd/go/testdata/script/mod_retract_pseudo_base.txt new file mode 100644 index 0000000..87b440d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract_pseudo_base.txt @@ -0,0 +1,62 @@ +# When converting a commit to a pseudo-version, don't use a retracted version +# as the base. +# Verifies golang.org/issue/41700. + +[short] skip +[!git] skip +env GOPROXY=direct +env GOSUMDB=off +go mod init m + +# Control: check that v1.0.0 is the only version and is retracted. +go list -m -versions vcs-test.golang.org/git/retract-pseudo.git +stdout '^vcs-test.golang.org/git/retract-pseudo.git$' +go list -m -versions -retracted vcs-test.golang.org/git/retract-pseudo.git +stdout '^vcs-test.golang.org/git/retract-pseudo.git v1.0.0$' + +# 713affd19d7b is a commit after v1.0.0. Don't use v1.0.0 as the base. +go list -m vcs-test.golang.org/git/retract-pseudo.git@713affd19d7b +stdout '^vcs-test.golang.org/git/retract-pseudo.git v0.0.0-20201009173747-713affd19d7b$' + +# 64c061ed4371 is the commit v1.0.0 refers to. Don't convert to v1.0.0. +go list -m vcs-test.golang.org/git/retract-pseudo.git@64c061ed4371 +stdout '^vcs-test.golang.org/git/retract-pseudo.git v0.0.0-20201009173747-64c061ed4371' + +# A retracted version is a valid base. Retraction should not validate existing +# pseudo-versions, nor should it turn invalid pseudo-versions valid. +go get vcs-test.golang.org/git/retract-pseudo.git@v1.0.1-0.20201009173747-713affd19d7b +go list -m vcs-test.golang.org/git/retract-pseudo.git +stdout '^vcs-test.golang.org/git/retract-pseudo.git v1.0.1-0.20201009173747-713affd19d7b$' + +! go get vcs-test.golang.org/git/retract-pseudo.git@v1.0.1-0.20201009173747-64c061ed4371 +stderr '^go: vcs-test.golang.org/git/retract-pseudo.git@v1.0.1-0.20201009173747-64c061ed4371: invalid pseudo-version: tag \(v1.0.0\) found on revision 64c061ed4371 is already canonical, so should not be replaced with a pseudo-version derived from that tag$' + +-- retract-pseudo.sh -- +#!/bin/bash + +# This is not part of the test. +# Run this to generate and update the repository on vcs-test.golang.org. + +set -euo pipefail + +rm -rf retract-pseudo +mkdir retract-pseudo +cd retract-pseudo +git init + +# Create the module. +# Retract v1.0.0 and tag v1.0.0 at the same commit. +# The module has no unretracted release versions. +go mod init vcs-test.golang.org/git/retract-pseudo.git +go mod edit -retract v1.0.0 +echo 'package p' >p.go +git add -A +git commit -m 'create module retract-pseudo' +git tag v1.0.0 + +# Commit a trivial change so the default branch does not point to v1.0.0. +git mv p.go q.go +git commit -m 'trivial change' + +zip -r ../retract-pseudo.zip . +gsutil cp ../retract-pseudo.zip gs://vcs-test/git/retract-pseudo.zip diff --git a/src/cmd/go/testdata/script/mod_retract_rationale.txt b/src/cmd/go/testdata/script/mod_retract_rationale.txt new file mode 100644 index 0000000..92e9b7d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract_rationale.txt @@ -0,0 +1,79 @@ +# When there is no rationale, 'go get' should print a hard-coded message. +go get example.com/retract/rationale@v1.0.0-empty +stderr '^go: warning: example.com/retract/rationale@v1.0.0-empty: retracted by module author$' + +# 'go list' should print the same hard-coded message. +go list -m -retracted -f '{{.Retracted}}' example.com/retract/rationale +stdout '^\[retracted by module author\]$' + + +# When there is a multi-line message, 'go get' should print the first line. +go get example.com/retract/rationale@v1.0.0-multiline1 +stderr '^go: warning: example.com/retract/rationale@v1.0.0-multiline1: retracted by module author: short description$' +! stderr 'detail' + +# 'go list' should show the full message. +go list -m -retracted -f '{{.Retracted}}' example.com/retract/rationale +cmp stdout multiline + +# 'go get' output should be the same whether the retraction appears at top-level +# or in a block. +go get example.com/retract/rationale@v1.0.0-multiline2 +stderr '^go: warning: example.com/retract/rationale@v1.0.0-multiline2: retracted by module author: short description$' +! stderr 'detail' + +# Same for 'go list'. +go list -m -retracted -f '{{.Retracted}}' example.com/retract/rationale +cmp stdout multiline + + +# 'go get' should omit long messages. +go get example.com/retract/rationale@v1.0.0-long +stderr '^go: warning: example.com/retract/rationale@v1.0.0-long: retracted by module author: \(message omitted: too long\)' + +# 'go list' should show the full message. +go list -m -retracted -f '{{.Retracted}}' example.com/retract/rationale +stdout '^\[lo{500}ng\]$' + + +# 'go get' should omit messages with unprintable characters. +go get example.com/retract/rationale@v1.0.0-unprintable +stderr '^go: warning: example.com/retract/rationale@v1.0.0-unprintable: retracted by module author: \(message omitted: contains non-printable characters\)' + +# 'go list' should show the full message. +go list -m -retracted -f '{{.Retracted}}' example.com/retract/rationale +stdout '^\[Ends with a BEL character. Beep!\x07\]$' + + +# When there is a comment on a block, but not on individual retractions within +# the block, the rationale should come from the block comment. +go list -m -retracted -f '{{.Retracted}}' example.com/retract/rationale@v1.0.0-block +stdout '^\[block comment\]$' +go list -m -retracted -f '{{.Retracted}}' example.com/retract/rationale@v1.0.0-blockwithcomment +stdout '^\[inner comment\]$' + + +# When a version is covered by multiple retractions, all retractions should +# be reported in the order they appear in the file. +go list -m -retracted -f '{{range .Retracted}}{{.}},{{end}}' example.com/retract/rationale@v1.0.0-order +stdout '^degenerate range,single version,$' +go list -m -retracted -f '{{range .Retracted}}{{.}},{{end}}' example.com/retract/rationale@v1.0.1-order +stdout '^single version,degenerate range,$' + +# 'go get' will only report the first retraction to avoid being too verbose. +go get example.com/retract/rationale@v1.0.0-order +stderr '^go: warning: example.com/retract/rationale@v1.0.0-order: retracted by module author: degenerate range$' +go get example.com/retract/rationale@v1.0.1-order +stderr '^go: warning: example.com/retract/rationale@v1.0.1-order: retracted by module author: single version$' + +-- go.mod -- +module m + +go 1.14 + +-- multiline -- +[short description +more + +detail +suffix] diff --git a/src/cmd/go/testdata/script/mod_retract_rename.txt b/src/cmd/go/testdata/script/mod_retract_rename.txt new file mode 100644 index 0000000..38986f3 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract_rename.txt @@ -0,0 +1,28 @@ +# Populate go.sum. +go get + +# 'go list -m -retracted' should load retractions, even if the version +# containing retractions has a different module path. +go list -m -retracted -f '{{with .Retracted}}retracted{{end}}' example.com/retract/rename + +# 'go list -m -u' should load retractions, too. +go list -m -u -f '{{with .Retracted}}retracted{{end}}' example.com/retract/rename + +# 'go get' should warn about the retracted version. +go get +stderr '^go: warning: example.com/retract/rename@v1.0.0-bad: retracted by module author: bad$' + +# We can't upgrade, since this latest version has a different module path. +! go get example.com/retract/rename +stderr 'module declares its path as: example.com/retract/newname' + +-- go.mod -- +module example.com/use + +go 1.16 + +require example.com/retract/rename v1.0.0-bad +-- use.go -- +package use + +import _ "example.com/retract/rename" diff --git a/src/cmd/go/testdata/script/mod_retract_replace.txt b/src/cmd/go/testdata/script/mod_retract_replace.txt new file mode 100644 index 0000000..788968f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract_replace.txt @@ -0,0 +1,63 @@ +# If the latest unretracted version of a module is replaced, 'go list' should +# obtain retractions from the replacement. + +# Populate go.sum. +go get + +# The latest version, v1.9.0, is not available on the proxy. +go list -m -retracted example.com/retract/missingmod +stdout '^example.com/retract/missingmod v1.0.0$' +exists $GOPATH/pkg/mod/cache/download/example.com/retract/missingmod/@v/v1.9.0.info +! exists $GOPATH/pkg/mod/cache/download/example.com/retract/missingmod/@v/v1.9.0.mod + +# If we replace that version, we should see retractions. +go mod edit -replace=example.com/retract/missingmod@v1.9.0=./missingmod-v1.9.0 +go list -m -retracted -f '{{range .Retracted}}{{.}}{{end}}' example.com/retract/missingmod +stdout '^bad version$' + +# If we replace the retracted version, we should not see a retraction. +go mod edit -replace=example.com/retract/missingmod=./missingmod-v1.9.0 +go list -m -retracted -f '{{if not .Retracted}}good version{{end}}' example.com/retract/missingmod +stdout '^good version$' + + +# If a replacement version is retracted, we should see a retraction. +# It should appear in both the replaced module and the replacement, as other +# fields like GoMod do. +go list -m -retracted -f '{{range .Retracted}}{{.}}{{end}}' example.com/retract +! stdout . +go list -m -retracted -f '{{if .Replace}}replaced{{end}}' example.com/retract +! stdout . +go mod edit -replace example.com/retract@v1.0.0-good=example.com/retract@v1.0.0-bad +go list -m -mod=mod -retracted -f '{{range .Retracted}}{{.}}{{end}}' example.com/retract +stdout '^bad$' +go list -m -mod=mod -retracted -f '{{with .Replace}}{{range .Retracted}}{{.}}{{end}}{{end}}' example.com/retract +stdout '^bad$' + +-- go.mod -- +module m + +go 1.14 + +require ( + example.com/retract v1.0.0-good + example.com/retract/missingmod v1.0.0 +) +-- use.go -- +package use + +import ( + _ "example.com/retract" + _ "example.com/retract/missingmod" +) +-- missingmod-v1.0.0/go.mod -- +module example.com/retract/missingmod + +go 1.14 +-- missingmod-v1.9.0/go.mod -- +module example.com/retract/missingmod + +go 1.14 + +// bad version +retract v1.0.0 diff --git a/src/cmd/go/testdata/script/mod_retract_versions.txt b/src/cmd/go/testdata/script/mod_retract_versions.txt new file mode 100644 index 0000000..012fa15 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract_versions.txt @@ -0,0 +1,22 @@ +# https://golang.org/issue/44296: the --versions flag should not affect +# the version reported by 'go list' in case of retractions. + +env FMT='{{.Path}}{{with .Error}}: {{printf "%q" .Err}}{{end}} {{printf "%q" .Version}}{{with .Versions}} {{.}}{{end}}' + +go list -m -e -f $FMT example.com/retract/self/pseudo +stdout '^example.com/retract/self/pseudo: "module example.com/retract/self/pseudo: not a known dependency" ""$' + +go list -m -e -f $FMT example.com/retract/self/pseudo@latest +stdout '^example.com/retract/self/pseudo: "module example.com/retract/self/pseudo: no matching versions for query \\"latest\\"" "latest"$' + + +go list -m -e -f $FMT --versions example.com/retract/self/pseudo +stdout '^example.com/retract/self/pseudo ""$' + +go list -m -e -f $FMT --versions example.com/retract/self/pseudo@latest +stdout '^example.com/retract/self/pseudo: "module example.com/retract/self/pseudo: no matching versions for query \\"latest\\"" "latest"$' + +-- go.mod -- +module test + +go 1.17 diff --git a/src/cmd/go/testdata/script/mod_run_issue52331.txt b/src/cmd/go/testdata/script/mod_run_issue52331.txt new file mode 100644 index 0000000..917e890 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_run_issue52331.txt @@ -0,0 +1,35 @@ +# Regression test for https://go.dev/issue/52331: 'go run -mod=mod' +# failed to write go.mod and go.sum with the resolved dependencies. + +[short] skip + +! go run main.go +# stderr '^main\.go:6:2: no required module provides package example\.com/version; to add it:\n\tgo get example\.com/version\n\z' + +go run -mod=mod main.go +cmp go.mod go.mod.want +grep -count=1 '^example\.com/version v1.1.0 h1:' go.sum +grep -count=1 '^example\.com/version v1.1.0/go.mod h1:' go.sum + +-- go.mod -- +module example + +go 1.17 +-- go.mod.want -- +module example + +go 1.17 + +require example.com/version v1.1.0 // indirect +-- main.go -- +package main + +import ( + "fmt" + + "example.com/version" +) + +func main() { + fmt.Println(version.V) +} diff --git a/src/cmd/go/testdata/script/mod_run_nonmain.txt b/src/cmd/go/testdata/script/mod_run_nonmain.txt new file mode 100644 index 0000000..8435fc0 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_run_nonmain.txt @@ -0,0 +1,18 @@ +! go run $PWD +! stderr 'no packages loaded' +stderr '^package example.net/nonmain is not a main package$' + +! go run . +stderr '^package example.net/nonmain is not a main package$' + +! go run ./... +stderr '^go: warning: "\./\.\.\." matched only non-main packages$' +stderr '^go: no packages loaded from \./\.\.\.$' + +-- go.mod -- +module example.net/nonmain + +go 1.17 +-- nonmain.go -- +// Package nonmain is not a main package. +package nonmain diff --git a/src/cmd/go/testdata/script/mod_run_path.txt b/src/cmd/go/testdata/script/mod_run_path.txt new file mode 100644 index 0000000..4369ee4 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_run_path.txt @@ -0,0 +1,15 @@ +# Test that go run does not get confused by conflict +# between go.mod's module path and what you'd +# expect from GOPATH. golang.org/issue/26046. + +env GO111MODULE=on + +cd $GOPATH/src/example.com/hello +go run main.go + +-- $GOPATH/src/example.com/hello/go.mod -- +module example.com/hello/v2 + +-- $GOPATH/src/example.com/hello/main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/mod_run_pkg_version.txt b/src/cmd/go/testdata/script/mod_run_pkg_version.txt new file mode 100644 index 0000000..969852c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_run_pkg_version.txt @@ -0,0 +1,104 @@ +# This test checks the behavior of 'go run' with a 'cmd@version' argument. +# Most of 'go run' is covered in other tests. +# mod_install_pkg_version covers most of the package loading functionality. +# This test focuses on 'go run' behavior specific to this mode. +[short] skip + +# 'go run pkg@version' works outside a module. +env GO111MODULE=auto +go run example.com/cmd/a@v1.0.0 +stdout '^a@v1.0.0$' + + +# 'go run pkg@version' reports an error if modules are disabled. +env GO111MODULE=off +! go run example.com/cmd/a@v1.0.0 +stderr '^go: modules disabled by GO111MODULE=off; see ''go help modules''$' +env GO111MODULE=on + + +# 'go run pkg@version' ignores go.mod in the current directory. +cd m +cp go.mod go.mod.orig +! go list -m all +stderr '^go: example.com/cmd@v1.1.0-doesnotexist: reading http.*/mod/example\.com/cmd/@v/v1.1.0-doesnotexist.info: 404 Not Found\n\tserver response: 404 page not found$' +stderr '^go: example.com/cmd@v1.1.0-doesnotexist: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/cmd$' +go run example.com/cmd/a@v1.0.0 +stdout '^a@v1.0.0$' +cmp go.mod go.mod.orig +cd .. + + +# 'go install pkg@version' works on a module that doesn't have a go.mod file +# and with a module whose go.mod file has missing requirements. +# With a proxy, the two cases are indistinguishable. +go run rsc.io/fortune@v1.0.0 +stderr '^go: found rsc.io/quote in rsc.io/quote v1.5.2$' +stderr '^Hello, world.$' + + +# 'go run pkg@version' should report an error if pkg is not a main package. +! go run example.com/cmd/err@v1.0.0 +stderr '^package example.com/cmd/err is not a main package$' + + +# 'go run pkg@version' should report errors if the module contains +# replace or exclude directives. +go mod download example.com/cmd@v1.0.0-replace +! go run example.com/cmd/a@v1.0.0-replace +cmp stderr replace-err + +go mod download example.com/cmd@v1.0.0-exclude +! go run example.com/cmd/a@v1.0.0-exclude +cmp stderr exclude-err + + +# 'go run dir@version' works like a normal 'go run' command if +# dir is a relative or absolute path. +go mod download rsc.io/fortune@v1.0.0 +! go run $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0 +stderr '^go: go\.mod file not found in current directory or any parent directory; see ''go help modules''$' +! go run ../pkg/mod/rsc.io/fortune@v1.0.0 +stderr '^go: go\.mod file not found in current directory or any parent directory; see ''go help modules''$' +mkdir tmp +cd tmp +go mod init tmp +go mod edit -require=rsc.io/fortune@v1.0.0 +! go run -mod=readonly $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0 +stderr '^missing go\.sum entry for module providing package rsc\.io/fortune; to add:\n\tgo mod download rsc\.io/fortune$' +! go run -mod=readonly ../../pkg/mod/rsc.io/fortune@v1.0.0 +stderr '^missing go\.sum entry for module providing package rsc\.io/fortune; to add:\n\tgo mod download rsc\.io/fortune$' +cd .. +rm tmp + + +# 'go run' does not interpret @version arguments after the first. +go run example.com/cmd/a@v1.0.0 example.com/doesnotexist@v1.0.0 +stdout '^a@v1.0.0$' + + +# 'go run pkg@version' succeeds when -mod=readonly is set explicitly. +# Verifies #43278. +go run -mod=readonly example.com/cmd/a@v1.0.0 +stdout '^a@v1.0.0$' + +-- m/go.mod -- +module m + +go 1.16 + +require example.com/cmd v1.1.0-doesnotexist +-- x/x.go -- +package main + +func main() {} +-- replace-err -- +go: example.com/cmd/a@v1.0.0-replace (in example.com/cmd@v1.0.0-replace): + The go.mod file for the module providing named packages contains one or + more replace directives. It must not contain directives that would cause + it to be interpreted differently than if it were the main module. +-- exclude-err -- +go: example.com/cmd/a@v1.0.0-exclude (in example.com/cmd@v1.0.0-exclude): + The go.mod file for the module providing named packages contains one or + more exclude directives. It must not contain directives that would cause + it to be interpreted differently than if it were the main module. diff --git a/src/cmd/go/testdata/script/mod_run_pkgerror.txt b/src/cmd/go/testdata/script/mod_run_pkgerror.txt new file mode 100644 index 0000000..48f900d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_run_pkgerror.txt @@ -0,0 +1,32 @@ +# https://golang.org/issue/39986: files reported as invalid by go/build should +# be listed in InvalidGoFiles. + +go list -e -f '{{.Incomplete}}{{"\n"}}{{.Error}}{{"\n"}}{{.InvalidGoFiles}}{{"\n"}}' . +stdout '^true\nfound packages m \(m\.go\) and main \(main\.go\) in '$PWD'\n\[main.go\]\n' + + +# https://golang.org/issue/45827: 'go run .' should report the same package +# errors as 'go build' and 'go list'. + +! go build +stderr '^found packages m \(m\.go\) and main \(main\.go\) in '$PWD'$' + +! go list . +stderr '^found packages m \(m\.go\) and main \(main\.go\) in '$PWD'$' + +! go run . +! stderr 'no packages loaded' +stderr '^found packages m \(m\.go\) and main \(main\.go\) in '$PWD'$' + +! go run ./... +! stderr 'no packages loaded' +stderr '^found packages m \(m\.go\) and main \(main\.go\) in '$PWD'$' + +-- go.mod -- +module m + +go 1.17 +-- m.go -- +package m +-- main.go -- +package main diff --git a/src/cmd/go/testdata/script/mod_skip_write.txt b/src/cmd/go/testdata/script/mod_skip_write.txt new file mode 100644 index 0000000..db47b9c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_skip_write.txt @@ -0,0 +1,93 @@ +# Commands used to debug the module graph should not write go.mod or go.sum +# or report errors when those files need to be updated. + +# Everything's okay initially. +go list -m all + +# Downgrading sampler makes go.mod inconsistent, but 'go mod graph', +# 'go mod verify', and 'go mod why' still work. +cp go.mod go.mod.orig +go mod edit -require=rsc.io/sampler@v1.2.0 +cp go.mod go.mod.edit +! go list -m all +stderr 'updates to go.mod needed' + +go mod graph +cmp stdout graph.want +cmp go.mod go.mod.edit + +go mod verify +stdout '^all modules verified$' +cmp go.mod go.mod.edit + +go mod why rsc.io/sampler +cmp stdout why.want +cmp go.mod go.mod.edit + +go mod why -m rsc.io/sampler +cmp stdout why.want +cmp go.mod go.mod.edit + +cp go.mod.orig go.mod + +# Removing go.sum breaks other commands, but 'go mod graph' and +# 'go mod why' still work. +rm go.sum +! go list -m all +stderr 'missing go.sum entry' + +go mod graph +cmp stdout graph.want +! exists go.sum + +go mod verify +stdout '^all modules verified$' +! exists go.sum + +go mod why rsc.io/sampler +cmp stdout why.want +! exists go.sum + +go mod why -m rsc.io/sampler +cmp stdout why.want +! exists go.sum + +-- go.mod -- +module m + +go 1.18 + +require rsc.io/quote v1.5.2 + +require ( + golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect + rsc.io/sampler v1.3.0 // indirect + rsc.io/testonly v1.0.0 // indirect +) +-- go.sum -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.2.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= +-- use.go -- +package use + +import _ "rsc.io/quote" +-- graph.want -- +m go@1.18 +m golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c +m rsc.io/quote@v1.5.2 +m rsc.io/sampler@v1.3.0 +m rsc.io/testonly@v1.0.0 +rsc.io/quote@v1.5.2 rsc.io/sampler@v1.3.0 +rsc.io/sampler@v1.3.0 golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c +-- why.want -- +# rsc.io/sampler +m +rsc.io/quote +rsc.io/sampler diff --git a/src/cmd/go/testdata/script/mod_stale.txt b/src/cmd/go/testdata/script/mod_stale.txt new file mode 100644 index 0000000..c6ab27d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_stale.txt @@ -0,0 +1,15 @@ +[short] skip + +env GOCACHE=$WORK/cache +go list -f '{{.Stale}}' . +stdout true +go install . +go list -f '{{.Stale}}' . +stdout false + +-- go.mod -- +module example.com/mod + +go 1.20 +-- m.go -- +package m diff --git a/src/cmd/go/testdata/script/mod_std_vendor.txt b/src/cmd/go/testdata/script/mod_std_vendor.txt new file mode 100644 index 0000000..ed47542 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_std_vendor.txt @@ -0,0 +1,77 @@ +env GO111MODULE=on +env GOPROXY=off + +[!compiler:gc] skip + +# 'go list' should report imports from _test.go in the TestImports field. +go list -f '{{.TestImports}}' +stdout net/http # from .TestImports + +# 'go list' should find standard-vendored packages. +go list -f '{{.Dir}}' vendor/golang.org/x/net/http2/hpack +stdout $GOROOT[/\\]src[/\\]vendor + +# 'go list -test' should report vendored transitive dependencies of _test.go +# imports in the Deps field. +go list -test -f '{{range .Deps}}{{.}}{{"\n"}}{{end}}' +stdout ^vendor/golang.org/x/crypto # dep of .TestImports + + +# Modules outside the standard library should not use the packages vendored there... +cd broken +! go build -mod=readonly +stderr 'disabled by -mod=readonly' +! go build -mod=vendor +stderr 'http.go:5:2: cannot find module providing package golang.org/x/net/http2/hpack: import lookup disabled by -mod=vendor' + +# ...even if they explicitly use the "cmd/vendor/" or "vendor/" prefix. +cd ../importcmd +! go build . +stderr 'use of vendored package' + +cd ../importstd +! go build . +stderr 'use of vendored package' + + +# When run within the 'std' module, 'go list -test' should report vendored +# transitive dependencies at their vendored paths. +cd $GOROOT/src +go list -test -f '{{range .Deps}}{{.}}{{"\n"}}{{end}}' net/http +! stdout ^golang.org/x/net/http2/hpack +stdout ^vendor/golang.org/x/net/http2/hpack + +-- go.mod -- +module m + +-- x.go -- +package x + +-- x_test.go -- +package x +import "testing" +import _ "net/http" +func Test(t *testing.T) {} + +-- broken/go.mod -- +module broken +-- broken/http.go -- +package broken + +import ( + _ "net/http" + _ "golang.org/x/net/http2/hpack" +) + +-- importcmd/go.mod -- +module importcmd +-- importcmd/x.go -- +package importcmd + +import _ "cmd/vendor/golang.org/x/tools/go/analysis" +-- importstd/go.mod -- +module importvendor +-- importstd/x.go -- +package importstd + +import _ "vendor/golang.org/x/net/http2/hpack" diff --git a/src/cmd/go/testdata/script/mod_string_alias.txt b/src/cmd/go/testdata/script/mod_string_alias.txt new file mode 100644 index 0000000..5c3d428 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_string_alias.txt @@ -0,0 +1,14 @@ +[short] skip + +env GO111MODULE=on + +go mod init golang.org/issue/27584 + +go build . + +-- main.go -- +package main + +type string = []int + +func main() {} diff --git a/src/cmd/go/testdata/script/mod_sum_ambiguous.txt b/src/cmd/go/testdata/script/mod_sum_ambiguous.txt new file mode 100644 index 0000000..07c6659 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sum_ambiguous.txt @@ -0,0 +1,62 @@ +# Confirm our build list. +cp go.sum.buildlist-only go.sum +go list -m all +stdout '^example.com/ambiguous/a v1.0.0$' +stdout '^example.com/ambiguous/a/b v0.0.0-empty$' + +# If two modules could provide a package, but only one does, +# 'go mod tidy' should retain sums for both zips. +go mod tidy +grep '^example.com/ambiguous/a v1.0.0 h1:' go.sum +grep '^example.com/ambiguous/a/b v0.0.0-empty h1:' go.sum + +# 'go mod download' should also add sums. +cp go.sum.buildlist-only go.sum +go mod download example.com/ambiguous/a +grep '^example.com/ambiguous/a v1.0.0 h1:' go.sum +! grep '^example.com/ambiguous/a/b v0.0.0-empty h1:' go.sum +go mod download example.com/ambiguous/a/b +grep '^example.com/ambiguous/a/b v0.0.0-empty h1:' go.sum + +# If two modules could provide a package, and we're missing a sum for one, +# we should see a missing sum error, even if we have a sum for a module that +# provides the package. +cp go.sum.a-only go.sum +! go list example.com/ambiguous/a/b +stderr '^missing go.sum entry needed to verify package example.com/ambiguous/a/b is provided by exactly one module; to add:\n\tgo mod download example.com/ambiguous/a/b$' +! go list -deps . +stderr '^use.go:3:8: missing go.sum entry needed to verify package example.com/ambiguous/a/b \(imported by m\) is provided by exactly one module; to add:\n\tgo get m$' + +cp go.sum.b-only go.sum +! go list example.com/ambiguous/a/b +stderr '^missing go.sum entry for module providing package example.com/ambiguous/a/b; to add:\n\tgo mod download example.com/ambiguous/a$' +! go list -deps . +stderr '^use.go:3:8: missing go.sum entry for module providing package example.com/ambiguous/a/b \(imported by m\); to add:\n\tgo get m$' + +cp go.sum.buildlist-only go.sum +! go list example.com/ambiguous/a/b +stderr '^missing go.sum entry for module providing package example.com/ambiguous/a/b; to add:\n\tgo mod download example.com/ambiguous/a example.com/ambiguous/a/b$' +! go list -deps . +stderr '^use.go:3:8: missing go.sum entry for module providing package example.com/ambiguous/a/b \(imported by m\); to add:\n\tgo get m$' + +-- go.mod -- +module m + +go 1.15 + +require example.com/ambiguous/a v1.0.0 +-- go.sum.buildlist-only -- +example.com/ambiguous/a v1.0.0/go.mod h1:TrBl/3xTPFJ2gmMIYz53h2gkNtg0dokszEMuyS1QEb0= +example.com/ambiguous/a/b v0.0.0-empty/go.mod h1:MajJq5jPEBnnXP+NTWIeXX7kwaPS1sbVEJdooTmsePQ= +-- go.sum.a-only -- +example.com/ambiguous/a v1.0.0 h1:pGZhTXy6+titE2rNfwHwJykSjXDR4plO52PfZrBM0T8= +example.com/ambiguous/a v1.0.0/go.mod h1:TrBl/3xTPFJ2gmMIYz53h2gkNtg0dokszEMuyS1QEb0= +example.com/ambiguous/a/b v0.0.0-empty/go.mod h1:MajJq5jPEBnnXP+NTWIeXX7kwaPS1sbVEJdooTmsePQ= +-- go.sum.b-only -- +example.com/ambiguous/a v1.0.0/go.mod h1:TrBl/3xTPFJ2gmMIYz53h2gkNtg0dokszEMuyS1QEb0= +example.com/ambiguous/a/b v0.0.0-empty h1:xS29ReXXuhjT7jc79mo91h/PevaZ2oS9PciF1DucXtg= +example.com/ambiguous/a/b v0.0.0-empty/go.mod h1:MajJq5jPEBnnXP+NTWIeXX7kwaPS1sbVEJdooTmsePQ= +-- use.go -- +package use + +import _ "example.com/ambiguous/a/b" diff --git a/src/cmd/go/testdata/script/mod_sum_issue56222.txt b/src/cmd/go/testdata/script/mod_sum_issue56222.txt new file mode 100644 index 0000000..12848c9 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sum_issue56222.txt @@ -0,0 +1,91 @@ +# Regression test for #56222: 'go get -t' and 'go mod tidy' +# should save enough checksums to run 'go test' on the named +# packages or any package in "all" respectively. + +# 'go mod tidy' in a module at go 1.21 or higher should preserve +# checksums needed to run 'go test all'. +cd m1 +go mod tidy + +go list -f '{{if eq .ImportPath "example.com/generics"}}{{.Module.GoVersion}}{{end}}' -deps -test example.com/m2/q +stdout 1.18 +[!short] go test -o $devnull -c all + +cat go.sum +replace 'example.com/generics v1.0.0/go.mod' 'example.com/notgenerics v1.0.0/go.mod' go.sum + +! go list -f '{{if eq .ImportPath "example.com/generics"}}{{.Module.GoVersion}}{{end}}' -deps -test example.com/m2/q +stderr '^go: can''t load test package: \.\.'${/}m2${/}q${/}'q_test.go:3:8: example\.com/generics@v1\.0\.0: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example\.com/generics$' + +go mod download -json example.com/generics +stdout '"GoModSum":' +go list -f '{{if eq .ImportPath "example.com/generics"}}{{.Module.GoVersion}}{{end}}' -deps -test example.com/m2/q +stdout 1.18 + + +# At go 1.20 or earlier, 'go mod tidy' should preserve the historical go.sum +# contents, but 'go test' should flag the missing checksums (instead of trying +# to build the test dependency with the wrong language version). + +go mod tidy -go=1.20 +! go test -o $devnull -c all +stderr '^# example.com/m2/q\n'..${/}m2${/}q${/}'q_test.go:3:8: example.com/generics@v1.0.0: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/generics$' + +go mod download -json example.com/generics +go list -f '{{if eq .ImportPath "example.com/generics"}}{{.Module.GoVersion}}{{end}}' -deps -test example.com/m2/q +stdout 1.18 + + +# Even at go 1.20 or earlier, 'go mod tidy' shouldn't need go.mod files or +# checksums that it won't record. + +go mod tidy -go=1.20 +go clean -modcache # Remove checksums from the module cache, so that only go.sum is used. + +# Issue 60667: 'go list' without -mod=mod shouldn't report the checksums as +# dirty either. +go list -m -u all + +env OLDSUMDB=$GOSUMDB +env GOSUMDB=bad +go mod tidy + +env GOSUMDB=$OLDSUMDB + + +# Regardless of the go version in go.mod, 'go get -t' should fetch +# enough checksums to run 'go test' on the named package. + +rm p +go mod tidy -go=1.20 +go list -m all +! stdout example.com/generics +go get -t example.com/m2/q@v1.0.0 +go list -f '{{if eq .ImportPath "example.com/generics"}}{{.Module.GoVersion}}{{end}}' -deps -test example.com/m2/q +stdout 1.18 +[!short] go test -o $devnull -c example.com/m2/q + + +-- m1/go.mod -- +module example.com/m1 + +go 1.21 + +require example.com/m2 v1.0.0 +replace example.com/m2 => ../m2 +-- m1/p/p.go -- +package p + +import _ "example.com/m2/q" +-- m2/go.mod -- +module example.com/m2 + +go 1.19 + +require example.com/generics v1.0.0 +-- m2/q/q.go -- +package q +-- m2/q/q_test.go -- +package q + +import _ "example.com/generics" diff --git a/src/cmd/go/testdata/script/mod_sum_lookup.txt b/src/cmd/go/testdata/script/mod_sum_lookup.txt new file mode 100644 index 0000000..7513f7f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sum_lookup.txt @@ -0,0 +1,34 @@ +# When we attempt to resolve an import that doesn't exist, we should not save +# hashes for downloaded modules. +# Verifies golang.org/issue/36260. +# TODO(golang.org/issue/26603): use 'go mod tidy -e' when implemented. +go list -e -mod=mod -tags=ignore ./noexist +! exists go.sum + +# When an import is resolved successfully, we should only save hashes for +# the module that provides the package, not for other modules looked up. +# Verifies golang.org/issue/31580. +go get ./exist +grep '^example.com/join v1.1.0 h1:' go.sum +! grep '^example.com/join/subpkg' go.sum +cp go.sum go.list.sum +go mod tidy +cmp go.sum go.list.sum + +-- go.mod -- +module m + +go 1.15 + +-- noexist/use.go -- +// ignore tags prevents errors in 'go mod tidy' +// +build ignore + +package use + +import _ "example.com/join/subpkg/noexist" + +-- exist/use.go -- +package use + +import _ "example.com/join/subpkg" diff --git a/src/cmd/go/testdata/script/mod_sum_readonly.txt b/src/cmd/go/testdata/script/mod_sum_readonly.txt new file mode 100644 index 0000000..c426073 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sum_readonly.txt @@ -0,0 +1,87 @@ +# Test that go.sum does not get updated when -mod=readonly flag is set +env GO111MODULE=on + +# When a sum is needed to load the build list, we get an error for the +# specific module. The .mod file is not downloaded, and go.sum is not written. +! go list -m all +stderr '^go: rsc.io/quote@v1.5.2: missing go.sum entry for go.mod file; to add it:\n\tgo mod download rsc.io/quote$' +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod +! exists go.sum + +# If go.sum exists but contains hashes from an algorithm we don't know about, +# we should see the same error. +cp go.sum.h2only go.sum +! go list -m all +stderr '^go: rsc.io/quote@v1.5.2: missing go.sum entry for go.mod file; to add it:\n\tgo mod download rsc.io/quote$' +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod +cmp go.sum go.sum.h2only +rm go.sum + +# If we replace a module, we should see a missing sum error for the replacement. +cp go.mod go.mod.orig +go mod edit -replace rsc.io/quote@v1.5.2=rsc.io/quote@v1.5.1 +! go list -m all +stderr '^go: rsc.io/quote@v1.5.2 \(replaced by rsc.io/quote@v1.5.1\): missing go.sum entry for go.mod file; to add it:\n\tgo mod download rsc.io/quote$' +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.1.mod +! exists go.sum +cp go.mod.orig go.mod + +# Control: when sums are present, loading the build list downloads .mod files. +cp go.sum.buildlistonly go.sum +go list -m all +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod + + +# When a sum is needed to load a .mod file for a package outside the build list, +# we get a generic missing import error. +! go list example.com/doesnotexist +stderr '^no required module provides package example.com/doesnotexist; to add it:\n\tgo get example.com/doesnotexist$' + +# When a sum is needed to load a .zip file, we get a more specific error. +# The .zip file is not downloaded. +! go list rsc.io/quote +stderr '^missing go.sum entry for module providing package rsc.io/quote; to add:\n\tgo mod download rsc.io/quote$' +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip + +# The error is attached to the package from the missing module. We can load +# a package that imports it without that error. +go list -e -deps -f '{{.ImportPath}}{{with .Error}} {{.Err}}{{end}}' . +stdout '^m$' +stdout '^rsc.io/quote missing go.sum entry for module providing package rsc.io/quote \(imported by m\); to add:\n\tgo get m$' +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip + +# go.sum should not have been written. +cmp go.sum go.sum.buildlistonly + +# Control: when sums are present, 'go list' downloads .zip files. +cp go.sum.tidy go.sum +go list . +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip + +-- go.mod -- +module m + +go 1.15 + +require rsc.io/quote v1.5.2 +-- use.go -- +package use + +import _ "rsc.io/quote" +-- go.sum.h2only -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h2:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2/go.mod h2:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0/go.mod h2:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +-- go.sum.buildlistonly -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +-- go.sum.tidy -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= diff --git a/src/cmd/go/testdata/script/mod_sum_replaced.txt b/src/cmd/go/testdata/script/mod_sum_replaced.txt new file mode 100644 index 0000000..6c322a0 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sum_replaced.txt @@ -0,0 +1,28 @@ +env GO111MODULE=on + +# After 'go get', the go.sum file should contain the sum for the module. +go get rsc.io/quote@v1.5.0 +grep 'rsc.io/quote v1.5.0' go.sum + +# If we replace the module and run 'go mod tidy', we should get a sum for the replacement. +go mod edit -replace rsc.io/quote@v1.5.0=rsc.io/quote@v1.5.1 +go mod tidy +grep 'rsc.io/quote v1.5.1' go.sum +cp go.sum go.sum.tidy + +# 'go mod vendor' should preserve that sum, and should not need to add any new entries. +go mod vendor +grep 'rsc.io/quote v1.5.1' go.sum +cmp go.sum go.sum.tidy + +-- go.mod -- +module golang.org/issue/27868 + +require rsc.io/quote v1.5.0 + +-- main.go -- +package main + +import _ "rsc.io/quote" + +func main() {} diff --git a/src/cmd/go/testdata/script/mod_sumdb.txt b/src/cmd/go/testdata/script/mod_sumdb.txt new file mode 100644 index 0000000..d06db4a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sumdb.txt @@ -0,0 +1,45 @@ +env GO111MODULE=on +env sumdb=$GOSUMDB +env proxy=$GOPROXY +env GOPROXY GONOPROXY GOSUMDB GONOSUMDB +env dbname=localhost.localdev/sumdb + +# disagreeing with the sumdb produces security errors +# (this also populates tiles on the sumdb server). +cp go.mod.orig go.mod +env GOSUMDB=$sumdb' '$proxy/sumdb-wrong +! go get rsc.io/quote +stderr 'go: rsc.io/quote@v1.5.2: verifying module: checksum mismatch' +stderr 'downloaded: h1:3fEy' +stderr 'localhost.localdev/sumdb: h1:wrong' +stderr 'SECURITY ERROR\nThis download does NOT match the one reported by the checksum server.' +! go get rsc.io/sampler +! go get golang.org/x/text + +go mod edit -require rsc.io/quote@v1.5.2 +! go mod tidy +stderr 'go: rsc.io/quote@v1.5.2: verifying go.mod: checksum mismatch' +stderr 'SECURITY ERROR\n' + +rm go.sum + +# switching to truthful sumdb detects timeline inconsistency +cp go.mod.orig go.mod +env GOSUMDB=$sumdb +! go get rsc.io/fortune +stderr 'SECURITY ERROR\ngo.sum database server misbehavior detected!' +stderr 'proof of misbehavior:' + +# removing the cached wrong tree head and cached tiles clears the bad data +rm $GOPATH/pkg/sumdb/$dbname/latest +go clean -modcache +go get rsc.io/fortune + +-- go.mod.orig -- +module m + +go 1.16 +-- m.go -- +package m + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_sumdb_cache.txt b/src/cmd/go/testdata/script/mod_sumdb_cache.txt new file mode 100644 index 0000000..063fd20 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sumdb_cache.txt @@ -0,0 +1,47 @@ +env GO111MODULE=on +env sumdb=$GOSUMDB +env proxy=$GOPROXY +env GOPROXY GONOPROXY GOSUMDB GONOSUMDB + +# rejected proxy fails verification +cp go.mod.orig go.mod +rm go.sum +env GOPROXY=$proxy/sumdb-503 +! go get rsc.io/quote +stderr 503 + +# fetch through working proxy is OK +cp go.mod.orig go.mod +rm go.sum +env GOPROXY=$proxy +go get rsc.io/quote + +# repeated fetch works entirely from cache, does not consult sumdb +cp go.mod.orig go.mod +rm go.sum +env GOPROXY=$proxy/sumdb-503 +go get rsc.io/quote +rm go.sum + +# fetch specific module can work without proxy, using cache or go.sum +cp go.mod.orig go.mod +rm go.sum +env GOPROXY=off +go get rsc.io/quote@v1.5.2 # using cache +rm $GOPATH/pkg/mod/cache/download/sumdb/localhost.localdev/sumdb/lookup/rsc.io/quote@v1.5.2 +go get rsc.io/quote@v1.5.2 # using go.sum + +# fetch fails once we lose access to both cache and go.sum +rm go.sum +env GOPROXY=$proxy/sumdb-504 +! go get rsc.io/quote@v1.5.2 +stderr 504 + +# GOINSECURE does not bypass checksum lookup +env GOINSECURE=rsc.io +env GOPROXY=$proxy/sumdb-504 +! go get rsc.io/quote@v1.5.2 +stderr 504 + +-- go.mod.orig -- +module m diff --git a/src/cmd/go/testdata/script/mod_sumdb_file_path.txt b/src/cmd/go/testdata/script/mod_sumdb_file_path.txt new file mode 100644 index 0000000..2f42cb5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sumdb_file_path.txt @@ -0,0 +1,58 @@ +[!net:proxy.golang.org] skip +[!net:sum.golang.org] skip + +env GO111MODULE=on +[go-builder] env GOSUMDB= +[!go-builder] env GOSUMDB=sum.golang.org # Set explicitly in case GOROOT/go.env is modified. +env GOPATH=$WORK/gopath1 + +# With a file-based proxy with an empty checksum directory, +# downloading a new module should fail, even if a subsequent +# proxy contains a more complete mirror of the sum database. +# +# TODO(bcmills): The error message here is a bit redundant. +# It comes from the sumweb package, which isn't yet producing structured errors. +[GOOS:windows] env GOPROXY=file:///$WORK/sumproxy,https://proxy.golang.org +[!GOOS:windows] env GOPROXY=file://$WORK/sumproxy,https://proxy.golang.org +! go get golang.org/x/text@v0.3.2 +stderr '^go: golang.org/x/text@v0.3.2: verifying module: golang.org/x/text@v0.3.2: reading file://.*/sumdb/sum.golang.org/lookup/golang.org/x/text@v0.3.2: (no such file or directory|.*cannot find the path specified.*)' + +# If the proxy does not claim to support the database, +# checksum verification should fall through to the next proxy, +# and downloading should succeed. +[GOOS:windows] env GOPROXY=file:///$WORK/emptyproxy,https://proxy.golang.org +[!GOOS:windows] env GOPROXY=file://$WORK/emptyproxy,https://proxy.golang.org +go get golang.org/x/text@v0.3.2 + +# After a successful sumdb lookup, the lookup can be repeated +# using the download cache as a proxy. +cp supported $GOPATH/pkg/mod/cache/download/sumdb/sum.golang.org/supported +[GOOS:windows] env GOPROXY=file:///$WORK/gopath1/pkg/mod/cache/download,file:///$WORK/sumproxy +[!GOOS:windows] env GOPROXY=file://$WORK/gopath1/pkg/mod/cache/download,file://$WORK/sumproxy +env GOPATH=$WORK/gopath2 +rm go.sum +go get -x -v golang.org/x/text@v0.3.2 + +# Once the checksum is present in the go.sum file, +# an empty file-based sumdb can be used in conjunction with +# a fallback module mirror. +grep golang.org/x/text go.sum +env GOPATH=$WORK/gopath3 +[GOOS:windows] env GOPROXY=file:///$WORK/sumproxy +[!GOOS:windows] env GOPROXY=file://$WORK/sumproxy +! go get golang.org/x/text@v0.3.2 +[GOOS:windows] env GOPROXY=file:///$WORK/sumproxy,https://proxy.golang.org +[!GOOS:windows] env GOPROXY=file://$WORK/sumproxy,https://proxy.golang.org +go get golang.org/x/text@v0.3.2 + +-- supported -- + +-- go.mod -- +module example.com +go 1.13 +-- $WORK/emptyproxy/README.md -- +This proxy contains no modules. +-- $WORK/sumproxy/README.md -- +This proxy contains no modules. +-- $WORK/sumproxy/sumdb/sum.golang.org/supported -- +This proxy blocks checksum downloads from sum.golang.org. diff --git a/src/cmd/go/testdata/script/mod_sumdb_golang.txt b/src/cmd/go/testdata/script/mod_sumdb_golang.txt new file mode 100644 index 0000000..067e2e3 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sumdb_golang.txt @@ -0,0 +1,83 @@ +# Test default GOPROXY and GOSUMDB +[go-builder] env GOPROXY= +[go-builder] env GOSUMDB= +[go-builder] go env GOPROXY +[go-builder] stdout '^https://proxy.golang.org,direct$' +[go-builder] go env GOSUMDB +[go-builder] stdout '^sum.golang.org$' +[go-builder] env GOPROXY=https://proxy.golang.org +[go-builder] go env GOSUMDB +[go-builder] stdout '^sum.golang.org$' + +# Download direct from github. + +[!net:proxy.golang.org] skip +[!net:sum.golang.org] skip +[!git] skip +env GOSUMDB=sum.golang.org +env GOPROXY=direct + +go get rsc.io/quote@v1.5.2 +cp go.sum saved.sum + + +# Download from proxy.golang.org with go.sum entry already. +# Use 'go list' instead of 'go get' since the latter may download extra go.mod +# files not listed in go.sum. + +go clean -modcache +env GOSUMDB=sum.golang.org +env GOPROXY=https://proxy.golang.org,direct + +go list -x -m all # Download go.mod files. +! stderr github +stderr proxy.golang.org/rsc.io/quote +! stderr sum.golang.org/tile +! stderr sum.golang.org/lookup/rsc.io/quote + +go list -x -deps rsc.io/quote # Download module source. +! stderr github +stderr proxy.golang.org/rsc.io/quote +! stderr sum.golang.org/tile +! stderr sum.golang.org/lookup/rsc.io/quote + +cmp go.sum saved.sum + + +# Download again. +# Should use the checksum database to validate new go.sum lines, +# but not need to fetch any new data from the proxy. + +rm go.sum + +go list -mod=mod -x -m all # Add checksums for go.mod files. +stderr sum.golang.org/tile +! stderr github +! stderr proxy.golang.org/rsc.io/quote +stderr sum.golang.org/lookup/rsc.io/quote + +go list -mod=mod -x rsc.io/quote # Add checksums for module source. +! stderr . # Adds checksums, but for entities already in the module cache. + +cmp go.sum saved.sum + + +# test fallback to direct + +env TESTGOPROXY404=1 +go clean -modcache +rm go.sum + +go list -mod=mod -x -m all # Download go.mod files +stderr 'proxy.golang.org.*404 testing' +stderr github.com/rsc + +go list -mod=mod -x rsc.io/quote # Download module source. +stderr 'proxy.golang.org.*404 testing' +stderr github.com/rsc + +cmp go.sum saved.sum + + +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/mod_sumdb_proxy.txt b/src/cmd/go/testdata/script/mod_sumdb_proxy.txt new file mode 100644 index 0000000..194c0c9 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sumdb_proxy.txt @@ -0,0 +1,65 @@ +env GO111MODULE=on +env sumdb=$GOSUMDB +env proxy=$GOPROXY +env GOPROXY GONOPROXY GOSUMDB GONOSUMDB + +# basic fetch (through proxy) works +cp go.mod.orig go.mod +go get rsc.io/fortune@v1.0.0 # note: must use test proxy, does not exist in real world +rm $GOPATH/pkg/mod/cache/download/sumdb # rm sumdb cache but NOT package download cache +rm go.sum + +# can fetch by explicit URL +cp go.mod.orig go.mod +env GOSUMDB=$sumdb' '$proxy/sumdb-direct +go get rsc.io/fortune@v1.0.0 +rm $GOPATH/pkg/mod/cache/download/sumdb +rm go.sum + +# direct access fails (because localhost.localdev does not exist) +# web.get is providing the error message - there's no actual network access. +cp go.mod.orig go.mod +env GOSUMDB=$sumdb +env GOPROXY=direct +! go get rsc.io/fortune@v1.0.0 +stderr 'verifying module: rsc.io/fortune@v1.0.0: .*: no such host localhost.localdev' +rm $GOPATH/pkg/mod/cache/download/sumdb +rm go.sum + +# proxy 404 falls back to direct access (which fails) +cp go.mod.orig go.mod +env GOSUMDB=$sumdb +env GOPROXY=$proxy/sumdb-404 +! go get rsc.io/fortune@v1.0.0 +stderr 'verifying.*localhost.localdev' +rm $GOPATH/pkg/mod/cache/download/sumdb +rm go.sum + +# proxy non-200/404/410 stops direct access +cp go.mod.orig go.mod +env GOSUMDB=$sumdb +env GOPROXY=$proxy/sumdb-503 +! go get rsc.io/fortune@v1.0.0 +stderr '503 Service Unavailable' +rm $GOPATH/pkg/mod/cache/download/sumdb +rm go.sum + +# the error from the last attempted proxy should be returned. +cp go.mod.orig go.mod +env GOSUMDB=$sumdb +env GOPROXY=$proxy/sumdb-404,$proxy/sumdb-503 +! go get rsc.io/fortune@v1.0.0 +stderr '503 Service Unavailable' +rm $GOPATH/pkg/mod/cache/download/sumdb +rm go.sum + +# if proxies are separated with '|', fallback is allowed on any error. +cp go.mod.orig go.mod +env GOSUMDB=$sumdb +env GOPROXY=$proxy/sumdb-503|https://0.0.0.0|$proxy +go get rsc.io/fortune@v1.0.0 +rm $GOPATH/pkg/mod/cache/download/sumdb +rm go.sum + +-- go.mod.orig -- +module m diff --git a/src/cmd/go/testdata/script/mod_symlink.txt b/src/cmd/go/testdata/script/mod_symlink.txt new file mode 100644 index 0000000..0604e1a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_symlink.txt @@ -0,0 +1,45 @@ +env GO111MODULE=on +[!symlink] skip + +# 'go get' should resolve modules of imported packages. +go get +go list -deps -f '{{.Module}}' . +stdout golang.org/x/text + +go get ./subpkg +go list -deps -f '{{.Module}}' ./subpkg +stdout golang.org/x/text + +# Create a copy of the module using symlinks in src/links. +mkdir links +symlink links/go.mod -> $GOPATH/src/go.mod +symlink links/go.sum -> $GOPATH/src/go.sum +symlink links/issue.go -> $GOPATH/src/issue.go +mkdir links/subpkg +symlink links/subpkg/issue.go -> $GOPATH/src/subpkg/issue.go + +# We should see the copy as a valid module root. +cd links +go env GOMOD +stdout links[/\\]go.mod +go list -m +stdout golang.org/issue/28107 + +# The symlink-based copy should contain the same packages +# and have the same dependencies as the original. +go list -deps -f '{{.Module}}' . +stdout golang.org/x/text +go list -deps -f '{{.Module}}' ./subpkg +stdout golang.org/x/text + +-- go.mod -- +module golang.org/issue/28107 + +-- issue.go -- +package issue + +import _ "golang.org/x/text/language" +-- subpkg/issue.go -- +package issue + +import _ "golang.org/x/text/language" diff --git a/src/cmd/go/testdata/script/mod_symlink_dotgo.txt b/src/cmd/go/testdata/script/mod_symlink_dotgo.txt new file mode 100644 index 0000000..d4cc143 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_symlink_dotgo.txt @@ -0,0 +1,17 @@ +env GO111MODULE=on +[!symlink] skip + +symlink dir.go -> dir + +# Issue #39841: symlinks to directories should be ignored, not treated as source files. +go list -f '{{range .GoFiles}}{{.}}{{"\n"}}{{end}}' . +stdout 'p\.go$' +! stdout 'dir\.go$' + +-- go.mod -- +module example.com +go 1.15 +-- p.go -- +package p +-- dir/README.txt -- +This file exists to ensure that dir is a directory. diff --git a/src/cmd/go/testdata/script/mod_tagged_import_cycle.txt b/src/cmd/go/testdata/script/mod_tagged_import_cycle.txt new file mode 100644 index 0000000..0491acb --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tagged_import_cycle.txt @@ -0,0 +1,106 @@ +# Because 'go mod' subcommands ignore build constraints, they can encounter +# package-import cycles that are not possible in an ordinary build. This test +# verifies that such cycles are handled even when they cross module boundaries. + +# First, verify that the import graph depends on build tags as expected. +go list -deps example.com/left +stdout '^example.com/right$' +go list -deps example.com/right +! stdout left + +env GOFLAGS=-tags=mirror +go list -deps example.com/left +! stdout right +go list -deps example.com/right +stdout '^example.com/left$' +env GOFLAGS='' + +# 'go mod why' should be agnostic to build tags. +go mod why example.com/left +stdout '^example.com/chiral$\n^example.com/left$' +go mod why example.com/right +stdout '^example.com/chiral$\n^example.com/right$' + +env GOFLAGS='-tags=mirror' +go mod why example.com/left +stdout '^example.com/chiral$\n^example.com/left$' +go mod why example.com/right +stdout '^example.com/chiral$\n^example.com/right$' +env GOFLAGS='' + +# 'go mod tidy' should successfully handle the cycle. +env GOFLAGS=-mod=readonly +go mod tidy + +# 'go mod vendor' should copy in both packages without crashing. +go mod vendor +exists vendor/example.com/left/default.go +exists vendor/example.com/left/mirror.go +exists vendor/example.com/right/default.go +exists vendor/example.com/right/mirror.go + +-- go.mod -- +module example.com/chiral + +go 1.14 + +require ( + example.com/left v0.1.0 + example.com/right v0.1.0 +) + +replace ( + example.com/left => ./left + example.com/right => ./right +) +-- chiral.go -- +// Package chiral imports packages in an order that depends on build tags. +package chiral +-- default.go -- +// +build !mirror + +package chiral + +import _ "example.com/left" +-- mirror.go -- +// +build mirror + +package chiral + +import _ "example.com/right" +-- left/go.mod -- +module example.com/left + +go 1.14 + +require example.com/right v0.1.0 + +replace example.com/right v0.1.0 => ../right +-- left/default.go -- +// +build !mirror + +package left + +import _ "example.com/right" +-- left/mirror.go -- +// +build mirror + +package left +-- right/go.mod -- +module example.com/right + +go 1.14 + +require example.com/left v0.1.0 + +replace example.com/left v0.1.0 => ../left +-- right/default.go -- +// +build !mirror + +package right +-- right/mirror.go -- +// +build mirror + +package right + +import _ "example.com/left" diff --git a/src/cmd/go/testdata/script/mod_test.txt b/src/cmd/go/testdata/script/mod_test.txt new file mode 100644 index 0000000..76f1d7a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_test.txt @@ -0,0 +1,130 @@ +env GO111MODULE=on +env GOFLAGS=-mod=mod +[short] skip + +# TODO(bcmills): Convert the 'go test' calls below to 'go list -test' once 'go +# list' is more sensitive to package loading errors. + +# A test in the module's root package should work. +cd a/ +cp go.mod.empty go.mod +go list -test +! stderr error + +cp go.mod.empty go.mod +go list -deps +! stdout ^testing$ + +# list all should include test dependencies, like testing +cp go.mod.empty go.mod +go list all +stdout ^testing$ +stdout ^rsc.io/quote$ +stdout ^rsc.io/testonly$ + +# list -deps -tests should also include testing +# but not deps of tests of deps (rsc.io/testonly). +go list -deps -test +stdout ^testing$ +stdout ^rsc.io/quote$ +! stdout ^rsc.io/testonly$ + +# list -test all should succeed +cp go.mod.empty go.mod +go list -test all +stdout '^testing' + +cp go.mod.empty go.mod +go list -test +! stderr error + +# A test with the "_test" suffix in the module root should also work. +cd ../b/ +go list -test +! stderr error + +# A test with the "_test" suffix of a *package* with a "_test" suffix should +# even work (not that you should ever do that). +cd ../c_test +go list -test +! stderr error + +cd ../d_test +go list -test +! stderr error + +cd ../e +go list -test +! stderr error + +-- a/go.mod.empty -- +module example.com/user/a + +go 1.11 + +-- a/a.go -- +package a + +-- a/a_test.go -- +package a + +import "testing" +import _ "rsc.io/quote" + +func Test(t *testing.T) {} + +-- b/go.mod -- +module example.com/user/b + +-- b/b.go -- +package b + +-- b/b_test.go -- +package b_test + +import "testing" + +func Test(t *testing.T) {} + +-- c_test/go.mod -- +module example.com/c_test + +-- c_test/umm.go -- +// Package c_test is the non-test package for its import path! +package c_test + +-- c_test/c_test_test.go -- +package c_test_test + +import "testing" + +func Test(t *testing.T) {} + +-- d_test/go.mod -- +// Package d is an ordinary package in a deceptively-named directory. +module example.com/d + +-- d_test/d.go -- +package d + +-- d_test/d_test.go -- +package d_test + +import "testing" + +func Test(t *testing.T) {} + +-- e/go.mod -- +module example.com/e_test + +-- e/wat.go -- +// Package e_test is the non-test package for its import path, +// in a deceptively-named directory! +package e_test + +-- e/e_test.go -- +package e_test_test + +import "testing" + +func Test(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/mod_test_cached.txt b/src/cmd/go/testdata/script/mod_test_cached.txt new file mode 100644 index 0000000..3da4358 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_test_cached.txt @@ -0,0 +1,76 @@ +[short] skip + +env GO111MODULE=on +env GOCACHE=$WORK/gocache +env GODEBUG=gocachetest=1 + +# The first run of a test should not be cached. +# The second run should be. +go test -run=WriteTmp . +! stdout '(cached)' +go test -run=WriteTmp . +stdout '(cached)' + +# 'go test' without arguments should never be cached. +go test -run=WriteTmp +! stdout '(cached)' +go test -run=WriteTmp +! stdout '(cached)' + +# We should never cache a test run from command-line files. +go test -run=WriteTmp ./foo_test.go +! stdout '(cached)' +go test -run=WriteTmp ./foo_test.go +! stdout '(cached)' + +[!exec:sleep] stop +# The go command refuses to cache access to files younger than 2s, so sleep that long. +exec sleep 2 + +# Touching a file that the test reads from within its testdata should invalidate the cache. +go test -run=ReadTestdata . +! stdout '(cached)' +go test -run=ReadTestdata . +stdout '(cached)' +cp testdata/bar.txt testdata/foo.txt +go test -run=ReadTestdata . +! stdout '(cached)' + +-- go.mod -- +module golang.org/issue/29111/foo + +-- foo.go -- +package foo + +-- testdata/foo.txt -- +foo +-- testdata/bar.txt -- +bar + +-- foo_test.go -- +package foo_test + +import ( + "os" + "path/filepath" + "testing" +) + +func TestWriteTmp(t *testing.T) { + dir, err := os.MkdirTemp("", "") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + err = os.WriteFile(filepath.Join(dir, "x"), nil, 0666) + if err != nil { + t.Fatal(err) + } +} + +func TestReadTestdata(t *testing.T) { + _, err := os.ReadFile("testdata/foo.txt") + if err != nil { + t.Fatal(err) + } +} diff --git a/src/cmd/go/testdata/script/mod_test_files.txt b/src/cmd/go/testdata/script/mod_test_files.txt new file mode 100644 index 0000000..6f520c7 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_test_files.txt @@ -0,0 +1,50 @@ +env GO111MODULE=on + +cd foo + +# Testing an explicit source file should use the same import visibility as the +# package in the same directory. +go list -test -deps +go list -test -deps foo_test.go + +# If the file is inside the main module's vendor directory, it should have +# visibility based on the vendor-relative import path. +mkdir vendor/example.com/foo +cp foo_test.go vendor/example.com/foo +go list -test -deps vendor/example.com/foo/foo_test.go + +# If the file is outside the main module entirely, it should be treated as outside. +cp foo_test.go ../foo_test.go +! go list -test -deps ../foo_test.go +stderr 'use of internal package' + +-- foo/go.mod -- +module example.com/foo +go 1.12 +require example.com/internal v0.0.0 +replace example.com/internal => ../internal + +-- foo/internal.go -- +package foo +import _ "example.com/internal" + +-- foo/foo_test.go -- +package foo_test + +import ( + "testing" + "example.com/internal" +) + +func TestHacksEnabled(t *testing.T) { + if !internal.Hacks { + t.Fatal("hacks not enabled") + } +} + +-- internal/go.mod -- +module example.com/internal + +-- internal/internal.go -- +package internal +const Hacks = true diff --git a/src/cmd/go/testdata/script/mod_tidy.txt b/src/cmd/go/testdata/script/mod_tidy.txt new file mode 100644 index 0000000..b1d9371 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy.txt @@ -0,0 +1,72 @@ +env GO111MODULE=on + +# tidy removes unused y, but everything else is used +go mod tidy -v +stderr '^unused y.1' +! stderr '^unused [^y]' + +grep 'go 1.10' go.mod + +go list -m all +! stdout '^y' +stdout '^w.1 v1.2.0' +stdout '^z.1 v1.2.0' + +# empty tidy should not crash +cd triv +! grep 'go ' go.mod +go mod tidy + +# tidy should add missing go line +grep 'go ' go.mod + +-- go.mod -- +module m + +go 1.10 + +require ( + x.1 v1.0.0 + y.1 v1.0.0 + w.1 v1.2.0 +) + +replace x.1 v1.0.0 => ./x +replace y.1 v1.0.0 => ./y +replace z.1 v1.1.0 => ./z +replace z.1 v1.2.0 => ./z +replace w.1 => ./w + +-- m.go -- +package m + +import _ "x.1" +import _ "z.1/sub" + +-- w/go.mod -- +module w + +-- w/w.go -- +package w + +-- x/go.mod -- +module x +require w.1 v1.1.0 +require z.1 v1.1.0 + +-- x/x.go -- +package x +import _ "w.1" + +-- y/go.mod -- +module y +require z.1 v1.2.0 + +-- z/go.mod -- +module z + +-- z/sub/sub.go -- +package sub + +-- triv/go.mod -- +module triv diff --git a/src/cmd/go/testdata/script/mod_tidy_compat.txt b/src/cmd/go/testdata/script/mod_tidy_compat.txt new file mode 100644 index 0000000..724c83e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_compat.txt @@ -0,0 +1,95 @@ +# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by +# default preserve enough checksums for the module to be used by Go 1.16. +# +# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the +# 'go' version in the go.mod file to 1.16, without actually updating the +# requirements to match. + +[short] skip + +env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' + + +# This module has the same module dependency graph in Go 1.16 as in Go 1.17, +# but in 1.16 requires (checksums for) additional (irrelevant) go.mod files. +# +# The module graph under both versions looks like: +# +# m ---- example.com/version v1.1.0 +# | +# + ---- example.net/lazy v0.1.0 ---- example.com/version v1.0.1 +# +# Go 1.17 avoids loading the go.mod file for example.com/version v1.0.1 +# (because it is lower than the version explicitly required by m, +# and the module that requires it — m — specifies 'go 1.17'). +# +# That go.mod file happens not to affect the final 1.16 module graph anyway, +# so the pruned graph is equivalent to the unpruned one. + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +go list -m all +cmp stdout m_all.txt + +go mod edit -go=1.16 +go list -m all +cmp stdout m_all.txt + + +# If we explicitly drop compatibility with 1.16, we retain fewer checksums, +# which gives a cleaner go.sum file but causes 1.16 to fail in readonly mode. + +cp go.mod.orig go.mod +go mod tidy -compat=1.17 +cmp go.mod go.mod.orig + +go list -m all +cmp stdout m_all.txt + +go mod edit -go=1.16 +! go list -m all +stderr '^go: example.net/lazy@v0.1.0 requires\n\texample.com/version@v1.0.1: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/version$' + + +-- go.mod -- +// Module m happens to have the exact same build list as what would be +// selected under Go 1.16, but computes that build list without looking at +// as many go.mod files. +module example.com/m + +go 1.17 + +replace example.net/lazy v0.1.0 => ./lazy + +require ( + example.com/version v1.1.0 + example.net/lazy v0.1.0 +) +-- m_all.txt -- +example.com/m +example.com/version v1.1.0 +example.net/lazy v0.1.0 => ./lazy +-- compatible.go -- +package compatible + +import ( + _ "example.com/version" + _ "example.net/lazy" +) +-- lazy/go.mod -- +// Module lazy requires example.com/version v1.0.1. +// +// However, since this module is lazy, its dependents +// should not need checksums for that version of the module +// unless they actually import packages from it. +module example.net/lazy + +go 1.17 + +require example.com/version v1.0.1 +-- lazy/lazy.go -- +package lazy + +import _ "example.com/version" diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_added.txt b/src/cmd/go/testdata/script/mod_tidy_compat_added.txt new file mode 100644 index 0000000..b3f75ad --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_compat_added.txt @@ -0,0 +1,105 @@ +# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by +# default preserve enough checksums for the module to be used by Go 1.16. +# +# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the +# 'go' version in the go.mod file to 1.16, without actually updating the +# requirements to match. + +[short] skip + +env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' + + +# For this module, Go 1.17 produces an error for one module, and Go 1.16 +# produces a different error for a different module. + +cp go.mod go.mod.orig + +! go mod tidy + +stderr '^go: example\.com/m imports\n\texample\.net/added: module example\.net/added@latest found \(v0\.3\.0, replaced by \./a1\), but does not contain package example\.net/added$' + +cmp go.mod go.mod.orig + + +# When we run 'go mod tidy -e', we should proceed past the first error and follow +# it with a second error describing the version discrepancy. +# +# We should not provide advice on how to push past the version discrepancy, +# because the '-e' flag should already do that, writing out an otherwise-tidied +# go.mod file. + +go mod tidy -e + +stderr '^go: example\.com/m imports\n\texample\.net/added: module example\.net/added@latest found \(v0\.3\.0, replaced by \./a1\), but does not contain package example\.net/added\ngo: example\.net/added failed to load from any module,\n\tbut go 1\.16 would load it from example\.net/added@v0\.2\.0$' + +! stderr '\n\tgo mod tidy' + +cmp go.mod go.mod.tidy + + +-- go.mod -- +module example.com/m + +go 1.17 + +replace ( + example.net/added v0.1.0 => ./a1 + example.net/added v0.2.0 => ./a2 + example.net/added v0.3.0 => ./a1 + example.net/lazy v0.1.0 => ./lazy + example.net/pruned v0.1.0 => ./pruned +) + +require ( + example.net/added v0.1.0 + example.net/lazy v0.1.0 +) +-- go.mod.tidy -- +module example.com/m + +go 1.17 + +replace ( + example.net/added v0.1.0 => ./a1 + example.net/added v0.2.0 => ./a2 + example.net/added v0.3.0 => ./a1 + example.net/lazy v0.1.0 => ./lazy + example.net/pruned v0.1.0 => ./pruned +) + +require example.net/lazy v0.1.0 +-- m.go -- +package m + +import ( + _ "example.net/added" + _ "example.net/lazy" +) + +-- a1/go.mod -- +module example.net/added + +go 1.17 +-- a2/go.mod -- +module example.net/added + +go 1.17 +-- a2/added.go -- +package added + +-- lazy/go.mod -- +module example.net/lazy + +go 1.17 + +require example.net/pruned v0.1.0 +-- lazy/lazy.go -- +package lazy + +-- pruned/go.mod -- +module example.net/pruned + +go 1.17 + +require example.net/added v0.2.0 diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt b/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt new file mode 100644 index 0000000..5316220 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt @@ -0,0 +1,97 @@ +# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by +# default preserve enough checksums for the module to be used by Go 1.16. +# +# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the +# 'go' version in the go.mod file to 1.16, without actually updating the +# requirements to match. + +[short] skip + +env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' + +# For this module, the dependency providing package +# example.net/ambiguous/nested/pkg is unambiguous in Go 1.17 (because only one +# root of the module graph contains the package), whereas it is ambiguous in +# Go 1.16 (because two different modules contain plausible packages and Go 1.16 +# does not privilege roots above other dependencies). +# +# However, the overall build list is identical for both versions. + +cp go.mod go.mod.orig + +! go mod tidy + +stderr '^go: example\.com/m imports\n\texample\.net/indirect imports\n\texample\.net/ambiguous/nested/pkg loaded from example\.net/ambiguous/nested@v0\.1\.0,\n\tbut go 1.16 would fail to locate it:\n\tambiguous import: found package example\.net/ambiguous/nested/pkg in multiple modules:\n\texample\.net/ambiguous v0.1.0 \(.*\)\n\texample\.net/ambiguous/nested v0.1.0 \(.*\)\n\n' + +stderr '\n\nTo proceed despite packages unresolved in go 1\.16:\n\tgo mod tidy -e\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n' + +cmp go.mod go.mod.orig + + +# If we run 'go mod tidy -e', we should still save enough checksums to run +# 'go list -m all' reproducibly with go 1.16, even though we can't list +# the specific package. + +go mod tidy -e +! stderr '\n\tgo mod tidy' +cmp go.mod go.mod.orig + +go list -m all +cmp stdout all-m.txt + +go list -f $MODFMT example.net/ambiguous/nested/pkg +stdout '^example.net/ambiguous/nested v0\.1\.0$' +! stderr . + +go mod edit -go=1.16 +go list -m all +cmp stdout all-m.txt + +! go list -f $MODFMT example.net/ambiguous/nested/pkg +stderr '^ambiguous import: found package example\.net/ambiguous/nested/pkg in multiple modules:\n\texample\.net/ambiguous v0\.1\.0 \(.*\)\n\texample\.net/ambiguous/nested v0\.1\.0 \(.*\)\n' + + +# On the other hand, if we use -compat=1.17, 1.16 can't even load +# the build list (due to missing checksums). + +cp go.mod.orig go.mod +go mod tidy -compat=1.17 +! stderr . +go list -m all +cmp stdout all-m.txt + +go mod edit -go=1.16 +! go list -m all +stderr '^go: example\.net/indirect@v0\.1\.0 requires\n\texample\.net/ambiguous@v0\.1\.0: missing go\.sum entry for go\.mod file; to add it:\n\tgo mod download example\.net/ambiguous\n' + + +-- go.mod -- +module example.com/m + +go 1.17 + +replace example.net/indirect v0.1.0 => ./indirect + +require example.net/indirect v0.1.0 + +require example.net/ambiguous/nested v0.1.0 // indirect +-- all-m.txt -- +example.com/m +example.net/ambiguous v0.1.0 +example.net/ambiguous/nested v0.1.0 +example.net/indirect v0.1.0 => ./indirect +-- m.go -- +package m + +import _ "example.net/indirect" + +-- indirect/go.mod -- +module example.net/indirect + +go 1.17 + +require example.net/ambiguous v0.1.0 +-- indirect/indirect.go -- +package indirect + +import _ "example.net/ambiguous/nested/pkg" diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt b/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt new file mode 100644 index 0000000..b148fc1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt @@ -0,0 +1,128 @@ +# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by +# default preserve enough checksums for the module to be used by Go 1.16. +# +# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the +# 'go' version in the go.mod file to 1.16, without actually updating the +# requirements to match. + +[short] skip + +env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' + + +# For this module, the "deleted" dependency contains an imported package, but +# Go 1.16 selects a higher version (in which that package has been deleted). + +cp go.mod go.mod.orig + +! go mod tidy + +stderr '^go: example\.com/m imports\n\texample\.net/deleted loaded from example\.net/deleted@v0\.1\.0,\n\tbut go 1\.16 would fail to locate it in example\.net/deleted@v0\.2\.0\n\n' + +stderr '\n\nTo upgrade to the versions selected by go 1.16, leaving some packages unresolved:\n\tgo mod tidy -e -go=1\.16 && go mod tidy -e -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n' + + +# The suggested 'go mod tidy -e' command should proceed anyway. + +go mod tidy -e +cmp go.mod go.mod.tidy + + +# In 'go 1.16' mode we should error out in the way we claimed. + +cd 116-outside +! go list -deps -f $MODFMT example.com/m +stderr '^\.\.[/\\]m\.go:4:2: no required module provides package example\.net/deleted; to add it:\n\tgo get example\.net/deleted$' +cd .. + +go mod edit -go=1.16 +! go list -deps -f $MODFMT example.com/m +stderr '^go: updates to go\.mod needed; to update it:\n\tgo mod tidy$' + +! go mod tidy +stderr '^go: example\.com/m imports\n\texample\.net/deleted: module example\.net/deleted@latest found \(v0\.2\.0, replaced by \./d2\), but does not contain package example\.net/deleted$' + + +-- go.mod -- +module example.com/m + +go 1.17 + +replace ( + example.net/deleted v0.1.0 => ./d1 + example.net/deleted v0.2.0 => ./d2 + example.net/lazy v0.1.0 => ./lazy + example.net/pruned v0.1.0 => ./pruned +) + +require ( + example.net/deleted v0.1.0 + example.net/deleted v0.1.0 // redundant + example.net/lazy v0.1.0 +) +-- go.mod.tidy -- +module example.com/m + +go 1.17 + +replace ( + example.net/deleted v0.1.0 => ./d1 + example.net/deleted v0.2.0 => ./d2 + example.net/lazy v0.1.0 => ./lazy + example.net/pruned v0.1.0 => ./pruned +) + +require ( + example.net/deleted v0.1.0 + example.net/lazy v0.1.0 +) +-- 116-outside/go.mod -- +module outside + +go 1.16 + +replace ( + example.com/m => ../ + example.net/deleted v0.1.0 => ../d1 + example.net/deleted v0.2.0 => ../d2 + example.net/lazy v0.1.0 => ../lazy + example.net/pruned v0.1.0 => ../pruned +) + +require example.com/m v0.1.0 +-- m.go -- +package m + +import ( + _ "example.net/deleted" + _ "example.net/lazy" +) + +-- d1/go.mod -- +module example.net/deleted + +go 1.17 +-- d1/deleted.go -- +package deleted +-- d2/go.mod -- +module example.net/deleted + +go 1.17 +-- d2/README -- +There is no longer a Go package here. + +-- lazy/go.mod -- +module example.net/lazy + +go 1.17 + +require example.net/pruned v0.1.0 +-- lazy/lazy.go -- +package lazy + +-- pruned/go.mod -- +module example.net/pruned + +go 1.17 + +require example.net/deleted v0.2.0 diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt b/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt new file mode 100644 index 0000000..26e4749 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt @@ -0,0 +1,128 @@ +# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by +# default preserve enough checksums for the module to be used by Go 1.16. +# +# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the +# 'go' version in the go.mod file to 1.16, without actually updating the +# requirements to match. + +[short] skip + +env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' + + +# For this module, Go 1.16 selects the same versions of all explicit dependencies +# as Go 1.17 does. However, Go 1.16 selects a higher version of an *implicit* +# dependency, imported by a test of one of the (external) imported packages. +# As a result, Go 1.16 also needs checksums for the module sources for that higher +# version. +# +# The Go 1.16 module graph looks like: +# +# m ---- lazy v0.1.0 ---- incompatible v1.0.0 +# | +# + ------------- requireincompatible v0.1.0 ---- incompatible v2.0.0+incompatible +# +# The Go 1.17 module graph is the same except that the dependencies of +# requireincompatible are pruned out (because the module that requires +# it — lazy v0.1.0 — specifies 'go 1.17', and it is not otherwise relevant to +# the main module). + +# 'go mod tidy' should by default diagnose the difference in dependencies as an +# error, with useful suggestions about how to resolve it. + +cp go.mod go.mod.orig +! go mod tidy +stderr '^go: example\.com/m imports\n\texample\.net/lazy tested by\n\texample\.net/lazy.test imports\n\texample\.com/retract/incompatible loaded from example\.com/retract/incompatible@v1\.0\.0,\n\tbut go 1\.16 would select v2\.0\.0\+incompatible\n\n' +stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n' + +cmp go.mod go.mod.orig + +# The suggested '-compat' flag to ignore differences should silence the error +# and leave go.mod unchanged, resulting in checksum errors when Go 1.16 tries +# to load a module pruned out by Go 1.17. + +go mod tidy -compat=1.17 +! stderr . +cmp go.mod go.mod.orig + +go list -deps -test -f $MODFMT ./... +stdout '^example.net/lazy v0.1.0$' + +go mod edit -go=1.16 +! go list -deps -test -f $MODFMT ./... + +stderr -count=1 '^go: example\.net/lazy@v0\.1\.0 requires\n\texample\.com/retract/incompatible@v1\.0\.0: missing go\.sum entry for go\.mod file; to add it:\n\tgo mod download example\.com/retract/incompatible$' + + +# If we combine a Go 1.16 go.sum file... +go mod tidy -go=1.16 + +# ...with a Go 1.17 go.mod file... +cp go.mod.orig go.mod + +# ...then Go 1.17 no longer works. 😞 +! go list -deps -test -f $MODFMT all +stderr -count=1 '^go: can''t load test package: lazy[/\\]lazy_test.go:3:8: missing go\.sum entry for module providing package example\.com/retract/incompatible \(imported by example\.net/lazy\); to add:\n\tgo get -t example.net/lazy@v0\.1\.0$' + + +# However, if we take the union of the go.sum files... +go list -mod=mod -deps -test all +cmp go.mod go.mod.orig + +# ...then Go 1.17 continues to work... +go list -deps -test -f $MODFMT all +stdout '^example\.com/retract/incompatible v1\.0\.0$' + +# ...and 1.16 also works(‽), but selects a different version for the +# external-test dependency. +go mod edit -go=1.16 +go list -deps -test -f $MODFMT all +stdout '^example\.com/retract/incompatible v2\.0\.0\+incompatible$' + + +-- go.mod -- +// Module m imports packages from the same versions under Go 1.17 +// as under Go 1.16, but under 1.16 its (implicit) external test dependencies +// are higher. +module example.com/m + +go 1.17 + +replace ( + example.net/lazy v0.1.0 => ./lazy + example.net/requireincompatible v0.1.0 => ./requireincompatible +) + +require example.net/lazy v0.1.0 +-- implicit.go -- +package implicit + +import _ "example.net/lazy" +-- lazy/go.mod -- +// Module lazy requires example.com/retract/incompatible v1.0.0. +// +// When viewed from the outside it also has a transitive dependency +// on v2.0.0+incompatible, but in lazy mode that transitive dependency +// is pruned out. +module example.net/lazy + +go 1.17 + +exclude example.com/retract/incompatible v2.0.0+incompatible + +require ( + example.com/retract/incompatible v1.0.0 + example.net/requireincompatible v0.1.0 +) +-- lazy/lazy.go -- +package lazy +-- lazy/lazy_test.go -- +package lazy_test + +import _ "example.com/retract/incompatible" +-- requireincompatible/go.mod -- +module example.net/requireincompatible + +go 1.15 + +require example.com/retract/incompatible v2.0.0+incompatible diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt b/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt new file mode 100644 index 0000000..9e2a9ee --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt @@ -0,0 +1,133 @@ +# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by +# default preserve enough checksums for the module to be used by Go 1.16. +# +# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the +# 'go' version in the go.mod file to 1.16, without actually updating the +# requirements to match. + +[short] skip + +env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' + + +# For this module, Go 1.17 prunes out a (transitive and otherwise-irrelevant) +# requirement on a retracted higher version of a dependency. +# However, when Go 1.16 reads the same requirements from the go.mod file, +# it does not prune out that requirement, and selects the retracted version. +# +# The Go 1.16 module graph looks like: +# +# m ---- lazy v0.1.0 ---- requireincompatible v0.1.0 ---- incompatible v2.0.0+incompatible +# | | +# + -------+------------- incompatible v1.0.0 +# +# The Go 1.17 module graph is the same except that the dependencies of +# requireincompatible are pruned out (because the module that requires +# it — lazy v0.1.0 — specifies 'go 1.17', and it is not otherwise relevant to +# the main module). + + +# 'go mod tidy' should by default diagnose the difference in dependencies as an +# error, with useful suggestions about how to resolve it. + +cp go.mod go.mod.orig +! go mod tidy +stderr '^go: example\.com/m imports\n\texample\.net/lazy imports\n\texample\.com/retract/incompatible loaded from example\.com/retract/incompatible@v1\.0\.0,\n\tbut go 1\.16 would select v2\.0\.0\+incompatible\n\n' +stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1\.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n' + +cmp go.mod go.mod.orig + + +# The suggested '-compat' flag to ignore differences should silence the error +# and leave go.mod unchanged, resulting in checksum errors when Go 1.16 tries +# to load a module pruned out by Go 1.17. + +go mod tidy -compat=1.17 +! stderr . +cmp go.mod go.mod.orig + +go mod edit -go=1.16 +! go list -f $MODFMT -deps ./... +stderr -count=1 '^go: example\.net/lazy@v0\.1\.0 requires\n\texample\.net/requireincompatible@v0\.1\.0 requires\n\texample\.com/retract/incompatible@v2\.0\.0\+incompatible: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/retract/incompatible$' + + +# There are two ways for the module author to bring the two into alignment. +# One is to *explicitly* 'exclude' the version that is already *implicitly* +# pruned out under 1.17. + +go mod edit -exclude=example.com/retract/incompatible@v2.0.0+incompatible +go list -f $MODFMT -deps ./... +stdout '^example.com/retract/incompatible v1\.0\.0$' +! stdout 'v2\.0\.0' + + +# The other is to explicitly upgrade the version required under Go 1.17 +# to match the version selected by Go 1.16. The commands suggested by +# 'go mod tidy' should do exactly that. + +cp go.mod.orig go.mod + +go mod tidy -go=1.16 +go list -f $MODFMT -deps ./... +stdout '^example.com/retract/incompatible v2\.0\.0\+incompatible$' +! stdout 'v1\.0\.0' + +go mod tidy -go=1.17 +go list -f $MODFMT -deps ./... +stdout '^example.com/retract/incompatible v2\.0\.0\+incompatible$' +! stdout 'v1\.0\.0' + +go mod edit -go=1.16 +go list -f $MODFMT -deps ./... +stdout '^example.com/retract/incompatible v2\.0\.0\+incompatible$' +! stdout 'v1\.0\.0' + + +-- go.mod -- +// Module m indirectly imports a package from +// example.com/retract/incompatible. Its selected version of +// that module is lower under Go 1.17 semantics than under Go 1.16. +module example.com/m + +go 1.17 + +replace ( + example.net/lazy v0.1.0 => ./lazy + example.net/requireincompatible v0.1.0 => ./requireincompatible +) + +require example.net/lazy v0.1.0 + +require example.com/retract/incompatible v1.0.0 // indirect +-- incompatible.go -- +package incompatible + +import _ "example.net/lazy" + +-- lazy/go.mod -- +// Module lazy requires example.com/retract/incompatible v1.0.0. +// +// When viewed from the outside it also has a transitive dependency +// on v2.0.0+incompatible, but in lazy mode that transitive dependency +// is pruned out. +module example.net/lazy + +go 1.17 + +exclude example.com/retract/incompatible v2.0.0+incompatible + +require ( + example.com/retract/incompatible v1.0.0 + example.net/requireincompatible v0.1.0 +) +-- lazy/lazy.go -- +package lazy + +import _ "example.com/retract/incompatible" + +-- requireincompatible/go.mod -- +module example.net/requireincompatible + +go 1.15 + +require example.com/retract/incompatible v2.0.0+incompatible diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_irrelevant.txt b/src/cmd/go/testdata/script/mod_tidy_compat_irrelevant.txt new file mode 100644 index 0000000..e4eaea0 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_compat_irrelevant.txt @@ -0,0 +1,98 @@ +# https://golang.org/issue/46141: 'go mod tidy' for a Go 1.17 module should by +# default preserve enough checksums for the module to be used by Go 1.16. +# +# We don't have a copy of Go 1.16 handy, but we can simulate it by editing the +# 'go' version in the go.mod file to 1.16, without actually updating the +# requirements to match. + +[short] skip + +env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' + + +# This module selects the same versions in Go 1.16 and 1.17 for all modules +# that provide packages (or test dependencies of packages) imported by the +# main module. However, in Go 1.16 it selects a higher version of a +# transitive module dependency that is not otherwise relevant to the main module. +# As a result, Go 1.16 needs an additional checksum for the go.mod file of +# that irrelevant dependency. +# +# The Go 1.16 module graph looks like: +# +# m ---- lazy v0.1.0 ---- incompatible v1.0.0 +# | +# + ------------- requireincompatible v0.1.0 ---- incompatible v2.0.0+incompatible + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +go list -deps -test -f $MODFMT all +cp stdout out-117.txt + +go mod edit -go=1.16 +go list -deps -test -f $MODFMT all +cmp stdout out-117.txt + + +# If we explicitly drop compatibility with 1.16, we retain fewer checksums, +# which gives a cleaner go.sum file but causes 1.16 to fail in readonly mode. + +cp go.mod.orig go.mod +go mod tidy -compat=1.17 +cmp go.mod go.mod.orig + +go list -deps -test -f $MODFMT all +cmp stdout out-117.txt + +go mod edit -go=1.16 +! go list -deps -test -f $MODFMT all +stderr -count=1 '^go: example.net/lazy@v0.1.0 requires\n\texample.com/retract/incompatible@v1.0.0: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/retract/incompatible$' + + +-- go.mod -- +// Module m imports packages from the same versions under Go 1.17 +// as under Go 1.16, but under 1.16 its (implicit) external test dependencies +// are higher. +module example.com/m + +go 1.17 + +replace ( + example.net/lazy v0.1.0 => ./lazy + example.net/requireincompatible v0.1.0 => ./requireincompatible +) + +require example.net/lazy v0.1.0 +-- m.go -- +package m + +import _ "example.net/lazy" +-- lazy/go.mod -- +// Module lazy requires example.com/retract/incompatible v1.0.0. +// +// When viewed from the outside it also has a transitive dependency +// on v2.0.0+incompatible, but in lazy mode that transitive dependency +// is pruned out. +module example.net/lazy + +go 1.17 + +exclude example.com/retract/incompatible v2.0.0+incompatible + +require ( + example.com/retract/incompatible v1.0.0 + example.net/requireincompatible v0.1.0 +) +-- lazy/lazy.go -- +package lazy +-- lazy/unimported/unimported.go -- +package unimported + +import _ "example.com/retract/incompatible" +-- requireincompatible/go.mod -- +module example.net/requireincompatible + +go 1.15 + +require example.com/retract/incompatible v2.0.0+incompatible diff --git a/src/cmd/go/testdata/script/mod_tidy_convergence.txt b/src/cmd/go/testdata/script/mod_tidy_convergence.txt new file mode 100644 index 0000000..45f74b4 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_convergence.txt @@ -0,0 +1,202 @@ +# This test demonstrates a simple case in which 'go mod tidy' may resolve a +# missing package, only to remove that package when resolving its dependencies. +# +# If we naively iterate 'go mod tidy' until the dependency graph converges, this +# scenario may fail to converge. + +# The import graph used in this test looks like: +# +# m --- x +# | +# x_test --- y +# +# The module dependency graph of m is initially empty. +# Modules x and y look like: +# +# x.1 (provides package x that imports y, but does not depend on module y) +# +# x.2-pre (no dependencies, but does not provide package x) +# +# y.1 (no dependencies, but provides package y) +# +# y.2 --- x.2-pre (provides package y) +# +# +# When we resolve the missing import of y in x_test, we add y@latest — which is +# y.2, not y.1 — as a new dependency. That upgrades to x to x.2-pre, which +# removes package x (and also the need for module y). We can then safely remove +# the dependency on module y, because nothing imports package y any more! +# +# We might be tempted to remove the dependency on module x for the same reason: +# it no longer provides any imported package. However, that would cause 'go mod +# tidy -e' to become unstable: with x.2-pre out of the way, we could once again +# resolve the missing import of package x by re-adding x.1. + +cp go.mod go.mod.orig + +# 'go mod tidy' without -e should fail without modifying go.mod, +# because it cannot resolve x and y simultaneously. +! go mod tidy + +cmp go.mod go.mod.orig + +stderr '^go: found example\.net/y in example\.net/y v0.2.0$' +stderr '^go: finding module for package example\.net/x$' + + # TODO: This error message should be clearer — it doesn't indicate why v0.2.0-pre is required. +stderr '^go: example\.net/m imports\n\texample\.net/x: package example\.net/x provided by example\.net/x at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$' + + +# 'go mod tidy -e' should follow upgrades to try to resolve the modules that it +# can, and then stop. When we resolve example.net/y, we upgrade to example.net/x +# to v0.2.0-pre. At that version, package x no longer exists and no longer +# imports package y, so the import of x should be left unsatisfied and the +# existing dependency on example.net/x removed. +# +# TODO(bcmills): It would be ever better if we could keep the original +# dependency on example.net/x v0.1.0, but I don't see a way to do that without +# making the algorithm way too complicated. (We would have to detect that the +# new dependency on example.net/y interferes with the package that caused us to +# to add that dependency in the first place, and back out that part of the change +# without also backing out any other needed changes.) + +go mod tidy -e +cmp go.mod go.mod.tidye +stderr '^go: found example\.net/y in example\.net/y v0.2.0$' + + # TODO: This error message should be clearer — it doesn't indicate why v0.2.0-pre is required. +stderr '^go: example\.net/m imports\n\texample\.net/x: package example\.net/x provided by example\.net/x at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$' + + +# Since we attempt to resolve the dependencies of package x whenever we add x itself, +# this end state is stable. + +go mod tidy -e +cmp go.mod go.mod.tidye + + +# An explicit 'go get' with the correct versions should allow 'go mod tidy' to +# succeed and remain stable. y.1 does not upgrade x, and can therefore be used +# with it. + +go get example.net/x@v0.1.0 example.net/y@v0.1.0 +go mod tidy +cmp go.mod go.mod.postget + + +# The 'tidy' logic for a lazy main module is somewhat different from that for an +# eager main module, but the overall behavior is the same. + +cp go.mod.orig go.mod +go mod edit -go=1.17 go.mod +go mod edit -go=1.17 go.mod.tidye + +go mod tidy -e +cmp go.mod go.mod.tidye +stderr '^go: found example\.net/y in example\.net/y v0.2.0$' +stderr '^go: example\.net/m imports\n\texample\.net/x: package example\.net/x provided by example\.net/x at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$' + +go get example.net/x@v0.1.0 example.net/y@v0.1.0 +go mod tidy +cmp go.mod go.mod.postget-117 + + +-- go.mod -- +module example.net/m + +go 1.16 + +replace ( + example.net/x v0.1.0 => ./x1 + example.net/x v0.2.0-pre => ./x2-pre + example.net/y v0.1.0 => ./y1 + example.net/y v0.2.0 => ./y2 +) + +require ( + example.net/x v0.1.0 +) +-- go.mod.tidye -- +module example.net/m + +go 1.16 + +replace ( + example.net/x v0.1.0 => ./x1 + example.net/x v0.2.0-pre => ./x2-pre + example.net/y v0.1.0 => ./y1 + example.net/y v0.2.0 => ./y2 +) +-- go.mod.postget -- +module example.net/m + +go 1.16 + +replace ( + example.net/x v0.1.0 => ./x1 + example.net/x v0.2.0-pre => ./x2-pre + example.net/y v0.1.0 => ./y1 + example.net/y v0.2.0 => ./y2 +) + +require ( + example.net/x v0.1.0 + example.net/y v0.1.0 // indirect +) +-- go.mod.postget-117 -- +module example.net/m + +go 1.17 + +replace ( + example.net/x v0.1.0 => ./x1 + example.net/x v0.2.0-pre => ./x2-pre + example.net/y v0.1.0 => ./y1 + example.net/y v0.2.0 => ./y2 +) + +require example.net/x v0.1.0 + +require example.net/y v0.1.0 // indirect +-- m.go -- +package m + +import _ "example.net/x" + +-- x1/go.mod -- +module example.net/x + +go 1.16 +-- x1/x.go -- +package x +-- x1/x_test.go -- +package x + +import _ "example.net/y" + +-- x2-pre/go.mod -- +module example.net/x + +go 1.16 +-- x2-pre/README.txt -- +There is no package x here. Use example.com/x/subpkg instead. +-- x2-pre/subpkg/subpkg.go -- +package subpkg // import "example.net/x/subpkg" + +-- y1/go.mod -- +module example.net/y + +go 1.16 +-- y1/y.go -- +package y + +-- y2/go.mod -- +module example.net/y + +go 1.16 + +require example.net/x v0.2.0-pre +-- y2/y.go -- +package y + +import _ "example.net/x/subpkg" diff --git a/src/cmd/go/testdata/script/mod_tidy_convergence_loop.txt b/src/cmd/go/testdata/script/mod_tidy_convergence_loop.txt new file mode 100644 index 0000000..ec58159 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_convergence_loop.txt @@ -0,0 +1,329 @@ +# This test demonstrates a simple case in which 'go mod tidy' may resolve a +# missing package, only to remove that package when resolving its dependencies. +# +# If we naively iterate 'go mod tidy' until the dependency graph converges, this +# scenario may fail to converge. + +# The import graph used in this test looks like: +# +# m --- w +# | +# + --- x +# | +# + --- y +# | +# + --- z +# +# The module dependency graph of m initially contains w.1 (and, by extension, +# y.2-pre and z.2-pre). This is an arbitrary point in the cycle of possible +# configurations. +# +# w.1 requires y.2-pre and z.2-pre +# x.1 requires z.2-pre and w.2-pre +# y.1 requires w.2-pre and x.2-pre +# z.1 requires x.2-pre and y.2-pre +# +# At each point, exactly one missing package can be resolved by adding a +# dependency on the .1 release of the module that provides that package. +# However, adding that dependency causes the module providing another package to +# roll over from its .1 release to its .2-pre release, which removes the +# package. Once the package is removed, 'go mod tidy -e' no longer sees the +# module as relevant to the main module, and will happily remove the existing +# dependency on it. +# +# The cycle is of length 4 so that at every step only one package can be +# resolved. This is important because it prevents the iteration from ever +# reaching a state in which every package is simultaneously over-upgraded — such +# a state is stable and does not exhibit failure to converge. + +cp go.mod go.mod.orig + +# 'go mod tidy' without -e should fail without modifying go.mod, +# because it cannot resolve x, y, and z simultaneously. +! go mod tidy + +cmp go.mod go.mod.orig + +stderr '^go: finding module for package example\.net/w$' +stderr '^go: finding module for package example\.net/x$' +stderr -count=2 '^go: finding module for package example\.net/y$' +stderr -count=2 '^go: finding module for package example\.net/z$' +stderr '^go: found example\.net/x in example\.net/x v0.1.0$' + + # TODO: These error messages should be clearer — it doesn't indicate why v0.2.0-pre is required. +stderr '^go: example\.net/m imports\n\texample\.net/w: package example\.net/w provided by example\.net/w at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$' +stderr '^go: example\.net/m imports\n\texample\.net/y: package example\.net/y provided by example\.net/y at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$' +stderr '^go: example\.net/m imports\n\texample\.net/z: package example\.net/z provided by example\.net/z at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$' + + +# 'go mod tidy -e' should preserve all of the upgrades to modules that could +# provide the missing packages but don't. That would at least explain why they +# are missing, and why no individual module can be upgraded in order to satisfy +# a missing import. +# +# TODO(bcmills): Today, it doesn't preserve those upgrades, and instead advances +# the state by one through the cycle of semi-tidy states. + +go mod tidy -e + +cmp go.mod go.mod.tidye1 + +stderr '^go: finding module for package example\.net/w$' +stderr '^go: finding module for package example\.net/x$' +stderr -count=2 '^go: finding module for package example\.net/y$' +stderr -count=2 '^go: finding module for package example\.net/z$' +stderr '^go: found example\.net/x in example\.net/x v0.1.0$' + +stderr '^go: example\.net/m imports\n\texample\.net/w: package example\.net/w provided by example\.net/w at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$' +stderr '^go: example\.net/m imports\n\texample\.net/y: package example\.net/y provided by example\.net/y at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$' +stderr '^go: example\.net/m imports\n\texample\.net/z: package example\.net/z provided by example\.net/z at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$' + + +go mod tidy -e +cmp go.mod go.mod.tidye2 + +go mod tidy -e +cmp go.mod go.mod.tidye3 + +go mod tidy -e +cmp go.mod go.mod.orig + + +# If we upgrade away all of the packages simultaneously, the resulting tidy +# state converges at "no dependencies", because simultaneously adding all of the +# packages simultaneously over-upgrades all of the dependencies, and 'go mod +# tidy' treats "no package can be added" as a terminal state. + +go get example.net/w@v0.2.0-pre example.net/x@v0.2.0-pre example.net/y@v0.2.0-pre example.net/z@v0.2.0-pre +go mod tidy -e +cmp go.mod go.mod.postget +go mod tidy -e +cmp go.mod go.mod.postget + + +# The 'tidy' logic for a lazy main module requires more iterations to converge, +# because it is willing to drop dependencies on non-root modules that do not +# otherwise provide imported packages. +# +# On the first iteration, it adds x.1 as a root, which upgrades z and w, +# dropping w.1's requirement on y. w.1 was initially a root, so the upgraded +# w.2-pre is retained as a root. +# +# On the second iteration, it adds y.1 as a root, which upgrades w and x, +# dropping x.1's requirement on z. x.1 was added as a root in the previous step, +# so the upgraded x.2-pre is retained as a root. +# +# On the third iteration, it adds z.1 as a root, which upgrades x and y. +# x and y were already roots (from the previous steps), so their upgraded versions +# are retained (not dropped) and the iteration stops. +# +# At that point, we have z.1 as a root providing package z, +# and w, x, and y have all been upgraded to no longer provide any packages. +# So only z is retained as a new root. +# +# (From the above, we can see that in a lazy module we still cycle through the +# same possible root states, but in a different order from the eager case.) +# +# TODO(bcmills): if we retained the upgrades on w, x, and y (since they are +# lexical prefixes for unresolved packages w, x, and y, respectively), then 'go +# mod tidy -e' itself would become stable and no longer cycle through states. + +cp go.mod.orig go.mod +go mod edit -go=1.17 go.mod +cp go.mod go.mod.117 +go mod edit -go=1.17 go.mod.tidye1 +go mod edit -go=1.17 go.mod.tidye2 +go mod edit -go=1.17 go.mod.tidye3 +go mod edit -go=1.17 go.mod.postget + +go list -m all + +go mod tidy -e +cmp go.mod go.mod.tidye3 + +go mod tidy -e +cmp go.mod go.mod.tidye2 + +go mod tidy -e +cmp go.mod go.mod.tidye1 + +go mod tidy -e +cmp go.mod go.mod.117 + + +# As in the eager case, for the lazy module the fully-upgraded dependency graph +# becomes empty, and the empty graph is stable. + +go get example.net/w@v0.2.0-pre example.net/x@v0.2.0-pre example.net/y@v0.2.0-pre example.net/z@v0.2.0-pre +go mod tidy -e +cmp go.mod go.mod.postget +go mod tidy -e +cmp go.mod go.mod.postget + + +-- m.go -- +package m + +import ( + _ "example.net/w" + _ "example.net/x" + _ "example.net/y" + _ "example.net/z" +) + +-- go.mod -- +module example.net/m + +go 1.16 + +replace ( + example.net/w v0.1.0 => ./w1 + example.net/w v0.2.0-pre => ./w2-pre + example.net/x v0.1.0 => ./x1 + example.net/x v0.2.0-pre => ./x2-pre + example.net/y v0.1.0 => ./y1 + example.net/y v0.2.0-pre => ./y2-pre + example.net/z v0.1.0 => ./z1 + example.net/z v0.2.0-pre => ./z2-pre +) + +require example.net/w v0.1.0 +-- go.mod.tidye1 -- +module example.net/m + +go 1.16 + +replace ( + example.net/w v0.1.0 => ./w1 + example.net/w v0.2.0-pre => ./w2-pre + example.net/x v0.1.0 => ./x1 + example.net/x v0.2.0-pre => ./x2-pre + example.net/y v0.1.0 => ./y1 + example.net/y v0.2.0-pre => ./y2-pre + example.net/z v0.1.0 => ./z1 + example.net/z v0.2.0-pre => ./z2-pre +) + +require example.net/x v0.1.0 +-- go.mod.tidye2 -- +module example.net/m + +go 1.16 + +replace ( + example.net/w v0.1.0 => ./w1 + example.net/w v0.2.0-pre => ./w2-pre + example.net/x v0.1.0 => ./x1 + example.net/x v0.2.0-pre => ./x2-pre + example.net/y v0.1.0 => ./y1 + example.net/y v0.2.0-pre => ./y2-pre + example.net/z v0.1.0 => ./z1 + example.net/z v0.2.0-pre => ./z2-pre +) + +require example.net/y v0.1.0 +-- go.mod.tidye3 -- +module example.net/m + +go 1.16 + +replace ( + example.net/w v0.1.0 => ./w1 + example.net/w v0.2.0-pre => ./w2-pre + example.net/x v0.1.0 => ./x1 + example.net/x v0.2.0-pre => ./x2-pre + example.net/y v0.1.0 => ./y1 + example.net/y v0.2.0-pre => ./y2-pre + example.net/z v0.1.0 => ./z1 + example.net/z v0.2.0-pre => ./z2-pre +) + +require example.net/z v0.1.0 +-- go.mod.postget -- +module example.net/m + +go 1.16 + +replace ( + example.net/w v0.1.0 => ./w1 + example.net/w v0.2.0-pre => ./w2-pre + example.net/x v0.1.0 => ./x1 + example.net/x v0.2.0-pre => ./x2-pre + example.net/y v0.1.0 => ./y1 + example.net/y v0.2.0-pre => ./y2-pre + example.net/z v0.1.0 => ./z1 + example.net/z v0.2.0-pre => ./z2-pre +) +-- w1/go.mod -- +module example.net/w + +go 1.16 + +require ( + example.net/y v0.2.0-pre + example.net/z v0.2.0-pre +) +-- w1/w.go -- +package w +-- w2-pre/go.mod -- +module example.net/w + +go 1.16 +-- w2-pre/README.txt -- +Package w has been removed. + +-- x1/go.mod -- +module example.net/x + +go 1.16 + +require ( + example.net/z v0.2.0-pre + example.net/w v0.2.0-pre +) +-- x1/x.go -- +package x +-- x2-pre/go.mod -- +module example.net/x + +go 1.16 +-- x2-pre/README.txt -- +Package x has been removed. + +-- y1/go.mod -- +module example.net/y + +go 1.16 + +require ( + example.net/w v0.2.0-pre + example.net/x v0.2.0-pre +) +-- y1/y.go -- +package y + +-- y2-pre/go.mod -- +module example.net/y + +go 1.16 +-- y2-pre/README.txt -- +Package y has been removed. + +-- z1/go.mod -- +module example.net/z + +go 1.16 + +require ( + example.net/x v0.2.0-pre + example.net/y v0.2.0-pre +) +-- z1/z.go -- +package z + +-- z2-pre/go.mod -- +module example.net/z + +go 1.16 +-- z2-pre/README.txt -- +Package z has been removed. diff --git a/src/cmd/go/testdata/script/mod_tidy_cycle.txt b/src/cmd/go/testdata/script/mod_tidy_cycle.txt new file mode 100644 index 0000000..e46f37d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_cycle.txt @@ -0,0 +1,75 @@ +# Regression test for https://golang.org/issue/34086: +# 'go mod tidy' produced different go.mod file from other +# subcommands when certain kinds of cycles were present +# in the build graph. + +env GO111MODULE=on + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +# If the go.mod file is already tidy, 'go mod graph' should not modify it. +go mod graph +cmp go.mod go.mod.orig + +-- go.mod -- +module root + +go 1.13 + +replace ( + a v0.1.0 => ./a1 + b v0.1.0 => ./b1 + b v0.2.0 => ./b2 + c v0.1.0 => ./c1 + c v0.2.0 => ./c2 +) + +require ( + a v0.1.0 + b v0.2.0 // indirect +) +-- main.go -- +package main + +import _ "a" + +func main() {} + +-- a1/go.mod -- +module a + +go 1.13 + +require b v0.1.0 +-- a1/a.go -- +package a + +import _ "c" +-- b1/go.mod -- +module b + +go 1.13 + +require c v0.1.0 +-- b2/go.mod -- +module b + +go 1.13 + +require c v0.2.0 +-- c1/go.mod -- +module c + +go 1.13 +-- c2/c.go -- +package c +-- c2/go.mod -- +module c + +go 1.13 + +require b v0.2.0 +-- c2/c.go -- +package c diff --git a/src/cmd/go/testdata/script/mod_tidy_downgrade_ambiguous.txt b/src/cmd/go/testdata/script/mod_tidy_downgrade_ambiguous.txt new file mode 100644 index 0000000..8b508c7 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_downgrade_ambiguous.txt @@ -0,0 +1,58 @@ +# Verifies golang.org/issue/47738. + +# In this test, the user has rewritten their imports to use rsc.io/quote/v3, +# but their go.mod still requires rsc.io/quote@v1.5.2, and they indirectly +# require rsc.io/quote@v1.5.1 but don't import anything from it. +go list -m -f '{{.Path}}@{{.Version}}{{if .Indirect}} indirect{{end}}' all +stdout '^rsc.io/quote@v1.5.2$' +! stdout 'rsc.io/quote/v3' +go list -e all +! stdout '^rsc.io/quote$' + +# 'go mod tidy' should preserve the requirement on rsc.io/quote but mark it +# indirect. This prevents a downgrade to v1.5.1, which could introduce +# an ambiguity. +go mod tidy +go list -m -f '{{.Path}}@{{.Version}}{{if .Indirect}} indirect{{end}}' all +stdout '^rsc.io/quote@v1.5.2 indirect$' +stdout '^rsc.io/quote/v3@v3.0.0$' + +-- go.mod -- +module use + +go 1.16 + +require ( + old-indirect v0.0.0 + rsc.io/quote v1.5.2 +) + +replace old-indirect v0.0.0 => ./old-indirect +-- go.sum -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.1/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +-- use.go -- +package use + +import ( + _ "old-indirect/empty" + + _ "rsc.io/quote/v3" +) +-- old-indirect/empty/empty.go -- +package empty +-- old-indirect/go.mod -- +module old-indirect + +go 1.16 + +require rsc.io/quote v1.5.1 +-- old-indirect/go.sum -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/src/cmd/go/testdata/script/mod_tidy_duplicates.txt b/src/cmd/go/testdata/script/mod_tidy_duplicates.txt new file mode 100644 index 0000000..d454c8d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_duplicates.txt @@ -0,0 +1,38 @@ +env GO111MODULE=on + +# Regression test for golang.org/issue/28456: +# 'go mod tidy' should not leave duplicate lines when re-writing the file. + +go mod tidy +cmp go.sum golden.sum + +-- go.mod -- +module use + +go 1.16 + +require rsc.io/quote v1.5.2 + +-- go.sum -- +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= +-- golden.sum -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= +-- main.go -- +package use + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_tidy_error.txt b/src/cmd/go/testdata/script/mod_tidy_error.txt new file mode 100644 index 0000000..fc6cd78 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_error.txt @@ -0,0 +1,39 @@ +env GO111MODULE=on + +# Regression test for golang.org/issue/27063: +# 'go mod tidy' and 'go mod vendor' should not hide loading errors. + +! go mod tidy +! stderr 'package nonexist is not in std' +stderr '^go: issue27063 imports\n\tnonexist.example.com: cannot find module providing package nonexist.example.com' +stderr '^go: issue27063 imports\n\tissue27063/other imports\n\tother.example.com/nonexist: cannot find module providing package other.example.com/nonexist' + +! go mod vendor +! stderr 'package nonexist is not in std' +stderr '^go: issue27063 imports\n\tnonexist.example.com: no required module provides package nonexist.example.com; to add it:\n\tgo get nonexist.example.com$' +stderr '^go: issue27063 imports\n\tissue27063/other imports\n\tother.example.com/nonexist: no required module provides package other.example.com/nonexist; to add it:\n\tgo get other.example.com/nonexist$' + +-- go.mod -- +module issue27063 + +go 1.13 + +require issue27063/other v0.0.0 +replace issue27063/other => ./other +-- x.go -- +package main + +import ( + "nonexist" + + "nonexist.example.com" + "issue27063/other" +) + +func main() {} +-- other/go.mod -- +module issue27063/other +-- other/other.go -- +package other + +import "other.example.com/nonexist" diff --git a/src/cmd/go/testdata/script/mod_tidy_indirect.txt b/src/cmd/go/testdata/script/mod_tidy_indirect.txt new file mode 100644 index 0000000..1f092b2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_indirect.txt @@ -0,0 +1,67 @@ +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +-- go.mod -- +module example.com/tidy + +go 1.16 + +require ( + example.net/incomplete v0.1.0 + example.net/indirect v0.2.0 // indirect + example.net/toolow v0.1.0 +) + +replace ( + example.net/incomplete v0.1.0 => ./incomplete + example.net/indirect v0.1.0 => ./indirect.1 + example.net/indirect v0.2.0 => ./indirect.2 + example.net/toolow v0.1.0 => ./toolow +) +-- tidy.go -- +package tidy + +import ( + _ "example.net/incomplete" + _ "example.net/toolow" +) + +-- incomplete/go.mod -- +module example.net/incomplete + +go 1.16 + +// This module omits a needed requirement on example.net/indirect. +-- incomplete/incomplete.go -- +package incomplete + +import _ "example.net/indirect/newpkg" + +-- toolow/go.mod -- +module example.net/toolow + +go 1.16 + +require example.net/indirect v0.1.0 +-- toolow/toolow.go -- +package toolow + +import _ "example.net/indirect/oldpkg" + +-- indirect.1/go.mod -- +module example.net/indirect + +go 1.16 +-- indirect.1/oldpkg/oldpkg.go -- +package oldpkg + + +-- indirect.2/go.mod -- +module example.net/indirect + +go 1.16 +-- indirect.2/oldpkg/oldpkg.go -- +package oldpkg +-- indirect.2/newpkg/newpkg.go -- +package newpkg diff --git a/src/cmd/go/testdata/script/mod_tidy_issue60313.txt b/src/cmd/go/testdata/script/mod_tidy_issue60313.txt new file mode 100644 index 0000000..6963994 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_issue60313.txt @@ -0,0 +1,69 @@ +# Regression test for https://go.dev/issue/60313: 'go mod tidy' did not preserve +# dependencies needed to prevent 'ambiguous import' errors in external test +# dependencies. + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +-- go.mod -- +module example + +go 1.21 + +require ( + example.net/a v0.1.0 + example.net/b v0.1.0 +) + +require example.net/outer/inner v0.1.0 // indirect + +replace ( + example.net/a v0.1.0 => ./a + example.net/b v0.1.0 => ./b + example.net/outer v0.1.0 => ./outer + example.net/outer/inner v0.1.0 => ./inner +) +-- example.go -- +package example + +import ( + _ "example.net/a" + _ "example.net/b" +) +-- a/go.mod -- +module example.net/a + +go 1.21 + +require example.net/outer/inner v0.1.0 +-- a/a.go -- +package a +-- a/a_test.go -- +package a_test + +import _ "example.net/outer/inner" +-- b/go.mod -- +module example.net/b + +go 1.21 + +require example.net/outer v0.1.0 +-- b/b.go -- +package b +-- b/b_test.go -- +package b_test + +import _ "example.net/outer/inner" +-- inner/go.mod -- +module example.net/outer/inner + +go 1.21 +-- inner/inner.go -- +package inner +-- outer/go.mod -- +module example.net/outer + +go 1.21 +-- outer/inner/inner.go -- +package inner diff --git a/src/cmd/go/testdata/script/mod_tidy_lazy_self.txt b/src/cmd/go/testdata/script/mod_tidy_lazy_self.txt new file mode 100644 index 0000000..9abbabd --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_lazy_self.txt @@ -0,0 +1,66 @@ +# Regression test for https://golang.org/issue/46078: +# 'go mod tidy' should not panic if the main module initially +# requires an older version of itself. + +# A module may require an older version of itself without error. This is +# inconsistent (the required version is never selected), but we still get +# a reproducible build list. +go list -m all +stdout '^golang.org/issue/46078$' + +# 'go mod tidy' should fix this (and not crash). +go mod tidy + + +# We prune out redundant roots very early on in module loading, and at that +# point the indirect requirement on example.net/x v0.1.0 appears to be +# irrelevant. It should be pruned out; when the import of "example.net/x" is +# later resolved, it should resolve at the latest version (v0.2.0), not the +# version implied by the (former) misleading requirement on the older version of +# the main module. + +cmp go.mod go.mod.tidy + + +-- go.mod -- +module golang.org/issue/46078 + +go 1.17 + +replace ( + example.net/x v0.1.0 => ./x + example.net/x v0.2.0 => ./x + golang.org/issue/46078 v0.1.0 => ./old +) + +require golang.org/issue/46078 v0.1.0 +-- go.mod.tidy -- +module golang.org/issue/46078 + +go 1.17 + +replace ( + example.net/x v0.1.0 => ./x + example.net/x v0.2.0 => ./x + golang.org/issue/46078 v0.1.0 => ./old +) + +require example.net/x v0.2.0 +-- issue46078/issue.go -- +package issue46078 + +import _ "example.net/x" + +-- old/go.mod -- +module golang.org/issue/46078 + +go 1.17 + +require example.net/x v0.1.0 + +-- x/go.mod -- +module example.net/x + +go 1.17 +-- x/x.go -- +package x diff --git a/src/cmd/go/testdata/script/mod_tidy_newroot.txt b/src/cmd/go/testdata/script/mod_tidy_newroot.txt new file mode 100644 index 0000000..3abd5ef --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_newroot.txt @@ -0,0 +1,82 @@ +# https://golang.org/issue/45952: 'go mod tidy' in an eager module failed due +# to an erroneous check on root completeness. +# +# Per the issue report: +# > It may have to do with: +# > +# > package A imports package B in go.mod, which imports package C in its own go.mod +# > package A drops direct dependency on package B … +# +# We infer from that that package C is still needed by some other indirect +# dependency, and must be at a higher version than what is required by that +# dependency (or else no new root would be needed). An additional package D +# in its own module satisfies that condition, reproducing the bug. + +go mod tidy +cmp go.mod go.mod.tidy + +-- go.mod -- +module example.net/a + +go 1.16 + +require ( + example.net/b v0.1.0 + example.net/d v0.1.0 +) + +replace ( + example.net/b v0.1.0 => ./b + example.net/c v0.1.0 => ./c + example.net/c v0.2.0 => ./c + example.net/d v0.1.0 => ./d +) +-- go.mod.tidy -- +module example.net/a + +go 1.16 + +require ( + example.net/c v0.2.0 // indirect + example.net/d v0.1.0 +) + +replace ( + example.net/b v0.1.0 => ./b + example.net/c v0.1.0 => ./c + example.net/c v0.2.0 => ./c + example.net/d v0.1.0 => ./d +) +-- a.go -- +package a + +import _ "example.net/d" + +-- b/go.mod -- +module example.net/b + +go 1.16 + +require example.net/c v0.2.0 +-- b/b.go -- +package b + +import _ "example.net/c" + +-- c/go.mod -- +module example.net/c + +go 1.16 +-- c/c.go -- +package c + +-- d/go.mod -- +module example.net/d + +go 1.16 + +require example.net/c v0.1.0 +-- d/d.go -- +package d + +import _ "example.net/c" diff --git a/src/cmd/go/testdata/script/mod_tidy_old.txt b/src/cmd/go/testdata/script/mod_tidy_old.txt new file mode 100644 index 0000000..7428f0c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_old.txt @@ -0,0 +1,46 @@ +# 'go mod tidy' should remove content sums for module versions that aren't +# in the build list. It should preserve go.mod sums for module versions that +# are in the module graph though. +# Verifies golang.org/issue/33008. +go mod tidy +! grep '^rsc.io/quote v1.5.0 h1:' go.sum +grep '^rsc.io/quote v1.5.0/go.mod h1:' go.sum + +-- go.mod -- +module m + +go 1.15 + +require ( + rsc.io/quote v1.5.2 + example.com/r v0.0.0 +) + +replace example.com/r => ./r + +-- go.sum -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.0 h1:6fJa6E+wGadANKkUMlZ0DhXFpoKlslOQDCo259XtdIE= +rsc.io/quote v1.5.0/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= + +-- r/go.mod -- +module example.com/r + +require rsc.io/quote v1.5.0 + +-- use.go -- +package use + +import _ "example.com/r" + +-- r/use.go -- +package use + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_tidy_oldgo.txt b/src/cmd/go/testdata/script/mod_tidy_oldgo.txt new file mode 100644 index 0000000..0e88b06 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_oldgo.txt @@ -0,0 +1,21 @@ +# Modules were introduced in Go 1.11, but for various reasons users may +# decide to declare a (much!) older go version in their go.mod file. +# Modules with very old versions should not be rejected, and should have +# the same module-graph semantics as in Go 1.11. + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +-- go.mod -- +module example.com/legacy/go1 + +go 1.0 + +require golang.org/x/text v0.3.0 +-- main.go -- +package main + +import _ "golang.org/x/text/language" + +func main() {} diff --git a/src/cmd/go/testdata/script/mod_tidy_quote.txt b/src/cmd/go/testdata/script/mod_tidy_quote.txt new file mode 100644 index 0000000..423c7c2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_quote.txt @@ -0,0 +1,26 @@ +# Check that mod tidy does not introduce repeated +# require statements when input go.mod has quoted requirements. +env GO111MODULE=on + +go mod tidy +grep -count=1 rsc.io/quote go.mod + +cp go.mod2 go.mod +go mod tidy +grep -count=1 rsc.io/quote go.mod + + +-- go.mod -- +module x + +-- x.go -- +package x +import "rsc.io/quote" +func main() { _ = quote.Hello } + +-- go.mod2 -- +module x +require ( + "rsc.io/sampler" v1.3.0 + "rsc.io/quote" v1.5.2 +) diff --git a/src/cmd/go/testdata/script/mod_tidy_replace.txt b/src/cmd/go/testdata/script/mod_tidy_replace.txt new file mode 100644 index 0000000..274f3bf --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_replace.txt @@ -0,0 +1,145 @@ +env GO111MODULE=on +env GOFLAGS=-mod=mod +[short] skip + +# golang.org/issue/30166: 'go mod tidy' should not crash if a replaced module is +# involved in a cycle. +cd cycle +env GOTRACEBACK=off +go mod tidy +cd .. + +# From inside the module, 'go list -m all' should NOT include transitive +# requirements of modules that have been replaced. +go list -m all +stdout 'rsc.io/quote/v3 v3.0.0' +! stdout 'rsc.io/sampler' +! stdout 'golang.org/x/text' + +# From outside the module, 'go list -m all' should include them. +cd outside +go list -m all +stdout 'rsc.io/quote/v3 v3.0.0' +stdout 'rsc.io/sampler v1.3.0' +stdout 'golang.org/x/text' +cd .. + +# 'go list all' should add indirect requirements to satisfy the packages +# imported from replacement modules. +! grep 'rsc.io/sampler' go.mod +! grep 'golang.org/x/text' go.mod +go list all +grep 'rsc.io/sampler' go.mod +grep 'golang.org/x/text' go.mod + +# 'go get' and 'go mod tidy' should follow the requirements of the replacements, +# not the originals, even if that results in a set of versions that are +# misleading or redundant without those replacements. +go get rsc.io/sampler@v1.2.0 +go mod tidy +go list -m all +stdout 'rsc.io/quote/v3 v3.0.0' +stdout 'rsc.io/sampler v1.2.0' +stdout 'golang.org/x/text' + +# The requirements seen from outside may be higher (or lower) +# than those seen from within the module. +grep 'rsc.io/sampler v1.2.0' go.mod +cd outside +go list -m all +stdout 'rsc.io/sampler v1.3.0' +cd .. + +# The same module can't be used as two different paths. +cd multiple-paths +! go mod tidy +stderr 'rsc.io/quote/v3@v3.0.0 used for two different module paths \(not-rsc.io/quote/v3 and rsc.io/quote/v3\)' + +-- go.mod -- +module example.com/tidy + +require rsc.io/quote/v3 v3.0.0 +replace rsc.io/quote/v3 => ./not-rsc.io/quote/v3 + +-- imports.go -- +package tidy + +import _ "rsc.io/quote/v3" + +-- outside/go.mod -- +module example.com/tidy/outside + +require example.com/tidy v0.0.0 +replace example.com/tidy => ./.. + +-- not-rsc.io/quote/v3/go.mod -- +module not-rsc.io/quote/v3 + +// No requirements specified! + +-- not-rsc.io/quote/v3/quote.go -- +package quote + +import ( + _ "rsc.io/sampler" + _ "golang.org/x/text/language" +) + +-- cycle/go.mod -- +module golang.org/issue/30166 + +require ( + golang.org/issue/30166/a v0.0.0 + golang.org/issue/30166/b v0.0.0 +) + +replace ( + golang.org/issue/30166/a => ./a + golang.org/issue/30166/b => ./b +) +-- cycle/cycle.go -- +package cycle + +import ( + _ "golang.org/issue/30166/a" + _ "golang.org/issue/30166/b" +) +-- cycle/a/a.go -- +package a +-- cycle/a/go.mod -- +module golang.org/issue/30166/a + +require golang.org/issue/30166/b v0.0.0 +-- cycle/b/b.go -- +package b +-- cycle/b/go.mod -- +module golang.org/issue/30166/b + +require golang.org/issue/30166/a v0.0.0 +-- multiple-paths/main.go -- +package main + +import ( + "fmt" + "rsc.io/quote/v3" +) + +func main() { + fmt.Println(quote.GoV3()) +} +-- multiple-paths/go.mod -- +module quoter + +require ( + rsc.io/quote/v3 v3.0.0 + not-rsc.io/quote/v3 v3.0.0 +) + +replace not-rsc.io/quote/v3 => rsc.io/quote/v3 v3.0.0 +-- multiple-paths/use.go -- +package quoter + +import ( + _ "not-rsc.io/quote/v3" + _ "rsc.io/quote/v3" +) diff --git a/src/cmd/go/testdata/script/mod_tidy_replace_old.txt b/src/cmd/go/testdata/script/mod_tidy_replace_old.txt new file mode 100644 index 0000000..18605b1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_replace_old.txt @@ -0,0 +1,34 @@ +# Regression test for https://golang.org/issue/46659. +# +# If a 'replace' directive specifies an older-than-selected version of a module, +# 'go mod tidy' shouldn't try to add that version to the build list to resolve a +# missing package: it won't be selected, and would cause the module loader to +# loop indefinitely trying to resolve the package. + +cp go.mod go.mod.orig + +! go mod tidy +! stderr panic +stderr '^go: golang\.org/issue46659 imports\n\texample\.com/missingpkg/deprecated: package example\.com/missingpkg/deprecated provided by example\.com/missingpkg at latest version v1\.0\.0 but not at required version v1\.0\.1-beta$' + +go mod tidy -e + +cmp go.mod go.mod.orig + +-- go.mod -- +module golang.org/issue46659 + +go 1.17 + +replace example.com/missingpkg v1.0.1-alpha => example.com/missingpkg v1.0.0 + +require example.com/usemissingpre v1.0.0 + +require example.com/missingpkg v1.0.1-beta // indirect +-- m.go -- +package m + +import ( + _ "example.com/missingpkg/deprecated" + _ "example.com/usemissingpre" +) diff --git a/src/cmd/go/testdata/script/mod_tidy_sum.txt b/src/cmd/go/testdata/script/mod_tidy_sum.txt new file mode 100644 index 0000000..5a15818 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_sum.txt @@ -0,0 +1,33 @@ +env GO111MODULE=on + +# go.sum should list directly used modules and dependencies +go get rsc.io/quote@v1.5.2 +go mod tidy +grep rsc.io/sampler go.sum + +# go.sum should not normally lose old entries +go get rsc.io/quote@v1.0.0 +grep 'rsc.io/quote v1.0.0' go.sum +grep 'rsc.io/quote v1.5.2' go.sum +grep rsc.io/sampler go.sum + +# go mod tidy should clear dead entries from go.sum +go mod tidy +grep 'rsc.io/quote v1.0.0' go.sum +! grep 'rsc.io/quote v1.5.2' go.sum +! grep rsc.io/sampler go.sum + +# go.sum with no entries is OK to keep +# (better for version control not to delete and recreate.) +cp x.go.noimports x.go +go mod tidy +exists go.sum +! grep . go.sum + +-- go.mod -- +module x +-- x.go -- +package x +import _ "rsc.io/quote" +-- x.go.noimports -- +package x diff --git a/src/cmd/go/testdata/script/mod_tidy_support_buildx.txt b/src/cmd/go/testdata/script/mod_tidy_support_buildx.txt new file mode 100644 index 0000000..d2135e1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_support_buildx.txt @@ -0,0 +1,18 @@ +# This test checks that "go mod tidy -x" print +# commands tidy executes. +# Verifies golang.org/issue/35849 + +rm $GOPATH/pkg/mod/cache/download/rsc.io/quote +go mod tidy +! stderr 'get '$GOPROXY + +rm $GOPATH/pkg/mod/cache/download/rsc.io/quote +go mod tidy -x +stderr 'get '$GOPROXY + +-- go.mod -- +module example.com/mod + +-- a.go -- +package mod +import _ "rsc.io/quote"
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/mod_tidy_symlink_issue35941.txt b/src/cmd/go/testdata/script/mod_tidy_symlink_issue35941.txt new file mode 100644 index 0000000..d4658c6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_symlink_issue35941.txt @@ -0,0 +1,36 @@ +env GO111MODULE=on +[!symlink] skip + +cd m +symlink symlink -> ../outside + +cp go.mod go.mod.orig + +# Issue 35941: suppress symlink warnings when running 'go mod tidy'. +# 'go mod tidy' should not scan packages in symlinked subdirectories. +go mod tidy +! stderr 'warning: ignoring symlink' +cmp go.mod go.mod.orig + +! go build ./symlink +stderr '^symlink[\\/]symlink.go:3:8: module example.net/unresolved provides package example.net/unresolved and is replaced but not required; to add it:\n\tgo get example.net/unresolved@v0.1.0$' + +-- m/go.mod -- +module example.net/m + +go 1.16 + +replace example.net/unresolved v0.1.0 => ../unresolved +-- m/a.go -- +package a +-- outside/symlink.go -- +package symlink + +import _ "example.net/unresolved" +-- unresolved/go.mod -- +module example.net/unresolved + +go 1.16 +-- unresolved/unresolved.go -- +// Package unresolved exists, but 'go mod tidy' won't add it. +package unresolved diff --git a/src/cmd/go/testdata/script/mod_tidy_temp.txt b/src/cmd/go/testdata/script/mod_tidy_temp.txt new file mode 100644 index 0000000..8a2fa4e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_temp.txt @@ -0,0 +1,26 @@ +# Regression test for https://go.dev/issue/51992 + +# 'go mod tidy' should error instead of throwing panic in the situation below. +# 1. /tmp/go.mod exists +# 2. run 'go mod tidy' in /tmp or in the child directory not having go.mod. + +[GOOS:plan9] stop # Plan 9 has no $TMPDIR variable to set. + +env GOROOT=$TESTGO_GOROOT +env TMP=$WORK +env TMPDIR=$WORK +mkdir $WORK/child + +! go mod tidy +! stdout . +stderr 'go: go.mod file not found in current directory or any parent directory' + +cd $WORK/child +! go mod tidy +! stdout . +stderr 'go: go.mod file not found in current directory or any parent directory' + +-- $WORK/go.mod -- +module issue51992 + +go 1.18 diff --git a/src/cmd/go/testdata/script/mod_tidy_version.txt b/src/cmd/go/testdata/script/mod_tidy_version.txt new file mode 100644 index 0000000..e3f2561 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_version.txt @@ -0,0 +1,394 @@ +# https://golang.org/issue/45094: 'go mod tidy' now accepts a '-go' flag +# to change the language version in use. +# +# The package import graph used in this test looks like: +# +# m --- a --- b +# | +# b_test --- c +# | +# c_test --- d +# +# The module diagram looks like: +# +# m --- a --- b +# | +# + --- c +# | +# + --- d +# +# Module b omits its dependency on c, and module c omits its dependency on d. +# +# In go 1.15, the tidy main module must require a (because it is direct), +# c (because it is a missing test dependency of an imported package), +# and d (because it is a missing transitive test dependency). +# +# In go 1.16, the tidy main module can omit d because it is no longer +# included in "all". +# +# In go 1.17, the main module must explicitly require b +# (because it is transitively imported by the main module). + +cp go.mod go.mod.orig + + # Pretend we're a release version so that we can theoretically + # write our version in toolchain lines. +env goversion=1.99.0 +env TESTGO_VERSION=go${goversion} + +# An invalid argument should be rejected. + +! go mod tidy -go=bananas +stderr '^invalid value "bananas" for flag -go: expecting a Go version like "'$goversion'"$' +cmp go.mod go.mod.orig + +! go mod tidy -go=0.9 +stderr '^invalid value "0.9" for flag -go: expecting a Go version like "'$goversion'"$' + +! go mod tidy -go=2000.0 +stderr '^invalid value "2000.0" for flag -go: maximum supported Go version is '$goversion'$' + + +# Supported versions should change the go.mod file to be tidy according to the +# indicated version. + +go mod tidy -go=1.15 +cmp go.mod go.mod.115 + +go mod tidy +cmp go.mod go.mod.115 + + +go mod tidy -go=1.16 +cmp go.mod go.mod.116 + +go mod tidy +cmp go.mod go.mod.116 + + +go mod tidy -go=1.17 +cmp go.mod go.mod.117 + +go mod tidy +cmp go.mod go.mod.117 + + +# If we downgrade back to 1.15, we should re-resolve d to v0.2.0 instead +# of the original v0.1.0 (because the original requirement is lost). + +go mod tidy -go=1.15 +cmp go.mod go.mod.115-2 + + +# -go= (with an empty argument) maintains the existing version or adds the +# default version (just like omitting the flag). + +go mod tidy -go='' +cmp go.mod go.mod.115-2 + +cp go.mod.orig go.mod +go mod tidy -go='' +cmpenv go.mod go.mod.latest + +# Repeat with go get go@ instead of mod tidy. + +# Go 1.16 -> 1.17 should be a no-op. +cp go.mod.116 go.mod +go get go@1.16 +cmp go.mod go.mod.116 + +# Go 1.17 -> 1.16 should leave b (go get is not tidy). +cp go.mod.117 go.mod +go get go@1.16 +cmp go.mod go.mod.116from117 + +# Go 1.15 -> 1.16 should leave d (go get is not tidy). +cp go.mod.115 go.mod +go get go@1.16 +cmp go.mod go.mod.116from115 + +# Go 1.16 -> 1.17 should add b. +cp go.mod.116 go.mod +go get go@1.17 +stderr '^\tnote: expanded dependencies to upgrade to go 1.17 or higher; run ''go mod tidy'' to clean up' +cmp go.mod go.mod.117 + +# Go 1.16 -> 1.15 should add d, +# but 'go get' doesn't load enough packages to know that. +# (This leaves the module untidy, but the user can fix it by running 'go mod tidy'.) +cp go.mod.116 go.mod +go get go@1.15 toolchain@none +cmp go.mod go.mod.115from116 +go mod tidy +cmp go.mod go.mod.115-2 + +# Updating the go line to 1.21 or higher also updates the toolchain line, +# only if the toolchain is higher than what would be implied by the go line. + +cp go.mod.117 go.mod +go mod tidy -go=$goversion +cmpenv go.mod go.mod.latest + +cp go.mod.117 go.mod +go mod tidy -go=1.21.0 # lower than $goversion +cmpenv go.mod go.mod.121toolchain + + +-- go.mod -- +module example.com/m + +require example.net/a v0.1.0 + +require ( + example.net/c v0.1.0 // indirect + example.net/d v0.1.0 // indirect +) + +replace ( + example.net/a v0.1.0 => ./a + example.net/a v0.2.0 => ./a + example.net/b v0.1.0 => ./b + example.net/b v0.2.0 => ./b + example.net/c v0.1.0 => ./c + example.net/c v0.2.0 => ./c + example.net/d v0.1.0 => ./d + example.net/d v0.2.0 => ./d +) +-- m.go -- +package m + +import _ "example.net/a" + +-- go.mod.115 -- +module example.com/m + +go 1.15 + +require example.net/a v0.1.0 + +require ( + example.net/c v0.1.0 // indirect + example.net/d v0.1.0 // indirect +) + +replace ( + example.net/a v0.1.0 => ./a + example.net/a v0.2.0 => ./a + example.net/b v0.1.0 => ./b + example.net/b v0.2.0 => ./b + example.net/c v0.1.0 => ./c + example.net/c v0.2.0 => ./c + example.net/d v0.1.0 => ./d + example.net/d v0.2.0 => ./d +) +-- go.mod.115from116 -- +module example.com/m + +go 1.15 + +require example.net/a v0.1.0 + +require example.net/c v0.1.0 // indirect + +replace ( + example.net/a v0.1.0 => ./a + example.net/a v0.2.0 => ./a + example.net/b v0.1.0 => ./b + example.net/b v0.2.0 => ./b + example.net/c v0.1.0 => ./c + example.net/c v0.2.0 => ./c + example.net/d v0.1.0 => ./d + example.net/d v0.2.0 => ./d +) +-- go.mod.116from115 -- +module example.com/m + +go 1.16 + +require example.net/a v0.1.0 + +require ( + example.net/c v0.1.0 // indirect + example.net/d v0.1.0 // indirect +) + +replace ( + example.net/a v0.1.0 => ./a + example.net/a v0.2.0 => ./a + example.net/b v0.1.0 => ./b + example.net/b v0.2.0 => ./b + example.net/c v0.1.0 => ./c + example.net/c v0.2.0 => ./c + example.net/d v0.1.0 => ./d + example.net/d v0.2.0 => ./d +) +-- go.mod.115-2 -- +module example.com/m + +go 1.15 + +require example.net/a v0.1.0 + +require ( + example.net/c v0.1.0 // indirect + example.net/d v0.2.0 // indirect +) + +replace ( + example.net/a v0.1.0 => ./a + example.net/a v0.2.0 => ./a + example.net/b v0.1.0 => ./b + example.net/b v0.2.0 => ./b + example.net/c v0.1.0 => ./c + example.net/c v0.2.0 => ./c + example.net/d v0.1.0 => ./d + example.net/d v0.2.0 => ./d +) +-- go.mod.116 -- +module example.com/m + +go 1.16 + +require example.net/a v0.1.0 + +require example.net/c v0.1.0 // indirect + +replace ( + example.net/a v0.1.0 => ./a + example.net/a v0.2.0 => ./a + example.net/b v0.1.0 => ./b + example.net/b v0.2.0 => ./b + example.net/c v0.1.0 => ./c + example.net/c v0.2.0 => ./c + example.net/d v0.1.0 => ./d + example.net/d v0.2.0 => ./d +) +-- go.mod.117 -- +module example.com/m + +go 1.17 + +require example.net/a v0.1.0 + +require ( + example.net/b v0.1.0 // indirect + example.net/c v0.1.0 // indirect +) + +replace ( + example.net/a v0.1.0 => ./a + example.net/a v0.2.0 => ./a + example.net/b v0.1.0 => ./b + example.net/b v0.2.0 => ./b + example.net/c v0.1.0 => ./c + example.net/c v0.2.0 => ./c + example.net/d v0.1.0 => ./d + example.net/d v0.2.0 => ./d +) +-- go.mod.116from117 -- +module example.com/m + +go 1.16 + +require example.net/a v0.1.0 + +require ( + example.net/b v0.1.0 // indirect + example.net/c v0.1.0 // indirect +) + +replace ( + example.net/a v0.1.0 => ./a + example.net/a v0.2.0 => ./a + example.net/b v0.1.0 => ./b + example.net/b v0.2.0 => ./b + example.net/c v0.1.0 => ./c + example.net/c v0.2.0 => ./c + example.net/d v0.1.0 => ./d + example.net/d v0.2.0 => ./d +) +-- go.mod.latest -- +module example.com/m + +go $goversion + +require example.net/a v0.1.0 + +require ( + example.net/b v0.1.0 // indirect + example.net/c v0.1.0 // indirect +) + +replace ( + example.net/a v0.1.0 => ./a + example.net/a v0.2.0 => ./a + example.net/b v0.1.0 => ./b + example.net/b v0.2.0 => ./b + example.net/c v0.1.0 => ./c + example.net/c v0.2.0 => ./c + example.net/d v0.1.0 => ./d + example.net/d v0.2.0 => ./d +) +-- go.mod.121toolchain -- +module example.com/m + +go 1.21.0 + +toolchain $TESTGO_VERSION + +require example.net/a v0.1.0 + +require ( + example.net/b v0.1.0 // indirect + example.net/c v0.1.0 // indirect +) + +replace ( + example.net/a v0.1.0 => ./a + example.net/a v0.2.0 => ./a + example.net/b v0.1.0 => ./b + example.net/b v0.2.0 => ./b + example.net/c v0.1.0 => ./c + example.net/c v0.2.0 => ./c + example.net/d v0.1.0 => ./d + example.net/d v0.2.0 => ./d +) +-- a/go.mod -- +module example.net/a + +go 1.15 + +require example.net/b v0.1.0 +-- a/a.go -- +package a + +import _ "example.net/b" + +-- b/go.mod -- +module example.net/b + +go 1.15 +-- b/b.go -- +package b +-- b/b_test.go -- +package b_test + +import _ "example.net/c" + +-- c/go.mod -- +module example.net/c + +go 1.15 +-- c/c.go -- +package c +-- c/c_test.go -- +package c_test + +import _ "example.net/d" + +-- d/go.mod -- +module example.net/d + +go 1.15 +-- d/d.go -- +package d diff --git a/src/cmd/go/testdata/script/mod_tidy_version_tooold.txt b/src/cmd/go/testdata/script/mod_tidy_version_tooold.txt new file mode 100644 index 0000000..713ef1a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_version_tooold.txt @@ -0,0 +1,23 @@ +env TESTGO_VERSION=go1.22.0 + +! go mod tidy -go=1.21 +stderr '^go: example.net/a@v0.1.0 requires go@1.22, but 1.21 is requested$' + +-- go.mod -- +module example + +go 1.22 + +require example.net/a v0.1.0 + +replace example.net/a v0.1.0 => ./a +-- example.go -- +package example + +import "example.net/a" +-- a/go.mod -- +module example.net/a + +go 1.22 +-- a/a.go -- +package a diff --git a/src/cmd/go/testdata/script/mod_toolchain.txt b/src/cmd/go/testdata/script/mod_toolchain.txt new file mode 100644 index 0000000..c771cae --- /dev/null +++ b/src/cmd/go/testdata/script/mod_toolchain.txt @@ -0,0 +1,76 @@ +env TESTGO_VERSION=go1.100.0 +env TESTGO_VERSION_SWITCH=switch + +go get toolchain@go1.22.1 +stderr '^go: added toolchain go1.22.1$' +! stderr '(added|removed|upgraded|downgraded) go' +grep 'toolchain go1.22.1' go.mod + +go get toolchain@none +stderr '^go: removed toolchain go1.22.1$' +! stderr '(added|removed|upgraded|downgraded) go' +! grep toolchain go.mod + +go get toolchain@go1.22.1 +stderr '^go: added toolchain go1.22.1$' +! stderr '(added|removed|upgraded|downgraded) go' +grep 'toolchain go1.22.1' go.mod + +go get go@1.22.3 +stderr '^go: upgraded go 1.10 => 1.22.3$' +stderr '^go: upgraded toolchain go1.22.1 => go1.100.0$' +grep 'go 1.22.3' go.mod + +go get go@1.22.3 toolchain@1.22.3 +stderr '^go: removed toolchain go1.100.0$' +! grep toolchain go.mod + +go get go@1.22.1 toolchain@go1.22.3 +stderr '^go: downgraded go 1.22.3 => 1.22.1$' +stderr '^go: added toolchain go1.22.3$' +grep 'go 1.22.1' go.mod +grep 'toolchain go1.22.3' go.mod + +go get go@1.22.3 toolchain@1.22.3 +stderr '^go: upgraded go 1.22.1 => 1.22.3$' +stderr '^go: removed toolchain go1.22.3$' +grep 'go 1.22.3' go.mod +! grep toolchain go.mod + +go get toolchain@1.22.1 +stderr '^go: downgraded go 1.22.3 => 1.22.1$' +! stderr toolchain # already gone, was not added +grep 'go 1.22.1' go.mod +! grep toolchain go.mod + +env TESTGO_VERSION=go1.22.1 +env GOTOOLCHAIN=local +! go get go@1.22.3 +stderr 'go: updating go.mod requires go >= 1.22.3 \(running go 1.22.1; GOTOOLCHAIN=local\)$' + +env TESTGO_VERSION=go1.30 +go get toolchain@1.22.3 +grep 'toolchain go1.22.3' go.mod + +go get go@1.22.1 +grep 'go 1.22.1' go.mod +go get m2@v1.0.0 +stderr '^go: upgraded go 1.22.1 => 1.23$' +stderr '^go: added m2 v1.0.0$' +grep 'go 1.23$' go.mod + +go get toolchain@go1.23.9 go@1.23.5 +go get toolchain@none +stderr '^go: removed toolchain go1.23.9' +! stderr ' go 1' +grep 'go 1.23.5' go.mod + +-- go.mod -- +module m +go 1.10 + +replace m2 v1.0.0 => ./m2 + +-- m2/go.mod -- +module m2 +go 1.23 diff --git a/src/cmd/go/testdata/script/mod_toolchain_slash.txt b/src/cmd/go/testdata/script/mod_toolchain_slash.txt new file mode 100644 index 0000000..bb1f770 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_toolchain_slash.txt @@ -0,0 +1,32 @@ +[!exec:/bin/sh] skip + +chmod 0777 go1.999999-/run.sh +chmod 0777 run.sh + +! go list all +! stdout 'RAN SCRIPT' + +cd subdir +! go list all +! stdout 'RAN SCRIPT' + +-- go.mod -- +module exploit + +go 1.21 +toolchain go1.999999-/run.sh +-- go1.999999-/run.sh -- +#!/bin/sh +printf 'RAN SCRIPT\n' +exit 1 +-- run.sh -- +#!/bin/sh +printf 'RAN SCRIPT\n' +exit 1 +-- subdir/go.mod -- +module exploit + +go 1.21 +toolchain go1.999999-/../../run.sh +-- subdir/go1.999999-/README.txt -- +heh heh heh diff --git a/src/cmd/go/testdata/script/mod_update_sum_readonly.txt b/src/cmd/go/testdata/script/mod_update_sum_readonly.txt new file mode 100644 index 0000000..41f12e4 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_update_sum_readonly.txt @@ -0,0 +1,34 @@ +# When finding the latest version of a module, we should not download version +# contents. Previously, we downloaded .zip files to determine whether a real +# .mod file was present in order to decide whether +incompatible versions +# could be "latest". +# +# Verifies #47377. + +# rsc.io/breaker has two versions, neither of which has a .mod file. +go list -m -versions rsc.io/breaker +stdout '^rsc.io/breaker v1.0.0 v2.0.0\+incompatible$' +go mod download rsc.io/breaker@v1.0.0 +! grep '^go' $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v1.0.0.mod +go mod download rsc.io/breaker@v2.0.0+incompatible +! grep '^go' $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v2.0.0+incompatible.mod + +# Delete downloaded .zip files. +go clean -modcache + +# Check for updates. +go list -m -u rsc.io/breaker +stdout '^rsc.io/breaker v1.0.0 \[v2.0.0\+incompatible\]$' + +# We should not have downloaded zips. +! exists $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v1.0.0.zip +! exists $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v2.0.0+incompatible.zip + +-- go.mod -- +module m + +go 1.16 + +require rsc.io/breaker v1.0.0 +-- go.sum -- +rsc.io/breaker v1.0.0/go.mod h1:s5yxDXvD88U1/ESC23I2FK3Lkv4YIKaB1ij/Hbm805g= diff --git a/src/cmd/go/testdata/script/mod_upgrade_patch.txt b/src/cmd/go/testdata/script/mod_upgrade_patch.txt new file mode 100644 index 0000000..79a9808 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_upgrade_patch.txt @@ -0,0 +1,110 @@ +env GO111MODULE=on +[short] skip + +# Initially, we are at v1.0.0 for all dependencies. +go get +cp go.mod go.mod.orig +go list -m all +stdout '^patch.example.com/direct v1.0.0' +stdout '^patch.example.com/indirect v1.0.0' +! stdout '^patch.example.com/depofdirectpatch' + +# @patch should be rejected for modules not already in the build list. +! go get patch.example.com/depofdirectpatch@patch +stderr '^go: can''t query version "patch" of module patch.example.com/depofdirectpatch: no existing version is required$' +cmp go.mod.orig go.mod + +# get -u=patch, with no arguments, should patch-update all dependencies +# of the package in the current directory, pulling in transitive dependencies +# and also patching those. +cp go.mod.orig go.mod +go get -u=patch +go list -m all +stdout '^patch.example.com/direct v1.0.1' +stdout '^patch.example.com/indirect v1.0.1' +stdout '^patch.example.com/depofdirectpatch v1.0.0' + +# 'get all@patch' should patch the modules that provide packages in 'all'. +cp go.mod.orig go.mod +go get all@patch +go list -m all +stdout '^patch.example.com/direct v1.0.1' +stdout '^patch.example.com/indirect v1.0.1' +stdout '^patch.example.com/depofdirectpatch v1.0.0' + +# ...but 'all@patch' should fail if any of the affected modules do not already +# have a selected version. +cp go.mod.orig go.mod +go mod edit -droprequire=patch.example.com/direct +cp go.mod go.mod.dropped +! go get all@patch +stderr '^go: all@patch: can''t query version "patch" of module patch.example.com/direct: no existing version is required$' +cmp go.mod.dropped go.mod + +# Requesting the direct dependency with -u=patch but without an explicit version +# should patch-update it and its dependencies. +cp go.mod.orig go.mod +go get -u=patch patch.example.com/direct +go list -m all +stdout '^patch.example.com/direct v1.0.1' +stdout '^patch.example.com/indirect v1.0.1' +stdout '^patch.example.com/depofdirectpatch v1.0.0' + +# Requesting only the indirect dependency should not update the direct one. +cp go.mod.orig go.mod +go get -u=patch patch.example.com/indirect +go list -m all +stdout '^patch.example.com/direct v1.0.0' +stdout '^patch.example.com/indirect v1.0.1' +! stdout '^patch.example.com/depofdirectpatch' + +# @patch should apply only to the specific module, +# but the result must reflect its upgraded requirements. +cp go.mod.orig go.mod +go get patch.example.com/direct@patch +go list -m all +stdout '^patch.example.com/direct v1.0.1' +stdout '^patch.example.com/indirect v1.0.0' +stdout '^patch.example.com/depofdirectpatch v1.0.0' + +# An explicit @patch should override a general -u. +cp go.mod.orig go.mod +go get -u patch.example.com/direct@patch +go list -m all +stdout '^patch.example.com/direct v1.0.1' +stdout '^patch.example.com/indirect v1.1.0' +stdout '^patch.example.com/depofdirectpatch v1.0.0' + +# An explicit @latest should override a general -u=patch. +cp go.mod.orig go.mod +go get -u=patch patch.example.com/direct@latest +go list -m all +stdout '^patch.example.com/direct v1.1.0' +stdout '^patch.example.com/indirect v1.0.1' +! stdout '^patch.example.com/depofdirectpatch' + +# Standard library packages cannot be upgraded explicitly. +cp go.mod.orig go.mod +! go get cmd/vet@patch +stderr 'go: can''t request explicit version "patch" of standard library package cmd/vet$' + +# However, standard-library packages without explicit versions are fine. +go get -u=patch cmd/go + +# We can upgrade to a new version of a module with no root package. +go get example.com/noroot@v1.0.0 +go list -m all +stdout '^example.com/noroot v1.0.0$' +go get example.com/noroot@patch +go list -m all +stdout '^example.com/noroot v1.0.1$' + + +-- go.mod -- +module x + +require patch.example.com/direct v1.0.0 + +-- main.go -- +package x +import _ "patch.example.com/direct" diff --git a/src/cmd/go/testdata/script/mod_vcs_missing.txt b/src/cmd/go/testdata/script/mod_vcs_missing.txt new file mode 100644 index 0000000..7f63e9d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vcs_missing.txt @@ -0,0 +1,28 @@ +[exec:bzr] skip 'tests NOT having bzr' +[!net:launchpad.net] skip + +env GO111MODULE=on +env GOPROXY=direct + +cd empty +! go get launchpad.net/gocheck +stderr '"bzr": executable file not found' +cd .. + +# 1.11 used to give the cryptic error "cannot find module for path" here, but +# only for a main package. +cd main +! go build -mod=mod +stderr '"bzr": executable file not found' +cd .. + +-- empty/go.mod -- +module m +-- main/go.mod -- +module m +-- main/main.go -- +package main + +import _ "launchpad.net/gocheck" + +func main() {} diff --git a/src/cmd/go/testdata/script/mod_vendor.txt b/src/cmd/go/testdata/script/mod_vendor.txt new file mode 100644 index 0000000..b02341d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor.txt @@ -0,0 +1,354 @@ +env GO111MODULE=on + +# Without vendoring, a build should succeed unless -mod=vendor is set. +[!short] go build +[!short] ! go build -mod=vendor + +# Without vendoring, 'go list' should report the replacement directory for +# a package in a replaced module. +go list -f {{.Dir}} x +stdout 'src[\\/]x' + +# 'go mod vendor' should copy all replaced modules to the vendor directory. +go mod vendor -v +stderr '^# x v1.0.0 => ./x' +stderr '^x' +stderr '^# y v1.0.0 => ./y' +stderr '^y' +stderr '^# z v1.0.0 => ./z' +stderr '^z' +! stderr '^w' +grep 'a/foo/bar/b\na/foo/bar/c' vendor/modules.txt # must be sorted + +# An explicit '-mod=mod' should ignore the vendor directory. +go list -mod=mod -f {{.Dir}} x +stdout 'src[\\/]x' + +go list -mod=mod -f {{.Dir}} -m x +stdout 'src[\\/]x' + +# An explicit '-mod=vendor' should report package directories within +# the vendor directory. +go list -mod=vendor -f {{.Dir}} x +stdout 'src[\\/]vendor[\\/]x' + +# 'go list -mod=vendor -m' should successfully list vendored modules, +# but should not provide a module directory because no directory contains +# the complete module. +go list -mod=vendor -f '{{.Version}} {{.Dir}}' -m x +stdout '^v1.0.0 $' + +# -mod=vendor should cause 'go list' flags that look up versions to fail. +! go list -mod=vendor -versions -m x +stderr '^go: can''t determine available versions using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)$' +! go list -mod=vendor -u -m x +stderr '^go: can''t determine available upgrades using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)$' + +# 'go list -mod=vendor -m' on a transitive dependency that does not +# provide vendored packages should give a helpful error rather than +# 'not a known dependency'. +! go list -mod=vendor -f '{{.Version}} {{.Dir}}' -m diamondright +stderr 'go: module diamondright: can''t resolve module using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)' + +# 'go list -mod=mod' should report packages outside the import graph, +# but 'go list -mod=vendor' should error out for them. +go list -mod=mod -f {{.Dir}} w +stdout 'src[\\/]w' +! go list -mod=vendor -f {{.Dir}} w +stderr 'package w is not in std' + +go list -mod=mod -f {{.Dir}} diamondright +stdout 'src[\\/]diamondright' + +# Test dependencies should not be copied. +! exists vendor/x/testdata +! exists vendor/a/foo/bar/b/ignored.go +! exists vendor/a/foo/bar/b/main_test.go + +# Licenses and other metadata for each module should be copied +# if any package within their module is copied. +exists vendor/a/foo/AUTHORS.txt +exists vendor/a/foo/CONTRIBUTORS +exists vendor/a/foo/LICENSE +exists vendor/a/foo/PATENTS +exists vendor/a/foo/COPYING +exists vendor/a/foo/COPYLEFT +exists vendor/x/NOTICE! +exists vendor/mysite/myname/mypkg/LICENSE.txt + +! exists vendor/a/foo/licensed-to-kill +! exists vendor/w +! exists vendor/w/LICENSE +! exists vendor/x/x2 +! exists vendor/x/x2/LICENSE + +# 'go mod vendor' should work with an alternative vendor directory if the -o flag is provided. +go mod vendor -v -o alternative-vendor-dir +exists alternative-vendor-dir/modules.txt +exists alternative-vendor-dir/a/foo/LICENSE + +# 'go mod vendor' should interpret paths relative to the current working directory when the -o flag is provided. +mkdir dir1 +mkdir dir2 + +cd dir1 +go mod vendor -v -o relative-vendor-dir + +go mod vendor -v -o ../dir2/relative-vendor-dir + +cd .. +exists dir1/relative-vendor-dir/modules.txt +exists dir1/relative-vendor-dir/a/foo/LICENSE +exists dir2/relative-vendor-dir/modules.txt +exists dir2/relative-vendor-dir/a/foo/LICENSE + +# 'go mod vendor' should fall back to the default 'vendor' directory when an empty argument is passed to the -o flag +# the same behavior should be exhibited both on the module root directory, as well as nested subdirectories + +go mod vendor -v -o '' +exists vendor/modules.txt + +env GOFLAGS=-o=foo +go mod vendor -v -o '' +exists vendor/modules.txt +env GOFLAGS='' + +mkdir -p nested/dir +cd nested/dir +go mod vendor -v -o '' +! exists vendor/ +exists ../../vendor/modules.txt +cd ../.. + +# 'go mod vendor' should work with absolute paths as well +go mod vendor -v -o $WORK/tmp/absolute-vendor-dir +exists $WORK/tmp/absolute-vendor-dir/modules.txt + +[short] stop + +# 'go build' and 'go test' using vendored packages should succeed. +go build -mod=mod +go build -mod=vendor +go test -mod=vendor . ./subdir +go test -mod=vendor ./... +go fmt -mod=vendor ./... + +-- go.mod -- +module m + +go 1.13 + +require ( + a v1.0.0 + diamondroot v0.0.0 + mysite/myname/mypkg v1.0.0 + w v1.0.0 // indirect + x v1.0.0 + y v1.0.0 + z v1.0.0 +) + +replace ( + a v1.0.0 => ./a + diamondleft => ./diamondleft + diamondpoint => ./diamondpoint + diamondright => ./diamondright + diamondroot => ./diamondroot + mysite/myname/mypkg v1.0.0 => ./mypkg + w v1.0.0 => ./w + x v1.0.0 => ./x + y v1.0.0 => ./y + z v1.0.0 => ./z +) + +-- a/foo/AUTHORS.txt -- +-- a/foo/CONTRIBUTORS -- +-- a/foo/LICENSE -- +-- a/foo/PATENTS -- +-- a/foo/COPYING -- +-- a/foo/COPYLEFT -- +-- a/foo/licensed-to-kill -- +-- w/LICENSE -- +-- x/NOTICE! -- +-- x/x2/LICENSE -- +-- mypkg/LICENSE.txt -- + +-- a/foo/bar/b/main.go -- +package b +-- a/foo/bar/b/ignored.go -- +// This file is intended for use with "go run"; it isn't really part of the package. + +// +build ignore + +package main + +func main() {} +-- a/foo/bar/b/main_test.go -- +package b + +import ( + "os" + "testing" +) + +func TestDir(t *testing.T) { + if _, err := os.Stat("../testdata/1"); err != nil { + t.Fatalf("testdata: %v", err) + } +} +-- a/foo/bar/c/main.go -- +package c +import _ "a/foo/bar/b" +-- a/foo/bar/c/main_test.go -- +package c + +import ( + "os" + "testing" +) + +func TestDir(t *testing.T) { + if _, err := os.Stat("../../../testdata/1"); err != nil { + t.Fatalf("testdata: %v", err) + } + if _, err := os.Stat("./testdata/1"); err != nil { + t.Fatalf("testdata: %v", err) + } +} +-- a/foo/bar/c/testdata/1 -- +-- a/foo/bar/testdata/1 -- +-- a/go.mod -- +module a +-- a/main.go -- +package a +-- a/main_test.go -- +package a + +import ( + "os" + "testing" +) + +func TestDir(t *testing.T) { + if _, err := os.Stat("./testdata/1"); err != nil { + t.Fatalf("testdata: %v", err) + } +} +-- a/testdata/1 -- +-- appengine.go -- +// +build appengine + +package m + +import _ "appengine" +import _ "appengine/datastore" +-- mypkg/go.mod -- +module me +-- mypkg/mydir/d.go -- +package mydir +-- subdir/v1_test.go -- +package m + +import _ "mysite/myname/mypkg/mydir" +-- testdata1.go -- +package m + +import _ "a" +-- testdata2.go -- +package m + +import _ "a/foo/bar/c" +-- v1.go -- +package m + +import _ "x" +-- v2.go -- +// +build abc + +package mMmMmMm + +import _ "y" +-- v3.go -- +// +build !abc + +package m + +import _ "z" +-- v4.go -- +// +build notmytag + +package m + +import _ "x/x1" +-- importdiamond.go -- +package m + +import _ "diamondroot" +-- w/go.mod -- +module w +-- w/w.go -- +package w +-- x/go.mod -- +module x +-- x/testdata/x.txt -- +placeholder - want directory with no go files +-- x/x.go -- +package x +-- x/x1/x1.go -- +// +build notmytag + +package x1 +-- x/x2/dummy.txt -- +dummy +-- x/x_test.go -- +package x + +import _ "w" +-- y/go.mod -- +module y +-- y/y.go -- +package y +-- z/go.mod -- +module z +-- z/z.go -- +package z + +-- diamondroot/go.mod -- +module diamondroot + +require ( + diamondleft v0.0.0 + diamondright v0.0.0 +) +-- diamondroot/x.go -- +package diamondroot + +import _ "diamondleft" +-- diamondroot/unused/unused.go -- +package unused + +import _ "diamondright" +-- diamondleft/go.mod -- +module diamondleft + +require ( + diamondpoint v0.0.0 +) +-- diamondleft/x.go -- +package diamondleft + +import _ "diamondpoint" +-- diamondright/go.mod -- +module diamondright + +require ( + diamondpoint v0.0.0 +) +-- diamondright/x.go -- +package diamondright + +import _ "diamondpoint" +-- diamondpoint/go.mod -- +module diamondpoint +-- diamondpoint/x.go -- +package diamondpoint diff --git a/src/cmd/go/testdata/script/mod_vendor_auto.txt b/src/cmd/go/testdata/script/mod_vendor_auto.txt new file mode 100644 index 0000000..2cafcda --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_auto.txt @@ -0,0 +1,259 @@ +# Integration test for golang.org/issue/33848: automatically check and use vendored packages. + +env GO111MODULE=on + +[short] skip + +cd $WORK/auto +cp go.mod go.mod.orig +cp $WORK/modules-1.13.txt $WORK/auto/modules.txt + +# An explicit -mod=vendor should force use of the vendor directory. +env GOFLAGS=-mod=vendor + +# Pass -e to permit an error: tools.go imports a main package +# "example.com/printversion". +# TODO(#59186): investigate why it didn't fail without -e. +go list -f {{.Dir}} -tags tools -e all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]printversion$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]version$' + +! go list -m all +stderr 'go: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)' + +! go list -m -f '{{.Dir}}' all +stderr 'go: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)' + +# An explicit -mod=mod should force the vendor directory to be ignored. +env GOFLAGS=-mod=mod + +go list -f {{.Dir}} -tags tools -e all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$GOPATH'[/\\]pkg[/\\]mod[/\\]example.com[/\\]printversion@v1.0.0$' +stdout '^'$WORK'[/\\]auto[/\\]replacement-version$' + +go list -m all +stdout '^example.com/auto$' +stdout 'example.com/printversion v1.0.0' +stdout 'example.com/version v1.0.0' + +go list -m -f '{{.Dir}}' all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$GOPATH'[/\\]pkg[/\\]mod[/\\]example.com[/\\]printversion@v1.0.0$' +stdout '^'$WORK'[/\\]auto[/\\]replacement-version$' + +# If the main module's "go" directive says 1.13, we should default to -mod=mod. +env GOFLAGS= +go mod edit -go=1.13 + +go list -f {{.Dir}} -tags tools -e all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$GOPATH'[/\\]pkg[/\\]mod[/\\]example.com[/\\]printversion@v1.0.0$' +stdout '^'$WORK'[/\\]auto[/\\]replacement-version$' + +go list -m -f '{{.Dir}}' all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$GOPATH'[/\\]pkg[/\\]mod[/\\]example.com[/\\]printversion@v1.0.0$' +stdout '^'$WORK'[/\\]auto[/\\]replacement-version$' + +# A 'go 1.14' directive in the main module's go.mod file should enable +# -mod=vendor by default, along with stronger checks for consistency +# between the go.mod file and vendor/modules.txt. +# A 'go 1.13' vendor/modules.txt file is not usually sufficient +# to pass those checks. +go mod edit -go=1.14 + +! go list -f {{.Dir}} -tags tools all +stderr '^go: inconsistent vendoring in '$WORK[/\\]auto':$' +stderr '^\texample.com/printversion@v1.0.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt' +stderr '^\texample.com/unused: is replaced in go.mod, but not marked as replaced in vendor/modules.txt' +stderr '^\texample.com/version@v1.2.0: is replaced in go.mod, but not marked as replaced in vendor/modules.txt' +stderr '^\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor$' + +# Module-specific subcommands should continue to load the full module graph. +go mod graph +stdout '^example.com/printversion@v1.0.0 example.com/version@v1.0.0$' + +# An explicit -mod=mod should still force the vendor directory to be ignored. +env GOFLAGS=-mod=mod + +go list -f {{.Dir}} -tags tools -e all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$GOPATH'[/\\]pkg[/\\]mod[/\\]example.com[/\\]printversion@v1.0.0$' +stdout '^'$WORK'[/\\]auto[/\\]replacement-version$' + +go list -m all +stdout '^example.com/auto$' +stdout 'example.com/printversion v1.0.0' +stdout 'example.com/version v1.0.0' + +go list -m -f '{{.Dir}}' all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$GOPATH'[/\\]pkg[/\\]mod[/\\]example.com[/\\]printversion@v1.0.0$' +stdout '^'$WORK'[/\\]auto[/\\]replacement-version$' + +# 'go mod vendor' should repair vendor/modules.txt so that the implicit +# -mod=vendor works again. +env GOFLAGS= + +go mod edit -go=1.14 +go mod vendor + +go list -f {{.Dir}} -tags tools -e all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]printversion$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]version$' + +# ...but 'go list -m' should continue to fail, this time without +# referring to a -mod default that the user didn't set. +! go list -m all +stderr 'go: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)' + +! go list -m -f '{{.Dir}}' all +stderr 'go: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)' + + +# 'go mod init' should work if there is already a GOPATH-mode vendor directory +# present. If there are no module dependencies, -mod=vendor should be used by +# default and should not fail the consistency check even though no module +# information is present. + +rm go.mod +rm vendor/modules.txt + +go mod init example.com/auto +go list -f {{.Dir}} -tags tools -e all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]printversion$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]version$' + +# If information about dependencies is added to a 1.14 go.mod file, subsequent +# list commands should error out if vendor/modules.txt is missing or incomplete. + +cp go.mod.orig go.mod +go mod edit -go=1.14 +! go list -f {{.Dir}} -tags tools -e all +stderr '^go: inconsistent vendoring in '$WORK[/\\]auto':$' +stderr '^\texample.com/printversion@v1.0.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt' +stderr '^\texample.com/unused: is replaced in go.mod, but not marked as replaced in vendor/modules.txt' +stderr '^\texample.com/version@v1.2.0: is replaced in go.mod, but not marked as replaced in vendor/modules.txt' +stderr '^\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor$' + +# If -mod=vendor is set, limited consistency checks should apply even when +# the go version is 1.13 or earlier. +# An incomplete or missing vendor/modules.txt should resolve the vendored packages... +go mod edit -go=1.13 +go list -mod=vendor -f {{.Dir}} -tags tools -e all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]printversion$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]version$' + +# ...but a version mismatch for an explicit dependency should be noticed. +cp $WORK/modules-bad-1.13.txt vendor/modules.txt +! go list -mod=vendor -f {{.Dir}} -tags tools all +stderr '^go: inconsistent vendoring in '$WORK[/\\]auto':$' +stderr '^\texample.com/printversion@v1.0.0: is explicitly required in go.mod, but vendor/modules.txt indicates example.com/printversion@v1.1.0$' +stderr '^\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor$' + +# If the go version is still 1.13, 'go mod vendor' should write a +# matching vendor/modules.txt containing the corrected 1.13 data. +go mod vendor +cmp $WORK/modules-1.13.txt vendor/modules.txt + +go list -mod=vendor -f {{.Dir}} -tags tools -e all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]printversion$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]version$' + +# When the version is upgraded to 1.14, 'go mod vendor' should write a +# vendor/modules.txt with the updated 1.14 annotations. +go mod edit -go=1.14 +go mod vendor +cmp $WORK/modules-1.14.txt vendor/modules.txt + +# Then, -mod=vendor should kick in automatically and succeed. +go list -f {{.Dir}} -tags tools -e all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]printversion$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]version$' + +# 'go get' should update from the network or module cache, +# even if a vendor directory is present. +go get example.com/version@v1.1.0 +! go list -f {{.Dir}} -tags tools all +stderr '^go: inconsistent vendoring' + +-- $WORK/auto/go.mod -- +module example.com/auto + +go 1.13 + +require example.com/printversion v1.0.0 + +replace ( + example.com/unused => nonexistent.example.com/unused v1.0.0-whatever + example.com/version v1.0.0 => ./replacement-version + example.com/version v1.2.0 => nonexistent.example.com/version v1.2.0 +) +-- $WORK/auto/tools.go -- +// +build tools + +package auto + +import _ "example.com/printversion" +-- $WORK/auto/auto.go -- +package auto +-- $WORK/auto/replacement-version/go.mod -- +module example.com/version +-- $WORK/auto/replacement-version/version.go -- +package version + +const V = "v1.0.0-replaced" +-- $WORK/modules-1.14.txt -- +# example.com/printversion v1.0.0 +## explicit +example.com/printversion +# example.com/version v1.0.0 => ./replacement-version +example.com/version +# example.com/unused => nonexistent.example.com/unused v1.0.0-whatever +# example.com/version v1.2.0 => nonexistent.example.com/version v1.2.0 +-- $WORK/modules-1.13.txt -- +# example.com/printversion v1.0.0 +example.com/printversion +# example.com/version v1.0.0 => ./replacement-version +example.com/version +-- $WORK/modules-bad-1.13.txt -- +# example.com/printversion v1.1.0 +example.com/printversion +# example.com/version v1.1.0 +example.com/version +-- $WORK/auto/vendor/example.com/printversion/go.mod -- +module example.com/printversion + +require example.com/version v1.0.0 +replace example.com/version v1.0.0 => ../oops v0.0.0 +exclude example.com/version v1.0.1 +-- $WORK/auto/vendor/example.com/printversion/printversion.go -- +package main + +import ( + "fmt" + "os" + "runtime/debug" + + _ "example.com/version" +) + +func main() { + info, _ := debug.ReadBuildInfo() + fmt.Fprintf(os.Stdout, "path is %s\n", info.Path) + fmt.Fprintf(os.Stdout, "main is %s %s\n", info.Main.Path, info.Main.Version) + for _, m := range info.Deps { + fmt.Fprintf(os.Stdout, "using %s %s\n", m.Path, m.Version) + } +} +-- $WORK/auto/vendor/example.com/version/version.go -- +package version + +const V = "v1.0.0-replaced" diff --git a/src/cmd/go/testdata/script/mod_vendor_build.txt b/src/cmd/go/testdata/script/mod_vendor_build.txt new file mode 100644 index 0000000..4efda55 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_build.txt @@ -0,0 +1,41 @@ +env GO111MODULE=on +[short] skip + +# Populate go.mod and go.sum. +go mod tidy + +# initial conditions: using sampler v1.3.0, not listed in go.mod. +go list -deps +stdout rsc.io/sampler +! grep 'rsc.io/sampler v1.3.0' go.mod + +# update to v1.3.1, now indirect in go.mod. +go get rsc.io/sampler@v1.3.1 +grep 'rsc.io/sampler v1.3.1 // indirect' go.mod +cp go.mod go.mod.good + +# vendoring can but should not need to make changes. +go mod vendor +cmp go.mod go.mod.good + +# go list -mod=vendor (or go build -mod=vendor) must not modify go.mod. +# golang.org/issue/26704 +go list -mod=vendor +cmp go.mod go.mod.good + +# With a clean (and empty) module cache, 'go list -mod=vendor' should not download modules. +go clean -modcache +env GOPROXY=off +! go list ... +go list -mod=vendor ... + +# However, it should still list packages in the main module. +go list -mod=vendor m/... +stdout m + +-- go.mod -- +module m +go 1.12 +-- x.go -- +package x +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_vendor_embed.txt b/src/cmd/go/testdata/script/mod_vendor_embed.txt new file mode 100644 index 0000000..1a3b2fe --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_embed.txt @@ -0,0 +1,209 @@ +go mod vendor +cmp vendor/example.com/a/samedir_embed.txt a/samedir_embed.txt +cmp vendor/example.com/a/subdir/embed.txt a/subdir/embed.txt +cmp vendor/example.com/a/subdir/test/embed.txt a/subdir/test/embed.txt +cmp vendor/example.com/a/subdir/test/xtest/embed.txt a/subdir/test/xtest/embed.txt + +cd broken_no_matching_files +! go mod vendor +stderr 'go: pattern foo.txt: no matching files found' + +cd ../broken_bad_pattern +! go mod vendor +stderr 'go: pattern ../foo.txt: invalid pattern syntax' + +cd ../embed_go122 +go mod vendor +cmp vendor/example.com/a/samedir_embed.txt ../a/samedir_embed.txt +cmp vendor/example.com/a/subdir/embed.txt ../a/subdir/embed.txt +! exists vendor/example.com/a/subdir/test/embed.txt +! exists vendor/example.com/a/subdir/test/xtest/embed.txt +-- embed_go122/go.mod -- +module example.com/foo +go 1.22 + +require ( + example.com/a v0.1.0 +) + +replace ( + example.com/a v0.1.0 => ../a +) +-- embed_go122/foo.go -- +package main + +import ( + "fmt" + + "example.com/a" +) + +func main() { + fmt.Println(a.Str()) +} + +# matchPotentialSourceFile prunes out tests and unbuilt code. +# Make sure that they are vendored if they are embedded files. +cd ../embed_unbuilt +go mod vendor +cmp vendor/example.com/dep/unbuilt.go dep/unbuilt.go +cmp vendor/example.com/dep/dep_test.go dep/dep_test.go +! exists vendor/example.com/dep/not_embedded_unbuilt.go +! exists vendor/example.com/dep/not_embedded_dep_test.go +-- go.mod -- +module example.com/foo +go 1.16 + +require ( + example.com/a v0.1.0 +) + +replace ( + example.com/a v0.1.0 => ./a +) +-- foo.go -- +package main + +import ( + "fmt" + + "example.com/a" +) + +func main() { + fmt.Println(a.Str()) +} +-- a/go.mod -- +module example.com/a +-- a/a.go -- +package a + +import _ "embed" + +//go:embed samedir_embed.txt +var sameDir string + +//go:embed subdir/embed.txt +var subDir string + +func Str() string { + return sameDir + subDir +} +-- a/a_test.go -- +package a + +import _ "embed" + +//go:embed subdir/test/embed.txt +var subderTest string +-- a/a_x_test.go -- +package a_test + +import _ "embed" + +//go:embed subdir/test/xtest/embed.txt +var subdirXtest string +-- a/samedir_embed.txt -- +embedded file in same directory as package +-- a/subdir/embed.txt -- +embedded file in subdirectory of package +-- a/subdir/test/embed.txt -- +embedded file of test in subdirectory of package +-- a/subdir/test/xtest/embed.txt -- +embedded file of xtest in subdirectory of package +-- broken_no_matching_files/go.mod -- +module example.com/broken +go 1.16 + +require ( + example.com/brokendep v0.1.0 +) + +replace ( + example.com/brokendep v0.1.0 => ./brokendep +) +-- broken_no_matching_files/f.go -- +package broken + +import _ "example.com/brokendep" + +func F() {} +-- broken_no_matching_files/brokendep/go.mod -- +module example.com/brokendep +go 1.16 +-- broken_no_matching_files/brokendep/f.go -- +package brokendep + +import _ "embed" + +//go:embed foo.txt +var foo string +-- broken_bad_pattern/go.mod -- +module example.com/broken +go 1.16 + +require ( + example.com/brokendep v0.1.0 +) + +replace ( + example.com/brokendep v0.1.0 => ./brokendep +) +-- broken_bad_pattern/f.go -- +package broken + +import _ "example.com/brokendep" + +func F() {} +-- broken_bad_pattern/brokendep/go.mod -- +module example.com/brokendep +go 1.16 +-- broken_bad_pattern/brokendep/f.go -- +package brokendep + +import _ "embed" + +//go:embed ../foo.txt +var foo string +-- embed_unbuilt/go.mod -- +module example.com/foo +go 1.16 + +require ( + example.com/dep v0.1.0 +) + +replace ( + example.com/dep v0.1.0 => ./dep +) +-- embed_unbuilt/foo.go -- +package a + +import _ "example.com/dep" + +func F() {} +-- embed_unbuilt/dep/go.mod -- +module example.com/dep +go 1.16 +-- embed_unbuilt/dep/dep.go -- +package dep + +import _ "embed" + +//go:embed unbuilt.go +var unbuilt string + +//go:embed dep_test.go +var depTest string +-- embed_unbuilt/dep/unbuilt.go -- +// +build ignore + +package dep +-- embed_unbuilt/dep/not_embedded_unbuilt.go -- +// +build ignore + +package dep +-- embed_unbuilt/dep/dep_test.go -- +package dep +-- embed_unbuilt/dep/not_embedded_dep_test.go -- +package dep diff --git a/src/cmd/go/testdata/script/mod_vendor_gomod.txt b/src/cmd/go/testdata/script/mod_vendor_gomod.txt new file mode 100644 index 0000000..3f6ea35 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_gomod.txt @@ -0,0 +1,38 @@ +# https://golang.org/issue/42970: As of Go 1.17, go.mod and go.sum files should +# be stripped from vendored dependencies. + +go mod vendor +cd vendor/example.net/x +go list all +! stdout '^example.net/m' +stdout '^example.net/x$' +exists ./go.sum + +cd ../../.. +go mod edit -go=1.17 +go mod vendor +cd vendor/example.net/x +go list all +stdout '^example.net/m$' +stdout '^example.net/x$' +! exists ./go.sum + +-- go.mod -- +module example.net/m + +go 1.16 + +require example.net/x v0.1.0 + +replace example.net/x v0.1.0 => ./x +-- m.go -- +package m + +import _ "example.net/x" +-- x/go.mod -- +module example.net/x + +go 1.16 +-- x/go.sum -- +-- x/x.go -- +package x diff --git a/src/cmd/go/testdata/script/mod_vendor_goversion.txt b/src/cmd/go/testdata/script/mod_vendor_goversion.txt new file mode 100644 index 0000000..838c557 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_goversion.txt @@ -0,0 +1,102 @@ +# https://golang.org/issue/36876: As of Go 1.17, vendor/modules.txt should +# indicate the language version used by each dependency. + +[short] skip + +# Control case: without a vendor directory, need117 builds and bad114 doesn't. + +go build example.net/need117 +! go build example.net/bad114 +stderr '^bad114[/\\]bad114.go:15:2: duplicate method Y( .*)?$' + + +# With a vendor/modules.txt lacking language versions, the world is topsy-turvy, +# because we have to guess a uniform version for everything. +# +# We always guess Go 1.16, because that was the last version for which +# 'go mod vendor' failed to record dependency versions, and it has most of +# the language features added since modules were introduced in Go 1.11. +# +# Even so, modules that declare 'go 1.17' and use 1.17 features spuriously fail +# to build, and modules that declare an older version and use features from a +# newer one spuriously build (instead of failing as they ought to). + +go mod vendor + +! grep 1.17 vendor/modules.txt +! go build example.net/need117 +stderr '^vendor[/\\]example\.net[/\\]need117[/\\]need117.go:5:1[89]:' +stderr 'conversion of slices to array pointers requires go1\.17 or later' + +! grep 1.13 vendor/modules.txt +go build example.net/bad114 + + +# Upgrading the main module to 1.17 adds version annotations. +# Then everything is once again consistent with the non-vendored world. + +go mod edit -go=1.17 +go mod vendor + +grep '^## explicit; go 1.17$' vendor/modules.txt +go build example.net/need117 + +grep '^## explicit; go 1.13$' vendor/modules.txt +! go build example.net/bad114 +stderr '^vendor[/\\]example\.net[/\\]bad114[/\\]bad114.go:15:2: duplicate method Y( .+)?$' + +-- go.mod -- +module example.net/m + +go 1.16 + +require ( + example.net/bad114 v0.1.0 + example.net/need117 v0.1.0 +) + +replace ( + example.net/bad114 v0.1.0 => ./bad114 + example.net/need117 v0.1.0 => ./need117 +) +-- m.go -- +package m + +import _ "example.net/bad114" +import _ "example.net/need117" + +-- bad114/go.mod -- +// Module bad114 requires Go 1.14 or higher, but declares Go 1.13. +module example.net/bad114 + +go 1.13 +-- bad114/bad114.go -- +package bad114 + +type XY interface { + X() + Y() +} + +type YZ interface { + Y() + Z() +} + +type XYZ interface { + XY + YZ +} + +-- need117/go.mod -- +// Module need117 requires Go 1.17 or higher. +module example.net/need117 + +go 1.17 +-- need117/need117.go -- +package need117 + +func init() { + s := make([]byte, 4) + _ = (*[4]byte)(s) +} diff --git a/src/cmd/go/testdata/script/mod_vendor_issue46867.txt b/src/cmd/go/testdata/script/mod_vendor_issue46867.txt new file mode 100644 index 0000000..38ae87b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_issue46867.txt @@ -0,0 +1,31 @@ +# Regression test for golang.org/issue/46867: +# 'go mod vendor' on Windows attempted to open and copy +# files from directories outside of the module. + +cd subdir +go mod vendor +! exists vendor/example.net/NOTICE +exists vendor/example.net/m/NOTICE + +-- subdir/go.mod -- +module golang.org/issue46867 + +go 1.17 + +replace example.net/m v0.1.0 => ./m + +require example.net/m v0.1.0 +-- subdir/issue.go -- +package issue + +import _ "example.net/m/n" +-- subdir/m/go.mod -- +module example.net/m + +go 1.17 +-- subdir/m/n/n.go -- +package n +-- subdir/m/NOTICE -- +This notice is in module m and SHOULD be vendored. +-- subdir/NOTICE -- +This notice is outside of module m and SHOULD NOT be vendored. diff --git a/src/cmd/go/testdata/script/mod_vendor_nodeps.txt b/src/cmd/go/testdata/script/mod_vendor_nodeps.txt new file mode 100644 index 0000000..e9a84ca --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_nodeps.txt @@ -0,0 +1,9 @@ +env GO111MODULE=on + +go mod vendor +stderr '^go: no dependencies to vendor' + +-- go.mod -- +module x +-- x.go -- +package x diff --git a/src/cmd/go/testdata/script/mod_vendor_redundant_requirement.txt b/src/cmd/go/testdata/script/mod_vendor_redundant_requirement.txt new file mode 100644 index 0000000..3f6f5c5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_redundant_requirement.txt @@ -0,0 +1,29 @@ +# 'go list -mod=vendor' should succeed even when go.mod contains redundant +# requirements. Verifies #47565. +go list -mod=vendor + +-- go.mod -- +module m + +go 1.17 + +require example.com/m v0.0.0 +require example.com/m v0.0.0 + +replace example.com/m v0.0.0 => ./m +-- m/go.mod -- +module example.com/m + +go 1.17 +-- m/m.go -- +package m +-- use.go -- +package use + +import _ "example.com/m" +-- vendor/example.com/m/m.go -- +package m +-- vendor/modules.txt -- +# example.com/m v0.0.0 => ./m +## explicit; go 1.17 +example.com/m diff --git a/src/cmd/go/testdata/script/mod_vendor_replace.txt b/src/cmd/go/testdata/script/mod_vendor_replace.txt new file mode 100644 index 0000000..c492999 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_replace.txt @@ -0,0 +1,89 @@ +env GO111MODULE=on + +# Replacement should not use a vendor directory as the target. +! go mod vendor +stderr 'replacement path ./vendor/not-rsc.io/quote/v3 inside vendor directory' + +cp go.mod1 go.mod +rm -r vendor + +# Before vendoring, we expect to see the original directory. +go list -f '{{with .Module}}{{.Version}}{{end}} {{.Dir}}' rsc.io/quote/v3 +stdout 'v3.0.0' +stdout '.*[/\\]not-rsc.io[/\\]quote[/\\]v3' + +# Since all dependencies are replaced, 'go mod vendor' should not +# have to download anything from the network. +go mod vendor +! stderr 'downloading' +! stderr 'finding' + +# After vendoring, we expect to see the replacement in the vendor directory, +# without attempting to look up the non-replaced version. +cmp vendor/rsc.io/quote/v3/quote.go local/not-rsc.io/quote/v3/quote.go + +go list -mod=vendor -f '{{with .Module}}{{.Version}}{{end}} {{.Dir}}' rsc.io/quote/v3 +stdout 'v3.0.0' +stdout '.*[/\\]vendor[/\\]rsc.io[/\\]quote[/\\]v3' +! stderr 'finding' +! stderr 'lookup disabled' + +# 'go list' should provide the original replacement directory as the module's +# replacement path. +go list -mod=vendor -f '{{with .Module}}{{with .Replace}}{{.Path}}{{end}}{{end}}' rsc.io/quote/v3 +stdout '.*[/\\]not-rsc.io[/\\]quote[/\\]v3' + +# The same module can't be used as two different paths. +cd multiple-paths +! go mod vendor +stderr 'rsc.io/quote/v3@v3.0.0 used for two different module paths \(not-rsc.io/quote/v3 and rsc.io/quote/v3\)' + +-- go.mod -- +module example.com/replace + +require rsc.io/quote/v3 v3.0.0 +replace rsc.io/quote/v3 => ./vendor/not-rsc.io/quote/v3 + +-- go.mod1 -- +module example.com/replace + +require rsc.io/quote/v3 v3.0.0 +replace rsc.io/quote/v3 => ./local/not-rsc.io/quote/v3 + +-- imports.go -- +package replace + +import _ "rsc.io/quote/v3" + +-- local/not-rsc.io/quote/v3/go.mod -- +module not-rsc.io/quote/v3 + +-- local/not-rsc.io/quote/v3/quote.go -- +package quote + +-- multiple-paths/main.go -- +package main +import ( + "fmt" + "rsc.io/quote/v3" +) +func main() { + fmt.Println(quote.GoV3()) +} +-- multiple-paths/go.mod -- +module quoter +require ( + rsc.io/quote/v3 v3.0.0 + not-rsc.io/quote/v3 v3.0.0 +) +replace not-rsc.io/quote/v3 => rsc.io/quote/v3 v3.0.0 +-- multiple-paths/go.sum -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote/v3 v3.0.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= + +-- vendor/not-rsc.io/quote/v3/go.mod -- +module not-rsc.io/quote/v3 + +-- vendor/not-rsc.io/quote/v3/quote.go -- +package quote diff --git a/src/cmd/go/testdata/script/mod_vendor_trimpath.txt b/src/cmd/go/testdata/script/mod_vendor_trimpath.txt new file mode 100644 index 0000000..d9d9d98 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_trimpath.txt @@ -0,0 +1,49 @@ +# Check that when -trimpath and -mod=vendor are used together, +# paths in vendored packages are properly trimmed. +# Verifies golang.org/issue/36566. + +[short] skip + +# Only the main module has a root directory in vendor mode. +go mod vendor +go list -f {{.Module.Dir}} example.com/main +stdout $PWD +go list -f {{.Module.Dir}} example.com/stack +! stdout . + +# The program prints a file name from a vendored package. +# Without -trimpath, the name should include the vendor directory. +go run main.go +stdout vendor + +# With -trimpath, everything before the package path should be trimmed. +# As with -mod=mod, the version should appear as part of the module path. +go run -mod=vendor -trimpath main.go +stdout '^example.com/stack@v1.0.0/stack.go$' + +# With pristinely vendored source code, a trimmed binary built from vendored +# code should have the same behavior as one build from the module cache. +go run -mod=mod -trimpath main.go +stdout '^example.com/stack@v1.0.0/stack.go$' + +-- go.mod -- +module example.com/main + +go 1.17 + +require example.com/stack v1.0.0 +-- go.sum -- +example.com/stack v1.0.0 h1:IEDLeew5NytZ8vrgCF/QVem3H3SR3QMttdu9HfJvk9I= +example.com/stack v1.0.0/go.mod h1:7wFEbaV5e5O7wJ8aBdqQOR//UXppm/pwnwziMKViuI4= +-- main.go -- +package main + +import ( + "fmt" + + "example.com/stack" +) + +func main() { + fmt.Println(stack.TopFile()) +} diff --git a/src/cmd/go/testdata/script/mod_vendor_unused.txt b/src/cmd/go/testdata/script/mod_vendor_unused.txt new file mode 100644 index 0000000..96251bb --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_unused.txt @@ -0,0 +1,67 @@ +# Auxiliary test for inclusion of otherwise-unused replacements in +# vendor/modules.txt for golang.org/issue/33848. +# We need metadata about replacements in order to verify that modules.txt +# remains in sync with the main module's go.mod file. + +env GO111MODULE=on + +go mod vendor +cmp go1.14-modules.txt vendor/modules.txt + +-- go.mod -- +module example.com/foo +go 1.14 + +require ( + example.com/a v0.1.0 +) + +replace ( + example.com/a v0.1.0 => ./a + example.com/b v0.1.0 => ./b1 + example.com/b v0.2.0-unused => ./b2 + example.com/c => ./c + example.com/d v0.1.0 => ./d1 + example.com/d v0.2.0 => ./d2 + example.com/e => example.com/e v0.1.0-unused +) +-- foo.go -- +package foo +import _ "example.com/a" +-- a/go.mod -- +module example.com/a +require ( + example.com/b v0.1.0 // indirect + example.com/c v0.1.0 // indirect +) +-- a/a.go -- +package a +import _ "example.com/d" +-- b1/go.mod -- +module example.com/b +require example.com/d v0.1.0 +-- b2/go.mod -- +module example.com/b +require example.com/c v0.2.0 +-- c/go.mod -- +module example.com/c +require example.com/d v0.2.0 +-- d1/go.mod -- +module example.com/d +-- d1/d1.go -- +package d +-- d2/go.mod -- +module example.com/d +-- d2/d2.go -- +package d +-- go1.14-modules.txt -- +# example.com/a v0.1.0 => ./a +## explicit +example.com/a +# example.com/d v0.2.0 => ./d2 +example.com/d +# example.com/b v0.1.0 => ./b1 +# example.com/b v0.2.0-unused => ./b2 +# example.com/c => ./c +# example.com/d v0.1.0 => ./d1 +# example.com/e => example.com/e v0.1.0-unused diff --git a/src/cmd/go/testdata/script/mod_vendor_unused_only.txt b/src/cmd/go/testdata/script/mod_vendor_unused_only.txt new file mode 100644 index 0000000..accd9f3 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_unused_only.txt @@ -0,0 +1,19 @@ +# Ensure that we generate a vendor/modules.txt file even when the only +# requirements in go.mod are unused. Regression test for +# golang.org/issue/36580 + +env GO111MODULE=on + +go mod vendor +cmp go1.14-modules.txt vendor/modules.txt + +-- go.mod -- +module example.com/m +go 1.14 + +require example.com v1.0.0 // indirect +-- go.sum -- +example.com v1.0.0/go.mod h1:WRiieAqDBb1hVdDXLLdxNtCDWNfehn7FWyPC5Oz2vB4= +-- go1.14-modules.txt -- +# example.com v1.0.0 +## explicit diff --git a/src/cmd/go/testdata/script/mod_verify.txt b/src/cmd/go/testdata/script/mod_verify.txt new file mode 100644 index 0000000..018709e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_verify.txt @@ -0,0 +1,82 @@ +env GO111MODULE=on +[short] skip + +# With good go.sum, verify succeeds by avoiding download. +cp go.sum.good go.sum +go mod verify +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.zip + +# With bad go.sum, verify succeeds by avoiding download. +cp go.sum.bad go.sum +go mod verify +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.zip + +# With bad go.sum, sync (which must download) fails. +rm go.sum +cp go.sum.bad go.sum +! go mod tidy +stderr 'checksum mismatch' +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.zip + +# With good go.sum, sync works. +rm go.sum +cp go.sum.good go.sum +go mod tidy +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.zip +exists $GOPATH/pkg/mod/rsc.io/quote@v1.1.0/quote.go + +# go.sum should have the new checksum for go.mod +grep '^rsc.io/quote v1.1.0/go.mod ' go.sum + +# verify should work +go mod verify + +# basic loading of module graph should detect incorrect go.mod files. +go mod graph +cp go.sum.bad2 go.sum +! go mod graph +stderr 'go.mod: checksum mismatch' + +# go.sum should be created and updated automatically. +rm go.sum +go mod tidy +grep '^rsc.io/quote v1.1.0/go.mod ' go.sum +grep '^rsc.io/quote v1.1.0 ' go.sum + +# verify should fail on a missing ziphash. tidy should restore it. +rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.ziphash +! go mod verify +stderr '^rsc.io/quote v1.1.0: missing ziphash: open '$GOPATH'[/\\]pkg[/\\]mod[/\\]cache[/\\]download[/\\]rsc.io[/\\]quote[/\\]@v[/\\]v1.1.0.ziphash' +go mod tidy +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.ziphash +go mod verify + +# Packages below module root should not be mentioned in go.sum. +rm go.sum +go mod edit -droprequire rsc.io/quote +go get rsc.io/quote/buggy +grep '^rsc.io/quote v1.5.2/go.mod ' go.sum +! grep buggy go.sum + +# non-existent packages below module root should not be mentioned in go.sum +go mod edit -droprequire rsc.io/quote +! go list rsc.io/quote/morebuggy +grep '^rsc.io/quote v1.5.2/go.mod ' go.sum +! grep buggy go.sum + +-- go.mod -- +module x +require rsc.io/quote v1.1.0 + +-- x.go -- +package x +import _ "rsc.io/quote" + +-- go.sum.good -- +rsc.io/quote v1.1.0 h1:a3YaZoizPtXyv6ZsJ74oo2L4/bwOSTKMY7MAyo4O/0c= + +-- go.sum.bad -- +rsc.io/quote v1.1.0 h1:a3YaZoizPtXyv6ZsJ74oo2L4/bwOSTKMY7MAyo4O/1c= + +-- go.sum.bad2 -- +rsc.io/quote v1.1.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl1= diff --git a/src/cmd/go/testdata/script/mod_verify_work.txt b/src/cmd/go/testdata/script/mod_verify_work.txt new file mode 100644 index 0000000..d9f5a54 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_verify_work.txt @@ -0,0 +1,24 @@ +# Regression test for Issue #62663: we would filter out the toolchain and +# main modules from the build list incorrectly, leading to the workspace +# modules being checked for correct sums. Specifically this would happen when +# the module name sorted after the virtual 'go' version module name because +# it could not get chopped off when we removed the MainModules.Len() modules +# at the beginning of the build list and we would remove the go module instead. + +go mod verify + +-- go.work -- +go 1.21 + +use ( + ./a + ./b +) +-- a/go.mod -- +module hexample.com/a // important for test that module name sorts after 'go' + +go 1.21 +-- b/go.mod -- +module hexample.com/b // important for test that module name sorts after 'go' + +go 1.21
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/mod_versions.txt b/src/cmd/go/testdata/script/mod_versions.txt new file mode 100644 index 0000000..aaa4216 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_versions.txt @@ -0,0 +1,14 @@ +# Test rejection of pkg@version in GOPATH mode. +env GO111MODULE=off +! go get rsc.io/quote@v1.5.1 +stderr '^go: modules disabled by GO111MODULE=off' +! go build rsc.io/quote@v1.5.1 +stderr '^package rsc.io/quote@v1.5.1: can only use path@version syntax with ''go get'' and ''go install'' in module-aware mode$' + +env GO111MODULE=on +cd x +! go build rsc.io/quote@v1.5.1 +stderr '^package rsc.io/quote@v1.5.1: can only use path@version syntax with ''go get'' and ''go install'' in module-aware mode$' + +-- x/go.mod -- +module x diff --git a/src/cmd/go/testdata/script/mod_why.txt b/src/cmd/go/testdata/script/mod_why.txt new file mode 100644 index 0000000..b3036fa --- /dev/null +++ b/src/cmd/go/testdata/script/mod_why.txt @@ -0,0 +1,130 @@ +env GO111MODULE=on +[short] skip + +# Populate go.sum. +go mod tidy +cp go.mod go.mod.orig + +go list -test all +stdout rsc.io/quote +stdout golang.org/x/text/language + +# why a package? +go mod why golang.org/x/text/language +cmp stdout why-language.txt + +# why a module? +go mod why -m golang.org... +cmp stdout why-text-module.txt + +# why a package used only in tests? +go mod why rsc.io/testonly +cmp stdout why-testonly.txt + +# why a module used only in a test of a dependency? +go mod why -m rsc.io/testonly +cmp stdout why-testonly.txt + +# test package not needed +go mod why golang.org/x/text/unused +cmp stdout why-unused.txt + +# vendor doesn't use packages used only in tests. +go mod why -vendor rsc.io/testonly +cmp stdout why-vendor.txt + +# vendor doesn't use modules used only in tests. +go mod why -vendor -m rsc.io/testonly +cmp stdout why-vendor-module.txt + +# test multiple packages +go mod why golang.org/x/text/language golang.org/x/text/unused +cmp stdout why-both.txt + +# test multiple modules +go mod why -m rsc.io/quote rsc.io/sampler +cmp stdout why-both-module.txt + +# package in a module that isn't even in the module graph +# (https://golang.org/issue/26977) +go mod why rsc.io/fortune +cmp stdout why-missing.txt + +# None of these command should have changed the go.mod file. +cmp go.mod go.mod.orig + +-- go.mod -- +module mymodule +require rsc.io/quote v1.5.2 + +-- x/x.go -- +package x +import _ "mymodule/z" + +-- y/y.go -- +package y + +-- y/y_test.go -- +package y +import _ "rsc.io/quote" + +-- z/z.go -- +package z +import _ "mymodule/y" + + +-- why-language.txt -- +# golang.org/x/text/language +mymodule/y +mymodule/y.test +rsc.io/quote +rsc.io/sampler +golang.org/x/text/language +-- why-unused.txt -- +# golang.org/x/text/unused +(main module does not need package golang.org/x/text/unused) +-- why-text-module.txt -- +# golang.org/x/text +mymodule/y +mymodule/y.test +rsc.io/quote +rsc.io/sampler +golang.org/x/text/language +-- why-testonly.txt -- +# rsc.io/testonly +mymodule/y +mymodule/y.test +rsc.io/quote +rsc.io/sampler +rsc.io/sampler.test +rsc.io/testonly +-- why-vendor.txt -- +# rsc.io/testonly +(main module does not need to vendor package rsc.io/testonly) +-- why-vendor-module.txt -- +# rsc.io/testonly +(main module does not need to vendor module rsc.io/testonly) +-- why-both.txt -- +# golang.org/x/text/language +mymodule/y +mymodule/y.test +rsc.io/quote +rsc.io/sampler +golang.org/x/text/language + +# golang.org/x/text/unused +(main module does not need package golang.org/x/text/unused) +-- why-both-module.txt -- +# rsc.io/quote +mymodule/y +mymodule/y.test +rsc.io/quote + +# rsc.io/sampler +mymodule/y +mymodule/y.test +rsc.io/quote +rsc.io/sampler +-- why-missing.txt -- +# rsc.io/fortune +(main module does not need package rsc.io/fortune) diff --git a/src/cmd/go/testdata/script/modfile_flag.txt b/src/cmd/go/testdata/script/modfile_flag.txt new file mode 100644 index 0000000..6d28759 --- /dev/null +++ b/src/cmd/go/testdata/script/modfile_flag.txt @@ -0,0 +1,98 @@ +# Tests the behavior of the -modfile flag in commands that support it. +# The go.mod file exists but should not be read or written. +# Same with go.sum. + +env GOFLAGS=-modfile=go.alt.mod +cp go.mod go.mod.orig +cp go.sum go.sum.orig + + +# go mod init should create a new file, even though go.mod already exists. +go mod init example.com/m +grep example.com/m go.alt.mod + +# 'go env GOMOD' should print the path to the real file. +# 'go env' does not recognize the '-modfile' flag. +go env GOMOD +stdout '^'$WORK${/}gopath${/}src${/}'go\.mod$' + +# 'go list -m' should print the effective go.mod file as GoMod though. +go list -m -f '{{.GoMod}}' +stdout '^go.alt.mod$' + +# go mod edit should operate on the alternate file +go mod edit -require rsc.io/quote@v1.5.2 +grep rsc.io/quote go.alt.mod + +# 'go list -m' should add sums to the alternate go.sum. +go list -m -mod=mod all +grep '^rsc.io/quote v1.5.2/go.mod ' go.alt.sum +! grep '^rsc.io/quote v1.5.2 ' go.alt.sum + +# other 'go mod' commands should work. 'go mod vendor' is tested later. +go mod download rsc.io/quote +go mod graph +stdout rsc.io/quote +go mod tidy +grep rsc.io/quote go.alt.sum +go mod verify +go mod why rsc.io/quote + + +# 'go list' and other commands with build flags should work. +# They should update the alternate go.mod when a dependency is missing. +go mod edit -droprequire rsc.io/quote +go list -mod=mod . +grep rsc.io/quote go.alt.mod +go build -n -mod=mod . +go test -n -mod=mod . +go get rsc.io/quote + + +# 'go mod vendor' should work. +go mod vendor +exists vendor + +# Automatic vendoring should be broken by editing an explicit requirement +# in the alternate go.mod file. +go mod edit -require rsc.io/quote@v1.5.1 +! go list . +go list -mod=mod +rm vendor + + +# 'go generate' should use the alternate file when resolving packages. +# Recursive go commands started with 'go generate' should not get an explicitly +# passed -modfile, but they should see arguments from GOFLAGS. +cp go.alt.mod go.gen.mod +env OLD_GOFLAGS=$GOFLAGS +env GOFLAGS=-modfile=go.gen.mod +go generate -modfile=go.alt.mod . +env GOFLAGS=$OLD_GOFLAGS +grep example.com/exclude go.gen.mod +! grep example.com/exclude go.alt.mod + + +# The original files should not have been modified. +cmp go.mod go.mod.orig +cmp go.sum go.sum.orig + + +# If the alternate mod file does not have a ".mod" suffix, an error +# should be reported. +cp go.alt.mod goaltmod +! go mod tidy -modfile=goaltmod +stderr '-modfile=goaltmod: file does not have .mod extension' + +-- go.mod -- +ʕ◔ϖ◔ʔ +-- go.sum -- +ʕ◔ϖ◔ʔ +-- use.go -- +package main + +import _ "rsc.io/quote" +-- gen.go -- +//go:generate go mod edit -exclude example.com/exclude@v1.0.0 + +package main diff --git a/src/cmd/go/testdata/script/noncanonical_import.txt b/src/cmd/go/testdata/script/noncanonical_import.txt new file mode 100644 index 0000000..018cb01 --- /dev/null +++ b/src/cmd/go/testdata/script/noncanonical_import.txt @@ -0,0 +1,19 @@ +env GO111MODULE=off + +! go build canonical/d +stderr '^canonical[/\\]b[/\\]b.go:3:8: non-canonical import path "canonical/a/": should be "canonical/a"$' + +-- canonical/a/a.go -- +package a + +import _ "c" +-- canonical/b/b.go -- +package b + +import _ "canonical/a/" +-- canonical/a/vendor/c/c.go -- +package c +-- canonical/d/d.go -- +package d + +import _ "canonical/b" diff --git a/src/cmd/go/testdata/script/old_tidy_toolchain.txt b/src/cmd/go/testdata/script/old_tidy_toolchain.txt new file mode 100644 index 0000000..d4b5af2 --- /dev/null +++ b/src/cmd/go/testdata/script/old_tidy_toolchain.txt @@ -0,0 +1,28 @@ +# Commands in an old module with no go line and no toolchain line, +# or with only a go line, should succeed. +# (They should not fail due to the go.mod not being tidy.) + +# No go line, no toolchain line. +go list + +# Old go line, no toolchain line. +go mod edit -go=1.16 +go list + +go mod edit -go=1.20 +go list + +# New go line, no toolchain line, using same toolchain. +env TESTGO_VERSION=1.21 +go mod edit -go=1.21 +go list + +# New go line, no toolchain line, using newer Go version. +# (Until we need to update the go line, no toolchain addition.) +env TESTGO_VERSION=1.21.0 +go list + +-- go.mod -- +module m +-- p.go -- +package p diff --git a/src/cmd/go/testdata/script/pattern_syntax_error.txt b/src/cmd/go/testdata/script/pattern_syntax_error.txt new file mode 100644 index 0000000..9a1f5e5 --- /dev/null +++ b/src/cmd/go/testdata/script/pattern_syntax_error.txt @@ -0,0 +1,12 @@ +env GO111MODULE=off + +# patterns match directories with syntax errors +! go list ./... +! go build ./... +! go install ./... + +-- mypkg/x.go -- +package mypkg + +-- mypkg/y.go -- +pkg mypackage diff --git a/src/cmd/go/testdata/script/prevent_sys_unix_import.txt b/src/cmd/go/testdata/script/prevent_sys_unix_import.txt new file mode 100644 index 0000000..ea1ad78 --- /dev/null +++ b/src/cmd/go/testdata/script/prevent_sys_unix_import.txt @@ -0,0 +1,6 @@ +# Policy decision: we shouldn't vendor golang.org/x/sys/unix in std +# See https://golang.org/issue/32102 + +env GO111MODULE=on +go list std +! stdout vendor/golang.org/x/sys/unix diff --git a/src/cmd/go/testdata/script/repro_build.txt b/src/cmd/go/testdata/script/repro_build.txt new file mode 100644 index 0000000..7c6e317 --- /dev/null +++ b/src/cmd/go/testdata/script/repro_build.txt @@ -0,0 +1,22 @@ +# Check that goroutine scheduling does not affect compiler output. +# If it does, reproducible builds will not work very well. +[short] skip +[GOOS:aix] env CGO_ENABLED=0 # go.dev/issue/56896 +env GOMAXPROCS=16 +go build -a -o http16.o net/http +env GOMAXPROCS=17 +go build -a -o http17.o net/http +cmp -q http16.o http17.o +env GOMAXPROCS=18 +go build -a -o http18.o net/http +cmp -q http16.o http18.o + +# Check that goroutine scheduling does not affect linker output. +env GOMAXPROCS=16 +go build -a -o gofmt16.exe cmd/gofmt +env GOMAXPROCS=17 +go build -a -o gofmt17.exe cmd/gofmt +cmp -q gofmt16.exe gofmt17.exe +env GOMAXPROCS=18 +go build -a -o gofmt18.exe cmd/gofmt +cmp -q gofmt16.exe gofmt18.exe diff --git a/src/cmd/go/testdata/script/reuse_git.txt b/src/cmd/go/testdata/script/reuse_git.txt new file mode 100644 index 0000000..432f5a9 --- /dev/null +++ b/src/cmd/go/testdata/script/reuse_git.txt @@ -0,0 +1,376 @@ +[short] skip +[!git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +# go mod download with the pseudo-version should invoke git but not have a TagSum or Ref. +go mod download -x -json vcs-test.golang.org/git/hello.git@v0.0.0-20170922010558-fc3a09f3dc5c +stderr 'git fetch' +cp stdout hellopseudo.json +! stdout '"(Query|TagPrefix|TagSum|Ref)"' +stdout '"Version": "v0.0.0-20170922010558-fc3a09f3dc5c"' +stdout '"VCS": "git"' +stdout '"URL": ".*/git/hello"' +stdout '"Hash": "fc3a09f3dc5cfe0d7a743ea18f1f5226e68b3777"' +go clean -modcache + +# go mod download vcstest/hello should invoke git, print origin info +go mod download -x -json vcs-test.golang.org/git/hello.git@latest +stderr 'git fetch' +cp stdout hello.json +stdout '"Version": "v0.0.0-20170922010558-fc3a09f3dc5c"' +stdout '"VCS": "git"' +stdout '"URL": ".*/git/hello"' +stdout '"Query": "latest"' +! stdout '"TagPrefix"' +stdout '"TagSum": "t1:47DEQpj8HBSa[+]/TImW[+]5JCeuQeRkm5NMpJWZG3hSuFU="' +stdout '"Ref": "HEAD"' +stdout '"Hash": "fc3a09f3dc5cfe0d7a743ea18f1f5226e68b3777"' + +# pseudo-version again should not invoke git fetch (it has the version from the @latest query) +# but still be careful not to include a TagSum or a Ref, especially not Ref set to HEAD, +# which is easy to do when reusing the cached version from the @latest query. +go mod download -x -json vcs-test.golang.org/git/hello.git@v0.0.0-20170922010558-fc3a09f3dc5c +! stderr 'git fetch' +cp stdout hellopseudo2.json +cmpenv hellopseudo.json hellopseudo2.json + +# go mod download vcstest/hello@hash needs to check TagSum to find pseudoversion base. +go mod download -x -json vcs-test.golang.org/git/hello.git@fc3a09f3dc5c +! stderr 'git fetch' +cp stdout hellohash.json +stdout '"Version": "v0.0.0-20170922010558-fc3a09f3dc5c"' +stdout '"Query": "fc3a09f3dc5c"' +stdout '"VCS": "git"' +stdout '"URL": ".*/git/hello"' +stdout '"TagSum": "t1:47DEQpj8HBSa[+]/TImW[+]5JCeuQeRkm5NMpJWZG3hSuFU="' +stdout '"Hash": "fc3a09f3dc5cfe0d7a743ea18f1f5226e68b3777"' + +# go mod download vcstest/hello/v9 should fail, still print origin info +! go mod download -x -json vcs-test.golang.org/git/hello.git/v9@latest +cp stdout hellov9.json +stdout '"Version": "latest"' +stdout '"Error":.*no matching versions' +! stdout '"TagPrefix"' +stdout '"TagSum": "t1:47DEQpj8HBSa[+]/TImW[+]5JCeuQeRkm5NMpJWZG3hSuFU="' +stdout '"Ref": "HEAD"' +stdout '"Hash": "fc3a09f3dc5cfe0d7a743ea18f1f5226e68b3777"' +! stdout 'RepoSum' + +# go mod download vcstest/hello/sub/v9 should also fail, print origin info with TagPrefix +! go mod download -x -json vcs-test.golang.org/git/hello.git/sub/v9@latest +cp stdout hellosubv9.json +stdout '"Version": "latest"' +stdout '"Error":.*no matching versions' +stdout '"TagPrefix": "sub/"' +stdout '"TagSum": "t1:47DEQpj8HBSa[+]/TImW[+]5JCeuQeRkm5NMpJWZG3hSuFU="' +stdout '"Ref": "HEAD"' +stdout '"Hash": "fc3a09f3dc5cfe0d7a743ea18f1f5226e68b3777"' +! stdout 'RepoSum' + +# go mod download vcstest/hello@nonexist should fail, still print origin info +! go mod download -x -json vcs-test.golang.org/git/hello.git@nonexist +cp stdout hellononexist.json +stdout '"Version": "nonexist"' +stdout '"Error":.*unknown revision nonexist' +stdout '"RepoSum": "r1:c0/9JCZ25lxoBiK3[+]3BhACU4giH49flcJmBynJ[+]Jvmc="' +! stdout '"(TagPrefix|TagSum|Ref|Hash)"' + +# go mod download vcstest/hello@1234567890123456789012345678901234567890 should fail, still print origin info +# (40 hex digits is assumed to be a full hash and is a slightly different code path from @nonexist) +! go mod download -x -json vcs-test.golang.org/git/hello.git@1234567890123456789012345678901234567890 +cp stdout hellononhash.json +stdout '"Version": "1234567890123456789012345678901234567890"' +stdout '"Error":.*unknown revision 1234567890123456789012345678901234567890' +stdout '"RepoSum": "r1:c0/9JCZ25lxoBiK3[+]3BhACU4giH49flcJmBynJ[+]Jvmc="' +! stdout '"(TagPrefix|TagSum|Ref|Hash)"' + +# go mod download vcstest/hello@v0.0.0-20220101120101-123456789abc should fail, still print origin info +# (non-existent pseudoversion) +! go mod download -x -json vcs-test.golang.org/git/hello.git@v0.0.0-20220101120101-123456789abc +cp stdout hellononpseudo.json +stdout '"Version": "v0.0.0-20220101120101-123456789abc"' +stdout '"Error":.*unknown revision 123456789abc' +stdout '"RepoSum": "r1:c0/9JCZ25lxoBiK3[+]3BhACU4giH49flcJmBynJ[+]Jvmc="' +! stdout '"(TagPrefix|TagSum|Ref|Hash)"' + +# go mod download vcstest/tagtests should invoke git, print origin info +go mod download -x -json vcs-test.golang.org/git/tagtests.git@latest +stderr 'git fetch' +cp stdout tagtests.json +stdout '"Version": "v0.2.2"' +stdout '"Query": "latest"' +stdout '"VCS": "git"' +stdout '"URL": ".*/git/tagtests"' +! stdout '"TagPrefix"' +stdout '"TagSum": "t1:Dp7yRKDuE8WjG0429PN9hYWjqhy2te7P9Oki/sMEOGo="' +stdout '"Ref": "refs/tags/v0.2.2"' +stdout '"Hash": "59356c8cd18c5fe9a598167d98a6843e52d57952"' + +# go mod download vcstest/tagtests@v0.2.2 should print origin info, no TagSum needed +go mod download -x -json vcs-test.golang.org/git/tagtests.git@v0.2.2 +cp stdout tagtestsv022.json +stdout '"Version": "v0.2.2"' +! stdout '"Query":' +stdout '"VCS": "git"' +stdout '"URL": ".*/git/tagtests"' +! stdout '"TagPrefix"' +! stdout '"TagSum"' +stdout '"Ref": "refs/tags/v0.2.2"' +stdout '"Hash": "59356c8cd18c5fe9a598167d98a6843e52d57952"' + +# go mod download vcstest/tagtests@master needs a TagSum again +go mod download -x -json vcs-test.golang.org/git/tagtests.git@master +cp stdout tagtestsmaster.json +stdout '"Version": "v0.2.3-0.20190509225625-c7818c24fa2f"' +stdout '"Query": "master"' +stdout '"VCS": "git"' +stdout '"URL": ".*/git/tagtests"' +! stdout '"TagPrefix"' +stdout '"TagSum": "t1:Dp7yRKDuE8WjG0429PN9hYWjqhy2te7P9Oki/sMEOGo="' +stdout '"Ref": "refs/heads/master"' +stdout '"Hash": "c7818c24fa2f3f714c67d0a6d3e411c85a518d1f"' + +# go mod download vcstest/prefixtagtests should invoke git, print origin info +go mod download -x -json vcs-test.golang.org/git/prefixtagtests.git/sub@latest +stderr 'git fetch' +cp stdout prefixtagtests.json +stdout '"Version": "v0.0.10"' +stdout '"Query": "latest"' +stdout '"VCS": "git"' +stdout '"URL": ".*/git/prefixtagtests"' +stdout '"Subdir": "sub"' +stdout '"TagPrefix": "sub/"' +stdout '"TagSum": "t1:YGSbWkJ8dn9ORAr[+]BlKHFK/2ZhXLb9hVuYfTZ9D8C7g="' +stdout '"Ref": "refs/tags/sub/v0.0.10"' +stdout '"Hash": "2b7c4692e12c109263cab51b416fcc835ddd7eae"' + +# go mod download of a bunch of these should fail (some are invalid) but write good JSON for later +! go mod download -json vcs-test.golang.org/git/hello.git@latest vcs-test.golang.org/git/hello.git/v9@latest vcs-test.golang.org/git/hello.git/sub/v9@latest vcs-test.golang.org/git/tagtests.git@latest vcs-test.golang.org/git/tagtests.git@v0.2.2 vcs-test.golang.org/git/tagtests.git@master +cp stdout all.json + +# clean the module cache, make sure that makes go mod download re-run git fetch, clean again +go clean -modcache +go mod download -x -json vcs-test.golang.org/git/hello.git@latest +stderr 'git fetch' +go clean -modcache + +# reuse go mod download vcstest/hello result +go mod download -reuse=hello.json -x -json vcs-test.golang.org/git/hello.git@latest +! stderr 'git fetch' +stdout '"Reuse": true' +stdout '"Version": "v0.0.0-20170922010558-fc3a09f3dc5c"' +stdout '"VCS": "git"' +stdout '"URL": ".*/git/hello"' +! stdout '"TagPrefix"' +stdout '"TagSum": "t1:47DEQpj8HBSa[+]/TImW[+]5JCeuQeRkm5NMpJWZG3hSuFU="' +stdout '"Ref": "HEAD"' +stdout '"Hash": "fc3a09f3dc5cfe0d7a743ea18f1f5226e68b3777"' +! stdout '"Dir"' +! stdout '"Info"' +! stdout '"GoMod"' +! stdout '"Zip"' + +# reuse go mod download vcstest/hello pseudoversion result +go mod download -reuse=hellopseudo.json -x -json vcs-test.golang.org/git/hello.git@v0.0.0-20170922010558-fc3a09f3dc5c +! stderr 'git fetch' +stdout '"Reuse": true' +stdout '"Version": "v0.0.0-20170922010558-fc3a09f3dc5c"' +stdout '"VCS": "git"' +stdout '"URL": ".*/git/hello"' +! stdout '"(Query|TagPrefix|TagSum|Ref)"' +stdout '"Hash": "fc3a09f3dc5cfe0d7a743ea18f1f5226e68b3777"' +! stdout '"(Dir|Info|GoMod|Zip)"' + +# reuse go mod download vcstest/hello@hash +go mod download -reuse=hellohash.json -x -json vcs-test.golang.org/git/hello.git@fc3a09f3dc5c +! stderr 'git fetch' +stdout '"Reuse": true' +stdout '"Query": "fc3a09f3dc5c"' +stdout '"Version": "v0.0.0-20170922010558-fc3a09f3dc5c"' +stdout '"VCS": "git"' +stdout '"URL": ".*/git/hello"' +! stdout '"(TagPrefix|Ref)"' +stdout '"TagSum": "t1:47DEQpj8HBSa[+]/TImW[+]5JCeuQeRkm5NMpJWZG3hSuFU="' +stdout '"Hash": "fc3a09f3dc5cfe0d7a743ea18f1f5226e68b3777"' +! stdout '"(Dir|Info|GoMod|Zip)"' + +# reuse go mod download vcstest/hello/v9 error result +! go mod download -reuse=hellov9.json -x -json vcs-test.golang.org/git/hello.git/v9@latest +! stderr 'git fetch' +stdout '"Reuse": true' +stdout '"Error":.*no matching versions' +! stdout '"TagPrefix"' +stdout '"TagSum": "t1:47DEQpj8HBSa[+]/TImW[+]5JCeuQeRkm5NMpJWZG3hSuFU="' +stdout '"Ref": "HEAD"' +stdout '"Hash": "fc3a09f3dc5cfe0d7a743ea18f1f5226e68b3777"' +! stdout '"(Dir|Info|GoMod|Zip)"' + +# reuse go mod download vcstest/hello/sub/v9 error result +! go mod download -reuse=hellosubv9.json -x -json vcs-test.golang.org/git/hello.git/sub/v9@latest +! stderr 'git fetch' +stdout '"Reuse": true' +stdout '"Error":.*no matching versions' +stdout '"TagPrefix": "sub/"' +stdout '"TagSum": "t1:47DEQpj8HBSa[+]/TImW[+]5JCeuQeRkm5NMpJWZG3hSuFU="' +stdout '"Ref": "HEAD"' +stdout '"Hash": "fc3a09f3dc5cfe0d7a743ea18f1f5226e68b3777"' +! stdout '"(Dir|Info|GoMod|Zip)"' + +# reuse go mod download vcstest/hello@nonexist +! go mod download -reuse=hellononexist.json -x -json vcs-test.golang.org/git/hello.git@nonexist +! stderr 'git fetch' +stdout '"Reuse": true' +stdout '"Version": "nonexist"' +stdout '"Error":.*unknown revision nonexist' +stdout '"RepoSum": "r1:c0/9JCZ25lxoBiK3[+]3BhACU4giH49flcJmBynJ[+]Jvmc="' +! stdout '"(TagPrefix|TagSum|Ref|Hash)"' +! stdout '"(Dir|Info|GoMod|Zip)"' + +# reuse go mod download vcstest/hello@1234567890123456789012345678901234567890 +! go mod download -reuse=hellononhash.json -x -json vcs-test.golang.org/git/hello.git@1234567890123456789012345678901234567890 +! stderr 'git fetch' +stdout '"Reuse": true' +stdout '"Version": "1234567890123456789012345678901234567890"' +stdout '"Error":.*unknown revision 1234567890123456789012345678901234567890' +stdout '"RepoSum": "r1:c0/9JCZ25lxoBiK3[+]3BhACU4giH49flcJmBynJ[+]Jvmc="' +! stdout '"(TagPrefix|TagSum|Ref|Hash)"' +! stdout '"(Dir|Info|GoMod|Zip)"' + +# reuse go mod download vcstest/hello@v0.0.0-20220101120101-123456789abc +! go mod download -reuse=hellononpseudo.json -x -json vcs-test.golang.org/git/hello.git@v0.0.0-20220101120101-123456789abc +! stderr 'git fetch' +stdout '"Reuse": true' +stdout '"Version": "v0.0.0-20220101120101-123456789abc"' +stdout '"Error":.*unknown revision 123456789abc' +stdout '"RepoSum": "r1:c0/9JCZ25lxoBiK3[+]3BhACU4giH49flcJmBynJ[+]Jvmc="' +! stdout '"(TagPrefix|TagSum|Ref|Hash)"' +! stdout '"(Dir|Info|GoMod|Zip)"' + +# reuse go mod download vcstest/tagtests result +go mod download -reuse=tagtests.json -x -json vcs-test.golang.org/git/tagtests.git@latest +! stderr 'git fetch' +stdout '"Reuse": true' +stdout '"Version": "v0.2.2"' +stdout '"Query": "latest"' +stdout '"VCS": "git"' +stdout '"URL": ".*/git/tagtests"' +! stdout '"TagPrefix"' +stdout '"TagSum": "t1:Dp7yRKDuE8WjG0429PN9hYWjqhy2te7P9Oki/sMEOGo="' +stdout '"Ref": "refs/tags/v0.2.2"' +stdout '"Hash": "59356c8cd18c5fe9a598167d98a6843e52d57952"' +! stdout '"(Dir|Info|GoMod|Zip)"' + +# reuse go mod download vcstest/tagtests@v0.2.2 result +go mod download -reuse=tagtestsv022.json -x -json vcs-test.golang.org/git/tagtests.git@v0.2.2 +! stderr 'git fetch' +stdout '"Reuse": true' +stdout '"Version": "v0.2.2"' +! stdout '"Query":' +stdout '"VCS": "git"' +stdout '"URL": ".*/git/tagtests"' +! stdout '"TagPrefix"' +! stdout '"TagSum"' +stdout '"Ref": "refs/tags/v0.2.2"' +stdout '"Hash": "59356c8cd18c5fe9a598167d98a6843e52d57952"' +! stdout '"(Dir|Info|GoMod|Zip)"' + +# reuse go mod download vcstest/tagtests@master result +go mod download -reuse=tagtestsmaster.json -x -json vcs-test.golang.org/git/tagtests.git@master +! stderr 'git fetch' +stdout '"Reuse": true' +stdout '"Version": "v0.2.3-0.20190509225625-c7818c24fa2f"' +stdout '"Query": "master"' +stdout '"VCS": "git"' +stdout '"URL": ".*/git/tagtests"' +! stdout '"TagPrefix"' +stdout '"TagSum": "t1:Dp7yRKDuE8WjG0429PN9hYWjqhy2te7P9Oki/sMEOGo="' +stdout '"Ref": "refs/heads/master"' +stdout '"Hash": "c7818c24fa2f3f714c67d0a6d3e411c85a518d1f"' +! stdout '"(Dir|Info|GoMod|Zip)"' + +# reuse go mod download vcstest/tagtests@master result again with all.json +go mod download -reuse=all.json -x -json vcs-test.golang.org/git/tagtests.git@master +! stderr 'git fetch' +stdout '"Reuse": true' +stdout '"Version": "v0.2.3-0.20190509225625-c7818c24fa2f"' +stdout '"Query": "master"' +stdout '"VCS": "git"' +stdout '"URL": ".*/git/tagtests"' +! stdout '"TagPrefix"' +stdout '"TagSum": "t1:Dp7yRKDuE8WjG0429PN9hYWjqhy2te7P9Oki/sMEOGo="' +stdout '"Ref": "refs/heads/master"' +stdout '"Hash": "c7818c24fa2f3f714c67d0a6d3e411c85a518d1f"' +! stdout '"(Dir|Info|GoMod|Zip)"' + +# go mod download vcstest/prefixtagtests result with json +go mod download -reuse=prefixtagtests.json -x -json vcs-test.golang.org/git/prefixtagtests.git/sub@latest +! stderr 'git fetch' +stdout '"Version": "v0.0.10"' +stdout '"Query": "latest"' +stdout '"VCS": "git"' +stdout '"URL": ".*/git/prefixtagtests"' +stdout '"Subdir": "sub"' +stdout '"TagPrefix": "sub/"' +stdout '"TagSum": "t1:YGSbWkJ8dn9ORAr[+]BlKHFK/2ZhXLb9hVuYfTZ9D8C7g="' +stdout '"Ref": "refs/tags/sub/v0.0.10"' +stdout '"Hash": "2b7c4692e12c109263cab51b416fcc835ddd7eae"' +! stdout '"(Dir|Info|GoMod|Zip)"' + +# reuse the bulk results with all.json +! go mod download -reuse=all.json -json vcs-test.golang.org/git/hello.git@latest vcs-test.golang.org/git/hello.git/v9@latest vcs-test.golang.org/git/hello.git/sub/v9@latest vcs-test.golang.org/git/tagtests.git@latest vcs-test.golang.org/git/tagtests.git@v0.2.2 vcs-test.golang.org/git/tagtests.git@master +! stderr 'git fetch' +stdout '"Reuse": true' +! stdout '"(Dir|Info|GoMod|Zip)"' + +# reuse attempt with stale hash should reinvoke git, not report reuse +cp tagtestsv022.json tagtestsv022badhash.json +replace '57952' '56952XXX' tagtestsv022badhash.json +go mod download -reuse=tagtestsv022badhash.json -x -json vcs-test.golang.org/git/tagtests.git@v0.2.2 +stderr 'git fetch' +! stdout '"Reuse": true' +stdout '"Version": "v0.2.2"' +! stdout '"Query"' +stdout '"VCS": "git"' +stdout '"URL": ".*/git/tagtests"' +! stdout '"(TagPrefix|TagSum)"' +stdout '"Ref": "refs/tags/v0.2.2"' +stdout '"Hash": "59356c8cd18c5fe9a598167d98a6843e52d57952"' +stdout '"Dir"' +stdout '"Info"' +stdout '"GoMod"' +stdout '"Zip"' + +# reuse with stale repo URL +cp tagtestsv022.json tagtestsv022badurl.json +replace 'git/tagtests\"' 'git/tagtestsXXX\"' tagtestsv022badurl.json +go mod download -reuse=tagtestsv022badurl.json -x -json vcs-test.golang.org/git/tagtests.git@v0.2.2 +! stdout '"Reuse": true' +stdout '"URL": ".*/git/tagtests"' +stdout '"Dir"' +stdout '"Info"' +stdout '"GoMod"' +stdout '"Zip"' + +# reuse with stale VCS +cp tagtestsv022.json tagtestsv022badvcs.json +replace '\"git\"' '\"gitXXX\"' tagtestsv022badvcs.json +go mod download -reuse=tagtestsv022badvcs.json -x -json vcs-test.golang.org/git/tagtests.git@v0.2.2 +! stdout '"Reuse": true' +stdout '"URL": ".*/git/tagtests"' + +# reuse with stale Dir +cp tagtestsv022.json tagtestsv022baddir.json +replace '\t\t\"Ref\":' '\t\t\"Subdir\": \"subdir\",\n\t\t\"Ref\":' tagtestsv022baddir.json +go mod download -reuse=tagtestsv022baddir.json -x -json vcs-test.golang.org/git/tagtests.git@v0.2.2 +! stdout '"Reuse": true' +stdout '"URL": ".*/git/tagtests"' + +# reuse with stale TagSum +cp tagtests.json tagtestsbadtagsum.json +replace 'sMEOGo=' 'sMEoGo=XXX' tagtestsbadtagsum.json +go mod download -reuse=tagtestsbadtagsum.json -x -json vcs-test.golang.org/git/tagtests.git@latest +! stdout '"Reuse": true' +stdout '"TagSum": "t1:Dp7yRKDuE8WjG0429PN9hYWjqhy2te7P9Oki/sMEOGo="' diff --git a/src/cmd/go/testdata/script/run_dirs.txt b/src/cmd/go/testdata/script/run_dirs.txt new file mode 100644 index 0000000..bd5cfbe --- /dev/null +++ b/src/cmd/go/testdata/script/run_dirs.txt @@ -0,0 +1,21 @@ +cd rundir + +! go run x.go sub/sub.go +stderr 'named files must all be in one directory; have . and sub' +! go run sub/sub.go x.go +stderr 'named files must all be in one directory; have sub and .' + +cd ../ +go run rundir/foo.go ./rundir/bar.go +stderr 'hello world' + +-- rundir/sub/sub.go -- +package main +-- rundir/x.go -- +package main +-- rundir/foo.go -- +package main +func main() { println(msg) } +-- rundir/bar.go -- +package main +const msg = "hello world" diff --git a/src/cmd/go/testdata/script/run_hello.txt b/src/cmd/go/testdata/script/run_hello.txt new file mode 100644 index 0000000..939b661 --- /dev/null +++ b/src/cmd/go/testdata/script/run_hello.txt @@ -0,0 +1,9 @@ +env GO111MODULE=off + +# hello world +go run hello.go +stderr 'hello world' + +-- hello.go -- +package main +func main() { println("hello world") } diff --git a/src/cmd/go/testdata/script/run_hello_pkg.txt b/src/cmd/go/testdata/script/run_hello_pkg.txt new file mode 100644 index 0000000..ea2b4d7 --- /dev/null +++ b/src/cmd/go/testdata/script/run_hello_pkg.txt @@ -0,0 +1,17 @@ +go run m/hello +stderr 'hello, world' + +cd hello +go run . +stderr 'hello, world' + +-- go.mod -- +module m + +go 1.16 +-- hello/hello.go -- +package main + +func main() { + println("hello, world") +} diff --git a/src/cmd/go/testdata/script/run_internal.txt b/src/cmd/go/testdata/script/run_internal.txt new file mode 100644 index 0000000..d021850 --- /dev/null +++ b/src/cmd/go/testdata/script/run_internal.txt @@ -0,0 +1,64 @@ +env GO111MODULE=off + +go list -e -f '{{.Incomplete}}' m/runbad1.go +stdout true +! go run m/runbad1.go +stderr 'use of internal package m/x/internal not allowed' + +go list -e -f '{{.Incomplete}}' m/runbad2.go +stdout true +! go run m/runbad2.go +stderr 'use of internal package m/x/internal/y not allowed' + +go list -e -f '{{.Incomplete}}' m/runok.go +stdout false +go run m/runok.go + +cd m +env GO111MODULE=on + +go list -e -f '{{.Incomplete}}' runbad1.go +stdout true +! go run runbad1.go +stderr 'use of internal package m/x/internal not allowed' + +go list -e -f '{{.Incomplete}}' runbad2.go +stdout true +! go run runbad2.go +stderr 'use of internal package m/x/internal/y not allowed' + +go list -e -f '{{.Incomplete}}' runok.go +stdout false +go run runok.go + + +-- m/go.mod -- +module m + +-- m/x/internal/internal.go -- +package internal + +-- m/x/internal/y/y.go -- +package y + +-- m/internal/internal.go -- +package internal + +-- m/internal/z/z.go -- +package z + +-- m/runbad1.go -- +package main +import _ "m/x/internal" +func main() {} + +-- m/runbad2.go -- +package main +import _ "m/x/internal/y" +func main() {} + +-- m/runok.go -- +package main +import _ "m/internal" +import _ "m/internal/z" +func main() {} diff --git a/src/cmd/go/testdata/script/run_issue11709.txt b/src/cmd/go/testdata/script/run_issue11709.txt new file mode 100644 index 0000000..c8ba998 --- /dev/null +++ b/src/cmd/go/testdata/script/run_issue11709.txt @@ -0,0 +1,15 @@ +# 'go run' should not pass extraneous environment variables to the subprocess. +go run run.go +! stdout . +! stderr . + +-- run.go -- +package main + +import "os" + +func main() { + if os.Getenv("TERM") != "" { + os.Exit(1) + } +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/run_issue51125.txt b/src/cmd/go/testdata/script/run_issue51125.txt new file mode 100644 index 0000000..8fa4486 --- /dev/null +++ b/src/cmd/go/testdata/script/run_issue51125.txt @@ -0,0 +1,54 @@ +# Regression test for https://go.dev/issue/51125: +# Relative import paths (a holdover from GOPATH) were accidentally allowed in module mode. + +cd $WORK + +# Relative imports should not be allowed with a go.mod file. + +! go run driver.go +stderr '^driver.go:3:8: "./mypkg" is relative, but relative import paths are not supported in module mode$' + +go list -e -f '{{with .Error}}{{.}}{{end}}' -deps driver.go +stdout '^driver.go:3:8: "./mypkg" is relative, but relative import paths are not supported in module mode$' +! stderr . + + +# Relative imports should not be allowed in module mode even without a go.mod file. +rm go.mod + +! go run driver.go +stderr '^driver.go:3:8: "./mypkg" is relative, but relative import paths are not supported in module mode$' + +go list -e -f '{{with .Error}}{{.}}{{end}}' -deps driver.go +stdout '^driver.go:3:8: "./mypkg" is relative, but relative import paths are not supported in module mode$' +! stderr . + + +# In GOPATH mode, they're still allowed (but only outside of GOPATH/src). +env GO111MODULE=off + +[!short] go run driver.go + +go list -deps driver.go + + +-- $WORK/go.mod -- +module example + +go 1.17 +-- $WORK/driver.go -- +package main + +import "./mypkg" + +func main() { + mypkg.MyFunc() +} +-- $WORK/mypkg/code.go -- +package mypkg + +import "fmt" + +func MyFunc() { + fmt.Println("Hello, world!") +} diff --git a/src/cmd/go/testdata/script/run_set_executable_name.txt b/src/cmd/go/testdata/script/run_set_executable_name.txt new file mode 100644 index 0000000..54ddee9 --- /dev/null +++ b/src/cmd/go/testdata/script/run_set_executable_name.txt @@ -0,0 +1,50 @@ +env GO111MODULE=on +[short] skip + +# Check for correct naming of temporary executable + +#Test for single file specified +cd x/y/z +go run foo.go +stderr 'foo' + +#Test for current directory +go run . +stderr 'z' + +#Test for set path +go run m/x/y/z/ +stderr 'z' + +-- m/x/y/z/foo.go -- +package main +import( + "os" + "path/filepath" +) +func main() { + println(filepath.Base(os.Args[0])) +} + +-- x/y/z/foo.go -- +package main +import( + "os" + "path/filepath" +) +func main() { + println(filepath.Base(os.Args[0])) +} + +-- x/y/z/foo.go -- +package main +import( + "os" + "path/filepath" +) +func main() { + println(filepath.Base(os.Args[0])) +} + +-- go.mod -- +module m
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/run_vendor.txt b/src/cmd/go/testdata/script/run_vendor.txt new file mode 100644 index 0000000..46cac06 --- /dev/null +++ b/src/cmd/go/testdata/script/run_vendor.txt @@ -0,0 +1,34 @@ +# Run +env GO111MODULE=off +cd vend/hello +go run hello.go +stdout 'hello, world' + +-- vend/hello/hello.go -- +package main + +import ( + "fmt" + "strings" // really ../vendor/strings +) + +func main() { + fmt.Printf("%s\n", strings.Msg) +} +-- vend/hello/hello_test.go -- +package main + +import ( + "strings" // really ../vendor/strings + "testing" +) + +func TestMsgInternal(t *testing.T) { + if strings.Msg != "hello, world" { + t.Fatalf("unexpected msg: %v", strings.Msg) + } +} +-- vend/vendor/strings/msg.go -- +package strings + +var Msg = "hello, world" diff --git a/src/cmd/go/testdata/script/run_wildcard.txt b/src/cmd/go/testdata/script/run_wildcard.txt new file mode 100644 index 0000000..3e7e7b7 --- /dev/null +++ b/src/cmd/go/testdata/script/run_wildcard.txt @@ -0,0 +1,7 @@ +env GO111MODULE=off + +# Fix for https://github.com/golang/go/issues/28696: +# go run x/... should not panic when directory x doesn't exist. + +! go run nonexistent/... +stderr '^go: no packages loaded from nonexistent/...$' diff --git a/src/cmd/go/testdata/script/run_work_versioned.txt b/src/cmd/go/testdata/script/run_work_versioned.txt new file mode 100644 index 0000000..eb0f22d --- /dev/null +++ b/src/cmd/go/testdata/script/run_work_versioned.txt @@ -0,0 +1,16 @@ +[short] skip +go run example.com/printversion@v0.1.0 +stdout '^main is example.com/printversion v0.1.0$' + +-- go.work -- +go 1.18 + +use ( + . +) +-- go.mod -- +module example + +go 1.18 + +require example.com/printversion v1.0.0 diff --git a/src/cmd/go/testdata/script/script_help.txt b/src/cmd/go/testdata/script/script_help.txt new file mode 100644 index 0000000..dd7f203 --- /dev/null +++ b/src/cmd/go/testdata/script/script_help.txt @@ -0,0 +1,7 @@ +help -v + +# To see help for a specific command or condition, run 'help' for it here. +# For example: +help wait +help [verbose] +help [exec:bash] diff --git a/src/cmd/go/testdata/script/script_wait.txt b/src/cmd/go/testdata/script/script_wait.txt new file mode 100644 index 0000000..f253060 --- /dev/null +++ b/src/cmd/go/testdata/script/script_wait.txt @@ -0,0 +1,28 @@ +env GO111MODULE=off + +[!exec:echo] skip +[!exec:false] skip + +exec echo foo +stdout foo + +exec echo foo & +exec echo bar & +! exec false & + +# Starting a background process should clear previous output. +! stdout foo + +# Wait should set the output to the concatenated outputs of the background +# programs, in the order in which they were started. +wait +stdout 'foo\nbar' + +# The end of the test should interrupt or kill any remaining background +# programs, but that should not cause the test to fail if it does not +# care about the exit status of those programs. +[exec:sleep] ? exec sleep 86400 & + +# It should also cancel any backgrounded builtins that respond to Context +# cancellation. +? sleep 86400s & diff --git a/src/cmd/go/testdata/script/slashpath.txt b/src/cmd/go/testdata/script/slashpath.txt new file mode 100644 index 0000000..22b3e9d --- /dev/null +++ b/src/cmd/go/testdata/script/slashpath.txt @@ -0,0 +1,18 @@ +# .a files should use slash-separated paths even on windows +# This is important for reproducing native builds with cross-compiled builds. +go build -o x.a text/template +! grep 'GOROOT\\' x.a +! grep 'text\\template' x.a +! grep 'c:\\' x.a + +# executables should use slash-separated paths even on windows +# This is important for reproducing native builds with cross-compiled builds. +go build -o hello.exe hello.go +! grep 'GOROOT\\' hello.exe +! grep '\\runtime' hello.exe +! grep 'runtime\\' hello.exe +! grep 'gofile..[A-Za-z]:\\' hello.exe + +-- hello.go -- +package main +func main() { println("hello") } diff --git a/src/cmd/go/testdata/script/src_file.txt b/src/cmd/go/testdata/script/src_file.txt new file mode 100644 index 0000000..8d5c20b --- /dev/null +++ b/src/cmd/go/testdata/script/src_file.txt @@ -0,0 +1,9 @@ +# Files in src should not be treated as packages + +exists $GOROOT/src/regexp/testdata/README +go list -f '{{.Dir}}' regexp/testdata/README + +-- go.mod -- +module regexp/testdata/README +-- p.go -- +package p diff --git a/src/cmd/go/testdata/script/std_vendor.txt b/src/cmd/go/testdata/script/std_vendor.txt new file mode 100644 index 0000000..731ee9e --- /dev/null +++ b/src/cmd/go/testdata/script/std_vendor.txt @@ -0,0 +1,43 @@ +env GO111MODULE=off + +[!compiler:gc] skip + +# 'go list' should report imports from _test.go in the TestImports field. +go list -f '{{.TestImports}}' +stdout net/http # from .TestImports + +# 'go list' should report standard-vendored packages by path. +go list -f '{{.Dir}}' vendor/golang.org/x/net/http2/hpack +stdout $GOROOT[/\\]src[/\\]vendor + +# 'go list -test' should report vendored transitive dependencies of _test.go +# imports in the Deps field, with a 'vendor' prefix on their import paths. +go list -test -f '{{.Deps}}' +stdout golang.org/x/crypto # dep of .TestImports + +# Packages outside the standard library should not use its copy of vendored packages. +cd broken +! go build +stderr 'cannot find package' + +-- go.mod -- +module m + +-- x.go -- +package x + +-- x_test.go -- +package x +import "testing" +import _ "net/http" +func Test(t *testing.T) {} + +-- broken/go.mod -- +module broken +-- broken/http.go -- +package broken + +import ( + _ "net/http" + _ "golang.org/x/net/http/httpproxy" +) diff --git a/src/cmd/go/testdata/script/test2json_interrupt.txt b/src/cmd/go/testdata/script/test2json_interrupt.txt new file mode 100644 index 0000000..763c336 --- /dev/null +++ b/src/cmd/go/testdata/script/test2json_interrupt.txt @@ -0,0 +1,58 @@ +[short] skip 'links and runs a test binary' +[!fuzz] skip 'tests SIGINT behavior for interrupting fuzz tests' +[GOOS:windows] skip 'windows does not support os.Interrupt' + +? go test -json -fuzz FuzzInterrupt -run '^$' -parallel 1 +stdout -count=1 '"Action":"pass","Package":"example","Test":"FuzzInterrupt"' +stdout -count=1 '"Action":"pass","Package":"example","Elapsed":' + +mkdir $WORK/fuzzcache +go test -c . -fuzz=. -o example_test.exe +? go tool test2json -p example -t ./example_test.exe -test.v -test.paniconexit0 -test.fuzzcachedir $WORK/fuzzcache -test.fuzz FuzzInterrupt -test.run '^$' -test.parallel 1 +stdout -count=1 '"Action":"pass","Package":"example","Test":"FuzzInterrupt"' +stdout -count=1 '"Action":"pass","Package":"example","Elapsed":' + +-- go.mod -- +module example +go 1.20 +-- example_test.go -- +package example_test + +import ( + "fmt" + "os" + "strconv" + "testing" + "strings" + "time" +) + +func FuzzInterrupt(f *testing.F) { + pids := os.Getenv("GO_TEST_INTERRUPT_PIDS") + if pids == "" { + // This is the main test process. + // Set the environment variable for fuzz workers. + pid := os.Getpid() + ppid := os.Getppid() + os.Setenv("GO_TEST_INTERRUPT_PIDS", fmt.Sprintf("%d,%d", ppid, pid)) + } + + sentInterrupt := false + f.Fuzz(func(t *testing.T, orig string) { + if !sentInterrupt { + // Simulate a ctrl-C on the keyboard by sending SIGINT + // to the main test process and its parent. + for _, pid := range strings.Split(pids, ",") { + i, err := strconv.Atoi(pid) + if err != nil { + t.Fatal(err) + } + if p, err := os.FindProcess(i); err == nil { + p.Signal(os.Interrupt) + sentInterrupt = true // Only send interrupts once. + } + } + } + time.Sleep(1 * time.Millisecond) // Delay the fuzzer a bit to avoid wasting CPU. + }) +} diff --git a/src/cmd/go/testdata/script/test_android_issue62123.txt b/src/cmd/go/testdata/script/test_android_issue62123.txt new file mode 100644 index 0000000..2f46a6b --- /dev/null +++ b/src/cmd/go/testdata/script/test_android_issue62123.txt @@ -0,0 +1,19 @@ +env GOOS=android GOARCH=amd64 CGO_ENABLED=0 + +! go build -o $devnull cmd/buildid +stderr 'android/amd64 requires external \(cgo\) linking, but cgo is not enabled' +! stderr 'cannot find runtime/cgo' + +! go test -c -o $devnull os +stderr '# os\nandroid/amd64 requires external \(cgo\) linking, but cgo is not enabled' +! stderr 'cannot find runtime/cgo' + +env GOOS=ios GOARCH=arm64 CGO_ENABLED=0 + +! go build -o $devnull cmd/buildid +stderr 'ios/arm64 requires external \(cgo\) linking, but cgo is not enabled' +! stderr 'cannot find runtime/cgo' + +! go test -c -o $devnull os +stderr '# os\nios/arm64 requires external \(cgo\) linking, but cgo is not enabled' +! stderr 'cannot find runtime/cgo' diff --git a/src/cmd/go/testdata/script/test_bad_example.txt b/src/cmd/go/testdata/script/test_bad_example.txt new file mode 100644 index 0000000..1d147b6 --- /dev/null +++ b/src/cmd/go/testdata/script/test_bad_example.txt @@ -0,0 +1,13 @@ +# Tests that invalid examples are ignored. +# Verifies golang.org/issue/35284 +go test x_test.go + +-- x_test.go -- +package x + +import "fmt" + +func ExampleThisShouldNotHaveAParameter(thisShouldntExist int) { + fmt.Println("X") + // Output: +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_badtest.txt b/src/cmd/go/testdata/script/test_badtest.txt new file mode 100644 index 0000000..e79fc51 --- /dev/null +++ b/src/cmd/go/testdata/script/test_badtest.txt @@ -0,0 +1,49 @@ +env GO111MODULE=off + +! go test badtest/badexec +! stdout ^ok +stdout ^FAIL\tbadtest/badexec + +! go test badtest/badsyntax +! stdout ^ok +stdout ^FAIL\tbadtest/badsyntax + +! go test badtest/badvar +! stdout ^ok +stdout ^FAIL\tbadtest/badvar + +! go test notest +! stdout ^ok +stderr '^notest.hello.go:6:1: syntax error: non-declaration statement outside function body' # Exercise issue #7108 + +-- badtest/badexec/x_test.go -- +package badexec + +func init() { + panic("badexec") +} + +-- badtest/badsyntax/x.go -- +package badsyntax + +-- badtest/badsyntax/x_test.go -- +package badsyntax + +func func func func func! + +-- badtest/badvar/x.go -- +package badvar + +-- badtest/badvar/x_test.go -- +package badvar_test + +func f() { + _ = notdefined +} +-- notest/hello.go -- +package notest + +func hello() { + println("hello world") +} +Hello world
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_benchmark_1x.txt b/src/cmd/go/testdata/script/test_benchmark_1x.txt new file mode 100644 index 0000000..b1d4c39 --- /dev/null +++ b/src/cmd/go/testdata/script/test_benchmark_1x.txt @@ -0,0 +1,37 @@ +# Test that -benchtime 1x only runs a total of 1 loop iteration. +# See golang.org/issue/32051. + +go test -run ^$ -bench . -benchtime 1x + +-- go.mod -- +module bench + +go 1.16 +-- x_test.go -- +package bench + +import ( + "fmt" + "os" + "testing" +) + +var called = false + +func TestMain(m *testing.M) { + m.Run() + if !called { + fmt.Println("benchmark never called") + os.Exit(1) + } +} + +func Benchmark(b *testing.B) { + if b.N > 1 { + b.Fatalf("called with b.N=%d; want b.N=1 only", b.N) + } + if called { + b.Fatal("called twice") + } + called = true +} diff --git a/src/cmd/go/testdata/script/test_benchmark_chatty_fail.txt b/src/cmd/go/testdata/script/test_benchmark_chatty_fail.txt new file mode 100644 index 0000000..6031ead --- /dev/null +++ b/src/cmd/go/testdata/script/test_benchmark_chatty_fail.txt @@ -0,0 +1,32 @@ +# Run chatty tests. Assert on CONT lines. +! go test chatty_test.go -v -bench . chatty_bench + +# Sanity check that output occurs. +stdout -count=2 'this is sub-0' +stdout -count=2 'this is sub-1' +stdout -count=2 'this is sub-2' +stdout -count=1 'error from sub-0' +stdout -count=1 'error from sub-1' +stdout -count=1 'error from sub-2' + +# Benchmarks should not print CONT. +! stdout CONT + +-- chatty_test.go -- +package chatty_bench + +import ( + "testing" + "fmt" +) + +func BenchmarkChatty(b *testing.B) { + for i := 0; i < 3; i++ { + b.Run(fmt.Sprintf("sub-%d", i), func(b *testing.B) { + for j := 0; j < 2; j++ { + b.Logf("this is sub-%d", i) + } + b.Errorf("error from sub-%d", i) + }) + } +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_benchmark_chatty_success.txt b/src/cmd/go/testdata/script/test_benchmark_chatty_success.txt new file mode 100644 index 0000000..a1c0d65 --- /dev/null +++ b/src/cmd/go/testdata/script/test_benchmark_chatty_success.txt @@ -0,0 +1,29 @@ +# Run chatty tests. Assert on CONT lines. +go test chatty_test.go -v -bench . chatty_bench + +# Sanity check that output happens. We don't provide -count because the amount +# of output is variable. +stdout 'this is sub-0' +stdout 'this is sub-1' +stdout 'this is sub-2' + +# Benchmarks should not print CONT. +! stdout CONT + +-- chatty_test.go -- +package chatty_bench + +import ( + "testing" + "fmt" +) + +func BenchmarkChatty(b *testing.B) { + for i := 0; i < 3; i++ { + b.Run(fmt.Sprintf("sub-%d", i), func(b *testing.B) { + for j := 0; j < 2; j++ { + b.Logf("this is sub-%d", i) + } + }) + } +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_benchmark_fatal.txt b/src/cmd/go/testdata/script/test_benchmark_fatal.txt new file mode 100644 index 0000000..e281379 --- /dev/null +++ b/src/cmd/go/testdata/script/test_benchmark_fatal.txt @@ -0,0 +1,19 @@ +# Test that calling t.Fatal in a benchmark causes a non-zero exit status. + +! go test -run '^$' -bench . benchfatal +! stdout ^ok +! stderr ^ok +stdout FAIL.*benchfatal + +-- go.mod -- +module benchfatal + +go 1.16 +-- x_test.go -- +package benchfatal + +import "testing" + +func BenchmarkThatCallsFatal(b *testing.B) { + b.Fatal("called by benchmark") +} diff --git a/src/cmd/go/testdata/script/test_benchmark_labels.txt b/src/cmd/go/testdata/script/test_benchmark_labels.txt new file mode 100644 index 0000000..6b424c1 --- /dev/null +++ b/src/cmd/go/testdata/script/test_benchmark_labels.txt @@ -0,0 +1,23 @@ +# Tests that go test -bench prints out goos, goarch, and pkg. + +# Check for goos, goarch, and pkg. +go test -run ^$ -bench . bench +stdout '^goos: '$GOOS +stdout '^goarch: '$GOARCH +stdout '^pkg: bench' + +# Check go test does not print pkg multiple times +! stdout 'pkg:.*pkg: ' +! stderr 'pkg:.*pkg:' + +-- go.mod -- +module bench + +go 1.16 +-- x_test.go -- +package bench + +import "testing" + +func Benchmark(b *testing.B) { +} diff --git a/src/cmd/go/testdata/script/test_benchmark_timeout.txt b/src/cmd/go/testdata/script/test_benchmark_timeout.txt new file mode 100644 index 0000000..4bae7e7 --- /dev/null +++ b/src/cmd/go/testdata/script/test_benchmark_timeout.txt @@ -0,0 +1,18 @@ +# Tests issue #18845 +[short] skip + +go test -bench . -timeout=750ms timeoutbench_test.go +stdout ok +stdout PASS + +-- timeoutbench_test.go -- +package timeoutbench_test + +import ( + "testing" + "time" +) + +func BenchmarkSleep1s(b *testing.B) { + time.Sleep(1 * time.Second) +} diff --git a/src/cmd/go/testdata/script/test_build_failure.txt b/src/cmd/go/testdata/script/test_build_failure.txt new file mode 100644 index 0000000..e8c984f --- /dev/null +++ b/src/cmd/go/testdata/script/test_build_failure.txt @@ -0,0 +1,31 @@ +[short] skip + +! go test -x coverbad +! stderr '[\\/]coverbad\.test( |$)' # 'go test' should not claim to have run the test. +stderr 'undefined: g' +[cgo] stderr 'undefined: j' + +-- go.mod -- +module coverbad + +go 1.16 +-- p.go -- +package p + +func f() { + g() +} +-- p1.go -- +package p + +import "C" + +func h() { + j() +} +-- p_test.go -- +package p + +import "testing" + +func Test(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/test_buildvcs.txt b/src/cmd/go/testdata/script/test_buildvcs.txt new file mode 100644 index 0000000..db844f8 --- /dev/null +++ b/src/cmd/go/testdata/script/test_buildvcs.txt @@ -0,0 +1,104 @@ +# https://go.dev/issue/51723: 'go test' should not stamp VCS metadata +# in the build settings. (It isn't worth the latency hit, given that +# test binaries are almost never distributed to users.) + +[short] skip +[!git] skip + +exec git init + +# The test binaries should not have VCS settings stamped by default. +# (The test itself verifies that.) +go test . ./testonly + +# However, setting -buildvcs explicitly should override that and +# stamp anyway (https://go.dev/issue/52648). +go test -buildvcs -c -o ./testonly.exe ./testonly +! exec ./testonly.exe +stdout 'unexpected VCS setting: vcs\.modified=true' + + +# Remove 'git' from $PATH. The test should still build. +# This ensures that we aren't loading VCS metadata that +# we subsequently throw away. +env PATH='' +env path='' + +# Compiling the test should not require the VCS tool. +go test -c -o $devnull . + + +# When listing a main package, in general we need its VCS metadata to determine +# the .Stale and .StaleReason fields. +! go list -buildvcs=true . +stderr '^go: missing Git command\. See https://golang\.org/s/gogetcmd\nerror obtaining VCS status: .*\n\tUse -buildvcs=false to disable VCS stamping.' + +# Adding the -test flag should be strictly additive — it should not suppress the error. +! go list -buildvcs=true -test . +stderr '^go: missing Git command\. See https://golang\.org/s/gogetcmd\nerror obtaining VCS status: .*\n\tUse -buildvcs=false to disable VCS stamping.' + +# Adding the suggested flag should suppress the error. +go list -test -buildvcs=false . +! stderr . + + +# Since the ./testonly package doesn't itself produce an actual binary, we shouldn't +# invoke a VCS tool to compute a build stamp by default when listing it. +go list ./testonly +! stderr . +go list -test ./testonly +! stderr . + +# Again, setting -buildvcs explicitly should force the use of the VCS tool. +! go list -buildvcs ./testonly +stderr '^go: missing Git command\. See https://golang\.org/s/gogetcmd\nerror obtaining VCS status: .*\n\tUse -buildvcs=false to disable VCS stamping.' +! go list -buildvcs -test ./testonly +stderr '^go: missing Git command\. See https://golang\.org/s/gogetcmd\nerror obtaining VCS status: .*\n\tUse -buildvcs=false to disable VCS stamping.' + + +-- go.mod -- +module example + +go 1.18 +-- example.go -- +package main +-- example_test.go -- +package main + +import ( + "runtime/debug" + "strings" + "testing" +) + +func TestDetail(t *testing.T) { + bi, ok := debug.ReadBuildInfo() + if !ok { + t.Fatal("BuildInfo not present") + } + for _, s := range bi.Settings { + if strings.HasPrefix(s.Key, "vcs.") { + t.Fatalf("unexpected VCS setting: %s=%s", s.Key, s.Value) + } + } +} +-- testonly/main_test.go -- +package main + +import ( + "runtime/debug" + "strings" + "testing" +) + +func TestDetail(t *testing.T) { + bi, ok := debug.ReadBuildInfo() + if !ok { + t.Fatal("BuildInfo not present") + } + for _, s := range bi.Settings { + if strings.HasPrefix(s.Key, "vcs.") { + t.Fatalf("unexpected VCS setting: %s=%s", s.Key, s.Value) + } + } +} diff --git a/src/cmd/go/testdata/script/test_cache_inputs.txt b/src/cmd/go/testdata/script/test_cache_inputs.txt new file mode 100644 index 0000000..3705c70 --- /dev/null +++ b/src/cmd/go/testdata/script/test_cache_inputs.txt @@ -0,0 +1,270 @@ +env GO111MODULE=off + +# Test that cached test results are invalidated in response to +# changes to the external inputs to the test. + +[short] skip +[GODEBUG:gocacheverify=1] skip + +# We're testing cache behavior, so start with a clean GOCACHE. +env GOCACHE=$WORK/cache + +# Build a helper binary to invoke os.Chtimes. +go build -o mkold$GOEXE mkold.go + +# Make test input files appear to be a minute old. +exec ./mkold$GOEXE 1m testcache/file.txt +exec ./mkold$GOEXE 1m testcache/script.sh + +# If the test reads an environment variable, changes to that variable +# should invalidate cached test results. +env TESTKEY=x +go test testcache -run=TestLookupEnv +go test testcache -run=TestLookupEnv +stdout '\(cached\)' + +env TESTKEY=y +go test testcache -run=TestLookupEnv +! stdout '\(cached\)' +go test testcache -run=TestLookupEnv +stdout '\(cached\)' + +# Changes in arguments forwarded to the test should invalidate cached test +# results. +go test testcache -run=TestOSArgs -v hello +! stdout '\(cached\)' +stdout 'hello' +go test testcache -run=TestOSArgs -v goodbye +! stdout '\(cached\)' +stdout 'goodbye' + +# golang.org/issue/36134: that includes the `-timeout` argument. +go test testcache -run=TestOSArgs -timeout=20m -v +! stdout '\(cached\)' +stdout '-test\.timeout[= ]20m' +go test testcache -run=TestOSArgs -timeout=5s -v +! stdout '\(cached\)' +stdout '-test\.timeout[= ]5s' + +# If the test stats a file, changes to the file should invalidate the cache. +go test testcache -run=FileSize +go test testcache -run=FileSize +stdout '\(cached\)' + +cp 4x.txt testcache/file.txt +go test testcache -run=FileSize +! stdout '\(cached\)' +go test testcache -run=FileSize +stdout '\(cached\)' + +# Files should be tracked even if the test changes its working directory. +go test testcache -run=Chdir +go test testcache -run=Chdir +stdout '\(cached\)' +cp 6x.txt testcache/file.txt +go test testcache -run=Chdir +! stdout '\(cached\)' +go test testcache -run=Chdir +stdout '\(cached\)' + +# The content of files should affect caching, provided that the mtime also changes. +exec ./mkold$GOEXE 1m testcache/file.txt +go test testcache -run=FileContent +go test testcache -run=FileContent +stdout '\(cached\)' +cp 2y.txt testcache/file.txt +exec ./mkold$GOEXE 50s testcache/file.txt +go test testcache -run=FileContent +! stdout '\(cached\)' +go test testcache -run=FileContent +stdout '\(cached\)' + +# Directory contents read via os.ReadDirNames should affect caching. +go test testcache -run=DirList +go test testcache -run=DirList +stdout '\(cached\)' +rm testcache/file.txt +go test testcache -run=DirList +! stdout '\(cached\)' +go test testcache -run=DirList +stdout '\(cached\)' + +# Files outside GOROOT and GOPATH should not affect caching. +env TEST_EXTERNAL_FILE=$WORK/external.txt +go test testcache -run=ExternalFile +go test testcache -run=ExternalFile +stdout '\(cached\)' + +rm $WORK/external.txt +go test testcache -run=ExternalFile +stdout '\(cached\)' + +# The -benchtime flag without -bench should not affect caching. +go test testcache -run=Benchtime -benchtime=1x +go test testcache -run=Benchtime -benchtime=1x +stdout '\(cached\)' + +go test testcache -run=Benchtime -bench=Benchtime -benchtime=1x +go test testcache -run=Benchtime -bench=Benchtime -benchtime=1x +! stdout '\(cached\)' + +# golang.org/issue/47355: that includes the `-failfast` argument. +go test testcache -run=TestOSArgs -failfast +! stdout '\(cached\)' +go test testcache -run=TestOSArgs -failfast +stdout '\(cached\)' + +# Executables within GOROOT and GOPATH should affect caching, +# even if the test does not stat them explicitly. + +[!exec:/bin/sh] skip +chmod 0755 ./testcache/script.sh + +exec ./mkold$GOEXEC 1m testcache/script.sh +go test testcache -run=Exec +go test testcache -run=Exec +stdout '\(cached\)' + +exec ./mkold$GOEXE 50s testcache/script.sh +go test testcache -run=Exec +! stdout '\(cached\)' +go test testcache -run=Exec +stdout '\(cached\)' + +-- testcache/file.txt -- +xx +-- 4x.txt -- +xxxx +-- 6x.txt -- +xxxxxx +-- 2y.txt -- +yy +-- $WORK/external.txt -- +This file is outside of GOPATH. +-- testcache/script.sh -- +#!/bin/sh +exit 0 +-- testcache/testcache_test.go -- +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package testcache + +import ( + "io" + "os" + "testing" +) + +func TestChdir(t *testing.T) { + os.Chdir("..") + defer os.Chdir("testcache") + info, err := os.Stat("testcache/file.txt") + if err != nil { + t.Fatal(err) + } + if info.Size()%2 != 1 { + t.Fatal("even file") + } +} + +func TestOddFileContent(t *testing.T) { + f, err := os.Open("file.txt") + if err != nil { + t.Fatal(err) + } + data, err := io.ReadAll(f) + f.Close() + if err != nil { + t.Fatal(err) + } + if len(data)%2 != 1 { + t.Fatal("even file") + } +} + +func TestOddFileSize(t *testing.T) { + info, err := os.Stat("file.txt") + if err != nil { + t.Fatal(err) + } + if info.Size()%2 != 1 { + t.Fatal("even file") + } +} + +func TestOddGetenv(t *testing.T) { + val := os.Getenv("TESTKEY") + if len(val)%2 != 1 { + t.Fatal("even env value") + } +} + +func TestLookupEnv(t *testing.T) { + _, ok := os.LookupEnv("TESTKEY") + if !ok { + t.Fatal("env missing") + } +} + +func TestDirList(t *testing.T) { + f, err := os.Open(".") + if err != nil { + t.Fatal(err) + } + f.Readdirnames(-1) + f.Close() +} + +func TestExec(t *testing.T) { + // Note: not using os/exec to make sure there is no unexpected stat. + p, err := os.StartProcess("./script.sh", []string{"script"}, new(os.ProcAttr)) + if err != nil { + t.Fatal(err) + } + ps, err := p.Wait() + if err != nil { + t.Fatal(err) + } + if !ps.Success() { + t.Fatalf("script failed: %v", err) + } +} + +func TestExternalFile(t *testing.T) { + os.Open(os.Getenv("TEST_EXTERNAL_FILE")) + _, err := os.Stat(os.Getenv("TEST_EXTERNAL_FILE")) + if err != nil { + t.Fatal(err) + } +} + +func TestOSArgs(t *testing.T) { + t.Log(os.Args) +} + +func TestBenchtime(t *testing.T) { +} + +-- mkold.go -- +package main + +import ( + "log" + "os" + "time" +) + +func main() { + d, err := time.ParseDuration(os.Args[1]) + if err != nil { + log.Fatal(err) + } + path := os.Args[2] + old := time.Now().Add(-d) + err = os.Chtimes(path, old, old) + if err != nil { + log.Fatal(err) + } +} diff --git a/src/cmd/go/testdata/script/test_chatty_fail.txt b/src/cmd/go/testdata/script/test_chatty_fail.txt new file mode 100644 index 0000000..a5ef559 --- /dev/null +++ b/src/cmd/go/testdata/script/test_chatty_fail.txt @@ -0,0 +1,32 @@ +# Run chatty tests. Assert on CONT lines. +! go test chatty_test.go -v + +# Sanity check that output occurs. +stdout -count=2 'this is sub-0' +stdout -count=2 'this is sub-1' +stdout -count=2 'this is sub-2' +stdout -count=1 'error from sub-0' +stdout -count=1 'error from sub-1' +stdout -count=1 'error from sub-2' + +# Non-parallel tests should not print CONT. +! stdout CONT + +-- chatty_test.go -- +package chatty_test + +import ( + "testing" + "fmt" +) + +func TestChatty(t *testing.T) { + for i := 0; i < 3; i++ { + t.Run(fmt.Sprintf("sub-%d", i), func(t *testing.T) { + for j := 0; j < 2; j++ { + t.Logf("this is sub-%d", i) + } + t.Errorf("error from sub-%d", i) + }) + } +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt b/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt new file mode 100644 index 0000000..62f97db --- /dev/null +++ b/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt @@ -0,0 +1,62 @@ +# Run parallel chatty tests. +# Check that multiple parallel outputs continue running. +! go test -parallel 3 chatty_parallel_test.go -v + +stdout -count=1 '^=== CONT TestChattyParallel/sub-0' +stdout -count=1 '^=== CONT TestChattyParallel/sub-1' +stdout -count=1 '^=== CONT TestChattyParallel/sub-2' + +stdout -count=1 '^=== (CONT|NAME) TestChattyParallel/sub-0\n chatty_parallel_test.go:38: error from sub-0$' +stdout -count=1 '^=== (CONT|NAME) TestChattyParallel/sub-1\n chatty_parallel_test.go:38: error from sub-1$' +stdout -count=1 '^=== (CONT|NAME) TestChattyParallel/sub-2\n chatty_parallel_test.go:38: error from sub-2$' + +# Run parallel chatty tests with -json. +# Check that each output is attributed to the right test. +! go test -json -parallel 3 chatty_parallel_test.go -v +stdout -count=1 '"Test":"TestChattyParallel/sub-0","Output":" chatty_parallel_test.go:38: error from sub-0\\n"' +stdout -count=1 '"Test":"TestChattyParallel/sub-1","Output":" chatty_parallel_test.go:38: error from sub-1\\n"' +stdout -count=1 '"Test":"TestChattyParallel/sub-2","Output":" chatty_parallel_test.go:38: error from sub-2\\n"' + +-- chatty_parallel_test.go -- +package chatty_parallel_test + +import ( + "testing" + "fmt" + "flag" +) + +// This test ensures the order of CONT lines in parallel chatty tests. +func TestChattyParallel(t *testing.T) { + t.Parallel() + + // The number of concurrent tests running. This is closely tied to the + // -parallel test flag, so we grab it from the flag rather than setting it + // to some constant. + parallel := flag.Lookup("test.parallel").Value.(flag.Getter).Get().(int) + + // ready is a synchronization mechanism that causes subtests to execute + // round robin. + ready := make([]chan bool, parallel) + for i := range ready { + ready[i] = make(chan bool, 1) + } + ready[0] <- true + + for i := range ready { + i := i + t.Run(fmt.Sprintf("sub-%d", i), func(t *testing.T) { + t.Parallel() + + // Some basic log output to precede the failures. + <-ready[i] + t.Logf("this is sub-%d", i) + ready[(i+1)%len(ready)] <- true + + // The actual failure messages we care about. + <-ready[i] + t.Errorf("error from sub-%d", i) + ready[(i+1)%len(ready)] <- true + }) + } +} diff --git a/src/cmd/go/testdata/script/test_chatty_parallel_success.txt b/src/cmd/go/testdata/script/test_chatty_parallel_success.txt new file mode 100644 index 0000000..01653ac --- /dev/null +++ b/src/cmd/go/testdata/script/test_chatty_parallel_success.txt @@ -0,0 +1,52 @@ +# Run parallel chatty tests. Assert on CONT or NAME lines. This test makes sure that +# multiple parallel outputs have the appropriate test name lines between them. +go test -parallel 3 chatty_parallel_test.go -v +stdout -count=2 '^=== (CONT|NAME) TestChattyParallel/sub-0\n chatty_parallel_test.go:32: this is sub-0$' +stdout -count=2 '^=== (CONT|NAME) TestChattyParallel/sub-1\n chatty_parallel_test.go:32: this is sub-1$' +stdout -count=2 '^=== (CONT|NAME) TestChattyParallel/sub-2\n chatty_parallel_test.go:32: this is sub-2$' + +# Run parallel chatty tests with -json. +# Assert test2json has properly attributed output. +go test -json -parallel 3 chatty_parallel_test.go -v +stdout -count=2 '"Test":"TestChattyParallel/sub-0","Output":" chatty_parallel_test.go:32: this is sub-0\\n"' +stdout -count=2 '"Test":"TestChattyParallel/sub-1","Output":" chatty_parallel_test.go:32: this is sub-1\\n"' +stdout -count=2 '"Test":"TestChattyParallel/sub-2","Output":" chatty_parallel_test.go:32: this is sub-2\\n"' + +-- chatty_parallel_test.go -- +package chatty_parallel_test + +import ( + "testing" + "fmt" + "flag" +) + +// This test ensures the order of CONT lines in parallel chatty tests. +func TestChattyParallel(t *testing.T) { + t.Parallel() + + // The number of concurrent tests running. This is closely tied to the + // -parallel test flag, so we grab it from the flag rather than setting it + // to some constant. + parallel := flag.Lookup("test.parallel").Value.(flag.Getter).Get().(int) + + // ready is a synchronization mechanism that causes subtests to execute + // round robin. + ready := make([]chan bool, parallel) + for i := range ready { + ready[i] = make(chan bool, 1) + } + ready[0] <- true + + for i := range ready { + i := i + t.Run(fmt.Sprintf("sub-%d", i), func(t *testing.T) { + t.Parallel() + for j := 0; j < 2; j++ { + <-ready[i] + t.Logf("this is sub-%d", i) + ready[(i+1)%len(ready)] <- true + } + }) + } +} diff --git a/src/cmd/go/testdata/script/test_chatty_parallel_success_run.txt b/src/cmd/go/testdata/script/test_chatty_parallel_success_run.txt new file mode 100644 index 0000000..1d4b6d6 --- /dev/null +++ b/src/cmd/go/testdata/script/test_chatty_parallel_success_run.txt @@ -0,0 +1,41 @@ +# Run parallel chatty tests. Assert on CONT or NAME lines. This test makes sure that +# multiple parallel outputs have the appropriate CONT lines between them. +go test -parallel 3 chatty_parallel -v + +stdout '=== RUN TestInterruptor/interruption\n=== (CONT|NAME) TestLog\n chatty_parallel_test.go:28: this is the second TestLog log\n--- PASS: Test(Log|Interruptor) \([0-9.]{4}s\)' + +-- go.mod -- +module chatty_parallel + +go 1.18 +-- chatty_parallel_test.go -- +package chatty_parallel_test + +import ( + "testing" +) + +var ( + afterFirstLog = make(chan struct{}) + afterSubTest = make(chan struct{}) + afterSecondLog = make(chan struct{}) +) + +func TestInterruptor(t *testing.T) { + t.Parallel() + + <-afterFirstLog + t.Run("interruption", func (t *testing.T) {}) + close(afterSubTest) + <-afterSecondLog // Delay the "PASS: TestInterruptor" line until after "CONT TestLog". +} + +func TestLog(t *testing.T) { + t.Parallel() + + t.Logf("this is the first TestLog log") + close(afterFirstLog) + <-afterSubTest + t.Logf("this is the second TestLog log") + close(afterSecondLog) +} diff --git a/src/cmd/go/testdata/script/test_chatty_success.txt b/src/cmd/go/testdata/script/test_chatty_success.txt new file mode 100644 index 0000000..8bfa569 --- /dev/null +++ b/src/cmd/go/testdata/script/test_chatty_success.txt @@ -0,0 +1,27 @@ +# Run chatty tests. Assert on CONT lines. +go test chatty_test.go -v + +# Non-parallel tests should not print CONT. +! stdout CONT + +# The assertion is condensed into one line so that it precisely matches output, +# rather than skipping lines and allow rogue CONT lines. +stdout '=== RUN TestChatty\n=== RUN TestChatty/sub-0\n chatty_test.go:12: this is sub-0\n chatty_test.go:12: this is sub-0\n=== RUN TestChatty/sub-1\n chatty_test.go:12: this is sub-1\n chatty_test.go:12: this is sub-1\n=== RUN TestChatty/sub-2\n chatty_test.go:12: this is sub-2\n chatty_test.go:12: this is sub-2\n--- PASS: TestChatty' + +-- chatty_test.go -- +package chatty_test + +import ( + "testing" + "fmt" +) + +func TestChatty(t *testing.T) { + for i := 0; i < 3; i++ { + t.Run(fmt.Sprintf("sub-%d", i), func(t *testing.T) { + for j := 0; j < 2; j++ { + t.Logf("this is sub-%d", i) + } + }) + } +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_cleanup_failnow.txt b/src/cmd/go/testdata/script/test_cleanup_failnow.txt new file mode 100644 index 0000000..0aba8c7 --- /dev/null +++ b/src/cmd/go/testdata/script/test_cleanup_failnow.txt @@ -0,0 +1,46 @@ +# For issue 41355 +[short] skip + +# This test could fail if the testing package does not wait until +# a panicking test does the panic. Turn off multithreading and GC +# to increase the probability of such a failure. +env GOMAXPROCS=1 +env GOGC=off + +# If the test exits with 'no tests to run', it means the testing package +# implementation is incorrect and does not wait until a test panic. +# If the test exits with '(?s)panic: die.*panic: die', it means +# the testing package did an extra panic for a panicking test. + +! go test -v cleanup_failnow/panic_nocleanup_test.go +! stdout 'no tests to run' +stdout '(?s)panic: die \[recovered\].*panic: die' +! stdout '(?s)panic: die \[recovered\].*panic: die.*panic: die' + +! go test -v cleanup_failnow/panic_withcleanup_test.go +! stdout 'no tests to run' +stdout '(?s)panic: die \[recovered\].*panic: die' +! stdout '(?s)panic: die \[recovered\].*panic: die.*panic: die' + +-- cleanup_failnow/panic_nocleanup_test.go -- +package panic_nocleanup_test +import "testing" +func TestX(t *testing.T) { + t.Run("x", func(t *testing.T) { + panic("die") + }) +} + +-- cleanup_failnow/panic_withcleanup_test.go -- +package panic_withcleanup_test +import "testing" +func TestCleanupWithFailNow(t *testing.T) { + t.Cleanup(func() { + t.FailNow() + }) + t.Run("x", func(t *testing.T) { + t.Run("y", func(t *testing.T) { + panic("die") + }) + }) +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_compile_binary.txt b/src/cmd/go/testdata/script/test_compile_binary.txt new file mode 100644 index 0000000..63bb8ec --- /dev/null +++ b/src/cmd/go/testdata/script/test_compile_binary.txt @@ -0,0 +1,8 @@ +env GO111MODULE=off + +! go test -c compile_binary/... +stderr 'build comment' + +-- compile_binary/foo_test.go -- +// +build foo +package foo diff --git a/src/cmd/go/testdata/script/test_compile_multi_pkg.txt b/src/cmd/go/testdata/script/test_compile_multi_pkg.txt new file mode 100644 index 0000000..921ef5c --- /dev/null +++ b/src/cmd/go/testdata/script/test_compile_multi_pkg.txt @@ -0,0 +1,50 @@ +[short] skip 'links test binaries' + +# Verify test -c can output multiple executables to a directory. + +# This test also serves as a regression test for https://go.dev/issue/62221: +# prior to the fix for that issue, it occasionally failed with ETXTBSY when +# run on Unix platforms. + +go test -c -o $WORK/some/nonexisting/directory/ ./pkg/... +exists -exec $WORK/some/nonexisting/directory/pkg1.test$GOEXE +exists -exec $WORK/some/nonexisting/directory/pkg2.test$GOEXE + +go test -c ./pkg/... +exists -exec pkg1.test$GOEXE +exists -exec pkg2.test$GOEXE + +! go test -c -o $WORK/bin/test/bin.test.exe ./pkg/... +stderr '^with multiple packages, -o must refer to a directory or '$devnull + +! go test -c ./... +stderr '^cannot write test binary pkg1.test for multiple packages:\nexample/anotherpkg/pkg1\nexample/pkg/pkg1' + +! go test -c -o $WORK/bin/test/ ./... +stderr '^cannot write test binary pkg1.test for multiple packages:\nexample/anotherpkg/pkg1\nexample/pkg/pkg1' + +! go test -o $WORK/bin/filename.exe ./pkg/... +stderr '^with multiple packages, -o must refer to a directory or '$devnull + +! go test -o $WORK/bin/ ./... +stderr '^cannot write test binary pkg1.test for multiple packages:\nexample/anotherpkg/pkg1\nexample/pkg/pkg1' + +go test -c -o $devnull ./... + +rm pkg1.test$GOEXE +rm pkg2.test$GOEXE +go test -o . ./pkg/... +exists -exec pkg1.test$GOEXE +exists -exec pkg2.test$GOEXE + +-- go.mod -- +module example + +-- pkg/pkg1/pkg1_test.go -- +package pkg1 + +-- pkg/pkg2/pkg2_test.go -- +package pkg2 + +-- anotherpkg/pkg1/pkg1_test.go -- +package pkg1 diff --git a/src/cmd/go/testdata/script/test_compile_tempfile.txt b/src/cmd/go/testdata/script/test_compile_tempfile.txt new file mode 100644 index 0000000..05f721a --- /dev/null +++ b/src/cmd/go/testdata/script/test_compile_tempfile.txt @@ -0,0 +1,11 @@ +[short] skip + +# Ensure that the target of 'go build -o' can be an existing, empty file so that +# its name can be reserved using os.CreateTemp or the 'mktemp` command. + +go build -o empty-file$GOEXE main.go + +-- main.go -- +package main +func main() {} +-- empty-file$GOEXE -- diff --git a/src/cmd/go/testdata/script/test_deadline.txt b/src/cmd/go/testdata/script/test_deadline.txt new file mode 100644 index 0000000..06ae16f --- /dev/null +++ b/src/cmd/go/testdata/script/test_deadline.txt @@ -0,0 +1,54 @@ +[short] skip + +go test -timeout=0 -run=TestNoDeadline +go test -timeout=1m -run=TestDeadlineWithinMinute +go test -timeout=1m -run=TestSubtestDeadlineWithinMinute + +-- go.mod -- +module m + +go 1.16 +-- deadline_test.go -- +package testing_test + +import ( + "testing" + "time" +) + +func TestNoDeadline(t *testing.T) { + d, ok := t.Deadline() + if ok || !d.IsZero() { + t.Fatalf("t.Deadline() = %v, %v; want 0, false", d, ok) + } +} + +func TestDeadlineWithinMinute(t *testing.T) { + now := time.Now() + d, ok := t.Deadline() + if !ok || d.IsZero() { + t.Fatalf("t.Deadline() = %v, %v; want nonzero deadline", d, ok) + } + if !d.After(now) { + t.Fatalf("t.Deadline() = %v; want after start of test (%v)", d, now) + } + if d.Sub(now) > time.Minute { + t.Fatalf("t.Deadline() = %v; want within one minute of start of test (%v)", d, now) + } +} + +func TestSubtestDeadlineWithinMinute(t *testing.T) { + t.Run("sub", func(t *testing.T) { + now := time.Now() + d, ok := t.Deadline() + if !ok || d.IsZero() { + t.Fatalf("t.Deadline() = %v, %v; want nonzero deadline", d, ok) + } + if !d.After(now) { + t.Fatalf("t.Deadline() = %v; want after start of test (%v)", d, now) + } + if d.Sub(now) > time.Minute { + t.Fatalf("t.Deadline() = %v; want within one minute of start of test (%v)", d, now) + } + }) +} diff --git a/src/cmd/go/testdata/script/test_empty.txt b/src/cmd/go/testdata/script/test_empty.txt new file mode 100644 index 0000000..5ebbecd --- /dev/null +++ b/src/cmd/go/testdata/script/test_empty.txt @@ -0,0 +1,53 @@ +[!race] skip + +cd $GOPATH/src/empty/pkg +go test -cover -coverpkg=. -race + +[short] stop # Only run first case in short mode + +cd $GOPATH/src/empty/test +go test -cover -coverpkg=. -race + +cd $GOPATH/src/empty/xtest +go test -cover -coverpkg=. -race + +cd $GOPATH/src/empty/pkgtest +go test -cover -coverpkg=. -race + +cd $GOPATH/src/empty/pkgxtest +go test -cover -coverpkg=. -race + +cd $GOPATH/src/empty/pkgtestxtest +go test -cover -coverpkg=. -race + +cd $GOPATH/src/empty/testxtest +go test -cover -coverpkg=. -race + +-- empty/go.mod -- +module empty + +go 1.16 +-- empty/pkg/pkg.go -- +package p +-- empty/pkgtest/pkg.go -- +package p +-- empty/pkgtest/test_test.go -- +package p +-- empty/pkgtestxtest/pkg.go -- +package p +-- empty/pkgtestxtest/test_test.go -- +package p +-- empty/pkgtestxtest/xtest_test.go -- +package p_test +-- empty/pkgxtest/pkg.go -- +package p +-- empty/pkgxtest/xtest_test.go -- +package p_test +-- empty/test/test_test.go -- +package p +-- empty/testxtest/test_test.go -- +package p +-- empty/testxtest/xtest_test.go -- +package p_test +-- empty/xtest/xtest_test.go -- +package p_test diff --git a/src/cmd/go/testdata/script/test_env_term.txt b/src/cmd/go/testdata/script/test_env_term.txt new file mode 100644 index 0000000..8a5f79a --- /dev/null +++ b/src/cmd/go/testdata/script/test_env_term.txt @@ -0,0 +1,15 @@ +# Tests golang.org/issue/12096 + +env TERM='' +go test test_test.go +! stdout '^ok.*\[no tests to run\]' +stdout '^ok' + +-- test_test.go -- +package main +import ("os"; "testing") +func TestEnv(t *testing.T) { + if os.Getenv("TERM") != "" { + t.Fatal("TERM is set") + } +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_example_goexit.txt b/src/cmd/go/testdata/script/test_example_goexit.txt new file mode 100644 index 0000000..984f434 --- /dev/null +++ b/src/cmd/go/testdata/script/test_example_goexit.txt @@ -0,0 +1,29 @@ +# For issue golang.org/issue/41084 +[short] skip + +! go test -v examplegoexit +stdout '(?s)--- PASS.*--- FAIL.*' +stdout 'panic: test executed panic\(nil\) or runtime\.Goexit' + +-- go.mod -- +module examplegoexit + +go 1.16 +-- example_test.go -- +package main + +import ( + "fmt" + "runtime" +) + +func ExamplePass() { + fmt.Println("pass") + // Output: + // pass +} + +func ExampleGoexit() { + runtime.Goexit() + // Output: +} diff --git a/src/cmd/go/testdata/script/test_exit.txt b/src/cmd/go/testdata/script/test_exit.txt new file mode 100644 index 0000000..3703ba5 --- /dev/null +++ b/src/cmd/go/testdata/script/test_exit.txt @@ -0,0 +1,131 @@ +# Builds and runs test binaries, so skip in short mode. +[short] skip + +env GO111MODULE=on + +# If a test invoked by 'go test' exits with a zero status code, +# it will panic. +! go test ./zero +! stdout ^ok +! stdout 'exit status' +stdout 'panic' +stdout ^FAIL + +# If a test exits with a non-zero status code, 'go test' fails normally. +! go test ./one +! stdout ^ok +stdout 'exit status' +! stdout 'panic' +stdout ^FAIL + +# Ensure that other flags still do the right thing. +go test -list=. ./zero +stdout ExitZero + +! go test -bench=. ./zero +stdout 'panic' + +# 'go test' with no args streams output without buffering. Ensure that it still +# catches a zero exit with missing output. +cd zero +! go test +stdout 'panic' +cd ../normal +go test +stdout ^ok +cd .. + +# If a TestMain exits with a zero status code, 'go test' shouldn't +# complain about that. It's a common way to skip testing a package +# entirely. +go test ./main_zero +! stdout 'skipping all tests' +stdout ^ok + +# With -v, we'll see the warning from TestMain. +go test -v ./main_zero +stdout 'skipping all tests' +stdout ^ok + +# Listing all tests won't actually give a result if TestMain exits. That's okay, +# because this is how TestMain works. If we decide to support -list even when +# TestMain is used to skip entire packages, we can change this test case. +go test -list=. ./main_zero +stdout 'skipping all tests' +! stdout TestNotListed + +# Running the test directly still fails, if we pass the flag. +go test -c -o ./zero.exe ./zero +! exec ./zero.exe -test.paniconexit0 + +# Using -json doesn't affect the exit status. +! go test -json ./zero +! stdout '"Output":"ok' +! stdout 'exit status' +stdout 'panic' +stdout '"Output":"FAIL' + +# Running the test via test2json also fails. +! go tool test2json ./zero.exe -test.v -test.paniconexit0 +! stdout '"Output":"ok' +! stdout 'exit status' +stdout 'panic' + +-- go.mod -- +module m + +-- ./normal/normal.go -- +package normal +-- ./normal/normal_test.go -- +package normal + +import "testing" + +func TestExitZero(t *testing.T) { +} + +-- ./zero/zero.go -- +package zero +-- ./zero/zero_test.go -- +package zero + +import ( + "os" + "testing" +) + +func TestExitZero(t *testing.T) { + os.Exit(0) +} + +-- ./one/one.go -- +package one +-- ./one/one_test.go -- +package one + +import ( + "os" + "testing" +) + +func TestExitOne(t *testing.T) { + os.Exit(1) +} + +-- ./main_zero/zero.go -- +package zero +-- ./main_zero/zero_test.go -- +package zero + +import ( + "fmt" + "os" + "testing" +) + +func TestMain(m *testing.M) { + fmt.Println("skipping all tests") + os.Exit(0) +} + +func TestNotListed(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/test_fail_fast.txt b/src/cmd/go/testdata/script/test_fail_fast.txt new file mode 100644 index 0000000..132ea70 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fail_fast.txt @@ -0,0 +1,113 @@ +[short] skip + +# test fail fast +! go test ./failfast_test.go -run='TestFailingA' -failfast=true +stdout -count=1 'FAIL - ' +! go test ./failfast_test.go -run='TestFailing[AB]' -failfast=true +stdout -count=1 'FAIL - ' +! go test ./failfast_test.go -run='TestFailing[AB]' -failfast=false +stdout -count=2 'FAIL - ' + +# mix with non-failing tests +! go test ./failfast_test.go -run='TestA|TestFailing[AB]' -failfast=true +stdout -count=1 'FAIL - ' +! go test ./failfast_test.go -run='TestA|TestFailing[AB]' -failfast=false +stdout -count=2 'FAIL - ' + +# mix with parallel tests +! go test ./failfast_test.go -run='TestFailingB|TestParallelFailingA' -failfast=true +stdout -count=2 'FAIL - ' +! go test ./failfast_test.go -run='TestFailingB|TestParallelFailingA' -failfast=false +stdout -count=2 'FAIL - ' +! go test ./failfast_test.go -run='TestFailingB|TestParallelFailing[AB]' -failfast=true +stdout -count=3 'FAIL - ' +! go test ./failfast_test.go -run='TestFailingB|TestParallelFailing[AB]' -failfast=false +stdout -count=3 'FAIL - ' + +# mix with parallel sub-tests +! go test ./failfast_test.go -run='TestFailingB|TestParallelFailing[AB]|TestParallelFailingSubtestsA' -failfast=true +stdout -count=3 'FAIL - ' +! go test ./failfast_test.go -run='TestFailingB|TestParallelFailing[AB]|TestParallelFailingSubtestsA' -failfast=false +stdout -count=5 'FAIL - ' +! go test ./failfast_test.go -run='TestParallelFailingSubtestsA' -failfast=true +stdout -count=1 'FAIL - ' + +# only parallels +! go test ./failfast_test.go -run='TestParallelFailing[AB]' -failfast=false +stdout -count=2 'FAIL - ' + +# non-parallel subtests +! go test ./failfast_test.go -run='TestFailingSubtestsA' -failfast=true +stdout -count=1 'FAIL - ' +! go test ./failfast_test.go -run='TestFailingSubtestsA' -failfast=false +stdout -count=2 'FAIL - ' + +# fatal test +! go test ./failfast_test.go -run='TestFatal[CD]' -failfast=true +stdout -count=1 'FAIL - ' +! go test ./failfast_test.go -run='TestFatal[CD]' -failfast=false +stdout -count=2 'FAIL - ' + +-- failfast_test.go -- +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package failfast + +import "testing" + +func TestA(t *testing.T) { + // Edge-case testing, mixing unparallel tests too + t.Logf("LOG: %s", t.Name()) +} + +func TestFailingA(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) +} + +func TestB(t *testing.T) { + // Edge-case testing, mixing unparallel tests too + t.Logf("LOG: %s", t.Name()) +} + +func TestParallelFailingA(t *testing.T) { + t.Parallel() + t.Errorf("FAIL - %s", t.Name()) +} + +func TestParallelFailingB(t *testing.T) { + t.Parallel() + t.Errorf("FAIL - %s", t.Name()) +} + +func TestParallelFailingSubtestsA(t *testing.T) { + t.Parallel() + t.Run("TestFailingSubtestsA1", func(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) + }) + t.Run("TestFailingSubtestsA2", func(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) + }) +} + +func TestFailingSubtestsA(t *testing.T) { + t.Run("TestFailingSubtestsA1", func(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) + }) + t.Run("TestFailingSubtestsA2", func(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) + }) +} + +func TestFailingB(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) +} + +func TestFatalC(t *testing.T) { + t.Fatalf("FAIL - %s", t.Name()) +} + +func TestFatalD(t *testing.T) { + t.Fatalf("FAIL - %s", t.Name()) +} diff --git a/src/cmd/go/testdata/script/test_fail_newline.txt b/src/cmd/go/testdata/script/test_fail_newline.txt new file mode 100644 index 0000000..43cee56 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fail_newline.txt @@ -0,0 +1,65 @@ +[short] skip + +# In package list mode, output is buffered. +# Check that a newline is printed after the buffer's contents. +cd fail +! go test . +! stderr . +stdout '^exitcode=1\n' +stdout '^FAIL\s+example/fail' + +# In local directory mode output is streamed, so we don't know +# whether the test printed anything at all, so we print the exit code +# (just in case it failed without emitting any output at all), +# and that happens to add the needed newline as well. +! go test +! stderr . +stdout '^exitcode=1exit status 1\n' +stdout '^FAIL\s+example/fail' + +# In package list mode, if the test passes the 'ok' message appears +# on its own line. +cd ../skip +go test -v . +! stderr . +stdout '^skipping\n' +stdout '^ok\s+example/skip' + +# If the output is streamed and the test passes, we can't tell whether it ended +# in a partial line, and don't want to emit any extra output in the +# overwhelmingly common case that it did not. +# (In theory we could hook the 'os' package to report whether output +# was emitted and whether it ended in a newline, but that seems too invasive.) +go test +! stderr . +stdout '^skippingok\s+example/skip' + + +-- go.mod -- +module example + +go 1.18 +-- fail/fail_test.go -- +package fail + +import ( + "os" + "testing" +) + +func TestMain(m *testing.M) { + os.Stderr.WriteString("exitcode=1") + os.Exit(1) +} +-- skip/skip_test.go -- +package skip + +import ( + "os" + "testing" +) + +func TestMain(m *testing.M) { + os.Stderr.WriteString("skipping") + os.Exit(0) +} diff --git a/src/cmd/go/testdata/script/test_finished_subtest_goroutines.txt b/src/cmd/go/testdata/script/test_finished_subtest_goroutines.txt new file mode 100644 index 0000000..8db821e --- /dev/null +++ b/src/cmd/go/testdata/script/test_finished_subtest_goroutines.txt @@ -0,0 +1,52 @@ +# Regression test for https://golang.org/issue/45127: +# Goroutines for completed parallel subtests should exit immediately, +# not block until earlier subtests have finished. + +[short] skip + +! go test . +stdout 'panic: slow failure' +! stdout '\[chan send' + +-- go.mod -- +module golang.org/issue45127 + +go 1.16 +-- issue45127_test.go -- +package main + +import ( + "fmt" + "runtime" + "runtime/debug" + "sync" + "testing" +) + +func TestTestingGoroutineLeak(t *testing.T) { + debug.SetTraceback("all") + + var wg sync.WaitGroup + const nFast = 10 + + t.Run("slow", func(t *testing.T) { + t.Parallel() + wg.Wait() + for i := 0; i < nFast; i++ { + // If the subtest goroutines are going to park on the channel + // send, allow them to park now. If they're not going to park, + // make sure they have had a chance to run to completion so + // that they aren't spuriously parked when we panic. + runtime.Gosched() + } + panic("slow failure") + }) + + wg.Add(nFast) + for i := 0; i < nFast; i++ { + t.Run(fmt.Sprintf("leaky%d", i), func(t *testing.T) { + t.Parallel() + wg.Done() + }) + } +} diff --git a/src/cmd/go/testdata/script/test_flag.txt b/src/cmd/go/testdata/script/test_flag.txt new file mode 100644 index 0000000..6ef4529 --- /dev/null +++ b/src/cmd/go/testdata/script/test_flag.txt @@ -0,0 +1,38 @@ +[short] skip + +go test flag_test.go -v -args -v=7 # Two distinct -v flags +go test -v flag_test.go -args -v=7 # Two distinct -v flags + +# Using a custom flag mixed with regular 'go test' flags should be OK. +go test -count=1 -custom -args -v=7 + +# However, it should be an error to use custom flags when -c is used, +# since we know for sure that no test binary will run at all. +! go test -c -custom +stderr '^go: unknown flag -custom cannot be used with -c$' + +# The same should apply even if -c comes after a custom flag. +! go test -custom -c +stderr '^go: unknown flag -custom cannot be used with -c$' + +-- go.mod -- +module m +-- flag_test.go -- +package flag_test + +import ( + "flag" + "log" + "testing" +) + +var v = flag.Int("v", 0, "v flag") + +var custom = flag.Bool("custom", false, "") + +// Run this as go test pkg -v=7 +func TestVFlagIsSet(t *testing.T) { + if *v != 7 { + log.Fatal("v flag not set") + } +} diff --git a/src/cmd/go/testdata/script/test_flags.txt b/src/cmd/go/testdata/script/test_flags.txt new file mode 100644 index 0000000..3f7964b --- /dev/null +++ b/src/cmd/go/testdata/script/test_flags.txt @@ -0,0 +1,131 @@ +env GO111MODULE=on + +[short] skip + +# Arguments after the flag terminator should be ignored. +# If we pass '-- -test.v', we should not get verbose output +# *and* output from the test should not be echoed. +go test ./x -- -test.v +stdout '\Aok\s+example.com/x\s+[0-9.s]+\n\z' +! stderr . + +# For backward-compatibility with previous releases of the 'go' command, +# arguments that appear after unrecognized flags should not be treated +# as packages, even if they are unambiguously not arguments to flags. +# Even though ./x looks like a package path, the real package should be +# the implicit '.'. +! go test --answer=42 ./x +stderr '^no Go files in '$PWD'$' + +# However, *flags* that appear after unrecognized flags should still be +# interpreted as flags, under the (possibly-erroneous) assumption that +# unrecognized flags are non-boolean. + +go test -v -x ./x -timeout 24h -boolflag=true foo -timeout 25h +stdout 'args: foo -timeout 25h' +stdout 'timeout: 24h0m0s$' # -timeout is unambiguously not a flag, so the real flag wins. + +go test -v -x ./x -timeout 24h -boolflag foo -timeout 25h +stdout 'args: foo -test\.timeout=25h0m0s' # For legacy reasons, '-timeout ' is erroneously rewritten to -test.timeout; see https://golang.org/issue/40763. +stdout 'timeout: 24h0m0s$' # Actual flag wins. + +go test -v -x ./x -timeout 24h -stringflag foo -timeout 25h +stdout 'args: $' +stdout 'timeout: 25h0m0s$' # Later flag wins. + +# An explicit '-outputdir=' argument should set test.outputdir +# to the 'go' command's working directory, not zero it out +# for the test binary. +go test -x -coverprofile=cover.out '-outputdir=' ./x +stderr '-test.outputdir=[^ ]' +exists ./cover.out +! exists ./x/cover.out + +# Test flags from GOFLAGS should be forwarded to the test binary, +# with the 'test.' prefix in the GOFLAGS entry... +env GOFLAGS='-test.timeout=24h0m0s -count=1' +go test -v -x ./x +stdout 'timeout: 24h0m0s$' +stderr '-test.count=1' + +# ...or without. +env GOFLAGS='-timeout=24h0m0s -count=1' +go test -v -x ./x +stdout 'timeout: 24h0m0s$' +stderr '-test.count=1' + +# Arguments from the command line should override GOFLAGS... +go test -v -x -timeout=25h0m0s ./x +stdout 'timeout: 25h0m0s$' +stderr '-test.count=1' + +# ...even if they use a different flag name. +go test -v -x -test.timeout=26h0m0s ./x +stdout 'timeout: 26h0m0s$' +stderr '-test\.timeout=26h0m0s' +! stderr 'timeout=24h0m0s' +stderr '-test.count=1' + +# Invalid flags should be reported exactly once. +! go test -covermode=walrus ./x +stderr -count=1 'invalid value "walrus" for flag -covermode: valid modes are .*$' +stderr '^usage: go test .*$' +stderr '^Run ''go help test'' and ''go help testflag'' for details.$' + +# Passing -help to the test binary should show flag help. +go test ./x -args -help +stdout 'usage_message' + +# -covermode, -coverpkg, and -coverprofile should imply -cover +go test -covermode=set ./x +stdout '\s+coverage:\s+' + +go test -coverpkg=encoding/binary ./x +stdout '\s+coverage:\s+' + +go test -coverprofile=cover.out ./x +stdout '\s+coverage:\s+' +exists ./cover.out +rm ./cover.out + +# -*profile and -trace flags should force output to the current working directory +# or -outputdir, not the directory containing the test. + +go test -memprofile=mem.out ./x +exists ./mem.out +rm ./mem.out + +go test -trace=trace.out ./x +exists ./trace.out +rm ./trace.out + +# Relative paths with -outputdir should be relative to the go command's working +# directory, not the directory containing the test. +mkdir profiles +go test -memprofile=mem.out -outputdir=./profiles ./x +exists ./profiles/mem.out +rm profiles + +-- go.mod -- +module example.com +go 1.14 +-- x/x_test.go -- +package x + +import ( + "flag" + "strings" + "testing" +) + +var _ = flag.String("usage_message", "", "dummy flag to check usage message") +var boolflag = flag.Bool("boolflag", false, "ignored boolean flag") +var stringflag = flag.String("stringflag", "", "ignored string flag") + +func TestLogTimeout(t *testing.T) { + t.Logf("timeout: %v", flag.Lookup("test.timeout").Value) +} + +func TestLogArgs(t *testing.T) { + t.Logf("args: %s", strings.Join(flag.Args(), " ")) +} diff --git a/src/cmd/go/testdata/script/test_fullpath.txt b/src/cmd/go/testdata/script/test_fullpath.txt new file mode 100644 index 0000000..8e01552 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fullpath.txt @@ -0,0 +1,21 @@ +[short] skip + +# test with -fullpath +! go test ./x/... -fullpath +stdout '^ +.+/gopath/src/x/fullpath/fullpath_test.go:8: test failed' +# test without -fullpath +! go test ./x/... +stdout '^ +fullpath_test.go:8: test failed' + +-- go.mod -- +module example +-- x/fullpath/fullpath_test.go -- +package fullpath_test + +import ( + "testing" +) + +func TestFullPath(t *testing.T) { + t.Error("test failed") +} diff --git a/src/cmd/go/testdata/script/test_fuzz.txt b/src/cmd/go/testdata/script/test_fuzz.txt new file mode 100644 index 0000000..37170bf --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz.txt @@ -0,0 +1,500 @@ +[!fuzz] skip +[short] skip +env GOCACHE=$WORK/cache + +# Test that running a fuzz target that returns without failing or calling +# f.Fuzz fails and causes a non-zero exit status. +! go test noop_fuzz_test.go +! stdout ^ok +stdout FAIL + +# Test that fuzzing a fuzz target that returns without failing or calling +# f.Fuzz fails and causes a non-zero exit status. +! go test -fuzz=Fuzz -fuzztime=1x noop_fuzz_test.go +! stdout ^ok +stdout FAIL + +# Test that calling f.Error in a fuzz target causes a non-zero exit status. +! go test -fuzz=Fuzz -fuzztime=1x error_fuzz_test.go +! stdout ^ok +stdout FAIL + +# Test that calling f.Fatal in a fuzz target causes a non-zero exit status. +! go test fatal_fuzz_test.go +! stdout ^ok +stdout FAIL + +# Test that successful test exits cleanly. +go test success_fuzz_test.go +stdout ^ok +! stdout FAIL + +# Test that successful fuzzing exits cleanly. +go test -fuzz=Fuzz -fuzztime=1x success_fuzz_test.go +stdout ok +! stdout FAIL + +# Test that calling f.Fatal while fuzzing causes a non-zero exit status. +! go test -fuzz=Fuzz -fuzztime=1x fatal_fuzz_test.go +! stdout ^ok +stdout FAIL + +# Test error with seed corpus in f.Fuzz +! go test -run FuzzError fuzz_add_test.go +! stdout ^ok +stdout FAIL +stdout 'error here' + +[short] stop + +# Test that calling panic(nil) in a fuzz target causes a non-zero exit status. +! go test panic_fuzz_test.go +! stdout ^ok +stdout FAIL + +# Test that skipped test exits cleanly. +go test skipped_fuzz_test.go +stdout ok +! stdout FAIL + +# Test that f.Fatal within f.Fuzz panics +! go test fatal_fuzz_fn_fuzz_test.go +! stdout ^ok +! stdout 'fatal here' +stdout FAIL +stdout 'fuzz target' + +# Test that f.Error within f.Fuzz panics +! go test error_fuzz_fn_fuzz_test.go +! stdout ^ok +! stdout 'error here' +stdout FAIL +stdout 'fuzz target' + +# Test that f.Fail within f.Fuzz panics +! go test fail_fuzz_fn_fuzz_test.go +! stdout ^ok +stdout FAIL +stdout 'fuzz target' + +# Test that f.Skip within f.Fuzz panics +! go test skip_fuzz_fn_fuzz_test.go +! stdout ^ok +! stdout 'skip here' +stdout FAIL +stdout 'fuzz target' + +# Test that f.Skipped within f.Fuzz panics +! go test skipped_fuzz_fn_fuzz_test.go +! stdout ^ok +! stdout 'f.Skipped is' +stdout FAIL +stdout 'fuzz target' +stdout 't.Skipped is false' + +# Test that runtime.Goexit within the fuzz function is an error. +! go test goexit_fuzz_fn_fuzz_test.go +! stdout ^ok +stdout FAIL + +# Test that a call to f.Fatal after the Fuzz func is executed. +! go test fatal_after_fuzz_func_fuzz_test.go +! stdout ok +stdout FAIL + +# Test that missing *T in f.Fuzz causes a non-zero exit status. +! go test incomplete_fuzz_call_fuzz_test.go +! stdout ^ok +stdout FAIL + +# Test that a panic in the Cleanup func is executed. +! go test cleanup_fuzz_test.go +! stdout ^ok +stdout FAIL +stdout 'failed some precondition' + +# Test success with seed corpus in f.Fuzz +go test -run FuzzPass fuzz_add_test.go +stdout ok +! stdout FAIL +! stdout 'off by one error' + +# Test fatal with seed corpus in f.Fuzz +! go test -run FuzzFatal fuzz_add_test.go +! stdout ^ok +stdout FAIL +stdout 'fatal here' + +# Test panic with seed corpus in f.Fuzz +! go test -run FuzzPanic fuzz_add_test.go +! stdout ^ok +stdout FAIL +stdout 'off by one error' + +# Test panic(nil) with seed corpus in f.Fuzz +! go test -run FuzzNilPanic fuzz_add_test.go +! stdout ^ok +stdout FAIL + +# Test panic with unsupported seed corpus +! go test -run FuzzUnsupported fuzz_add_test.go +! stdout ^ok +stdout FAIL + +# Test panic with different number of args to f.Add +! go test -run FuzzAddDifferentNumber fuzz_add_test.go +! stdout ^ok +stdout FAIL + +# Test panic with different type of args to f.Add +! go test -run FuzzAddDifferentType fuzz_add_test.go +! stdout ^ok +stdout FAIL + +# Test that the wrong type given with f.Add will fail. +! go test -run FuzzWrongType fuzz_add_test.go +! stdout ^ok +stdout '\[string int\], want \[\[\]uint8 int8\]' +stdout FAIL + +# Test fatal with testdata seed corpus +! go test -run FuzzFail corpustesting/fuzz_testdata_corpus_test.go +! stdout ^ok +stdout FAIL +stdout 'fatal here' + +# Test pass with testdata seed corpus +go test -run FuzzPass corpustesting/fuzz_testdata_corpus_test.go +stdout ok +! stdout FAIL +! stdout 'fatal here' + +# Test pass with testdata and f.Add seed corpus +go test -run FuzzPassString corpustesting/fuzz_testdata_corpus_test.go +stdout ok +! stdout FAIL + +# Fuzzing pass with testdata and f.Add seed corpus (skip running tests first) +go test -run=None -fuzz=FuzzPassString corpustesting/fuzz_testdata_corpus_test.go -fuzztime=10x +stdout ok +! stdout FAIL + +# Fuzzing pass with testdata and f.Add seed corpus +go test -run=FuzzPassString -fuzz=FuzzPassString corpustesting/fuzz_testdata_corpus_test.go -fuzztime=10x +stdout ok +! stdout FAIL + +# Test panic with malformed seed corpus +! go test -run FuzzFail corpustesting/fuzz_testdata_corpus_test.go +! stdout ^ok +stdout FAIL + +# Test pass with file in other nested testdata directory +go test -run FuzzInNestedDir corpustesting/fuzz_testdata_corpus_test.go +stdout ok +! stdout FAIL +! stdout 'fatal here' + +# Test fails with file containing wrong type +! go test -run FuzzWrongType corpustesting/fuzz_testdata_corpus_test.go +! stdout ^ok +stdout FAIL + +-- noop_fuzz_test.go -- +package noop_fuzz + +import "testing" + +func Fuzz(f *testing.F) {} + +-- error_fuzz_test.go -- +package error_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Error("error in target") +} + +-- fatal_fuzz_test.go -- +package fatal_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Fatal("fatal in target") +} + +-- panic_fuzz_test.go -- +package panic_fuzz + +import "testing" + +func FuzzPanic(f *testing.F) { + panic(nil) +} + +-- success_fuzz_test.go -- +package success_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Fuzz(func (*testing.T, []byte) {}) +} + +-- skipped_fuzz_test.go -- +package skipped_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Skip() +} + +-- fatal_fuzz_fn_fuzz_test.go -- +package fatal_fuzz_fn_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Add([]byte("aa")) + f.Fuzz(func(t *testing.T, b []byte) { + f.Fatal("fatal here") + }) +} + +-- error_fuzz_fn_fuzz_test.go -- +package error_fuzz_fn_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Add([]byte("aa")) + f.Fuzz(func(t *testing.T, b []byte) { + f.Error("error here") + }) +} + +-- fail_fuzz_fn_fuzz_test.go -- +package skip_fuzz_fn_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Add([]byte("aa")) + f.Fuzz(func(t *testing.T, b []byte) { + f.Fail() + }) +} + +-- skip_fuzz_fn_fuzz_test.go -- +package skip_fuzz_fn_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Add([]byte("aa")) + f.Fuzz(func(t *testing.T, b []byte) { + f.Skip("skip here") + }) +} + +-- skipped_fuzz_fn_fuzz_test.go -- +package skipped_fuzz_fn_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Add([]byte("aa")) + f.Fuzz(func(t *testing.T, b []byte) { + t.Logf("t.Skipped is %t\n", t.Skipped()) + t.Logf("f.Skipped is %t\n", f.Skipped()) + }) +} + +-- goexit_fuzz_fn_fuzz_test.go -- +package goexit_fuzz_fn_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Add([]byte("aa")) + f.Fuzz(func(t *testing.T, b []byte) { + runtime.Goexit() + }) +} + +-- fatal_after_fuzz_func_fuzz_test.go -- +package fatal_after_fuzz_func_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + // no-op + }) + f.Fatal("this shouldn't be called") +} + +-- incomplete_fuzz_call_fuzz_test.go -- +package incomplete_fuzz_call_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Fuzz(func(b []byte) { + // this is missing *testing.T as the first param, so should panic + }) +} + +-- cleanup_fuzz_test.go -- +package cleanup_fuzz_test + +import "testing" + +func Fuzz(f *testing.F) { + f.Cleanup(func() { + panic("failed some precondition") + }) + f.Fuzz(func(t *testing.T, b []byte) { + // no-op + }) +} + +-- fuzz_add_test.go -- +package fuzz_add + +import "testing" + +func add(f *testing.F) { + f.Helper() + f.Add([]byte("123")) + f.Add([]byte("12345")) + f.Add([]byte("")) +} + +func FuzzPass(f *testing.F) { + add(f) + f.Fuzz(func(t *testing.T, b []byte) { + if len(b) == -1 { + t.Fatal("fatal here") // will not be executed + } + }) +} + +func FuzzError(f *testing.F) { + add(f) + f.Fuzz(func(t *testing.T, b []byte) { + if len(b) == 3 { + t.Error("error here") + } + }) +} + +func FuzzFatal(f *testing.F) { + add(f) + f.Fuzz(func(t *testing.T, b []byte) { + if len(b) == 0 { + t.Fatal("fatal here") + } + }) +} + +func FuzzPanic(f *testing.F) { + add(f) + f.Fuzz(func(t *testing.T, b []byte) { + if len(b) == 5 { + panic("off by one error") + } + }) +} + +func FuzzNilPanic(f *testing.F) { + add(f) + f.Fuzz(func(t *testing.T, b []byte) { + if len(b) == 3 { + panic(nil) + } + }) +} + +func FuzzUnsupported(f *testing.F) { + m := make(map[string]bool) + f.Add(m) + f.Fuzz(func(*testing.T, []byte) {}) +} + +func FuzzAddDifferentNumber(f *testing.F) { + f.Add([]byte("a")) + f.Add([]byte("a"), []byte("b")) + f.Fuzz(func(*testing.T, []byte) {}) +} + +func FuzzAddDifferentType(f *testing.F) { + f.Add(false) + f.Add(1234) + f.Fuzz(func(*testing.T, []byte) {}) +} + +func FuzzWrongType(f *testing.F) { + f.Add("hello", 50) + f.Fuzz(func(*testing.T, []byte, int8) {}) +} + +-- corpustesting/fuzz_testdata_corpus_test.go -- +package fuzz_testdata_corpus + +import "testing" + +func fuzzFn(f *testing.F) { + f.Helper() + f.Fuzz(func(t *testing.T, b []byte) { + if string(b) == "12345" { + t.Fatal("fatal here") + } + }) +} + +func FuzzFail(f *testing.F) { + fuzzFn(f) +} + +func FuzzPass(f *testing.F) { + fuzzFn(f) +} + +func FuzzPassString(f *testing.F) { + f.Add("some seed corpus") + f.Fuzz(func(*testing.T, string) {}) +} + +func FuzzPanic(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) {}) +} + +func FuzzInNestedDir(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) {}) +} + +func FuzzWrongType(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) {}) +} + +-- corpustesting/testdata/fuzz/FuzzFail/1 -- +go test fuzz v1 +[]byte("12345") +-- corpustesting/testdata/fuzz/FuzzPass/1 -- +go test fuzz v1 +[]byte("00000") +-- corpustesting/testdata/fuzz/FuzzPassString/1 -- +go test fuzz v1 +string("hello") +-- corpustesting/testdata/fuzz/FuzzPanic/1 -- +malformed +-- corpustesting/testdata/fuzz/FuzzInNestedDir/anotherdir/1 -- +go test fuzz v1 +[]byte("12345") +-- corpustesting/testdata/fuzz/FuzzWrongType/1 -- +go test fuzz v1 +int("00000") diff --git a/src/cmd/go/testdata/script/test_fuzz_cache.txt b/src/cmd/go/testdata/script/test_fuzz_cache.txt new file mode 100644 index 0000000..752ab3a --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_cache.txt @@ -0,0 +1,97 @@ +[!fuzz-instrumented] skip + +[short] skip +env GOCACHE=$WORK/cache + +# Fuzz cache should not exist after a regular test run. +go test . +exists $GOCACHE +! exists $GOCACHE/fuzz + +# Fuzzing should write interesting values to the cache. +go test -fuzz=FuzzY -fuzztime=100x . +go run ./contains_files $GOCACHE/fuzz/example.com/y/FuzzY + +# 'go clean -cache' should not delete the fuzz cache. +go clean -cache +exists $GOCACHE/fuzz + +# 'go clean -fuzzcache' should delete the fuzz cache but not the build cache. +go build -x ./empty +stderr '(compile|gccgo)( |\.exe).*empty.go' +go clean -fuzzcache +! exists $GOCACHE/fuzz +go build -x ./empty +! stderr '(compile|gccgo)( |\.exe).*empty.go' + +# Fuzzing indicates that one new interesting value was found with an empty +# corpus, and the total size of the cache is now 1. +go clean -fuzzcache +go test -fuzz=FuzzEmpty -fuzztime=10000x . +stdout 'new interesting: 1' +stdout 'total: 1' + +# Fuzzing again with a small fuzztime does not find any other interesting +# values but still indicates that the cache size is 1. +go test -fuzz=FuzzEmpty -fuzztime=2x . +stdout 'new interesting: 0' +stdout 'total: 1' + +! go clean -fuzzcache example.com/y +stderr 'go: clean -fuzzcache cannot be used with package arguments' + +-- go.mod -- +module example.com/y + +go 1.16 +-- y_test.go -- +package y + +import ( + "io" + "testing" +) + +func FuzzEmpty(f *testing.F) { + f.Fuzz(func (*testing.T, []byte) {}) +} + +func FuzzY(f *testing.F) { + f.Add([]byte("y")) + f.Fuzz(func(t *testing.T, b []byte) { Y(io.Discard, b) }) +} +-- y.go -- +package y + +import ( + "bytes" + "io" +) + +func Y(w io.Writer, b []byte) { + if !bytes.Equal(b, []byte("y")) { + w.Write([]byte("not equal")) + } +} +-- empty/empty.go -- +package empty +-- contains_files/contains_files.go -- +package main + +import ( + "fmt" + "path/filepath" + "io/ioutil" + "os" +) + +func main() { + infos, err := ioutil.ReadDir(filepath.Clean(os.Args[1])) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if len(infos) == 0 { + os.Exit(1) + } +} diff --git a/src/cmd/go/testdata/script/test_fuzz_chatty.txt b/src/cmd/go/testdata/script/test_fuzz_chatty.txt new file mode 100644 index 0000000..01a68cb --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_chatty.txt @@ -0,0 +1,103 @@ +[!fuzz] skip +[short] skip +env GOCACHE=$WORK/cache + +# Run chatty fuzz targets with an error. +! go test -v chatty_error_fuzz_test.go +! stdout '^ok' +stdout 'FAIL' +stdout 'error in target' + +# Run chatty fuzz targets with a fatal. +! go test -v chatty_fatal_fuzz_test.go +! stdout '^ok' +stdout 'FAIL' +stdout 'fatal in target' + +# Run chatty fuzz target with a panic +! go test -v chatty_panic_fuzz_test.go +! stdout ^ok +stdout FAIL +stdout 'this is bad' + +# Run skipped chatty fuzz targets. +go test -v chatty_skipped_fuzz_test.go +stdout ok +stdout SKIP +! stdout FAIL + +# Run successful chatty fuzz targets. +go test -v chatty_fuzz_test.go +stdout ok +stdout PASS +stdout 'all good here' +! stdout FAIL + +# Fuzz successful chatty fuzz target that includes a separate unit test. +go test -v chatty_with_test_fuzz_test.go -fuzz=Fuzz -fuzztime=1x +stdout ok +stdout PASS +! stdout FAIL +stdout -count=1 'all good here' +# Verify that the unit test is only run once. +stdout -count=1 'logged foo' + +-- chatty_error_fuzz_test.go -- +package chatty_error_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Error("error in target") +} + +-- chatty_fatal_fuzz_test.go -- +package chatty_fatal_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Fatal("fatal in target") +} + +-- chatty_panic_fuzz_test.go -- +package chatty_panic_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + panic("this is bad") +} + +-- chatty_skipped_fuzz_test.go -- +package chatty_skipped_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Skip() +} + +-- chatty_fuzz_test.go -- +package chatty_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Log("all good here") + f.Fuzz(func(*testing.T, []byte) {}) +} + +-- chatty_with_test_fuzz_test.go -- +package chatty_with_test_fuzz + +import "testing" + +func TestFoo(t *testing.T) { + t.Log("logged foo") +} + +func Fuzz(f *testing.F) { + f.Log("all good here") + f.Fuzz(func(*testing.T, []byte) {}) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_cleanup.txt b/src/cmd/go/testdata/script/test_fuzz_cleanup.txt new file mode 100644 index 0000000..5f86498 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_cleanup.txt @@ -0,0 +1,67 @@ +[!fuzz] skip +[short] skip +env GOCACHE=$WORK/cache + +# Cleanup should run after F.Skip. +go test -run=FuzzTargetSkip +stdout cleanup + +# Cleanup should run after F.Fatal. +! go test -run=FuzzTargetFatal +stdout cleanup + +# Cleanup should run after an unexpected runtime.Goexit. +! go test -run=FuzzTargetGoexit +stdout cleanup + +# Cleanup should run after panic. +! go test -run=FuzzTargetPanic +stdout cleanup + +# Cleanup should run in fuzz function on seed corpus. +go test -v -run=FuzzFunction +stdout '(?s)inner.*outer' + +# TODO(jayconrod): test cleanup while fuzzing. For now, the worker process's +# stdout and stderr is connected to the coordinator's, but it should eventually +# be connected to os.DevNull, so we wouldn't see t.Log output. + +-- go.mod -- +module cleanup + +go 1.15 +-- cleanup_test.go -- +package cleanup + +import ( + "runtime" + "testing" +) + +func FuzzTargetSkip(f *testing.F) { + f.Cleanup(func() { f.Log("cleanup") }) + f.Skip() +} + +func FuzzTargetFatal(f *testing.F) { + f.Cleanup(func() { f.Log("cleanup") }) + f.Fatal() +} + +func FuzzTargetGoexit(f *testing.F) { + f.Cleanup(func() { f.Log("cleanup") }) + runtime.Goexit() +} + +func FuzzTargetPanic(f *testing.F) { + f.Cleanup(func() { f.Log("cleanup") }) + panic("oh no") +} + +func FuzzFunction(f *testing.F) { + f.Add([]byte{0}) + f.Cleanup(func() { f.Log("outer") }) + f.Fuzz(func(t *testing.T, b []byte) { + t.Cleanup(func() { t.Logf("inner") }) + }) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_cov.txt b/src/cmd/go/testdata/script/test_fuzz_cov.txt new file mode 100644 index 0000000..c0844a3 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_cov.txt @@ -0,0 +1,36 @@ +# Test that coverage instrumentation is working. Without the instrumentation +# it is _extremely_ unlikely that the fuzzer would produce this particular +# input in any reasonable amount of time. + +[short] skip +[!fuzz-instrumented] skip +env GOCACHE=$WORK/cache + +# TODO(#51484): enabled debugging info to help diagnose a deadlock in the fuzzer +env GODEBUG=fuzzdebug=1 +! go test -fuzz=FuzzCov -v +! stderr 'cov instrumentation working' + +-- go.mod -- +module test + +-- cov_test.go -- +package cov + +import "testing" + +func FuzzCov(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + if len(b) == 8 && + b[0] == 'h' && + b[1] == 'e' && + b[2] == 'l' && + b[3] == 'l' && + b[4] == 'o' && + b[5] == ' ' && + b[6] == ':' && + b[7] == ')' { + panic("cov instrumentation working") + } + }) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_deadline.txt b/src/cmd/go/testdata/script/test_fuzz_deadline.txt new file mode 100644 index 0000000..46d3521 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_deadline.txt @@ -0,0 +1,36 @@ +[!fuzz] skip +[short] skip +env GOCACHE=$WORK/cache + +# The fuzz function should be able to detect whether -timeout +# was set with T.Deadline. Note there is no F.Deadline, and +# there is no timeout while fuzzing, even if -fuzztime is set. +go test -run=FuzzDeadline -wantdeadline=true # -timeout defaults to 10m +go test -run=FuzzDeadline -timeout=0 -wantdeadline=false +! go test -run=FuzzDeadline -timeout=1s -wantdeadline=false +go test -run=FuzzDeadline -timeout=1s -wantdeadline=true +go test -fuzz=FuzzDeadline -timeout=0 -fuzztime=1s -wantdeadline=false +go test -fuzz=FuzzDeadline -timeout=0 -fuzztime=100x -wantdeadline=false + +-- go.mod -- +module fuzz + +go 1.16 +-- fuzz_deadline_test.go -- +package fuzz_test + +import ( + "flag" + "testing" +) + +var wantDeadline = flag.Bool("wantdeadline", false, "whether the test should have a deadline") + +func FuzzDeadline(f *testing.F) { + f.Add("run once") + f.Fuzz(func (t *testing.T, _ string) { + if _, hasDeadline := t.Deadline(); hasDeadline != *wantDeadline { + t.Fatalf("function got %v; want %v", hasDeadline, *wantDeadline) + } + }) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_dup_cache.txt b/src/cmd/go/testdata/script/test_fuzz_dup_cache.txt new file mode 100644 index 0000000..f54a77c --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_dup_cache.txt @@ -0,0 +1,53 @@ +[!fuzz] skip +[short] skip +env GOCACHE=$WORK/cache + +# This test checks that cached corpus loading properly handles duplicate entries (this can +# happen when a f.Add value has a duplicate entry in the cached corpus.) Duplicate entries +# should be discarded, and the rest of the cache should be loaded as normal. + +env GOCACHE=$WORK/cache +env GODEBUG=fuzzdebug=1 + +mkdir -p $GOCACHE/fuzz/fuzztest/FuzzTarget +go run ./populate $GOCACHE/fuzz/fuzztest/FuzzTarget + +go test -fuzz=FuzzTarget -fuzztime=10x . +stdout 'entries: 5' + +-- go.mod -- +module fuzztest + +go 1.17 + +-- fuzz_test.go -- +package fuzz + +import "testing" + +func FuzzTarget(f *testing.F) { + f.Add(int(0)) + f.Fuzz(func(t *testing.T, _ int) {}) +} + +-- populate/main.go -- +package main + +import ( + "path/filepath" + "fmt" + "os" +) + +func main() { + for i := 0; i < 10; i++ { + b := byte(0) + if i > 5 { + b = byte(i) + } + tmpl := "go test fuzz v1\nint(%d)\n" + if err := os.WriteFile(filepath.Join(os.Args[1], fmt.Sprint(i)), []byte(fmt.Sprintf(tmpl, b)), 0777); err != nil { + panic(err) + } + } +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_fuzz_err_deadlock.txt b/src/cmd/go/testdata/script/test_fuzz_err_deadlock.txt new file mode 100644 index 0000000..4feb41a --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_err_deadlock.txt @@ -0,0 +1,50 @@ +[short] skip +[!fuzz-instrumented] skip + +env GOCACHE=$WORK/cache +! go test -fuzz=FuzzDead -v +# This is a somewhat inexact check, but since we don't prefix the error with anything +# and as the error suffix is platform dependent, this is the best we can do. In the +# deadlock failure case, the test will just deadlock and timeout anyway, so it should +# be clear that that failure mode is different. +stdout 'open' + +-- go.mod -- +module test + +-- cov_test.go -- +package dead + +import ( + "os" + "path/filepath" + "testing" + "time" +) + +func FuzzDead(f *testing.F) { + go func() { + c := filepath.Join(os.Getenv("GOCACHE"), "fuzz", "test", "FuzzDead") + t := time.NewTicker(time.Second) + for range t.C { + files, _ := os.ReadDir(c) + if len(files) > 0 { + os.RemoveAll(c) + } + } + }() + + f.Fuzz(func(t *testing.T, b []byte) { + if len(b) == 8 && + b[0] == 'h' && + b[1] == 'e' && + b[2] == 'l' && + b[3] == 'l' && + b[4] == 'o' && + b[5] == ' ' && + b[6] == ':' && + b[7] == ')' { + return + } + }) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_fuzztime.txt b/src/cmd/go/testdata/script/test_fuzz_fuzztime.txt new file mode 100644 index 0000000..28ef3bf --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_fuzztime.txt @@ -0,0 +1,120 @@ +[!fuzz] skip +[short] skip +env GOCACHE=$WORK/cache + +# There are no seed values, so 'go test' should finish quickly. +go test + +# Fuzzing should exit 0 after fuzztime, even if timeout is short. +go test -timeout=3s -fuzz=FuzzFast -fuzztime=5s + +# We should see the same behavior when invoking the test binary directly. +go test -c +exec ./fuzz.test$GOEXE -test.timeout=3s -test.fuzz=FuzzFast -test.fuzztime=5s -test.parallel=1 -test.fuzzcachedir=$WORK/cache + +# Timeout should not cause inputs to be written as crashers. +! exists testdata/fuzz + +# When we use fuzztime with an "x" suffix, it runs a specific number of times. +# This fuzz function creates a file with a unique name ($pid.$count) on each +# run. We count the files to find the number of runs. +mkdir count +go test -fuzz=FuzzTestCount -fuzztime=1000x -fuzzminimizetime=1x +go run check_file_count.go count 1000 + +# When we use fuzzminimizetime with an "x" suffix, it runs a specific number of +# times while minimizing. This fuzz function creates a file with a unique name +# ($pid.$count) on each run once the first crash has been found. That means that +# there should be one file for each execution of the fuzz function during +# minimization, so we count these to determine how many times minimization was +# run. +mkdir minimizecount +! go test -fuzz=FuzzMinimizeCount -fuzzminimizetime=3x -parallel=1 +go run check_file_count.go minimizecount 3 + +-- go.mod -- +module fuzz + +go 1.16 +-- fuzz_fast_test.go -- +package fuzz_test + +import "testing" + +func FuzzFast(f *testing.F) { + f.Fuzz(func (*testing.T, []byte) {}) +} +-- fuzz_count_test.go -- +package fuzz + +import ( + "fmt" + "os" + "testing" +) + +func FuzzTestCount(f *testing.F) { + pid := os.Getpid() + n := 0 + f.Fuzz(func(t *testing.T, _ []byte) { + name := fmt.Sprintf("count/%v.%d", pid, n) + if err := os.WriteFile(name, nil, 0666); err != nil { + t.Fatal(err) + } + n++ + }) +} +-- fuzz_minimize_count_test.go -- +package fuzz + +import ( + "bytes" + "fmt" + "os" + "testing" +) + +func FuzzMinimizeCount(f *testing.F) { + pid := os.Getpid() + n := 0 + seed := bytes.Repeat([]byte("a"), 357) + f.Add(seed) + crashFound := false + f.Fuzz(func(t *testing.T, b []byte) { + if crashFound { + name := fmt.Sprintf("minimizecount/%v.%d", pid, n) + if err := os.WriteFile(name, nil, 0666); err != nil { + t.Fatal(err) + } + n++ + } + if !bytes.Equal(b, seed) { // this should happen right away + crashFound = true + t.Error("minimize this!") + } + }) +} +-- check_file_count.go -- +// +build ignore + +package main + +import ( + "fmt" + "os" + "strconv" +) + +func main() { + dir, err := os.ReadDir(os.Args[1]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + got := len(dir) + want, _ := strconv.Atoi(os.Args[2]) + if got != want { + fmt.Fprintf(os.Stderr, "got %d files; want %d\n", got, want) + os.Exit(1) + } +} diff --git a/src/cmd/go/testdata/script/test_fuzz_io_error.txt b/src/cmd/go/testdata/script/test_fuzz_io_error.txt new file mode 100644 index 0000000..01b4da6 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_io_error.txt @@ -0,0 +1,102 @@ +# Test that when the coordinator experiences an I/O error communicating +# with a worker, the coordinator stops the worker and reports the error. +# The coordinator should not record a crasher. +# +# We simulate an I/O error in the test by writing garbage to fuzz_out. +# This is unlikely, but possible. It's difficult to simulate interruptions +# due to ^C and EOF errors which are more common. We don't report those. +[short] skip +[!fuzz] skip +env GOCACHE=$WORK/cache + +# If the I/O error occurs before F.Fuzz is called, the coordinator should +# stop the worker and say that. +! go test -fuzz=FuzzClosePipeBefore -parallel=1 +stdout '\s*fuzzing process terminated without fuzzing:' +! stdout 'communicating with fuzzing process' +! exists testdata + +# If the I/O error occurs after F.Fuzz is called (unlikely), just exit. +# It's hard to distinguish this case from the worker being interrupted by ^C +# or exiting with status 0 (which it should do when interrupted by ^C). +! go test -fuzz=FuzzClosePipeAfter -parallel=1 +stdout '^\s*communicating with fuzzing process: invalid character ''!'' looking for beginning of value$' +! exists testdata + +-- go.mod -- +module test + +go 1.17 +-- io_error_test.go -- +package io_error + +import ( + "flag" + "testing" + "time" +) + +func isWorker() bool { + f := flag.Lookup("test.fuzzworker") + if f == nil { + return false + } + get, ok := f.Value.(flag.Getter) + if !ok { + return false + } + return get.Get() == interface{}(true) +} + +func FuzzClosePipeBefore(f *testing.F) { + if isWorker() { + sendGarbageToCoordinator(f) + time.Sleep(3600 * time.Second) // pause until coordinator terminates the process + } + f.Fuzz(func(*testing.T, []byte) {}) +} + +func FuzzClosePipeAfter(f *testing.F) { + f.Fuzz(func(t *testing.T, _ []byte) { + if isWorker() { + sendGarbageToCoordinator(t) + time.Sleep(3600 * time.Second) // pause until coordinator terminates the process + } + }) +} +-- io_error_windows_test.go -- +package io_error + +import ( + "fmt" + "os" + "testing" +) + +func sendGarbageToCoordinator(tb testing.TB) { + v := os.Getenv("GO_TEST_FUZZ_WORKER_HANDLES") + var fuzzInFD, fuzzOutFD uintptr + if _, err := fmt.Sscanf(v, "%x,%x", &fuzzInFD, &fuzzOutFD); err != nil { + tb.Fatalf("parsing GO_TEST_FUZZ_WORKER_HANDLES: %v", err) + } + f := os.NewFile(fuzzOutFD, "fuzz_out") + if _, err := f.Write([]byte("!!")); err != nil { + tb.Fatalf("writing fuzz_out: %v", err) + } +} +-- io_error_notwindows_test.go -- +// +build !windows + +package io_error + +import ( + "os" + "testing" +) + +func sendGarbageToCoordinator(tb testing.TB) { + f := os.NewFile(4, "fuzz_out") + if _, err := f.Write([]byte("!!")); err != nil { + tb.Fatalf("writing fuzz_out: %v", err) + } +} diff --git a/src/cmd/go/testdata/script/test_fuzz_limit_dup_entry.txt b/src/cmd/go/testdata/script/test_fuzz_limit_dup_entry.txt new file mode 100644 index 0000000..d69f6e0 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_limit_dup_entry.txt @@ -0,0 +1,37 @@ +[!fuzz] skip +[short] skip +env GOCACHE=$WORK/cache + +# FuzzA attempts to cause the mutator to create duplicate inputs that generate +# new coverage. Previously this would trigger a corner case when the fuzzer +# had an execution limit, causing it to deadlock and sit in the coordinator +# loop indefinitely, failing to exit once the limit had been exhausted. + +go test -fuzz=FuzzA -fuzztime=100x -parallel=1 + +-- go.mod -- +module m + +go 1.16 +-- fuzz_test.go -- +package fuzz_test + +import ( + "fmt" + "testing" +) + +func FuzzA(f *testing.F) { + f.Add([]byte("seed")) + i := 0 + f.Fuzz(func(t *testing.T, b []byte) { + i++ + if string(b) == "seed" { + if i == 0 { + fmt.Println("a") + } else if i > 1 { + fmt.Println("b") + } + } + }) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_match.txt b/src/cmd/go/testdata/script/test_fuzz_match.txt new file mode 100644 index 0000000..d149586 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_match.txt @@ -0,0 +1,40 @@ +[!fuzz] skip +[short] skip +env GOCACHE=$WORK/cache + +# Matches only fuzz targets to test. +go test standalone_fuzz_test.go +! stdout '^ok.*\[no tests to run\]' +stdout '^ok' + +# Matches only for fuzzing. +go test -fuzz Fuzz -fuzztime 1x standalone_fuzz_test.go +! stdout '^ok.*\[no tests to run\]' +stdout '^ok' + +# Matches none for fuzzing but will run the fuzz target as a test. +go test -fuzz ThisWillNotMatch -fuzztime 1x standalone_fuzz_test.go +! stdout '^ok.*no tests to run' +stdout '^ok' +stdout 'no fuzz tests to fuzz' + +[short] stop + +# Matches only fuzz targets to test with -run. +go test -run Fuzz standalone_fuzz_test.go +! stdout '^ok.*\[no tests to run\]' +stdout '^ok' + +# Matches no fuzz targets. +go test -run ThisWillNotMatch standalone_fuzz_test.go +stdout '^ok.*no tests to run' +! stdout 'no fuzz tests to fuzz' + +-- standalone_fuzz_test.go -- +package standalone_fuzz + +import "testing" + +func Fuzz(f *testing.F) { + f.Fuzz(func (*testing.T, []byte) {}) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_minimize.txt b/src/cmd/go/testdata/script/test_fuzz_minimize.txt new file mode 100644 index 0000000..a6dc3f1 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_minimize.txt @@ -0,0 +1,203 @@ +[!fuzz] skip +[short] skip + +# We clean the fuzz cache during this test. Don't clean the user's cache. +env GOCACHE=$WORK/gocache + +# Test that fuzzminimizetime cannot be negative seconds +! go test -fuzz=FuzzMinimizerRecoverable -run=FuzzMinimizerRecoverable -fuzztime=10000x -fuzzminimizetime=-1ms . +! stdout '^ok' +! stdout 'contains a non-zero byte' +stdout 'invalid duration' +stdout FAIL + +# Test that fuzzminimizetime cannot be negative times +! go test -fuzz=FuzzMinimizerRecoverable -run=FuzzMinimizerRecoverable -fuzztime=10000x -fuzzminimizetime=-1x . +! stdout '^ok' +! stdout 'contains a non-zero byte' +stdout 'invalid count' +stdout FAIL + +# Test that fuzzminimizetime can be zero seconds, and minimization is disabled +! go test -fuzz=FuzzMinimizeZeroDurationSet -run=FuzzMinimizeZeroDurationSet -fuzztime=10000x -fuzzminimizetime=0s . +! stdout '^ok' +! stdout 'minimizing' +stdout 'there was an Error' +stdout FAIL + +# Test that fuzzminimizetime can be zero times, and minimization is disabled +! go test -fuzz=FuzzMinimizeZeroLimitSet -run=FuzzMinimizeZeroLimitSet -fuzztime=10000x -fuzzminimizetime=0x . +! stdout '^ok' +! stdout 'minimizing' +stdout -count=1 'there was an Error' +stdout FAIL + +# Test that minimization is working for recoverable errors. +! go test -fuzz=FuzzMinimizerRecoverable -run=FuzzMinimizerRecoverable -fuzztime=10000x . +! stdout '^ok' +stdout 'got the minimum size!' +# The error message that was printed should be for the one written to testdata. +stdout 'contains a non-zero byte of length 50' +stdout FAIL + +# Check that the bytes written to testdata are of length 50 (the minimum size) +go run ./check_testdata FuzzMinimizerRecoverable 50 + +# Test that re-running the minimized value causes a crash. +! go test -run=FuzzMinimizerRecoverable . +rm testdata + +# Test that minimization is working for recoverable errors. Run it with -v this +# time to ensure the command line output still looks right. +! go test -v -fuzz=FuzzMinimizerRecoverable -run=FuzzMinimizerRecoverable -fuzztime=10000x . +! stdout '^ok' +stdout 'got the minimum size!' +# The error message that was printed should be for the one written to testdata. +stdout 'contains a non-zero byte of length 50' +stdout FAIL + +# Check that the bytes written to testdata are of length 50 (the minimum size) +go run ./check_testdata FuzzMinimizerRecoverable 50 + +# Test that re-running the minimized value causes a crash. +! go test -run=FuzzMinimizerRecoverable . +rm testdata + +# Test that minimization doesn't run for non-recoverable errors. +! go test -fuzz=FuzzMinimizerNonrecoverable -run=FuzzMinimizerNonrecoverable -fuzztime=10000x . +! stdout '^ok' +! stdout 'minimizing' +stdout -count=1 '^\s+fuzzing process hung or terminated unexpectedly: exit status 99' +stdout FAIL + +# Check that re-running the value causes a crash. +! go test -run=FuzzMinimizerNonrecoverable . +rm testdata + +# Clear the fuzzing cache. There may already be minimized inputs that would +# interfere with the next stage of the test. +go clean -fuzzcache + +# Test that minimization can be cancelled by fuzzminimizetime and the latest +# crash will still be logged and written to testdata. +! go test -fuzz=FuzzMinimizerRecoverable -run=FuzzMinimizerRecoverable -fuzztime=100x -fuzzminimizetime=1x . +! stdout '^ok' +stdout 'testdata[/\\]fuzz[/\\]FuzzMinimizerRecoverable[/\\]' +! stdout 'got the minimum size!' # it shouldn't have had enough time to minimize it +stdout FAIL + +# Test that re-running the unminimized value causes a crash. +! go test -run=FuzzMinimizerRecoverable . + +# TODO(jayconrod,katiehockman): add a test which verifies that the right bytes +# are written to testdata in the case of an interrupt during minimization. + +-- go.mod -- +module example.com/y + +go 1.16 +-- y_test.go -- +package y + +import ( + "os" + "testing" +) + +func FuzzMinimizeZeroDurationSet(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + if len(b) > 5 { + t.Errorf("there was an Error") + } + }) +} + +func FuzzMinimizeZeroLimitSet(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + if len(b) > 5 { + t.Errorf("there was an Error") + } + }) +} + +func FuzzMinimizerRecoverable(f *testing.F) { + f.Add(make([]byte, 100)) + f.Fuzz(func(t *testing.T, b []byte) { + if len(b) < 50 { + // Make sure that b is large enough that it can be minimized + return + } + // Given the randomness of the mutations, this should allow the + // minimizer to trim down the value a bit. + for _, n := range b { + if n != 0 { + if len(b) == 50 { + t.Log("got the minimum size!") + } + t.Fatalf("contains a non-zero byte of length %d", len(b)) + } + } + }) +} + +func FuzzMinimizerNonrecoverable(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + os.Exit(99) + }) +} +-- empty/empty.go -- +package empty +-- check_testdata/check_testdata.go -- +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strconv" +) + +func main() { + target := os.Args[1] + numBytes, err := strconv.Atoi(os.Args[2]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + // Open the file in testdata (there should only be one) + dir := fmt.Sprintf("testdata/fuzz/%s", target) + files, err := ioutil.ReadDir(dir) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if len(files) != 1 { + fmt.Fprintf(os.Stderr, "expected one file, got %d", len(files)) + os.Exit(1) + } + got, err := ioutil.ReadFile(filepath.Join(dir, files[0].Name())) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + // Trim the newline at the end of the file + got = bytes.TrimSpace(got) + + // Make sure that there were exactly 100 bytes written to the corpus entry + prefix := []byte("[]byte(") + i := bytes.Index(got, prefix) + gotBytes := got[i+len(prefix) : len(got)-1] + s, err := strconv.Unquote(string(gotBytes)) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if want, got := numBytes, len(s); want != got { + fmt.Fprintf(os.Stderr, "want %d bytes, got %d\n", want, got) + os.Exit(1) + } +} diff --git a/src/cmd/go/testdata/script/test_fuzz_minimize_dirty_cov.txt b/src/cmd/go/testdata/script/test_fuzz_minimize_dirty_cov.txt new file mode 100644 index 0000000..c8af9be --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_minimize_dirty_cov.txt @@ -0,0 +1,85 @@ +# Test that minimization doesn't use dirty coverage snapshots when it +# is unable to actually minimize the input. We do this by checking that +# an expected value appears in the cache. If a dirty coverage map is used +# (i.e. the coverage map generated during the last minimization step, +# rather than the map provided with the initial input) then this value +# is unlikely to appear in the cache, since the map generated during +# the last minimization step should not increase the coverage. + +[short] skip +[!fuzz-instrumented] skip + +env GOCACHE=$WORK/gocache +go test -fuzz=FuzzCovMin -fuzztime=500000x -test.fuzzcachedir=$GOCACHE/fuzz +go run check_file/main.go $GOCACHE/fuzz/FuzzCovMin ab + +-- go.mod -- +module test + +-- covmin_test.go -- +package covmin + +import "testing" + +func FuzzCovMin(f *testing.F) { + f.Add([]byte("aa")) + f.Fuzz(func(t *testing.T, data []byte) { + if len(data) == 2 && data[0] == 'a' && data[1] == 'b' { + return + } + }) +} + +-- check_file/main.go -- +package main + +import ( + "bytes" + "fmt" + "os" + "path/filepath" + "regexp" + "strconv" +) + +func checkFile(name, expected string) (bool, error) { + data, err := os.ReadFile(name) + if err != nil { + return false, err + } + for _, line := range bytes.Split(data, []byte("\n")) { + m := valRe.FindSubmatch(line) + if m == nil { + continue + } + fmt.Println(strconv.Unquote(string(m[1]))) + if s, err := strconv.Unquote(string(m[1])); err != nil { + return false, err + } else if s == expected { + return true, nil + } + } + return false, nil +} + +var valRe = regexp.MustCompile(`^\[\]byte\(([^)]+)\)$`) + +func main() { + dir, expected := os.Args[1], os.Args[2] + ents, err := os.ReadDir(dir) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + for _, ent := range ents { + name := filepath.Join(dir, ent.Name()) + if good, err := checkFile(name, expected); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } else if good { + os.Exit(0) + } + } + fmt.Fprintln(os.Stderr, "input over minimized") + os.Exit(1) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_minimize_interesting.txt b/src/cmd/go/testdata/script/test_fuzz_minimize_interesting.txt new file mode 100644 index 0000000..11aaaca --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_minimize_interesting.txt @@ -0,0 +1,230 @@ +[short] skip +[!fuzz-instrumented] skip + +# Test that when an interesting value is discovered (one that expands coverage), +# the fuzzing engine minimizes it before writing it to the cache. +# +# The program below starts with a seed value of length 100, but more coverage +# will be found for any value other than the seed. We should end with a value +# in the cache of length 1 (the minimizer currently does not produce empty +# strings). check_cache.go confirms that. +# +# We would like to verify that ALL values in the cache were minimized to a +# length of 1, but this isn't always possible when new coverage is found in +# functions called by testing or internal/fuzz in the background. + +go test -c -fuzz=. # Build using shared build cache for speed. +env GOCACHE=$WORK/gocache +exec ./fuzz.test$GOEXE -test.fuzzcachedir=$GOCACHE/fuzz -test.fuzz=FuzzMinCache -test.fuzztime=1000x +go run check_cache/check_cache.go $GOCACHE/fuzz/FuzzMinCache + +# Test that minimization occurs for a crash that appears while minimizing a +# newly found interesting input. There must be only one worker for this test to +# be flaky like we want. +! exec ./fuzz.test$GOEXE -test.fuzzcachedir=$GOCACHE/fuzz -test.fuzz=FuzzMinimizerCrashInMinimization -test.run=^$ -test.fuzztime=10000x -test.parallel=1 +! stdout '^ok' +stdout -count=1 'got the minimum size!' +stdout -count=1 'bad input' +stdout FAIL +# Check that the input written to testdata will reproduce the error, and is the +# smallest possible. +go run check_testdata/check_testdata.go FuzzMinimizerCrashInMinimization 1 + +# Test that a nonrecoverable error that occurs while minimizing an interesting +# input is reported correctly. +! exec ./fuzz.test$GOEXE -test.fuzzcachedir=$GOCACHE/fuzz -test.fuzz=FuzzMinimizerNonrecoverableCrashInMinimization -test.run=^$ -test.fuzztime=10000x -test.parallel=1 +! stdout '^ok' +stdout -count=1 'fuzzing process hung or terminated unexpectedly while minimizing' +stdout -count=1 'EOF' +stdout FAIL +# Check that the input written to testdata will reproduce the error. +go run check_testdata/check_testdata.go FuzzMinimizerNonrecoverableCrashInMinimization 1 + +-- go.mod -- +module fuzz + +go 1.17 +-- y.go -- +package fuzz + +import ( + "bytes" + "io" +) + +func Y(w io.Writer, s string) { + if !bytes.Equal([]byte(s), []byte("y")) { + w.Write([]byte("not equal")) + } +} +-- fuzz_test.go -- +package fuzz + +import ( + "bytes" + "os" + "testing" +) + +func FuzzMinimizerCrashInMinimization(f *testing.F) { + seed := bytes.Repeat([]byte{255}, 100) + f.Add(seed) + f.Fuzz(func(t *testing.T, b []byte) { + if bytes.Equal(seed, b) { + return + } + t.Error("bad input") + if len(b) == 1 { + t.Error("got the minimum size!") + } + }) +} + +var fuzzing bool + +func FuzzMinimizerNonrecoverableCrashInMinimization(f *testing.F) { + seed := bytes.Repeat([]byte{255}, 100) + f.Add(seed) + f.Fuzz(func(t *testing.T, b []byte) { + if bytes.Equal(seed, b) { + return + } else if len(b) == 1 { + os.Exit(1) + } + }) +} + +func FuzzMinCache(f *testing.F) { + seed := bytes.Repeat([]byte("a"), 20) + f.Add(seed) + f.Fuzz(func(t *testing.T, buf []byte) { + if bytes.Equal(buf, seed) { + return + } + }) +} +-- check_testdata/check_testdata.go -- +//go:build ignore +// +build ignore + +// check_testdata.go checks that the string written +// is not longer than the provided length. +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "regexp" + "strconv" +) + +func main() { + wantLen, err := strconv.Atoi(os.Args[2]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + testName := os.Args[1] + dir := filepath.Join("testdata/fuzz", testName) + + files, err := ioutil.ReadDir(dir) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + if len(files) == 0 { + fmt.Fprintf(os.Stderr, "expect at least one failure to be written to testdata\n") + os.Exit(1) + } + + for _, f := range files { + data, err := ioutil.ReadFile(filepath.Join(dir, f.Name())) + if err != nil { + panic(err) + } + var containsVal bool + for _, line := range bytes.Split(data, []byte("\n")) { + m := valRe.FindSubmatch(line) + if m == nil { + continue + } + containsVal = true + s, err := strconv.Unquote(string(m[1])) + if err != nil { + panic(err) + } + if len(s) != wantLen { + fmt.Fprintf(os.Stderr, "expect length %d, got %d (%q)\n", wantLen, len(s), line) + os.Exit(1) + } + } + if !containsVal { + fmt.Fprintln(os.Stderr, "corpus file contained no values") + os.Exit(1) + } + } +} + +var valRe = regexp.MustCompile(`^\[\]byte\(([^)]+)\)$`) + +-- check_cache/check_cache.go -- +//go:build ignore +// +build ignore + +// check_cache.go checks that each file in the cached corpus has a []byte +// of length at most 1. This verifies that at least one cached input is minimized. +package main + +import ( + "bytes" + "fmt" + "os" + "path/filepath" + "regexp" + "strconv" +) + +func main() { + dir := os.Args[1] + ents, err := os.ReadDir(dir) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + for _, ent := range ents { + name := filepath.Join(dir, ent.Name()) + if good, err := checkCacheFile(name); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } else if good { + os.Exit(0) + } + } + fmt.Fprintln(os.Stderr, "no cached inputs were minimized") + os.Exit(1) +} + +func checkCacheFile(name string) (good bool, err error) { + data, err := os.ReadFile(name) + if err != nil { + return false, err + } + for _, line := range bytes.Split(data, []byte("\n")) { + m := valRe.FindSubmatch(line) + if m == nil { + continue + } + if s, err := strconv.Unquote(string(m[1])); err != nil { + return false, err + } else if len(s) <= 1 { + return true, nil + } + } + return false, nil +} + +var valRe = regexp.MustCompile(`^\[\]byte\(([^)]+)\)$`) diff --git a/src/cmd/go/testdata/script/test_fuzz_modcache.txt b/src/cmd/go/testdata/script/test_fuzz_modcache.txt new file mode 100644 index 0000000..c0f18ea --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_modcache.txt @@ -0,0 +1,58 @@ +# This test demonstrates the fuzz corpus behavior for packages outside of the main module. +# (See https://golang.org/issue/48495.) + +[short] skip + +# Set -modcacherw so that the test behaves the same regardless of whether the +# module cache is writable. (For example, on some platforms it can always be +# written if the user is running as root.) At one point, a failing fuzz test +# in a writable module cache would corrupt module checksums in the cache. +env GOFLAGS=-modcacherw + + +# When the upstream module has no test corpus, running 'go test' should succeed, +# but 'go test -fuzz=.' should error out before running the test. +# (It should NOT corrupt the module cache by writing out new fuzz inputs, +# even if the cache is writable.) + +go get -t example.com/fuzzfail@v0.1.0 +go test example.com/fuzzfail + +! go test -fuzz=. example.com/fuzzfail +! stdout . +stderr '^cannot use -fuzz flag on package outside the main module$' + +go mod verify + + +# If the module does include a test corpus, 'go test' (without '-fuzz') should +# load that corpus and run the fuzz tests against it, but 'go test -fuzz=.' +# should continue to be rejected. + +go get -t example.com/fuzzfail@v0.2.0 + +! go test example.com/fuzzfail +stdout '^\s*fuzzfail_test\.go:7: oops:' + +! go test -fuzz=. example.com/fuzzfail +! stdout . +stderr '^cannot use -fuzz flag on package outside the main module$' + +go mod verify + + +# Packages in 'std' cannot be fuzzed when the corresponding GOROOT module is not +# the main module — either the failures would not be recorded or the behavior of +# the 'std' tests would change globally. + +! go test -fuzz . encoding/json +stderr '^cannot use -fuzz flag on package outside the main module$' + +! go test -fuzz . cmd/buildid +stderr '^cannot use -fuzz flag on package outside the main module$' + + +-- go.mod -- +module example.com/m + +go 1.18 diff --git a/src/cmd/go/testdata/script/test_fuzz_multiple.txt b/src/cmd/go/testdata/script/test_fuzz_multiple.txt new file mode 100644 index 0000000..c96112f --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_multiple.txt @@ -0,0 +1,50 @@ +# This test checks that 'go test' prints a reasonable error when fuzzing is +# enabled, and multiple package or multiple fuzz targets match. +# TODO(#46312): support fuzzing multiple targets in multiple packages. + +[!fuzz] skip +[short] skip +env GOCACHE=$WORK/cache + +# With fuzzing disabled, multiple targets can be tested. +go test ./... + +# With fuzzing enabled, at most one package may be tested, +# even if only one package contains fuzz targets. +! go test -fuzz=. ./... +stderr '^cannot use -fuzz flag with multiple packages$' +! go test -fuzz=. ./zero ./one +stderr '^cannot use -fuzz flag with multiple packages$' +go test -fuzz=. -fuzztime=1x ./one + +# With fuzzing enabled, at most one target in the same package may match. +! go test -fuzz=. ./two +stdout '^testing: will not fuzz, -fuzz matches more than one fuzz test: \[FuzzOne FuzzTwo\]$' +go test -fuzz=FuzzTwo -fuzztime=1x ./two + +-- go.mod -- +module fuzz + +go 1.18 +-- zero/zero.go -- +package zero +-- one/one_test.go -- +package one + +import "testing" + +func FuzzOne(f *testing.F) { + f.Fuzz(func(*testing.T, []byte) {}) +} +-- two/two_test.go -- +package two + +import "testing" + +func FuzzOne(f *testing.F) { + f.Fuzz(func(*testing.T, []byte) {}) +} + +func FuzzTwo(f *testing.F) { + f.Fuzz(func(*testing.T, []byte) {}) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_mutate_crash.txt b/src/cmd/go/testdata/script/test_fuzz_mutate_crash.txt new file mode 100644 index 0000000..4b9b36d --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_mutate_crash.txt @@ -0,0 +1,323 @@ +[!fuzz] skip + +# Tests that a crash caused by a mutator-discovered input writes the bad input +# to testdata, and fails+reports correctly. This tests the end-to-end behavior +# of the mutator finding a crash while fuzzing, adding it as a regression test +# to the seed corpus in testdata, and failing the next time the test is run. + +[short] skip +env GOCACHE=$WORK/cache + +# Running the seed corpus for all of the targets should pass the first +# time, since nothing in the seed corpus will cause a crash. +go test + +# Running the fuzzer should find a crashing input quickly. +! go test -fuzz=FuzzWithBug -fuzztime=100x -fuzzminimizetime=1000x +stdout 'testdata[/\\]fuzz[/\\]FuzzWithBug[/\\]' +stdout 'this input caused a crash!' +go run check_testdata.go FuzzWithBug + +# Now, the failing bytes should have been added to the seed corpus for +# the target, and should fail when run without fuzzing. +! go test +stdout 'FuzzWithBug/[a-f0-9]{16}' +stdout 'this input caused a crash!' + +! go test -run=FuzzWithNilPanic -fuzz=FuzzWithNilPanic -fuzztime=100x -fuzzminimizetime=1000x +stdout 'testdata[/\\]fuzz[/\\]FuzzWithNilPanic[/\\]' +stdout 'panic called with nil argument|test executed panic.nil. or runtime.Goexit' +go run check_testdata.go FuzzWithNilPanic + +! go test -run=FuzzWithGoexit -fuzz=FuzzWithGoexit -fuzztime=100x -fuzzminimizetime=1000x +stdout 'testdata[/\\]fuzz[/\\]FuzzWithGoexit[/\\]' +stdout 'runtime.Goexit' +go run check_testdata.go FuzzWithGoexit + +! go test -run=FuzzWithFail -fuzz=FuzzWithFail -fuzztime=100x -fuzzminimizetime=1000x +stdout 'testdata[/\\]fuzz[/\\]FuzzWithFail[/\\]' +go run check_testdata.go FuzzWithFail + +! go test -run=FuzzWithLogFail -fuzz=FuzzWithLogFail -fuzztime=100x -fuzzminimizetime=1000x +stdout 'testdata[/\\]fuzz[/\\]FuzzWithLogFail[/\\]' +stdout 'logged something' +go run check_testdata.go FuzzWithLogFail + +! go test -run=FuzzWithErrorf -fuzz=FuzzWithErrorf -fuzztime=100x -fuzzminimizetime=1000x +stdout 'testdata[/\\]fuzz[/\\]FuzzWithErrorf[/\\]' +stdout 'errorf was called here' +go run check_testdata.go FuzzWithErrorf + +! go test -run=FuzzWithFatalf -fuzz=FuzzWithFatalf -fuzztime=100x -fuzzminimizetime=1000x +stdout 'testdata[/\\]fuzz[/\\]FuzzWithFatalf[/\\]' +stdout 'fatalf was called here' +go run check_testdata.go FuzzWithFatalf + +! go test -run=FuzzWithBadExit -fuzz=FuzzWithBadExit -fuzztime=100x -fuzzminimizetime=1000x +stdout 'testdata[/\\]fuzz[/\\]FuzzWithBadExit[/\\]' +stdout '^\s+fuzzing process hung or terminated unexpectedly: exit status' +go run check_testdata.go FuzzWithBadExit + +! go test -run=FuzzDeadlock -fuzz=FuzzDeadlock -fuzztime=100x -fuzzminimizetime=0x +stdout 'testdata[/\\]fuzz[/\\]FuzzDeadlock[/\\]' +stdout '^\s+fuzzing process hung or terminated unexpectedly: exit status' +go run check_testdata.go FuzzDeadlock + +# Running the fuzzer should find a crashing input quickly for fuzzing two types. +! go test -run=FuzzWithTwoTypes -fuzz=FuzzWithTwoTypes -fuzztime=100x -fuzzminimizetime=1000x +stdout 'testdata[/\\]fuzz[/\\]FuzzWithTwoTypes[/\\]' +stdout 'these inputs caused a crash!' +go run check_testdata.go FuzzWithTwoTypes + +# Running the fuzzer should find a crashing input quickly for an integer. +! go test -run=FuzzInt -fuzz=FuzzInt -fuzztime=100x -fuzzminimizetime=1000x +stdout 'testdata[/\\]fuzz[/\\]FuzzInt[/\\]' +stdout 'this input caused a crash!' +go run check_testdata.go FuzzInt + +! go test -run=FuzzUint -fuzz=FuzzUint -fuzztime=100x -fuzzminimizetime=1000x +stdout 'testdata[/\\]fuzz[/\\]FuzzUint[/\\]' +stdout 'this input caused a crash!' +go run check_testdata.go FuzzUint + +# Running the fuzzer should find a crashing input quickly for a bool. +! go test -run=FuzzBool -fuzz=FuzzBool -fuzztime=100x -fuzzminimizetime=1000x +stdout 'testdata[/\\]fuzz[/\\]FuzzBool[/\\]' +stdout 'this input caused a crash!' +go run check_testdata.go FuzzBool + +# Running the fuzzer should find a crashing input quickly for a float. +! go test -run=FuzzFloat -fuzz=FuzzFloat -fuzztime=100x -fuzzminimizetime=1000x +stdout 'testdata[/\\]fuzz[/\\]FuzzFloat[/\\]' +stdout 'this input caused a crash!' +go run check_testdata.go FuzzFloat + +# Running the fuzzer should find a crashing input quickly for a byte. +! go test -run=FuzzByte -fuzz=FuzzByte -fuzztime=100x -fuzzminimizetime=1000x +stdout 'testdata[/\\]fuzz[/\\]FuzzByte[/\\]' +stdout 'this input caused a crash!' +go run check_testdata.go FuzzByte + +# Running the fuzzer should find a crashing input quickly for a rune. +! go test -run=FuzzRune -fuzz=FuzzRune -fuzztime=100x -fuzzminimizetime=1000x +stdout 'testdata[/\\]fuzz[/\\]FuzzRune[/\\]' +stdout 'this input caused a crash!' +go run check_testdata.go FuzzRune + +# Running the fuzzer should find a crashing input quickly for a string. +! go test -run=FuzzString -fuzz=FuzzString -fuzztime=100x -fuzzminimizetime=1000x +stdout 'testdata[/\\]fuzz[/\\]FuzzString[/\\]' +stdout 'this input caused a crash!' +go run check_testdata.go FuzzString + +-- go.mod -- +module m + +go 1.16 +-- fuzz_crash_test.go -- +package fuzz_crash + +import ( + "os" + "runtime" + "testing" +) + +func FuzzWithBug(f *testing.F) { + f.Add([]byte("aa")) + f.Fuzz(func(t *testing.T, b []byte) { + if string(b) != "aa" { + panic("this input caused a crash!") + } + }) +} + +func FuzzWithNilPanic(f *testing.F) { + f.Add([]byte("aa")) + f.Fuzz(func(t *testing.T, b []byte) { + if string(b) != "aa" { + panic(nil) + } + }) +} + +func FuzzWithGoexit(f *testing.F) { + f.Add([]byte("aa")) + f.Fuzz(func(t *testing.T, b []byte) { + if string(b) != "aa" { + runtime.Goexit() + } + }) +} + +func FuzzWithFail(f *testing.F) { + f.Add([]byte("aa")) + f.Fuzz(func(t *testing.T, b []byte) { + if string(b) != "aa" { + t.Fail() + } + }) +} + +func FuzzWithLogFail(f *testing.F) { + f.Add([]byte("aa")) + f.Fuzz(func(t *testing.T, b []byte) { + if string(b) != "aa" { + t.Log("logged something") + t.Fail() + } + }) +} + +func FuzzWithErrorf(f *testing.F) { + f.Add([]byte("aa")) + f.Fuzz(func(t *testing.T, b []byte) { + if string(b) != "aa" { + t.Errorf("errorf was called here") + } + }) +} + +func FuzzWithFatalf(f *testing.F) { + f.Add([]byte("aa")) + f.Fuzz(func(t *testing.T, b []byte) { + if string(b) != "aa" { + t.Fatalf("fatalf was called here") + } + }) +} + +func FuzzWithBadExit(f *testing.F) { + f.Add([]byte("aa")) + f.Fuzz(func(t *testing.T, b []byte) { + if string(b) != "aa" { + os.Exit(1) + } + }) +} + +func FuzzDeadlock(f *testing.F) { + f.Add(int(0)) + f.Fuzz(func(t *testing.T, n int) { + if n != 0 { + select {} + } + }) +} + +func FuzzWithTwoTypes(f *testing.F) { + f.Fuzz(func(t *testing.T, a, b []byte) { + if len(a) > 0 && len(b) > 0 { + panic("these inputs caused a crash!") + } + }) +} + +func FuzzInt(f *testing.F) { + f.Add(0) + f.Fuzz(func(t *testing.T, a int) { + if a != 0 { + panic("this input caused a crash!") + } + }) +} + +func FuzzUint(f *testing.F) { + f.Add(uint(0)) + f.Fuzz(func(t *testing.T, a uint) { + if a != 0 { + panic("this input caused a crash!") + } + }) +} + +func FuzzBool(f *testing.F) { + f.Add(false) + f.Fuzz(func(t *testing.T, a bool) { + if a { + panic("this input caused a crash!") + } + }) +} + +func FuzzFloat(f *testing.F) { + f.Fuzz(func(t *testing.T, a float64) { + if a != 0 { + panic("this input caused a crash!") + } + }) +} + +func FuzzByte(f *testing.F) { + f.Add(byte(0)) + f.Fuzz(func(t *testing.T, a byte) { + if a != 0 { + panic("this input caused a crash!") + } + }) +} + +func FuzzRune(f *testing.F) { + f.Add(rune(0)) + f.Fuzz(func(t *testing.T, a rune) { + if a != 0 { + panic("this input caused a crash!") + } + }) +} + +func FuzzString(f *testing.F) { + f.Add("") + f.Fuzz(func(t *testing.T, a string) { + if a != "" { + panic("this input caused a crash!") + } + }) +} + +-- check_testdata.go -- +// +build ignore + +package main + +import ( + "bytes" + "crypto/sha256" + "fmt" + "io/ioutil" + "os" + "path/filepath" +) + +func main() { + target := os.Args[1] + dir := filepath.Join("testdata/fuzz", target) + + files, err := ioutil.ReadDir(dir) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + if len(files) == 0 { + fmt.Fprintf(os.Stderr, "expect at least one new mutation to be written to testdata\n") + os.Exit(1) + } + + fname := files[0].Name() + contents, err := ioutil.ReadFile(filepath.Join(dir, fname)) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if bytes.Equal(contents, []byte("aa")) { + fmt.Fprintf(os.Stderr, "newly written testdata entry was not mutated\n") + os.Exit(1) + } + // The hash of the bytes in the file should match the filename. + h := []byte(fmt.Sprintf("%x", sha256.Sum256(contents))) + if !bytes.HasPrefix(h, []byte(fname)) { + fmt.Fprintf(os.Stderr, "hash of bytes %q does not match filename %q\n", h, fname) + os.Exit(1) + } +} diff --git a/src/cmd/go/testdata/script/test_fuzz_mutate_fail.txt b/src/cmd/go/testdata/script/test_fuzz_mutate_fail.txt new file mode 100644 index 0000000..213b73a --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_mutate_fail.txt @@ -0,0 +1,103 @@ +[!fuzz] skip + +# Check that if a worker does not call F.Fuzz or calls F.Fail first, +# 'go test' exits non-zero and no crasher is recorded. + +[short] skip +env GOCACHE=$WORK/cache + +! go test -fuzz=FuzzReturn +! exists testdata + +! go test -fuzz=FuzzSkip +! exists testdata + +! go test -fuzz=FuzzFail +! exists testdata + +! go test -fuzz=FuzzPanic +! exists testdata + +! go test -fuzz=FuzzNilPanic +! exists testdata + +! go test -fuzz=FuzzGoexit +! exists testdata + +! go test -fuzz=FuzzExit +! exists testdata + +-- go.mod -- +module m + +go 1.17 +-- fuzz_fail_test.go -- +package fuzz_fail + +import ( + "flag" + "os" + "runtime" + "testing" +) + +func isWorker() bool { + f := flag.Lookup("test.fuzzworker") + if f == nil { + return false + } + get, ok := f.Value.(flag.Getter) + if !ok { + return false + } + return get.Get() == interface{}(true) +} + +func FuzzReturn(f *testing.F) { + if isWorker() { + return + } + f.Fuzz(func(*testing.T, []byte) {}) +} + +func FuzzSkip(f *testing.F) { + if isWorker() { + f.Skip() + } + f.Fuzz(func(*testing.T, []byte) {}) +} + +func FuzzFail(f *testing.F) { + if isWorker() { + f.Fail() + } + f.Fuzz(func(*testing.T, []byte) {}) +} + +func FuzzPanic(f *testing.F) { + if isWorker() { + panic("nope") + } + f.Fuzz(func(*testing.T, []byte) {}) +} + +func FuzzNilPanic(f *testing.F) { + if isWorker() { + panic(nil) + } + f.Fuzz(func(*testing.T, []byte) {}) +} + +func FuzzGoexit(f *testing.F) { + if isWorker() { + runtime.Goexit() + } + f.Fuzz(func(*testing.T, []byte) {}) +} + +func FuzzExit(f *testing.F) { + if isWorker() { + os.Exit(99) + } + f.Fuzz(func(*testing.T, []byte) {}) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_mutator.txt b/src/cmd/go/testdata/script/test_fuzz_mutator.txt new file mode 100644 index 0000000..cc1f989 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_mutator.txt @@ -0,0 +1,166 @@ +[!fuzz] skip + +# Test basic fuzzing mutator behavior. +# +# fuzz_test.go has two fuzz targets (FuzzA, FuzzB) which both add a seed value. +# Each fuzz function writes the input to a log file. The coordinator and worker +# use separate log files. check_logs.go verifies that the coordinator only +# tests seed values and the worker tests mutated values on the fuzz target. + +[short] skip +env GOCACHE=$WORK/cache + +go test -fuzz=FuzzA -fuzztime=100x -parallel=1 -log=fuzz +go run check_logs.go fuzz fuzz.worker + +# TODO(b/181800488): remove -parallel=1, here and below. For now, when a +# crash is found, all workers keep running, wasting resources and reducing +# the number of executions available to the minimizer, increasing flakiness. + +# Test that the mutator is good enough to find several unique mutations. +! go test -fuzz=FuzzMutator -parallel=1 -fuzztime=100x mutator_test.go +! stdout '^ok' +stdout FAIL +stdout 'mutator found enough unique mutations' + +-- go.mod -- +module m + +go 1.16 +-- fuzz_test.go -- +package fuzz_test + +import ( + "flag" + "fmt" + "os" + "testing" +) + +var ( + logPath = flag.String("log", "", "path to log file") + logFile *os.File +) + +func TestMain(m *testing.M) { + flag.Parse() + var err error + logFile, err = os.OpenFile(*logPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) + if os.IsExist(err) { + *logPath += ".worker" + logFile, err = os.OpenFile(*logPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) + } + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + os.Exit(m.Run()) +} + +func FuzzA(f *testing.F) { + f.Add([]byte("seed")) + f.Fuzz(func(t *testing.T, b []byte) { + fmt.Fprintf(logFile, "FuzzA %q\n", b) + }) +} + +func FuzzB(f *testing.F) { + f.Add([]byte("seed")) + f.Fuzz(func(t *testing.T, b []byte) { + fmt.Fprintf(logFile, "FuzzB %q\n", b) + }) +} + +-- check_logs.go -- +// +build ignore + +package main + +import ( + "bufio" + "bytes" + "fmt" + "io" + "os" + "strings" +) + +func main() { + coordPath, workerPath := os.Args[1], os.Args[2] + + coordLog, err := os.Open(coordPath) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + defer coordLog.Close() + if err := checkCoordLog(coordLog); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + workerLog, err := os.Open(workerPath) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + defer workerLog.Close() + if err := checkWorkerLog(workerLog); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func checkCoordLog(r io.Reader) error { + b, err := io.ReadAll(r) + if err != nil { + return err + } + if string(bytes.TrimSpace(b)) != `FuzzB "seed"` { + return fmt.Errorf("coordinator: did not test FuzzB seed") + } + return nil +} + +func checkWorkerLog(r io.Reader) error { + scan := bufio.NewScanner(r) + var sawAMutant bool + for scan.Scan() { + line := scan.Text() + if !strings.HasPrefix(line, "FuzzA ") { + return fmt.Errorf("worker: tested something other than target: %s", line) + } + if strings.TrimPrefix(line, "FuzzA ") != `"seed"` { + sawAMutant = true + } + } + if err := scan.Err(); err != nil && err != bufio.ErrTooLong { + return err + } + if !sawAMutant { + return fmt.Errorf("worker: did not test any mutants") + } + return nil +} +-- mutator_test.go -- +package fuzz_test + +import ( + "testing" +) + +// TODO(katiehockman): re-work this test once we have a better fuzzing engine +// (ie. more mutations, and compiler instrumentation) +func FuzzMutator(f *testing.F) { + // TODO(katiehockman): simplify this once we can dedupe crashes (e.g. + // replace map with calls to panic, and simply count the number of crashes + // that were added to testdata) + crashes := make(map[string]bool) + // No seed corpus initiated + f.Fuzz(func(t *testing.T, b []byte) { + crashes[string(b)] = true + if len(crashes) >= 10 { + panic("mutator found enough unique mutations") + } + }) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_mutator_repeat.txt b/src/cmd/go/testdata/script/test_fuzz_mutator_repeat.txt new file mode 100644 index 0000000..3b005c9 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_mutator_repeat.txt @@ -0,0 +1,75 @@ +# TODO(jayconrod): support shared memory on more platforms. +[!GOOS:darwin] [!GOOS:linux] [!GOOS:windows] skip + +# Verify that the fuzzing engine records the actual crashing input, even when +# a worker process terminates without communicating the crashing input back +# to the coordinator. + +[short] skip +env GOCACHE=$WORK/cache + +# Start fuzzing. The worker crashes after 100 iterations. +# The fuzz function writes the crashing input to "want" before exiting. +# The fuzzing engine reconstructs the crashing input and saves it to testdata. +! exists want +! go test -fuzz=. -parallel=1 -fuzztime=110x -fuzzminimizetime=10x -v +stdout '^\s+fuzzing process hung or terminated unexpectedly: exit status' +stdout 'Failing input written to testdata' + +# Run the fuzz target without fuzzing. The fuzz function is called with the +# crashing input in testdata. The test passes if that input is identical to +# the one saved in "want". +exists want +go test -want=want + +-- go.mod -- +module fuzz + +go 1.17 +-- fuzz_test.go -- +package fuzz + +import ( + "bytes" + "flag" + "os" + "testing" +) + +var wantFlag = flag.String("want", "", "file containing previous crashing input") + +func FuzzRepeat(f *testing.F) { + i := 0 + f.Fuzz(func(t *testing.T, b []byte) { + i++ + if i == 100 { + f, err := os.OpenFile("want", os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666) + if err != nil { + // Couldn't create the file. Return without crashing, and try + // again. + i-- + t.Skip(err) + } + if _, err := f.Write(b); err != nil { + // We already created the file, so if we failed to write it + // there's not much we can do. The test will fail anyway, but + // at least make sure the error is logged to stdout. + t.Fatal(err) + } + if err := f.Close(); err != nil { + t.Fatal(err) + } + os.Exit(1) // crash without communicating + } + + if *wantFlag != "" { + want, err := os.ReadFile(*wantFlag) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(want, b) { + t.Fatalf("inputs are not equal!\n got: %q\nwant:%q", b, want) + } + } + }) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_non_crash_signal.txt b/src/cmd/go/testdata/script/test_fuzz_non_crash_signal.txt new file mode 100644 index 0000000..94a0421 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_non_crash_signal.txt @@ -0,0 +1,76 @@ +# NOTE: this test is skipped on Windows, since there's no concept of signals. +# When a process terminates another process, it provides an exit code. +[GOOS:windows] skip +[!fuzz] skip +[short] skip +env GOCACHE=$WORK/cache + +# FuzzNonCrash sends itself a signal that does not appear to be a crash. +# We should not save a crasher. +! go test -fuzz=FuzzNonCrash +! exists testdata +! stdout unreachable +! stderr unreachable +stdout 'fuzzing process terminated by unexpected signal; no crash will be recorded: signal: terminated' + +# FuzzKill sends itself a signal that cannot be caught by the worker process +# and does not appear to be a crash. +# We should not save a crasher. +! go test -fuzz=FuzzKill +! exists testdata +! stdout unreachable +! stderr unreachable +stdout 'fuzzing process terminated by unexpected signal; no crash will be recorded: signal: killed' + +# FuzzCrash sends itself a signal that looks like a crash. +# We should save a crasher. +! go test -fuzz=FuzzCrash +exists testdata/fuzz/FuzzCrash +stdout '^\s+fuzzing process hung or terminated unexpectedly: exit status' + +-- go.mod -- +module test + +go 1.17 +-- fuzz_posix_test.go -- +// +build darwin freebsd linux + +package fuzz + +import ( + "syscall" + "testing" +) + +func FuzzNonCrash(f *testing.F) { + f.Fuzz(func(*testing.T, bool) { + pid := syscall.Getpid() + if err := syscall.Kill(pid, syscall.SIGTERM); err != nil { + panic(err) + } + // signal may not be received immediately. Wait for it. + select{} + }) +} + +func FuzzKill(f *testing.F) { + f.Fuzz(func(*testing.T, bool) { + pid := syscall.Getpid() + if err := syscall.Kill(pid, syscall.SIGKILL); err != nil { + panic(err) + } + // signal may not be received immediately. Wait for it. + select{} + }) +} + +func FuzzCrash(f *testing.F) { + f.Fuzz(func(*testing.T, bool) { + pid := syscall.Getpid() + if err := syscall.Kill(pid, syscall.SIGILL); err != nil { + panic(err) + } + // signal may not be received immediately. Wait for it. + select{} + }) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_parallel.txt b/src/cmd/go/testdata/script/test_fuzz_parallel.txt new file mode 100644 index 0000000..8ff965a --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_parallel.txt @@ -0,0 +1,67 @@ +[!fuzz] skip +[short] skip +env GOCACHE=$WORK/cache + +# When running seed inputs, T.Parallel should let multiple inputs run in +# parallel. +go test -run=FuzzSeed + +# When fuzzing, T.Parallel should be safe to call, but it should have no effect. +# We just check that it doesn't hang, which would be the most obvious +# failure mode. +# TODO(jayconrod): check for the string "after T.Parallel". It's not printed +# by 'go test', so we can't distinguish that crasher from some other panic. +! go test -run=FuzzMutate -fuzz=FuzzMutate +exists testdata/fuzz/FuzzMutate + +# Testdata should now contain a corpus entry which will fail FuzzMutate. +# Run the test without fuzzing, setting -parallel to different values to make +# sure it fails, and doesn't hang. +! go test -run=FuzzMutate -parallel=1 +! go test -run=FuzzMutate -parallel=2 +! go test -run=FuzzMutate -parallel=4 + +-- go.mod -- +module fuzz_parallel + +go 1.17 +-- fuzz_parallel_test.go -- +package fuzz_parallel + +import ( + "sort" + "sync" + "testing" +) + +func FuzzSeed(f *testing.F) { + for _, v := range [][]byte{{'a'}, {'b'}, {'c'}} { + f.Add(v) + } + + var mu sync.Mutex + var before, after []byte + f.Cleanup(func() { + sort.Slice(after, func(i, j int) bool { return after[i] < after[j] }) + got := string(before) + string(after) + want := "abcabc" + if got != want { + f.Fatalf("got %q; want %q", got, want) + } + }) + + f.Fuzz(func(t *testing.T, b []byte) { + before = append(before, b...) + t.Parallel() + mu.Lock() + after = append(after, b...) + mu.Unlock() + }) +} + +func FuzzMutate(f *testing.F) { + f.Fuzz(func(t *testing.T, _ []byte) { + t.Parallel() + t.Error("after T.Parallel") + }) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_profile_flags.txt b/src/cmd/go/testdata/script/test_fuzz_profile_flags.txt new file mode 100644 index 0000000..5434c72 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_profile_flags.txt @@ -0,0 +1,38 @@ +[!fuzz] skip + +! go test -fuzz=FuzzTrivial -coverprofile=prof +! stdout . +stderr '^cannot use -coverprofile flag with -fuzz flag$' + +! go test -fuzz=FuzzTrivial -blockprofile=prof +! stdout . +stderr '^cannot use -blockprofile flag with -fuzz flag$' + +! go test -fuzz=FuzzTrivial -cpuprofile=prof +! stdout . +stderr '^cannot use -cpuprofile flag with -fuzz flag$' + +! go test -fuzz=FuzzTrivial -memprofile=prof +! stdout . +stderr '^cannot use -memprofile flag with -fuzz flag$' + +! go test -fuzz=FuzzTrivial -mutexprofile=prof +! stdout . +stderr '^cannot use -mutexprofile flag with -fuzz flag$' + +! go test -fuzz=FuzzTrivial -trace=prof +! stdout . +stderr '^cannot use -trace flag with -fuzz flag$' + +-- go.mod -- +module example + +go 1.18 +-- fuzz_test.go -- +package example + +import "testing" + +func FuzzTrivial(f *testing.F) { + f.Fuzz(func(t *testing.T, _ []byte) {}) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_return.txt b/src/cmd/go/testdata/script/test_fuzz_return.txt new file mode 100644 index 0000000..63275aa --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_return.txt @@ -0,0 +1,19 @@ +[short] skip + +! go test . +stdout '^panic: testing: fuzz target must not return a value \[recovered\]$' + +-- go.mod -- +module test +go 1.18 +-- x_test.go -- +package test + +import "testing" + +func FuzzReturnErr(f *testing.F) { + f.Add("hello, validation!") + f.Fuzz(func(t *testing.T, in string) string { + return in + }) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_run.txt b/src/cmd/go/testdata/script/test_fuzz_run.txt new file mode 100644 index 0000000..99a4413 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_run.txt @@ -0,0 +1,143 @@ +[!fuzz] skip +[short] skip +env GOCACHE=$WORK/cache + +# Tests which verify the behavior and command line output when +# running a fuzz target as a unit test. + +# Tests without -run. + +! go test +stdout FAIL +stdout 'error here' + +! go test -v +stdout FAIL +stdout 'error here' +stdout '=== RUN FuzzFoo/thisfails' +stdout '--- FAIL: FuzzFoo/thisfails' +stdout '=== RUN FuzzFoo/thispasses' +stdout '--- PASS: FuzzFoo/thispasses' + +# Tests where -run matches all seed corpora. + +! go test -run FuzzFoo/this +stdout FAIL +stdout 'error here' +! stdout 'no tests to run' + +! go test -run /this +stdout FAIL +stdout 'error here' +! stdout 'no tests to run' + +! go test -v -run FuzzFoo/this +stdout FAIL +stdout 'error here' +stdout '=== RUN FuzzFoo/thisfails' +stdout '--- FAIL: FuzzFoo/thisfails' +stdout '=== RUN FuzzFoo/thispasses' +stdout '--- PASS: FuzzFoo/thispasses' +! stdout 'no tests to run' + +! go test -v -run /this +stdout FAIL +stdout 'error here' +stdout '=== RUN FuzzFoo/thisfails' +stdout '--- FAIL: FuzzFoo/thisfails' +stdout '=== RUN FuzzFoo/thispasses' +stdout '--- PASS: FuzzFoo/thispasses' +! stdout 'no tests to run' + +# Tests where -run only matches one seed corpus which passes. + +go test -run FuzzFoo/thispasses +stdout ok +! stdout 'no tests to run' + +go test -run /thispasses +stdout ok +! stdout 'no tests to run' + +# Same tests in verbose mode +go test -v -run FuzzFoo/thispasses +stdout '=== RUN FuzzFoo/thispasses' +stdout '--- PASS: FuzzFoo/thispasses' +! stdout '=== RUN FuzzFoo/thisfails' +! stdout 'no tests to run' + +go test -v -run /thispasses +stdout '=== RUN FuzzFoo/thispasses' +stdout '--- PASS: FuzzFoo/thispasses' +! stdout '=== RUN FuzzFoo/thisfails' +! stdout 'no tests to run' + +# Tests where -run only matches one seed corpus which fails. + +! go test -run FuzzFoo/thisfails +stdout FAIL +stdout 'error here' +! stdout 'no tests to run' + +! go test -run /thisfails +stdout FAIL +stdout 'error here' +! stdout 'no tests to run' + +! go test -v -run FuzzFoo/thisfails +stdout 'error here' +stdout '=== RUN FuzzFoo/thisfails' +stdout '--- FAIL: FuzzFoo/thisfails' +! stdout '=== RUN FuzzFoo/thispasses' +! stdout 'no tests to run' + +! go test -v -run /thisfails +stdout 'error here' +stdout '=== RUN FuzzFoo/thisfails' +stdout '--- FAIL: FuzzFoo/thisfails' +! stdout '=== RUN FuzzFoo/thispasses' +! stdout 'no tests to run' + +# Tests where -run doesn't match any seed corpora. + +go test -run FuzzFoo/nomatch +stdout ok + +go test -run /nomatch +stdout ok + +go test -v -run FuzzFoo/nomatch +stdout '=== RUN FuzzFoo' +stdout '--- PASS: FuzzFoo' +stdout ok +! stdout 'no tests to run' + +go test -v -run /nomatch +stdout '=== RUN FuzzFoo' +stdout '--- PASS: FuzzFoo' +stdout ok +! stdout 'no tests to run' + +-- go.mod -- +module example.com/x + +go 1.16 +-- x_test.go -- +package x + +import "testing" + +func FuzzFoo(f *testing.F) { + f.Add("this is fine") + f.Fuzz(func(t *testing.T, s string) { + if s == "fails" { + t.Error("error here") + } + }) +} +-- testdata/fuzz/FuzzFoo/thisfails -- +go test fuzz v1 +string("fails") +-- testdata/fuzz/FuzzFoo/thispasses -- +go test fuzz v1 +string("passes") diff --git a/src/cmd/go/testdata/script/test_fuzz_seed_corpus.txt b/src/cmd/go/testdata/script/test_fuzz_seed_corpus.txt new file mode 100644 index 0000000..3e3fbad --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_seed_corpus.txt @@ -0,0 +1,203 @@ +[!fuzz-instrumented] skip +[short] skip +env GOCACHE=$WORK/cache + +# Test that fuzzing a target with a failure in f.Add prints the crash +# and doesn't write anything to testdata/fuzz +! go test -fuzz=FuzzWithAdd -run=FuzzWithAdd -fuzztime=1x +! stdout ^ok +! stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithAdd[/\\]' +stdout FAIL + +# Test that fuzzing a target with a success in f.Add and a fuzztime of only +# 1 does not produce a crash. +go test -fuzz=FuzzWithGoodAdd -run=FuzzWithGoodAdd -fuzztime=1x +stdout ok +! stdout FAIL + +# Test that fuzzing a target with a failure in testdata/fuzz prints the crash +# and doesn't write anything to testdata/fuzz +! go test -fuzz=FuzzWithTestdata -run=FuzzWithTestdata -fuzztime=1x +! stdout ^ok +! stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithTestdata[/\\]' +stdout 'failure while testing seed corpus entry: FuzzWithTestdata/1' +stdout FAIL + +# Test that fuzzing a target with no seed corpus or cache finds a crash, prints +# it, and write it to testdata +! go test -fuzz=FuzzWithNoCache -run=FuzzWithNoCache -fuzztime=1x +! stdout ^ok +stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithNoCache[/\\]' +stdout FAIL + +# Write a crashing input to the cache +mkdir $GOCACHE/fuzz/example.com/x/FuzzWithCache +cp cache-file $GOCACHE/fuzz/example.com/x/FuzzWithCache/1 + +# Test that fuzzing a target with a failure in the cache prints the crash +# and writes this as a "new" crash to testdata/fuzz +! go test -fuzz=FuzzWithCache -run=FuzzWithCache -fuzztime=1x +! stdout ^ok +stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithCache[/\\]' +stdout FAIL + +# Write a crashing input to the cache +mkdir $GOCACHE/fuzz/example.com/x/FuzzWithMinimizableCache +cp cache-file-bytes $GOCACHE/fuzz/example.com/x/FuzzWithMinimizableCache/1 + +# Test that fuzzing a target with a failure in the cache minimizes it and writes +# the new crash to testdata/fuzz +! go test -fuzz=FuzzWithMinimizableCache -run=FuzzWithMinimizableCache -fuzztime=10000x +! stdout ^ok +stdout 'gathering baseline coverage' +stdout 'got the minimum size!' +stdout 'contains a non-zero byte of length 10' +stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithMinimizableCache[/\\]' +stdout FAIL +# Make sure this crash didn't come from fuzzing +# (the log line that states fuzzing began shouldn't have printed) +! stdout 'execs' + +# Clear the fuzz cache and make sure it's gone +go clean -fuzzcache +! exists $GOCACHE/fuzz + +# The tests below should operate the exact same as the previous tests. If -fuzz +# is enabled, then whatever target is going to be fuzzed shouldn't be run by +# anything other than the workers. + +# Test that fuzzing a target (with -run=None set) with a failure in f.Add prints +# the crash and doesn't write anything to testdata/fuzz -fuzztime=1x +! go test -fuzz=FuzzWithAdd -run=None +! stdout ^ok +! stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithAdd[/\\]' +stdout FAIL + +# Test that fuzzing a target (with -run=None set) with a success in f.Add and a +# fuzztime of only 1 does not produce a crash. +go test -fuzz=FuzzWithGoodAdd -run=None -fuzztime=1x +stdout ok +! stdout FAIL + +# Test that fuzzing a target (with -run=None set) with a failure in +# testdata/fuzz prints the crash and doesn't write anything to testdata/fuzz +! go test -fuzz=FuzzWithTestdata -run=None -fuzztime=1x +! stdout ^ok +! stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithTestdata[/\\]' +stdout FAIL + +# Write a crashing input to the cache +mkdir $GOCACHE/fuzz/example.com/x/FuzzRunNoneWithCache +cp cache-file $GOCACHE/fuzz/example.com/x/FuzzRunNoneWithCache/1 + +# Test that fuzzing a target (with -run=None set) with a failure in the cache +# prints the crash and writes this as a "new" crash to testdata/fuzz +! go test -fuzz=FuzzRunNoneWithCache -run=None -fuzztime=1x +! stdout ^ok +stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzRunNoneWithCache[/\\]' +stdout FAIL + +# Clear the fuzz cache and make sure it's gone +go clean -fuzzcache +! exists $GOCACHE/fuzz + +# The tests below should operate the exact same way for the previous tests with +# a seed corpus (namely, they should still fail). However, the binary is built +# without instrumentation, so this should be a "testing only" run which executes +# the seed corpus before attempting to fuzz. + +go test -c +! exec ./x.test$GOEXE -test.fuzz=FuzzWithAdd -test.run=FuzzWithAdd -test.fuzztime=1x -test.fuzzcachedir=$WORK/cache +! stdout ^ok +! stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithAdd[/\\]' +stdout FAIL +stderr warning + +go test -c +! exec ./x.test$GOEXE -test.fuzz=FuzzWithTestdata -test.run=FuzzWithTestdata -test.fuzztime=1x -test.fuzzcachedir=$WORK/cache +! stdout ^ok +! stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithTestdata[/\\]' +stdout FAIL +stderr warning + +-- go.mod -- +module example.com/x + +go 1.16 +-- x_test.go -- +package x + +import "testing" + +func FuzzWithAdd(f *testing.F) { + f.Add(10) + f.Fuzz(func(t *testing.T, i int) { + if i == 10 { + t.Error("bad thing here") + } + }) +} + +func FuzzWithGoodAdd(f *testing.F) { + f.Add(10) + f.Fuzz(func(t *testing.T, i int) { + if i != 10 { + t.Error("bad thing here") + } + }) +} + +func FuzzWithTestdata(f *testing.F) { + f.Fuzz(func(t *testing.T, i int) { + if i == 10 { + t.Error("bad thing here") + } + }) +} + +func FuzzWithNoCache(f *testing.F) { + f.Fuzz(func(t *testing.T, i int) { + t.Error("bad thing here") + }) +} + +func FuzzWithCache(f *testing.F) { + f.Fuzz(func(t *testing.T, i int) { + if i == 10 { + t.Error("bad thing here") + } + }) +} + +func FuzzWithMinimizableCache(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + if len(b) < 10 { + return + } + for _, n := range b { + if n != 0 { + if len(b) == 10 { + t.Log("got the minimum size!") + } + t.Fatalf("contains a non-zero byte of length %d", len(b)) + } + } + }) +} + +func FuzzRunNoneWithCache(f *testing.F) { + f.Fuzz(func(t *testing.T, i int) { + if i == 10 { + t.Error("bad thing here") + } + }) +} +-- testdata/fuzz/FuzzWithTestdata/1 -- +go test fuzz v1 +int(10) +-- cache-file -- +go test fuzz v1 +int(10) +-- cache-file-bytes -- +go test fuzz v1 +[]byte("11111111111111111111") diff --git a/src/cmd/go/testdata/script/test_fuzz_setenv.txt b/src/cmd/go/testdata/script/test_fuzz_setenv.txt new file mode 100644 index 0000000..1370cd8 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_setenv.txt @@ -0,0 +1,46 @@ +[!fuzz] skip +[short] skip +env GOCACHE=$WORK/cache + +go test -fuzz=FuzzA -fuzztime=100x fuzz_setenv_test.go + +-- fuzz_setenv_test.go -- +package fuzz + +import ( + "flag" + "os" + "testing" +) + +func FuzzA(f *testing.F) { + if s := os.Getenv("TEST_FUZZ_SETENV_A"); isWorker() && s == "" { + f.Fatal("environment variable not set") + } else if !isWorker() && s != "" { + f.Fatal("environment variable already set") + } + f.Setenv("TEST_FUZZ_SETENV_A", "A") + if os.Getenv("TEST_FUZZ_SETENV_A") == "" { + f.Fatal("Setenv did not set environment variable") + } + f.Fuzz(func(*testing.T, []byte) {}) +} + +func FuzzB(f *testing.F) { + if os.Getenv("TEST_FUZZ_SETENV_A") != "" { + f.Fatal("environment variable not cleared after FuzzA") + } + f.Skip() +} + +func isWorker() bool { + f := flag.Lookup("test.fuzzworker") + if f == nil { + return false + } + get, ok := f.Value.(flag.Getter) + if !ok { + return false + } + return get.Get() == interface{}(true) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_test_race.txt b/src/cmd/go/testdata/script/test_fuzz_test_race.txt new file mode 100644 index 0000000..1bed47d --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_test_race.txt @@ -0,0 +1,40 @@ +# Test that when both race detection and coverage instrumentation are enabled, +# and seed values are being executed, the race detector isn't mistakenly +# triggered. + +[short] skip +[!fuzz] skip +[!race] skip +env GOCACHE=$WORK/cache + +# Test with coverage instrumentation enabled (-fuzz) and race instrumentation +# but without actually fuzzing the target (by using a non-matching pattern) +go test -fuzz=xxx -race -v +! stderr 'race detected during execution of test' + +# Test with just race instrumentation enabled +go test -race -v +! stderr 'race detected during execution of test' + +# Test with coverage and race instrumentation enabled, and a matching fuzz +# pattern +go test -fuzz=FuzzRace -race -v -fuzztime=200x +! stderr 'race detected during execution of test' + +-- go.mod -- +module test + +-- race_test.go -- +package race + +import "testing" + +func FuzzRace(f *testing.F) { + for i := 0; i < 100; i++ { + f.Add(i) + } + + f.Fuzz(func(t *testing.T, i int) { + t.Parallel() + }) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_unsupported.txt b/src/cmd/go/testdata/script/test_fuzz_unsupported.txt new file mode 100644 index 0000000..1ed0b8a --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_unsupported.txt @@ -0,0 +1,18 @@ +[fuzz] skip + +! go test -fuzz=. -fuzztime=1x +! stdout . +stderr '^-fuzz flag is not supported on '$GOOS'/'$GOARCH'$' + +-- go.mod -- +module example + +go 1.18 +-- fuzz_test.go -- +package example + +import "testing" + +func FuzzTrivial(f *testing.F) { + f.Fuzz(func(t *testing.T, _ []byte) {}) +} diff --git a/src/cmd/go/testdata/script/test_generated_main.txt b/src/cmd/go/testdata/script/test_generated_main.txt new file mode 100644 index 0000000..2e991a5 --- /dev/null +++ b/src/cmd/go/testdata/script/test_generated_main.txt @@ -0,0 +1,34 @@ +# Tests that the generated test main file has a generated code comment. +# This is needed by analyzers that access source files through 'go list'. +# Verifies golang.org/issue/31971. +# TODO(jayconrod): This test is brittle. We should write _testmain.go as +# a build action instead of with an ad-hoc WriteFile call +# in internal/test/test.go. Then we could just grep 'go get -n'. +go test x_test.go + +-- x_test.go -- +package x + +import ( + "os" + "path/filepath" + "regexp" + "testing" +) + +func Test(t *testing.T) { + exePath, err := os.Executable() + if err != nil { + t.Fatal(err) + } + testmainPath := filepath.Join(filepath.Dir(exePath), "_testmain.go") + source, err := os.ReadFile(testmainPath) + if err != nil { + t.Fatal(err) + } + if matched, err := regexp.Match(`(?m)^// Code generated .* DO NOT EDIT\.$`, source); err != nil { + t.Fatal(err) + } else if !matched { + t.Error("_testmain.go does not have generated code comment") + } +} diff --git a/src/cmd/go/testdata/script/test_go111module_cache.txt b/src/cmd/go/testdata/script/test_go111module_cache.txt new file mode 100644 index 0000000..ca1de43 --- /dev/null +++ b/src/cmd/go/testdata/script/test_go111module_cache.txt @@ -0,0 +1,15 @@ +env GO111MODULE=on +go mod init foo +go test +stdout ^ok\s+foo +env GO111MODULE=off +go test +stdout ^ok\s+ +! stdout ^ok\s+(cache)$ + +-- main_test.go -- +package main + +import "testing" + +func TestF(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/test_goroot_PATH.txt b/src/cmd/go/testdata/script/test_goroot_PATH.txt new file mode 100644 index 0000000..a6278ca --- /dev/null +++ b/src/cmd/go/testdata/script/test_goroot_PATH.txt @@ -0,0 +1,41 @@ +# https://go.dev/issue/51473: to avoid the need for tests to rely on +# runtime.GOROOT, 'go test' should run the test with its own GOROOT/bin +# at the beginning of $PATH. + +[short] skip + +[!GOOS:plan9] env PATH= +[GOOS:plan9] env path= +go test . + +[!GOOS:plan9] env PATH=$WORK${/}bin +[GOOS:plan9] env path=$WORK${/}bin +go test . + +-- go.mod -- +module example + +go 1.19 +-- example_test.go -- +package example + +import ( + "os" + "os/exec" + "path/filepath" + "testing" +) + +func TestGoCommandExists(t *testing.T) { + got, err := exec.LookPath("go") + if err != nil { + t.Fatal(err) + } + + want := filepath.Join(os.Getenv("GOROOT"), "bin", "go" + os.Getenv("GOEXE")) + if got != want { + t.Fatalf(`exec.LookPath("go") = %q; want %q`, got, want) + } +} +-- $WORK/bin/README.txt -- +This directory contains no executables. diff --git a/src/cmd/go/testdata/script/test_import_error_stack.txt b/src/cmd/go/testdata/script/test_import_error_stack.txt new file mode 100644 index 0000000..6c60f3d --- /dev/null +++ b/src/cmd/go/testdata/script/test_import_error_stack.txt @@ -0,0 +1,31 @@ +env GO111MODULE=off +! go test testdep/p1 +stderr 'package testdep/p1 \(test\)\n\timports testdep/p2\n\timports testdep/p3: build constraints exclude all Go files ' # check for full import stack +! go vet testdep/p1 +stderr 'package testdep/p1 \(test\)\n\timports testdep/p2\n\timports testdep/p3: build constraints exclude all Go files ' # check for full import stack + +env GO111MODULE=on +cd testdep +! go test testdep/p1 +stderr 'package testdep/p1 \(test\)\n\timports testdep/p2\n\timports testdep/p3: build constraints exclude all Go files ' # check for full import stack +! go vet testdep/p1 +stderr 'package testdep/p1 \(test\)\n\timports testdep/p2\n\timports testdep/p3: build constraints exclude all Go files ' # check for full import stack + +-- testdep/go.mod -- +module testdep + +go 1.16 +-- testdep/p1/p1.go -- +package p1 +-- testdep/p1/p1_test.go -- +package p1 + +import _ "testdep/p2" +-- testdep/p2/p2.go -- +package p2 + +import _ "testdep/p3" +-- testdep/p3/p3.go -- +// +build ignore + +package ignored diff --git a/src/cmd/go/testdata/script/test_issue45477.txt b/src/cmd/go/testdata/script/test_issue45477.txt new file mode 100644 index 0000000..f435b6a --- /dev/null +++ b/src/cmd/go/testdata/script/test_issue45477.txt @@ -0,0 +1,12 @@ +[short] skip # links and runs a test binary + +go test -v . + +-- go.mod -- +module example.com/pkg_test + +-- pkg.go -- +package pkg_test + +-- pkg_test.go -- +package pkg_test diff --git a/src/cmd/go/testdata/script/test_json.txt b/src/cmd/go/testdata/script/test_json.txt new file mode 100644 index 0000000..6207c2e --- /dev/null +++ b/src/cmd/go/testdata/script/test_json.txt @@ -0,0 +1,80 @@ +[compiler:gccgo] skip # gccgo does not have standard packages +[short] skip + +env GOCACHE=$WORK/tmp + +# Run go test -json on errors m/empty/pkg and m/skipper +# It would be nice to test that the output is interlaced +# but it seems to be impossible to do that in a short test +# that isn't also flaky. Just check that we get JSON output. +go test -json -short -v errors m/empty/pkg m/skipper + +# Check errors for run action +stdout '"Package":"errors"' +stdout '"Action":"start","Package":"errors"' +stdout '"Action":"run","Package":"errors"' + +# Check m/empty/pkg for output and skip actions +stdout '"Action":"start","Package":"m/empty/pkg"' +stdout '"Action":"output","Package":"m/empty/pkg","Output":".*no test files' +stdout '"Action":"skip","Package":"m/empty/pkg"' + +# Check skipper for output and skip actions +stdout '"Action":"start","Package":"m/skipper"' +stdout '"Action":"output","Package":"m/skipper","Test":"Test","Output":"--- SKIP:' +stdout '"Action":"skip","Package":"m/skipper","Test":"Test"' + +# Check that starts were ordered properly. +stdout '(?s)"Action":"start","Package":"errors".*"Action":"start","Package":"m/empty/pkg".*"Action":"start","Package":"m/skipper"' + +# Run go test -json on errors and check it's cached +go test -json -short -v errors +stdout '"Action":"output","Package":"errors","Output":".*\(cached\)' + +go test -json -bench=NONE -short -v errors +stdout '"Package":"errors"' +stdout '"Action":"run"' + +# Test running test2json +go test -o $WORK/tmp/errors.test$GOEXE -c errors +go tool test2json -p errors $WORK/tmp/errors.test$GOEXE -test.v -test.short +stdout '"Package":"errors"' +stdout '"Action":"run"' +stdout '\{"Action":"pass","Package":"errors"\}' + +-- go.mod -- +module m + +go 1.16 +-- skipper/skip_test.go -- +package skipper + +import "testing" + +func Test(t *testing.T) { + t.Skip("skipping") +} +-- empty/pkg/pkg.go -- +package p +-- empty/pkgtest/pkg.go -- +package p +-- empty/pkgtest/test_test.go -- +package p +-- empty/pkgtestxtest/pkg.go -- +package p +-- empty/pkgtestxtest/test_test.go -- +package p +-- empty/pkgtestxtest/xtest_test.go -- +package p_test +-- empty/pkgxtest/pkg.go -- +package p +-- empty/pkgxtest/xtest_test.go -- +package p_test +-- empty/test/test_test.go -- +package p +-- empty/testxtest/test_test.go -- +package p +-- empty/testxtest/xtest_test.go -- +package p_test +-- empty/xtest/xtest_test.go -- +package p_test diff --git a/src/cmd/go/testdata/script/test_json_exit.txt b/src/cmd/go/testdata/script/test_json_exit.txt new file mode 100644 index 0000000..dc7ffb0 --- /dev/null +++ b/src/cmd/go/testdata/script/test_json_exit.txt @@ -0,0 +1,102 @@ +[short] skip + +go test -c -o mainpanic.exe ./mainpanic & +go test -c -o mainexit0.exe ./mainexit0 & +go test -c -o testpanic.exe ./testpanic & +go test -c -o testbgpanic.exe ./testbgpanic & +wait + +# Test binaries that panic in TestMain should be marked as failing. + +! go test -json ./mainpanic +stdout '"Action":"fail"' +! stdout '"Action":"pass"' + +! go tool test2json ./mainpanic.exe +stdout '"Action":"fail"' +! stdout '"Action":"pass"' + +# Test binaries that exit with status 0 should be marked as passing. + +go test -json ./mainexit0 +stdout '"Action":"pass"' +! stdout '"Action":"fail"' + +go tool test2json ./mainexit0.exe +stdout '"Action":"pass"' +! stdout '"Action":"fail"' + +# Test functions that panic should never be marked as passing +# (https://golang.org/issue/40132). + +! go test -json ./testpanic +stdout '"Action":"fail"' +! stdout '"Action":"pass"' + +! go tool test2json ./testpanic.exe -test.v +stdout '"Action":"fail"' +! stdout '"Action":"pass"' + +! go tool test2json ./testpanic.exe +stdout '"Action":"fail"' +! stdout '"Action":"pass"' + +# Tests that panic in a background goroutine should be marked as failing. + +! go test -json ./testbgpanic +stdout '"Action":"fail"' +! stdout '"Action":"pass"' + +! go tool test2json ./testbgpanic.exe -test.v +stdout '"Action":"fail"' +! stdout '"Action":"pass"' + +! go tool test2json ./testbgpanic.exe +stdout '"Action":"fail"' +! stdout '"Action":"pass"' + +-- go.mod -- +module m +go 1.14 +-- mainpanic/mainpanic_test.go -- +package mainpanic_test + +import "testing" + +func TestMain(m *testing.M) { + panic("haha no") +} +-- mainexit0/mainexit0_test.go -- +package mainexit0_test + +import ( + "fmt" + "os" + "testing" +) + +func TestMain(m *testing.M) { + fmt.Println("nothing to do") + os.Exit(0) +} +-- testpanic/testpanic_test.go -- +package testpanic_test + +import "testing" + +func TestPanic(*testing.T) { + panic("haha no") +} +-- testbgpanic/testbgpanic_test.go -- +package testbgpanic_test + +import "testing" + +func TestPanicInBackground(*testing.T) { + c := make(chan struct{}) + go func() { + panic("haha no") + close(c) + }() + <-c +} diff --git a/src/cmd/go/testdata/script/test_json_interleaved.txt b/src/cmd/go/testdata/script/test_json_interleaved.txt new file mode 100644 index 0000000..e2d349e --- /dev/null +++ b/src/cmd/go/testdata/script/test_json_interleaved.txt @@ -0,0 +1,27 @@ +# Regression test for https://golang.org/issue/40657: output from the main test +# function should be attributed correctly even if interleaved with the PAUSE +# line for a new parallel subtest. + +[short] skip + +go test -json +stdout '"Test":"TestWeirdTiming","Output":"[^"]* logging to outer again\\n"' + +-- go.mod -- +module example.com +go 1.15 +-- main_test.go -- +package main + +import ( + "testing" +) + +func TestWeirdTiming(outer *testing.T) { + outer.Run("pauser", func(pauser *testing.T) { + outer.Logf("logging to outer") + pauser.Parallel() + }) + + outer.Logf("logging to outer again") +} diff --git a/src/cmd/go/testdata/script/test_json_issue35169.txt b/src/cmd/go/testdata/script/test_json_issue35169.txt new file mode 100644 index 0000000..fdb5755 --- /dev/null +++ b/src/cmd/go/testdata/script/test_json_issue35169.txt @@ -0,0 +1,28 @@ +! go test -json . + + # We should see only JSON output on stdout, no non-JSON. + # To simplify the check, we just look for non-curly-braces, since + # every JSON entry has them and they're unlikely to occur + # in other error messages. +! stdout '^[^{]' +! stdout '[^}]\n$' + + # Since the only test we requested failed to build, we should + # not see any "pass" actions in the JSON stream. +! stdout '\{.*"Action":"pass".*\}' + + # TODO(#62067): emit this as a build event instead of a test event. +stdout '\{.*"Action":"output","Package":"example","Output":"FAIL\\texample \[build failed\]\\n"\}' +stdout '\{.*"Action":"fail","Package":"example",.*\}' + +-- go.mod -- +module example +go 1.19 +-- example.go -- +package example + +This is not valid Go source. +-- example_test.go -- +package example + +func Test(*testing.T) {} diff --git a/src/cmd/go/testdata/script/test_json_panic_exit.txt b/src/cmd/go/testdata/script/test_json_panic_exit.txt new file mode 100644 index 0000000..5f1d033 --- /dev/null +++ b/src/cmd/go/testdata/script/test_json_panic_exit.txt @@ -0,0 +1,69 @@ +# Verifies golang.org/issue/37555. + +[short] skip + +# 'go test -json' should say a test passes if it says it passes. +go test -json ./pass +stdout '"Action":"pass","Package":"[^"]*","Elapsed":[^"]*}\n\z' +! stdout '"Test":.*\n\z' + +# 'go test -json' should say a test passes if it exits 0 and prints nothing. +# TODO(golang.org/issue/29062): this should fail in the future. +go test -json ./exit0main +stdout '"Action":"pass".*\n\z' +! stdout '"Test":.*\n\z' + +# 'go test -json' should say a test fails if it exits 1 and prints nothing. +! go test -json ./exit1main +stdout '"Action":"fail".*\n\z' +! stdout '"Test":.*\n\z' + +# 'go test -json' should say a test fails if it panics. +! go test -json ./panic +stdout '"Action":"fail".*\n\z' +! stdout '"Test":.*\n\z' + +-- go.mod -- +module example.com/test + +go 1.14 + +-- pass/pass_test.go -- +package pass_test + +import "testing" + +func TestPass(t *testing.T) {} + +-- exit0main/exit0main_test.go -- +package exit0_test + +import ( + "os" + "testing" +) + +func TestMain(m *testing.M) { + os.Exit(0) +} + +-- exit1main/exit1main_test.go -- +package exit1_test + +import ( + "os" + "testing" +) + +func TestMain(m *testing.M) { + os.Exit(1) +} + +-- panic/panic_test.go -- +package panic_test + +import "testing" + +func TestPanic(t *testing.T) { + panic("oh no") +} diff --git a/src/cmd/go/testdata/script/test_json_prints.txt b/src/cmd/go/testdata/script/test_json_prints.txt new file mode 100644 index 0000000..f979998 --- /dev/null +++ b/src/cmd/go/testdata/script/test_json_prints.txt @@ -0,0 +1,48 @@ +go test -json + +stdout '"Action":"output","Package":"p","Output":"M1"}' +stdout '"Action":"output","Package":"p","Test":"Test","Output":"=== RUN Test\\n"}' +stdout '"Action":"output","Package":"p","Test":"Test","Output":"T1"}' +stdout '"Action":"output","Package":"p","Test":"Test/Sub1","Output":"=== RUN Test/Sub1\\n"}' +stdout '"Action":"output","Package":"p","Test":"Test/Sub1","Output":"Sub1 x_test.go:19: SubLog1\\n"}' +stdout '"Action":"output","Package":"p","Test":"Test/Sub1","Output":"Sub2"}' +stdout '"Action":"output","Package":"p","Test":"Test/Sub1","Output":"--- PASS: Test/Sub1 \([\d.]+s\)\\n"}' +stdout '"Action":"pass","Package":"p","Test":"Test/Sub1","Elapsed"' +stdout '"Action":"output","Package":"p","Test":"Test/Sub3","Output":"foo bar"}' +stdout '"Action":"output","Package":"p","Test":"Test/Sub3","Output":"baz\\n"}' +stdout '"Action":"output","Package":"p","Test":"Test","Output":"T2"}' +stdout '"Action":"output","Package":"p","Test":"Test","Output":"--- PASS: Test \([\d.]+s\)\\n"}' +stdout '"Action":"pass","Package":"p","Test":"Test","Elapsed"' +stdout '"Action":"output","Package":"p","Output":"M2ok \\tp\\t[\d.]+s\\n"}' +stdout '"Action":"pass","Package":"p","Elapsed"' + +-- go.mod -- +module p + +-- x_test.go -- +package p + +import ( + "os" + "testing" +) + +func TestMain(m *testing.M) { + print("M1") + code := m.Run() + print("M2") + os.Exit(code) +} + +func Test(t *testing.T) { + print("T1") + t.Run("Sub1", func(t *testing.T) { + print("Sub1") + t.Log("SubLog1") + print("Sub2") + }) + t.Run("Sub3", func(t *testing.T) { + print("\x16foo bar\x16baz\n") + }) + print("T2") +} diff --git a/src/cmd/go/testdata/script/test_json_timeout.txt b/src/cmd/go/testdata/script/test_json_timeout.txt new file mode 100644 index 0000000..0a2329b --- /dev/null +++ b/src/cmd/go/testdata/script/test_json_timeout.txt @@ -0,0 +1,19 @@ +! go test -json -timeout=1ms + +stdout '"Action":"output","Package":"p","Output":"FAIL\\tp\\t' +stdout '"Action":"fail","Package":"p","Elapsed":' + +-- go.mod -- +module p + +-- x_test.go -- +package p + +import ( + "testing" + "time" +) + +func Test(t *testing.T) { + time.Sleep(1*time.Hour) +} diff --git a/src/cmd/go/testdata/script/test_main.txt b/src/cmd/go/testdata/script/test_main.txt new file mode 100644 index 0000000..25d02e4 --- /dev/null +++ b/src/cmd/go/testdata/script/test_main.txt @@ -0,0 +1,92 @@ +# Test TestMain +go test standalone_main_normal_test.go +! stdout '^ok.*\[no tests to run\]' +! stderr '^ok.*\[no tests to run\]' +stdout '^ok' + +# Test TestMain sees testing flags +go test standalone_testmain_flag_test.go +stdout '^ok.*\[no tests to run\]' + +# Test TestMain with wrong signature (Issue #22388) +! go test standalone_main_wrong_test.go +stderr 'wrong signature for TestMain, must be: func TestMain\(m \*testing.M\)' + +# Test TestMain does not call os.Exit (Issue #34129) +! go test standalone_testmain_not_call_os_exit_test.go +! stdout '^ok' + +-- standalone_main_normal_test.go -- +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package standalone_main_normal_test + +import "testing" + +func TestMain(t *testing.T) { +} +-- standalone_main_wrong_test.go -- +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package standalone_main_wrong_test + +import "testing" + +func TestMain(m *testing.Main) { +} +-- standalone_testmain_flag_test.go -- +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package standalone_testmain_flag_test + +import ( + "flag" + "fmt" + "os" + "testing" +) + +func TestMain(m *testing.M) { + // A TestMain should be able to access testing flags if it calls + // flag.Parse without needing to use testing.Init. + flag.Parse() + found := false + flag.VisitAll(func(f *flag.Flag) { + if f.Name == "test.count" { + found = true + } + }) + if !found { + fmt.Println("testing flags not registered") + os.Exit(1) + } + os.Exit(m.Run()) +} +-- standalone_testmain_not_call_os_exit_test.go -- +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package standalone_testmain_not_call_os_exit_test + +import ( + "testing" +) + +func TestWillFail(t *testing.T) { + t.Error("this test will fail.") +} + +func TestMain(m *testing.M) { + defer func() { + recover() + }() + exit := m.Run() + panic(exit) +} diff --git a/src/cmd/go/testdata/script/test_main_archive.txt b/src/cmd/go/testdata/script/test_main_archive.txt new file mode 100644 index 0000000..410d923 --- /dev/null +++ b/src/cmd/go/testdata/script/test_main_archive.txt @@ -0,0 +1,32 @@ +env GO111MODULE=off + +# Test that a main_test of 'package main' imports the package, +# not the installed binary. + +[short] skip + +env GOBIN=$WORK/bin +go test main_test +go install main_test + +go list -f '{{.Stale}}' main_test +stdout false + +go test main_test + +-- main_test/m.go -- +package main + +func F() {} +func main() {} +-- main_test/m_test.go -- +package main_test + +import ( + . "main_test" + "testing" +) + +func Test1(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/script/test_main_panic.txt b/src/cmd/go/testdata/script/test_main_panic.txt new file mode 100644 index 0000000..45887c5 --- /dev/null +++ b/src/cmd/go/testdata/script/test_main_panic.txt @@ -0,0 +1,30 @@ +[short] skip +[!race] skip + +! go test -v -race main_panic/testmain_parallel_sub_panic_test.go +! stdout 'DATA RACE' +-- main_panic/testmain_parallel_sub_panic_test.go -- +package testmain_parallel_sub_panic_test + +import "testing" + +func setup() { println("setup()") } +func teardown() { println("teardown()") } +func TestA(t *testing.T) { + t.Run("1", func(t *testing.T) { + t.Run("1", func(t *testing.T) { + t.Parallel() + panic("A/1/1 panics") + }) + t.Run("2", func(t *testing.T) { + t.Parallel() + println("A/1/2 is ok") + }) + }) +} + +func TestMain(m *testing.M) { + setup() + defer teardown() + m.Run() +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_main_twice.txt b/src/cmd/go/testdata/script/test_main_twice.txt new file mode 100644 index 0000000..f32d4fc --- /dev/null +++ b/src/cmd/go/testdata/script/test_main_twice.txt @@ -0,0 +1,27 @@ +[short] skip + +env GOCACHE=$WORK/tmp +go test -v multimain +stdout -count=2 notwithstanding # check tests ran twice + +-- go.mod -- +module multimain + +go 1.16 +-- multimain_test.go -- +package multimain_test + +import "testing" + +func TestMain(m *testing.M) { + // Some users run m.Run multiple times, changing + // some kind of global state between runs. + // This used to work so I guess now it has to keep working. + // See golang.org/issue/23129. + m.Run() + m.Run() +} + +func Test(t *testing.T) { + t.Log("notwithstanding") +} diff --git a/src/cmd/go/testdata/script/test_match_benchmark_labels.txt b/src/cmd/go/testdata/script/test_match_benchmark_labels.txt new file mode 100644 index 0000000..13c4007 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_benchmark_labels.txt @@ -0,0 +1,18 @@ +# Benchmark labels, file outside gopath +# TODO(matloob): This test was called TestBenchmarkLabelsOutsideGOPATH +# why "OutsideGOPATH"? Does the go command need to be run outside GOPATH? +# Do the files need to exist outside GOPATH? +cp $GOPATH/src/standalone_benchmark_test.go $WORK/tmp/standalone_benchmark_test.go +go test -run '^$' -bench . $WORK/tmp/standalone_benchmark_test.go +stdout '^goos: '$GOOS +stdout '^goarch: '$GOARCH +! stdout '^pkg:' +! stderr '^pkg:' + +-- standalone_benchmark_test.go -- +package standalone_benchmark + +import "testing" + +func Benchmark(b *testing.B) { +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_match_no_benchmarks.txt b/src/cmd/go/testdata/script/test_match_no_benchmarks.txt new file mode 100644 index 0000000..30f4be8 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_no_benchmarks.txt @@ -0,0 +1,13 @@ +# Matches no benchmarks +go test -run '^$' -bench ThisWillNotMatch standalone_benchmark_test.go +! stdout '^ok.*\[no tests to run\]' +! stderr '^ok.*\[no tests to run\]' +stdout '^ok' + +-- standalone_benchmark_test.go -- +package standalone_benchmark + +import "testing" + +func Benchmark(b *testing.B) { +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_match_no_subtests.txt b/src/cmd/go/testdata/script/test_match_no_subtests.txt new file mode 100644 index 0000000..7abb1eb --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_no_subtests.txt @@ -0,0 +1,12 @@ +# The subtests don't match +go test -run Test/ThisWillNotMatch standalone_sub_test.go +stdout '^ok.*\[no tests to run\]' + +-- standalone_sub_test.go -- +package standalone_sub_test + +import "testing" + +func Test(t *testing.T) { + t.Run("Sub", func(t *testing.T) {}) +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_match_no_subtests_failure.txt b/src/cmd/go/testdata/script/test_match_no_subtests_failure.txt new file mode 100644 index 0000000..b3c5b92 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_no_subtests_failure.txt @@ -0,0 +1,15 @@ +# Matches no subtests, but parent test still fails +! go test -run TestThatFails/ThisWillNotMatch standalone_fail_sub_test.go +! stdout '^ok.*\[no tests to run\]' +! stderr '^ok.*\[no tests to run\]' +stdout 'FAIL' + +-- standalone_fail_sub_test.go -- +package standalone_fail_sub_test + +import "testing" + +func TestThatFails(t *testing.T) { + t.Run("Sub", func(t *testing.T) {}) + t.Fail() +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_match_no_subtests_parallel.txt b/src/cmd/go/testdata/script/test_match_no_subtests_parallel.txt new file mode 100644 index 0000000..11c734c --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_no_subtests_parallel.txt @@ -0,0 +1,19 @@ +# Matches no subtests, parallel +go test -run Test/Sub/ThisWillNotMatch standalone_parallel_sub_test.go +stdout '^ok.*\[no tests to run\]' + +-- standalone_parallel_sub_test.go -- +package standalone_parallel_sub_test + +import "testing" + +func Test(t *testing.T) { + ch := make(chan bool, 1) + t.Run("Sub", func(t *testing.T) { + t.Parallel() + <-ch + t.Run("Nested", func(t *testing.T) {}) + }) + // Ensures that Sub will finish after its t.Run call already returned. + ch <- true +} diff --git a/src/cmd/go/testdata/script/test_match_no_tests.txt b/src/cmd/go/testdata/script/test_match_no_tests.txt new file mode 100644 index 0000000..1ad2097 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_no_tests.txt @@ -0,0 +1,11 @@ +# Matches no tests +go test -run ThisWillNotMatch standalone_test.go +stdout '^ok.*\[no tests to run\]' + +-- standalone_test.go -- +package standalone_test + +import "testing" + +func Test(t *testing.T) { +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_match_no_tests_build_failure.txt b/src/cmd/go/testdata/script/test_match_no_tests_build_failure.txt new file mode 100644 index 0000000..e1c9643 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_no_tests_build_failure.txt @@ -0,0 +1,19 @@ +# Test that when there's a build failure and a -run flag that doesn't match, +# that the error for not matching tests does not override the error for +# the build failure. + +! go test -run ThisWillNotMatch syntaxerror +! stderr '(?m)^ok.*\[no tests to run\]' +stdout 'FAIL' + +-- go.mod -- +module syntaxerror + +go 1.16 +-- x.go -- +package p +-- x_test.go -- +package p + +func f() (x.y, z int) { +} diff --git a/src/cmd/go/testdata/script/test_match_no_tests_with_subtests.txt b/src/cmd/go/testdata/script/test_match_no_tests_with_subtests.txt new file mode 100644 index 0000000..0d94918 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_no_tests_with_subtests.txt @@ -0,0 +1,12 @@ +# Matches no tests with subtests +go test -run ThisWillNotMatch standalone_sub_test.go +stdout '^ok.*\[no tests to run\]' + +-- standalone_sub_test.go -- +package standalone_sub_test + +import "testing" + +func Test(t *testing.T) { + t.Run("Sub", func(t *testing.T) {}) +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_match_only_benchmarks.txt b/src/cmd/go/testdata/script/test_match_only_benchmarks.txt new file mode 100644 index 0000000..5dfb96e --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_only_benchmarks.txt @@ -0,0 +1,13 @@ +# Matches only benchmarks +go test -run '^$' -bench . standalone_benchmark_test.go +! stdout '^ok.*\[no tests to run\]' +! stderr '^ok.*\[no tests to run\]' +stdout '^ok' + +-- standalone_benchmark_test.go -- +package standalone_benchmark + +import "testing" + +func Benchmark(b *testing.B) { +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_match_only_example.txt b/src/cmd/go/testdata/script/test_match_only_example.txt new file mode 100644 index 0000000..515ccb3 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_only_example.txt @@ -0,0 +1,31 @@ +[short] skip + +# Check that it's okay for test pattern to match only examples. +go test -run Example example1_test.go +! stderr '^ok.*\[no tests to run\]' +stdout '^ok' + +-- example1_test.go -- +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Make sure that go test runs Example_Z before Example_A, preserving source order. + +package p + +import "fmt" + +var n int + +func Example_Z() { + n++ + fmt.Println(n) + // Output: 1 +} + +func Example_A() { + n++ + fmt.Println(n) + // Output: 2 +} diff --git a/src/cmd/go/testdata/script/test_match_only_subtests.txt b/src/cmd/go/testdata/script/test_match_only_subtests.txt new file mode 100644 index 0000000..beea895 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_only_subtests.txt @@ -0,0 +1,14 @@ +# Matches only subtests +go test -run Test/Sub standalone_sub_test.go +! stdout '^ok.*\[no tests to run\]' +! stderr '^ok.*\[no tests to run\]' +stdout '^ok' + +-- standalone_sub_test.go -- +package standalone_sub_test + +import "testing" + +func Test(t *testing.T) { + t.Run("Sub", func(t *testing.T) {}) +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_match_only_subtests_parallel.txt b/src/cmd/go/testdata/script/test_match_only_subtests_parallel.txt new file mode 100644 index 0000000..11872c2 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_only_subtests_parallel.txt @@ -0,0 +1,21 @@ +# Matches only subtests, parallel +go test -run Test/Sub/Nested standalone_parallel_sub_test.go +! stdout '^ok.*\[no tests to run\]' +! stderr '^ok.*\[no tests to run\]' +stdout '^ok' + +-- standalone_parallel_sub_test.go -- +package standalone_parallel_sub_test + +import "testing" + +func Test(t *testing.T) { + ch := make(chan bool, 1) + t.Run("Sub", func(t *testing.T) { + t.Parallel() + <-ch + t.Run("Nested", func(t *testing.T) {}) + }) + // Ensures that Sub will finish after its t.Run call already returned. + ch <- true +} diff --git a/src/cmd/go/testdata/script/test_match_only_tests.txt b/src/cmd/go/testdata/script/test_match_only_tests.txt new file mode 100644 index 0000000..9185793 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_only_tests.txt @@ -0,0 +1,13 @@ +# Matches only tests +go test -run Test standalone_test.go +! stdout '^ok.*\[no tests to run\]' +! stderr '^ok.*\[no tests to run\]' +stdout '^ok' + +-- standalone_test.go -- +package standalone_test + +import "testing" + +func Test(t *testing.T) { +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_minus_n.txt b/src/cmd/go/testdata/script/test_minus_n.txt new file mode 100644 index 0000000..9900dbc --- /dev/null +++ b/src/cmd/go/testdata/script/test_minus_n.txt @@ -0,0 +1,14 @@ +# The intent here is to verify that 'go test -n' works without crashing. +# Any test will do. + +go test -n x_test.go + +-- x_test.go -- +package x_test + +import ( + "testing" +) + +func TestEmpty(t *testing.T) { +} diff --git a/src/cmd/go/testdata/script/test_no_run_example.txt b/src/cmd/go/testdata/script/test_no_run_example.txt new file mode 100644 index 0000000..53ac755 --- /dev/null +++ b/src/cmd/go/testdata/script/test_no_run_example.txt @@ -0,0 +1,30 @@ +go test -v norunexample +stdout 'File with non-runnable example was built.' + +-- go.mod -- +module norunexample + +go 1.16 +-- example_test.go -- +package pkg_test + +import "os" + +func init() { + os.Stdout.Write([]byte("File with non-runnable example was built.\n")) +} + +func Example_test() { + // This test will not be run, it has no "Output:" comment. +} +-- test_test.go -- +package pkg + +import ( + "os" + "testing" +) + +func TestBuilt(t *testing.T) { + os.Stdout.Write([]byte("A normal test was executed.\n")) +} diff --git a/src/cmd/go/testdata/script/test_no_tests.txt b/src/cmd/go/testdata/script/test_no_tests.txt new file mode 100644 index 0000000..2d624d1 --- /dev/null +++ b/src/cmd/go/testdata/script/test_no_tests.txt @@ -0,0 +1,15 @@ +# Tests issue #26242 + +go test testnorun +stdout 'testnorun\t\[no test files\]' + +-- go.mod -- +module testnorun + +go 1.16 +-- p.go -- +package p + +func init() { + panic("go test must not link and run test binaries without tests") +} diff --git a/src/cmd/go/testdata/script/test_overlay.txt b/src/cmd/go/testdata/script/test_overlay.txt new file mode 100644 index 0000000..b6bdc11 --- /dev/null +++ b/src/cmd/go/testdata/script/test_overlay.txt @@ -0,0 +1,24 @@ +[short] skip + +cd $WORK/gopath/src/foo +go test -list=. -overlay=overlay.json . +stdout 'TestBar' + +-- go.mod -- +module test.pkg +-- foo/foo_test.go -- +package foo + +import "testing" + +func TestFoo(t *testing.T) { } +-- tmp/bar_test.go -- +package foo + +import "testing" + +func TestBar(t *testing.T) { + t.Fatal("dummy failure") +} +-- foo/overlay.json -- +{"Replace": {"foo_test.go": "../tmp/bar_test.go"}} diff --git a/src/cmd/go/testdata/script/test_parallel_number.txt b/src/cmd/go/testdata/script/test_parallel_number.txt new file mode 100644 index 0000000..4eb9794 --- /dev/null +++ b/src/cmd/go/testdata/script/test_parallel_number.txt @@ -0,0 +1,25 @@ +[short] skip + +# go test -parallel -1 shouldn't work +! go test -parallel -1 standalone_parallel_sub_test.go +stdout '-parallel can only be given' + +# go test -parallel 0 shouldn't work +! go test -parallel 0 standalone_parallel_sub_test.go +stdout '-parallel can only be given' + +-- standalone_parallel_sub_test.go -- +package standalone_parallel_sub_test + +import "testing" + +func Test(t *testing.T) { + ch := make(chan bool, 1) + t.Run("Sub", func(t *testing.T) { + t.Parallel() + <-ch + t.Run("Nested", func(t *testing.T) {}) + }) + // Ensures that Sub will finish after its t.Run call already returned. + ch <- true +} diff --git a/src/cmd/go/testdata/script/test_ppc64_linker_funcs.txt b/src/cmd/go/testdata/script/test_ppc64_linker_funcs.txt new file mode 100644 index 0000000..735b5dc --- /dev/null +++ b/src/cmd/go/testdata/script/test_ppc64_linker_funcs.txt @@ -0,0 +1,49 @@ +# Tests that the linker implements the PPC64 ELFv2 ABI +# register save and restore functions as defined in +# section 2.3.3.1 of the PPC64 ELFv2 ABI when linking +# external objects most likely compiled with gcc's +# -Os option. +# +# Verifies golang.org/issue/52366 for linux/ppc64le +[!GOOS:linux] skip +[!compiler:gc] skip +[!cgo] skip +[!GOARCH:ppc64le] skip + +go build -ldflags='-linkmode=internal' +exec ./abitest +stdout success + +-- go.mod -- +module abitest + +-- abitest.go -- +package main + +/* +#cgo CFLAGS: -Os + +int foo_fpr() { + asm volatile("":::"fr31","fr30","fr29","fr28"); +} +int foo_gpr0() { + asm volatile("":::"r30","r29","r28"); +} +int foo_gpr1() { + asm volatile("":::"fr31", "fr30","fr29","fr28","r30","r29","r28"); +} +int foo_vr() { + asm volatile("":::"v31","v30","v29","v28"); +} +*/ +import "C" + +import "fmt" + +func main() { + C.foo_fpr() + C.foo_gpr0() + C.foo_gpr1() + C.foo_vr() + fmt.Println("success") +} diff --git a/src/cmd/go/testdata/script/test_ppc64le_cgo_inline_plt.txt b/src/cmd/go/testdata/script/test_ppc64le_cgo_inline_plt.txt new file mode 100644 index 0000000..ef9ff03 --- /dev/null +++ b/src/cmd/go/testdata/script/test_ppc64le_cgo_inline_plt.txt @@ -0,0 +1,38 @@ +# Verify the linker will correctly resolve +# ppc64le objects compiled with gcc's -fno-plt +# option. This inlines PLT calls, and generates +# additional reloc types which the internal linker +# should handle. +# +# Verifies golang.org/issue/53345 +# +# Note, older gcc/clang may accept this option, but +# ignore it if binutils does not support the relocs. +[!compiler:gc] skip +[!cgo] skip +[!GOARCH:ppc64le] skip + +env CGO_CFLAGS='-fno-plt -O2 -g' + +go build -ldflags='-linkmode=internal' +exec ./noplttest +stdout helloworld + +-- go.mod -- +module noplttest + +-- noplttest.go -- +package main + +/* +#include <stdio.h> +void helloworld(void) { + printf("helloworld\n"); + fflush(stdout); +} +*/ +import "C" + +func main() { + C.helloworld() +} diff --git a/src/cmd/go/testdata/script/test_profile.txt b/src/cmd/go/testdata/script/test_profile.txt new file mode 100644 index 0000000..9110706 --- /dev/null +++ b/src/cmd/go/testdata/script/test_profile.txt @@ -0,0 +1,19 @@ +[compiler:gccgo] skip 'gccgo has no standard packages' +[short] skip + +# Check go test -cpuprofile creates errors.test +go test -cpuprofile errors.prof errors +exists -exec errors.test$GOEXE + +# Check go test -cpuprofile -o myerrors.test creates errors.test +go test -cpuprofile errors.prof -o myerrors.test$GOEXE errors +exists -exec myerrors.test$GOEXE + +# Check go test -mutexprofile creates errors.test +go test -mutexprofile errors.prof errors +exists -exec errors.test$GOEXE + +# Check go test -mutexprofile -o myerrors.test creates errors.test +go test -mutexprofile errors.prof -o myerrors.test$GOEXE errors +exists -exec myerrors.test$GOEXE + diff --git a/src/cmd/go/testdata/script/test_race.txt b/src/cmd/go/testdata/script/test_race.txt new file mode 100644 index 0000000..2ffea46 --- /dev/null +++ b/src/cmd/go/testdata/script/test_race.txt @@ -0,0 +1,51 @@ +[short] skip +[!race] skip + +go test testrace + +! go test -race testrace +stdout 'FAIL: TestRace' +! stdout 'PASS' +! stderr 'PASS' + +! go test -race testrace -run XXX -bench . +stdout 'FAIL: BenchmarkRace' +! stdout 'PASS' +! stderr 'PASS' + +-- go.mod -- +module testrace + +go 1.16 +-- race_test.go -- +package testrace + +import "testing" + +func TestRace(t *testing.T) { + for i := 0; i < 10; i++ { + c := make(chan int) + x := 1 + go func() { + x = 2 + c <- 1 + }() + x = 3 + <-c + _ = x + } +} + +func BenchmarkRace(b *testing.B) { + for i := 0; i < b.N; i++ { + c := make(chan int) + x := 1 + go func() { + x = 2 + c <- 1 + }() + x = 3 + <-c + _ = x + } +} diff --git a/src/cmd/go/testdata/script/test_race_cover_mode_issue20435.txt b/src/cmd/go/testdata/script/test_race_cover_mode_issue20435.txt new file mode 100644 index 0000000..eacc882 --- /dev/null +++ b/src/cmd/go/testdata/script/test_race_cover_mode_issue20435.txt @@ -0,0 +1,48 @@ +[short] skip +[!race] skip + +# Make sure test is functional. +go test testrace + +# Now, check that -race -covermode=set is not allowed. +! go test -race -covermode=set testrace +stderr '-covermode must be "atomic", not "set", when -race is enabled' +! stdout PASS +! stderr PASS + +-- go.mod -- +module testrace + +go 1.16 +-- race_test.go -- +package testrace + +import "testing" + +func TestRace(t *testing.T) { + for i := 0; i < 10; i++ { + c := make(chan int) + x := 1 + go func() { + x = 2 + c <- 1 + }() + x = 3 + <-c + _ = x + } +} + +func BenchmarkRace(b *testing.B) { + for i := 0; i < b.N; i++ { + c := make(chan int) + x := 1 + go func() { + x = 2 + c <- 1 + }() + x = 3 + <-c + _ = x + } +} diff --git a/src/cmd/go/testdata/script/test_race_install.txt b/src/cmd/go/testdata/script/test_race_install.txt new file mode 100644 index 0000000..918d7e9 --- /dev/null +++ b/src/cmd/go/testdata/script/test_race_install.txt @@ -0,0 +1,12 @@ +[!race] skip +[short] skip + +mkdir $WORKDIR/tmp/pkg +go install -race -pkgdir=$WORKDIR/tmp/pkg std + +-- go.mod -- +module empty + +go 1.16 +-- pkg/pkg.go -- +package p diff --git a/src/cmd/go/testdata/script/test_race_install_cgo.txt b/src/cmd/go/testdata/script/test_race_install_cgo.txt new file mode 100644 index 0000000..e1fe4f2 --- /dev/null +++ b/src/cmd/go/testdata/script/test_race_install_cgo.txt @@ -0,0 +1,91 @@ +# Tests Issue #10500 + +[!race] skip + +env GOBIN=$WORK/bin +go install m/mtime m/sametime + +go tool -n cgo +cp stdout cgopath.txt +exec $GOBIN/mtime cgopath.txt # get the mtime of the file whose name is in cgopath.txt +cp stdout cgotime_before.txt + + # For this test, we don't actually care whether 'go test -race -i' succeeds. + # It may fail if GOROOT is read-only (perhaps it was installed as root). + # We only care that it does not overwrite cmd/cgo regardless. +? go test -race -i runtime/race + +exec $GOBIN/mtime cgopath.txt # get the mtime of the file whose name is in cgopath.txt +cp stdout cgotime_after.txt +exec $GOBIN/sametime cgotime_before.txt cgotime_after.txt + +-- go.mod -- +module m + +go 1.16 +-- mtime/mtime.go -- +package main + +import ( + "encoding/json" + "fmt" + "os" + "strings" +) + +func main() { + b, err := os.ReadFile(os.Args[1]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + filename := strings.TrimSpace(string(b)) + info, err := os.Stat(filename) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if err := json.NewEncoder(os.Stdout).Encode(info.ModTime()); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} +-- sametime/sametime.go -- +package main + +import ( + "encoding/json" + "fmt" + "os" + "time" +) + + +func main() { + var t1 time.Time + b1, err := os.ReadFile(os.Args[1]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if err := json.Unmarshal(b1, &t1); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + var t2 time.Time + b2, err := os.ReadFile(os.Args[2]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if err := json.Unmarshal(b2, &t2); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + if !t1.Equal(t2) { + fmt.Fprintf(os.Stderr, "time in %v (%v) is not the same as time in %v (%v)", os.Args[1], t1, os.Args[2], t2) + os.Exit(1) + } +} diff --git a/src/cmd/go/testdata/script/test_race_tag.txt b/src/cmd/go/testdata/script/test_race_tag.txt new file mode 100644 index 0000000..4b18ebc --- /dev/null +++ b/src/cmd/go/testdata/script/test_race_tag.txt @@ -0,0 +1,29 @@ +# Tests Issue #54468 + +[short] skip 'links a test binary' +[!race] skip + +go mod tidy +go test -c -o=$devnull -race . + +! stderr 'cannot find package' + +-- go.mod -- +module testrace + +go 1.18 + +require rsc.io/sampler v1.0.0 +-- race_test.go -- +//go:build race + +package testrace + +import ( + "testing" + + _ "rsc.io/sampler" +) + +func TestRaceTag(t *testing.T) { +} diff --git a/src/cmd/go/testdata/script/test_rebuildall.txt b/src/cmd/go/testdata/script/test_rebuildall.txt new file mode 100644 index 0000000..38233c1 --- /dev/null +++ b/src/cmd/go/testdata/script/test_rebuildall.txt @@ -0,0 +1,14 @@ +env GO111MODULE=off + +# Regression test for golang.org/issue/6844: +# 'go test -a' should force dependencies in the standard library to be rebuilt. + +[short] skip + +go test -x -a -c testdata/dep_test.go +stderr '^.*[/\\]compile'$GOEXE'["]? (.* )?regexp .*[/\\]regexp\.go' + +-- testdata/dep_test.go -- +package deps + +import _ "testing" diff --git a/src/cmd/go/testdata/script/test_regexps.txt b/src/cmd/go/testdata/script/test_regexps.txt new file mode 100644 index 0000000..2f33080 --- /dev/null +++ b/src/cmd/go/testdata/script/test_regexps.txt @@ -0,0 +1,79 @@ +go test -cpu=1 -run=X/Y -bench=X/Y -count=2 -v testregexp + +# Test the following: + +# TestX is run, twice +stdout -count=2 '^=== RUN TestX$' +stdout -count=2 '^ x_test.go:6: LOG: X running$' + +# TestX/Y is run, twice +stdout -count=2 '^=== RUN TestX/Y$' +stdout -count=2 '^ x_test.go:8: LOG: Y running$' + +# TestXX is run, twice +stdout -count=2 '^=== RUN TestXX$' +stdout -count=2 '^ z_test.go:10: LOG: XX running' + +# TestZ is not run +! stdout '^=== RUN TestZ$' + +# BenchmarkX is run with N=1 once, only to discover what sub-benchmarks it has, +# and should not print a final summary line. +stdout -count=1 '^ x_test.go:13: LOG: X running N=1$' +! stdout '^\s+BenchmarkX: x_test.go:13: LOG: X running N=\d\d+' +! stdout 'BenchmarkX\s+\d+' + +# Same for BenchmarkXX. +stdout -count=1 '^ z_test.go:18: LOG: XX running N=1$' +! stdout '^ z_test.go:18: LOG: XX running N=\d\d+' +! stdout 'BenchmarkXX\s+\d+' + +# BenchmarkX/Y is run in full twice due to -count=2. +# "Run in full" means that it runs for approximately the default benchtime, +# but may cap out at N=1e9. +# We don't actually care what the final iteration count is, but it should be +# a large number, and the last iteration count prints right before the results. +stdout -count=2 '^ x_test.go:15: LOG: Y running N=[1-9]\d{4,}\nBenchmarkX/Y\s+\d+' + +-- go.mod -- +module testregexp + +go 1.16 +-- x_test.go -- +package x + +import "testing" + +func TestX(t *testing.T) { + t.Logf("LOG: X running") + t.Run("Y", func(t *testing.T) { + t.Logf("LOG: Y running") + }) +} + +func BenchmarkX(b *testing.B) { + b.Logf("LOG: X running N=%d", b.N) + b.Run("Y", func(b *testing.B) { + b.Logf("LOG: Y running N=%d", b.N) + }) +} +-- z_test.go -- +package x + +import "testing" + +func TestZ(t *testing.T) { + t.Logf("LOG: Z running") +} + +func TestXX(t *testing.T) { + t.Logf("LOG: XX running") +} + +func BenchmarkZ(b *testing.B) { + b.Logf("LOG: Z running N=%d", b.N) +} + +func BenchmarkXX(b *testing.B) { + b.Logf("LOG: XX running N=%d", b.N) +} diff --git a/src/cmd/go/testdata/script/test_relative_cmdline.txt b/src/cmd/go/testdata/script/test_relative_cmdline.txt new file mode 100644 index 0000000..96f7b87 --- /dev/null +++ b/src/cmd/go/testdata/script/test_relative_cmdline.txt @@ -0,0 +1,52 @@ +# Relative imports in command line package + +env GO111MODULE=off + +# Run tests outside GOPATH. +env GOPATH=$WORK/tmp + +go test ./testimport/p.go ./testimport/p_test.go ./testimport/x_test.go +stdout '^ok' + +-- testimport/p.go -- +package p + +func F() int { return 1 } +-- testimport/p1/p1.go -- +package p1 + +func F() int { return 1 } +-- testimport/p2/p2.go -- +package p2 + +func F() int { return 1 } +-- testimport/p_test.go -- +package p + +import ( + "./p1" + + "testing" +) + +func TestF(t *testing.T) { + if F() != p1.F() { + t.Fatal(F()) + } +} +-- testimport/x_test.go -- +package p_test + +import ( + . "../testimport" + + "./p2" + + "testing" +) + +func TestF1(t *testing.T) { + if F() != p2.F() { + t.Fatal(F()) + } +} diff --git a/src/cmd/go/testdata/script/test_relative_import.txt b/src/cmd/go/testdata/script/test_relative_import.txt new file mode 100644 index 0000000..938a875 --- /dev/null +++ b/src/cmd/go/testdata/script/test_relative_import.txt @@ -0,0 +1,31 @@ +# Relative imports in go test +env GO111MODULE=off # relative import not supported in module mode + +# Run tests outside GOPATH. +env GOPATH=$WORK/tmp + +go test ./testimport +stdout '^ok' + +-- testimport/p.go -- +package p + +func F() int { return 1 } +-- testimport/p1/p1.go -- +package p1 + +func F() int { return 1 } +-- testimport/p_test.go -- +package p + +import ( + "./p1" + + "testing" +) + +func TestF(t *testing.T) { + if F() != p1.F() { + t.Fatal(F()) + } +} diff --git a/src/cmd/go/testdata/script/test_script_cmdcd.txt b/src/cmd/go/testdata/script/test_script_cmdcd.txt new file mode 100644 index 0000000..6e6f67e --- /dev/null +++ b/src/cmd/go/testdata/script/test_script_cmdcd.txt @@ -0,0 +1,13 @@ +# Tests that after a cd command, where usually the UNIX path separator is used, +# a match against $PWD does not fail on Windows. + +cd $WORK/a/b/c/pkg + +go list -find -f {{.Root}} +stdout $PWD + +-- $WORK/a/b/c/pkg/go.mod -- +module pkg + +-- $WORK/a/b/c/pkg/pkg.go -- +package pkg diff --git a/src/cmd/go/testdata/script/test_shuffle.txt b/src/cmd/go/testdata/script/test_shuffle.txt new file mode 100644 index 0000000..98029f5 --- /dev/null +++ b/src/cmd/go/testdata/script/test_shuffle.txt @@ -0,0 +1,134 @@ +# Shuffle order of tests and benchmarks + +[short] skip 'builds and repeatedly runs a test binary' + +# Run tests +go test -v foo_test.go +! stdout '-test.shuffle ' +stdout '(?s)TestOne(.*)TestTwo(.*)TestThree' + +go test -v -shuffle=off foo_test.go +! stdout '-test.shuffle ' +stdout '(?s)TestOne(.*)TestTwo(.*)TestThree' + +go test -v -shuffle=42 foo_test.go +stdout '^-test.shuffle 42' +stdout '(?s)TestThree(.*)TestOne(.*)TestTwo' + +go test -v -shuffle=0 foo_test.go +stdout '^-test.shuffle 0' +stdout '(?s)TestTwo(.*)TestOne(.*)TestThree' + +go test -v -shuffle -1 foo_test.go +stdout '^-test.shuffle -1' +stdout '(?s)TestThree(.*)TestOne(.*)TestTwo' + +go test -v -shuffle=on foo_test.go +stdout '^-test.shuffle ' +stdout '(?s)=== RUN TestOne(.*)--- PASS: TestOne' +stdout '(?s)=== RUN TestTwo(.*)--- PASS: TestTwo' +stdout '(?s)=== RUN TestThree(.*)--- PASS: TestThree' + + +# Run tests and benchmarks +go test -v -bench=. foo_test.go +! stdout '-test.shuffle ' +stdout '(?s)TestOne(.*)TestTwo(.*)TestThree(.*)BenchmarkOne(.*)BenchmarkTwo(.*)BenchmarkThree' + +go test -v -bench=. -shuffle=off foo_test.go +! stdout '-test.shuffle ' +stdout '(?s)TestOne(.*)TestTwo(.*)TestThree(.*)BenchmarkOne(.*)BenchmarkTwo(.*)BenchmarkThree' + +go test -v -bench=. -shuffle=42 foo_test.go +stdout '^-test.shuffle 42' +stdout '(?s)TestThree(.*)TestOne(.*)TestTwo(.*)BenchmarkThree(.*)BenchmarkOne(.*)BenchmarkTwo' + +go test -v -bench=. -shuffle=0 foo_test.go +stdout '^-test.shuffle 0' +stdout '(?s)TestTwo(.*)TestOne(.*)TestThree(.*)BenchmarkThree(.*)BenchmarkOne(.*)BenchmarkTwo' + +go test -v -bench=. -shuffle -1 foo_test.go +stdout '^-test.shuffle -1' +stdout '(?s)TestThree(.*)TestOne(.*)TestTwo(.*)BenchmarkOne(.*)BenchmarkThree(.*)BenchmarkTwo' + +go test -v -bench=. -shuffle=on foo_test.go +stdout '^-test.shuffle ' +stdout '(?s)=== RUN TestOne(.*)--- PASS: TestOne' +stdout '(?s)=== RUN TestTwo(.*)--- PASS: TestTwo' +stdout '(?s)=== RUN TestThree(.*)--- PASS: TestThree' +stdout -count=2 'BenchmarkOne' +stdout -count=2 'BenchmarkTwo' +stdout -count=2 'BenchmarkThree' + + +# When running go test -count=N, each of the N runs distinct runs should maintain the same +# shuffled order of these tests. +go test -v -shuffle=43 -count=4 foo_test.go +stdout '^-test.shuffle 43' +stdout '(?s)TestThree(.*)TestTwo(.*)TestOne(.*)TestThree(.*)TestTwo(.*)TestOne(.*)TestThree(.*)TestTwo(.*)TestOne(.*)TestThree(.*)TestTwo(.*)TestOne' + +go test -v -bench=. -shuffle=44 -count=2 foo_test.go +stdout '^-test.shuffle 44' +stdout '(?s)TestOne(.*)TestThree(.*)TestTwo(.*)TestOne(.*)TestThree(.*)TestTwo(.*)BenchmarkTwo(.*)BenchmarkOne(.*)BenchmarkThree(.*)' + + +# The feature should work with test binaries as well +go test -c +exec ./m.test -test.shuffle=off +! stdout '^-test.shuffle ' + +exec ./m.test -test.shuffle=on +stdout '^-test.shuffle ' + +exec ./m.test -test.v -test.bench=. -test.shuffle=0 foo_test.go +stdout '^-test.shuffle 0' +stdout '(?s)TestTwo(.*)TestOne(.*)TestThree(.*)BenchmarkThree(.*)BenchmarkOne(.*)BenchmarkTwo' + +exec ./m.test -test.v -test.bench=. -test.shuffle=123 foo_test.go +stdout '^-test.shuffle 123' +stdout '(?s)TestThree(.*)TestOne(.*)TestTwo(.*)BenchmarkThree(.*)BenchmarkTwo(.*)BenchmarkOne' + +exec ./m.test -test.v -test.bench=. -test.shuffle=-1 foo_test.go +stdout '^-test.shuffle -1' +stdout '(?s)TestThree(.*)TestOne(.*)TestTwo(.*)BenchmarkOne(.*)BenchmarkThree(.*)BenchmarkTwo' + +exec ./m.test -test.v -test.bench=. -test.shuffle=44 -test.count=2 foo_test.go +stdout '^-test.shuffle 44' +stdout '(?s)TestOne(.*)TestThree(.*)TestTwo(.*)TestOne(.*)TestThree(.*)TestTwo(.*)BenchmarkTwo(.*)BenchmarkOne(.*)BenchmarkThree(.*)' + + +# Negative testcases for invalid input +! go test -shuffle -count=2 +stderr 'invalid value "-count=2" for flag -shuffle: -shuffle argument must be "on", "off", or an int64: strconv.ParseInt: parsing "-count=2": invalid syntax' + +! go test -shuffle= +stderr '(?s)invalid value "" for flag -shuffle: -shuffle argument must be "on", "off", or an int64: strconv.ParseInt: parsing "": invalid syntax' + +! go test -shuffle=' ' +stderr '(?s)invalid value " " for flag -shuffle: -shuffle argument must be "on", "off", or an int64: strconv.ParseInt: parsing " ": invalid syntax' + +! go test -shuffle=true +stderr 'invalid value "true" for flag -shuffle: -shuffle argument must be "on", "off", or an int64: strconv.ParseInt: parsing "true": invalid syntax' + +! go test -shuffle='abc' +stderr 'invalid value "abc" for flag -shuffle: -shuffle argument must be "on", "off", or an int64: strconv.ParseInt: parsing "abc": invalid syntax' + +-- go.mod -- +module m + +go 1.16 +-- foo_test.go -- +package foo + +import "testing" + +func TestOne(t *testing.T) {} +func TestTwo(t *testing.T) {} +func TestThree(t *testing.T) {} + +func BenchmarkOne(b *testing.B) {} +func BenchmarkTwo(b *testing.B) {} +func BenchmarkThree(b *testing.B) {} + +-- foo.go -- +package foo diff --git a/src/cmd/go/testdata/script/test_skip.txt b/src/cmd/go/testdata/script/test_skip.txt new file mode 100644 index 0000000..2e5f4d6 --- /dev/null +++ b/src/cmd/go/testdata/script/test_skip.txt @@ -0,0 +1,45 @@ +go test -v -run Test -skip T skip_test.go +! stdout RUN +stdout '^ok.*\[no tests to run\]' + +go test -v -skip T skip_test.go +! stdout RUN + +go test -v -skip 1 skip_test.go +! stdout Test1 +stdout RUN.*Test2 +stdout RUN.*Test2/3 + +go test -v -skip 2/3 skip_test.go +stdout RUN.*Test1 +stdout RUN.*Test2 +stdout RUN.*ExampleTest1 +! stdout Test2/3 + +go test -v -skip 2/4 skip_test.go +stdout RUN.*Test1 +stdout RUN.*Test2 +stdout RUN.*Test2/3 +stdout RUN.*ExampleTest1 + +go test -v -skip Example skip_test.go +stdout RUN.*Test1 +stdout RUN.*Test2 +stdout RUN.*Test2/3 +! stdout ExampleTest1 + +-- skip_test.go -- +package skip_test + +import "testing" + +func Test1(t *testing.T) { +} + +func Test2(t *testing.T) { + t.Run("3", func(t *testing.T) {}) +} + +func ExampleTest1() { + // Output: +} diff --git a/src/cmd/go/testdata/script/test_source_order.txt b/src/cmd/go/testdata/script/test_source_order.txt new file mode 100644 index 0000000..2865276 --- /dev/null +++ b/src/cmd/go/testdata/script/test_source_order.txt @@ -0,0 +1,54 @@ +[short] skip + +# Control +! go test example2_test.go example1_test.go + +# This test only passes if the source order is preserved +go test example1_test.go example2_test.go + +-- example1_test.go -- +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Make sure that go test runs Example_Z before Example_A, preserving source order. + +package p + +import "fmt" + +var n int + +func Example_Z() { + n++ + fmt.Println(n) + // Output: 1 +} + +func Example_A() { + n++ + fmt.Println(n) + // Output: 2 +} +-- example2_test.go -- +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Make sure that go test runs Example_Y before Example_B, preserving source order. + +package p + +import "fmt" + +func Example_Y() { + n++ + fmt.Println(n) + // Output: 3 +} + +func Example_B() { + n++ + fmt.Println(n) + // Output: 4 +} diff --git a/src/cmd/go/testdata/script/test_status.txt b/src/cmd/go/testdata/script/test_status.txt new file mode 100644 index 0000000..aa6ad3c --- /dev/null +++ b/src/cmd/go/testdata/script/test_status.txt @@ -0,0 +1,18 @@ +env GO111MODULE=off + +! go test x y +stdout ^FAIL\s+x +stdout ^ok\s+y +stdout (?-m)FAIL\n$ + +-- x/x_test.go -- +package x + +import "testing" + +func TestNothingJustFail(t *testing.T) { + t.Fail() +} + +-- y/y_test.go -- +package y diff --git a/src/cmd/go/testdata/script/test_syntax_error_says_fail.txt b/src/cmd/go/testdata/script/test_syntax_error_says_fail.txt new file mode 100644 index 0000000..44ff6e2 --- /dev/null +++ b/src/cmd/go/testdata/script/test_syntax_error_says_fail.txt @@ -0,0 +1,25 @@ +# Test that the error message for a syntax error in a test go file +# says FAIL. + +env GO111MODULE=off +! go test syntaxerror +stderr 'x_test.go:' # check that the error is diagnosed +stdout 'FAIL' # check that go test says FAIL + +env GO111MODULE=on +cd syntaxerror +! go test syntaxerror +stderr 'x_test.go:' # check that the error is diagnosed +stdout 'FAIL' # check that go test says FAIL + +-- syntaxerror/go.mod -- +module syntaxerror + +go 1.16 +-- syntaxerror/x.go -- +package p +-- syntaxerror/x_test.go -- +package p + +func f() (x.y, z int) { +} diff --git a/src/cmd/go/testdata/script/test_timeout.txt b/src/cmd/go/testdata/script/test_timeout.txt new file mode 100644 index 0000000..4de4df4 --- /dev/null +++ b/src/cmd/go/testdata/script/test_timeout.txt @@ -0,0 +1,23 @@ +[short] skip +env GO111MODULE=off +cd a + +# If no timeout is set explicitly, 'go test' should set +# -test.timeout to its internal deadline. +go test -v . -- +stdout '10m0s' + +# An explicit -timeout argument should be propagated to -test.timeout. +go test -v -timeout 30m . -- +stdout '30m0s' + +-- a/timeout_test.go -- +package t +import ( + "flag" + "fmt" + "testing" +) +func TestTimeout(t *testing.T) { + fmt.Println(flag.Lookup("test.timeout").Value.String()) +} diff --git a/src/cmd/go/testdata/script/test_timeout_stdin.txt b/src/cmd/go/testdata/script/test_timeout_stdin.txt new file mode 100644 index 0000000..f2de0a6 --- /dev/null +++ b/src/cmd/go/testdata/script/test_timeout_stdin.txt @@ -0,0 +1,88 @@ +# Regression test for https://go.dev/issue/24050: +# a test that exits with an I/O stream held open +# should fail after a reasonable delay, not wait forever. +# (As of the time of writing, that delay is 10% of the timeout, +# but this test does not depend on its specific value.) + +[short] skip 'runs a test that hangs until its WaitDelay expires' + +! go test -v -timeout=1m . + + # After the test process itself prints PASS and exits, + # the kernel closes its stdin pipe to to the orphaned subprocess. + # At that point, we expect the subprocess to print 'stdin closed' + # and periodically log to stderr until the WaitDelay expires. + # + # Once the WaitDelay expires, the copying goroutine for 'go test' stops and + # closes the read side of the stderr pipe, and the subprocess will eventually + # exit due to a failed write to that pipe. + +stdout '^--- PASS: TestOrphanCmd .*\nPASS\nstdin closed' +stdout '^\*\*\* Test I/O incomplete \d+.* after exiting\.\nexec: WaitDelay expired before I/O complete\nFAIL\s+example\s+\d+(\.\d+)?s' + +-- go.mod -- +module example + +go 1.20 +-- main_test.go -- +package main + +import ( + "fmt" + "io" + "os" + "os/exec" + "testing" + "time" +) + +func TestMain(m *testing.M) { + if os.Getenv("TEST_TIMEOUT_HANG") == "1" { + io.Copy(io.Discard, os.Stdin) + if _, err := os.Stderr.WriteString("stdin closed\n"); err != nil { + os.Exit(1) + } + + ticker := time.NewTicker(100 * time.Millisecond) + for t := range ticker.C { + _, err := fmt.Fprintf(os.Stderr, "still alive at %v\n", t) + if err != nil { + os.Exit(1) + } + } + } + + m.Run() +} + +func TestOrphanCmd(t *testing.T) { + exe, err := os.Executable() + if err != nil { + t.Fatal(err) + } + + cmd := exec.Command(exe) + cmd.Env = append(cmd.Environ(), "TEST_TIMEOUT_HANG=1") + + // Hold stdin open until this (parent) process exits. + if _, err := cmd.StdinPipe(); err != nil { + t.Fatal(err) + } + + // Forward stderr to the subprocess so that it can hold the stream open. + cmd.Stderr = os.Stderr + + if err := cmd.Start(); err != nil { + t.Fatal(err) + } + t.Logf("started %v", cmd) + + // Intentionally leak cmd when the test completes. + // This will allow the test process itself to exit, but (at least on Unix + // platforms) will keep the parent process's stderr stream open. + go func() { + if err := cmd.Wait(); err != nil { + os.Exit(3) + } + }() +} diff --git a/src/cmd/go/testdata/script/test_trimpath.txt b/src/cmd/go/testdata/script/test_trimpath.txt new file mode 100644 index 0000000..065f9ce --- /dev/null +++ b/src/cmd/go/testdata/script/test_trimpath.txt @@ -0,0 +1,51 @@ +[short] skip + +go test -trimpath -v . +! stdout '[/\\]pkg_test[/\\]' +stdout -count=3 '[/\\]pkg[/\\]' + +-- go.mod -- +module example.com/pkg + +go 1.17 + +-- pkg.go -- +package pkg + +import "runtime" + +func PrintFile() { + _, file, _, _ := runtime.Caller(0) + println(file) +} + +-- pkg_test.go -- +package pkg + +import "runtime" + +func PrintFileForTest() { + _, file, _, _ := runtime.Caller(0) + println(file) +} + +-- pkg_x_test.go -- +package pkg_test + +import ( + "runtime" + "testing" + + "example.com/pkg" +) + +func TestMain(m *testing.M) { + pkg.PrintFile() + pkg.PrintFileForTest() + PrintFileInXTest() +} + +func PrintFileInXTest() { + _, file, _, _ := runtime.Caller(0) + println(file) +} diff --git a/src/cmd/go/testdata/script/test_trimpath_main.txt b/src/cmd/go/testdata/script/test_trimpath_main.txt new file mode 100644 index 0000000..c076212 --- /dev/null +++ b/src/cmd/go/testdata/script/test_trimpath_main.txt @@ -0,0 +1,38 @@ +[short] skip + +go test -trimpath -v . +! stdout '[/\\]pkg_test[/\\]' +stdout -count=2 '[/\\]pkg[/\\]' + +-- go.mod -- +module example.com/pkg + +go 1.17 + +-- main.go -- +package main + +import "runtime" + +func PrintFile() { + _, file, _, _ := runtime.Caller(0) + println(file) +} + +-- main_test.go -- +package main + +import ( + "runtime" + "testing" +) + +func PrintFileForTest() { + _, file, _, _ := runtime.Caller(0) + println(file) +} + +func TestMain(m *testing.M) { + PrintFile() + PrintFileForTest() +} diff --git a/src/cmd/go/testdata/script/test_trimpath_test_suffix.txt b/src/cmd/go/testdata/script/test_trimpath_test_suffix.txt new file mode 100644 index 0000000..6cbad83 --- /dev/null +++ b/src/cmd/go/testdata/script/test_trimpath_test_suffix.txt @@ -0,0 +1,40 @@ +[short] skip + +go test -trimpath -v . +! stdout '[/\\]pkg_test_test[/\\]' +stdout -count=2 '[/\\]pkg_test[/\\]' + +-- go.mod -- +module example.com/pkg_test + +go 1.17 + +-- pkg.go -- +package pkg_test + +import "runtime" + +func PrintFile() { + _, file, _, _ := runtime.Caller(0) + println(file) +} + +-- pkg_x_test.go -- +package pkg_test_test + +import ( + "runtime" + "testing" + + "example.com/pkg_test" +) + +func PrintFileForTest() { + _, file, _, _ := runtime.Caller(0) + println(file) +} + +func TestMain(m *testing.M) { + pkg_test.PrintFile() + PrintFileForTest() +} diff --git a/src/cmd/go/testdata/script/test_vendor.txt b/src/cmd/go/testdata/script/test_vendor.txt new file mode 100644 index 0000000..c6a88b6 --- /dev/null +++ b/src/cmd/go/testdata/script/test_vendor.txt @@ -0,0 +1,57 @@ +# In GOPATH mode, vendored packages can replace std packages. +env GO111MODULE=off +cd vend/hello +go test -v +stdout TestMsgInternal +stdout TestMsgExternal + +# In module mode, they cannot. +env GO111MODULE=on +! go test -mod=vendor +stderr 'undefined: strings.Msg' + +-- vend/hello/go.mod -- +module vend/hello + +go 1.16 +-- vend/hello/hello.go -- +package main + +import ( + "fmt" + "strings" // really ../vendor/strings +) + +func main() { + fmt.Printf("%s\n", strings.Msg) +} +-- vend/hello/hello_test.go -- +package main + +import ( + "strings" // really ../vendor/strings + "testing" +) + +func TestMsgInternal(t *testing.T) { + if strings.Msg != "hello, world" { + t.Fatalf("unexpected msg: %v", strings.Msg) + } +} +-- vend/hello/hellox_test.go -- +package main_test + +import ( + "strings" // really ../vendor/strings + "testing" +) + +func TestMsgExternal(t *testing.T) { + if strings.Msg != "hello, world" { + t.Fatalf("unexpected msg: %v", strings.Msg) + } +} +-- vend/vendor/strings/msg.go -- +package strings + +var Msg = "hello, world" diff --git a/src/cmd/go/testdata/script/test_vet.txt b/src/cmd/go/testdata/script/test_vet.txt new file mode 100644 index 0000000..6151f91 --- /dev/null +++ b/src/cmd/go/testdata/script/test_vet.txt @@ -0,0 +1,123 @@ +[short] skip + +# Test file +! go test p1_test.go +stderr 'Logf format %d' +go test -vet=off +stdout '^ok' + +# Non-test file +! go test p1.go +stderr 'Printf format %d' +go test -x -vet=shift p1.go +stderr '[\\/]vet.*-shift' +stdout '\[no test files\]' +go test -vet=off p1.go +! stderr '[\\/]vet.*-shift' +stdout '\[no test files\]' + +# ensure all runs non-default vet +! go test -vet=all ./vetall/... +stderr 'using resp before checking for errors' + +# Test issue #47309 +! go test -vet=bools,xyz ./vetall/... +stderr '-vet argument must be a supported analyzer' + +# Test with a single analyzer +! go test -vet=httpresponse ./vetall/... +stderr 'using resp before checking for errors' + +# Test with a list of analyzers +go test -vet=atomic,bools,nilfunc ./vetall/... +stdout 'm/vetall.*\[no tests to run\]' + +# Test issue #22890 +go test m/vetcycle +stdout 'm/vetcycle.*\[no test files\]' + +# Test with ... +! go test ./vetfail/... +stderr 'Printf format %d' +stdout 'ok\s+m/vetfail/p2' + +# Check there's no diagnosis of a bad build constraint in vetxonly mode. +# Use -a so that we need to recompute the vet-specific export data for +# vetfail/p1. +go test -a m/vetfail/p2 +! stderr 'invalid.*constraint' + +-- go.mod -- +module m + +go 1.16 +-- p1_test.go -- +package p + +import "testing" + +func Test(t *testing.T) { + t.Logf("%d") // oops +} +-- p1.go -- +package p + +import "fmt" + +func F() { + fmt.Printf("%d") // oops +} +-- vetall/p.go -- +package p + +import "net/http" + +func F() { + resp, err := http.Head("example.com") + defer resp.Body.Close() + if err != nil { + panic(err) + } + // (defer statement belongs here) +} +-- vetall/p_test.go -- +package p +-- vetcycle/p.go -- +package p + +type ( + _ interface{ m(B1) } + A1 interface{ a(D1) } + B1 interface{ A1 } + C1 interface { + B1 /* ERROR issue #18395 */ + } + D1 interface{ C1 } +) + +var _ A1 = C1 /* ERROR cannot use C1 */ (nil) +-- vetfail/p1/p1.go -- +// +build !foo-bar + +package p1 + +import "fmt" + +func F() { + fmt.Printf("%d", "hello") // causes vet error +} +-- vetfail/p2/p2.go -- +package p2 + +import _ "m/vetfail/p1" + +func F() { +} +-- vetfail/p2/p2_test.go -- +package p2 + +import "testing" + +func TestF(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/script/test_write_profiles_on_timeout.txt b/src/cmd/go/testdata/script/test_write_profiles_on_timeout.txt new file mode 100644 index 0000000..0db183f --- /dev/null +++ b/src/cmd/go/testdata/script/test_write_profiles_on_timeout.txt @@ -0,0 +1,26 @@ +# Tests issue 19394 + +[short] skip + +! go test -cpuprofile cpu.pprof -memprofile mem.pprof -timeout 1ms +stdout '^panic: test timed out' +grep . cpu.pprof +grep . mem.pprof + +-- go.mod -- +module profiling + +go 1.16 +-- timeout_test.go -- +package timeouttest_test + +import ( + "testing" + "time" +) + +func TestSleep(t *testing.T) { + for { + time.Sleep(1 * time.Second) + } +} diff --git a/src/cmd/go/testdata/script/test_xtestonly_works.txt b/src/cmd/go/testdata/script/test_xtestonly_works.txt new file mode 100644 index 0000000..8e150db --- /dev/null +++ b/src/cmd/go/testdata/script/test_xtestonly_works.txt @@ -0,0 +1,27 @@ +[short] skip + +go test xtestonly +! stdout '^ok.*\[no tests to run\]' +stdout '^ok' + +-- go.mod -- +module xtestonly + +go 1.16 +-- f.go -- +package xtestonly + +func F() int { return 42 } +-- f_test.go -- +package xtestonly_test + +import ( + "testing" + "xtestonly" +) + +func TestF(t *testing.T) { + if x := xtestonly.F(); x != 42 { + t.Errorf("f.F() = %d, want 42", x) + } +} diff --git a/src/cmd/go/testdata/script/testing_coverage.txt b/src/cmd/go/testdata/script/testing_coverage.txt new file mode 100644 index 0000000..6cf6adb --- /dev/null +++ b/src/cmd/go/testdata/script/testing_coverage.txt @@ -0,0 +1,57 @@ + +# Rudimentary test of testing.Coverage(). + +[short] skip +[!GOEXPERIMENT:coverageredesign] skip + +# Simple test. +go test -v -cover -count=1 + +# Make sure test still passes when test executable is built and +# run outside the go command. +go test -c -o t.exe -cover +exec ./t.exe + +-- go.mod -- +module hello + +go 1.20 +-- hello.go -- +package hello + +func Hello() { + println("hello") +} + +// contents not especially interesting, just need some code +func foo(n int) int { + t := 0 + for i := 0; i < n; i++ { + for j := 0; j < i; j++ { + t += i ^ j + if t == 1010101 { + break + } + } + } + return t +} + +-- hello_test.go -- +package hello + +import "testing" + +func TestTestCoverage(t *testing.T) { + Hello() + C1 := testing.Coverage() + foo(29) + C2 := testing.Coverage() + if C1 == 0.0 || C2 == 0.0 { + t.Errorf("unexpected zero values C1=%f C2=%f", C1, C2) + } + if C1 >= C2 { + t.Errorf("testing.Coverage() not monotonically increasing C1=%f C2=%f", C1, C2) + } +} + diff --git a/src/cmd/go/testdata/script/testing_issue40908.txt b/src/cmd/go/testdata/script/testing_issue40908.txt new file mode 100644 index 0000000..839320e --- /dev/null +++ b/src/cmd/go/testdata/script/testing_issue40908.txt @@ -0,0 +1,25 @@ +[short] skip +[!race] skip + +go test -race testrace + +-- go.mod -- +module testrace + +go 1.16 +-- race_test.go -- +package testrace + +import "testing" + +func TestRace(t *testing.T) { + helperDone := make(chan struct{}) + go func() { + t.Logf("Something happened before cleanup.") + close(helperDone) + }() + + t.Cleanup(func() { + <-helperDone + }) +} diff --git a/src/cmd/go/testdata/script/toolexec.txt b/src/cmd/go/testdata/script/toolexec.txt new file mode 100644 index 0000000..20a5968 --- /dev/null +++ b/src/cmd/go/testdata/script/toolexec.txt @@ -0,0 +1,128 @@ +[short] skip + +# Build our simple toolexec program. +go build ./cmd/mytool + +# Use an ephemeral build cache so that our toolexec output is not cached +# for any stale standard-library dependencies. +# +# TODO(#27628): This should not be necessary. +env GOCACHE=$WORK/gocache + +# Build the main package with our toolexec program. For each action, it will +# print the tool's name and the TOOLEXEC_IMPORTPATH value. We expect to compile +# each package once, and link the main package once. +# Don't check the entire output at once, because the order in which the tools +# are run is irrelevant here. +# Finally, note that asm and cgo are run twice. + +go build -toolexec=$PWD/mytool +[GOARCH:amd64] stderr -count=2 '^asm'${GOEXE}' TOOLEXEC_IMPORTPATH="test/main/withasm"$' +stderr -count=1 '^compile'${GOEXE}' TOOLEXEC_IMPORTPATH="test/main/withasm"$' +[cgo] stderr -count=2 '^cgo'${GOEXE}' TOOLEXEC_IMPORTPATH="test/main/withcgo"$' +[cgo] stderr -count=1 '^compile'${GOEXE}' TOOLEXEC_IMPORTPATH="test/main/withcgo"$' +stderr -count=1 '^compile'${GOEXE}' TOOLEXEC_IMPORTPATH="test/main"$' +stderr -count=1 '^link'${GOEXE}' TOOLEXEC_IMPORTPATH="test/main"$' + +# Test packages are a little bit trickier. +# We have four variants of test/main, as reported by 'go list -test': +# +# test/main - the regular non-test package +# test/main.test - the generated test program +# test/main [test/main.test] - the test package for foo_test.go +# test/main_test [test/main.test] - the test package for foo_separate_test.go +# +# As such, TOOLEXEC_IMPORTPATH must see the same strings, to be able to uniquely +# identify each package being built as reported by 'go list -f {{.ImportPath}}'. +# Note that these are not really "import paths" anymore, but that naming is +# consistent with 'go list -json' at least. + +go test -toolexec=$PWD/mytool + +stderr -count=2 '^# test/main\.test$' +stderr -count=1 '^compile'${GOEXE}' TOOLEXEC_IMPORTPATH="test/main\.test"$' +stderr -count=1 '^link'${GOEXE}' TOOLEXEC_IMPORTPATH="test/main\.test"$' + +stderr -count=1 '^# test/main \[test/main\.test\]$' +stderr -count=1 '^compile'${GOEXE}' TOOLEXEC_IMPORTPATH="test/main \[test/main\.test\]"$' + +stderr -count=1 '^# test/main_test \[test/main\.test\]$' +stderr -count=1 '^compile'${GOEXE}' TOOLEXEC_IMPORTPATH="test/main_test \[test/main\.test\]"$' + +-- go.mod -- +module test/main +-- foo.go -- +// Simple package so we can test a program build with -toolexec. +// With a dummy import, to test different TOOLEXEC_IMPORTPATH values. +// Includes dummy uses of cgo and asm, to cover those tools as well. +package main + +import ( + _ "test/main/withasm" + _ "test/main/withcgo" +) + +func main() {} +-- foo_test.go -- +package main + +import "testing" + +func TestFoo(t *testing.T) {} +-- foo_separate_test.go -- +package main_test + +import "testing" + +func TestSeparateFoo(t *testing.T) {} +-- withcgo/withcgo.go -- +package withcgo + +// int fortytwo() +// { +// return 42; +// } +import "C" +-- withcgo/stub.go -- +package withcgo + +// Stub file to ensure we build without cgo too. +-- withasm/withasm.go -- +package withasm + +// Note that we don't need to declare the Add func at all. +-- withasm/withasm_amd64.s -- +TEXT ·Add(SB),$0-24 + MOVQ a+0(FP), AX + ADDQ b+8(FP), AX + MOVQ AX, ret+16(FP) + RET +-- cmd/mytool/main.go -- +package main + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" +) + +func main() { + tool, args := os.Args[1], os.Args[2:] + toolName := filepath.Base(tool) + if len(args) > 0 && args[0] == "-V=full" { + // We can't alter the version output. + } else { + // Print which tool we're running, and on what package. + fmt.Fprintf(os.Stdout, "%s TOOLEXEC_IMPORTPATH=%q\n", toolName, os.Getenv("TOOLEXEC_IMPORTPATH")) + } + + // Simply run the tool. + cmd := exec.Command(tool, args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/src/cmd/go/testdata/script/tooltags.txt b/src/cmd/go/testdata/script/tooltags.txt new file mode 100644 index 0000000..27068ee --- /dev/null +++ b/src/cmd/go/testdata/script/tooltags.txt @@ -0,0 +1,57 @@ +env GOOS=linux + +env GOARCH=amd64 +env GOAMD64=v3 +go list -f '{{context.ToolTags}}' +stdout 'amd64.v1 amd64.v2 amd64.v3' + +env GOARCH=arm +env GOARM=6 +go list -f '{{context.ToolTags}}' +stdout 'arm.5 arm.6' + +env GOARCH=mips +env GOMIPS=hardfloat +go list -f '{{context.ToolTags}}' +stdout 'mips.hardfloat' + +env GOARCH=mips64 +env GOMIPS=hardfloat +go list -f '{{context.ToolTags}}' +stdout 'mips64.hardfloat' + +env GOARCH=ppc64 +env GOPPC64=power9 +go list -f '{{context.ToolTags}}' +stdout 'ppc64.power8 ppc64.power9' + +env GOARCH=ppc64 +env GOPPC64=power10 +go list -f '{{context.ToolTags}}' +stdout 'ppc64.power8 ppc64.power9 ppc64.power10' + +env GOARCH=ppc64le +env GOPPC64=power9 +go list -f '{{context.ToolTags}}' +stdout 'ppc64le.power8 ppc64le.power9' + +env GOARCH=ppc64le +env GOPPC64=power10 +go list -f '{{context.ToolTags}}' +stdout 'ppc64le.power8 ppc64le.power9 ppc64le.power10' + +env GOARCH=386 +env GO386=sse2 +go list -f '{{context.ToolTags}}' +stdout '386.sse2' + +env GOARCH=wasm +env GOWASM=satconv +go list -f '{{context.ToolTags}}' +stdout 'wasm.satconv' + +-- go.mod -- +module m + +-- p.go -- +package p diff --git a/src/cmd/go/testdata/script/trampoline_reuse_test.txt b/src/cmd/go/testdata/script/trampoline_reuse_test.txt new file mode 100644 index 0000000..41e86e4 --- /dev/null +++ b/src/cmd/go/testdata/script/trampoline_reuse_test.txt @@ -0,0 +1,100 @@ +# Verify PPC64 does not reuse a trampoline which is too far away. +# This tests an edge case where the direct call relocation addend should +# be ignored when computing the distance from the direct call to the +# already placed trampoline +[short] skip +[!GOARCH:ppc64] [!GOARCH:ppc64le] skip +[GOOS:aix] skip + +# Note, this program does not run. Presumably, 'DWORD $0' is simpler to +# assembly 2^26 or so times. +# +# We build something which should be laid out as such: +# +# bar.Bar +# main.Func1 +# bar.Bar+400-tramp0 +# main.BigAsm +# main.Func2 +# bar.Bar+400-tramp1 +# +# bar.Bar needs to be placed far enough away to generate relocations +# from main package calls. and main.Func1 and main.Func2 are placed +# a bit more than the direct call limit apart, but not more than 0x400 +# bytes beyond it (to verify the reloc calc). + +go build + +-- go.mod -- + +module foo + +go 1.19 + +-- main.go -- + +package main + +import "foo/bar" + +func Func1() + +func main() { + Func1() + bar.Bar2() +} + +-- foo.s -- + +TEXT main·Func1(SB),0,$0-0 + CALL bar·Bar+0x400(SB) + CALL main·BigAsm(SB) +// A trampoline will be placed here to bar.Bar + +// This creates a gap sufficiently large to prevent trampoline reuse +#define NOP64 DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; +#define NOP256 NOP64 NOP64 NOP64 NOP64 +#define NOP2S10 NOP256 NOP256 NOP256 NOP256 +#define NOP2S12 NOP2S10 NOP2S10 NOP2S10 NOP2S10 +#define NOP2S14 NOP2S12 NOP2S12 NOP2S12 NOP2S12 +#define NOP2S16 NOP2S14 NOP2S14 NOP2S14 NOP2S14 +#define NOP2S18 NOP2S16 NOP2S16 NOP2S16 NOP2S16 +#define NOP2S20 NOP2S18 NOP2S18 NOP2S18 NOP2S18 +#define NOP2S22 NOP2S20 NOP2S20 NOP2S20 NOP2S20 +#define NOP2S24 NOP2S22 NOP2S22 NOP2S22 NOP2S22 +#define BIGNOP NOP2S24 NOP2S24 +TEXT main·BigAsm(SB),0,$0-0 + // Fill to the direct call limit so Func2 must generate a new trampoline. + // As the implicit trampoline above is just barely unreachable. + BIGNOP + MOVD $main·Func2(SB), R3 + +TEXT main·Func2(SB),0,$0-0 + CALL bar·Bar+0x400(SB) +// Another trampoline should be placed here. + +-- bar/bar.s -- + +#define NOP64 DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; +#define NOP256 NOP64 NOP64 NOP64 NOP64 +#define NOP2S10 NOP256 NOP256 NOP256 NOP256 +#define NOP2S12 NOP2S10 NOP2S10 NOP2S10 NOP2S10 +#define NOP2S14 NOP2S12 NOP2S12 NOP2S12 NOP2S12 +#define NOP2S16 NOP2S14 NOP2S14 NOP2S14 NOP2S14 +#define NOP2S18 NOP2S16 NOP2S16 NOP2S16 NOP2S16 +#define NOP2S20 NOP2S18 NOP2S18 NOP2S18 NOP2S18 +#define NOP2S22 NOP2S20 NOP2S20 NOP2S20 NOP2S20 +#define NOP2S24 NOP2S22 NOP2S22 NOP2S22 NOP2S22 +#define BIGNOP NOP2S24 NOP2S24 NOP2S10 +// A very big not very interesting function. +TEXT bar·Bar(SB),0,$0-0 + BIGNOP + +-- bar/bar.go -- + +package bar + +func Bar() + +func Bar2() { +} diff --git a/src/cmd/go/testdata/script/vendor_complex.txt b/src/cmd/go/testdata/script/vendor_complex.txt new file mode 100644 index 0000000..290efdb --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_complex.txt @@ -0,0 +1,75 @@ +env GO111MODULE=off + +# smoke test for complex build configuration +go build -o complex.exe complex +[!cross] [exec:gccgo] go build -compiler=gccgo -o complex.exe complex + +-- complex/main.go -- +package main + +import ( + _ "complex/nest/sub/test12" + _ "complex/nest/sub/test23" + "complex/w" + "v" +) + +func main() { + println(v.Hello + " " + w.World) +} + +-- complex/nest/sub/test12/p.go -- +package test12 + +// Check that vendor/v1 is used but vendor/v2 is NOT used (sub/vendor/v2 wins). + +import ( + "v1" + "v2" +) + +const x = v1.ComplexNestVendorV1 +const y = v2.ComplexNestSubVendorV2 + +-- complex/nest/sub/test23/p.go -- +package test23 + +// Check that vendor/v3 is used but vendor/v2 is NOT used (sub/vendor/v2 wins). + +import ( + "v2" + "v3" +) + +const x = v3.ComplexNestVendorV3 +const y = v2.ComplexNestSubVendorV2 + +-- complex/nest/sub/vendor/v2/v2.go -- +package v2 + +const ComplexNestSubVendorV2 = true + +-- complex/nest/vendor/v1/v1.go -- +package v1 + +const ComplexNestVendorV1 = true + +-- complex/nest/vendor/v2/v2.go -- +package v2 + +const ComplexNestVendorV2 = true + +-- complex/nest/vendor/v3/v3.go -- +package v3 + +const ComplexNestVendorV3 = true + +-- complex/vendor/v/v.go -- +package v + +const Hello = "hello" + +-- complex/w/w.go -- +package w + +const World = "world" diff --git a/src/cmd/go/testdata/script/vendor_gopath_issue11409.txt b/src/cmd/go/testdata/script/vendor_gopath_issue11409.txt new file mode 100644 index 0000000..c85f674 --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_gopath_issue11409.txt @@ -0,0 +1,52 @@ +[!GOOS:windows] [short] stop 'this test only applies to Windows' +env GO111MODULE=off + +go build run_go.go +exec ./run_go$GOEXE $GOPATH $GOPATH/src/vend/hello +stdout 'hello, world' + +-- run_go.go -- +package main + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" +) + +func changeVolume(s string, f func(s string) string) string { + vol := filepath.VolumeName(s) + return f(vol) + s[len(vol):] +} + +func main() { + gopath := changeVolume(os.Args[1], strings.ToLower) + dir := changeVolume(os.Args[2], strings.ToUpper) + cmd := exec.Command("go", "run", "hello.go") + cmd.Dir = dir + cmd.Env = append(os.Environ(), "GOPATH="+gopath) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +-- vend/hello/hello.go -- +package main + +import ( + "fmt" + "strings" // really ../vendor/strings +) + +func main() { + fmt.Printf("%s\n", strings.Msg) +} +-- vend/vendor/strings/msg.go -- +package strings + +var Msg = "hello, world" diff --git a/src/cmd/go/testdata/script/vendor_import.txt b/src/cmd/go/testdata/script/vendor_import.txt new file mode 100644 index 0000000..c64af2c --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_import.txt @@ -0,0 +1,106 @@ +# Imports +env GO111MODULE=off + +# Pass -e to permit errors (e.g. bad.go, invalid.go) +go list -f '{{.ImportPath}} {{.Imports}}' -e 'vend/...' 'vend/vendor/...' 'vend/x/vendor/...' +cmp stdout want_vendor_imports.txt + +-- want_vendor_imports.txt -- +vend [vend/vendor/p r] +vend/dir1 [] +vend/hello [fmt vend/vendor/strings] +vend/subdir [vend/vendor/p r] +vend/x [vend/x/vendor/p vend/vendor/q vend/x/vendor/r vend/dir1 vend/vendor/vend/dir1/dir2] +vend/x/invalid [vend/x/invalid/vendor/foo] +vend/vendor/p [] +vend/vendor/q [] +vend/vendor/strings [] +vend/vendor/vend/dir1/dir2 [] +vend/x/vendor/p [] +vend/x/vendor/p/p [notfound] +vend/x/vendor/r [] +-- vend/bad.go -- +package vend + +import _ "r" +-- vend/dir1/dir1.go -- +package dir1 +-- vend/good.go -- +package vend + +import _ "p" +-- vend/hello/hello.go -- +package main + +import ( + "fmt" + "strings" // really ../vendor/strings +) + +func main() { + fmt.Printf("%s\n", strings.Msg) +} +-- vend/hello/hello_test.go -- +package main + +import ( + "strings" // really ../vendor/strings + "testing" +) + +func TestMsgInternal(t *testing.T) { + if strings.Msg != "hello, world" { + t.Fatalf("unexpected msg: %v", strings.Msg) + } +} +-- vend/hello/hellox_test.go -- +package main_test + +import ( + "strings" // really ../vendor/strings + "testing" +) + +func TestMsgExternal(t *testing.T) { + if strings.Msg != "hello, world" { + t.Fatalf("unexpected msg: %v", strings.Msg) + } +} +-- vend/subdir/bad.go -- +package subdir + +import _ "r" +-- vend/subdir/good.go -- +package subdir + +import _ "p" +-- vend/vendor/p/p.go -- +package p +-- vend/vendor/q/q.go -- +package q +-- vend/vendor/strings/msg.go -- +package strings + +var Msg = "hello, world" +-- vend/vendor/vend/dir1/dir2/dir2.go -- +package dir2 +-- vend/x/invalid/invalid.go -- +package invalid + +import "vend/x/invalid/vendor/foo" +-- vend/x/vendor/p/p/p.go -- +package p + +import _ "notfound" +-- vend/x/vendor/p/p.go -- +package p +-- vend/x/vendor/r/r.go -- +package r +-- vend/x/x.go -- +package x + +import _ "p" +import _ "q" +import _ "r" +import _ "vend/dir1" // not vendored +import _ "vend/dir1/dir2" // vendored diff --git a/src/cmd/go/testdata/script/vendor_import_missing.txt b/src/cmd/go/testdata/script/vendor_import_missing.txt new file mode 100644 index 0000000..8e50dfe --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_import_missing.txt @@ -0,0 +1,7 @@ +# Missing package error message +! go build vend/x/vendor/p/p + +-- vend/x/vendor/p/p/p.go -- +package p + +import _ "notfound" diff --git a/src/cmd/go/testdata/script/vendor_import_wrong.txt b/src/cmd/go/testdata/script/vendor_import_wrong.txt new file mode 100644 index 0000000..73bf595 --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_import_wrong.txt @@ -0,0 +1,20 @@ +# Wrong import path +env GO111MODULE=off +! go build vend/x/invalid +stderr 'must be imported as foo' + +env GO111MODULE= +cd vend/x/invalid +! go build vend/x/invalid +stderr 'must be imported as foo' + +-- vend/x/invalid/go.mod -- +module vend/x/invalid + +go 1.16 + +-- vend/x/invalid/invalid.go -- +package invalid + +import "vend/x/invalid/vendor/foo" + diff --git a/src/cmd/go/testdata/script/vendor_internal.txt b/src/cmd/go/testdata/script/vendor_internal.txt new file mode 100644 index 0000000..4c0f1fa --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_internal.txt @@ -0,0 +1,16 @@ +go build ./vendor/foo.com/internal/bar/a + +-- go.mod -- +module example.com/x +go 1.19 + +require "foo.com/internal/bar" v1.0.0 +-- vendor/modules.txt -- +# foo.com/internal/bar v1.0.0 +## explicit +foo.com/internal/bar/a +-- vendor/foo.com/internal/bar/a/a.go -- +package a +import _ "foo.com/internal/bar/b" +-- vendor/foo.com/internal/bar/b/b.go -- +package b
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/vendor_issue12156.txt b/src/cmd/go/testdata/script/vendor_issue12156.txt new file mode 100644 index 0000000..ac95c6d --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_issue12156.txt @@ -0,0 +1,16 @@ +# Tests issue #12156, a former index out of range panic. + +env GO111MODULE=off +env GOPATH=$WORK/gopath/src/testvendor2 # vendor/x is directly in $GOPATH, not in $GOPATH/src +cd $WORK/gopath/src/testvendor2/src/p + +! go build p.go +! stderr panic # Make sure it doesn't panic +stderr 'cannot find package "x"' + +-- testvendor2/src/p/p.go -- +package p + +import "x" +-- testvendor2/vendor/x/x.go -- +package x diff --git a/src/cmd/go/testdata/script/vendor_list_issue11977.txt b/src/cmd/go/testdata/script/vendor_list_issue11977.txt new file mode 100644 index 0000000..f1ed613 --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_list_issue11977.txt @@ -0,0 +1,87 @@ +env GO111MODULE=off + +go list -f '{{join .TestImports "\n"}}' github.com/rsc/go-get-issue-11864/t +stdout 'go-get-issue-11864/vendor/vendor.org/p' + +go list -f '{{join .XTestImports "\n"}}' github.com/rsc/go-get-issue-11864/tx +stdout 'go-get-issue-11864/vendor/vendor.org/p' + +go list -f '{{join .XTestImports "\n"}}' github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2 +stdout 'go-get-issue-11864/vendor/vendor.org/tx2' + +go list -f '{{join .XTestImports "\n"}}' github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3 +stdout 'go-get-issue-11864/vendor/vendor.org/tx3' + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/m.go -- +package g + +import _ "vendor.org/p" +import _ "vendor.org/p1" + +func main() {} + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/t/t_test.go -- +package t + +import _ "vendor.org/p" +import _ "vendor.org/p1" +import "testing" + +func TestNop(t *testing.T) {} + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/t/t.go -- +package t + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/tx/tx_test.go -- +package tx_test + +import _ "vendor.org/p" +import _ "vendor.org/p1" +import "testing" + +func TestNop(t *testing.T) {} + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/tx/tx.go -- +package tx + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/p1/p1.go -- +package p1 // import "vendor.org/p1" + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3/tx3_test.go -- +package tx3_test + +import "vendor.org/tx3" +import "testing" + +var Found = tx3.Exported + +func TestNop(t *testing.T) {} + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3/export_test.go -- +package tx3 + +var Exported = true + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3/tx3.go -- +package tx3 + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2/tx2_test.go -- +package tx2_test + +import . "vendor.org/tx2" +import "testing" + +var Found = Exported + +func TestNop(t *testing.T) {} + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2/export_test.go -- +package tx2 + +var Exported = true + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2/tx2.go -- +package tx2 + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/p/p.go -- +package p diff --git a/src/cmd/go/testdata/script/vendor_outside_module.txt b/src/cmd/go/testdata/script/vendor_outside_module.txt new file mode 100644 index 0000000..3ad4579 --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_outside_module.txt @@ -0,0 +1,36 @@ +# baz.go (importing just fmt) works with -mod=mod, -mod=vendor. +go build -x -mod=mod my-module/vendor/example.com/another-module/foo/bar/baz.go +go build -x -mod=readonly my-module/vendor/example.com/another-module/foo/bar/baz.go +go build -x -mod=vendor my-module/vendor/example.com/another-module/foo/bar/baz.go + +# baz_with_outside_dep.go (with a non-std dependency) works with -mod=mod +# but not with -mod=readonly and -mod=vendor. +go build -x -mod=mod my-module/vendor/example.com/another-module/foo/bar/baz_with_outside_dep.go +! go build -x -mod=readonly my-module/vendor/example.com/another-module/foo/bar/baz_with_outside_dep.go +stderr 'no required module provides package rsc.io/quote' +! go build -x -mod=vendor my-module/vendor/example.com/another-module/foo/bar/baz_with_outside_dep.go +stderr 'no required module provides package rsc.io/quote' + +-- my-module/go.mod -- +module example.com/my-module + +go 1.20 +-- my-module/vendor/example.com/another-module/foo/bar/baz.go -- +package main + +import "fmt" + +func main() { + fmt.Println("hello, world.") +} +-- my-module/vendor/example.com/another-module/foo/bar/baz_with_outside_dep.go -- +package main + +import ( + "fmt" + "rsc.io/quote" +) + +func main() { + fmt.Println(quote.Hello()) +} diff --git a/src/cmd/go/testdata/script/vendor_resolve.txt b/src/cmd/go/testdata/script/vendor_resolve.txt new file mode 100644 index 0000000..bc8cf0a --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_resolve.txt @@ -0,0 +1,21 @@ +env GO111MODULE=off +! go build p +stderr 'must be imported as x' + +-- p/p.go -- +package p + +import ( + _ "q/y" + _ "q/z" +) +-- q/vendor/x/x.go -- +package x +-- q/y/y.go -- +package y + +import _ "x" +-- q/z/z.go -- +package z + +import _ "q/vendor/x" diff --git a/src/cmd/go/testdata/script/vendor_test_issue11864.txt b/src/cmd/go/testdata/script/vendor_test_issue11864.txt new file mode 100644 index 0000000..90c9c59 --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_test_issue11864.txt @@ -0,0 +1,83 @@ +[short] skip +env GO111MODULE=off + +# test should work too +go test github.com/rsc/go-get-issue-11864 +go test github.com/rsc/go-get-issue-11864/t + +# external tests should observe internal test exports (golang.org/issue/11977) +go test github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2 + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/m.go -- +package g + +import _ "vendor.org/p" +import _ "vendor.org/p1" + +func main() {} + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/t/t_test.go -- +package t + +import _ "vendor.org/p" +import _ "vendor.org/p1" +import "testing" + +func TestNop(t *testing.T) {} + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/t/t.go -- +package t + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/tx/tx_test.go -- +package tx_test + +import _ "vendor.org/p" +import _ "vendor.org/p1" +import "testing" + +func TestNop(t *testing.T) {} + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/tx/tx.go -- +package tx + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/p1/p1.go -- +package p1 // import "vendor.org/p1" + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3/tx3_test.go -- +package tx3_test + +import "vendor.org/tx3" +import "testing" + +var Found = tx3.Exported + +func TestNop(t *testing.T) {} + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3/export_test.go -- +package tx3 + +var Exported = true + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3/tx3.go -- +package tx3 + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2/tx2_test.go -- +package tx2_test + +import . "vendor.org/tx2" +import "testing" + +var Found = Exported + +func TestNop(t *testing.T) {} + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2/export_test.go -- +package tx2 + +var Exported = true + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2/tx2.go -- +package tx2 + +-- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/p/p.go -- +package p diff --git a/src/cmd/go/testdata/script/vendor_test_issue14613.txt b/src/cmd/go/testdata/script/vendor_test_issue14613.txt new file mode 100644 index 0000000..d2f05c9 --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_test_issue14613.txt @@ -0,0 +1,52 @@ +[short] skip +env GO111MODULE=off + +# test folder should work +go test github.com/clsung/go-vendor-issue-14613 + +# test with specified _test.go should work too +cd $GOPATH/src +go test github.com/clsung/go-vendor-issue-14613/vendor_test.go + +# test with imported and not used +! go test github.com/clsung/go-vendor-issue-14613/vendor/mylibtesttest/myapp/myapp_test.go +stderr 'imported and not used' + +-- $GOPATH/src/github.com/clsung/go-vendor-issue-14613/./vendor_test.go -- +package main + +import ( + "testing" + + "github.com/clsung/fake" +) + +func TestVendor(t *testing.T) { + ret := fake.DoNothing() + expected := "Ok" + if expected != ret { + t.Errorf("fake returned %q, expected %q", ret, expected) + } +} + +-- $GOPATH/src/github.com/clsung/go-vendor-issue-14613/./vendor/mylibtesttest/myapp/myapp_test.go -- +package myapp +import ( + "mylibtesttest/rds" +) + +-- $GOPATH/src/github.com/clsung/go-vendor-issue-14613/./vendor/mylibtesttest/rds/rds.go -- +package rds + +-- $GOPATH/src/github.com/clsung/go-vendor-issue-14613/./vendor/github.com/clsung/fake/fake.go -- +package fake + +func DoNothing() string { + return "Ok" +} + +-- $GOPATH/src/github.com/clsung/go-vendor-issue-14613/./m.go -- +package main + +func main() {} + diff --git a/src/cmd/go/testdata/script/version.txt b/src/cmd/go/testdata/script/version.txt new file mode 100644 index 0000000..0a2ac1e --- /dev/null +++ b/src/cmd/go/testdata/script/version.txt @@ -0,0 +1,92 @@ +# Without arguments, we just print Go's own version. +go version +stdout '^go version' + +# Flags without files, or paths to missing files, should error. +! go version missing.exe +! go version -m +stderr 'with arguments' +! go version -v +stderr 'with arguments' + +# Check that 'go version' succeed even when it does not contain Go build info. +# It should print an error if the file has a known Go binary extension. +# +go version empty.txt +! stdout . +! stderr . +go version empty.exe +stderr 'could not read Go build info' +go version empty.so +stderr 'could not read Go build info' +go version empty.dll +stderr 'could not read Go build info' + +# Neither of the two flags above should be an issue via GOFLAGS. +env GOFLAGS='-m -v' +go version +stdout '^go version' +env GOFLAGS= + +env GO111MODULE=on + +# Check that very basic version lookup succeeds. +go build empty.go +go version empty$GOEXE +[cgo] go build -ldflags=-linkmode=external empty.go +[cgo] go version empty$GOEXE + +# Skip the remaining builds if we are running in short mode. +[short] skip + +# Check that 'go version' and 'go version -m' work on a binary built in module mode. +go get rsc.io/fortune +go build -o fortune.exe rsc.io/fortune +go version fortune.exe +stdout '^fortune.exe: .+' +go version -m fortune.exe +stdout -buildmode=exe +stdout '^\tpath\trsc.io/fortune' +stdout '^\tmod\trsc.io/fortune\tv1.0.0' + +# Check the build info of a binary built from $GOROOT/src/cmd +go build -o test2json.exe cmd/test2json +go version -m test2json.exe +stdout -buildmode=exe +stdout '^test2json.exe: .+' +stdout '^\tpath\tcmd/test2json$' +! stdout 'mod[^e]' + +# Repeat the test with -buildmode=pie. +[!buildmode:pie] stop +go build -buildmode=pie -o external.exe rsc.io/fortune +go version external.exe +stdout '^external.exe: .+' +go version -m external.exe +stdout -buildmode=pie +stdout '^\tpath\trsc.io/fortune' +stdout '^\tmod\trsc.io/fortune\tv1.0.0' + +# Also test PIE with internal linking. +# currently only supported on linux/amd64, linux/arm64 and windows/amd64. +[!GOOS:linux] [!GOOS:windows] stop +[!GOARCH:amd64] [!GOARCH:arm64] stop +go build -buildmode=pie -ldflags=-linkmode=internal -o internal.exe rsc.io/fortune +go version internal.exe +stdout '^internal.exe: .+' +go version -m internal.exe +stdout -buildmode=pie +stdout '^\tpath\trsc.io/fortune' +stdout '^\tmod\trsc.io/fortune\tv1.0.0' + +-- go.mod -- +module m + +-- empty.go -- +package main +func main(){} + +-- empty.txt -- +-- empty.exe -- +-- empty.so -- +-- empty.dll -- diff --git a/src/cmd/go/testdata/script/version_build_settings.txt b/src/cmd/go/testdata/script/version_build_settings.txt new file mode 100644 index 0000000..cd3f5cf --- /dev/null +++ b/src/cmd/go/testdata/script/version_build_settings.txt @@ -0,0 +1,89 @@ +[short] skip + +# Compiler name is always added. +go build +go version -m m$GOEXE +stdout '^\tbuild\t-compiler=gc$' +stdout '^\tbuild\tGOOS=' +stdout '^\tbuild\tGOARCH=' +[GOARCH:amd64] stdout '^\tbuild\tGOAMD64=' +! stdout asmflags|gcflags|ldflags|gccgoflags + +# Toolchain flags are added if present. +# The raw flags are included, with package patterns if specified. +go build -asmflags=example.com/m=-D=FOO=bar +go version -m m$GOEXE +stdout '^\tbuild\t-asmflags=example\.com/m=-D=FOO=bar$' + +go build -gcflags=example.com/m=-N +go version -m m$GOEXE +stdout '^\tbuild\t-gcflags=example\.com/m=-N$' + +go build -ldflags=example.com/m=-w +go version -m m$GOEXE +stdout '^\tbuild\t-ldflags=example\.com/m=-w$' + +go build -trimpath +go version -m m$GOEXE +stdout '\tbuild\t-trimpath=true$' + +# gccgoflags are not added when gc is used, and vice versa. +# TODO: test gccgo. +go build -gccgoflags=all=UNUSED +go version -m m$GOEXE +! stdout gccgoflags + +# Build and tool tags are added but not release tags. +# "race" is included with build tags but not "cgo". +go build -tags=a,b +go version -m m$GOEXE +stdout '^\tbuild\t-tags=a,b$' +[race] go build -race +[race] go version -m m$GOEXE +[race] ! stdout '^\tbuild\t-tags=' +[race] stdout '^\tbuild\t-race=true$' + +# CGO flags are separate settings. +# CGO_ENABLED is always present. +# Other flags are added if CGO_ENABLED is true. +env CGO_ENABLED=0 +go build +go version -m m$GOEXE +stdout '^\tbuild\tCGO_ENABLED=0$' +! stdout CGO_CPPFLAGS|CGO_CFLAGS|CGO_CXXFLAGS|CGO_LDFLAGS + +[cgo] env CGO_ENABLED=1 +[cgo] env CGO_CPPFLAGS=-DFROM_CPPFLAGS=1 +[cgo] env CGO_CFLAGS=-DFROM_CFLAGS=1 +[cgo] env CGO_CXXFLAGS=-DFROM_CXXFLAGS=1 +[cgo] env CGO_LDFLAGS=-L/extra/dir/does/not/exist +[cgo] go build '-ldflags=all=-linkmode=external -extldflags=-L/bonus/dir/does/not/exist' +[cgo] go version -m m$GOEXE +[cgo] stdout '^\tbuild\t-ldflags="all=-linkmode=external -extldflags=-L/bonus/dir/does/not/exist"$' +[cgo] stdout '^\tbuild\tCGO_ENABLED=1$' +[cgo] stdout '^\tbuild\tCGO_CPPFLAGS=-DFROM_CPPFLAGS=1$' +[cgo] stdout '^\tbuild\tCGO_CFLAGS=-DFROM_CFLAGS=1$' +[cgo] stdout '^\tbuild\tCGO_CXXFLAGS=-DFROM_CXXFLAGS=1$' +[cgo] stdout '^\tbuild\tCGO_LDFLAGS=-L/extra/dir/does/not/exist$' + +# https://go.dev/issue/52372: a cgo-enabled binary should not be stamped with +# CGO_ flags that contain paths. +[cgo] env CGO_ENABLED=1 +[cgo] env CGO_CPPFLAGS=-DFROM_CPPFLAGS=1 +[cgo] env CGO_CFLAGS=-DFROM_CFLAGS=1 +[cgo] env CGO_CXXFLAGS=-DFROM_CXXFLAGS=1 +[cgo] env CGO_LDFLAGS=-L/extra/dir/does/not/exist +[cgo] go build -trimpath '-ldflags=all=-linkmode=external -extldflags=-L/bonus/dir/does/not/exist' +[cgo] go version -m m$GOEXE +[cgo] ! stdout '/extra/dir/does/not/exist' +[cgo] ! stdout '/bonus/dir/does/not/exist' +[cgo] stdout '^\tbuild\tCGO_ENABLED=1$' + +-- go.mod -- +module example.com/m + +go 1.18 +-- m.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/version_buildvcs_bzr.txt b/src/cmd/go/testdata/script/version_buildvcs_bzr.txt new file mode 100644 index 0000000..85db9ba --- /dev/null +++ b/src/cmd/go/testdata/script/version_buildvcs_bzr.txt @@ -0,0 +1,107 @@ +# This test checks that VCS information is stamped into Go binaries by default, +# controlled with -buildvcs. This test focuses on Bazaar specifics. +# The Git test covers common functionality. + +[!exec:bzr] skip +[short] skip +env GOBIN=$WORK/gopath/bin +env oldpath=$PATH +env HOME=$WORK +cd repo/a +exec bzr whoami 'J.R. Gopher <gopher@golang.org>' + +# If there's no local repository, there's no VCS info. +go install +go version -m $GOBIN/a$GOEXE +! stdout bzrrevision +rm $GOBIN/a$GOEXE + +# If there is a repository, but it can't be used for some reason, +# there should be an error. It should hint about -buildvcs=false. +cd .. +mkdir .bzr +env PATH=$WORK${/}fakebin${:}$oldpath +chmod 0755 $WORK/fakebin/bzr +! exec bzr help +cd a +! go install +stderr '^error obtaining VCS status: exit status 1\n\tUse -buildvcs=false to disable VCS stamping.$' +rm $GOBIN/a$GOEXE +cd .. +env PATH=$oldpath +rm .bzr + +# If there is an empty repository in a parent directory, only "modified" is tagged. +exec bzr init +cd a +go install +go version -m $GOBIN/a$GOEXE +stdout '^\tbuild\tvcs=bzr$' +! stdout vcs.revision +! stdout vcs.time +stdout '^\tbuild\tvcs.modified=true$' +cd .. + +# Revision and commit time are tagged for repositories with commits. +exec bzr add a README +exec bzr commit -m 'initial commit' +cd a +go install +go version -m $GOBIN/a$GOEXE +stdout '^\tbuild\tvcs=bzr$' +stdout '^\tbuild\tvcs.revision=' +stdout '^\tbuild\tvcs.time=' +stdout '^\tbuild\tvcs.modified=false$' +rm $GOBIN/a$GOEXE + +# Building an earlier commit should still build clean. +cp ../../outside/empty.txt ../NEWS +exec bzr add ../NEWS +exec bzr commit -m 'add NEWS' +exec bzr update -r1 +go install +go version -m $GOBIN/a$GOEXE +stdout '^\tbuild\tvcs=bzr$' +stdout '^\tbuild\tvcs.revision=' +stdout '^\tbuild\tvcs.time=' +stdout '^\tbuild\tvcs.modified=false$' + +# Building with -buildvcs=false suppresses the info. +go install -buildvcs=false +go version -m $GOBIN/a$GOEXE +! stdout vcs.revision +rm $GOBIN/a$GOEXE + +# An untracked file is shown as modified, even if it isn't part of the build. +cp ../../outside/empty.txt . +go install +go version -m $GOBIN/a$GOEXE +stdout '^\tbuild\tvcs.modified=true$' +rm empty.txt +rm $GOBIN/a$GOEXE + +# An edited file is shown as modified, even if it isn't part of the build. +cp ../../outside/empty.txt ../README +go install +go version -m $GOBIN/a$GOEXE +stdout '^\tbuild\tvcs.modified=true$' +exec bzr revert ../README +rm $GOBIN/a$GOEXE + +-- $WORK/fakebin/bzr -- +#!/bin/sh +exit 1 +-- $WORK/fakebin/bzr.bat -- +exit 1 +-- repo/README -- +Far out in the uncharted backwaters of the unfashionable end of the western +spiral arm of the Galaxy lies a small, unregarded yellow sun. +-- repo/a/go.mod -- +module example.com/a + +go 1.18 +-- repo/a/a.go -- +package main + +func main() {} +-- outside/empty.txt -- diff --git a/src/cmd/go/testdata/script/version_buildvcs_fossil.txt b/src/cmd/go/testdata/script/version_buildvcs_fossil.txt new file mode 100644 index 0000000..bd6b89d --- /dev/null +++ b/src/cmd/go/testdata/script/version_buildvcs_fossil.txt @@ -0,0 +1,94 @@ +# This test checks that VCS information is stamped into Go binaries by default, +# controlled with -buildvcs. This test focuses on Fossil specifics. +# The Git test covers common functionality. + +# "fossil" is the Fossil file server on Plan 9. +[GOOS:plan9] skip +[!exec:fossil] skip +[short] skip +env GOBIN=$WORK/gopath/bin +env oldpath=$PATH +env HOME=$WORK +env USER=gopher +[!GOOS:windows] env fslckout=.fslckout +[GOOS:windows] env fslckout=_FOSSIL_ +exec pwd +exec fossil init repo.fossil +cd repo/a + +# If there's no local repository, there's no VCS info. +go install +go version -m $GOBIN/a$GOEXE +! stdout vcs.revision +rm $GOBIN/a$GOEXE + +# If there is a repository, but it can't be used for some reason, +# there should be an error. It should hint about -buildvcs=false. +cd .. +mv fslckout $fslckout +env PATH=$WORK${/}fakebin${:}$oldpath +chmod 0755 $WORK/fakebin/fossil +! exec fossil help +cd a +! go install +stderr '^error obtaining VCS status: exit status 1\n\tUse -buildvcs=false to disable VCS stamping.$' +rm $GOBIN/a$GOEXE +cd .. +env PATH=$oldpath +rm $fslckout + +# Revision and commit time are tagged for repositories with commits. +exec fossil open ../repo.fossil -f +exec fossil add a README +exec fossil commit -m 'initial commit' +cd a +go install +go version -m $GOBIN/a$GOEXE +stdout '^\tbuild\tvcs=fossil\n' +stdout '^\tbuild\tvcs.revision=' +stdout '^\tbuild\tvcs.time=' +stdout '^\tbuild\tvcs.modified=false$' +rm $GOBIN/a$GOEXE + +# Building with -buildvcs=false suppresses the info. +go install -buildvcs=false +go version -m $GOBIN/a$GOEXE +! stdout vcs.revision +rm $GOBIN/a$GOEXE + +# An untracked file is shown as modified, even if it isn't part of the build. +cp ../../outside/empty.txt . +go install +go version -m $GOBIN/a$GOEXE +stdout '^\tbuild\tvcs=fossil\n' +stdout '^\tbuild\tvcs.modified=true$' +rm empty.txt +rm $GOBIN/a$GOEXE + +# An edited file is shown as modified, even if it isn't part of the build. +cp ../../outside/empty.txt ../README +go install +go version -m $GOBIN/a$GOEXE +stdout '^\tbuild\tvcs=fossil\n' +stdout '^\tbuild\tvcs.modified=true$' +exec fossil revert ../README +rm $GOBIN/a$GOEXE + +-- $WORK/fakebin/fossil -- +#!/bin/sh +exit 1 +-- $WORK/fakebin/fossil.bat -- +exit 1 +-- repo/README -- +Far out in the uncharted backwaters of the unfashionable end of the western +spiral arm of the Galaxy lies a small, unregarded yellow sun. +-- repo/fslckout -- +-- repo/a/go.mod -- +module example.com/a + +go 1.18 +-- repo/a/a.go -- +package main + +func main() {} +-- outside/empty.txt -- diff --git a/src/cmd/go/testdata/script/version_buildvcs_git.txt b/src/cmd/go/testdata/script/version_buildvcs_git.txt new file mode 100644 index 0000000..680e492 --- /dev/null +++ b/src/cmd/go/testdata/script/version_buildvcs_git.txt @@ -0,0 +1,182 @@ +# This test checks that VCS information is stamped into Go binaries by default, +# controlled with -buildvcs. This test focuses on Git. Other tests focus on +# other VCS tools but may not cover common functionality. + +[!git] skip +[short] skip +env GOBIN=$WORK/gopath/bin +env oldpath=$PATH +cd repo/a + +# If there's no local repository, there's no VCS info. +go install +go version -m $GOBIN/a$GOEXE +! stdout vcs.revision +rm $GOBIN/a$GOEXE + +# If there's an orphan .git file left by a git submodule, it's not a git +# repository, and there's no VCS info. +cd ../gitsubmodule +go install +go version -m $GOBIN/gitsubmodule$GOEXE +! stdout vcs.revision +rm $GOBIN/gitsubmodule$GOEXE + +# If there is a repository, but it can't be used for some reason, +# there should be an error. It should hint about -buildvcs=false. +# Also ensure that multiple errors are collected by "go list -e". +cd .. +mkdir .git +env PATH=$WORK${/}fakebin${:}$oldpath +chmod 0755 $WORK/fakebin/git +! exec git help +cd a +! go install +stderr '^error obtaining VCS status: exit status 1\n\tUse -buildvcs=false to disable VCS stamping.$' +go list -e -f '{{.ImportPath}}: {{.Error}}' ./... +stdout -count=1 '^example\.com/a: error obtaining VCS status' +stdout -count=1 '^example\.com/a/library: <nil>' +stdout -count=1 '^example\.com/a/othermain: error obtaining VCS status' +cd .. +env PATH=$oldpath +rm .git + +# If there is an empty repository in a parent directory, only "uncommitted" is tagged. +exec git init +exec git config user.email gopher@golang.org +exec git config user.name 'J.R. Gopher' +cd a +go install +go version -m $GOBIN/a$GOEXE +stdout '^\tbuild\tvcs=git$' +stdout '^\tbuild\tvcs.modified=true$' +! stdout vcs.revision +! stdout vcs.time +rm $GOBIN/a$GOEXE + +# Revision and commit time are tagged for repositories with commits. +exec git add -A +exec git commit -m 'initial commit' +go install +go version -m $GOBIN/a$GOEXE +stdout '^\tbuild\tvcs.revision=' +stdout '^\tbuild\tvcs.time=' +stdout '^\tbuild\tvcs.modified=false$' +rm $GOBIN/a$GOEXE + +# Building with -buildvcs=false suppresses the info. +go install -buildvcs=false +go version -m $GOBIN/a$GOEXE +! stdout vcs.revision +rm $GOBIN/a$GOEXE + +# An untracked file is shown as uncommitted, even if it isn't part of the build. +cp ../../outside/empty.txt . +go install +go version -m $GOBIN/a$GOEXE +stdout '^\tbuild\tvcs.modified=true$' +rm empty.txt +rm $GOBIN/a$GOEXE + +# An edited file is shown as uncommitted, even if it isn't part of the build. +cp ../../outside/empty.txt ../README +go install +go version -m $GOBIN/a$GOEXE +stdout '^\tbuild\tvcs.modified=true$' +exec git checkout ../README +rm $GOBIN/a$GOEXE + +# If the build doesn't include any packages from the repository, +# there should be no VCS info. +go install example.com/cmd/a@v1.0.0 +go version -m $GOBIN/a$GOEXE +! stdout vcs.revision +rm $GOBIN/a$GOEXE + +go mod edit -require=example.com/c@v0.0.0 +go mod edit -replace=example.com/c@v0.0.0=../../outside/c +go install example.com/c +go version -m $GOBIN/c$GOEXE +! stdout vcs.revision +rm $GOBIN/c$GOEXE +exec git checkout go.mod + +# If the build depends on a package in the repository, but it's not in the +# main module, there should be no VCS info. +go mod edit -require=example.com/b@v0.0.0 +go mod edit -replace=example.com/b@v0.0.0=../b +go mod edit -require=example.com/d@v0.0.0 +go mod edit -replace=example.com/d@v0.0.0=../../outside/d +go install example.com/d +go version -m $GOBIN/d$GOEXE +! stdout vcs.revision +exec git checkout go.mod +rm $GOBIN/d$GOEXE + +# If we're loading multiple main packages, +# but they share the same VCS repository, +# we only need to execute VCS status commands once. +go list -x ./... +stdout -count=3 '^example.com' +stderr -count=1 '^git status' +stderr -count=1 '^git -c log.showsignature=false show' + +-- $WORK/fakebin/git -- +#!/bin/sh +exit 1 +-- $WORK/fakebin/git.bat -- +exit 1 +-- repo/README -- +Far out in the uncharted backwaters of the unfashionable end of the western +spiral arm of the Galaxy lies a small, unregarded yellow sun. +-- repo/a/go.mod -- +module example.com/a + +go 1.18 +-- repo/a/a.go -- +package main + +func main() {} +-- repo/a/library/f.go -- +package library +-- repo/a/othermain/f.go -- +package main + +func main() {} +-- repo/b/go.mod -- +module example.com/b + +go 1.18 +-- repo/b/b.go -- +package b +-- repo/gitsubmodule/.git -- +gitdir: ../.git/modules/gitsubmodule +-- repo/gitsubmodule/go.mod -- +module example.com/gitsubmodule + +go 1.18 +-- repo/gitsubmodule/main.go -- +package main + +func main() {} +-- outside/empty.txt -- +-- outside/c/go.mod -- +module example.com/c + +go 1.18 +-- outside/c/main.go -- +package main + +func main() {} +-- outside/d/go.mod -- +module example.com/d + +go 1.18 + +require example.com/b v0.0.0 +-- outside/d/main.go -- +package main + +import _ "example.com/b" + +func main() {} diff --git a/src/cmd/go/testdata/script/version_buildvcs_hg.txt b/src/cmd/go/testdata/script/version_buildvcs_hg.txt new file mode 100644 index 0000000..fbbd886 --- /dev/null +++ b/src/cmd/go/testdata/script/version_buildvcs_hg.txt @@ -0,0 +1,91 @@ +# This test checks that VCS information is stamped into Go binaries by default, +# controlled with -buildvcs. This test focuses on Mercurial specifics. +# The Git test covers common functionality. + +[!exec:hg] skip +[short] skip +env GOBIN=$WORK/gopath/bin +env oldpath=$PATH +cd repo/a + +# If there's no local repository, there's no VCS info. +go install +go version -m $GOBIN/a$GOEXE +! stdout hgrevision +rm $GOBIN/a$GOEXE + +# If there is a repository, but it can't be used for some reason, +# there should be an error. It should hint about -buildvcs=false. +cd .. +mkdir .hg +env PATH=$WORK${/}fakebin${:}$oldpath +chmod 0755 $WORK/fakebin/hg +! exec hg help +cd a +! go install +stderr '^error obtaining VCS status: exit status 1\n\tUse -buildvcs=false to disable VCS stamping.$' +rm $GOBIN/a$GOEXE +cd .. +env PATH=$oldpath +rm .hg + +# If there is an empty repository in a parent directory, only "uncommitted" is tagged. +exec hg init +cd a +go install +go version -m $GOBIN/a$GOEXE +! stdout vcs.revision +! stdout vcs.time +stdout '^\tbuild\tvcs.modified=true$' +cd .. + +# Revision and commit time are tagged for repositories with commits. +exec hg add a README +exec hg commit -m 'initial commit' +cd a +go install +go version -m $GOBIN/a$GOEXE +stdout '^\tbuild\tvcs.revision=' +stdout '^\tbuild\tvcs.time=' +stdout '^\tbuild\tvcs.modified=false$' +rm $GOBIN/a$GOEXE + +# Building with -buildvcs=false suppresses the info. +go install -buildvcs=false +go version -m $GOBIN/a$GOEXE +! stdout hgrevision +rm $GOBIN/a$GOEXE + +# An untracked file is shown as uncommitted, even if it isn't part of the build. +cp ../../outside/empty.txt . +go install +go version -m $GOBIN/a$GOEXE +stdout '^\tbuild\tvcs.modified=true$' +rm empty.txt +rm $GOBIN/a$GOEXE + +# An edited file is shown as uncommitted, even if it isn't part of the build. +cp ../../outside/empty.txt ../README +go install +go version -m $GOBIN/a$GOEXE +stdout '^\tbuild\tvcs.modified=true$' +exec hg revert ../README +rm $GOBIN/a$GOEXE + +-- $WORK/fakebin/hg -- +#!/bin/sh +exit 1 +-- $WORK/fakebin/hg.bat -- +exit 1 +-- repo/README -- +Far out in the uncharted backwaters of the unfashionable end of the western +spiral arm of the Galaxy lies a small, unregarded yellow sun. +-- repo/a/go.mod -- +module example.com/a + +go 1.18 +-- repo/a/a.go -- +package main + +func main() {} +-- outside/empty.txt -- diff --git a/src/cmd/go/testdata/script/version_buildvcs_nested.txt b/src/cmd/go/testdata/script/version_buildvcs_nested.txt new file mode 100644 index 0000000..6dab847 --- /dev/null +++ b/src/cmd/go/testdata/script/version_buildvcs_nested.txt @@ -0,0 +1,51 @@ +[!git] skip +[!exec:hg] skip +[short] skip +env GOFLAGS='-n -buildvcs' + +# Create a root module in a root Git repository. +mkdir root +cd root +go mod init example.com/root +exec git init + +# Nesting repositories in parent directories are ignored, as the current +# directory main package, and containing main module are in the same repository. +# This is an error in GOPATH mode (to prevent VCS injection), but for modules, +# we assume users have control over repositories they've checked out. +mkdir hgsub +cd hgsub +exec hg init +cp ../../main.go main.go +! go build +stderr '^error obtaining VCS status: main module is in repository ".*root" but current directory is in repository ".*hgsub"$' +stderr '^\tUse -buildvcs=false to disable VCS stamping.$' +go build -buildvcs=false +go mod init example.com/root/hgsub +go build +cd .. + +# It's an error to build a package from a nested Git repository if the package +# is in a separate repository from the current directory or from the module +# root directory. +mkdir gitsub +cd gitsub +exec git init +exec git config user.name 'J.R.Gopher' +exec git config user.email 'gopher@golang.org' +cp ../../main.go main.go +! go build +stderr '^error obtaining VCS status: main module is in repository ".*root" but current directory is in repository ".*gitsub"$' +go build -buildvcs=false +go mod init example.com/root/gitsub +exec git commit --allow-empty -m empty # status commands fail without this +go build +rm go.mod +cd .. +! go build ./gitsub +stderr '^error obtaining VCS status: main package is in repository ".*gitsub" but current directory is in repository ".*root"$' +go build -buildvcs=false -o=gitsub${/} ./gitsub + +-- main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/version_cshared.txt b/src/cmd/go/testdata/script/version_cshared.txt new file mode 100644 index 0000000..29e21fc --- /dev/null +++ b/src/cmd/go/testdata/script/version_cshared.txt @@ -0,0 +1,19 @@ +[short] skip +[!buildmode:c-shared] stop + +env GO111MODULE=on + +go get rsc.io/fortune +go build -buildmode=c-shared -o external.so rsc.io/fortune +go version external.so +stdout '^external.so: .+' +go version -m external.so +stdout '^\tpath\trsc.io/fortune' +stdout '^\tmod\trsc.io/fortune\tv1.0.0' + +-- go.mod -- +module m + +-- empty.go -- +package main +func main(){} diff --git a/src/cmd/go/testdata/script/version_gc_sections.txt b/src/cmd/go/testdata/script/version_gc_sections.txt new file mode 100644 index 0000000..4bda23b --- /dev/null +++ b/src/cmd/go/testdata/script/version_gc_sections.txt @@ -0,0 +1,24 @@ +# This test checks that external linking with --gc-sections does not strip version information. + +[short] skip +[!cgo] skip +[GOOS:aix] skip # no --gc-sections +[GOOS:darwin] skip # no --gc-sections + +go build -ldflags='-linkmode=external -extldflags=-Wl,--gc-sections' +go version hello$GOEXE +! stdout 'not a Go executable' +! stderr 'not a Go executable' + +-- go.mod -- +module hello +-- hello.go -- +package main + +/* +*/ +import "C" + +func main() { + println("hello") +} diff --git a/src/cmd/go/testdata/script/version_goexperiment.txt b/src/cmd/go/testdata/script/version_goexperiment.txt new file mode 100644 index 0000000..4b165eb --- /dev/null +++ b/src/cmd/go/testdata/script/version_goexperiment.txt @@ -0,0 +1,16 @@ +# Test that experiments appear in "go version <binary>" + +# This test requires rebuilding the runtime, which takes a while. +[short] skip + +env GOEXPERIMENT=fieldtrack +go build -o main$GOEXE version.go +go version main$GOEXE +stdout 'X:fieldtrack$' +exec ./main$GOEXE +stderr 'X:fieldtrack$' + +-- version.go -- +package main +import "runtime" +func main() { println(runtime.Version()) } diff --git a/src/cmd/go/testdata/script/version_replace.txt b/src/cmd/go/testdata/script/version_replace.txt new file mode 100644 index 0000000..82b8504 --- /dev/null +++ b/src/cmd/go/testdata/script/version_replace.txt @@ -0,0 +1,33 @@ +[short] skip + +go mod download example.com/printversion@v0.1.0 example.com/printversion@v1.0.0 +go get example.com/printversion@v0.1.0 +go install example.com/printversion + +go run example.com/printversion +cmp stdout out.txt + +go version -m $GOPATH/bin/printversion$GOEXE +stdout '^.*[/\\]bin[/\\]printversion'$GOEXE': .*$' +stdout '^ path example.com/printversion$' +stdout '^ mod example.com/printversion v0.1.0$' +stdout '^ => example.com/printversion v1.0.0 h1:.*$' +stdout '^ dep example.com/version v1.0.0$' +stdout '^ => example.com/version v1.0.1 h1:.*$' + +-- go.mod -- +module golang.org/issue/37392 +go 1.14 +require ( + example.com/printversion v0.1.0 +) +replace ( + example.com/printversion => example.com/printversion v1.0.0 + example.com/version v1.0.0 => example.com/version v1.0.1 +) +-- out.txt -- +path is example.com/printversion +main is example.com/printversion v0.1.0 + (replaced by example.com/printversion v1.0.0) +using example.com/version v1.0.0 + (replaced by example.com/version v1.0.1) diff --git a/src/cmd/go/testdata/script/vet.txt b/src/cmd/go/testdata/script/vet.txt new file mode 100644 index 0000000..6573ae3 --- /dev/null +++ b/src/cmd/go/testdata/script/vet.txt @@ -0,0 +1,62 @@ +# Package with external tests +! go vet m/vetpkg +stderr 'Printf' + +# With tags +! go vet -tags tagtest m/vetpkg +stderr 'c\.go.*Printf' + +# With flags on +! go vet -printf m/vetpkg +stderr 'Printf' + +# With flags off +go vet -printf=false m/vetpkg +! stderr . + +# With only test files (tests issue #23395) +go vet m/onlytest +! stderr . + +# With only cgo files (tests issue #24193) +[!cgo] skip +[short] skip +go vet m/onlycgo +! stderr . + +-- go.mod -- +module m + +go 1.16 +-- vetpkg/a_test.go -- +package p_test +-- vetpkg/b.go -- +package p + +import "fmt" + +func f() { + fmt.Printf("%d") +} +-- vetpkg/c.go -- +// +build tagtest + +package p + +import "fmt" + +func g() { + fmt.Printf("%d", 3, 4) +} +-- onlytest/p_test.go -- +package p + +import "testing" + +func TestMe(*testing.T) {} +-- onlycgo/p.go -- +package p + +import "C" + +func F() {} diff --git a/src/cmd/go/testdata/script/vet_asm.txt b/src/cmd/go/testdata/script/vet_asm.txt new file mode 100644 index 0000000..ae2db97 --- /dev/null +++ b/src/cmd/go/testdata/script/vet_asm.txt @@ -0,0 +1,32 @@ +env GO111MODULE=off + +# Issue 27665. Verify that "go vet" analyzes non-Go files. + +[!GOARCH:amd64] skip +! go vet -asmdecl a +stderr 'f: invalid MOVW of x' + +# -c flag shows context +! go vet -c=2 -asmdecl a +stderr '...invalid MOVW...' +stderr '1 .*TEXT' +stderr '2 MOVW' +stderr '3 RET' +stderr '4' + +# -json causes success, even with diagnostics and errors. +go vet -json -asmdecl a +stderr '"a": {' +stderr '"asmdecl":' +stderr '"posn": ".*asm.s:2:1",' +stderr '"message": ".*invalid MOVW.*"' + +-- a/a.go -- +package a + +func f(x int8) + +-- a/asm.s -- +TEXT ·f(SB),0,$0-1 + MOVW x+0(FP), AX + RET diff --git a/src/cmd/go/testdata/script/vet_deps.txt b/src/cmd/go/testdata/script/vet_deps.txt new file mode 100644 index 0000000..b2a8f16 --- /dev/null +++ b/src/cmd/go/testdata/script/vet_deps.txt @@ -0,0 +1,34 @@ +env GO111MODULE=off + +# Issue 30296. Verify that "go vet" uses only immediate dependencies. + +# First run fills the cache. +go vet a + +go vet -x a +! stderr 'transitive' + +-- a/a.go -- +package a + +import "b" + +func F() { + b.F() +} + +-- b/b.go -- +package b + +import "transitive" + +func F() { + transitive.F() +} + +-- transitive/c.go -- +package transitive + +func F() { +} + diff --git a/src/cmd/go/testdata/script/vet_flags.txt b/src/cmd/go/testdata/script/vet_flags.txt new file mode 100644 index 0000000..73f4e41 --- /dev/null +++ b/src/cmd/go/testdata/script/vet_flags.txt @@ -0,0 +1,91 @@ +env GO111MODULE=on + +# Issue 35837: "go vet -<analyzer> <std package>" should use the requested +# analyzers, not the default analyzers for 'go test'. +go vet -n -buildtags=false runtime +stderr '-buildtags=false' +! stderr '-unsafeptr=false' + +# Issue 37030: "go vet <std package>" without other flags should disable the +# unsafeptr check by default. +go vet -n runtime +stderr '-unsafeptr=false' +! stderr '-unreachable=false' + +# However, it should be enabled if requested explicitly. +go vet -n -unsafeptr runtime +stderr '-unsafeptr' +! stderr '-unsafeptr=false' + +# -unreachable is disabled during test but on during plain vet. +go test -n runtime +stderr '-unreachable=false' + +# A flag terminator should be allowed before the package list. +go vet -n -- . + +[short] stop + +# Analyzer flags should be included from GOFLAGS, and should override +# the defaults. +go vet . +env GOFLAGS='-tags=buggy' +! go vet . +stderr 'possible Printf formatting directive' + +# Enabling one analyzer in GOFLAGS should disable the rest implicitly... +env GOFLAGS='-tags=buggy -unsafeptr' +go vet . + +# ...but enabling one on the command line should not disable the analyzers +# enabled via GOFLAGS. +env GOFLAGS='-tags=buggy -printf' +! go vet -unsafeptr +stderr 'possible Printf formatting directive' + +# Analyzer flags don't exist unless we're running 'go vet', +# and we shouldn't run the vet tool to discover them otherwise. +# (Maybe someday we'll hard-code the analyzer flags for the default vet +# tool to make this work, but not right now.) +env GOFLAGS='-unsafeptr' +! go list . +stderr 'go: parsing \$GOFLAGS: unknown flag -unsafeptr' +env GOFLAGS= + +# "go test" on a user package should by default enable an explicit list of analyzers. +go test -n -run=none . +stderr '[/\\]vet'$GOEXE'["]? .* -errorsas .* ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' + +# An explicitly-empty -vet argument should imply the default analyzers. +go test -n -vet= -run=none . +stderr '[/\\]vet'$GOEXE'["]? .* -errorsas .* ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' + +# "go test" on a standard package should by default disable an explicit list. +go test -n -run=none encoding/binary +stderr '[/\\]vet'$GOEXE'["]? -unsafeptr=false -unreachable=false ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' + +go test -n -vet= -run=none encoding/binary +stderr '[/\\]vet'$GOEXE'["]? -unsafeptr=false -unreachable=false ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' + +# Both should allow users to override via the -vet flag. +go test -n -vet=unreachable -run=none . +stderr '[/\\]vet'$GOEXE'["]? -unreachable ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' +go test -n -vet=unreachable -run=none encoding/binary +stderr '[/\\]vet'$GOEXE'["]? -unreachable ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' + +-- go.mod -- +module example.com/x +-- x.go -- +package x +-- x_test.go -- +package x +-- x_tagged.go -- +// +build buggy + +package x + +import "fmt" + +func init() { + fmt.Sprint("%s") // oops! +} diff --git a/src/cmd/go/testdata/script/vet_internal.txt b/src/cmd/go/testdata/script/vet_internal.txt new file mode 100644 index 0000000..85f7093 --- /dev/null +++ b/src/cmd/go/testdata/script/vet_internal.txt @@ -0,0 +1,71 @@ +env GO111MODULE=off + +# Issue 36173. Verify that "go vet" prints line numbers on load errors. + +! go vet a/a.go +stderr '^package command-line-arguments\n\ta[/\\]a.go:5:3: use of internal package' + +! go vet a/a_test.go +stderr '^package command-line-arguments \(test\)\n\ta[/\\]a_test.go:4:3: use of internal package' + +! go vet a +stderr '^package a\n\ta[/\\]a.go:5:3: use of internal package' + +go vet b/b.go +! stderr 'use of internal package' + +! go vet b/b_test.go +stderr '^package command-line-arguments \(test\)\n\tb[/\\]b_test.go:4:3: use of internal package' + +! go vet depends-on-a/depends-on-a.go +stderr '^package command-line-arguments\n\timports a\n\ta[/\\]a.go:5:3: use of internal package' + +! go vet depends-on-a/depends-on-a_test.go +stderr '^package command-line-arguments \(test\)\n\timports a\n\ta[/\\]a.go:5:3: use of internal package a/x/internal/y not allowed' + +! go vet depends-on-a +stderr '^package depends-on-a\n\timports a\n\ta[/\\]a.go:5:3: use of internal package' + +-- a/a.go -- +// A package with bad imports in both src and test +package a + +import ( + _ "a/x/internal/y" +) + +-- a/a_test.go -- +package a + +import ( + _ "a/x/internal/y" +) + +-- b/b.go -- +// A package with a bad import in test only +package b + +-- b/b_test.go -- +package b + +import ( + _ "a/x/internal/y" +) + +-- depends-on-a/depends-on-a.go -- +// A package that depends on a package with a bad import +package depends + +import ( + _ "a" +) + +-- depends-on-a/depends-on-a_test.go -- +package depends + +import ( + _ "a" +) + +-- a/x/internal/y/y.go -- +package y diff --git a/src/cmd/go/testdata/script/work.txt b/src/cmd/go/testdata/script/work.txt new file mode 100644 index 0000000..69391ef --- /dev/null +++ b/src/cmd/go/testdata/script/work.txt @@ -0,0 +1,154 @@ +! go work init doesnotexist +stderr 'go: directory doesnotexist does not exist' +go env GOWORK +! stdout . + +go work init ./a ./b +cmpenv go.work go.work.want +go env GOWORK +stdout '^'$WORK'(\\|/)gopath(\\|/)src(\\|/)go.work$' + +! go run example.com/b +stderr 'a(\\|/)a.go:4:8: no required module provides package rsc.io/quote; to add it:\n\tcd '$WORK(\\|/)gopath(\\|/)src(\\|/)a'\n\tgo get rsc.io/quote' +cd a +go get rsc.io/quote +cat go.mod +go env GOMOD # go env GOMOD reports the module in a single module context +stdout $GOPATH(\\|/)src(\\|/)a(\\|/)go.mod +cd .. +go run example.com/b +stdout 'Hello, world.' + +# And try from a different directory +cd c +go run example.com/b +stdout 'Hello, world.' +cd $GOPATH/src + +go list all # all includes both modules +stdout 'example.com/a' +stdout 'example.com/b' + +# -mod can only be set to readonly in workspace mode +go list -mod=readonly all +! go list -mod=mod all +stderr '^go: -mod may only be set to readonly or vendor when in workspace mode' +env GOWORK=off +go list -mod=mod all +env GOWORK= + +# Test that duplicates in the use list return an error +cp go.work go.work.backup +cp go.work.dup go.work +! go run example.com/b +stderr 'reading go.work: path .* appears multiple times in workspace' +cp go.work.backup go.work + +cp go.work.d go.work +go work use # update go version +go run example.com/d + +# Test that we don't run into "newRequirements called with unsorted roots" +# panic with unsorted main modules. +cp go.work.backwards go.work +go work use # update go version +go run example.com/d + +# Test that command-line-arguments work inside and outside modules. +# This exercises the code that determines which module command-line-arguments +# belongs to. +go list ./b/main.go +env GOWORK=off +go build -n -o foo foo.go +env GOWORK= +go build -n -o foo foo.go + +-- go.work.dup -- +go 1.18 + +use ( + a + b + ../src/a +) +-- go.work.want -- +go $goversion + +use ( + ./a + ./b +) +-- go.work.d -- +go 1.18 + +use ( + a + b + d +) +-- a/go.mod -- + +module example.com/a + +-- a/a.go -- +package a + +import "fmt" +import "rsc.io/quote" + +func HelloFromA() { + fmt.Println(quote.Hello()) +} + +-- b/go.mod -- + +module example.com/b + +-- b/main.go -- +package main + +import "example.com/a" + +func main() { + a.HelloFromA() +} +-- b/lib/hello.go -- +package lib + +import "example.com/a" + +func Hello() { + a.HelloFromA() +} + +-- c/README -- +Create this directory so we can cd to +it and make sure paths are interpreted +relative to the go.work, not the cwd. +-- d/go.mod -- +module example.com/d + +-- d/main.go -- +package main + +import "example.com/b/lib" + +func main() { + lib.Hello() +} + +-- go.work.backwards -- +go 1.18 + +use ( + d + b + a +) + +-- foo.go -- +package main +import "fmt" +func main() { + fmt.Println("Hello, World") +} diff --git a/src/cmd/go/testdata/script/work_build_no_modules.txt b/src/cmd/go/testdata/script/work_build_no_modules.txt new file mode 100644 index 0000000..c9859b4 --- /dev/null +++ b/src/cmd/go/testdata/script/work_build_no_modules.txt @@ -0,0 +1,13 @@ +! go build . +stderr 'go: no modules were found in the current workspace; see ''go help work''' + +-- go.work -- +go 1.18 +-- go.mod -- +go 1.18 + +module foo +-- foo.go -- +package main + +func main() {}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/work_disablevendor.txt b/src/cmd/go/testdata/script/work_disablevendor.txt new file mode 100644 index 0000000..c4c580b --- /dev/null +++ b/src/cmd/go/testdata/script/work_disablevendor.txt @@ -0,0 +1,56 @@ +# Test that mod=vendor is disabled in workspace mode, even +# with a single workspace module. + +cd workspace + +# Base case: ensure the module would default to mod=vendor +# outside of workspace mode. +env GOWORK=off +go list -f '{{.Dir}}' example.com/dep +stdout $GOPATH[\\/]src[\\/]workspace[\\/]vendor[\\/]example.com[\\/]dep + +# Test case: endure the module does not enter mod=vendor outside +# worspace mode. +env GOWORK='' +go list -f '{{.Dir}}' example.com/dep +stdout $GOPATH[\\/]src[\\/]dep + +-- workspace/go.work -- +use . +replace example.com/dep => ../dep +-- workspace/main.go -- +package main + +import "example.com/dep" + +func main() { + dep.Dep() +} +-- workspace/go.mod -- +module example.com/mod + +go 1.20 + +require example.com/dep v1.0.0 +-- workspace/vendor/example.com/dep/dep.go -- +package dep + +import "fmt" + +func Dep() { + fmt.Println("the vendored dep") +} +-- workspace/vendor/modules.txt -- +# example.com/dep v1.0.0 +## explicit +example.com/dep +-- dep/go.mod -- +module example.com/dep +-- dep/dep.go -- +package dep + +import "fmt" + +func Dep () { + fmt.Println("the real dep") +} diff --git a/src/cmd/go/testdata/script/work_edit.txt b/src/cmd/go/testdata/script/work_edit.txt new file mode 100644 index 0000000..c67696d --- /dev/null +++ b/src/cmd/go/testdata/script/work_edit.txt @@ -0,0 +1,166 @@ +# Test editing go.work files. + +go work init m +cmpenv go.work go.work.want_initial + +go work edit -use n +cmpenv go.work go.work.want_use_n + +grep go go.work +go work edit -go none +! grep go go.work + +go work edit -go 1.18 +cmp go.work go.work.want_go_118 + +go work edit -dropuse m +cmp go.work go.work.want_dropuse_m + +go work edit -replace=x.1@v1.3.0=y.1@v1.4.0 -replace='x.1@v1.4.0 = ../z' +cmp go.work go.work.want_add_replaces + +go work edit -use n -use ../a -use /b -use c -use c +cmp go.work go.work.want_multiuse + +go work edit -dropuse /b -dropuse n +cmp go.work go.work.want_multidropuse + +go work edit -dropreplace='x.1@v1.4.0' +cmp go.work go.work.want_dropreplace + +go work edit -print -go 1.19 -use b -dropuse c -replace 'x.1@v1.4.0 = ../z' -dropreplace x.1 -dropreplace x.1@v1.3.0 +cmp stdout go.work.want_print + +go work edit -json -go 1.19 -use b -dropuse c -replace 'x.1@v1.4.0 = ../z' -dropreplace x.1 -dropreplace x.1@v1.3.0 +cmp stdout go.work.want_json + +env GOWORK=$GOPATH/src/unformatted +go work edit -print -fmt +cmp stdout formatted + +-- m/go.mod -- +module m + +go 1.18 +-- go.work.want_initial -- +go $goversion + +use ./m +-- go.work.want_use_n -- +go $goversion + +use ( + ./m + ./n +) +-- go.work.want_go_118 -- +go 1.18 + +use ( + ./m + ./n +) +-- go.work.want_dropuse_m -- +go 1.18 + +use ./n +-- go.work.want_add_replaces -- +go 1.18 + +use ./n + +replace ( + x.1 v1.3.0 => y.1 v1.4.0 + x.1 v1.4.0 => ../z +) +-- go.work.want_multiuse -- +go 1.18 + +use ( + ../a + ./c + ./n + /b +) + +replace ( + x.1 v1.3.0 => y.1 v1.4.0 + x.1 v1.4.0 => ../z +) +-- go.work.want_multidropuse -- +go 1.18 + +use ( + ../a + ./c +) + +replace ( + x.1 v1.3.0 => y.1 v1.4.0 + x.1 v1.4.0 => ../z +) +-- go.work.want_dropreplace -- +go 1.18 + +use ( + ../a + ./c +) + +replace x.1 v1.3.0 => y.1 v1.4.0 +-- go.work.want_print -- +go 1.19 + +use ( + ../a + ./b +) + +replace x.1 v1.4.0 => ../z +-- go.work.want_json -- +{ + "Go": "1.19", + "Use": [ + { + "DiskPath": "../a" + }, + { + "DiskPath": "./b" + } + ], + "Replace": [ + { + "Old": { + "Path": "x.1", + "Version": "v1.4.0" + }, + "New": { + "Path": "../z" + } + } + ] +} +-- unformatted -- +go 1.18 + use ( + a + b + c + ) + replace ( + x.1 v1.3.0 => y.1 v1.4.0 + x.1 v1.4.0 => ../z + ) +-- formatted -- +go 1.18 + +use ( + a + b + c +) + +replace ( + x.1 v1.3.0 => y.1 v1.4.0 + x.1 v1.4.0 => ../z +) diff --git a/src/cmd/go/testdata/script/work_edit_toolchain.txt b/src/cmd/go/testdata/script/work_edit_toolchain.txt new file mode 100644 index 0000000..b4e260d --- /dev/null +++ b/src/cmd/go/testdata/script/work_edit_toolchain.txt @@ -0,0 +1,20 @@ +# Test support for go work edit -toolchain to set toolchain to use + +env GOTOOLCHAIN=local +env GO111MODULE=on + +! grep toolchain go.work +go work edit -toolchain=go1.9 +grep 'toolchain go1.9' go.work + +go work edit -toolchain=default +grep 'toolchain default' go.work + +go work edit -toolchain=none +! grep toolchain go.work + +-- go.work -- +go 1.8 +use . +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/work_empty_panic_GOPATH.txt b/src/cmd/go/testdata/script/work_empty_panic_GOPATH.txt new file mode 100644 index 0000000..43ebf11 --- /dev/null +++ b/src/cmd/go/testdata/script/work_empty_panic_GOPATH.txt @@ -0,0 +1,13 @@ +# Regression test for https://go.dev/issue/58767: +# with an empty go.work file in GOPATH mode, calls to load.defaultGODEBUG for a +# package named "main" panicked in modload.MainModules.GoVersion. + +env GO111MODULE=off +cd example +go list example/m + +-- example/go.work -- +go 1.21 +-- example/m/main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/work_env.txt b/src/cmd/go/testdata/script/work_env.txt new file mode 100644 index 0000000..8b1779e --- /dev/null +++ b/src/cmd/go/testdata/script/work_env.txt @@ -0,0 +1,28 @@ +go env GOWORK +stdout '^'$GOPATH'[\\/]src[\\/]go.work$' +go env +stdout '^(set )?GOWORK=''?'$GOPATH'[\\/]src[\\/]go.work''?$' + +cd .. +go env GOWORK +! stdout . +go env +stdout 'GOWORK=("")?' + +cd src +go env GOWORK +stdout 'go.work' + +env GOWORK='off' +go env GOWORK +stdout 'off' + +! go env -w GOWORK=off +stderr '^go: GOWORK cannot be modified$' + +-- go.work -- +go 1.18 + +use a +-- a/go.mod -- +module example.com/a diff --git a/src/cmd/go/testdata/script/work_get_toolchain.txt b/src/cmd/go/testdata/script/work_get_toolchain.txt new file mode 100644 index 0000000..5a851bb --- /dev/null +++ b/src/cmd/go/testdata/script/work_get_toolchain.txt @@ -0,0 +1,24 @@ +# go get should update the go and toolchain lines in go.work +env TESTGO_VERSION=go1.21 +env TESTGO_VERSION_SWITCH=switch +env GOTOOLCHAIN=auto +cp go.mod.new go.mod +cp go.work.new go.work +go get rsc.io/needgo121 rsc.io/needgo122 rsc.io/needgo123 rsc.io/needall +stderr '^go: rsc.io/needall@v0.0.1 requires go >= 1.23; switching to go1.23.9$' +stderr '^go: added rsc.io/needall v0.0.1' +grep 'go 1.23$' go.mod +grep 'go 1.23$' go.work +grep 'toolchain go1.23.9' go.mod +grep 'toolchain go1.23.9' go.work + +-- go.mod.new -- +module m +go 1.1 + +-- p.go -- +package p + +-- go.work.new -- +go 1.18 +use . diff --git a/src/cmd/go/testdata/script/work_goline_order.txt b/src/cmd/go/testdata/script/work_goline_order.txt new file mode 100644 index 0000000..fe1cddb --- /dev/null +++ b/src/cmd/go/testdata/script/work_goline_order.txt @@ -0,0 +1,34 @@ +# Check that go line in go.work is always >= go line of used modules. + +# Using an old Go version, fails during module loading, but we rewrite the error to the +# same one a switching version would use, without the auto-switch. +# This is a misconfigured system that should not arise in practice. +env TESTGO_VERSION=go1.21.1 +env TESTGO_VERSION_SWITCH=switch +cp go.work go.work.orig +! go list +stderr '^go: module . listed in go.work file requires go >= 1.21.2, but go.work lists go 1.21.1; to update it:\n\tgo work use$' +go work use +go list + +# Using a new enough Go version, fails later and can suggest 'go work use'. +env TESTGO_VERSION=go1.21.2 +env TESTGO_VERSION_SWITCH=switch +cp go.work.orig go.work +! go list +stderr '^go: module . listed in go.work file requires go >= 1.21.2, but go.work lists go 1.21.1; to update it:\n\tgo work use$' + +# go work use fixes the problem. +go work use +go list + +-- go.work -- +go 1.21.1 +use . + +-- go.mod -- +module m +go 1.21.2 + +-- p.go -- +package p diff --git a/src/cmd/go/testdata/script/work_goproxy_off.txt b/src/cmd/go/testdata/script/work_goproxy_off.txt new file mode 100644 index 0000000..0a602e3 --- /dev/null +++ b/src/cmd/go/testdata/script/work_goproxy_off.txt @@ -0,0 +1,59 @@ +go work init +go work use . ./sub + +# Verify that the go.mod files for both modules in the workspace are tidy, +# and add missing go.sum entries as needed. + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +cd sub +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig +cd .. + +go list -m all +stdout '^rsc\.io/quote v1\.5\.1$' +stdout '^rsc\.io/sampler v1\.3\.1$' + +# Now remove the module dependencies from the module cache. +# Because one module upgrades a transitive dependency needed by another, +# listing the modules in the workspace should error out. + +go clean -modcache +env GOPROXY=off +! go list -m all +stderr '^go: rsc.io/sampler@v1.3.0: module lookup disabled by GOPROXY=off$' + +-- example.go -- +package example + +import _ "rsc.io/sampler" +-- go.mod -- +module example + +go 1.19 + +require rsc.io/sampler v1.3.0 + +require ( + golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect + rsc.io/testonly v1.0.0 // indirect +) +-- sub/go.mod -- +module example/sub + +go 1.19 + +require rsc.io/quote v1.5.1 + +require ( + golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect + rsc.io/sampler v1.3.1 // indirect +) +-- sub/sub.go -- +package example + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/work_gowork.txt b/src/cmd/go/testdata/script/work_gowork.txt new file mode 100644 index 0000000..1cfbf0c --- /dev/null +++ b/src/cmd/go/testdata/script/work_gowork.txt @@ -0,0 +1,24 @@ +env GOWORK=stop.work +! go list a # require absolute path +! stderr panic +env GOWORK=doesnotexist +! go list a +! stderr panic + +env GOWORK=$GOPATH/src/stop.work +go list -n a +go build -n a +go test -n a + +-- stop.work -- +go 1.18 + +use ./a +-- a/a.go -- +package a +-- a/a_test.go -- +package a +-- a/go.mod -- +module a + +go 1.18
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/work_init_gowork.txt b/src/cmd/go/testdata/script/work_init_gowork.txt new file mode 100644 index 0000000..55ac99b --- /dev/null +++ b/src/cmd/go/testdata/script/work_init_gowork.txt @@ -0,0 +1,19 @@ +# Test that the GOWORK environment variable flag is used by go work init. + +! exists go.work +go work init +exists go.work + +env GOWORK=$GOPATH/src/foo/foo.work +! exists foo/foo.work +go work init +exists foo/foo.work + +env GOWORK= +cd foo/bar +! go work init +stderr 'already exists' + +# Create directories to make go.work files in. +-- foo/dummy.txt -- +-- foo/bar/dummy.txt -- diff --git a/src/cmd/go/testdata/script/work_init_path.txt b/src/cmd/go/testdata/script/work_init_path.txt new file mode 100644 index 0000000..0a2d372 --- /dev/null +++ b/src/cmd/go/testdata/script/work_init_path.txt @@ -0,0 +1,33 @@ +# Regression test for https://go.dev/issue/51448. +# 'go work init . .. foo/bar' should produce a go.work file +# with the same paths as 'go work init; go work use -r ..', +# and it should have 'use .' rather than 'use ./.' inside. + +cd dir + +go work init . .. foo/bar +mv go.work go.work.init + +go work init +go work use -r .. +cmp go.work go.work.init + +cmpenv go.work $WORK/go.work.want + +-- go.mod -- +module example +go 1.18 +-- dir/go.mod -- +module example +go 1.18 +-- dir/foo/bar/go.mod -- +module example +go 1.18 +-- $WORK/go.work.want -- +go $goversion + +use ( + . + .. + ./foo/bar +) diff --git a/src/cmd/go/testdata/script/work_init_toolchain.txt b/src/cmd/go/testdata/script/work_init_toolchain.txt new file mode 100644 index 0000000..900ea2c --- /dev/null +++ b/src/cmd/go/testdata/script/work_init_toolchain.txt @@ -0,0 +1,35 @@ + +# Create basic modules and work space. +# Note that toolchain lines in modules should be completely ignored. +env TESTGO_VERSION=go1.50 +mkdir m1_22_0 +go mod init -C m1_22_0 +go mod edit -C m1_22_0 -go=1.22.0 -toolchain=go1.99.0 + +# work init writes the current Go version to the go line +go work init +grep '^go 1.50$' go.work +! grep toolchain go.work + +# work init with older modules should leave go 1.50 in the go.work. +rm go.work +go work init ./m1_22_0 +grep '^go 1.50$' go.work +! grep toolchain go.work + +# work init with newer modules should bump go, +# including updating to a newer toolchain as needed. +# Because work init writes the current toolchain as the go version, +# it writes the bumped go version, not the max of the used modules. +env TESTGO_VERSION=go1.21 +env TESTGO_VERSION_SWITCH=switch +rm go.work +env GOTOOLCHAIN=local +! go work init ./m1_22_0 +stderr '^go: m1_22_0'${/}'go.mod requires go >= 1.22.0 \(running go 1.21; GOTOOLCHAIN=local\)$' +env GOTOOLCHAIN=auto +go work init ./m1_22_0 +stderr '^go: m1_22_0'${/}'go.mod requires go >= 1.22.0; switching to go1.22.9$' +cat go.work +grep '^go 1.22.9$' go.work +! grep toolchain go.work diff --git a/src/cmd/go/testdata/script/work_install_submodule.txt b/src/cmd/go/testdata/script/work_install_submodule.txt new file mode 100644 index 0000000..3d11717 --- /dev/null +++ b/src/cmd/go/testdata/script/work_install_submodule.txt @@ -0,0 +1,36 @@ +# This is a regression test for golang.org/issue/50036 +# Don't check sums for other modules in the workspace. + +cd m/sub +go install -n + +-- go.work -- +go 1.18 + +use ( + ./m + ./m/sub +) +-- m/go.mod -- +module example.com/m + +go 1.18 + +-- m/m.go -- +package m + +func M() {} +-- m/sub/go.mod -- +module example.com/m/sub + +go 1.18 + +require example.com/m v1.0.0 +-- m/sub/main.go -- +package main + +import "example.com/m" + +func main() { + m.M() +} diff --git a/src/cmd/go/testdata/script/work_issue51204.txt b/src/cmd/go/testdata/script/work_issue51204.txt new file mode 100644 index 0000000..d483002 --- /dev/null +++ b/src/cmd/go/testdata/script/work_issue51204.txt @@ -0,0 +1,57 @@ +go work sync + +go list -f '{{.Dir}}' example.com/test +stdout '^'$PWD${/}test'$' + +-- go.work -- +go 1.18 + +use ( + ./test2 + ./test2/sub +) +-- test/go.mod -- +module example.com/test + +go 1.18 +-- test/file.go -- +package test + +func DoSomething() { +} +-- test2/go.mod -- +module example.com/test2 + +go 1.18 + +replace example.com/test => ../test + +require example.com/test v0.0.0-00010101000000-000000000000 +-- test2/file.go -- +package test2 + +import ( + "example.com/test" +) + +func DoSomething() { + test.DoSomething() +} +-- test2/sub/go.mod -- +module example.com/test2/sub + +go 1.18 + +replace example.com/test => ../../test + +require example.com/test v0.0.0 +-- test2/sub/file.go -- +package test2 + +import ( + "example.com/test" +) + +func DoSomething() { + test.DoSomething() +} diff --git a/src/cmd/go/testdata/script/work_issue54048.txt b/src/cmd/go/testdata/script/work_issue54048.txt new file mode 100644 index 0000000..ced3d90 --- /dev/null +++ b/src/cmd/go/testdata/script/work_issue54048.txt @@ -0,0 +1,19 @@ +! go list -m -json all +stderr 'go: module example.com/foo appears multiple times in workspace' + +-- go.work -- +go 1.18 + +use ( + ./a + ./b +) +-- a/go.mod -- +module example.com/foo + +go 1.18 + +-- b/go.mod -- +module example.com/foo + +go 1.18 diff --git a/src/cmd/go/testdata/script/work_issue54372.txt b/src/cmd/go/testdata/script/work_issue54372.txt new file mode 100644 index 0000000..bd3108a --- /dev/null +++ b/src/cmd/go/testdata/script/work_issue54372.txt @@ -0,0 +1,37 @@ +# go mod verify should not try to verify the workspace modules. +# This is a test for #54372. + +go mod verify +stdout 'all modules verified' +! stderr . + +-- go.work -- +go 1.21 + +use ( + ./a + ./b + ./c + ./d +) +-- a/go.mod -- +module example.com/a + +go 1.21 + +require rsc.io/quote v1.1.0 +-- a/a.go -- +package a +import _ "rsc.io/quote" +-- b/go.mod -- +module example.com/b + +go 1.21 +-- c/go.mod -- +module example.com/c + +go 1.21 +-- d/go.mod -- +module example.com/d + +go 1.21
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/work_module_not_in_go_work.txt b/src/cmd/go/testdata/script/work_module_not_in_go_work.txt new file mode 100644 index 0000000..074bac5 --- /dev/null +++ b/src/cmd/go/testdata/script/work_module_not_in_go_work.txt @@ -0,0 +1,40 @@ +# This is a regression test for issue #49632. +# The Go command should mention go.work if the user +# tries to load a local package that's in a module +# that's not in go.work and can't be resolved. + +! go list ./... +stderr 'pattern ./...: directory prefix . does not contain modules listed in go.work or their selected dependencies' + +! go list ./a/c +stderr 'directory a[\\/]c is contained in a module that is not one of the workspace modules listed in go.work. You can add the module to the workspace using:\n\tgo work use a' + +! go install ./a/c +stderr 'directory a[\\/]c is contained in a module that is not one of the workspace modules listed in go.work. You can add the module to the workspace using:\n\tgo work use a' + +cd a/c +! go run . +stderr 'current directory is contained in a module that is not one of the workspace modules listed in go.work. You can add the module to the workspace using:\n\tgo work use \.\.' + +cd ../.. +! go run . +stderr 'current directory outside modules listed in go.work or their selected dependencies' + +-- go.work -- +go 1.18 + +use ./b +-- a/go.mod -- +module example.com/a + +go 1.18 +-- a/a.go -- +package a +-- a/c/c.go -- +package main +-- b/go.mod -- +module example.com/b + +go 1.18 +-- foo.go -- +package foo diff --git a/src/cmd/go/testdata/script/work_nowork.txt b/src/cmd/go/testdata/script/work_nowork.txt new file mode 100644 index 0000000..b4c9b1d --- /dev/null +++ b/src/cmd/go/testdata/script/work_nowork.txt @@ -0,0 +1,20 @@ +! go work use +stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using GOWORK environment variable\)$' + +! go work use . +stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using GOWORK environment variable\)$' + +! go work edit +stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using GOWORK environment variable\)$' + +! go work edit -go=1.18 +stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using GOWORK environment variable\)$' + +! go work sync +stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using GOWORK environment variable\)$' + +-- go.mod -- +module example +go 1.18 +-- README.txt -- +There is no go.work file here. diff --git a/src/cmd/go/testdata/script/work_prune.txt b/src/cmd/go/testdata/script/work_prune.txt new file mode 100644 index 0000000..b1f569e --- /dev/null +++ b/src/cmd/go/testdata/script/work_prune.txt @@ -0,0 +1,103 @@ +# This test makes sure workspace mode's handling of the module graph +# is compatible with module pruning. The graph we load from either of +# the workspace modules should be the same, even if their graphs +# don't overlap. +# +# This is the module graph in the test: +# +# example.com/a -> example.com/b v1.0.0 -> example.com/q v1.1.0 +# example.com/p -> example.com/q v1.0.0 +# +# If we didn't load the whole graph and didn't load the dependencies of b +# when loading p, we would end up loading q v1.0.0, rather than v1.1.0, +# which is selected by MVS. + +go list -m -f '{{.Version}}' example.com/q +stdout '^v1.1.0$' + +-- go.work -- +go 1.18 + +use ( + ./a + ./p +) +-- a/go.mod -- +module example.com/a + +go 1.18 + +require example.com/b v1.0.0 + +replace example.com/b v1.0.0 => ../b +-- a/foo.go -- +package main + +import "example.com/b" + +func main() { + b.B() +} +-- b/go.mod -- +module example.com/b + +go 1.18 + +require example.com/q v1.1.0 + +replace example.com/q v1.0.0 => ../q1_0_0 +replace example.com/q v1.1.0 => ../q1_1_0 +-- b/b.go -- +package b + +func B() { +} +-- b/b_test.go -- +package b + +import "example.com/q" + +func TestB() { + q.PrintVersion() +} +-- p/go.mod -- +module example.com/p + +go 1.18 + +require example.com/q v1.0.0 + +replace example.com/q v1.0.0 => ../q1_0_0 +replace example.com/q v1.1.0 => ../q1_1_0 +-- p/main.go -- +package main + +import "example.com/q" + +func main() { + q.PrintVersion() +} +-- q1_0_0/go.mod -- +module example.com/q + +go 1.18 +-- q1_0_0/q.go -- +package q + +import "fmt" + +func PrintVersion() { + fmt.Println("version 1.0.0") +} +-- q1_1_0/go.mod -- +module example.com/q + +go 1.18 +-- q1_1_0/q.go -- +package q + +import "fmt" + +func PrintVersion() { + fmt.Println("version 1.1.0") +} diff --git a/src/cmd/go/testdata/script/work_prune_all.txt b/src/cmd/go/testdata/script/work_prune_all.txt new file mode 100644 index 0000000..a7ad9c0 --- /dev/null +++ b/src/cmd/go/testdata/script/work_prune_all.txt @@ -0,0 +1,176 @@ +# This test makes sure workspace mode's handling of the module graph +# is compatible with module pruning. The graph we load from either of +# the workspace modules should be the same, even if their graphs +# don't overlap. +# +# This is the module graph in the test: +# +# example.com/p -> example.com/q v1.0.0 +# example.com/a -> example.com/b v1.0.0 -> example.com/q v1.1.0 -> example.com/w v1.0.0 -> example.com/x v1.0.0 -> example.com/y v1.0.0 +# |-> example.com/z v1.0.0 |-> example.com/z v1.1.0 +# |-> example.com/q v1.0.5 -> example.com/r v1.0.0 +# If we didn't load the whole graph and didn't load the dependencies of b +# when loading p, we would end up loading q v1.0.0, rather than v1.1.0, +# which is selected by MVS. + +go list -m all +stdout 'example.com/w v1.0.0' +stdout 'example.com/q v1.1.0' +stdout 'example.com/z v1.1.0' +stdout 'example.com/x v1.0.0' +! stdout 'example.com/r' +! stdout 'example.com/y' + +-- go.work -- +go 1.18 + +use ( + ./a + ./p +) + +replace example.com/b v1.0.0 => ./b +replace example.com/q v1.0.0 => ./q1_0_0 +replace example.com/q v1.0.5 => ./q1_0_5 +replace example.com/q v1.1.0 => ./q1_1_0 +replace example.com/r v1.0.0 => ./r +replace example.com/w v1.0.0 => ./w +replace example.com/x v1.0.0 => ./x +replace example.com/y v1.0.0 => ./y +replace example.com/z v1.0.0 => ./z1_0_0 +replace example.com/z v1.1.0 => ./z1_1_0 + +-- a/go.mod -- +module example.com/a + +go 1.18 + +require example.com/b v1.0.0 +require example.com/z v1.0.0 +-- a/foo.go -- +package main + +import "example.com/b" + +func main() { + b.B() +} +-- b/go.mod -- +module example.com/b + +go 1.18 + +require example.com/q v1.1.0 +-- b/b.go -- +package b + +func B() { +} +-- p/go.mod -- +module example.com/p + +go 1.18 + +require example.com/q v1.0.0 + +replace example.com/q v1.0.0 => ../q1_0_0 +replace example.com/q v1.1.0 => ../q1_1_0 +-- p/main.go -- +package main + +import "example.com/q" + +func main() { + q.PrintVersion() +} +-- q1_0_0/go.mod -- +module example.com/q + +go 1.18 +-- q1_0_0/q.go -- +package q + +import "fmt" + +func PrintVersion() { + fmt.Println("version 1.0.0") +} +-- q1_0_5/go.mod -- +module example.com/q + +go 1.18 + +require example.com/r v1.0.0 +-- q1_0_5/q.go -- +package q + +import _ "example.com/r" +-- q1_1_0/go.mod -- +module example.com/q + +require example.com/w v1.0.0 +require example.com/z v1.1.0 + +go 1.18 +-- q1_1_0/q.go -- +package q + +import _ "example.com/w" +import _ "example.com/z" + +import "fmt" + +func PrintVersion() { + fmt.Println("version 1.1.0") +} +-- r/go.mod -- +module example.com/r + +go 1.18 + +require example.com/r v1.0.0 +-- r/r.go -- +package r +-- w/go.mod -- +module example.com/w + +go 1.18 + +require example.com/x v1.0.0 +-- w/w.go -- +package w +-- w/w_test.go -- +package w + +import _ "example.com/x" +-- x/go.mod -- +module example.com/x + +go 1.18 +-- x/x.go -- +package x +-- x/x_test.go -- +package x +import _ "example.com/y" +-- y/go.mod -- +module example.com/y + +go 1.18 +-- y/y.go -- +package y +-- z1_0_0/go.mod -- +module example.com/z + +go 1.18 + +require example.com/q v1.0.5 +-- z1_0_0/z.go -- +package z + +import _ "example.com/q" +-- z1_1_0/go.mod -- +module example.com/z + +go 1.18 +-- z1_1_0/z.go -- +package z diff --git a/src/cmd/go/testdata/script/work_regression_hang.txt b/src/cmd/go/testdata/script/work_regression_hang.txt new file mode 100644 index 0000000..a7661b6 --- /dev/null +++ b/src/cmd/go/testdata/script/work_regression_hang.txt @@ -0,0 +1,71 @@ +# This test makes checks against a regression of a bug in the Go command +# where the module loader hung forever because all main module dependencies +# kept workspace pruning instead of adopting the pruning in their go.mod +# files, and the loader kept adding dependencies on the queue until they +# were either pruned or unpruned, never breaking a module dependency cycle. +# +# This is the module graph in the test: +# +# /-------------------------\ +# | | +# V | +# example.com/a -> example.com/b v1.0.0 -> example.com/c v1.1.0 + +go list -m -f '{{.Version}}' example.com/c + +-- go.work -- +go 1.16 + +use ( + ./a +) +-- a/go.mod -- +module example.com/a + +go 1.18 + +require example.com/b v1.0.0 + +replace example.com/b v1.0.0 => ../b +replace example.com/c v1.0.0 => ../c +-- a/foo.go -- +package main + +import "example.com/b" + +func main() { + b.B() +} +-- b/go.mod -- +module example.com/b + +go 1.18 + +require example.com/c v1.0.0 +-- b/b.go -- +package b + +func B() { +} +-- b/cmd/main.go -- +package main + +import "example.com/c" + +func main() { + c.C() +} +-- c/go.mod -- +module example.com/c + +go 1.18 + +require example.com/b v1.0.0 +-- c/c.go -- +package c + +import "example.com/b" + +func C() { + b.B() +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/work_reject_modfile.txt b/src/cmd/go/testdata/script/work_reject_modfile.txt new file mode 100644 index 0000000..f0cfa3b --- /dev/null +++ b/src/cmd/go/testdata/script/work_reject_modfile.txt @@ -0,0 +1,34 @@ +# Test that -modfile=path/to/go.mod is rejected in workspace mode. + +! go list -m -modfile=./a/go.alt.mod +stderr 'go: -modfile cannot be used in workspace mode' + +env GOFLAGS=-modfile=./a/go.alt.mod +! go list -m +stderr 'go: -modfile cannot be used in workspace mode' + +-- go.work -- +go 1.20 + +use ( + ./a +) + +-- a/go.mod -- +module example.com/foo + +go 1.20 + +-- a/go.alt.mod -- +module example.com/foo + +go 1.20 + +-- a/main.go -- +package main + +import "fmt" + +func main() { + fmt.Println("Hello world!") +} diff --git a/src/cmd/go/testdata/script/work_replace.txt b/src/cmd/go/testdata/script/work_replace.txt new file mode 100644 index 0000000..81268e5 --- /dev/null +++ b/src/cmd/go/testdata/script/work_replace.txt @@ -0,0 +1,55 @@ +# Support replace statement in go.work file + +# Replacement in go.work file, and none in go.mod file. +go list -m example.com/dep +stdout 'example.com/dep v1.0.0 => ./dep' + +# Wildcard replacement in go.work file overrides version replacement in go.mod +# file. +go list -m example.com/other +stdout 'example.com/other v1.0.0 => ./other2' + +-- go.work -- +use m + +replace example.com/dep => ./dep +replace example.com/other => ./other2 + +-- m/go.mod -- +module example.com/m + +require example.com/dep v1.0.0 +require example.com/other v1.0.0 + +replace example.com/other v1.0.0 => ./other +-- m/m.go -- +package m + +import "example.com/dep" +import "example.com/other" + +func F() { + dep.G() + other.H() +} +-- dep/go.mod -- +module example.com/dep +-- dep/dep.go -- +package dep + +func G() { +} +-- other/go.mod -- +module example.com/other +-- other/dep.go -- +package other + +func G() { +} +-- other2/go.mod -- +module example.com/other +-- other2/dep.go -- +package other + +func G() { +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/work_replace_conflict.txt b/src/cmd/go/testdata/script/work_replace_conflict.txt new file mode 100644 index 0000000..7b71b0f --- /dev/null +++ b/src/cmd/go/testdata/script/work_replace_conflict.txt @@ -0,0 +1,53 @@ +# Conflicting replaces in workspace modules returns error that suggests +# overriding it in the go.work file. + +! go list -m example.com/dep +stderr 'go: conflicting replacements for example.com/dep@v1.0.0:\n\t'$PWD${/}'dep1\n\t'$PWD${/}'dep2\nuse "go work edit -replace example.com/dep@v1.0.0=\[override\]" to resolve' +go work edit -replace example.com/dep@v1.0.0=./dep1 +go list -m example.com/dep +stdout 'example.com/dep v1.0.0 => ./dep1' + +-- foo -- +-- go.work -- +use m +use n +-- m/go.mod -- +module example.com/m + +require example.com/dep v1.0.0 +replace example.com/dep v1.0.0 => ../dep1 +-- m/m.go -- +package m + +import "example.com/dep" + +func F() { + dep.G() +} +-- n/go.mod -- +module example.com/n + +require example.com/dep v1.0.0 +replace example.com/dep v1.0.0 => ../dep2 +-- n/n.go -- +package n + +import "example.com/dep" + +func F() { + dep.G() +} +-- dep1/go.mod -- +module example.com/dep +-- dep1/dep.go -- +package dep + +func G() { +} +-- dep2/go.mod -- +module example.com/dep +-- dep2/dep.go -- +package dep + +func G() { +} diff --git a/src/cmd/go/testdata/script/work_replace_conflict_override.txt b/src/cmd/go/testdata/script/work_replace_conflict_override.txt new file mode 100644 index 0000000..c62084b --- /dev/null +++ b/src/cmd/go/testdata/script/work_replace_conflict_override.txt @@ -0,0 +1,57 @@ +# Conflicting workspace module replaces can be overridden by a replace in the +# go.work file. + +go list -m example.com/dep +stdout 'example.com/dep v1.0.0 => ./dep3' + +-- go.work -- +use m +use n +replace example.com/dep => ./dep3 +-- m/go.mod -- +module example.com/m + +require example.com/dep v1.0.0 +replace example.com/dep => ./dep1 +-- m/m.go -- +package m + +import "example.com/dep" + +func F() { + dep.G() +} +-- n/go.mod -- +module example.com/n + +require example.com/dep v1.0.0 +replace example.com/dep => ./dep2 +-- n/n.go -- +package n + +import "example.com/dep" + +func F() { + dep.G() +} +-- dep1/go.mod -- +module example.com/dep +-- dep1/dep.go -- +package dep + +func G() { +} +-- dep2/go.mod -- +module example.com/dep +-- dep2/dep.go -- +package dep + +func G() { +} +-- dep3/go.mod -- +module example.com/dep +-- dep3/dep.go -- +package dep + +func G() { +} diff --git a/src/cmd/go/testdata/script/work_replace_main_module.txt b/src/cmd/go/testdata/script/work_replace_main_module.txt new file mode 100644 index 0000000..b213764 --- /dev/null +++ b/src/cmd/go/testdata/script/work_replace_main_module.txt @@ -0,0 +1,45 @@ +# Ensure that replaces of the main module in workspace modules +# are ignored, and replaces in the go.work file are disallowed. +# This tests against an issue where requirements of the +# main module were being ignored because the main module +# was replaced in a transitive dependency with another +# version. + +go list example.com/dep + +cp replace_main_module.go.work go.work +! go list example.com/dep +stderr 'go: workspace module example.com/mainmoda is replaced at all versions in the go.work file. To fix, remove the replacement from the go.work file or specify the version at which to replace the module.' + +-- replace_main_module.go.work -- +go 1.18 +use ( + ./mainmoda + ./mainmodb +) +replace example.com/mainmoda => ../mainmodareplacement +-- go.work -- +go 1.18 +use ( + ./mainmoda + ./mainmodb +) +-- mainmoda/go.mod -- +module example.com/mainmoda + +go 1.18 + +require example.com/dep v1.0.0 +replace example.com/dep => ../dep + +-- dep/go.mod -- +module example.com/dep +-- dep/dep.go -- +package dep +-- mainmodb/go.mod -- +module example.com/mainmodb +go 1.18 +replace example.com/mainmoda => ../mainmodareplacement +-- mainmodareplacement/go.mod -- +module example.com/mainmoda +go 1.18
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/work_sum.txt b/src/cmd/go/testdata/script/work_sum.txt new file mode 100644 index 0000000..19dbb90 --- /dev/null +++ b/src/cmd/go/testdata/script/work_sum.txt @@ -0,0 +1,34 @@ +# Test adding sums to go.work.sum when sum isn't in go.mod. + +go run . +cmp go.work.sum want.sum + +-- want.sum -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +-- go.work -- +go 1.18 + +use . +-- go.mod -- +go 1.18 + +module example.com/hi + +require "rsc.io/quote" v1.5.2 +-- go.sum -- +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +-- main.go -- +package main + +import ( + "fmt" + "rsc.io/quote" +) + +func main() { + fmt.Println(quote.Hello()) +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/work_sum_mismatch.txt b/src/cmd/go/testdata/script/work_sum_mismatch.txt new file mode 100644 index 0000000..ca5d71d --- /dev/null +++ b/src/cmd/go/testdata/script/work_sum_mismatch.txt @@ -0,0 +1,61 @@ +# Test mismatched sums in go.sum files + +! go run ./a +cmpenv stderr want-error + +-- want-error -- +verifying rsc.io/sampler@v1.3.0/go.mod: checksum mismatch + downloaded: h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= + $WORK${/}gopath${/}src${/}a${/}go.sum: h1:U1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= + +SECURITY ERROR +This download does NOT match an earlier download recorded in go.sum. +The bits may have been replaced on the origin server, or an attacker may +have intercepted the download attempt. + +For more information, see 'go help module-auth'. +-- go.work -- +go 1.18 + +use ./a +use ./b +-- a/go.mod -- +go 1.18 + +module example.com/hi + +require "rsc.io/quote" v1.5.2 +-- a/go.sum -- +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:U1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +-- a/main.go -- +package main + +import ( + "fmt" + "rsc.io/quote" +) + +func main() { + fmt.Println(quote.Hello()) +} +-- b/go.mod -- +go 1.18 + +module example.com/hi2 + +require "rsc.io/quote" v1.5.2 +-- b/go.sum -- +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +-- b/main.go -- +package main + +import ( + "fmt" + "rsc.io/quote" +) + +func main() { + fmt.Println(quote.Hello()) +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/work_sync.txt b/src/cmd/go/testdata/script/work_sync.txt new file mode 100644 index 0000000..69167d4 --- /dev/null +++ b/src/cmd/go/testdata/script/work_sync.txt @@ -0,0 +1,119 @@ +go work sync +cmp a/go.mod a/want_go.mod +cmp b/go.mod b/want_go.mod + +-- go.work -- +go 1.18 + +use ( + ./a + ./b +) + +-- a/go.mod -- +go 1.18 + +module example.com/a + +require ( + example.com/p v1.0.0 + example.com/q v1.1.0 + example.com/r v1.0.0 +) + +replace ( + example.com/p => ../p + example.com/q => ../q + example.com/r => ../r +) +-- a/want_go.mod -- +go 1.18 + +module example.com/a + +require ( + example.com/p v1.1.0 + example.com/q v1.1.0 +) + +replace ( + example.com/p => ../p + example.com/q => ../q + example.com/r => ../r +) +-- a/a.go -- +package a + +import ( + "example.com/p" + "example.com/q" +) + +func Foo() { + p.P() + q.Q() +} +-- b/go.mod -- +go 1.18 + +module example.com/b + +require ( + example.com/p v1.1.0 + example.com/q v1.0.0 +) + +replace ( + example.com/p => ../p + example.com/q => ../q +) +-- b/want_go.mod -- +go 1.18 + +module example.com/b + +require ( + example.com/p v1.1.0 + example.com/q v1.1.0 +) + +replace ( + example.com/p => ../p + example.com/q => ../q +) +-- b/b.go -- +package b + +import ( + "example.com/p" + "example.com/q" +) + +func Foo() { + p.P() + q.Q() +} +-- p/go.mod -- +go 1.18 + +module example.com/p +-- p/p.go -- +package p + +func P() {} +-- q/go.mod -- +go 1.18 + +module example.com/q +-- q/q.go -- +package q + +func Q() {} +-- r/go.mod -- +go 1.18 + +module example.com/r +-- r/q.go -- +package r + +func R() {}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/work_sync_irrelevant_dependency.txt b/src/cmd/go/testdata/script/work_sync_irrelevant_dependency.txt new file mode 100644 index 0000000..072323d --- /dev/null +++ b/src/cmd/go/testdata/script/work_sync_irrelevant_dependency.txt @@ -0,0 +1,119 @@ +# Test of go work sync in a workspace in which some dependency needed by `a` +# appears at a lower version in the build list of `b`, but is not needed at all +# by `b` (so it should not be upgraded within b). +# +# a -> p 1.1 +# b -> q 1.0 -(through a test dependency)-> p 1.0 +go work sync +cmp a/go.mod a/want_go.mod +cmp b/go.mod b/want_go.mod + +-- go.work -- +go 1.18 + +use ( + ./a + ./b +) + +-- a/go.mod -- +go 1.18 + +module example.com/a + +require ( + example.com/p v1.1.0 +) + +replace ( + example.com/p => ../p +) +-- a/want_go.mod -- +go 1.18 + +module example.com/a + +require ( + example.com/p v1.1.0 +) + +replace ( + example.com/p => ../p +) +-- a/a.go -- +package a + +import ( + "example.com/p" +) + +func Foo() { + p.P() +} +-- b/go.mod -- +go 1.18 + +module example.com/b + +require ( + example.com/q v1.0.0 +) + +replace ( + example.com/q => ../q +) +-- b/want_go.mod -- +go 1.18 + +module example.com/b + +require ( + example.com/q v1.0.0 +) + +replace ( + example.com/q => ../q +) +-- b/b.go -- +package b + +import ( + "example.com/q" +) + +func Foo() { + q.Q() +} +-- p/go.mod -- +go 1.18 + +module example.com/p +-- p/p.go -- +package p + +func P() {} +-- q/go.mod -- +go 1.18 + +module example.com/q + +require ( + example.com/p v1.0.0 +) + +replace ( + example.com/p => ../p +) +-- q/q.go -- +package q + +func Q() { +} +-- q/q_test.go -- +package q + +import example.com/p + +func TestQ(t *testing.T) { + p.P() +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/work_sync_missing_module.txt b/src/cmd/go/testdata/script/work_sync_missing_module.txt new file mode 100644 index 0000000..0018c73 --- /dev/null +++ b/src/cmd/go/testdata/script/work_sync_missing_module.txt @@ -0,0 +1,12 @@ +# Ensure go work sync works without any modules in go.work. +go work sync + +# Ensure go work sync works even without a go.mod file. +rm go.mod +go work sync + +-- go.work -- +go 1.18 +-- go.mod -- +go 1.18 +module foo diff --git a/src/cmd/go/testdata/script/work_sync_relevant_dependency.txt b/src/cmd/go/testdata/script/work_sync_relevant_dependency.txt new file mode 100644 index 0000000..d799702 --- /dev/null +++ b/src/cmd/go/testdata/script/work_sync_relevant_dependency.txt @@ -0,0 +1,106 @@ +# Test of go work sync in a workspace in which some dependency in the build +# list of 'b' (but not otherwise needed by `b`, so not seen when lazy loading +# occurs) actually is relevant to `a`. +# +# a -> p 1.0 +# b -> q 1.1 -> p 1.1 +go work sync +cmp a/go.mod a/want_go.mod +cmp b/go.mod b/want_go.mod + +-- go.work -- +go 1.18 + +use ( + ./a + ./b +) + +-- a/go.mod -- +go 1.18 + +module example.com/a + +require ( + example.com/p v1.0.0 +) + +replace ( + example.com/p => ../p +) +-- a/want_go.mod -- +go 1.18 + +module example.com/a + +require example.com/p v1.1.0 + +replace example.com/p => ../p +-- a/a.go -- +package a + +import ( + "example.com/p" +) + +func Foo() { + p.P() +} +-- b/go.mod -- +go 1.18 + +module example.com/b + +require ( + example.com/q v1.1.0 +) + +replace ( + example.com/q => ../q +) +-- b/want_go.mod -- +go 1.18 + +module example.com/b + +require ( + example.com/q v1.1.0 +) + +replace ( + example.com/q => ../q +) +-- b/b.go -- +package b + +import ( + "example.com/q" +) + +func Foo() { + q.Q() +} +-- p/go.mod -- +go 1.18 + +module example.com/p +-- p/p.go -- +package p + +func P() {} +-- q/go.mod -- +go 1.18 + +module example.com/q + +require example.com/p v1.1.0 + +replace example.com/p => ../p +-- q/q.go -- +package q + +import example.com/p + +func Q() { + p.P() +} diff --git a/src/cmd/go/testdata/script/work_sync_sum.txt b/src/cmd/go/testdata/script/work_sync_sum.txt new file mode 100644 index 0000000..656fd31 --- /dev/null +++ b/src/cmd/go/testdata/script/work_sync_sum.txt @@ -0,0 +1,40 @@ +# Test that the sum file data state is properly reset between modules in +# go work sync so that the sum file that's written is correct. +# Exercises the fix to #50038. + +cp b/go.sum b/go.sum.want + +# As a sanity check, verify b/go.sum is tidy. +cd b +go mod tidy +cd .. +cmp b/go.sum b/go.sum.want + +# Run go work sync and verify it doesn't change b/go.sum. +go work sync +cmp b/go.sum b/go.sum.want + +-- b/go.sum -- +rsc.io/quote v1.0.0 h1:kQ3IZQzPTiDJxSZI98YaWgxFEhlNdYASHvh+MplbViw= +rsc.io/quote v1.0.0/go.mod h1:v83Ri/njykPcgJltBc/gEkJTmjTsNgtO1Y7vyIK1CQA= +-- go.work -- +go 1.18 +use ( + ./a + ./b +) +replace example.com/c => ./c +-- a/go.mod -- +module example.com/a +go 1.18 +require rsc.io/fortune v1.0.0 +-- a/a.go -- +package a +import "rsc.io/fortune" +-- b/go.mod -- +module example.com/b +go 1.18 +require rsc.io/quote v1.0.0 +-- b/b.go -- +package b +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/work_sync_toolchain.txt b/src/cmd/go/testdata/script/work_sync_toolchain.txt new file mode 100644 index 0000000..b752462 --- /dev/null +++ b/src/cmd/go/testdata/script/work_sync_toolchain.txt @@ -0,0 +1,45 @@ +# Create basic modules and work space. +env TESTGO_VERSION=go1.50 +mkdir m1_22_0 +go mod init -C m1_22_0 +go mod edit -C m1_22_0 -go=1.22.0 -toolchain=go1.99.0 +mkdir m1_22_1 +go mod init -C m1_22_1 +go mod edit -C m1_22_1 -go=1.22.1 -toolchain=go1.99.1 +mkdir m1_24_rc0 +go mod init -C m1_24_rc0 +go mod edit -C m1_24_rc0 -go=1.24rc0 -toolchain=go1.99.2 + +go work init ./m1_22_0 ./m1_22_1 +grep '^go 1.50$' go.work +! grep toolchain go.work + +# work sync with older modules should leave go 1.50 in the go.work. +go work sync +cat go.work +grep '^go 1.50$' go.work +! grep toolchain go.work + +# work sync with newer modules should update go 1.21 -> 1.22.1 and toolchain -> go1.22.9 in go.work +env TESTGO_VERSION=go1.21 +env TESTGO_VERSION_SWITCH=switch +go work edit -go=1.21 +grep '^go 1.21$' go.work +! grep toolchain go.work +env GOTOOLCHAIN=local +! go work sync +stderr '^go: cannot load module m1_22_0 listed in go.work file: m1_22_0'${/}'go.mod requires go >= 1.22.0 \(running go 1.21; GOTOOLCHAIN=local\)$' +stderr '^go: cannot load module m1_22_1 listed in go.work file: m1_22_1'${/}'go.mod requires go >= 1.22.1 \(running go 1.21; GOTOOLCHAIN=local\)$' +env GOTOOLCHAIN=auto +go work sync +stderr '^go: m1_22_1'${/}'go.mod requires go >= 1.22.1; switching to go1.22.9$' +grep '^go 1.22.1$' go.work +grep '^toolchain go1.22.9$' go.work + +# work sync with newer modules should update go 1.22.1 -> 1.24rc1 and drop toolchain +go work edit -use=./m1_24_rc0 +go work sync +stderr '^go: m1_24_rc0'${/}'go.mod requires go >= 1.24rc0; switching to go1.24rc1$' +cat go.work +grep '^go 1.24rc0$' go.work +grep '^toolchain go1.24rc1$' go.work diff --git a/src/cmd/go/testdata/script/work_use.txt b/src/cmd/go/testdata/script/work_use.txt new file mode 100644 index 0000000..7470899 --- /dev/null +++ b/src/cmd/go/testdata/script/work_use.txt @@ -0,0 +1,36 @@ +go work use -r foo +cmp go.work go.want_work_r + +! go work use other +stderr '^go: error reading other'${/}'go.mod: missing module declaration' + +go mod edit -C other -module=other +go work use other +cmp go.work go.want_work_other +-- go.work -- +go 1.18 + +use ( + foo + foo/bar // doesn't exist +) +-- go.want_work_r -- +go 1.18 + +use ( + ./foo + ./foo/bar/baz +) +-- go.want_work_other -- +go 1.18 + +use ( + ./foo + ./foo/bar/baz + ./other +) +-- foo/go.mod -- +module foo +-- foo/bar/baz/go.mod -- +module baz +-- other/go.mod -- diff --git a/src/cmd/go/testdata/script/work_use_deleted.txt b/src/cmd/go/testdata/script/work_use_deleted.txt new file mode 100644 index 0000000..b379cbc --- /dev/null +++ b/src/cmd/go/testdata/script/work_use_deleted.txt @@ -0,0 +1,22 @@ +go work use -r . +cmp go.work go.work.want + +-- go.work -- +go 1.18 + +use ( + . + ./sub + ./sub/dir/deleted +) +-- go.work.want -- +go 1.18 + +use ./sub/dir +-- sub/README.txt -- +A go.mod file has been deleted from this directory. +In addition, the entire subdirectory sub/dir/deleted +has been deleted, along with sub/dir/deleted/go.mod. +-- sub/dir/go.mod -- +module example/sub/dir +go 1.18 diff --git a/src/cmd/go/testdata/script/work_use_dot.txt b/src/cmd/go/testdata/script/work_use_dot.txt new file mode 100644 index 0000000..8f21042 --- /dev/null +++ b/src/cmd/go/testdata/script/work_use_dot.txt @@ -0,0 +1,49 @@ +cp go.work go.work.orig + +# If the current directory contains a go.mod file, +# 'go work use .' should add an entry for it. +cd bar/baz +go work use . +cmp ../../go.work ../../go.work.rel + +# If the current directory lacks a go.mod file, 'go work use .' +# should remove its entry. +mv go.mod go.mod.bak +go work use . +cmp ../../go.work ../../go.work.orig + +# If the path is absolute, it should remain absolute. +mv go.mod.bak go.mod +go work use $PWD +grep -count=1 '^use ' ../../go.work +grep '^use ["]?'$PWD'["]?$' ../../go.work + +# An absolute path should replace an entry for the corresponding relative path +# and vice-versa. +go work use . +cmp ../../go.work ../../go.work.rel +go work use $PWD +grep -count=1 '^use ' ../../go.work +grep '^use ["]?'$PWD'["]?$' ../../go.work + +# If both the absolute and relative paths are named, 'go work use' should error +# out: we don't know which one to use, and shouldn't add both because the +# resulting workspace would contain a duplicate module. +cp ../../go.work.orig ../../go.work +! go work use $PWD . +stderr '^go: already added "\./bar/baz" as "'$PWD'"$' +cmp ../../go.work ../../go.work.orig + + +-- go.mod -- +module example +go 1.18 +-- go.work -- +go 1.18 +-- go.work.rel -- +go 1.18 + +use ./bar/baz +-- bar/baz/go.mod -- +module example/bar/baz +go 1.18 diff --git a/src/cmd/go/testdata/script/work_use_issue50958.txt b/src/cmd/go/testdata/script/work_use_issue50958.txt new file mode 100644 index 0000000..7a25531 --- /dev/null +++ b/src/cmd/go/testdata/script/work_use_issue50958.txt @@ -0,0 +1,17 @@ +go work use -r . +cmp go.work go.work.want + +-- go.mod -- +module example +go 1.18 +-- go.work -- +go 1.18 + +use sub +-- go.work.want -- +go 1.18 + +use . +-- sub/README.txt -- +This directory no longer contains a go.mod file. + diff --git a/src/cmd/go/testdata/script/work_use_issue55952.txt b/src/cmd/go/testdata/script/work_use_issue55952.txt new file mode 100644 index 0000000..befec67 --- /dev/null +++ b/src/cmd/go/testdata/script/work_use_issue55952.txt @@ -0,0 +1,11 @@ +! go list . +stderr '^go: cannot load module y listed in go\.work file: open y'${/}'go\.mod:' + +-- go.work -- +use ./y +-- x/go.mod -- +module x + +go 1.19 +-- x/m.go -- +package m diff --git a/src/cmd/go/testdata/script/work_use_only_dirs.txt b/src/cmd/go/testdata/script/work_use_only_dirs.txt new file mode 100644 index 0000000..5d0fcdd --- /dev/null +++ b/src/cmd/go/testdata/script/work_use_only_dirs.txt @@ -0,0 +1,17 @@ +! go work use foo bar baz + +stderr '^go: foo is not a directory' +stderr '^go: directory baz does not exist' +cmp go.work go.work_want + +! go work use -r qux +stderr '^go: qux is not a directory' + +-- go.work -- +go 1.18 +-- go.work_want -- +go 1.18 +-- foo -- +-- qux -- +-- bar/go.mod -- +module bar diff --git a/src/cmd/go/testdata/script/work_use_toolchain.txt b/src/cmd/go/testdata/script/work_use_toolchain.txt new file mode 100644 index 0000000..bb3db9c --- /dev/null +++ b/src/cmd/go/testdata/script/work_use_toolchain.txt @@ -0,0 +1,51 @@ +# Create basic modules and work space. +env TESTGO_VERSION=go1.50 +mkdir m1_22_0 +go mod init -C m1_22_0 +go mod edit -C m1_22_0 -go=1.22.0 -toolchain=go1.99.0 +mkdir m1_22_1 +go mod init -C m1_22_1 +go mod edit -C m1_22_1 -go=1.22.1 -toolchain=go1.99.1 +mkdir m1_24_rc0 +go mod init -C m1_24_rc0 +go mod edit -C m1_24_rc0 -go=1.24rc0 -toolchain=go1.99.2 + +go work init +grep '^go 1.50$' go.work +! grep toolchain go.work + +# work use with older modules should leave go 1.50 in the go.work. +go work use ./m1_22_0 +grep '^go 1.50$' go.work +! grep toolchain go.work + +# work use with newer modules should bump go and toolchain, +# including updating to a newer toolchain as needed. +env TESTGO_VERSION=go1.21 +env TESTGO_VERSION_SWITCH=switch +rm go.work +go work init +env GOTOOLCHAIN=local +! go work use ./m1_22_0 +stderr '^go: m1_22_0'${/}'go.mod requires go >= 1.22.0 \(running go 1.21; GOTOOLCHAIN=local\)$' +env GOTOOLCHAIN=auto +go work use ./m1_22_0 +stderr '^go: m1_22_0'${/}'go.mod requires go >= 1.22.0; switching to go1.22.9$' +grep '^go 1.22.0$' go.work +grep '^toolchain go1.22.9$' go.work + +# work use with an even newer module should bump go again. +go work use ./m1_22_1 +! stderr switching +grep '^go 1.22.1$' go.work +grep '^toolchain go1.22.9$' go.work # unchanged + +# work use with an even newer module should bump go and toolchain again. +env GOTOOLCHAIN=go1.22.9 +! go work use ./m1_24_rc0 +stderr '^go: m1_24_rc0'${/}'go.mod requires go >= 1.24rc0 \(running go 1.22.9; GOTOOLCHAIN=go1.22.9\)$' +env GOTOOLCHAIN=auto +go work use ./m1_24_rc0 +stderr '^go: m1_24_rc0'${/}'go.mod requires go >= 1.24rc0; switching to go1.24rc1$' +grep '^go 1.24rc0$' go.work +grep '^toolchain go1.24rc1$' go.work diff --git a/src/cmd/go/testdata/script/work_vendor_empty.txt b/src/cmd/go/testdata/script/work_vendor_empty.txt new file mode 100644 index 0000000..3c0c7ed --- /dev/null +++ b/src/cmd/go/testdata/script/work_vendor_empty.txt @@ -0,0 +1,16 @@ +go work vendor +stderr 'go: no dependencies to vendor' +! exists vendor/modules.txt +! go list . +stderr 'go: no modules were found in the current workspace' +mkdir vendor +mv bad_modules.txt vendor/modules.txt +! go list . +stderr 'go: no modules were found in the current workspace' + +-- bad_modules.txt -- +# a/module +a/package +-- go.work -- +go 1.21 + diff --git a/src/cmd/go/testdata/script/work_vendor_main_module_replaced.txt b/src/cmd/go/testdata/script/work_vendor_main_module_replaced.txt new file mode 100644 index 0000000..70446c7 --- /dev/null +++ b/src/cmd/go/testdata/script/work_vendor_main_module_replaced.txt @@ -0,0 +1,46 @@ +# This is a test that if one of the main modules replaces the other +# the vendor consistency checks still pass. The replacement is ignored +# because it is of a main module, but it is still recorded in +# vendor/modules.txt. + +go work vendor +go list all # make sure the consistency checks pass +! stderr . + +# Removing the replace causes consistency checks to fail +cp a_go_mod_no_replace a/go.mod +! go list all # consistency checks fail +stderr 'example.com/b@v0.0.0: is marked as replaced in vendor/modules.txt, but not replaced in the workspace' + + +-- a_go_mod_no_replace -- +module example.com/a + +go 1.21 + +require example.com/b v0.0.0 +-- go.work -- +go 1.21 + +use ( + a + b +) +-- a/go.mod -- +module example.com/a + +go 1.21 + +require example.com/b v0.0.0 + +replace example.com/b => ../b +-- a/a.go -- +package a + +import _ "example.com/b" +-- b/go.mod -- +module example.com/b + +go 1.21 +-- b/b.go -- +package b
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/work_vendor_modules_txt_conditional.txt b/src/cmd/go/testdata/script/work_vendor_modules_txt_conditional.txt new file mode 100644 index 0000000..3d671eb --- /dev/null +++ b/src/cmd/go/testdata/script/work_vendor_modules_txt_conditional.txt @@ -0,0 +1,62 @@ +# This test checks to see if we only start in workspace vendor +# mode if the modules.txt specifies ## workspace (and only in +# standard vendor if it doesn't). + +# vendor directory produced for workspace, workspace mode +# runs in mod=vendor +go work vendor +cmp vendor/modules.txt want_workspace_modules_txt +go list -f {{.Dir}} example.com/b +stdout $GOPATH[\\/]src[\\/]vendor[\\/]example.com[\\/]b + +# vendor directory produced for workspace, module mode +# runs in mod=readonly +env GOWORK=off +go list -f {{.Dir}} example.com/b +stdout $GOPATH[\\/]src[\\/]b + +# vendor directory produced for module, module mode +# runs in mod=vendor +go mod vendor +cmp vendor/modules.txt want_module_modules_txt +go list -f {{.Dir}} example.com/b +stdout $GOPATH[\\/]src[\\/]vendor[\\/]example.com[\\/]b + +# vendor directory produced for module, workspace mode +# runs in mod=readonly +env GOWORK= +go list -f {{.Dir}} example.com/b +stdout $GOPATH[\\/]src[\\/]b + +-- want_workspace_modules_txt -- +## workspace +# example.com/b v0.0.0 => ./b +## explicit; go 1.21 +example.com/b +# example.com/b => ./b +-- want_module_modules_txt -- +# example.com/b v0.0.0 => ./b +## explicit; go 1.21 +example.com/b +# example.com/b => ./b +-- go.work -- +go 1.21 + +use . +-- go.mod -- +module example.com/a + +go 1.21 + +require example.com/b v0.0.0 +replace example.com/b => ./b +-- a.go -- +package a + +import _ "example.com/b" +-- b/go.mod -- +module example.com/b + +go 1.21 +-- b/b.go -- +package b
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/work_vendor_modules_txt_consistent.txt b/src/cmd/go/testdata/script/work_vendor_modules_txt_consistent.txt new file mode 100644 index 0000000..bc0f068 --- /dev/null +++ b/src/cmd/go/testdata/script/work_vendor_modules_txt_consistent.txt @@ -0,0 +1,141 @@ +go work vendor +cmp modules.txt.want vendor/modules.txt +go list example.com/a example.com/b + +# Module required in go.mod but not marked explicit in modules.txt +cp modules.txt.required_but_not_explicit vendor/modules.txt +! go list example.com/a example.com/b +cmpenv stderr required_but_not_explicit_error.txt + +# Replacement in go.mod but no replacement in modules.txt +cp modules.txt.missing_replacement vendor/modules.txt +! go list example.com/a example.com/b +cmpenv stderr missing_replacement_error.txt + +# Replacement in go.mod but different replacement target in modules.txt +cp modules.txt.different_replacement vendor/modules.txt +! go list example.com/a example.com/b +cmpenv stderr different_replacement_error.txt + +# Module marked explicit in modules.txt but not required in go.mod +cp modules.txt.extra_explicit vendor/modules.txt +! go list example.com/a example.com/b +cmpenv stderr extra_explicit_error.txt + +# Replacement in modules.txt but not in go.mod +cp modules.txt.extra_replacement vendor/modules.txt +! go list example.com/a example.com/b +cmpenv stderr extra_replacement_error.txt + +-- modules.txt.want -- +## workspace +# example.com/p v1.0.0 => ./p +## explicit; go 1.21 +# example.com/q v1.0.0 => ./q +## explicit; go 1.21 +-- modules.txt.required_but_not_explicit -- +## workspace +# example.com/p v1.0.0 => ./p +## go 1.21 +# example.com/q v1.0.0 => ./q +## explicit; go 1.21 +-- required_but_not_explicit_error.txt -- +go: inconsistent vendoring in $GOPATH${/}src: + example.com/p@v1.0.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt + + To ignore the vendor directory, use -mod=readonly or -mod=mod. + To sync the vendor directory, run: + go work vendor +-- modules.txt.missing_replacement -- +## workspace +# example.com/p v1.0.0 +## explicit; go 1.21 +# example.com/q v1.0.0 => ./q +## explicit; go 1.21 +-- missing_replacement_error.txt -- +go: inconsistent vendoring in $GOPATH${/}src: + example.com/p@v1.0.0: is replaced in a${/}go.mod, but not marked as replaced in vendor/modules.txt + + To ignore the vendor directory, use -mod=readonly or -mod=mod. + To sync the vendor directory, run: + go work vendor +-- modules.txt.different_replacement -- +## workspace +# example.com/p v1.0.0 => ./r +## explicit; go 1.21 +# example.com/q v1.0.0 => ./q +## explicit; go 1.21 +-- different_replacement_error.txt -- +go: inconsistent vendoring in $GOPATH${/}src: + example.com/p@v1.0.0: is replaced by ../p in a${/}go.mod, but marked as replaced by ./r in vendor/modules.txt + + To ignore the vendor directory, use -mod=readonly or -mod=mod. + To sync the vendor directory, run: + go work vendor +-- modules.txt.extra_explicit -- +## workspace +# example.com/p v1.0.0 => ./p +## explicit; go 1.21 +# example.com/q v1.0.0 => ./q +## explicit; go 1.21 +# example.com/r v1.0.0 +example.com/r +## explicit; go 1.21 +-- extra_explicit_error.txt -- +go: inconsistent vendoring in $GOPATH${/}src: + example.com/r@v1.0.0: is marked as explicit in vendor/modules.txt, but not explicitly required in a go.mod + + To ignore the vendor directory, use -mod=readonly or -mod=mod. + To sync the vendor directory, run: + go work vendor +-- modules.txt.extra_replacement -- +## workspace +# example.com/p v1.0.0 => ./p +## explicit; go 1.21 +# example.com/q v1.0.0 => ./q +## explicit; go 1.21 +# example.com/r v1.0.0 => ./r +example.com/r +## go 1.21 +-- extra_replacement_error.txt -- +go: inconsistent vendoring in $GOPATH${/}src: + example.com/r@v1.0.0: is marked as replaced in vendor/modules.txt, but not replaced in the workspace + + To ignore the vendor directory, use -mod=readonly or -mod=mod. + To sync the vendor directory, run: + go work vendor +-- go.work -- +go 1.21 + +use ( + ./a + ./b +) +-- a/go.mod -- +module example.com/a + +go 1.21 + +require example.com/p v1.0.0 + +replace example.com/p v1.0.0 => ../p +-- a/a.go -- +package p +-- b/go.mod -- +module example.com/b + +go 1.21 + +require example.com/q v1.0.0 + +replace example.com/q v1.0.0 => ../q +-- b/b.go -- +package b +-- p/go.mod -- +module example.com/p + +go 1.21 +-- q/go.mod -- +module example.com/q + +go 1.21 diff --git a/src/cmd/go/testdata/script/work_vendor_prune.txt b/src/cmd/go/testdata/script/work_vendor_prune.txt new file mode 100644 index 0000000..424b4d5 --- /dev/null +++ b/src/cmd/go/testdata/script/work_vendor_prune.txt @@ -0,0 +1,116 @@ +# This test exercises that vendoring works properly using the workspace in the +# the work_prune test case. + +go work vendor +cmp vendor/modules.txt modules.txt.want +cmp vendor/example.com/b/b.go b/b.go +cmp vendor/example.com/q/q.go q1_1_0/q.go +go list -m -f '{{.Version}}' example.com/q +stdout '^v1.1.0$' + +go list -f '{{.Dir}}' example.com/q +stdout $GOPATH[\\/]src[\\/]vendor[\\/]example.com[\\/]q +go list -f '{{.Dir}}' example.com/b +stdout $GOPATH[\\/]src[\\/]vendor[\\/]example.com[\\/]b + +[short] skip + +rm b +rm q1_0_0 +rm q1_1_0 +go run example.com/p +stdout 'version 1.1.0' + +-- modules.txt.want -- +## workspace +# example.com/b v1.0.0 => ./b +## explicit; go 1.18 +example.com/b +# example.com/q v1.0.0 => ./q1_0_0 +## explicit; go 1.18 +# example.com/q v1.1.0 => ./q1_1_0 +## go 1.18 +example.com/q +-- go.work -- +go 1.18 + +use ( + ./a + ./p +) +-- a/go.mod -- +module example.com/a + +go 1.18 + +require example.com/b v1.0.0 + +replace example.com/b v1.0.0 => ../b +-- a/foo.go -- +package main + +import "example.com/b" + +func main() { + b.B() +} +-- b/go.mod -- +module example.com/b + +go 1.18 + +require example.com/q v1.1.0 +-- b/b.go -- +package b + +func B() { +} +-- b/b_test.go -- +package b + +import "example.com/q" + +func TestB() { + q.PrintVersion() +} +-- p/go.mod -- +module example.com/p + +go 1.18 + +require example.com/q v1.0.0 + +replace example.com/q v1.0.0 => ../q1_0_0 +replace example.com/q v1.1.0 => ../q1_1_0 +-- p/main.go -- +package main + +import "example.com/q" + +func main() { + q.PrintVersion() +} +-- q1_0_0/go.mod -- +module example.com/q + +go 1.18 +-- q1_0_0/q.go -- +package q + +import "fmt" + +func PrintVersion() { + fmt.Println("version 1.0.0") +} +-- q1_1_0/go.mod -- +module example.com/q + +go 1.18 +-- q1_1_0/q.go -- +package q + +import "fmt" + +func PrintVersion() { + fmt.Println("version 1.1.0") +} diff --git a/src/cmd/go/testdata/script/work_vendor_prune_all.txt b/src/cmd/go/testdata/script/work_vendor_prune_all.txt new file mode 100644 index 0000000..a369d22 --- /dev/null +++ b/src/cmd/go/testdata/script/work_vendor_prune_all.txt @@ -0,0 +1,201 @@ +# This test exercises that vendoring works properly using the workspace in the +# the work_prune test case. + +go work vendor +cmp vendor/modules.txt modules.txt.want +go list -f '{{with .Module}}{{.Path}}@{{.Version}}{{end}}' all +cmp stdout want_versions + +go list -f '{{.Dir}}' example.com/q +stdout $GOPATH[\\/]src[\\/]vendor[\\/]example.com[\\/]q +go list -f '{{.Dir}}' example.com/b +stdout $GOPATH[\\/]src[\\/]vendor[\\/]example.com[\\/]b +go list -f '{{.Dir}}' example.com/w +stdout $GOPATH[\\/]src[\\/]vendor[\\/]example.com[\\/]w +go list -f '{{.Dir}}' example.com/z +stdout $GOPATH[\\/]src[\\/]vendor[\\/]example.com[\\/]z + +cmp $GOPATH/src/vendor/example.com/q/q.go q1_1_0/q.go + +-- modules.txt.want -- +## workspace +# example.com/b v1.0.0 => ./b +## explicit; go 1.18 +example.com/b +# example.com/q v1.0.0 => ./q1_0_0 +## explicit; go 1.18 +# example.com/q v1.1.0 => ./q1_1_0 +## go 1.18 +example.com/q +# example.com/w v1.0.0 => ./w +## go 1.18 +example.com/w +# example.com/z v1.0.0 => ./z1_0_0 +## explicit; go 1.18 +# example.com/z v1.1.0 => ./z1_1_0 +## go 1.18 +example.com/z +# example.com/q v1.0.5 => ./q1_0_5 +# example.com/r v1.0.0 => ./r +# example.com/x v1.0.0 => ./x +# example.com/y v1.0.0 => ./y +-- want_versions -- +example.com/a@ +example.com/b@v1.0.0 +example.com/p@ +example.com/q@v1.1.0 +example.com/w@v1.0.0 +example.com/z@v1.1.0 +-- go.work -- +go 1.18 + +use ( + ./a + ./p +) + +replace example.com/b v1.0.0 => ./b +replace example.com/q v1.0.0 => ./q1_0_0 +replace example.com/q v1.0.5 => ./q1_0_5 +replace example.com/q v1.1.0 => ./q1_1_0 +replace example.com/r v1.0.0 => ./r +replace example.com/w v1.0.0 => ./w +replace example.com/x v1.0.0 => ./x +replace example.com/y v1.0.0 => ./y +replace example.com/z v1.0.0 => ./z1_0_0 +replace example.com/z v1.1.0 => ./z1_1_0 + +-- a/go.mod -- +module example.com/a + +go 1.18 + +require example.com/b v1.0.0 +require example.com/z v1.0.0 +-- a/foo.go -- +package main + +import "example.com/b" + +func main() { + b.B() +} +-- b/go.mod -- +module example.com/b + +go 1.18 + +require example.com/q v1.1.0 +-- b/b.go -- +package b + +func B() { +} +-- p/go.mod -- +module example.com/p + +go 1.18 + +require example.com/q v1.0.0 + +replace example.com/q v1.0.0 => ../q1_0_0 +replace example.com/q v1.1.0 => ../q1_1_0 +-- p/main.go -- +package main + +import "example.com/q" + +func main() { + q.PrintVersion() +} +-- q1_0_0/go.mod -- +module example.com/q + +go 1.18 +-- q1_0_0/q.go -- +package q + +import "fmt" + +func PrintVersion() { + fmt.Println("version 1.0.0") +} +-- q1_0_5/go.mod -- +module example.com/q + +go 1.18 + +require example.com/r v1.0.0 +-- q1_0_5/q.go -- +package q + +import _ "example.com/r" +-- q1_1_0/go.mod -- +module example.com/q + +require example.com/w v1.0.0 +require example.com/z v1.1.0 + +go 1.18 +-- q1_1_0/q.go -- +package q + +import _ "example.com/w" +import _ "example.com/z" + +import "fmt" + +func PrintVersion() { + fmt.Println("version 1.1.0") +} +-- r/go.mod -- +module example.com/r + +go 1.18 + +require example.com/r v1.0.0 +-- r/r.go -- +package r +-- w/go.mod -- +module example.com/w + +go 1.18 + +require example.com/x v1.0.0 +-- w/w.go -- +package w +-- w/w_test.go -- +package w + +import _ "example.com/x" +-- x/go.mod -- +module example.com/x + +go 1.18 +-- x/x.go -- +package x +-- x/x_test.go -- +package x +import _ "example.com/y" +-- y/go.mod -- +module example.com/y + +go 1.18 +-- y/y.go -- +package y +-- z1_0_0/go.mod -- +module example.com/z + +go 1.18 + +require example.com/q v1.0.5 +-- z1_0_0/z.go -- +package z + +import _ "example.com/q" +-- z1_1_0/go.mod -- +module example.com/z + +go 1.18 +-- z1_1_0/z.go -- +package z diff --git a/src/cmd/go/testdata/script/work_vet.txt b/src/cmd/go/testdata/script/work_vet.txt new file mode 100644 index 0000000..f95cadd --- /dev/null +++ b/src/cmd/go/testdata/script/work_vet.txt @@ -0,0 +1,19 @@ +! go vet ./a +stderr 'fmt.Println call has possible Printf formatting directive' + +-- go.work -- +go 1.18 + +use ./a +-- a/go.mod -- +module example.com/a + +go 1.18 +-- a/a.go -- +package a + +import "fmt" + +func A() { + fmt.Println("%s") +}
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/work_why_download_graph.txt b/src/cmd/go/testdata/script/work_why_download_graph.txt new file mode 100644 index 0000000..8f1aedd --- /dev/null +++ b/src/cmd/go/testdata/script/work_why_download_graph.txt @@ -0,0 +1,65 @@ +# Test go mod download, why, and graph work in workspace mode. +# TODO(bcmills): clarify the interaction with #44435 + +go mod download rsc.io/quote +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.info +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.mod +grep '^rsc\.io/quote v1\.5\.2/go\.mod h1:' go.work.sum +grep '^rsc\.io/quote v1\.5\.2 h1:' go.work.sum + +go clean -modcache +rm go.work.sum +go mod download +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.info +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.mod +grep '^rsc\.io/quote v1\.5\.2/go\.mod h1:' go.work.sum +grep '^rsc\.io/quote v1\.5\.2 h1:' go.work.sum + +go mod why rsc.io/quote +stdout '# rsc.io/quote\nexample.com/a\nrsc.io/quote' + +go mod graph +stdout 'example.com/a rsc.io/quote@v1.5.2\nexample.com/b example.com/c@v1.0.0\nrsc.io/quote@v1.5.2 rsc.io/sampler@v1.3.0\nrsc.io/sampler@v1.3.0 golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c' + +-- go.work -- +go 1.18 + +use ( + ./a + ./b +) +-- a/go.mod -- +go 1.18 + +module example.com/a + +require "rsc.io/quote" v1.5.2 +-- a/main.go -- +package main + +import ( + "fmt" + "rsc.io/quote" +) + +func main() { + fmt.Println(quote.Hello()) +} +-- b/go.mod -- +go 1.18 + +module example.com/b + +require example.com/c v1.0.0 +replace example.com/c => ../c +-- c/go.mod -- +go 1.18 + +module example.com/c + |