// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package quick implements utility functions to help with black box testing. // // The testing/quick package is frozen and is not accepting new features.
package quick import ( ) var defaultMaxCount *int = 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 { // Generate returns a random instance of the type on which it is a // method using the size as a size hint. Generate(rand *rand.Rand, size int) reflect.Value } // randFloat32 generates a random float taking the full range of a float32. func randFloat32( *rand.Rand) float32 { := .Float64() * math.MaxFloat32 if .Int()&1 == 1 { = - } return float32() } // randFloat64 generates a random float taking the full range of a float64. func randFloat64( *rand.Rand) float64 { := .Float64() * math.MaxFloat64 if .Int()&1 == 1 { = - } return } // randInt64 returns a random int64. func randInt64( *rand.Rand) int64 { return int64(.Uint64()) } // complexSize is the maximum length of arbitrary values that contain other // values. const complexSize = 50 // Value returns an arbitrary value of the given type. // 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 ( reflect.Type, *rand.Rand) ( reflect.Value, bool) { return sizedValue(, , 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( reflect.Type, *rand.Rand, int) ( reflect.Value, bool) { if , := reflect.Zero().Interface().(Generator); { return .Generate(, ), true } := reflect.New().Elem() switch := ; .Kind() { case reflect.Bool: .SetBool(.Int()&1 == 0) case reflect.Float32: .SetFloat(float64(randFloat32())) case reflect.Float64: .SetFloat(randFloat64()) case reflect.Complex64: .SetComplex(complex(float64(randFloat32()), float64(randFloat32()))) case reflect.Complex128: .SetComplex(complex(randFloat64(), randFloat64())) case reflect.Int16: .SetInt(randInt64()) case reflect.Int32: .SetInt(randInt64()) case reflect.Int64: .SetInt(randInt64()) case reflect.Int8: .SetInt(randInt64()) case reflect.Int: .SetInt(randInt64()) case reflect.Uint16: .SetUint(uint64(randInt64())) case reflect.Uint32: .SetUint(uint64(randInt64())) case reflect.Uint64: .SetUint(uint64(randInt64())) case reflect.Uint8: .SetUint(uint64(randInt64())) case reflect.Uint: .SetUint(uint64(randInt64())) case reflect.Uintptr: .SetUint(uint64(randInt64())) case reflect.Map: := .Intn() .Set(reflect.MakeMap()) for := 0; < ; ++ { , := (.Key(), , ) , := (.Elem(), , ) if ! || ! { return reflect.Value{}, false } .SetMapIndex(, ) } case reflect.Pointer: if .Intn() == 0 { .SetZero() // Generate nil pointer. } else { , := (.Elem(), , ) if ! { return reflect.Value{}, false } .Set(reflect.New(.Elem())) .Elem().Set() } case reflect.Slice: := .Intn() := - .Set(reflect.MakeSlice(, , )) for := 0; < ; ++ { , := (.Elem(), , ) if ! { return reflect.Value{}, false } .Index().Set() } case reflect.Array: for := 0; < .Len(); ++ { , := (.Elem(), , ) if ! { return reflect.Value{}, false } .Index().Set() } case reflect.String: := .Intn(complexSize) := make([]rune, ) for := 0; < ; ++ { [] = rune(.Intn(0x10ffff)) } .SetString(string()) case reflect.Struct: := .NumField() // Divide sizeLeft evenly among the struct fields. := if > { = 1 } else if > 0 { /= } for := 0; < ; ++ { , := (.Field().Type, , ) if ! { return reflect.Value{}, false } .Field().Set() } default: return reflect.Value{}, false } return , true } // A Config structure contains options for running a test. type Config struct { // MaxCount sets the maximum number of iterations. // If zero, MaxCountScale is used. MaxCount int // MaxCountScale is a non-negative scale factor applied to the // default maximum. // A count of zero implies the default, which is usually 100 // but can be set by the -quickchecks flag. MaxCountScale float64 // Rand specifies a source of random numbers. // If nil, a default pseudo-random source will be used. Rand *rand.Rand // Values specifies a function to generate a slice of // arbitrary reflect.Values that are congruent with the // arguments to the function being tested. // If nil, the top-level Value function is used to generate them. Values func([]reflect.Value, *rand.Rand) } var defaultConfig Config // getRand returns the *rand.Rand to use for a given Config. func ( *Config) () *rand.Rand { if .Rand == nil { return rand.New(rand.NewSource(time.Now().UnixNano())) } return .Rand } // getMaxCount returns the maximum number of iterations to run for a given // Config. func ( *Config) () ( int) { = .MaxCount if == 0 { if .MaxCountScale != 0 { = int(.MaxCountScale * float64(*defaultMaxCount)) } else { = *defaultMaxCount } } return } // A SetupError is the result of an error in the way that check is being // used, independent of the functions being tested. type SetupError string func ( SetupError) () string { return string() } // A CheckError is the result of Check finding an error. type CheckError struct { Count int In []any } func ( *CheckError) () string { return fmt.Sprintf("#%d: failed on input %s", .Count, toString(.In)) } // A CheckEqualError is the result [CheckEqual] finding an error. type CheckEqualError struct { CheckError Out1 []any Out2 []any } func ( *CheckEqualError) () string { return fmt.Sprintf("#%d: failed on input %s. Output 1: %s. Output 2: %s", .Count, toString(.In), toString(.Out1), toString(.Out2)) } // Check looks for an input to f, any function that returns bool, // such that f returns false. It calls f repeatedly, with arbitrary // values for each argument. If f returns false on a given input, // Check returns that input as a *[CheckError]. // For example: // // func TestOddMultipleOfThree(t *testing.T) { // f := func(x int) bool { // y := OddMultipleOfThree(x) // return y%2 == 1 && y%3 == 0 // } // if err := quick.Check(f, nil); err != nil { // t.Error(err) // } // } func ( any, *Config) error { if == nil { = &defaultConfig } , , := functionAndType() if ! { return SetupError("argument is not a function") } if .NumOut() != 1 { return SetupError("function does not return one value") } if .Out(0).Kind() != reflect.Bool { return SetupError("function does not return a bool") } := make([]reflect.Value, .NumIn()) := .getRand() := .getMaxCount() for := 0; < ; ++ { := arbitraryValues(, , , ) if != nil { return } if !.Call()[0].Bool() { return &CheckError{ + 1, toInterfaces()} } } return nil } // CheckEqual looks for an input on which f and g return different results. // It calls f and g repeatedly with arbitrary values for each argument. // If f and g return different answers, CheckEqual returns a *[CheckEqualError] // describing the input and the outputs. func (, any, *Config) error { if == nil { = &defaultConfig } , , := functionAndType() if ! { return SetupError("f is not a function") } , , := functionAndType() if ! { return SetupError("g is not a function") } if != { return SetupError("functions have different types") } := make([]reflect.Value, .NumIn()) := .getRand() := .getMaxCount() for := 0; < ; ++ { := arbitraryValues(, , , ) if != nil { return } := toInterfaces(.Call()) := toInterfaces(.Call()) if !reflect.DeepEqual(, ) { return &CheckEqualError{CheckError{ + 1, toInterfaces()}, , } } } return nil } // arbitraryValues writes Values to args such that args contains Values // suitable for calling f. func arbitraryValues( []reflect.Value, reflect.Type, *Config, *rand.Rand) ( error) { if .Values != nil { .Values(, ) return } for := 0; < len(); ++ { var bool [], = Value(.In(), ) if ! { = SetupError(fmt.Sprintf("cannot create arbitrary value of type %s for argument %d", .In(), )) return } } return } func functionAndType( any) ( reflect.Value, reflect.Type, bool) { = reflect.ValueOf() = .Kind() == reflect.Func if ! { return } = .Type() return } func toInterfaces( []reflect.Value) []any { := make([]any, len()) for , := range { [] = .Interface() } return } func toString( []any) string { := make([]string, len()) for , := range { [] = fmt.Sprintf("%#v", ) } return strings.Join(, ", ") }