Skip to content
This repository was archived by the owner on Jan 10, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 28 additions & 17 deletions fuzz.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,16 @@ type fuzzFuncMap map[reflect.Type]reflect.Value

// Fuzzer knows how to fill any object with random fields.
type Fuzzer struct {
fuzzFuncs fuzzFuncMap
defaultFuzzFuncs fuzzFuncMap
r *rand.Rand
nilChance float64
minElements int
maxElements int
maxDepth int
allowUnexportedFields bool
skipFieldPatterns []*regexp.Regexp
fuzzFuncs fuzzFuncMap
defaultFuzzFuncs fuzzFuncMap
r *rand.Rand
nilChance float64
minElements int
maxElements int
maxDepth int
allowUnexportedFields bool
allowUnsupportedFields bool
skipFieldPatterns []*regexp.Regexp

fuzzLock sync.Mutex
}
Expand All @@ -60,13 +61,14 @@ func NewWithSeed(seed int64) *Fuzzer {
reflect.TypeOf(&time.Time{}): reflect.ValueOf(fuzzTime),
},

fuzzFuncs: fuzzFuncMap{},
r: rand.New(rand.NewSource(seed)),
nilChance: .2,
minElements: 1,
maxElements: 10,
maxDepth: 100,
allowUnexportedFields: false,
fuzzFuncs: fuzzFuncMap{},
r: rand.New(rand.NewSource(seed)),
nilChance: .2,
minElements: 1,
maxElements: 10,
maxDepth: 100,
allowUnexportedFields: false,
allowUnsupportedFields: false,
}
return f
}
Expand Down Expand Up @@ -198,6 +200,13 @@ func (f *Fuzzer) AllowUnexportedFields(flag bool) *Fuzzer {
return f
}

// AllowUnsupportedFields decides whether to ignore fields that we don't support fuzzing on,
// like interfaces and channels, by default this is not allowed and the fuzzer will panic on an unsupported field.
func (f *Fuzzer) AllowUnsupportedFields(flag bool) *Fuzzer {
f.allowUnsupportedFields = flag
return f
}

// SkipFieldsWithPattern Skip fields which match the supplied pattern. Call this multiple times if needed
// This is useful to skip XXX_ fields generated by protobuf
func (f *Fuzzer) SkipFieldsWithPattern(pattern *regexp.Regexp) *Fuzzer {
Expand Down Expand Up @@ -358,7 +367,9 @@ func (fc *fuzzerContext) doFuzz(v reflect.Value, flags uint64) {
case reflect.Interface:
fallthrough
default:
panic(fmt.Sprintf("Can't handle type %v with value %#v", v.Type(), v.Interface()))
if !fc.fuzzer.allowUnsupportedFields {
panic(fmt.Sprintf("Can't handle type %v with value %#v", v.Type(), v.Interface()))
}
}
}

Expand Down
38 changes: 38 additions & 0 deletions fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,44 @@ func TestFuzzer_AllowUnexportedFields(t *testing.T) {
}
}

func TestFuzzer_AllowUnsupportedFields(t *testing.T) {
type S struct {
InterfaceField interface{}
}

f := New().NilChance(0)
obj := S{}

failingFuzz := func(obj *S) {
defer func() {
if r := recover(); r != nil {
t.Log("Panicked as expected")
}
}()
f.Fuzz(obj)
t.Errorf("Expected to panic")
}

failingFuzz(&obj)
if obj.InterfaceField != nil {
t.Errorf("Expected obj.InterfaceField to be empty")
}

f.AllowUnsupportedFields(true)
obj = S{}
f.Fuzz(&obj)
if obj.InterfaceField != nil {
t.Errorf("Expected obj.InterfaceField to be empty")
}

f.AllowUnsupportedFields(false)
obj = S{}
failingFuzz(&obj)
if obj.InterfaceField != nil {
t.Errorf("Expected obj.InterfaceField to be empty")
}
}

func TestFuzz_SkipPattern(t *testing.T) {
obj := &struct {
S1 string
Expand Down