diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cmd/go/testdata/script/test_fuzz.txt | 37 | ||||
| -rw-r--r-- | src/testing/fuzz.go | 33 |
2 files changed, 44 insertions, 26 deletions
diff --git a/src/cmd/go/testdata/script/test_fuzz.txt b/src/cmd/go/testdata/script/test_fuzz.txt index 8f3242dc5e..2a3e6e26c7 100644 --- a/src/cmd/go/testdata/script/test_fuzz.txt +++ b/src/cmd/go/testdata/script/test_fuzz.txt @@ -57,16 +57,22 @@ stdout 'f.Fuzz function' stdout FAIL stdout 'f.Fuzz function' -# Test that multiple calls to f.Fuzz causes a non-zero exit status. -! go test multiple_fuzz_calls_fuzz_test.go -! stdout ^ok -stdout FAIL +# Test that a call to f.Fatal after the Fuzz func is never 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 @@ -161,8 +167,8 @@ func Fuzz(f *testing.F) { }) } --- multiple_fuzz_calls_fuzz_test.go -- -package multiple_fuzz_calls_fuzz +-- fatal_after_fuzz_func_fuzz_test.go -- +package fatal_after_fuzz_func_fuzz import "testing" @@ -170,10 +176,7 @@ func Fuzz(f *testing.F) { f.Fuzz(func(t *testing.T, b []byte) { // no-op }) - - f.Fuzz(func(t *testing.T, b []byte) { - // this second call should panic - }) + f.Fatal("this shouldn't be called") } -- incomplete_fuzz_call_fuzz_test.go -- @@ -187,6 +190,20 @@ func Fuzz(f *testing.F) { }) } +-- 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 diff --git a/src/testing/fuzz.go b/src/testing/fuzz.go index 01895e8d7d..11bbd8fb16 100644 --- a/src/testing/fuzz.go +++ b/src/testing/fuzz.go @@ -9,6 +9,7 @@ import ( "flag" "fmt" "os" + "runtime" "time" ) @@ -28,12 +29,11 @@ type InternalFuzzTarget struct { // F is a type passed to fuzz targets for fuzz testing. type F struct { common - context *fuzzContext - corpus []corpusEntry // corpus is the in-memory corpus - result FuzzResult // result is the result of running the fuzz target - fuzzFunc func(f *F) // fuzzFunc is the function which makes up the fuzz target - fuzz bool // fuzz indicates whether the fuzzing engine should run - fuzzCalled bool // fuzzCalled indicates whether f.Fuzz has been called for this target + context *fuzzContext + corpus []corpusEntry // corpus is the in-memory corpus + result FuzzResult // result is the result of running the fuzz target + fuzzFunc func(f *F) // fuzzFunc is the function which makes up the fuzz target + fuzz bool // fuzz indicates whether the fuzzing engine should run } // corpus corpusEntry @@ -61,21 +61,20 @@ func (f *F) Add(args ...interface{}) { } } -// Fuzz runs the fuzz function, ff, for fuzz testing. It runs ff in a separate -// goroutine. Only the first call to Fuzz will be executed, and any subsequent -// calls will panic. If ff fails for a set of arguments, those arguments will be -// added to the seed corpus. +// Fuzz runs the fuzz function, ff, for fuzz testing. If ff fails for a set of +// arguments, those arguments will be added to the seed corpus. +// +// This is a terminal function which will terminate the currently running fuzz +// target by calling runtime.Goexit. To run any code after this function, use +// Cleanup. func (f *F) Fuzz(ff interface{}) { - if f.fuzzCalled { - panic("testing: found more than one call to Fuzz, will skip") - } - f.fuzzCalled = true - fn, ok := ff.(func(*T, []byte)) if !ok { panic("testing: Fuzz function must have type func(*testing.T, []byte)") } + defer runtime.Goexit() // exit after this function + var errStr string run := func(t *T, b []byte) { defer func() { @@ -118,6 +117,7 @@ func (f *F) Fuzz(ff interface{}) { errStr += string(t.output) } } + f.finished = true if f.Failed() { f.result = FuzzResult{Error: errors.New(errStr)} return @@ -169,12 +169,13 @@ func (f *F) runTarget(fn func(*F)) { } if err != nil { f.Fail() - f.result = FuzzResult{Error: fmt.Errorf("%s", err)} + f.result = FuzzResult{Error: fmt.Errorf(" %s", err)} } f.report() f.setRan() f.signal <- true // signal that the test has finished }() + defer f.runCleanup(normalPanic) fn(f) f.finished = true } |
