mirror of
https://github.com/golang/go
synced 2024-11-23 18:20:04 -07:00
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>
This commit is contained in:
parent
763e8fcc89
commit
0ccabe2e0b
@ -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 }
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user