[!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 sucess 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 sucess 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")
