Support fuzzing unexported fields (#63)
Support fuzzing unexported fields.
diff --git a/fuzz.go b/fuzz.go
index 92c9165..dbce1ed 100644
--- a/fuzz.go
+++ b/fuzz.go
@@ -23,6 +23,7 @@
"regexp"
"sync"
"time"
+ "unsafe"
"github.com/google/gofuzz/bytesource"
"strings"
@@ -33,14 +34,15 @@
// 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
- skipFieldPatterns []*regexp.Regexp
+ fuzzFuncs fuzzFuncMap
+ defaultFuzzFuncs fuzzFuncMap
+ r *rand.Rand
+ nilChance float64
+ minElements int
+ maxElements int
+ maxDepth int
+ allowUnexportedFields bool
+ skipFieldPatterns []*regexp.Regexp
fuzzLock sync.Mutex
}
@@ -57,12 +59,13 @@
reflect.TypeOf(&time.Time{}): reflect.ValueOf(fuzzTime),
},
- fuzzFuncs: fuzzFuncMap{},
- r: rand.New(rand.NewSource(seed)),
- nilChance: .2,
- minElements: 1,
- maxElements: 10,
- maxDepth: 100,
+ fuzzFuncs: fuzzFuncMap{},
+ r: rand.New(rand.NewSource(seed)),
+ nilChance: .2,
+ minElements: 1,
+ maxElements: 10,
+ maxDepth: 100,
+ allowUnexportedFields: false,
}
return f
}
@@ -186,7 +189,14 @@
return f
}
-// Skip fields which match the supplied pattern. Call this multiple times if needed
+// AllowUnexportedFields decides whether to do fuzz on the unexported fields,
+// i.e. the fields that start with lower case letter.
+func (f *Fuzzer) AllowUnexportedFields(flag bool) *Fuzzer {
+ f.allowUnexportedFields = 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 {
f.skipFieldPatterns = append(f.skipFieldPatterns, pattern)
@@ -263,7 +273,10 @@
defer func() { fc.curDepth-- }()
if !v.CanSet() {
- return
+ if !fc.fuzzer.allowUnexportedFields || !v.CanAddr() {
+ return
+ }
+ v = reflect.NewAt(v.Type(), unsafe.Pointer(v.UnsafeAddr())).Elem()
}
if flags&flagNoCustomFuzz == 0 {
diff --git a/fuzz_test.go b/fuzz_test.go
index 0d18abf..af466a8 100644
--- a/fuzz_test.go
+++ b/fuzz_test.go
@@ -483,6 +483,34 @@
}
}
+func TestFuzzer_AllowUnexportedFields(t *testing.T) {
+ type S struct {
+ stringField string
+ }
+
+ f := New().NilChance(0)
+
+ obj := S{}
+ f.Fuzz(&obj)
+ if obj.stringField != "" {
+ t.Errorf("Expected obj.stringField to be empty")
+ }
+
+ f.AllowUnexportedFields(true)
+ obj = S{}
+ f.Fuzz(&obj)
+ if obj.stringField == "" {
+ t.Errorf("Expected stringFiled not empty")
+ }
+
+ f.AllowUnexportedFields(false)
+ obj = S{}
+ f.Fuzz(&obj)
+ if obj.stringField != "" {
+ t.Errorf("Expected obj.stringField to be empty")
+ }
+}
+
func TestFuzz_SkipPattern(t *testing.T) {
obj := &struct {
S1 string