package  quick 
 
import  ( 
	"flag"  
	"fmt"  
	"math"  
	"math/rand"  
	"reflect"  
	"strings"  
	"time"  
) 
 
var  defaultMaxCount *int  = flag .Int ("quickchecks" , 100 , "The default number of iterations for each check" ) 
 
 
type  Generator  interface  { 
	 
 
	Generate (rand *rand .Rand , size int ) reflect .Value  
} 
 
 
func  randFloat32(rand  *rand .Rand ) float32  { 
	f  := rand .Float64 () * math .MaxFloat32  
	if  rand .Int ()&1  == 1  { 
		f  = -f  
	} 
	return  float32 (f ) 
} 
 
 
func  randFloat64(rand  *rand .Rand ) float64  { 
	f  := rand .Float64 () * math .MaxFloat64  
	if  rand .Int ()&1  == 1  { 
		f  = -f  
	} 
	return  f  
} 
 
 
func  randInt64(rand  *rand .Rand ) int64  { 
	return  int64 (rand .Uint64 ()) 
} 
 
 
 
const  complexSize = 50  
 
 
 
 
func  Value  (t  reflect .Type , rand  *rand .Rand ) (value  reflect .Value , ok  bool ) { 
	return  sizedValue (t , rand , complexSize ) 
} 
 
 
 
 
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 , size ), true  
	} 
 
	v  := reflect .New (t ).Elem () 
	switch  concrete  := t ; concrete .Kind () { 
	case  reflect .Bool : 
		v .SetBool (rand .Int ()&1  == 0 ) 
	case  reflect .Float32 : 
		v .SetFloat (float64 (randFloat32 (rand ))) 
	case  reflect .Float64 : 
		v .SetFloat (randFloat64 (rand )) 
	case  reflect .Complex64 : 
		v .SetComplex (complex (float64 (randFloat32 (rand )), float64 (randFloat32 (rand )))) 
	case  reflect .Complex128 : 
		v .SetComplex (complex (randFloat64 (rand ), randFloat64 (rand ))) 
	case  reflect .Int16 : 
		v .SetInt (randInt64 (rand )) 
	case  reflect .Int32 : 
		v .SetInt (randInt64 (rand )) 
	case  reflect .Int64 : 
		v .SetInt (randInt64 (rand )) 
	case  reflect .Int8 : 
		v .SetInt (randInt64 (rand )) 
	case  reflect .Int : 
		v .SetInt (randInt64 (rand )) 
	case  reflect .Uint16 : 
		v .SetUint (uint64 (randInt64 (rand ))) 
	case  reflect .Uint32 : 
		v .SetUint (uint64 (randInt64 (rand ))) 
	case  reflect .Uint64 : 
		v .SetUint (uint64 (randInt64 (rand ))) 
	case  reflect .Uint8 : 
		v .SetUint (uint64 (randInt64 (rand ))) 
	case  reflect .Uint : 
		v .SetUint (uint64 (randInt64 (rand ))) 
	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  
			} 
			v .SetMapIndex (key , value ) 
		} 
	case  reflect .Pointer : 
		if  rand .Intn (size ) == 0  { 
			v .SetZero ()  
		} else  { 
			elem , ok  := sizedValue (concrete .Elem (), rand , size ) 
			if  !ok  { 
				return  reflect .Value {}, false  
			} 
			v .Set (reflect .New (concrete .Elem ())) 
			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  
			} 
			v .Index (i ).Set (elem ) 
		} 
	case  reflect .Array : 
		for  i  := 0 ; i  < v .Len (); i ++ { 
			elem , ok  := sizedValue (concrete .Elem (), rand , size ) 
			if  !ok  { 
				return  reflect .Value {}, false  
			} 
			v .Index (i ).Set (elem ) 
		} 
	case  reflect .String : 
		numChars  := rand .Intn (complexSize ) 
		codePoints  := make ([]rune , numChars ) 
		for  i  := 0 ; i  < numChars ; i ++ { 
			codePoints [i ] = rune (rand .Intn (0x10ffff )) 
		} 
		v .SetString (string (codePoints )) 
	case  reflect .Struct : 
		n  := v .NumField () 
		 
		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  
			} 
			v .Field (i ).Set (elem ) 
		} 
	default : 
		return  reflect .Value {}, false  
	} 
 
	return  v , true  
} 
 
 
type  Config  struct  { 
	 
 
	MaxCount int  
	 
 
 
 
	MaxCountScale float64  
	 
 
	Rand *rand .Rand  
	 
 
 
 
	Values func ([]reflect .Value , *rand .Rand ) 
} 
 
var  defaultConfig Config  
 
 
func  (c  *Config ) getRand () *rand .Rand  { 
	if  c .Rand  == nil  { 
		return  rand .New (rand .NewSource (time .Now ().UnixNano ())) 
	} 
	return  c .Rand  
} 
 
 
 
