# 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


# 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



-- 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.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.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
)
-- 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
