0
# DSL Integration
1
2
Integration with specs2's specification DSL for displaying Properties as examples and converting Prop objects. The `ScalaCheckPropertyDsl` trait provides seamless integration between ScalaCheck constructs and specs2's specification framework.
3
4
## Capabilities
5
6
### Prop to ScalaCheckProperty Conversion
7
8
Automatic conversion of raw ScalaCheck Prop objects to specs2-scalacheck property wrappers for enhanced integration.
9
10
```scala { .api }
11
trait ScalaCheckPropertyDsl extends FragmentsFactory with AsResultProp {
12
/**
13
* Convert ScalaCheck Prop to ScalaCheckProp wrapper
14
* Enables fluent configuration and specs2 integration
15
* @param prop - Raw ScalaCheck property
16
* @param parameters - Test execution parameters
17
* @param prettyFreqMap - Formatter for frequency/collector data
18
* @return ScalaCheckProp wrapper with specs2 integration
19
*/
20
implicit def propToScalaCheckProperty(prop: Prop)(implicit
21
parameters: Parameters,
22
prettyFreqMap: FreqMap[Set[Any]] => Pretty
23
): ScalaCheckProp
24
}
25
```
26
27
**Usage Examples:**
28
29
```scala
30
import org.specs2.{Specification, ScalaCheck}
31
import org.scalacheck.{Prop, Gen}
32
33
class DslIntegrationSpec extends Specification with ScalaCheck { def is = s2"""
34
DSL integration examples
35
raw prop becomes configurable $rawPropConfig
36
prop with custom settings $propWithSettings
37
prop with collectors $propWithCollectors
38
"""
39
40
// Raw Prop automatically becomes ScalaCheckProp
41
def rawPropConfig = {
42
val rawProp = Prop.forAll { (x: Int) => x + 0 == x }
43
44
// Can now use fluent configuration methods
45
rawProp.set(minTestsOk = 200)
46
.verbose
47
.setVerbosity(2)
48
}
49
50
// Prop with immediate configuration
51
def propWithSettings = {
52
implicit val params = Parameters(minTestsOk = 500).verbose
53
54
val prop = Prop.forAll { (s: String) =>
55
s.reverse.reverse == s
56
}
57
58
// Prop is automatically converted and can be configured further
59
prop.set(maxSize = 100)
60
}
61
62
// Prop with frequency collection
63
def propWithCollectors = {
64
val prop = Prop.forAll { (x: Int) =>
65
Prop.collect(if (x >= 0) "non-negative" else "negative") {
66
x + 1 > x
67
}
68
}
69
70
// Converted prop maintains collector functionality
71
prop.verbose.set(minTestsOk = 300)
72
}
73
}
74
```
75
76
### Properties Display Integration
77
78
Seamless integration for displaying ScalaCheck Properties objects as specs2 specification fragments.
79
80
```scala { .api }
81
/**
82
* Convert ScalaCheck Properties to specs2 specification fragments
83
* Each named property becomes a separate specs2 example
84
* @param ps - ScalaCheck Properties object with named properties
85
* @return Fragments representing each property as an example
86
*/
87
def properties(ps: Properties): Fragments
88
```
89
90
**Usage Examples:**
91
92
```scala
93
import org.scalacheck.Properties
94
95
class PropertiesDisplaySpec extends Specification with ScalaCheck { def is = s2"""
96
Mathematical properties
97
${properties(mathProperties)}
98
99
String manipulation properties
100
${properties(stringProperties)}
101
102
Collection properties
103
${properties(collectionProperties)}
104
"""
105
106
// Math properties displayed as individual examples
107
def mathProperties = new Properties("Math") {
108
property("addition commutative") = Prop.forAll { (x: Int, y: Int) =>
109
x + y == y + x
110
}
111
112
property("multiplication identity") = Prop.forAll { (x: Int) =>
113
x * 1 == x && 1 * x == x
114
}
115
116
property("additive inverse") = Prop.forAll { (x: Int) =>
117
x + (-x) == 0
118
}
119
}
120
121
// String properties with custom generators
122
def stringProperties = new Properties("Strings") {
123
property("length after trim") = Prop.forAll { (s: String) =>
124
s.trim.length <= s.length
125
}
126
127
property("uppercase idempotent") = Prop.forAll { (s: String) =>
128
s.toUpperCase.toUpperCase == s.toUpperCase
129
}
130
131
property("concat length") = Prop.forAll { (s1: String, s2: String) =>
132
(s1 + s2).length == s1.length + s2.length
133
}
134
}
135
136
// Collection properties with different types
137
def collectionProperties = new Properties("Collections") {
138
property("list reverse twice") = Prop.forAll { (list: List[Int]) =>
139
list.reverse.reverse == list
140
}
141
142
property("set union commutative") = Prop.forAll { (s1: Set[Int], s2: Set[Int]) =>
143
s1 union s2 == s2 union s1
144
}
145
146
property("map keys preserved") = Prop.forAll { (map: Map[String, Int]) =>
147
map.mapValues(_ + 1).keySet == map.keySet
148
}
149
}
150
}
151
```
152
153
### ScalaCheckProp Type
154
155
The wrapper type created by the DSL integration, providing both ScalaCheck functionality and specs2 integration.
156
157
```scala { .api }
158
/**
159
* Wrapper for ScalaCheck Prop with specs2 integration
160
* @param prop - The underlying ScalaCheck property
161
* @param parameters - Test execution parameters
162
* @param prettyFreqMap - Formatter for frequency/collector data
163
*/
164
case class ScalaCheckProp(
165
prop: Prop,
166
parameters: Parameters,
167
prettyFreqMap: FreqMap[Set[Any]] => Pretty
168
) extends ScalaCheckProperty {
169
170
type SelfType = ScalaCheckProp
171
172
/** Update test parameters */
173
def setParameters(ps: Parameters): ScalaCheckProp =
174
copy(parameters = ps)
175
176
/** Update frequency map formatter */
177
def setPrettyFreqMap(f: FreqMap[Set[Any]] => Pretty): ScalaCheckProp =
178
copy(prettyFreqMap = f)
179
}
180
```
181
182
**ScalaCheckProp Usage:**
183
184
```scala
185
// Direct ScalaCheckProp creation
186
val customProp = ScalaCheckProp(
187
prop = Prop.forAll { (x: Int) => x >= Int.MinValue },
188
parameters = Parameters(minTestsOk = 1000).verbose,
189
prettyFreqMap = defaultFreqMapPretty
190
)
191
192
// Fluent configuration of converted Props
193
val configuredProp = {
194
val baseProp = Prop.forAll { (s: String) => s.length >= 0 }
195
baseProp.setParameters(Parameters(maxSize = 50))
196
.setPrettyFreqMap(customFreqMapFormatter)
197
}
198
```
199
200
### Fragment Factory Integration
201
202
The DSL integration leverages specs2's `FragmentsFactory` for creating properly formatted specification fragments.
203
204
```scala { .api }
205
// Uses FragmentsFactory methods internally:
206
fragmentFactory.break // Line breaks between properties
207
fragmentFactory.example(name, prop) // Convert property to example fragment
208
209
// Example of generated fragment structure:
210
Fragments(
211
fragmentFactory.break,
212
fragmentFactory.example("addition commutative", commutativeProp),
213
fragmentFactory.break,
214
fragmentFactory.example("multiplication identity", identityProp),
215
fragmentFactory.break,
216
fragmentFactory.example("additive inverse", inverseProp)
217
)
218
```
219
220
### Advanced DSL Patterns
221
222
The DSL integration supports advanced specification patterns combining multiple ScalaCheck constructs:
223
224
```scala { .api }
225
class AdvancedDslSpec extends Specification with ScalaCheck { def is = s2"""
226
Advanced DSL integration patterns
227
228
Nested property groups
229
${properties(outerProperties)}
230
231
Mixed property and example testing
232
regular example $regularExample
233
property example $propertyExample
234
another regular example $anotherExample
235
236
Parameterized property groups
237
${properties(parameterizedProperties)}
238
"""
239
240
// Nested Properties with sub-groupings
241
def outerProperties = new Properties("Outer") {
242
// Include another Properties object
243
include(innerMathProperties)
244
include(innerStringProperties)
245
246
property("cross-type property") = Prop.forAll { (x: Int, s: String) =>
247
s"$x$s".contains(x.toString)
248
}
249
}
250
251
def innerMathProperties = new Properties("Math") {
252
property("addition") = Prop.forAll { (x: Int, y: Int) => x + y == y + x }
253
property("subtraction") = Prop.forAll { (x: Int) => x - x == 0 }
254
}
255
256
def innerStringProperties = new Properties("Strings") {
257
property("empty string") = Prop.forAll { (s: String) => (s + "").length >= s.length }
258
}
259
260
// Mixed regular examples and properties
261
def regularExample = 1 + 1 must_== 2
262
263
def propertyExample = prop { (x: Int) => x + 1 > x }
264
265
def anotherExample = "hello".length must_== 5
266
267
// Properties with different parameter configurations
268
def parameterizedProperties = new Properties("Parameterized") {
269
// Each property can have different implicit parameters
270
property("quick test") = {
271
implicit val params = Parameters(minTestsOk = 10)
272
Prop.forAll { (x: Boolean) => x || !x }
273
}
274
275
property("thorough test") = {
276
implicit val params = Parameters(minTestsOk = 1000).verbose
277
Prop.forAll { (list: List[String]) => list.reverse.reverse == list }
278
}
279
280
property("parallel test") = {
281
implicit val params = Parameters(workers = 4, minTestsOk = 500)
282
Prop.forAll { (set: Set[Int]) => set.union(set) == set }
283
}
284
}
285
}
286
```
287
288
This produces a well-structured specification with clear separation between different types of tests, automatic fragment generation for Properties, and seamless integration between ScalaCheck properties and regular specs2 examples.