0
# Property Framework
1
2
The ScalaCheck property framework enables expressing testable assertions about program behavior. Properties can be combined with logical operators, parameterized with generators, and executed with comprehensive reporting capabilities.
3
4
## Capabilities
5
6
### Core Property Class
7
8
The fundamental property abstraction with logical combinators and execution methods.
9
10
```scala { .api }
11
abstract class Prop {
12
def apply(prms: Gen.Parameters): Prop.Result
13
def &&(p: => Prop): Prop
14
def ||(p: => Prop): Prop
15
def ++(p: => Prop): Prop
16
def ==>(p: => Prop): Prop
17
def ==(p: => Prop): Prop
18
def check(): Unit
19
def check(prms: Test.Parameters): Unit
20
def check(paramFun: Test.Parameters => Test.Parameters): Unit
21
def label(l: String): Prop
22
def :|(l: String): Prop
23
def |:(l: String): Prop
24
def useSeed(seed: Seed): Prop
25
def viewSeed(name: String): Prop
26
}
27
```
28
29
**Usage Examples:**
30
```scala
31
val prop1 = Prop.forAll { (x: Int) => x + 0 == x }
32
val prop2 = Prop.forAll { (x: Int) => x * 1 == x }
33
val combinedProp = prop1 && prop2
34
val conditionalProp = (prop1 ==> prop2).label("identity laws")
35
36
combinedProp.check()
37
conditionalProp.check(_.withMinSuccessfulTests(1000))
38
```
39
40
### Property Constructors
41
42
Factory methods for creating properties from various sources.
43
44
```scala { .api }
45
object Prop {
46
def apply(f: Gen.Parameters => Prop.Result): Prop
47
def apply(r: Prop.Result): Prop
48
def apply(b: Boolean): Prop
49
50
val undecided: Prop
51
val falsified: Prop
52
val proved: Prop
53
val passed: Prop
54
val exception: Prop
55
}
56
```
57
58
**Usage Examples:**
59
```scala
60
val trueProp = Prop(true)
61
val falseProp = Prop(false)
62
val customProp = Prop { params =>
63
if (params.size > 10) Prop.Result(Prop.Passed)
64
else Prop.Result(Prop.Undecided)
65
}
66
```
67
68
### Universal Quantifiers (forAll)
69
70
Properties that must hold for all generated inputs, with support for explicit and implicit generators.
71
72
```scala { .api }
73
// With explicit generators (1-8 parameters)
74
def forAll[T1, P](g1: Gen[T1])(f: T1 => P)(implicit pp: P => Prop): Prop
75
def forAll[T1, T2, P](g1: Gen[T1], g2: Gen[T2])(f: (T1, T2) => P)(implicit pp: P => Prop): Prop
76
def forAll[T1, T2, T3, P](g1: Gen[T1], g2: Gen[T2], g3: Gen[T3])(f: (T1, T2, T3) => P)(implicit pp: P => Prop): Prop
77
// ... up to 8 parameters
78
79
// With implicit generators (1-8 parameters)
80
def forAll[A1, P](f: A1 => P)(implicit a1: Arbitrary[A1], pp: P => Prop): Prop
81
def forAll[A1, A2, P](f: (A1, A2) => P)(implicit a1: Arbitrary[A1], a2: Arbitrary[A2], pp: P => Prop): Prop
82
def forAll[A1, A2, A3, P](f: (A1, A2, A3) => P)(implicit a1: Arbitrary[A1], a2: Arbitrary[A2], a3: Arbitrary[A3], pp: P => Prop): Prop
83
// ... up to 8 parameters
84
85
// No-shrink variants
86
def forAllNoShrink[T1, P](g1: Gen[T1])(f: T1 => P)(implicit pp: P => Prop): Prop
87
// ... similar variants up to 8 parameters
88
```
89
90
**Usage Examples:**
91
```scala
92
// Implicit generators
93
val listReverseProp = forAll { (l: List[Int]) =>
94
l.reverse.reverse == l
95
}
96
97
// Explicit generators
98
val smallIntProp = forAll(Gen.choose(1, 100)) { n =>
99
n > 0 && n <= 100
100
}
101
102
// Multiple parameters
103
val additionProp = forAll(Gen.choose(1, 100), Gen.choose(1, 100)) { (a, b) =>
104
a + b > a && a + b > b
105
}
106
107
// No shrinking for performance-sensitive tests
108
val noShrinkProp = forAllNoShrink(complexGen) { data =>
109
expensiveProperty(data)
110
}
111
```
112
113
### Existential Quantifiers
114
115
Properties that must hold for at least one generated input.
116
117
```scala { .api }
118
def exists[A, P](f: A => P)(implicit a: Arbitrary[A], pp: P => Prop): Prop
119
def exists[A, P](g: Gen[A])(f: A => P)(implicit pp: P => Prop): Prop
120
```
121
122
**Usage Examples:**
123
```scala
124
val existsPrime = exists { (n: Int) =>
125
n > 1 && isPrime(n)
126
}
127
128
val existsEven = exists(Gen.choose(1, 100)) { n =>
129
n % 2 == 0
130
}
131
```
132
133
### Property Equality and Comparison
134
135
Specialized properties for testing equality relationships.
136
137
```scala { .api }
138
def ?=[T](x: T, y: T): Prop
139
def =?[T](x: T, y: T): Prop
140
```
141
142
**Usage Examples:**
143
```scala
144
val equalityProp = forAll { (s: String) =>
145
s.length ?= s.toList.length
146
}
147
148
val reverseEqualityProp = forAll { (l: List[Int]) =>
149
l.size =? l.reverse.size
150
}
151
```
152
153
### Property Combinators
154
155
Combining and transforming properties with logical operators.
156
157
```scala { .api }
158
def all(ps: Prop*): Prop
159
def atLeastOne(ps: Prop*): Prop
160
def collect[T](t: T)(prop: Prop): Prop
161
def classify(c: => Boolean, ifTrue: Any)(prop: Prop): Prop
162
def classify(c: => Boolean, ifTrue: Any, ifFalse: Any)(prop: Prop): Prop
163
```
164
165
**Usage Examples:**
166
```scala
167
val allProps = all(
168
forAll((x: Int) => x + 0 == x),
169
forAll((x: Int) => x * 1 == x),
170
forAll((x: Int) => x - x == 0)
171
)
172
173
val collectingProp = forAll { (l: List[Int]) =>
174
collect(l.length) {
175
l.reverse.reverse == l
176
}
177
}
178
179
val classifyingProp = forAll { (l: List[Int]) =>
180
classify(l.isEmpty, "empty list", "non-empty list") {
181
l.reverse.length == l.length
182
}
183
}
184
```
185
186
### Exception and Safety Utilities
187
188
Testing exception behavior and protecting against unsafe operations.
189
190
```scala { .api }
191
def secure[P](p: => P)(implicit pp: P => Prop): Prop
192
def throws[T <: Throwable](c: Class[T])(x: => Any): Boolean
193
def within(maximumMs: Long)(wrappedProp: => Prop): Prop
194
```
195
196
**Usage Examples:**
197
```scala
198
val divisionProp = forAll { (a: Int, b: Int) =>
199
secure {
200
if (b != 0) a / b == a / b else throws(classOf[ArithmeticException])(a / b)
201
}
202
}
203
204
val timeoutProp = forAll { (data: LargeDataSet) =>
205
within(5000) { // 5 seconds max
206
processData(data).size >= 0
207
}
208
}
209
210
val exceptionProp = Prop(throws(classOf[IllegalArgumentException])(processInvalidInput()))
211
```
212
213
### Lazy and Delayed Evaluation
214
215
Control over property evaluation timing and recursion.
216
217
```scala { .api }
218
def delay(p: => Prop): Prop
219
def lzy(p: => Prop): Prop
220
def protect(p: => Prop): Prop
221
def sizedProp(f: Int => Prop): Prop
222
```
223
224
**Usage Examples:**
225
```scala
226
val lazyProp = lzy {
227
// Expensive property that should be evaluated lazily
228
forAll(expensiveGen)(expensiveTest)
229
}
230
231
val sizedProperty = sizedProp { size =>
232
forAll(Gen.listOfN(size, Gen.choose(1, 100))) { l =>
233
l.length == size
234
}
235
}
236
237
val protectedProp = protect {
238
// May throw during property construction
239
forAll(riskyGen)(riskyTest)
240
}
241
```
242
243
### Conditional Testing
244
245
Implication and conditional property evaluation.
246
247
```scala { .api }
248
def imply[T](x: T, f: PartialFunction[T, Prop]): Prop
249
def iff[T](x: T, f: PartialFunction[T, Prop]): Prop
250
```
251
252
**Usage Examples:**
253
```scala
254
val conditionalProp = forAll { (l: List[Int]) =>
255
imply(l) {
256
case list if list.nonEmpty => list.head == list.head
257
}
258
}
259
260
val biconditionalProp = forAll { (n: Int) =>
261
iff(n) {
262
case num if num > 0 => num * num > 0
263
}
264
}
265
```
266
267
### Implicit Extensions
268
269
Automatic conversions and operator extensions for enhanced syntax.
270
271
```scala { .api }
272
implicit def propBoolean(b: Boolean): Prop
273
implicit def AnyOperators[T](x: => T): ExtendedAny[T]
274
275
class ExtendedAny[T](x: => T) {
276
def imply(f: PartialFunction[T, Prop]): Prop
277
def iff(f: PartialFunction[T, Prop]): Prop
278
def ?=(y: T): Prop
279
def =?(y: T): Prop
280
}
281
282
class ExtendedBoolean(b: => Boolean) {
283
def ==>(p: => Prop): Prop
284
def :|(l: String): Prop
285
}
286
```
287
288
**Usage Examples:**
289
```scala
290
// Boolean to Prop conversion
291
val boolProp: Prop = (5 > 3)
292
293
// Extended operators
294
val impliedProp = (someCondition: Boolean) ==> forAll { (x: Int) => x >= 0 }
295
296
val equalityProp = forAll { (a: Int, b: Int) =>
297
(a + b) ?= (b + a)
298
}
299
300
// Labels with operators
301
val labeledProp = (x > y) :| s"Expected $x > $y"
302
```
303
304
## Types
305
306
### Property Result Types
307
308
```scala { .api }
309
case class Prop.Result(
310
status: Prop.Status,
311
args: List[Prop.Arg[Any]],
312
collected: Set[Any],
313
labels: Set[String]
314
) {
315
def success: Boolean
316
def failure: Boolean
317
def proved: Boolean
318
}
319
320
sealed trait Prop.Status
321
case object Prop.Proof extends Prop.Status
322
case object Prop.True extends Prop.Status
323
case object Prop.False extends Prop.Status
324
case object Prop.Undecided extends Prop.Status
325
case class Prop.Exception(e: Throwable) extends Prop.Status
326
327
case class Prop.Arg[+T](
328
label: String,
329
arg: T,
330
shrinks: Int,
331
origArg: T,
332
prettyArg: Pretty,
333
prettyOrigArg: Pretty
334
)
335
```
336
337
## Property Composition Patterns
338
339
### Logical Combinations
340
341
```scala
342
val mathProps =
343
forAll((a: Int) => a + 0 == a) &&
344
forAll((a: Int) => a * 1 == a) &&
345
forAll((a: Int) => a - a == 0)
346
347
val anyProps =
348
forAll((x: Int) => x > 0) ||
349
forAll((x: Int) => x == 0) ||
350
forAll((x: Int) => x < 0)
351
```
352
353
### Conditional Properties
354
355
```scala
356
val sortedListProp = forAll { (l: List[Int]) =>
357
val sorted = l.sorted
358
(l.nonEmpty ==> (sorted.head <= sorted.last)) &&
359
(sorted.length ?= l.length)
360
}
361
```
362
363
### Data Collection and Classification
364
365
```scala
366
val statisticalProp = forAll { (l: List[Int]) =>
367
classify(l.isEmpty, "empty") {
368
classify(l.length < 10, "small", "large") {
369
collect(l.length) {
370
l.reverse.reverse == l
371
}
372
}
373
}
374
}
375
```
376
377
### Property Hierarchies
378
379
```scala
380
object CollectionProperties extends Properties("Collections") {
381
val listProps = all(
382
forAll((l: List[Int]) => l.reverse.reverse == l),
383
forAll((l: List[Int]) => l ++ Nil == l),
384
forAll((l: List[Int]) => Nil ++ l == l)
385
)
386
387
val setProps = all(
388
forAll((s: Set[Int]) => s union s == s),
389
forAll((s: Set[Int]) => s intersect s == s)
390
)
391
392
property("lists") = listProps
393
property("sets") = setProps
394
}
395
```