func  (c  *Config ) getMaxCount () (maxCount  int ) { 
	maxCount  = c .MaxCount  
	if  maxCount  == 0  { 
		if  c .MaxCountScale  != 0  { 
			maxCount  = int (c .MaxCountScale  * float64 (*defaultMaxCount )) 
		} else  { 
			maxCount  = *defaultMaxCount  
		} 
	} 
 
	return  
} 
 
 
 
type  SetupError  string  
 
func  (s  SetupError ) Error () string  { return  string (s ) } 
 
 
type  CheckError  struct  { 
	Count int  
	In    []any  
} 
 
func  (s  *CheckError ) Error () string  { 
	return  fmt .Sprintf ("#%d: failed on input %s" , s .Count , toString (s .In )) 
} 
 
 
type  CheckEqualError  struct  { 
	CheckError  
	Out1 []any  
	Out2 []any  
} 
 
func  (s  *CheckEqualError ) Error () string  { 
	return  fmt .Sprintf ("#%d: failed on input %s. Output 1: %s. Output 2: %s" , s .Count , toString (s .In ), toString (s .Out1 ), toString (s .Out2 )) 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
func  Check  (f  any , config  *Config ) error  { 
	if  config  == nil  { 
		config  = &defaultConfig  
	} 
 
	fVal , fType , ok  := functionAndType (f ) 
	if  !ok  { 
		return  SetupError ("argument is not a function" ) 
	} 
 
	if  fType .NumOut () != 1  { 
		return  SetupError ("function does not return one value" ) 
	} 
	if  fType .Out (0 ).Kind () != reflect .Bool  { 
		return  SetupError ("function does not return a bool" ) 
	} 
 
	arguments  := make ([]reflect .Value , fType .NumIn ()) 
	rand  := config .getRand () 
	maxCount  := config .getMaxCount () 
 
	for  i  := 0 ; i  < maxCount ; i ++ { 
		err  := arbitraryValues (arguments , fType , config , rand ) 
		if  err  != nil  { 
			return  err  
		} 
 
		if  !fVal .Call (arguments )[0 ].Bool () { 
			return  &CheckError {i  + 1 , toInterfaces (arguments )} 
		} 
	} 
 
	return  nil  
} 
 
 
 
 
 
func  CheckEqual  (f , g  any , config  *Config ) error  { 
	if  config  == nil  { 
		config  = &defaultConfig  
	} 
 
	x , xType , ok  := functionAndType (f ) 
	if  !ok  { 
		return  SetupError ("f is not a function" ) 
	} 
	y , yType , ok  := functionAndType (g ) 
	if  !ok  { 
		return  SetupError ("g is not a function" ) 
	} 
 
	if  xType  != yType  { 
		return  SetupError ("functions have different types" ) 
	} 
 
	arguments  := make ([]reflect .Value , xType .NumIn ()) 
	rand  := config .getRand () 
	maxCount  := config .getMaxCount () 
 
	for  i  := 0 ; i  < maxCount ; i ++ { 
		err  := arbitraryValues (arguments , xType , config , rand ) 
		if  err  != nil  { 
			return  err  
		} 
 
		xOut  := toInterfaces (x .Call (arguments )) 
		yOut  := toInterfaces (y .Call (arguments )) 
 
		if  !reflect .DeepEqual (xOut , yOut ) { 
			return  &CheckEqualError {CheckError {i  + 1 , toInterfaces (arguments )}, xOut , yOut } 
		} 
	} 
 
	return  nil  
} 
 
 
 
func  arbitraryValues(args  []reflect .Value , f  reflect .Type , config  *Config , rand  *rand .Rand ) (err  error ) { 
	if  config .Values  != nil  { 
		config .Values (args , rand ) 
		return  
	} 
 
	for  j  := 0 ; j  < len (args ); j ++ { 
		var  ok  bool  
		args [j ], ok  = Value (f .In (j ), rand ) 
		if  !ok  { 
			err  = SetupError (fmt .Sprintf ("cannot create arbitrary value of type %s for argument %d" , f .In (j ), j )) 
			return  
		} 
	} 
 
	return  
} 
 
func  functionAndType(f  any ) (v  reflect .Value , t  reflect .Type , ok  bool ) { 
	v  = reflect .ValueOf (f ) 
	ok  = v .Kind () == reflect .Func  
	if  !ok  { 
		return  
	} 
	t  = v .Type () 
	return  
} 
 
func  toInterfaces(values  []reflect .Value ) []any  { 
	ret  := make ([]any , len (values )) 
	for  i , v  := range  values  { 
		ret [i ] = v .Interface () 
	} 
	return  ret  
} 
 
func  toString(interfaces  []any ) string  { 
	s  := make ([]string , len (interfaces )) 
	for  i , v  := range  interfaces  { 
		s [i ] = fmt .Sprintf ("%#v" , v ) 
	} 
	return  strings .Join (s , ", " ) 
} 
  
The pages are generated with Golds   v0.7.9-preview . (GOOS=linux GOARCH=amd64)
Golds  is a Go 101  project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101  (reachable from the left QR code) to get the latest news of Golds .