0
# Property Creation
1
2
Core functionality for creating ScalaCheck properties from test functions. The `ScalaCheckPropertyCreation` trait provides `prop` methods that convert regular Scala functions into executable ScalaCheck properties with full typeclass customization.
3
4
## Capabilities
5
6
### Property Creation from Functions
7
8
Creates ScalaCheck properties from functions with 1-8 parameters, automatically handling generator, shrinking, and pretty-printing typeclass requirements.
9
10
```scala { .api }
11
trait ScalaCheckPropertyCreation {
12
/** Create a ScalaCheck property from a function of 1 argument */
13
def prop[T, R](result: T => R)(implicit
14
arbitrary: Arbitrary[T],
15
shrink: Shrink[T],
16
pretty: T => Pretty,
17
prettyFreqMap: FreqMap[Set[Any]] => Pretty,
18
asResult: AsResult[R],
19
parameters: Parameters
20
): ScalaCheckFunction1[T, R]
21
22
/** Create a ScalaCheck property from a function of 2 arguments */
23
def prop[T1, T2, R](result: (T1, T2) => R)(implicit
24
arbitrary1: Arbitrary[T1], shrink1: Shrink[T1], pretty1: T1 => Pretty,
25
arbitrary2: Arbitrary[T2], shrink2: Shrink[T2], pretty2: T2 => Pretty,
26
prettyFreqMap: FreqMap[Set[Any]] => Pretty,
27
asResult: AsResult[R],
28
parameters: Parameters
29
): ScalaCheckFunction2[T1, T2, R]
30
31
/** Create a ScalaCheck property from a function of 3 arguments */
32
def prop[T1, T2, T3, R](result: (T1, T2, T3) => R)(implicit
33
arbitrary1: Arbitrary[T1], shrink1: Shrink[T1], pretty1: T1 => Pretty,
34
arbitrary2: Arbitrary[T2], shrink2: Shrink[T2], pretty2: T2 => Pretty,
35
arbitrary3: Arbitrary[T3], shrink3: Shrink[T3], pretty3: T3 => Pretty,
36
prettyFreqMap: FreqMap[Set[Any]] => Pretty,
37
asResult: AsResult[R],
38
parameters: Parameters
39
): ScalaCheckFunction3[T1, T2, T3, R]
40
41
/** Similar methods exist for 4-8 arguments following the same pattern */
42
}
43
```
44
45
**Usage Examples:**
46
47
```scala
48
import org.specs2.ScalaCheck
49
import org.scalacheck.{Arbitrary, Gen}
50
51
class MySpec extends Specification with ScalaCheck { def is = s2"""
52
Property examples
53
simple property $simpleProp
54
two argument property $twoArgProp
55
custom generator property $customGenProp
56
"""
57
58
// Basic property with default generators
59
def simpleProp = prop { (x: Int) =>
60
x + 0 must_== x
61
}
62
63
// Property with two arguments
64
def twoArgProp = prop { (x: Int, y: Int) =>
65
(x + y) - y must_== x
66
}
67
68
// Property with custom generator
69
def customGenProp = {
70
implicit val customArb: Arbitrary[Int] = Arbitrary(Gen.choose(1, 100))
71
prop { (x: Int) =>
72
x must be_>(0)
73
}
74
}
75
}
76
```
77
78
### Property Function Types
79
80
The `prop` methods return strongly-typed property function objects that provide extensive customization capabilities.
81
82
```scala { .api }
83
/** Property function for single argument */
84
case class ScalaCheckFunction1[T, R](
85
execute: T => R,
86
arbitrary: Arbitrary[T],
87
shrink: Option[Shrink[T]],
88
collectors: List[T => Any],
89
pretty: T => Pretty,
90
prettyFreqMap: FreqMap[Set[Any]] => Pretty,
91
asResult: AsResult[R],
92
context: Option[Context],
93
parameters: Parameters
94
) extends ScalaCheckFunction {
95
96
/** Disable shrinking for this property */
97
def noShrink: ScalaCheckFunction1[T, R]
98
99
/** Set custom arbitrary generator */
100
def setArbitrary(arbitrary: Arbitrary[T]): ScalaCheckFunction1[T, R]
101
102
/** Set custom generator */
103
def setGen(gen: Gen[T]): ScalaCheckFunction1[T, R]
104
105
/** Set custom shrinking strategy */
106
def setShrink(shrink: Shrink[T]): ScalaCheckFunction1[T, R]
107
108
/** Set custom pretty printer */
109
def setPretty(pretty: T => Pretty): ScalaCheckFunction1[T, R]
110
111
/** Set custom pretty printer from string function */
112
def pretty(pretty: T => String): ScalaCheckFunction1[T, R]
113
114
/** Add value collector for frequency reporting */
115
def collectArg(f: T => Any): ScalaCheckFunction1[T, R]
116
117
/** Add default toString collector */
118
def collect: ScalaCheckFunction1[T, R]
119
120
/** Transform input parameters before execution */
121
def prepare(action: T => T): ScalaCheckFunction1[T, R]
122
}
123
124
/** Property functions for 2-8 arguments follow similar patterns with numbered methods */
125
126
// ScalaCheckFunction4 through ScalaCheckFunction8 provide parameter-specific methods:
127
case class ScalaCheckFunction4[T1, T2, T3, T4, R](
128
execute: (T1, T2, T3, T4) => R,
129
argInstances1: ScalaCheckArgInstances[T1],
130
argInstances2: ScalaCheckArgInstances[T2],
131
argInstances3: ScalaCheckArgInstances[T3],
132
argInstances4: ScalaCheckArgInstances[T4],
133
prettyFreqMap: FreqMap[Set[Any]] => Pretty,
134
asResult: AsResult[R],
135
context: Option[Context],
136
parameters: Parameters
137
) extends ScalaCheckFunction
138
139
// Similar patterns exist for ScalaCheckFunction5, ScalaCheckFunction6, ScalaCheckFunction7, ScalaCheckFunction8
140
case class ScalaCheckFunction2[T1, T2, R](
141
execute: (T1, T2) => R,
142
argInstances1: ScalaCheckArgInstances[T1],
143
argInstances2: ScalaCheckArgInstances[T2],
144
prettyFreqMap: FreqMap[Set[Any]] => Pretty,
145
asResult: AsResult[R],
146
context: Option[Context],
147
parameters: Parameters
148
) extends ScalaCheckFunction {
149
150
/** Disable shrinking for all parameters */
151
def noShrink: ScalaCheckFunction2[T1, T2, R]
152
153
/** Set arbitrary for first parameter */
154
def setArbitrary1(a1: Arbitrary[T1]): ScalaCheckFunction2[T1, T2, R]
155
156
/** Set arbitrary for second parameter */
157
def setArbitrary2(a2: Arbitrary[T2]): ScalaCheckFunction2[T1, T2, R]
158
159
/** Set arbitraries for both parameters */
160
def setArbitraries(a1: Arbitrary[T1], a2: Arbitrary[T2]): ScalaCheckFunction2[T1, T2, R]
161
162
/** Set generators for both parameters */
163
def setGens(g1: Gen[T1], g2: Gen[T2]): ScalaCheckFunction2[T1, T2, R]
164
165
/** Set shrinks for both parameters */
166
def setShrinks(s1: Shrink[T1], s2: Shrink[T2]): ScalaCheckFunction2[T1, T2, R]
167
168
/** Set pretty printers for both parameters */
169
def setPretties(p1: T1 => Pretty, p2: T2 => Pretty): ScalaCheckFunction2[T1, T2, R]
170
171
/** Set pretty printers from string functions for both parameters */
172
def pretties(p1: T1 => String, p2: T2 => String): ScalaCheckFunction2[T1, T2, R]
173
174
/** Add collector for first parameter */
175
def collectArg1(f: T1 => Any): ScalaCheckFunction2[T1, T2, R]
176
177
/** Add collector for second parameter */
178
def collectArg2(f: T2 => Any): ScalaCheckFunction2[T1, T2, R]
179
180
/** Add collectors for all parameters */
181
def collectAllArgs(f1: T1 => Any, f2: T2 => Any): ScalaCheckFunction2[T1, T2, R]
182
183
/** Add default toString collectors for all parameters */
184
def collectAll: ScalaCheckFunction2[T1, T2, R]
185
186
/** Transform input parameters before execution */
187
def prepare(action: (T1, T2) => (T1, T2)): ScalaCheckFunction2[T1, T2, R]
188
189
/** Set execution context */
190
def setContext(context: Context): ScalaCheckFunction2[T1, T2, R]
191
192
/** Set before action */
193
def before(action: =>Any): ScalaCheckFunction2[T1, T2, R]
194
195
/** Set after action */
196
def after(action: =>Any): ScalaCheckFunction2[T1, T2, R]
197
198
/** Set both before and after actions */
199
def beforeAfter(beforeAction: =>Any, afterAction: =>Any): ScalaCheckFunction2[T1, T2, R]
200
201
/** Set around action */
202
def around(action: Result => Result): ScalaCheckFunction2[T1, T2, R]
203
}
204
```
205
206
**Advanced Usage Examples:**
207
208
```scala
209
// Property with custom configuration
210
def customProperty = {
211
prop { (x: Int) =>
212
x > 0
213
}.setGen(Gen.choose(1, 1000))
214
.pretty(x => s"positive number: $x")
215
.collect
216
.verbose
217
.set(minTestsOk = 200)
218
}
219
220
// Property with setup/teardown
221
def contextProperty = {
222
var setupCount = 0
223
224
prop { (x: String) =>
225
x.length >= 0
226
}.before {
227
setupCount += 1
228
}.after {
229
println(s"Ran $setupCount tests")
230
}
231
}
232
233
// Property with before/after actions combined
234
def beforeAfterProperty = {
235
prop { (x: Int, y: Int) =>
236
x + y == y + x
237
}.beforeAfter(
238
beforeAction = println("Starting test"),
239
afterAction = println("Test completed")
240
)
241
}
242
243
// Property with data preparation
244
def dataPreparationProperty = {
245
prop { (x: Int, y: Int) =>
246
x >= 0 && y >= 0 && x + y >= 0
247
}.prepare { (x, y) =>
248
(math.abs(x), math.abs(y)) // Ensure positive inputs
249
}.verbose
250
}
251
252
// Property with collectors and custom parameters
253
def collectorProperty = {
254
prop { (x: Int, y: Int) =>
255
(x * y) % 2 == (x % 2) * (y % 2)
256
}.collectArg1(x => if (x % 2 == 0) "even" else "odd")
257
.collectArg2(y => if (y % 2 == 0) "even" else "odd")
258
.set(minTestsOk = 100, maxSize = 50)
259
}
260
```
261
262
### Multi-Parameter Property Support
263
264
The library provides property creation methods for functions with up to 8 parameters, each with independent typeclass customization:
265
266
```scala { .api }
267
// Each ScalaCheckFunctionN provides parameter-specific methods:
268
trait ScalaCheckFunction3[T1, T2, T3, R] extends ScalaCheckFunction {
269
def setArbitrary1(a1: Arbitrary[T1]): ScalaCheckFunction3[T1, T2, T3, R]
270
def setArbitrary2(a2: Arbitrary[T2]): ScalaCheckFunction3[T1, T2, T3, R]
271
def setArbitrary3(a3: Arbitrary[T3]): ScalaCheckFunction3[T1, T2, T3, R]
272
def setArbitraries(a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3]): ScalaCheckFunction3[T1, T2, T3, R]
273
274
def setGen1(g1: Gen[T1]): ScalaCheckFunction3[T1, T2, T3, R]
275
def setGen2(g2: Gen[T2]): ScalaCheckFunction3[T1, T2, T3, R]
276
def setGen3(g3: Gen[T3]): ScalaCheckFunction3[T1, T2, T3, R]
277
def setGens(g1: Gen[T1], g2: Gen[T2], g3: Gen[T3]): ScalaCheckFunction3[T1, T2, T3, R]
278
279
def collectArg1(f: T1 => Any): ScalaCheckFunction3[T1, T2, T3, R]
280
def collectArg2(f: T2 => Any): ScalaCheckFunction3[T1, T2, T3, R]
281
def collectArg3(f: T3 => Any): ScalaCheckFunction3[T1, T2, T3, R]
282
def collectAllArgs(f1: T1 => Any, f2: T2 => Any, f3: T3 => Any): ScalaCheckFunction3[T1, T2, T3, R]
283
}
284
```
285
286
### Typeclass Requirements
287
288
Each property creation method requires several Scala typeclasses to be in implicit scope:
289
290
```scala { .api }
291
// Required for each parameter type T
292
implicit val arbitrary: Arbitrary[T] // Generates random values
293
implicit val shrink: Shrink[T] // Shrinks failing cases
294
implicit val pretty: T => Pretty // Pretty prints values
295
296
// Required for the property function
297
implicit val prettyFreqMap: FreqMap[Set[Any]] => Pretty // Formats frequency data
298
implicit val asResult: AsResult[R] // Converts result to specs2 Result
299
implicit val parameters: Parameters // Test configuration
300
```
301
302
These typeclasses enable:
303
- **Arbitrary**: Random value generation for property inputs
304
- **Shrink**: Minimizing failing test cases to simpler counterexamples
305
- **Pretty**: Formatted display of values in test output
306
- **AsResult**: Integration with specs2's result system
307
- **Parameters**: Configuration of test execution parameters