github.com/vc42/parquet-go@v0.0.0-20240320194221-1a9adb5f23f5/internal/quick/quick.go (about)

     1  package quick
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"math/rand"
     7  	"reflect"
     8  	"strings"
     9  )
    10  
    11  var DefaultConfig = Config{
    12  	Sizes: []int{
    13  		0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
    14  		10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
    15  		20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
    16  		30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
    17  		99, 100, 101,
    18  		127, 128, 129,
    19  		255, 256, 257,
    20  		1000, 1023, 1024, 1025,
    21  		2000, 2095, 2048, 2049,
    22  		4000, 4095, 4096, 4097,
    23  	},
    24  	Seed: 0,
    25  }
    26  
    27  // Check is inspired by the standard quick.Check package, but enhances the
    28  // API and tests arrays of larger sizes than the maximum of 50 hardcoded in
    29  // testing/quick.
    30  func Check(f interface{}) error {
    31  	return DefaultConfig.Check(f)
    32  }
    33  
    34  type Config struct {
    35  	Sizes []int
    36  	Seed  int64
    37  }
    38  
    39  func (c *Config) Check(f interface{}) error {
    40  	v := reflect.ValueOf(f)
    41  	r := rand.New(rand.NewSource(c.Seed))
    42  	t := v.Type().In(0)
    43  
    44  	makeValue := MakeValueFuncOf(t.Elem())
    45  	makeArray := func(n int) reflect.Value {
    46  		array := reflect.MakeSlice(t, n, n)
    47  		for i := 0; i < n; i++ {
    48  			makeValue(array.Index(i), r)
    49  		}
    50  		return array
    51  	}
    52  
    53  	if makeArray == nil {
    54  		panic("cannot run quick check on function with input of type " + v.Type().In(0).String())
    55  	}
    56  
    57  	for _, n := range c.Sizes {
    58  		for i := 0; i < 3; i++ {
    59  			in := makeArray(n)
    60  			ok := v.Call([]reflect.Value{in})
    61  			if !ok[0].Bool() {
    62  				return fmt.Errorf("test #%d: failed on input of size %d: %#v\n", i+1, n, in.Interface())
    63  			}
    64  		}
    65  	}
    66  	return nil
    67  
    68  }
    69  
    70  type MakeValueFunc func(reflect.Value, *rand.Rand)
    71  
    72  func MakeValueFuncOf(t reflect.Type) MakeValueFunc {
    73  	switch t.Kind() {
    74  	case reflect.Bool:
    75  		return func(v reflect.Value, r *rand.Rand) {
    76  			v.SetBool((r.Int() % 2) != 0)
    77  		}
    78  
    79  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    80  		return func(v reflect.Value, r *rand.Rand) {
    81  			v.SetInt(r.Int63n(math.MaxInt32))
    82  		}
    83  
    84  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
    85  		return func(v reflect.Value, r *rand.Rand) {
    86  			v.SetUint(r.Uint64())
    87  		}
    88  
    89  	case reflect.Float32, reflect.Float64:
    90  		return func(v reflect.Value, r *rand.Rand) {
    91  			v.SetFloat(r.Float64())
    92  		}
    93  
    94  	case reflect.String:
    95  		return func(v reflect.Value, r *rand.Rand) {
    96  			const characters = "1234567890qwertyuiopasdfghjklzxcvbnm"
    97  			s := new(strings.Builder)
    98  			n := r.Intn(10)
    99  			for i := 0; i < n; i++ {
   100  				s.WriteByte(characters[i])
   101  			}
   102  			v.SetString(s.String())
   103  		}
   104  
   105  	case reflect.Array:
   106  		makeElem := MakeValueFuncOf(t.Elem())
   107  		return func(v reflect.Value, r *rand.Rand) {
   108  			for i, n := 0, v.Len(); i < n; i++ {
   109  				makeElem(v.Index(i), r)
   110  			}
   111  		}
   112  
   113  	case reflect.Slice:
   114  		switch e := t.Elem(); e.Kind() {
   115  		case reflect.Uint8:
   116  			return func(v reflect.Value, r *rand.Rand) {
   117  				b := make([]byte, r.Intn(50))
   118  				r.Read(b)
   119  				v.SetBytes(b)
   120  			}
   121  		default:
   122  			makeElem := MakeValueFuncOf(t.Elem())
   123  			return func(v reflect.Value, r *rand.Rand) {
   124  				n := r.Intn(10)
   125  				s := reflect.MakeSlice(t, n, n)
   126  				for i := 0; i < n; i++ {
   127  					makeElem(s.Index(i), r)
   128  				}
   129  				v.Set(s)
   130  			}
   131  		}
   132  
   133  	case reflect.Map:
   134  		makeKey := MakeValueFuncOf(t.Key())
   135  		makeElem := MakeValueFuncOf(t.Elem())
   136  		return func(v reflect.Value, r *rand.Rand) {
   137  			m := reflect.MakeMap(t)
   138  			n := r.Intn(10)
   139  			k := reflect.New(t.Key()).Elem()
   140  			e := reflect.New(t.Elem()).Elem()
   141  			for i := 0; i < n; i++ {
   142  				makeKey(k, r)
   143  				makeElem(e, r)
   144  				m.SetMapIndex(k, e)
   145  			}
   146  			v.Set(m)
   147  		}
   148  
   149  	case reflect.Struct:
   150  		fields := make([]reflect.StructField, 0, t.NumField())
   151  		makeValues := make([]MakeValueFunc, 0, cap(fields))
   152  		for i, n := 0, cap(fields); i < n; i++ {
   153  			if f := t.Field(i); f.PkgPath == "" { // skip unexported fields
   154  				fields = append(fields, f)
   155  				makeValues = append(makeValues, MakeValueFuncOf(f.Type))
   156  			}
   157  		}
   158  		return func(v reflect.Value, r *rand.Rand) {
   159  			for i := range fields {
   160  				makeValues[i](v.FieldByIndex(fields[i].Index), r)
   161  			}
   162  		}
   163  
   164  	case reflect.Ptr:
   165  		t = t.Elem()
   166  		makeValue := MakeValueFuncOf(t)
   167  		return func(v reflect.Value, r *rand.Rand) {
   168  			v.Set(reflect.New(t))
   169  			makeValue(v.Elem(), r)
   170  		}
   171  
   172  	default:
   173  		panic("quick.Check does not support test values of type " + t.String())
   174  	}
   175  }