1package gen
2
3import (
4	"math"
5	"reflect"
6
7	"github.com/leanovate/gopter"
8)
9
10// Int64Range generates int64 numbers within a given range
11func Int64Range(min, max int64) gopter.Gen {
12	if max < min {
13		return Fail(reflect.TypeOf(int64(0)))
14	}
15	if max == math.MaxInt64 && min == math.MinInt64 { // Check for range overflow
16		return func(genParams *gopter.GenParameters) *gopter.GenResult {
17			return gopter.NewGenResult(genParams.NextInt64(), Int64Shrinker)
18		}
19	}
20
21	rangeSize := uint64(max - min + 1)
22	return func(genParams *gopter.GenParameters) *gopter.GenResult {
23		var nextResult = uint64(min) + (genParams.NextUint64() % rangeSize)
24		genResult := gopter.NewGenResult(int64(nextResult), Int64Shrinker)
25		genResult.Sieve = func(v interface{}) bool {
26			return v.(int64) >= min && v.(int64) <= max
27		}
28		return genResult
29	}
30}
31
32// UInt64Range generates uint64 numbers within a given range
33func UInt64Range(min, max uint64) gopter.Gen {
34	if max < min {
35		return Fail(reflect.TypeOf(uint64(0)))
36	}
37	d := max - min + 1
38	if d == 0 { // Check overflow (i.e. max = MaxInt64, min = MinInt64)
39		return func(genParams *gopter.GenParameters) *gopter.GenResult {
40			return gopter.NewGenResult(genParams.NextUint64(), UInt64Shrinker)
41		}
42	}
43	return func(genParams *gopter.GenParameters) *gopter.GenResult {
44		genResult := gopter.NewGenResult(min+genParams.NextUint64()%d, UInt64Shrinker)
45		genResult.Sieve = func(v interface{}) bool {
46			return v.(uint64) >= min && v.(uint64) <= max
47		}
48		return genResult
49	}
50}
51
52// Int64 generates an arbitrary int64 number
53func Int64() gopter.Gen {
54	return Int64Range(math.MinInt64, math.MaxInt64)
55}
56
57// UInt64 generates an arbitrary Uint64 number
58func UInt64() gopter.Gen {
59	return UInt64Range(0, math.MaxUint64)
60}
61
62// Int32Range generates int32 numbers within a given range
63func Int32Range(min, max int32) gopter.Gen {
64	return Int64Range(int64(min), int64(max)).
65		Map(int64To32).
66		WithShrinker(Int32Shrinker).
67		SuchThat(func(v int32) bool {
68			return v >= min && v <= max
69		})
70}
71
72// UInt32Range generates uint32 numbers within a given range
73func UInt32Range(min, max uint32) gopter.Gen {
74	return UInt64Range(uint64(min), uint64(max)).
75		Map(uint64To32).
76		WithShrinker(UInt32Shrinker).
77		SuchThat(func(v uint32) bool {
78			return v >= min && v <= max
79		})
80}
81
82// Int32 generate arbitrary int32 numbers
83func Int32() gopter.Gen {
84	return Int32Range(math.MinInt32, math.MaxInt32)
85}
86
87// UInt32 generate arbitrary int32 numbers
88func UInt32() gopter.Gen {
89	return UInt32Range(0, math.MaxUint32)
90}
91
92// Int16Range generates int16 numbers within a given range
93func Int16Range(min, max int16) gopter.Gen {
94	return Int64Range(int64(min), int64(max)).
95		Map(int64To16).
96		WithShrinker(Int16Shrinker).
97		SuchThat(func(v int16) bool {
98			return v >= min && v <= max
99		})
100}
101
102// UInt16Range generates uint16 numbers within a given range
103func UInt16Range(min, max uint16) gopter.Gen {
104	return UInt64Range(uint64(min), uint64(max)).
105		Map(uint64To16).
106		WithShrinker(UInt16Shrinker).
107		SuchThat(func(v uint16) bool {
108			return v >= min && v <= max
109		})
110}
111
112// Int16 generate arbitrary int16 numbers
113func Int16() gopter.Gen {
114	return Int16Range(math.MinInt16, math.MaxInt16)
115}
116
117// UInt16 generate arbitrary uint16 numbers
118func UInt16() gopter.Gen {
119	return UInt16Range(0, math.MaxUint16)
120}
121
122// Int8Range generates int8 numbers within a given range
123func Int8Range(min, max int8) gopter.Gen {
124	return Int64Range(int64(min), int64(max)).
125		Map(int64To8).
126		WithShrinker(Int8Shrinker).
127		SuchThat(func(v int8) bool {
128			return v >= min && v <= max
129		})
130}
131
132// UInt8Range generates uint8 numbers within a given range
133func UInt8Range(min, max uint8) gopter.Gen {
134	return UInt64Range(uint64(min), uint64(max)).
135		Map(uint64To8).
136		WithShrinker(UInt8Shrinker).
137		SuchThat(func(v uint8) bool {
138			return v >= min && v <= max
139		})
140}
141
142// Int8 generate arbitrary int8 numbers
143func Int8() gopter.Gen {
144	return Int8Range(math.MinInt8, math.MaxInt8)
145}
146
147// UInt8 generate arbitrary uint8 numbers
148func UInt8() gopter.Gen {
149	return UInt8Range(0, math.MaxUint8)
150}
151
152// IntRange generates int numbers within a given range
153func IntRange(min, max int) gopter.Gen {
154	return Int64Range(int64(min), int64(max)).
155		Map(int64ToInt).
156		WithShrinker(IntShrinker).
157		SuchThat(func(v int) bool {
158			return v >= min && v <= max
159		})
160}
161
162// Int generate arbitrary int numbers
163func Int() gopter.Gen {
164	return Int64Range(math.MinInt32, math.MaxInt32).
165		Map(int64ToInt).
166		WithShrinker(IntShrinker)
167}
168
169// UIntRange generates uint numbers within a given range
170func UIntRange(min, max uint) gopter.Gen {
171	return UInt64Range(uint64(min), uint64(max)).
172		Map(uint64ToUint).
173		WithShrinker(UIntShrinker).
174		SuchThat(func(v uint) bool {
175			return v >= min && v <= max
176		})
177}
178
179// UInt generate arbitrary uint numbers
180func UInt() gopter.Gen {
181	return UInt64Range(0, math.MaxUint32).
182		Map(uint64ToUint).
183		WithShrinker(UIntShrinker)
184}
185
186// Size just extracts the MaxSize field of the GenParameters.
187// This can be helpful to generate limited integer value in a more structued
188// manner.
189func Size() gopter.Gen {
190	return func(genParams *gopter.GenParameters) *gopter.GenResult {
191		return gopter.NewGenResult(genParams.MaxSize, IntShrinker)
192	}
193}
194
195func int64To32(value int64) int32 {
196	return int32(value)
197}
198
199func uint64To32(value uint64) uint32 {
200	return uint32(value)
201}
202
203func int64To16(value int64) int16 {
204	return int16(value)
205}
206
207func uint64To16(value uint64) uint16 {
208	return uint16(value)
209}
210
211func int64To8(value int64) int8 {
212	return int8(value)
213}
214
215func uint64To8(value uint64) uint8 {
216	return uint8(value)
217}
218
219func int64ToInt(value int64) int {
220	return int(value)
221}
222
223func uint64ToUint(value uint64) uint {
224	return uint(value)
225}
226