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
})
}
--- 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"
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 --
})
}
+-- 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
"flag"
"fmt"
"os"
+ "runtime"
"time"
)
// 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
}
}
-// 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() {
errStr += string(t.output)
}
}
+ f.finished = true
if f.Failed() {
f.result = FuzzResult{Error: errors.New(errStr)}
return
}
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
}