aboutsummaryrefslogtreecommitdiff
path: root/src/testing/fuzz.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/testing/fuzz.go')
-rw-r--r--src/testing/fuzz.go147
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()
}