diff options
Diffstat (limited to 'src/testing/fuzz.go')
| -rw-r--r-- | src/testing/fuzz.go | 147 |
1 files changed, 22 insertions, 125 deletions
diff --git a/src/testing/fuzz.go b/src/testing/fuzz.go index d5cb5e853f..10665168f4 100644 --- a/src/testing/fuzz.go +++ b/src/testing/fuzz.go @@ -57,6 +57,10 @@ type InternalFuzzTarget struct { // call F.Fuzz once to provide a fuzz function. See the testing package // documentation for an example, and see the F.Fuzz and F.Add method // documentation for details. +// +// *F methods can only be called before (*F).Fuzz. Once inside the function +// passed to (*F).Fuzz, only (*T) methods can be used. The only *F methods that +// are allowed in the (*F).Fuzz function are (*F).Failed and (*F).Name. type F struct { common fuzzContext *fuzzContext @@ -88,78 +92,6 @@ type corpusEntry = struct { IsSeed bool } -// Cleanup registers a function to be called after the fuzz function has been -// called on all seed corpus entries, and after fuzzing completes (if enabled). -// Cleanup functions will be called in last added, first called order. -func (f *F) Cleanup(fn func()) { - if f.inFuzzFn { - panic("testing: f.Cleanup was called inside the f.Fuzz function, use t.Cleanup instead") - } - f.common.Helper() - f.common.Cleanup(fn) -} - -// Error is equivalent to Log followed by Fail. -func (f *F) Error(args ...interface{}) { - if f.inFuzzFn { - panic("testing: f.Error was called inside the f.Fuzz function, use t.Error instead") - } - f.common.Helper() - f.common.Error(args...) -} - -// Errorf is equivalent to Logf followed by Fail. -func (f *F) Errorf(format string, args ...interface{}) { - if f.inFuzzFn { - panic("testing: f.Errorf was called inside the f.Fuzz function, use t.Errorf instead") - } - f.common.Helper() - f.common.Errorf(format, args...) -} - -// Fail marks the function as having failed but continues execution. -func (f *F) Fail() { - if f.inFuzzFn { - panic("testing: f.Fail was called inside the f.Fuzz function, use t.Fail instead") - } - f.common.Helper() - f.common.Fail() -} - -// FailNow marks the function as having failed and stops its execution -// by calling runtime.Goexit (which then runs all deferred calls in the -// current goroutine). -// Execution will continue at the next test, benchmark, or fuzz function. -// FailNow must be called from the goroutine running the -// fuzz target, not from other goroutines -// created during the test. Calling FailNow does not stop -// those other goroutines. -func (f *F) FailNow() { - if f.inFuzzFn { - panic("testing: f.FailNow was called inside the f.Fuzz function, use t.FailNow instead") - } - f.common.Helper() - f.common.FailNow() -} - -// Fatal is equivalent to Log followed by FailNow. -func (f *F) Fatal(args ...interface{}) { - if f.inFuzzFn { - panic("testing: f.Fatal was called inside the f.Fuzz function, use t.Fatal instead") - } - f.common.Helper() - f.common.Fatal(args...) -} - -// Fatalf is equivalent to Logf followed by FailNow. -func (f *F) Fatalf(format string, args ...interface{}) { - if f.inFuzzFn { - panic("testing: f.Fatalf was called inside the f.Fuzz function, use t.Fatalf instead") - } - f.common.Helper() - f.common.Fatalf(format, args...) -} - // Helper marks the calling function as a test helper function. // When printing file and line information, that function will be skipped. // Helper may be called simultaneously from multiple goroutines. @@ -188,65 +120,26 @@ func (f *F) Helper() { } } -// Setenv calls os.Setenv(key, value) and uses Cleanup to restore the -// environment variable to its original value after the test. -// -// When fuzzing is enabled, the fuzzing engine spawns worker processes running -// the test binary. Each worker process inherits the environment of the parent -// process, including environment variables set with F.Setenv. -func (f *F) Setenv(key, value string) { - if f.inFuzzFn { - panic("testing: f.Setenv was called inside the f.Fuzz function, use t.Setenv instead") - } - f.common.Helper() - f.common.Setenv(key, value) -} - -// Skip is equivalent to Log followed by SkipNow. -func (f *F) Skip(args ...interface{}) { - if f.inFuzzFn { - panic("testing: f.Skip was called inside the f.Fuzz function, use t.Skip instead") - } - f.common.Helper() - f.common.Skip(args...) -} - -// SkipNow marks the test as having been skipped and stops its execution -// by calling runtime.Goexit. -// If a test fails (see Error, Errorf, Fail) and is then skipped, -// it is still considered to have failed. -// Execution will continue at the next test or benchmark. See also FailNow. -// SkipNow must be called from the goroutine running the test, not from -// other goroutines created during the test. Calling SkipNow does not stop -// those other goroutines. -func (f *F) SkipNow() { - if f.inFuzzFn { - panic("testing: f.SkipNow was called inside the f.Fuzz function, use t.SkipNow instead") - } - f.common.Helper() - f.common.SkipNow() -} - -// Skipf is equivalent to Logf followed by SkipNow. -func (f *F) Skipf(format string, args ...interface{}) { +// Fail marks the function as having failed but continues execution. +func (f *F) Fail() { + // (*F).Fail may be called by (*T).Fail, which we should allow. However, we + // shouldn't allow direct (*F).Fail calls from inside the (*F).Fuzz function. if f.inFuzzFn { - panic("testing: f.Skipf was called inside the f.Fuzz function, use t.Skipf instead") + panic("testing: f.Fail was called inside the f.Fuzz function, use t.Fail instead") } f.common.Helper() - f.common.Skipf(format, args...) + f.common.Fail() } -// TempDir returns a temporary directory for the test to use. -// The directory is automatically removed by Cleanup when the test and -// all its subtests complete. -// Each subsequent call to t.TempDir returns a unique directory; -// if the directory creation fails, TempDir terminates the test by calling Fatal. -func (f *F) TempDir() string { +// Skipped reports whether the test was skipped. +func (f *F) Skipped() bool { + // (*F).Skipped may be called by tRunner, which we should allow. However, we + // shouldn't allow direct (*F).Skipped calls from inside the (*F).Fuzz function. if f.inFuzzFn { - panic("testing: f.TempDir was called inside the f.Fuzz function, use t.TempDir instead") + panic("testing: f.Skipped was called inside the f.Fuzz function, use t.Skipped instead") } f.common.Helper() - return f.common.TempDir() + return f.common.Skipped() } // Add will add the arguments to the seed corpus for the fuzz target. This will @@ -297,6 +190,10 @@ var supportedTypes = map[reflect.Type]bool{ // float64, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64. // More types may be supported in the future. // +// ff must not call any *F methods, e.g. (*F).Log, (*F).Error, (*F).Skip. Use +// the corresponding *T method instead. The only *F methods that are allowed in +// the (*F).Fuzz function are (*F).Failed and (*F).Name. +// // This function sould be fast and deterministic, and its behavior should not // depend on shared state. No mutatable input arguments, or pointers to them, // should be retained between executions of the fuzz function, as the memory @@ -415,7 +312,7 @@ func (f *F) Fuzz(ff interface{}) { // TODO(#48132): adjust this to work with test2json. t.chatty.Updatef(t.name, "=== RUN %s\n", t.name) } - f.inFuzzFn = true + f.common.inFuzzFn, f.inFuzzFn = true, true go tRunner(t, func(t *T) { args := []reflect.Value{reflect.ValueOf(t)} for _, v := range e.Values { @@ -430,7 +327,7 @@ func (f *F) Fuzz(ff interface{}) { fn.Call(args) }) <-t.signal - f.inFuzzFn = false + f.common.inFuzzFn, f.inFuzzFn = false, false return !t.Failed() } |
