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  }