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