github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/testing/fuzz.go (about) 1 package testing 2 3 import ( 4 "errors" 5 "fmt" 6 "reflect" 7 "time" 8 ) 9 10 // InternalFuzzTarget is an internal type but exported because it is 11 // cross-package; it is part of the implementation of the "go test" command. 12 type InternalFuzzTarget struct { 13 Name string 14 Fn func(f *F) 15 } 16 17 // F is a type passed to fuzz tests. 18 // 19 // Fuzz tests run generated inputs against a provided fuzz target, which can 20 // find and report potential bugs in the code being tested. 21 // 22 // A fuzz test runs the seed corpus by default, which includes entries provided 23 // by (*F).Add and entries in the testdata/fuzz/<FuzzTestName> directory. After 24 // any necessary setup and calls to (*F).Add, the fuzz test must then call 25 // (*F).Fuzz to provide the fuzz target. See the testing package documentation 26 // for an example, and see the F.Fuzz and F.Add method documentation for 27 // details. 28 // 29 // *F methods can only be called before (*F).Fuzz. Once the test is 30 // executing the fuzz target, only (*T) methods can be used. The only *F methods 31 // that are allowed in the (*F).Fuzz function are (*F).Failed and (*F).Name. 32 type F struct { 33 common 34 fuzzContext *fuzzContext 35 testContext *testContext 36 37 // inFuzzFn is true when the fuzz function is running. Most F methods cannot 38 // be called when inFuzzFn is true. 39 inFuzzFn bool 40 41 // corpus is a set of seed corpus entries, added with F.Add and loaded 42 // from testdata. 43 corpus []corpusEntry 44 45 result fuzzResult 46 fuzzCalled bool 47 } 48 49 // corpusEntry is an alias to the same type as internal/fuzz.CorpusEntry. 50 // We use a type alias because we don't want to export this type, and we can't 51 // import internal/fuzz from testing. 52 type corpusEntry = struct { 53 Parent string 54 Path string 55 Data []byte 56 Values []interface{} 57 Generation int 58 IsSeed bool 59 } 60 61 // Add will add the arguments to the seed corpus for the fuzz test. This will be 62 // a no-op if called after or within the fuzz target, and args must match the 63 // arguments for the fuzz target. 64 func (f *F) Add(args ...interface{}) { 65 var values []interface{} 66 for i := range args { 67 if t := reflect.TypeOf(args[i]); !supportedTypes[t] { 68 panic(fmt.Sprintf("testing: unsupported type to Add %v", t)) 69 } 70 values = append(values, args[i]) 71 } 72 f.corpus = append(f.corpus, corpusEntry{Values: values, IsSeed: true, Path: fmt.Sprintf("seed#%d", len(f.corpus))}) 73 } 74 75 // supportedTypes represents all of the supported types which can be fuzzed. 76 var supportedTypes = map[reflect.Type]bool{ 77 reflect.TypeOf(([]byte)("")): true, 78 reflect.TypeOf((string)("")): true, 79 reflect.TypeOf((bool)(false)): true, 80 reflect.TypeOf((byte)(0)): true, 81 reflect.TypeOf((rune)(0)): true, 82 reflect.TypeOf((float32)(0)): true, 83 reflect.TypeOf((float64)(0)): true, 84 reflect.TypeOf((int)(0)): true, 85 reflect.TypeOf((int8)(0)): true, 86 reflect.TypeOf((int16)(0)): true, 87 reflect.TypeOf((int32)(0)): true, 88 reflect.TypeOf((int64)(0)): true, 89 reflect.TypeOf((uint)(0)): true, 90 reflect.TypeOf((uint8)(0)): true, 91 reflect.TypeOf((uint16)(0)): true, 92 reflect.TypeOf((uint32)(0)): true, 93 reflect.TypeOf((uint64)(0)): true, 94 } 95 96 // Fuzz runs the fuzz function, ff, for fuzz testing. If ff fails for a set of 97 // arguments, those arguments will be added to the seed corpus. 98 // 99 // ff must be a function with no return value whose first argument is *T and 100 // whose remaining arguments are the types to be fuzzed. 101 // For example: 102 // 103 // f.Fuzz(func(t *testing.T, b []byte, i int) { ... }) 104 // 105 // The following types are allowed: []byte, string, bool, byte, rune, float32, 106 // float64, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64. 107 // More types may be supported in the future. 108 // 109 // ff must not call any *F methods, e.g. (*F).Log, (*F).Error, (*F).Skip. Use 110 // the corresponding *T method instead. The only *F methods that are allowed in 111 // the (*F).Fuzz function are (*F).Failed and (*F).Name. 112 // 113 // This function should be fast and deterministic, and its behavior should not 114 // depend on shared state. No mutatable input arguments, or pointers to them, 115 // should be retained between executions of the fuzz function, as the memory 116 // backing them may be mutated during a subsequent invocation. ff must not 117 // modify the underlying data of the arguments provided by the fuzzing engine. 118 // 119 // When fuzzing, F.Fuzz does not return until a problem is found, time runs out 120 // (set with -fuzztime), or the test process is interrupted by a signal. F.Fuzz 121 // should be called exactly once, unless F.Skip or F.Fail is called beforehand. 122 func (f *F) Fuzz(ff interface{}) { 123 f.failed = true 124 f.result.N = 0 125 f.result.T = 0 126 f.result.Error = errors.New("operation not implemented") 127 return 128 } 129 130 // fuzzContext holds fields common to all fuzz tests. 131 type fuzzContext struct { 132 deps testDeps 133 mode fuzzMode 134 } 135 136 type fuzzMode uint8 137 138 // fuzzResult contains the results of a fuzz run. 139 type fuzzResult struct { 140 N int // The number of iterations. 141 T time.Duration // The total time taken. 142 Error error // Error is the error from the failing input 143 }