0
# Utilities
1
2
Utility traits and objects that provide additional functionality for specs2-scalacheck integration, including expectation control, pretty printing enhancements, and Scalaz integration.
3
4
## Capabilities
5
6
### Expectation Count Control
7
8
The `OneExpectationPerProp` trait modifies how specs2 counts expectations when using ScalaCheck properties, ensuring each property counts as a single expectation regardless of how many test cases are executed.
9
10
```scala { .api }
11
/**
12
* Utility trait for controlling expectation counts in specs2 reports
13
* Mix this trait into specifications to count each property as one expectation
14
* instead of counting each individual test case execution
15
*/
16
trait OneExpectationPerProp extends AsResultProp {
17
/**
18
* Override propAsResult to set expectation count to 1 per property
19
* @param p - Test parameters for property execution
20
* @param pfq - Pretty formatter for frequency/collector data
21
* @return AsResult that counts as single expectation
22
*/
23
implicit override def propAsResult(
24
implicit p: Parameters,
25
pfq: FreqMap[Set[Any]] => Pretty
26
): AsResult[Prop]
27
28
/**
29
* Override propertiesAsResult to set expectation count to 1 per Properties group
30
* @param p - Test parameters for property execution
31
* @param pfq - Pretty formatter for frequency/collector data
32
* @return AsResult that counts as single expectation
33
*/
34
implicit override def propertiesAsResult(
35
implicit p: Parameters,
36
pfq: FreqMap[Set[Any]] => Pretty
37
): AsResult[Properties]
38
}
39
```
40
41
**Usage Examples:**
42
43
```scala
44
import org.specs2.{Specification, ScalaCheck}
45
import org.specs2.scalacheck.OneExpectationPerProp
46
47
// Without OneExpectationPerProp: each property execution counts as separate expectation
48
class RegularSpec extends Specification with ScalaCheck { def is = s2"""
49
Properties that count multiple expectations
50
property with 100 test cases $prop100 // Counts as 100 expectations
51
"""
52
53
def prop100 = prop { (x: Int) => x + 0 == x }.set(minTestsOk = 100)
54
}
55
56
// With OneExpectationPerProp: each property counts as single expectation
57
class SingleExpectationSpec extends Specification with ScalaCheck with OneExpectationPerProp { def is = s2"""
58
Properties that count single expectations
59
property with 100 test cases $prop100 // Counts as 1 expectation
60
properties group $mathProperties // Counts as 1 expectation total
61
"""
62
63
def prop100 = prop { (x: Int) => x + 0 == x }.set(minTestsOk = 100)
64
65
def mathProperties = new Properties("Math") {
66
property("commutative") = Prop.forAll { (x: Int, y: Int) => x + y == y + x }
67
property("associative") = Prop.forAll { (x: Int, y: Int, z: Int) => (x + y) + z == x + (y + z) }
68
}
69
}
70
```
71
72
### Pretty Printing for Product Types
73
74
The `PrettyProduct` object provides utilities for creating pretty printers for Scala case classes and other Product types.
75
76
```scala { .api }
77
/**
78
* Utility object for pretty printing Product types (case classes, tuples, etc.)
79
*/
80
object PrettyProduct {
81
/**
82
* Convert Product to formatted string representation
83
* @param p - Product instance (case class, tuple, etc.)
84
* @return Formatted string showing field names and values
85
*/
86
def toString[P <: Product](p: P): String
87
88
/**
89
* Create Pretty instance for Product types
90
* @return Pretty function that formats Product types nicely
91
*/
92
def apply[P <: Product]: P => Pretty
93
}
94
```
95
96
**Usage Examples:**
97
98
```scala
99
import org.specs2.scalacheck.PrettyProduct
100
import org.scalacheck.{Arbitrary, Pretty}
101
102
// Case class for testing
103
case class Person(name: String, age: Int, email: String)
104
105
class PrettyProductSpec extends Specification with ScalaCheck { def is = s2"""
106
Pretty printing for case classes
107
person pretty printing $personPretty
108
custom product formatting $customFormat
109
"""
110
111
// Use PrettyProduct for automatic case class formatting
112
def personPretty = {
113
implicit val personPretty: Person => Pretty = PrettyProduct.apply[Person]
114
implicit val personArbitrary: Arbitrary[Person] = Arbitrary(
115
for {
116
name <- Gen.alphaStr
117
age <- Gen.choose(18, 80)
118
email <- Gen.alphaStr.map(_ + "@example.com")
119
} yield Person(name, age, email)
120
)
121
122
prop { (person: Person) =>
123
person.name.length >= 0 // Property will show nicely formatted Person instances
124
}.verbose.set(minTestsOk = 10)
125
}
126
127
// Custom formatting with PrettyProduct.toString
128
def customFormat = {
129
val person = Person("Alice", 30, "alice@example.com")
130
val formatted = PrettyProduct.toString(person)
131
formatted must contain("name") and contain("Alice") and contain("age") and contain("30")
132
}
133
```
134
135
### Detail Management for Frequency Maps
136
137
The `PrettyDetails` object provides utilities for extracting and managing failure details in frequency maps generated during property testing.
138
139
```scala { .api }
140
/**
141
* Utility object for handling failure details in frequency/collector maps
142
*/
143
object PrettyDetails {
144
/**
145
* Extract failure details from frequency map for specs2 Details
146
* @param fq - Frequency map potentially containing failure details
147
* @return specs2 Details object with extracted failure information
148
*/
149
def collectDetails[T](fq: FreqMap[Set[T]]): execute.Details
150
151
/**
152
* Remove failure details from frequency map for cleaner display
153
* @param fq - Frequency map that may contain failure details
154
* @return Cleaned frequency map with details removed
155
*/
156
def removeDetails(fq: FreqMap[Set[Any]]): FreqMap[Set[Any]]
157
}
158
```
159
160
**Usage Examples:**
161
162
```scala
163
import org.specs2.scalacheck.{PrettyDetails, Parameters}
164
import org.scalacheck.util.FreqMap
165
166
class DetailManagementSpec extends Specification with ScalaCheck { def is = s2"""
167
Detail management in frequency maps
168
clean frequency display $cleanFrequency
169
extract failure details $extractDetails
170
"""
171
172
// Clean frequency maps for better display
173
def cleanFrequency = {
174
implicit val params = Parameters().verbose
175
implicit val cleanFreqMapPretty: FreqMap[Set[Any]] => Pretty =
176
(fq: FreqMap[Set[Any]]) => Pretty.prettyFreqMap(PrettyDetails.removeDetails(fq))
177
178
prop { (x: Int) =>
179
Prop.collect(if (x >= 0) "positive" else "negative") {
180
x + 1 > x
181
}
182
}.set(minTestsOk = 100)
183
// Frequency information will be displayed without internal failure details
184
}
185
186
// Extract details for custom error handling
187
def extractDetails = {
188
// This would typically be used internally by the framework
189
// when processing test results and frequency maps
190
success("PrettyDetails provides detail extraction utilities")
191
}
192
```
193
194
### Scalaz Integration
195
196
The `GenInstances` trait provides Scalaz typeclass instances for ScalaCheck's `Gen` type, enabling functional programming patterns with generators.
197
198
```scala { .api }
199
/**
200
* Scalaz typeclass instances for ScalaCheck Gen
201
*/
202
trait GenInstances {
203
/**
204
* Monad instance for ScalaCheck Gen type
205
* Enables use of Scalaz monad operations (bind, map, etc.) with Gen
206
* @return Monad[Gen] instance
207
*/
208
implicit def genMonad: Monad[Gen]
209
}
210
```
211
212
**Usage Examples:**
213
214
```scala
215
import org.specs2.scalacheck.GenInstances
216
import org.scalacheck.Gen
217
import scalaz.syntax.monad._
218
219
class GenInstancesSpec extends Specification with ScalaCheck with GenInstances { def is = s2"""
220
Scalaz integration for Gen
221
monad operations on Gen $genMonad
222
generator composition $genComposition
223
"""
224
225
// Using Scalaz monad syntax with Gen
226
def genMonad = {
227
val complexGen: Gen[(String, Int, Boolean)] = for {
228
str <- Gen.alphaStr
229
num <- Gen.choose(1, 100)
230
bool <- Gen.oneOf(true, false)
231
} yield (str, num, bool)
232
233
// Can use Scalaz monad operations
234
val enhancedGen = complexGen >>= { case (s, n, b) =>
235
Gen.const((s.toUpperCase, n * 2, !b))
236
}
237
238
prop(enhancedGen) { case (s, n, b) =>
239
s.forall(_.isUpper) && n % 2 == 0
240
}
241
}
242
243
// Complex generator composition using Scalaz
244
def genComposition = {
245
implicit val genM = genMonad
246
247
val listGen = Gen.listOf(Gen.choose(1, 10))
248
val processedGen = listGen.map(_.filter(_ > 5).sorted)
249
250
prop(processedGen) { (list: List[Int]) =>
251
list.forall(_ > 5) && list == list.sorted
252
}
253
}
254
```
255
256
## Integration with specs2-scalacheck
257
258
These utilities are automatically available when using the main `ScalaCheck` trait, but can also be mixed in individually for specific functionality:
259
260
```scala
261
// Full integration (includes all utilities)
262
class FullSpec extends Specification with ScalaCheck
263
264
// Selective integration
265
class SelectiveSpec extends Specification
266
with ScalaCheck
267
with OneExpectationPerProp // Only expectation control
268
with GenInstances // Only Scalaz integration
269
270
// Custom pretty printing setup
271
class CustomPrettySpec extends Specification with ScalaCheck {
272
// Use PrettyProduct for all case classes
273
implicit def productPretty[P <: Product]: P => Pretty = PrettyProduct.apply[P]
274
275
// Custom frequency map formatting
276
implicit override def defaultFreqMapPretty: FreqMap[Set[Any]] => Pretty =
277
(fq: FreqMap[Set[Any]]) => Pretty.prettyFreqMap(PrettyDetails.removeDetails(fq))
278
}
279
```