0
# Automatic Value Generation
1
2
The ScalaCheck Arbitrary framework provides type-directed generator instances for automatic property parameterization. It eliminates the need to explicitly specify generators for common types and enables seamless integration with the property testing system.
3
4
## Capabilities
5
6
### Core Arbitrary Class
7
8
The fundamental type class that wraps generators and provides implicit resolution.
9
10
```scala { .api }
11
sealed abstract class Arbitrary[T] {
12
def arbitrary: Gen[T]
13
}
14
15
object Arbitrary {
16
def apply[T](g: => Gen[T]): Arbitrary[T]
17
def arbitrary[T](implicit a: Arbitrary[T]): Gen[T]
18
}
19
```
20
21
**Usage Examples:**
22
```scala
23
// Create custom Arbitrary instance
24
case class Person(name: String, age: Int)
25
implicit val arbPerson: Arbitrary[Person] = Arbitrary {
26
for {
27
name <- Gen.alphaStr.suchThat(_.nonEmpty)
28
age <- Gen.choose(0, 120)
29
} yield Person(name, age)
30
}
31
32
// Use implicit generator
33
val personProperty = forAll { (p: Person) =>
34
p.age >= 0 && p.name.nonEmpty
35
}
36
37
// Get generator explicitly
38
val personGen: Gen[Person] = Arbitrary.arbitrary[Person]
39
```
40
41
### Primitive Type Instances
42
43
Implicit generators for basic Scala and Java primitive types.
44
45
```scala { .api }
46
implicit val arbBool: Arbitrary[Boolean]
47
implicit val arbInt: Arbitrary[Int]
48
implicit val arbLong: Arbitrary[Long]
49
implicit val arbFloat: Arbitrary[Float]
50
implicit val arbDouble: Arbitrary[Double]
51
implicit val arbChar: Arbitrary[Char]
52
implicit val arbByte: Arbitrary[Byte]
53
implicit val arbShort: Arbitrary[Short]
54
implicit val arbUnit: Arbitrary[Unit]
55
implicit val arbAnyVal: Arbitrary[AnyVal]
56
```
57
58
**Usage Examples:**
59
```scala
60
// These work automatically due to implicit instances
61
val intProp = forAll { (x: Int) => x + 0 == x }
62
val boolProp = forAll { (b: Boolean) => b || !b }
63
val charProp = forAll { (c: Char) => c.toString.length == 1 }
64
val floatProp = forAll { (f: Float) => !f.isNaN ==> (f + 0.0f == f) }
65
```
66
67
### String and Text Types
68
69
Generators for various string and symbolic text representations.
70
71
```scala { .api }
72
implicit val arbString: Arbitrary[String]
73
implicit val arbSymbol: Arbitrary[Symbol]
74
```
75
76
**Usage Examples:**
77
```scala
78
val stringProp = forAll { (s: String) =>
79
s.reverse.reverse == s
80
}
81
82
val symbolProp = forAll { (sym: Symbol) =>
83
Symbol(sym.name) == sym
84
}
85
```
86
87
### Numeric Types
88
89
Arbitrary instances for big numeric types and Java numeric wrappers.
90
91
```scala { .api }
92
implicit val arbBigInt: Arbitrary[BigInt]
93
implicit val arbBigDecimal: Arbitrary[BigDecimal]
94
implicit val arbNumber: Arbitrary[Number]
95
```
96
97
**Usage Examples:**
98
```scala
99
val bigIntProp = forAll { (x: BigInt, y: BigInt) =>
100
x + y == y + x
101
}
102
103
val bigDecimalProp = forAll { (x: BigDecimal) =>
104
x * BigDecimal(1) == x
105
}
106
```
107
108
### Date and Time Types
109
110
Generators for temporal types including legacy Java date/time and Scala durations.
111
112
```scala { .api }
113
implicit val arbDate: Arbitrary[java.util.Date]
114
implicit val arbCalendar: Arbitrary[java.util.Calendar]
115
implicit val arbFiniteDuration: Arbitrary[FiniteDuration]
116
implicit val arbDuration: Arbitrary[Duration]
117
```
118
119
**Usage Examples:**
120
```scala
121
val dateProp = forAll { (d: java.util.Date) =>
122
new java.util.Date(d.getTime) == d
123
}
124
125
val durationProp = forAll { (d1: FiniteDuration, d2: FiniteDuration) =>
126
(d1 + d2) >= d1 && (d1 + d2) >= d2
127
}
128
```
129
130
### Exception Types
131
132
Generators for exception and error hierarchies.
133
134
```scala { .api }
135
implicit val arbThrowable: Arbitrary[Throwable]
136
implicit val arbException: Arbitrary[Exception]
137
implicit val arbError: Arbitrary[Error]
138
```
139
140
**Usage Examples:**
141
```scala
142
val exceptionProp = forAll { (e: Exception) =>
143
e.getMessage != null || e.getMessage == null // Either is valid
144
}
145
```
146
147
### Miscellaneous Types
148
149
Generators for UUIDs, bit sets, and other utility types.
150
151
```scala { .api }
152
implicit val arbUuid: Arbitrary[java.util.UUID]
153
implicit val arbBitSet: Arbitrary[collection.BitSet]
154
```
155
156
**Usage Examples:**
157
```scala
158
val uuidProp = forAll { (u: java.util.UUID) =>
159
java.util.UUID.fromString(u.toString) == u
160
}
161
162
val bitSetProp = forAll { (bs: collection.BitSet) =>
163
bs union bs == bs
164
}
165
```
166
167
### Higher-Order Type Instances
168
169
Automatic generator derivation for generic types and type constructors.
170
171
```scala { .api }
172
implicit def arbOption[T](implicit a: Arbitrary[T]): Arbitrary[Option[T]]
173
implicit def arbEither[T, U](implicit at: Arbitrary[T], au: Arbitrary[U]): Arbitrary[Either[T, U]]
174
implicit def arbTry[T](implicit a: Arbitrary[T]): Arbitrary[Try[T]]
175
implicit def arbFuture[T](implicit a: Arbitrary[T]): Arbitrary[Future[T]]
176
```
177
178
**Usage Examples:**
179
```scala
180
val optionProp = forAll { (opt: Option[String]) =>
181
opt.map(_.length).getOrElse(0) >= 0
182
}
183
184
val eitherProp = forAll { (e: Either[String, Int]) =>
185
e.isLeft || e.isRight
186
}
187
188
val tryProp = forAll { (t: Try[Int]) =>
189
t.isSuccess || t.isFailure
190
}
191
```
192
193
### Collection Type Instances
194
195
Automatic generator derivation for various collection types.
196
197
```scala { .api }
198
implicit def arbContainer[C[_], T](
199
implicit a: Arbitrary[T],
200
b: Buildable[T, C[T]]
201
): Arbitrary[C[T]]
202
203
implicit def arbContainer2[C[_, _], T, U](
204
implicit at: Arbitrary[T],
205
au: Arbitrary[U],
206
b: Buildable[(T, U), C[T, U]]
207
): Arbitrary[C[T, U]]
208
```
209
210
**Usage Examples:**
211
```scala
212
val listProp = forAll { (l: List[Int]) =>
213
l.reverse.reverse == l
214
}
215
216
val vectorProp = forAll { (v: Vector[String]) =>
217
v.length >= 0
218
}
219
220
val mapProp = forAll { (m: Map[String, Int]) =>
221
m.keys.size <= m.size
222
}
223
224
val setProp = forAll { (s: Set[Double]) =>
225
s union s == s
226
}
227
```
228
229
### Function Type Instances
230
231
Generators for function types using co-generators.
232
233
```scala { .api }
234
implicit def arbFunction0[T](implicit a: Arbitrary[T]): Arbitrary[() => T]
235
implicit def arbPartialFunction[A, B](
236
implicit aa: Arbitrary[A],
237
ca: Cogen[A],
238
ab: Arbitrary[B]
239
): Arbitrary[PartialFunction[A, B]]
240
```
241
242
**Usage Examples:**
243
```scala
244
val function0Prop = forAll { (f: () => Int) =>
245
f() == f() // Should be deterministic
246
}
247
248
val pfProp = forAll { (pf: PartialFunction[Int, String], x: Int) =>
249
pf.isDefinedAt(x) ==> (pf(x) != null)
250
}
251
```
252
253
### Java Enum Support
254
255
Automatic generator derivation for Java enumeration types.
256
257
```scala { .api }
258
implicit def arbEnum[A <: java.lang.Enum[A]](
259
implicit tag: reflect.ClassTag[A]
260
): Arbitrary[A]
261
```
262
263
**Usage Examples:**
264
```scala
265
// For Java enum types
266
enum Color { RED, GREEN, BLUE }
267
268
val colorProp = forAll { (c: Color) =>
269
c == Color.RED || c == Color.GREEN || c == Color.BLUE
270
}
271
```
272
273
### Test Infrastructure Types
274
275
Generators for ScalaCheck's own types, useful for meta-testing.
276
277
```scala { .api }
278
implicit val arbProp: Arbitrary[Prop]
279
implicit val arbTestParameters: Arbitrary[Test.Parameters]
280
implicit val arbGenParams: Arbitrary[Gen.Parameters]
281
implicit def arbGen[T](implicit a: Arbitrary[T]): Arbitrary[Gen[T]]
282
```
283
284
**Usage Examples:**
285
```scala
286
val propProp = forAll { (p: Prop) =>
287
// Meta-property: properties should be checkable
288
try { p.check(); true } catch { case _: Exception => true }
289
}
290
291
val genProp = forAll { (g: Gen[Int]) =>
292
g.sample.isDefined || g.sample.isEmpty
293
}
294
```
295
296
## Custom Arbitrary Instances
297
298
### Simple Custom Types
299
300
```scala
301
case class Email(value: String)
302
303
implicit val arbEmail: Arbitrary[Email] = Arbitrary {
304
for {
305
user <- Gen.alphaNumStr.suchThat(_.nonEmpty)
306
domain <- Gen.alphaNumStr.suchThat(_.nonEmpty)
307
tld <- Gen.oneOf("com", "org", "net", "edu")
308
} yield Email(s"$user@$domain.$tld")
309
}
310
```
311
312
### Recursive Data Structures
313
314
```scala
315
sealed trait Tree[+A]
316
case class Leaf[A](value: A) extends Tree[A]
317
case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A]
318
319
implicit def arbTree[A](implicit a: Arbitrary[A]): Arbitrary[Tree[A]] = Arbitrary {
320
val genLeaf = a.arbitrary.map(Leaf(_))
321
322
def genBranch(size: Int): Gen[Tree[A]] =
323
if (size <= 0) genLeaf
324
else Gen.oneOf(
325
genLeaf,
326
for {
327
left <- genBranch(size / 2)
328
right <- genBranch(size / 2)
329
} yield Branch(left, right)
330
)
331
332
Gen.sized(genBranch)
333
}
334
```
335
336
### Constrained Generation
337
338
```scala
339
case class PositiveInt(value: Int)
340
341
implicit val arbPositiveInt: Arbitrary[PositiveInt] = Arbitrary {
342
Gen.choose(1, Int.MaxValue).map(PositiveInt)
343
}
344
345
case class NonEmptyList[A](values: List[A])
346
347
implicit def arbNonEmptyList[A](implicit a: Arbitrary[A]): Arbitrary[NonEmptyList[A]] = Arbitrary {
348
Gen.nonEmptyListOf(a.arbitrary).map(NonEmptyList(_))
349
}
350
```
351
352
### Complex Business Objects
353
354
```scala
355
case class User(
356
id: Long,
357
username: String,
358
email: String,
359
age: Int,
360
roles: Set[String],
361
settings: Map[String, String]
362
)
363
364
implicit val arbUser: Arbitrary[User] = Arbitrary {
365
for {
366
id <- Gen.posNum[Long]
367
username <- Gen.alphaNumStr.suchThat(s => s.length >= 3 && s.length <= 20)
368
email <- Arbitrary.arbitrary[Email].map(_.value)
369
age <- Gen.choose(13, 120)
370
roleCount <- Gen.choose(1, 5)
371
roles <- Gen.listOfN(roleCount, Gen.oneOf("user", "admin", "moderator", "guest"))
372
.map(_.toSet)
373
settingCount <- Gen.choose(0, 10)
374
settingKeys <- Gen.listOfN(settingCount, Gen.alphaStr.suchThat(_.nonEmpty))
375
settingValues <- Gen.listOfN(settingCount, Gen.alphaNumStr)
376
settings = settingKeys.zip(settingValues).toMap
377
} yield User(id, username, email, age, roles, settings)
378
}
379
```
380
381
## Arbitrary Resolution Patterns
382
383
### Type Class Derivation Chain
384
385
```scala
386
// Automatic derivation works through implicit chains
387
val nestedProp = forAll { (data: Map[String, List[Option[Either[Int, String]]]]) =>
388
// This works because:
389
// 1. Arbitrary[Int] and Arbitrary[String] exist
390
// 2. Arbitrary[Either[Int, String]] is derived
391
// 3. Arbitrary[Option[Either[Int, String]]] is derived
392
// 4. Arbitrary[List[Option[Either[Int, String]]]] is derived
393
// 5. Arbitrary[Map[String, List[Option[Either[Int, String]]]]] is derived
394
data.size >= 0
395
}
396
```
397
398
### Manual Generator Override
399
400
```scala
401
// Sometimes you want a specific generator for a property
402
val customProp = forAll(Gen.choose(1, 10)) { (smallInt: Int) =>
403
// Uses explicit generator instead of Arbitrary[Int]
404
smallInt >= 1 && smallInt <= 10
405
}
406
407
// Mix explicit and implicit generators
408
val mixedProp = forAll(Gen.choose(1, 100), Arbitrary.arbitrary[String]) { (smallInt, str) =>
409
smallInt.toString.length <= str.length || str.isEmpty
410
}
411
```
412
413
### Conditional Arbitrary Instances
414
415
```scala
416
// Provide different generators based on type constraints
417
implicit def arbOrderedPair[T](implicit a: Arbitrary[T], ord: Ordering[T]): Arbitrary[(T, T)] = Arbitrary {
418
for {
419
x <- a.arbitrary
420
y <- a.arbitrary
421
} yield if (ord.lt(x, y)) (x, y) else (y, x)
422
}
423
```
424
425
### Java Time Support
426
427
ScalaCheck provides built-in Arbitrary instances for Java 8 time types through the `org.scalacheck.time` package.
428
429
```scala { .api }
430
// Import for Java Time support
431
import org.scalacheck.time._
432
433
// Date and Time Types
434
implicit val arbDuration: Arbitrary[java.time.Duration]
435
implicit val arbInstant: Arbitrary[java.time.Instant]
436
implicit val arbLocalDate: Arbitrary[java.time.LocalDate]
437
implicit val arbLocalTime: Arbitrary[java.time.LocalTime]
438
implicit val arbLocalDateTime: Arbitrary[java.time.LocalDateTime]
439
implicit val arbOffsetTime: Arbitrary[java.time.OffsetTime]
440
implicit val arbOffsetDateTime: Arbitrary[java.time.OffsetDateTime]
441
implicit val arbZonedDateTime: Arbitrary[java.time.ZonedDateTime]
442
443
// Period and Year Types
444
implicit val arbPeriod: Arbitrary[java.time.Period]
445
implicit val arbYear: Arbitrary[java.time.Year]
446
implicit val arbYearMonth: Arbitrary[java.time.YearMonth]
447
implicit val arbMonthDay: Arbitrary[java.time.MonthDay]
448
449
// Zone Types
450
implicit val arbZoneOffset: Arbitrary[java.time.ZoneOffset]
451
implicit val arbZoneId: Arbitrary[java.time.ZoneId]
452
```
453
454
**Usage Examples:**
455
```scala
456
import org.scalacheck.time._
457
import java.time._
458
459
val timestampProp = forAll { (instant: Instant) =>
460
instant.getEpochSecond >= Instant.MIN.getEpochSecond &&
461
instant.getEpochSecond <= Instant.MAX.getEpochSecond
462
}
463
464
val dateProp = forAll { (date: LocalDate) =>
465
date.isAfter(LocalDate.MIN) || date.isEqual(LocalDate.MIN)
466
}
467
468
val durationProp = forAll { (d1: Duration, d2: Duration) =>
469
d1.plus(d2).minus(d1) == d2
470
}
471
472
val zonedTimeProp = forAll { (zdt: ZonedDateTime) =>
473
zdt.toInstant.atZone(zdt.getZone) == zdt
474
}
475
```