aboutsummaryrefslogtreecommitdiff
path: root/src/testing/quick
diff options
context:
space:
mode:
authorMatt T. Proud <matt.proud@gmail.com>2015-10-29 11:14:05 +0100
committerBrad Fitzpatrick <bradfitz@golang.org>2016-02-26 20:04:04 +0000
commit0ccabe2e0b42a2602e0f37ce28d5368aa811f530 (patch)
tree58383052537513a7d1caa66259e6fc665267bf02 /src/testing/quick
parent763e8fcc8931b44db77f7bcbc7b6943a2a8fb747 (diff)
downloadgo-0ccabe2e0b42a2602e0f37ce28d5368aa811f530.tar.xz
testing/quick: generate more map and slice states
This change adds support in testing/quick to generate maps and slices in additional states: (1.) nil maps (2.) nil slices (3.) empty slice occupancy: `len(s) == 0 && s != nil` (4.) partial slice occupancy: `len(s) < cap(s) && s != nil` (5.) full slice occupancy: `len(s) == cap(s) && s != nil` Prior to this, only #5 was ever generated, thereby not sufficiently exercising all of the fuzzable code path outcomes. This change depends on https://go-review.googlesource.com/#/c/17499/. Change-Id: I9343c475cefbd72ffc5237281826465c25872206 Reviewed-on: https://go-review.googlesource.com/16470 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/testing/quick')
-rw-r--r--src/testing/quick/quick.go47
-rw-r--r--src/testing/quick/quick_test.go17
2 files changed, 29 insertions, 35 deletions
diff --git a/src/testing/quick/quick.go b/src/testing/quick/quick.go
index 187195c759..0c2bf2d72b 100644
--- a/src/testing/quick/quick.go
+++ b/src/testing/quick/quick.go
@@ -14,7 +14,7 @@ import (
"strings"
)
-var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of iterations for each check")
+var defaultMaxCount = flag.Int("quickchecks", 100, "The default number of iterations for each check")
// A Generator can generate random values of its own type.
type Generator interface {
@@ -98,18 +98,22 @@ func sizedValue(t reflect.Type, rand *rand.Rand, size int) (value reflect.Value,
case reflect.Uintptr:
v.SetUint(uint64(randInt64(rand)))
case reflect.Map:
- numElems := rand.Intn(size)
- v.Set(reflect.MakeMap(concrete))
- for i := 0; i < numElems; i++ {
- key, ok1 := sizedValue(concrete.Key(), rand, size)
- value, ok2 := sizedValue(concrete.Elem(), rand, size)
- if !ok1 || !ok2 {
- return reflect.Value{}, false
+ if generateNilValue(rand) {
+ v.Set(reflect.Zero(concrete)) // Generate nil map.
+ } else {
+ numElems := rand.Intn(size)
+ v.Set(reflect.MakeMap(concrete))
+ for i := 0; i < numElems; i++ {
+ key, ok1 := sizedValue(concrete.Key(), rand, size)
+ value, ok2 := sizedValue(concrete.Elem(), rand, size)
+ if !ok1 || !ok2 {
+ return reflect.Value{}, false
+ }
+ v.SetMapIndex(key, value)
}
- v.SetMapIndex(key, value)
}
case reflect.Ptr:
- if rand.Intn(size) == 0 {
+ if generateNilValue(rand) {
v.Set(reflect.Zero(concrete)) // Generate nil pointer.
} else {
elem, ok := sizedValue(concrete.Elem(), rand, size)
@@ -120,15 +124,20 @@ func sizedValue(t reflect.Type, rand *rand.Rand, size int) (value reflect.Value,
v.Elem().Set(elem)
}
case reflect.Slice:
- numElems := rand.Intn(size)
- sizeLeft := size - numElems
- v.Set(reflect.MakeSlice(concrete, numElems, numElems))
- for i := 0; i < numElems; i++ {
- elem, ok := sizedValue(concrete.Elem(), rand, sizeLeft)
- if !ok {
- return reflect.Value{}, false
+ if generateNilValue(rand) {
+ v.Set(reflect.Zero(concrete)) // Generate nil slice.
+ } else {
+ slCap := rand.Intn(size)
+ slLen := rand.Intn(slCap + 1)
+ sizeLeft := size - slCap
+ v.Set(reflect.MakeSlice(concrete, slLen, slCap))
+ for i := 0; i < slLen; i++ {
+ elem, ok := sizedValue(concrete.Elem(), rand, sizeLeft)
+ if !ok {
+ return reflect.Value{}, false
+ }
+ v.Index(i).Set(elem)
}
- v.Index(i).Set(elem)
}
case reflect.Array:
for i := 0; i < v.Len(); i++ {
@@ -384,3 +393,5 @@ func toString(interfaces []interface{}) string {
}
return strings.Join(s, ", ")
}
+
+func generateNilValue(r *rand.Rand) bool { return r.Intn(20) == 0 }
diff --git a/src/testing/quick/quick_test.go b/src/testing/quick/quick_test.go
index fe443592f8..018ece2a52 100644
--- a/src/testing/quick/quick_test.go
+++ b/src/testing/quick/quick_test.go
@@ -290,20 +290,3 @@ func TestMutuallyRecursive(t *testing.T) {
f := func(a A) bool { return true }
Check(f, nil)
}
-
-// Some serialization formats (e.g. encoding/pem) cannot distinguish
-// between a nil and an empty map or slice, so avoid generating the
-// zero value for these.
-func TestNonZeroSliceAndMap(t *testing.T) {
- type Q struct {
- M map[int]int
- S []int
- }
- f := func(q Q) bool {
- return q.M != nil && q.S != nil
- }
- err := Check(f, nil)
- if err != nil {
- t.Fatal(err)
- }
-}