0
# Generator Framework
1
2
The ScalaCheck generator framework provides comprehensive data generation capabilities for property-based testing. Generators create test values with configurable size parameters, deterministic seeds, and powerful combinators for building complex test data.
3
4
## Capabilities
5
6
### Core Generator Class
7
8
The fundamental generator abstraction with transformation, filtering, and sampling capabilities.
9
10
```scala { .api }
11
abstract class Gen[+T] {
12
def map[U](f: T => U): Gen[U]
13
def flatMap[U](f: T => Gen[U]): Gen[U]
14
def filter(p: T => Boolean): Gen[T]
15
def filterNot(p: T => Boolean): Gen[T]
16
def suchThat(f: T => Boolean): Gen[T]
17
def retryUntil(p: T => Boolean, maxTries: Int = 10): Gen[T]
18
def sample: Option[T]
19
def pureApply(p: Gen.Parameters, seed: Seed, retries: Int = 100): T
20
def label(l: String): Gen[T]
21
def :|(l: String): Gen[T]
22
def |:(l: String): Gen[T]
23
}
24
```
25
26
**Usage Example:**
27
```scala
28
val evenInts = Gen.choose(1, 100).filter(_ % 2 == 0)
29
val positiveStrings = Gen.alphaStr.suchThat(_.nonEmpty)
30
val taggedGen = Gen.choose(1, 10).label("small integers")
31
```
32
33
### Basic Generators
34
35
Fundamental generators for constant values, ranges, and selections.
36
37
```scala { .api }
38
object Gen {
39
def const[T](x: T): Gen[T]
40
def fail[T]: Gen[T]
41
def choose[T](min: T, max: T)(implicit num: Choose[T]): Gen[T]
42
def oneOf[T](xs: Iterable[T]): Gen[T]
43
def oneOf[T](t0: T, t1: T, tn: T*): Gen[T]
44
def frequency[T](gs: (Int, Gen[T])*): Gen[T]
45
def prob(chance: Double): Gen[Boolean]
46
}
47
```
48
49
**Usage Examples:**
50
```scala
51
val alwaysTrue = Gen.const(true)
52
val dice = Gen.choose(1, 6)
53
val coin = Gen.oneOf(true, false)
54
val weightedCoin = Gen.frequency(3 -> true, 1 -> false) // 75% true
55
val biasedCoin = Gen.prob(0.7) // 70% true
56
```
57
58
### Optional and Either Generators
59
60
Generators for optional values and Either types.
61
62
```scala { .api }
63
def option[T](g: Gen[T]): Gen[Option[T]]
64
def some[T](g: Gen[T]): Gen[Option[T]]
65
def either[T, U](gt: Gen[T], gu: Gen[U]): Gen[Either[T, U]]
66
```
67
68
**Usage Examples:**
69
```scala
70
val maybeInt = Gen.option(Gen.choose(1, 10))
71
val someInt = Gen.some(Gen.choose(1, 10)) // never generates None
72
val stringOrInt = Gen.either(Gen.alphaStr, Gen.choose(1, 100))
73
```
74
75
### Collection Generators
76
77
Comprehensive collection generation with size control and various collection types.
78
79
```scala { .api }
80
def listOf[T](g: Gen[T]): Gen[List[T]]
81
def listOfN[T](n: Int, g: Gen[T]): Gen[List[T]]
82
def nonEmptyListOf[T](g: Gen[T]): Gen[List[T]]
83
def containerOf[C[_], T](g: Gen[T])(implicit b: Buildable[T, C[T]]): Gen[C[T]]
84
def containerOfN[C[_], T](n: Int, g: Gen[T])(implicit b: Buildable[T, C[T]]): Gen[C[T]]
85
def nonEmptyContainerOf[C[_], T](g: Gen[T])(implicit b: Buildable[T, C[T]]): Gen[C[T]]
86
def mapOf[T, U](g: Gen[(T, U)]): Gen[Map[T, U]]
87
def mapOfN[T, U](n: Int, g: Gen[(T, U)]): Gen[Map[T, U]]
88
def nonEmptyMap[T, U](g: Gen[(T, U)]): Gen[Map[T, U]]
89
```
90
91
**Usage Examples:**
92
```scala
93
val intLists = Gen.listOf(Gen.choose(1, 10))
94
val exactly5Ints = Gen.listOfN(5, Gen.choose(1, 100))
95
val nonEmptyStrings = Gen.nonEmptyListOf(Gen.alphaChar.map(_.toString))
96
val intToStringMap = Gen.mapOf(Gen.zip(Gen.choose(1, 10), Gen.alphaStr))
97
val vectors = Gen.containerOf[Vector, Int](Gen.choose(1, 100))
98
```
99
100
### Subset and Picking Generators
101
102
Generators for selecting subsets and elements from existing collections.
103
104
```scala { .api }
105
def pick[T](n: Int, l: Iterable[T]): Gen[Seq[T]]
106
def someOf[T](l: Iterable[T]): Gen[Seq[T]]
107
def atLeastOne[T](l: Iterable[T]): Gen[Seq[T]]
108
```
109
110
**Usage Examples:**
111
```scala
112
val colors = List("red", "green", "blue", "yellow", "purple")
113
val threeColors = Gen.pick(3, colors)
114
val someColors = Gen.someOf(colors)
115
val atLeastOneColor = Gen.atLeastOne(colors)
116
```
117
118
### String and Character Generators
119
120
Specialized generators for characters and strings with various character sets.
121
122
```scala { .api }
123
val numChar: Gen[Char]
124
val alphaUpperChar: Gen[Char]
125
val alphaLowerChar: Gen[Char]
126
val alphaChar: Gen[Char]
127
val alphaNumChar: Gen[Char]
128
val asciiChar: Gen[Char]
129
val asciiPrintableChar: Gen[Char]
130
val hexChar: Gen[Char]
131
132
def stringOf(gc: Gen[Char]): Gen[String]
133
def stringOfN(n: Int, gc: Gen[Char]): Gen[String]
134
def nonEmptyStringOf(gc: Gen[Char]): Gen[String]
135
136
val identifier: Gen[String]
137
val numStr: Gen[String]
138
val alphaStr: Gen[String]
139
val alphaNumStr: Gen[String]
140
val asciiStr: Gen[String]
141
val hexStr: Gen[String]
142
```
143
144
**Usage Examples:**
145
```scala
146
val passwords = Gen.stringOfN(8, Gen.alphaNumChar)
147
val identifiers = Gen.identifier
148
val hexStrings = Gen.stringOf(Gen.hexChar)
149
val nonEmptyNames = Gen.nonEmptyStringOf(Gen.alphaChar)
150
```
151
152
### Numeric Generators
153
154
Generators for various numeric types with special values and distributions.
155
156
```scala { .api }
157
val long: Gen[Long]
158
val double: Gen[Double] // [0, 1)
159
def posNum[T](implicit num: Numeric[T], c: Choose[T]): Gen[T]
160
def negNum[T](implicit num: Numeric[T], c: Choose[T]): Gen[T]
161
def chooseNum[T](minT: T, maxT: T, specials: T*)(implicit num: Numeric[T], c: Choose[T]): Gen[T]
162
163
// Distribution generators
164
def gaussian(mean: Double, stdDev: Double): Gen[Double]
165
def exponential(rate: Double): Gen[Double]
166
def geometric(mean: Double): Gen[Int]
167
def poisson(rate: Double): Gen[Int]
168
def binomial(test: Gen[Boolean], trials: Int): Gen[Int]
169
```
170
171
**Usage Examples:**
172
```scala
173
val positiveInts = Gen.posNum[Int]
174
val negativeDoubles = Gen.negNum[Double]
175
val specialInts = Gen.chooseNum(1, 100, 42, 13, 7) // includes special values
176
val normalDistrib = Gen.gaussian(0.0, 1.0)
177
val coinFlips = Gen.binomial(Gen.prob(0.5), 10)
178
```
179
180
### Miscellaneous Generators
181
182
Generators for UUIDs, dates, and durations.
183
184
```scala { .api }
185
val uuid: Gen[UUID]
186
val calendar: Gen[Calendar]
187
val finiteDuration: Gen[FiniteDuration]
188
val duration: Gen[Duration] // includes infinite durations
189
```
190
191
**Usage Examples:**
192
```scala
193
val ids = Gen.uuid
194
val timestamps = Gen.calendar
195
val timeouts = Gen.finiteDuration
196
val allDurations = Gen.duration // may include Duration.Inf
197
```
198
199
### Advanced Combinators
200
201
Powerful combinators for complex generator composition and control flow.
202
203
```scala { .api }
204
def sequence[C[_], T](gs: Traversable[Gen[T]])(implicit b: Buildable[T, C[T]]): Gen[C[T]]
205
def tailRecM[A, B](a0: A)(fn: A => Gen[Either[A, B]]): Gen[B]
206
def lzy[T](g: => Gen[T]): Gen[T]
207
def delay[T](g: => Gen[T]): Gen[T]
208
def recursive[A](fn: Gen[A] => Gen[A]): Gen[A]
209
def parameterized[T](f: Gen.Parameters => Gen[T]): Gen[T]
210
def sized[T](f: Int => Gen[T]): Gen[T]
211
val size: Gen[Int]
212
def resize[T](s: Int, g: Gen[T]): Gen[T]
213
```
214
215
**Usage Examples:**
216
```scala
217
// Generate lists of generators into generator of lists
218
val genList = List(Gen.choose(1, 10), Gen.choose(20, 30), Gen.choose(40, 50))
219
val combined = Gen.sequence(genList)
220
221
// Size-dependent generation
222
val sizedLists = Gen.sized(n => Gen.listOfN(n, Gen.choose(1, 100)))
223
224
// Recursive data structures
225
case class Tree(value: Int, children: List[Tree])
226
val treeGen = Gen.recursive[Tree] { recurse =>
227
for {
228
value <- Gen.choose(1, 100)
229
size <- Gen.choose(0, 3)
230
children <- Gen.listOfN(size, recurse)
231
} yield Tree(value, children)
232
}
233
234
// Parameter access
235
val customGen = Gen.parameterized { params =>
236
Gen.listOfN(params.size, Gen.alphaChar)
237
}
238
```
239
240
### Zip Combinators
241
242
Combining multiple generators into tuples.
243
244
```scala { .api }
245
def zip[T, U](gt: Gen[T], gu: Gen[U]): Gen[(T, U)]
246
def zip[A, B, C](ga: Gen[A], gb: Gen[B], gc: Gen[C]): Gen[(A, B, C)]
247
// ... up to 9-tuples
248
```
249
250
**Usage Examples:**
251
```scala
252
val coordinates = Gen.zip(Gen.choose(-100, 100), Gen.choose(-100, 100))
253
val person = Gen.zip(Gen.alphaStr, Gen.choose(18, 80), Gen.oneOf("M", "F"))
254
```
255
256
## Types
257
258
### Generator Parameters
259
260
```scala { .api }
261
sealed abstract class Gen.Parameters {
262
val size: Int
263
val initialSeed: Option[Seed]
264
val useLegacyShrinking: Boolean
265
266
def withSize(size: Int): Gen.Parameters
267
def withInitialSeed(seed: Seed): Gen.Parameters
268
def withLegacyShrinking(b: Boolean): Gen.Parameters
269
}
270
271
object Gen.Parameters {
272
val default: Gen.Parameters
273
}
274
```
275
276
### Choose Type Class
277
278
```scala { .api }
279
trait Choose[T] {
280
def choose(min: T, max: T): Gen[T]
281
}
282
283
// Implicit instances for numeric types
284
implicit val chooseInt: Choose[Int]
285
implicit val chooseLong: Choose[Long]
286
implicit val chooseDouble: Choose[Double]
287
implicit val chooseChar: Choose[Char]
288
implicit val chooseBigInt: Choose[BigInt]
289
implicit val chooseBigDecimal: Choose[BigDecimal]
290
implicit val chooseFiniteDuration: Choose[FiniteDuration]
291
```
292
293
## Generator Composition Patterns
294
295
### For-Comprehension Style
296
297
```scala
298
val personGen = for {
299
name <- Gen.alphaStr.suchThat(_.length > 2)
300
age <- Gen.choose(18, 80)
301
email <- Gen.alphaStr.map(_ + "@example.com")
302
} yield Person(name, age, email)
303
```
304
305
### Conditional Generation
306
307
```scala
308
val dataGen = Gen.oneOf(true, false).flatMap { isComplex =>
309
if (isComplex) complexDataGen else simpleDataGen
310
}
311
```
312
313
### Weighted Distribution
314
315
```scala
316
val priorityGen = Gen.frequency(
317
1 -> "LOW",
318
3 -> "MEDIUM",
319
5 -> "HIGH",
320
1 -> "CRITICAL"
321
)
322
```