# These steps validate we get a proper error
# if we try to fuzz a module using GOFLAGS=-mod=vendor.
# It then stops.

# For the future, we have some unexecuted steps after the stop.
# These don't run now, but attempt to validate fuzzing a module using -mod=vendor,
# including validating that the actual code in the 'vendor' directory is used.

# TODO: -mod=vendor is not yet supported with go-fuzz, so the majority of this test is disabled with a 'stop' command.
# If you change go-fuzz-build to remove the check for -mod=vendor, it currently fails with error:
#    > exec go-fuzz-build -func=FuzzDependOnVendor
#    [stderr]
#    could not load packages: go [list -e -json -compiled=true -test=false -export=false -deps=true -find=false -tags gofuzz -- . 
#      github.com/dvyukov/go-fuzz/go-fuzz-dep]: exit status 1: build github.com/dvyukov/go-fuzz/go-fuzz-dep: 
#      cannot load github.com/dvyukov/go-fuzz/go-fuzz-dep: 
#      open $WORK\foo\vendor\github.com\dvyukov\go-fuzz\go-fuzz-dep: The system cannot find the path specified.

# TODO: this test currently relies on latest go-fuzz/go-fuzz-dep and go-fuzz-defs
# versions on master being downloaded from github as part of the tests.
# If this test is run in a go-fuzz branch and there have been signficant
# changes to go-fuzz/go-fuzz-dep and go-fuzz-defs in the branch, this test 
# will use the versions from master and might incorrectly fail.
# If that happens, the foo/go.mod below can temporarily be modified to point 
# to the branch, or this test can temporarily be ignored or removed.

# Enter a module that has a vendor directory, where the code in the vendor
# directory has been edited compared (so that we can validate the vendored
# code is in fact used).
# Note that we are outside of GOPATH, so the presence of the 'go.mod' here will
# enable module-module for cmd/go (which is true in Go 1.11-1.13, and likely will be true in 1.14 as well).
cd foo 

# Sanity check the module seems well formed.
exec go list -m all
stdout '^example.com/foo$'
stdout '^example.com/bar v0.0.0 => ../bar$'
exec go build

# Do an intial 'go mod vendor'
exec go mod vendor

# Overwrite the original bar with bad code that will not compile,
# while leaving the vendored version of bar alone 
# so that vendored code still compiles.
cp ../bar/bar.go_BAD ../bar/bar.go 

# Sanity check the good code compiles, and bad code fails.
# Successful compilation here relies on -mod=vendor being enabled.
env GOFLAGS=-mod=vendor
exec go build
env GOFLAGS=
! exec go build

# Validate we get the expected error if we try to run go-fuzz-build
# with -mod=vendor in GOFLAGS.
env GOFLAGS=-mod=vendor
! exec go-fuzz-build -func=FuzzDependOnVendor
stderr 'GOFLAGS with -mod=vendor is not supported'
env GOFLAGS='-v -mod=vendor'
! exec go-fuzz-build -func=FuzzDependOnVendor
stderr 'GOFLAGS with -mod=vendor is not supported'

# This is as far as we can currently go here, given go-fuzz does not support -mod=vendor.
# The remainder of the test has never passed, but we will leave here in case useful
# in the future. The rest of the tests are set to pass as if GOFLAGS=-mod=vendor worked,
# but they have never run, so might have a typo or other mistake.
stop 'do not run actual vendoring test. -mod=vendor not yet supported.'

# Ask go-fuzz-build to build, specifying the fuzz function for foo.
# First, we rely on -mod=vendor being set.
env GOFLAGS=-mod=vendor
exec go-fuzz-build -func=FuzzDependOnVendor
exists foo-fuzz.zip

# Validate we can start fuzzing.
# Note that 'timeout(1)' will error here, so we preface the invocation with '!'.
# For travis on Windows, we install 'timeout(1)' as part of our travis setup steps.
# To test this locally on Windows, you might need to change 'timeout' to '\cygwin64\bin\timeout' or similar.
! exec timeout 5 go-fuzz -procs=1 -func=FuzzUsingVendor
stderr 'workers: \d+, corpus: '

# Ask go-fuzz-build to build again, but now we do not specify -mod=vendor, 
# which results in a compilation failure because the non-vendored code
# deliberately does not compile (as a way to validate we are using the vendored code above).
env GOFLAGS=
rm foo-fuzz.zip
! exec go-fuzz-build
! exists foo-fuzz.zip

# Define two modules.
# example.com/foo has a fuzz function, and depends on example.com/bar.
# foo has vendored bar and (in theory) made a code change inside foo's vendor 
# directory. The bar code inside foo's vendor compiles, but the original
# bar code does not compile.
# The go.mod files set 'go 1.13' to avoid triggering the Go 1.14 auto
# detection of a vendor directory.

-- foo/fuzz.go --
package foo

import "example.com/bar"

func FuzzUsingVendor(data []byte) int {
	bar.Bar()
	return 0
}

-- foo/go.mod --
module example.com/foo

go 1.13

require (
    example.com/bar v0.0.0
    github.com/dvyukov/go-fuzz latest
)

replace example.com/bar => ../bar

-- bar/bar.go_BAD --
package bar

// This will not compile.
func BarWillNotCompile() string {

}

-- bar/bar.go --
package bar

// This compiles.
func Bar() string {
	return "hello from bar"
}

-- bar/go.mod --
module example.com/bar

go 1.13
