diff options
Diffstat (limited to 'libgo/go/testing/quick/quick.go')
-rw-r--r-- | libgo/go/testing/quick/quick.go | 38 |
1 files changed, 27 insertions, 11 deletions
diff --git a/libgo/go/testing/quick/quick.go b/libgo/go/testing/quick/quick.go index 13c56cdf488..187195c7590 100644 --- a/libgo/go/testing/quick/quick.go +++ b/libgo/go/testing/quick/quick.go @@ -52,8 +52,15 @@ const complexSize = 50 // If the type implements the Generator interface, that will be used. // Note: To create arbitrary values for structs, all the fields must be exported. func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) { + return sizedValue(t, rand, complexSize) +} + +// sizedValue returns an arbitrary value of the given type. The size +// hint is used for shrinking as a function of indirection level so +// that recursive data structures will terminate. +func sizedValue(t reflect.Type, rand *rand.Rand, size int) (value reflect.Value, ok bool) { if m, ok := reflect.Zero(t).Interface().(Generator); ok { - return m.Generate(rand, complexSize), true + return m.Generate(rand, size), true } v := reflect.New(t).Elem() @@ -91,21 +98,21 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) { case reflect.Uintptr: v.SetUint(uint64(randInt64(rand))) case reflect.Map: - numElems := rand.Intn(complexSize) + numElems := rand.Intn(size) v.Set(reflect.MakeMap(concrete)) for i := 0; i < numElems; i++ { - key, ok1 := Value(concrete.Key(), rand) - value, ok2 := Value(concrete.Elem(), rand) + 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) } case reflect.Ptr: - if rand.Intn(complexSize) == 0 { + if rand.Intn(size) == 0 { v.Set(reflect.Zero(concrete)) // Generate nil pointer. } else { - elem, ok := Value(concrete.Elem(), rand) + elem, ok := sizedValue(concrete.Elem(), rand, size) if !ok { return reflect.Value{}, false } @@ -113,10 +120,11 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) { v.Elem().Set(elem) } case reflect.Slice: - numElems := rand.Intn(complexSize) + numElems := rand.Intn(size) + sizeLeft := size - numElems v.Set(reflect.MakeSlice(concrete, numElems, numElems)) for i := 0; i < numElems; i++ { - elem, ok := Value(concrete.Elem(), rand) + elem, ok := sizedValue(concrete.Elem(), rand, sizeLeft) if !ok { return reflect.Value{}, false } @@ -124,7 +132,7 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) { } case reflect.Array: for i := 0; i < v.Len(); i++ { - elem, ok := Value(concrete.Elem(), rand) + elem, ok := sizedValue(concrete.Elem(), rand, size) if !ok { return reflect.Value{}, false } @@ -138,8 +146,16 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) { } v.SetString(string(codePoints)) case reflect.Struct: - for i := 0; i < v.NumField(); i++ { - elem, ok := Value(concrete.Field(i).Type, rand) + n := v.NumField() + // Divide sizeLeft evenly among the struct fields. + sizeLeft := size + if n > sizeLeft { + sizeLeft = 1 + } else if n > 0 { + sizeLeft /= n + } + for i := 0; i < n; i++ { + elem, ok := sizedValue(concrete.Field(i).Type, rand, sizeLeft) if !ok { return reflect.Value{}, false } |