github.com/leanovate/gopter@v0.2.9/derived_gen_test.go (about) 1 package gopter_test 2 3 import ( 4 "reflect" 5 "testing" 6 7 "github.com/leanovate/gopter" 8 "github.com/leanovate/gopter/gen" 9 ) 10 11 type downStruct struct { 12 a int 13 b string 14 c bool 15 } 16 17 func TestDeriveGenSingleDown(t *testing.T) { 18 gen := gopter.DeriveGen( 19 func(a int, b string, c bool) *downStruct { 20 return &downStruct{a: a, b: b, c: c} 21 }, 22 func(d *downStruct) (int, string, bool) { 23 return d.a, d.b, d.c 24 }, 25 gen.Int(), 26 gen.AnyString(), 27 gen.Bool(), 28 ) 29 30 sample, ok := gen.Sample() 31 if !ok { 32 t.Error("Sample not ok") 33 } 34 _, ok = sample.(*downStruct) 35 if !ok { 36 t.Errorf("%#v is not a downStruct", sample) 37 } 38 39 shrinker := gen(gopter.DefaultGenParameters()).Shrinker 40 shrink := shrinker(&downStruct{a: 10, b: "abcd", c: false}) 41 42 shrunkStructs := make([]*downStruct, 0) 43 value, next := shrink() 44 for next { 45 shrunkStruct, ok := value.(*downStruct) 46 if !ok { 47 t.Errorf("Invalid shrunk value: %#v", value) 48 } 49 shrunkStructs = append(shrunkStructs, shrunkStruct) 50 value, next = shrink() 51 } 52 53 expected := []*downStruct{ 54 {a: 0, b: "abcd", c: false}, 55 {a: 5, b: "abcd", c: false}, 56 {a: -5, b: "abcd", c: false}, 57 {a: 8, b: "abcd", c: false}, 58 {a: -8, b: "abcd", c: false}, 59 {a: 9, b: "abcd", c: false}, 60 {a: -9, b: "abcd", c: false}, 61 {a: 10, b: "cd", c: false}, 62 {a: 10, b: "ab", c: false}, 63 {a: 10, b: "bcd", c: false}, 64 {a: 10, b: "acd", c: false}, 65 {a: 10, b: "abd", c: false}, 66 {a: 10, b: "abc", c: false}, 67 } 68 if !reflect.DeepEqual(shrunkStructs, expected) { 69 t.Errorf("%v does not equal %v", shrunkStructs, expected) 70 } 71 } 72 73 func TestDeriveGenSingleDownWithSieves(t *testing.T) { 74 gen := gopter.DeriveGen( 75 func(a int, b string, c bool) *downStruct { 76 return &downStruct{a: a, b: b, c: c} 77 }, 78 func(d *downStruct) (int, string, bool) { 79 return d.a, d.b, d.c 80 }, 81 gen.Int().SuchThat(func(i int) bool { 82 return i%2 == 0 83 }), 84 gen.AnyString(), 85 gen.Bool(), 86 ) 87 88 parameters := gopter.DefaultGenParameters() 89 parameters.Rng.Seed(1234) 90 91 hasNoValue := false 92 sawEven := false 93 sawOdd := false 94 for i := 0; i < 100; i++ { 95 result := gen(parameters) 96 val, ok := result.Retrieve() 97 if ok { 98 ds := val.(*downStruct) 99 if ds.a%2 == 0 { 100 sawEven = true 101 } else { 102 sawOdd = true 103 } 104 } else { 105 hasNoValue = true 106 } 107 } 108 if !hasNoValue { 109 t.Error("Sieve is not applied") 110 } 111 112 if !sawEven { 113 t.Error("Sieve did not pass even") 114 } 115 116 if sawOdd { 117 t.Error("Sieve did pass odd") 118 } 119 } 120 121 func TestDeriveGenMultiDown(t *testing.T) { 122 gen := gopter.DeriveGen( 123 func(a int, b string, c bool, d int32) (*downStruct, int64) { 124 return &downStruct{a: a, b: b, c: c}, int64(a) + int64(d) 125 }, 126 func(d *downStruct, diff int64) (int, string, bool, int32) { 127 return d.a, d.b, d.c, int32(diff - int64(d.a)) 128 }, 129 gen.Int(), 130 gen.AnyString(), 131 gen.Bool(), 132 gen.Int32(), 133 ) 134 135 sample, ok := gen.Sample() 136 if !ok { 137 t.Error("Sample not ok") 138 } 139 values, ok := sample.([]interface{}) 140 if !ok || len(values) != 2 { 141 t.Errorf("%#v is not a slice of interface", sample) 142 } 143 _, ok = values[0].(*downStruct) 144 if !ok { 145 t.Errorf("%#v is not a downStruct", values[0]) 146 } 147 _, ok = values[1].(int64) 148 if !ok { 149 t.Errorf("%#v is not a int64", values[1]) 150 } 151 152 shrinker := gen(gopter.DefaultGenParameters()).Shrinker 153 shrink := shrinker([]interface{}{&downStruct{a: 10, b: "abcd", c: false}, int64(20)}) 154 155 value, next := shrink() 156 shrunkValues := make([][]interface{}, 0) 157 for next { 158 shrunk, ok := value.([]interface{}) 159 if !ok || len(values) != 2 { 160 t.Errorf("%#v is not a slice of interface", sample) 161 } 162 shrunkValues = append(shrunkValues, shrunk) 163 value, next = shrink() 164 } 165 166 expected := [][]interface{}{ 167 {&downStruct{a: 0, b: "abcd", c: false}, int64(10)}, 168 {&downStruct{a: 5, b: "abcd", c: false}, int64(15)}, 169 {&downStruct{a: -5, b: "abcd", c: false}, int64(5)}, 170 {&downStruct{a: 8, b: "abcd", c: false}, int64(18)}, 171 {&downStruct{a: -8, b: "abcd", c: false}, int64(2)}, 172 {&downStruct{a: 9, b: "abcd", c: false}, int64(19)}, 173 {&downStruct{a: -9, b: "abcd", c: false}, int64(1)}, 174 {&downStruct{a: 10, b: "cd", c: false}, int64(20)}, 175 {&downStruct{a: 10, b: "ab", c: false}, int64(20)}, 176 {&downStruct{a: 10, b: "bcd", c: false}, int64(20)}, 177 {&downStruct{a: 10, b: "acd", c: false}, int64(20)}, 178 {&downStruct{a: 10, b: "abd", c: false}, int64(20)}, 179 {&downStruct{a: 10, b: "abc", c: false}, int64(20)}, 180 {&downStruct{a: 10, b: "abcd", c: false}, int64(10)}, 181 {&downStruct{a: 10, b: "abcd", c: false}, int64(15)}, 182 {&downStruct{a: 10, b: "abcd", c: false}, int64(5)}, 183 {&downStruct{a: 10, b: "abcd", c: false}, int64(18)}, 184 {&downStruct{a: 10, b: "abcd", c: false}, int64(2)}, 185 {&downStruct{a: 10, b: "abcd", c: false}, int64(19)}, 186 {&downStruct{a: 10, b: "abcd", c: false}, int64(1)}, 187 } 188 189 if !reflect.DeepEqual(shrunkValues, expected) { 190 t.Errorf("%v does not equal %v", shrunkValues, expected) 191 } 192 } 193 194 func TestDeriveGenVaryingSieveAndShrinker(t *testing.T) { 195 gen := gopter.DeriveGen( 196 func(a interface{}) interface{} { 197 return a 198 }, 199 func(a interface{}) interface{} { 200 return a 201 }, 202 gen.OneGenOf(gen.AnyString(), gen.Int()), 203 ) 204 205 parameters := gopter.DefaultGenParameters() 206 parameters.Rng.Seed(1234) 207 208 for i := 0; i < 20; i++ { 209 result := gen(parameters) 210 sample, ok := result.Retrieve() 211 if !ok { 212 t.Error("Sample not ok") 213 } 214 if stringval, ok := sample.(string); ok { 215 // check that the Shrinker doesn't panic 216 result.Shrinker(stringval) 217 } else if intval, ok := sample.(int); ok { 218 result.Shrinker(intval) 219 } else { 220 t.Errorf("%#v is not a string or int", sample) 221 } 222 } 223 }