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' 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' without arguments implicitly operates on the main module, and thus
# should fail.
! go get
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
! go get -u
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
! go get -u ./needmod
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'

# 'go get -u all' upgrades the transitive import graph of the main module,
# which is empty.
! go get -u all
stderr '^go get: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'

# 'go get' should check the proposed module graph for consistency,
# even though we won't write it anywhere.
! go get -d example.com/printversion@v1.0.0 example.com/version@none
stderr '^go get: example.com/printversion@v1.0.0 requires example.com/version@v1.0.0, not example.com/version@none$'

# 'go get -d' should download and extract the source code needed to build the requested version.
rm -r $GOPATH/pkg/mod/example.com
go get -d example.com/printversion@v1.0.0
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 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 install: version is required 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 install' should succeed with a package in GOROOT.
go install cmd/addr2line
! stderr .

# 'go run' with a verison should fail due to syntax.
! go run example.com/printversion@v1.0.0
stderr 'can only use path@version syntax with'

# '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 get' of a binary without a go.mod should install the requested version,
# resolving outside dependencies to the latest available versions.
go get example.com/printversion@v0.1.0
exec ../bin/printversion
stdout 'path is example.com/printversion'
stdout 'main is example.com/printversion v0.1.0'
stdout 'using example.com/version v1.1.0'

# 'go get' of a versioned binary should build and install the latest version
# using its minimal required modules, ignoring replacements and exclusions.
go get example.com/printversion
exec ../bin/printversion
stdout 'path is example.com/printversion'
stdout 'main is example.com/printversion v1.0.0'
stdout 'using example.com/version v1.0.0'

# 'go get -u=patch' should patch dependencies before installing,
# again ignoring replacements and exclusions.
go get -u=patch example.com/printversion@v1.0.0
exec ../bin/printversion
stdout 'path is example.com/printversion'
stdout 'main is example.com/printversion v1.0.0'
stdout 'using example.com/version v1.0.1'

# '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 command-line-arguments \(devel\)'

# '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")
}

