1package gopter_test
2
3import (
4	"reflect"
5	"testing"
6
7	"github.com/leanovate/gopter"
8)
9
10func constGen(value interface{}) gopter.Gen {
11	return func(*gopter.GenParameters) *gopter.GenResult {
12		return gopter.NewGenResult(value, gopter.NoShrinker)
13	}
14}
15
16func TestGenSample(t *testing.T) {
17	gen := constGen("sample")
18
19	value, ok := gen.Sample()
20	if !ok || value != "sample" {
21		t.Errorf("Invalid gen sample: %#v", value)
22	}
23}
24
25func BenchmarkMap(b *testing.B) {
26	for i := 0; i < b.N; i++ {
27		gen := constGen("sample")
28		var mappedWith string
29		mapper := func(v string) string {
30			mappedWith = v
31			return "other"
32		}
33		value, ok := gen.Map(mapper).Sample()
34		if !ok || value != "other" {
35			b.Errorf("Invalid gen sample: %#v", value)
36		}
37		if mappedWith != "sample" {
38			b.Errorf("Invalid mapped with: %#v", mappedWith)
39		}
40
41		gen = gen.SuchThat(func(interface{}) bool {
42			return false
43		})
44		value, ok = gen.Map(mapper).Sample()
45		if ok {
46			b.Errorf("Invalid gen sample: %#v", value)
47		}
48	}
49}
50
51func TestGenMap(t *testing.T) {
52	gen := constGen("sample")
53	var mappedWith string
54	mapper := func(v string) string {
55		mappedWith = v
56		return "other"
57	}
58	value, ok := gen.Map(mapper).Sample()
59	if !ok || value != "other" {
60		t.Errorf("Invalid gen sample: %#v", value)
61	}
62	if mappedWith != "sample" {
63		t.Errorf("Invalid mapped with: %#v", mappedWith)
64	}
65
66	gen = gen.SuchThat(func(interface{}) bool {
67		return false
68	})
69	value, ok = gen.Map(mapper).Sample()
70	if ok {
71		t.Errorf("Invalid gen sample: %#v", value)
72	}
73}
74
75func TestGenMapWithParams(t *testing.T) {
76	gen := constGen("sample")
77	var mappedWith string
78	var mappedWithParams *gopter.GenParameters
79	mapper := func(v string, params *gopter.GenParameters) string {
80		mappedWith = v
81		mappedWithParams = params
82		return "other"
83	}
84	value, ok := gen.Map(mapper).Sample()
85	if !ok || value != "other" {
86		t.Errorf("Invalid gen sample: %#v", value)
87	}
88	if mappedWith != "sample" {
89		t.Errorf("Invalid mapped with: %#v", mappedWith)
90	}
91	if mappedWithParams == nil || mappedWithParams.MaxSize != 100 {
92		t.Error("Mapper not called with currect parameters")
93	}
94
95	gen = gen.SuchThat(func(interface{}) bool {
96		return false
97	})
98	value, ok = gen.Map(mapper).Sample()
99	if ok {
100		t.Errorf("Invalid gen sample: %#v", value)
101	}
102}
103
104func TestGenMapNoFunc(t *testing.T) {
105	defer expectPanic(t, "Param of Map has to be a func, but is string")
106	constGen("sample").Map("not a function")
107}
108
109func TestGenMapTooManyParams(t *testing.T) {
110	defer expectPanic(t, "Param of Map has to be a func with one or two params, but is 3")
111	constGen("sample").Map(func(a, b, C string) string {
112		return ""
113	})
114}
115
116func TestGenMapInvalidSecondParam(t *testing.T) {
117	defer expectPanic(t, "Second parameter of mapper function has to be a *GenParameters")
118	constGen("sample").Map(func(a, b string) string {
119		return ""
120	})
121}
122
123func TestGenMapToInvalidParamtype(t *testing.T) {
124	defer expectPanic(t, "Param of Map has to be a func with one param assignable to string, but is int")
125	constGen("sample").Map(func(a int) string {
126		return ""
127	})
128}
129
130func TestGenMapToManyReturns(t *testing.T) {
131	defer expectPanic(t, "Param of Map has to be a func with one return value, but is 2")
132	constGen("sample").Map(func(a string) (string, bool) {
133		return "", false
134	})
135}
136
137func TestGenMapResultIn(t *testing.T) {
138	gen := constGen("sample")
139	var mappedWith *gopter.GenResult
140	mapper := func(result *gopter.GenResult) string {
141		mappedWith = result
142		return "other"
143	}
144
145	value, ok := gen.Map(mapper).Sample()
146	if !ok || value != "other" {
147		t.Errorf("Invalid gen sample: %#v", value)
148	}
149	if mappedWith == nil {
150		t.Error("Mapper not called")
151	}
152	if mapperValue, ok := mappedWith.Retrieve(); !ok || mapperValue != "sample" {
153		t.Errorf("Mapper was called with invalid value: %#v", mapperValue)
154	}
155}
156
157func TestGenMapResultInWithParams(t *testing.T) {
158	gen := constGen("sample")
159	var mappedWith *gopter.GenResult
160	var mappedWithParams *gopter.GenParameters
161	mapper := func(result *gopter.GenResult, params *gopter.GenParameters) string {
162		mappedWith = result
163		mappedWithParams = params
164		return "other"
165	}
166
167	value, ok := gen.Map(mapper).Sample()
168	if !ok || value != "other" {
169		t.Errorf("Invalid gen sample: %#v", value)
170	}
171	if mappedWith == nil {
172		t.Error("Mapper not called")
173	}
174	if mappedWithParams == nil || mappedWithParams.MaxSize != 100 {
175		t.Error("Mapper not called with currect parameters")
176	}
177	if mapperValue, ok := mappedWith.Retrieve(); !ok || mapperValue != "sample" {
178		t.Errorf("Mapper was called with invalid value: %#v", mapperValue)
179	}
180}
181
182func TestGenMapResultOut(t *testing.T) {
183	gen := constGen("sample")
184	var mappedWith string
185	mapper := func(v string) *gopter.GenResult {
186		mappedWith = v
187		return gopter.NewGenResult("other", gopter.NoShrinker)
188	}
189	value, ok := gen.Map(mapper).Sample()
190	if !ok || value != "other" {
191		t.Errorf("Invalid gen sample: %#v", value)
192	}
193	if mappedWith != "sample" {
194		t.Errorf("Invalid mapped with: %#v", mappedWith)
195	}
196
197	gen = gen.SuchThat(func(interface{}) bool {
198		return false
199	})
200	value, ok = gen.Map(mapper).Sample()
201	if ok {
202		t.Errorf("Invalid gen sample: %#v", value)
203	}
204}
205
206func TestGenMapResultInOut(t *testing.T) {
207	gen := constGen("sample")
208	var mappedWith *gopter.GenResult
209	mapper := func(result *gopter.GenResult) *gopter.GenResult {
210		mappedWith = result
211		return gopter.NewGenResult("other", gopter.NoShrinker)
212	}
213
214	value, ok := gen.Map(mapper).Sample()
215	if !ok || value != "other" {
216		t.Errorf("Invalid gen sample: %#v", value)
217	}
218	if mappedWith == nil {
219		t.Error("Mapper not called")
220	}
221	if mapperValue, ok := mappedWith.Retrieve(); !ok || mapperValue != "sample" {
222		t.Errorf("Mapper was called with invalid value: %#v", mapperValue)
223	}
224}
225
226func TestGenFlatMap(t *testing.T) {
227	gen := constGen("sample")
228	var mappedWith interface{}
229	mapper := func(v interface{}) gopter.Gen {
230		mappedWith = v
231		return constGen("other")
232	}
233	value, ok := gen.FlatMap(mapper, reflect.TypeOf("")).Sample()
234	if !ok || value != "other" {
235		t.Errorf("Invalid gen sample: %#v", value)
236	}
237	if mappedWith.(string) != "sample" {
238		t.Errorf("Invalid mapped with: %#v", mappedWith)
239	}
240
241	gen = gen.SuchThat(func(interface{}) bool {
242		return false
243	})
244	value, ok = gen.FlatMap(mapper, reflect.TypeOf("")).Sample()
245	if ok {
246		t.Errorf("Invalid gen sample: %#v", value)
247	}
248}
249
250func TestGenMapResult(t *testing.T) {
251	gen := constGen("sample")
252	var mappedWith *gopter.GenResult
253	mapper := func(result *gopter.GenResult) *gopter.GenResult {
254		mappedWith = result
255		return gopter.NewGenResult("other", gopter.NoShrinker)
256	}
257
258	value, ok := gen.MapResult(mapper).Sample()
259	if !ok || value != "other" {
260		t.Errorf("Invalid gen sample: %#v", value)
261	}
262	if mappedWith == nil {
263		t.Error("Mapper not called")
264	}
265	if mapperValue, ok := mappedWith.Retrieve(); !ok || mapperValue != "sample" {
266		t.Errorf("Mapper was called with invalid value: %#v", mapperValue)
267	}
268}
269
270func TestCombineGens(t *testing.T) {
271	gens := make([]gopter.Gen, 0, 20)
272	for i := 0; i < 20; i++ {
273		gens = append(gens, constGen(i))
274	}
275	gen := gopter.CombineGens(gens...)
276	raw, ok := gen.Sample()
277	if !ok {
278		t.Errorf("Invalid combined gen: %#v", raw)
279	}
280	values, ok := raw.([]interface{})
281	if !ok || !reflect.DeepEqual(values, []interface{}{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}) {
282		t.Errorf("Invalid combined gen: %#v", raw)
283	}
284
285	gens[0] = gens[0].SuchThat(func(interface{}) bool {
286		return false
287	})
288	gen = gopter.CombineGens(gens...)
289	raw, ok = gen.Sample()
290	if ok {
291		t.Errorf("Invalid combined gen: %#v", raw)
292	}
293}
294
295func TestSuchThat(t *testing.T) {
296	var sieveArg string
297	sieve := func(v string) bool {
298		sieveArg = v
299		return true
300	}
301	gen := constGen("sample").SuchThat(sieve)
302	value, ok := gen.Sample()
303	if !ok || value != "sample" {
304		t.Errorf("Invalid result: %#v", value)
305	}
306	if sieveArg != "sample" {
307		t.Errorf("Invalid sieveArg: %#v", sieveArg)
308	}
309
310	sieveArg = ""
311	var sieve2Arg string
312	sieve2 := func(v string) bool {
313		sieve2Arg = v
314		return false
315	}
316	gen = gen.SuchThat(sieve2)
317	_, ok = gen.Sample()
318	if ok {
319		t.Error("Did not expect a result")
320	}
321	if sieveArg != "sample" {
322		t.Errorf("Invalid sieveArg: %#v", sieveArg)
323	}
324	if sieve2Arg != "sample" {
325		t.Errorf("Invalid sieve2Arg: %#v", sieve2Arg)
326	}
327}
328
329func TestGenSuchThatNoFunc(t *testing.T) {
330	defer expectPanic(t, "Param of SuchThat has to be a func, but is string")
331	constGen("sample").SuchThat("not a function")
332}
333
334func TestGenSuchTooManyParams(t *testing.T) {
335	defer expectPanic(t, "Param of SuchThat has to be a func with one param, but is 2")
336	constGen("sample").SuchThat(func(a, b string) bool {
337		return false
338	})
339}
340
341func TestGenSuchThatToInvalidParamtype(t *testing.T) {
342	defer expectPanic(t, "Param of SuchThat has to be a func with one param assignable to string, but is int")
343	constGen("sample").SuchThat(func(a int) bool {
344		return false
345	})
346}
347
348func TestGenSuchToManyReturns(t *testing.T) {
349	defer expectPanic(t, "Param of SuchThat has to be a func with one return value, but is 2")
350	constGen("sample").SuchThat(func(a string) (string, bool) {
351		return "", false
352	})
353}
354
355func TestGenSuchToInvalidReturns(t *testing.T) {
356	defer expectPanic(t, "Param of SuchThat has to be a func with one return value of bool, but is string")
357	constGen("sample").SuchThat(func(a string) string {
358		return ""
359	})
360}
361
362func TestWithShrinker(t *testing.T) {
363	var shrinkerArg interface{}
364	shrinker := func(v interface{}) gopter.Shrink {
365		shrinkerArg = v
366		return gopter.NoShrink
367	}
368	gen := constGen("sample").WithShrinker(shrinker)
369	result := gen(gopter.DefaultGenParameters())
370	value, ok := result.Retrieve()
371	if !ok {
372		t.Errorf("Invalid combined value: %#v", value)
373	}
374	result.Shrinker(value)
375	if shrinkerArg != "sample" {
376		t.Errorf("Invalid shrinkerArg: %#v", shrinkerArg)
377	}
378}
379
380func expectPanic(t *testing.T, expected string) {
381	r := recover()
382	if r == nil {
383		t.Errorf("The code did not panic")
384	} else if r.(string) != expected {
385		t.Errorf("Panic does not match: '%#v' != '%#v'", r, expected)
386	}
387}
388