0
# Collection Inspectors
1
2
Collection inspectors provide a powerful DSL for testing properties across collection elements using quantifier functions. They support collections, arrays, sequences, maps, and strings with comprehensive assertion capabilities for different testing scenarios.
3
4
## Capabilities
5
6
### Universal Collection Inspectors
7
8
These functions work with any `Collection<T>` and return the original collection for chaining.
9
10
```kotlin { .api }
11
/**
12
* Assert that all elements in the collection satisfy the given predicate
13
* @param fn Assertion function to apply to each element
14
* @return The original collection for chaining
15
*/
16
inline fun <T, C : Collection<T>> C.forAll(fn: (T) -> Unit): C
17
18
/**
19
* Assert that exactly one element satisfies the predicate
20
* @param fn Assertion function to apply to each element
21
* @return The original collection for chaining
22
*/
23
inline fun <T, C : Collection<T>> C.forOne(fn: (T) -> Unit): C
24
25
/**
26
* Assert that exactly k elements satisfy the predicate
27
* @param k The exact number of elements that should satisfy the predicate
28
* @param fn Assertion function to apply to each element
29
* @return The original collection for chaining
30
*/
31
inline fun <T, C : Collection<T>> C.forExactly(k: Int, fn: (T) -> Unit): C
32
33
/**
34
* Assert that some elements (at least 1) satisfy the predicate
35
* @param fn Assertion function to apply to each element
36
* @return The original collection for chaining
37
*/
38
inline fun <T, C : Collection<T>> C.forSome(fn: (T) -> Unit): C
39
40
/**
41
* Assert that any element satisfies the predicate (alias for forSome)
42
* @param fn Assertion function to apply to each element
43
* @return The original collection for chaining
44
*/
45
inline fun <T, C : Collection<T>> C.forAny(fn: (T) -> Unit): C
46
47
/**
48
* Assert that at least one element satisfies the predicate
49
* @param fn Assertion function to apply to each element
50
* @return The original collection for chaining
51
*/
52
inline fun <T, C : Collection<T>> C.forAtLeastOne(fn: (T) -> Unit): C
53
54
/**
55
* Assert that at least k elements satisfy the predicate
56
* @param k The minimum number of elements that should satisfy the predicate
57
* @param fn Assertion function to apply to each element
58
* @return The original collection for chaining
59
*/
60
inline fun <T, C : Collection<T>> C.forAtLeast(k: Int, fn: (T) -> Unit): C
61
62
/**
63
* Assert that at most one element satisfies the predicate
64
* @param fn Assertion function to apply to each element
65
* @return The original collection for chaining
66
*/
67
inline fun <T, C : Collection<T>> C.forAtMostOne(fn: (T) -> Unit): C
68
69
/**
70
* Assert that at most k elements satisfy the predicate
71
* @param k The maximum number of elements that should satisfy the predicate
72
* @param fn Assertion function to apply to each element
73
* @return The original collection for chaining
74
*/
75
inline fun <T, C : Collection<T>> C.forAtMost(k: Int, fn: (T) -> Unit): C
76
77
/**
78
* Assert that no elements satisfy the predicate
79
* @param fn Assertion function to apply to each element
80
* @return The original collection for chaining
81
*/
82
inline fun <T, C : Collection<T>> C.forNone(fn: (T) -> Unit): C
83
84
/**
85
* Assert that exactly one element exists and satisfies the predicate
86
* @param fn Assertion function to apply to the single element
87
* @return The single element in the collection
88
*/
89
fun <T, C : Collection<T>> C.forSingle(fn: (T) -> Unit): T
90
```
91
92
### Map-Specific Inspectors
93
94
Specialized inspectors for testing maps with separate key, value, and entry predicates.
95
96
```kotlin { .api }
97
/**
98
* Assert that all keys in the map satisfy the predicate
99
* @param fn Assertion function to apply to each key
100
* @return The original map for chaining
101
*/
102
inline fun <K, V, C : Map<K, V>> C.forAllKeys(fn: (K) -> Unit): C
103
104
/**
105
* Assert that all values in the map satisfy the predicate
106
* @param fn Assertion function to apply to each value
107
* @return The original map for chaining
108
*/
109
inline fun <K, V, C : Map<K, V>> C.forAllValues(fn: (V) -> Unit): C
110
111
/**
112
* Assert that all entries in the map satisfy the predicate
113
* @param fn Assertion function to apply to each entry
114
* @return The original map for chaining
115
*/
116
inline fun <K, V, C : Map<K, V>> C.forAll(fn: (Map.Entry<K, V>) -> Unit): C
117
118
/**
119
* Assert that exactly one key satisfies the predicate
120
* @param fn Assertion function to apply to each key
121
* @return The original map for chaining
122
*/
123
inline fun <K, V, C : Map<K, V>> C.forOneKey(fn: (K) -> Unit): C
124
125
/**
126
* Assert that exactly one value satisfies the predicate
127
* @param fn Assertion function to apply to each value
128
* @return The original map for chaining
129
*/
130
inline fun <K, V, C : Map<K, V>> C.forOneValue(fn: (V) -> Unit): C
131
132
/**
133
* Assert that exactly one entry satisfies the predicate
134
* @param fn Assertion function to apply to each entry
135
* @return The original map for chaining
136
*/
137
inline fun <K, V, C : Map<K, V>> C.forOne(fn: (Map.Entry<K, V>) -> Unit): C
138
139
/**
140
* Assert that exactly k keys satisfy the predicate
141
* @param k The exact number of keys that should satisfy the predicate
142
* @param fn Assertion function to apply to each key
143
* @return The original map for chaining
144
*/
145
inline fun <K, V, C : Map<K, V>> C.forKeysExactly(k: Int, fn: (K) -> Unit): C
146
147
/**
148
* Assert that exactly k values satisfy the predicate
149
* @param k The exact number of values that should satisfy the predicate
150
* @param fn Assertion function to apply to each value
151
* @return The original map for chaining
152
*/
153
inline fun <K, V, C : Map<K, V>> C.forValuesExactly(k: Int, fn: (V) -> Unit): C
154
155
// Similar patterns exist for forSome, forAny, forAtLeast, forAtMost, forNone
156
// with Keys, Values, and Entry variants
157
```
158
159
### Array Inspectors
160
161
All collection inspector functions are also available for arrays.
162
163
```kotlin { .api }
164
/**
165
* Assert that all elements in the array satisfy the predicate
166
* @param fn Assertion function to apply to each element
167
* @return The original array for chaining
168
*/
169
inline fun <T> Array<T>.forAll(fn: (T) -> Unit): Array<T>
170
171
/**
172
* Assert that exactly one element in the array satisfies the predicate
173
* @param fn Assertion function to apply to each element
174
* @return The original array for chaining
175
*/
176
inline fun <T> Array<T>.forOne(fn: (T) -> Unit): Array<T>
177
178
// All other quantifier functions (forExactly, forSome, forAny, etc.)
179
// follow the same pattern for arrays
180
```
181
182
### Sequence Inspectors
183
184
All collection inspector functions are available for sequences.
185
186
```kotlin { .api }
187
/**
188
* Assert that all elements in the sequence satisfy the predicate
189
* @param fn Assertion function to apply to each element
190
* @return The original sequence for chaining
191
*/
192
inline fun <T> Sequence<T>.forAll(fn: (T) -> Unit): Sequence<T>
193
194
/**
195
* Assert that exactly one element in the sequence satisfies the predicate
196
* @param fn Assertion function to apply to each element
197
* @return The original sequence for chaining
198
*/
199
inline fun <T> Sequence<T>.forOne(fn: (T) -> Unit): Sequence<T>
200
201
// All other quantifier functions follow the same pattern for sequences
202
```
203
204
### String/CharSequence Inspectors
205
206
Character-level inspection for strings and character sequences.
207
208
```kotlin { .api }
209
/**
210
* Assert that all characters in the string satisfy the predicate
211
* @param fn Assertion function to apply to each character
212
* @return The original string for chaining
213
*/
214
inline fun CharSequence.forAll(fn: (Char) -> Unit): CharSequence
215
216
/**
217
* Assert that exactly one character satisfies the predicate
218
* @param fn Assertion function to apply to each character
219
* @return The original string for chaining
220
*/
221
inline fun CharSequence.forOne(fn: (Char) -> Unit): CharSequence
222
223
// All other quantifier functions follow the same pattern for CharSequence
224
```
225
226
## Usage Examples
227
228
### Basic Collection Testing
229
230
```kotlin
231
import io.kotest.inspectors.*
232
import io.kotest.matchers.*
233
234
// Test all elements match a condition
235
listOf(2, 4, 6, 8).forAll {
236
it % 2 shouldBe 0 // All numbers are even
237
}
238
239
// Test exactly one element matches
240
listOf(1, 2, 3, 4).forOne {
241
it > 3 // Only one number is greater than 3
242
}
243
244
// Test some elements match
245
listOf(1, 2, 3, 4, 5).forSome {
246
it > 3 // Some numbers are greater than 3 (4 and 5)
247
}
248
249
// Test none match
250
listOf(1, 3, 5, 7).forNone {
251
it % 2 shouldBe 0 // No numbers are even
252
}
253
```
254
255
### Quantified Testing
256
257
```kotlin
258
import io.kotest.inspectors.*
259
import io.kotest.matchers.*
260
261
val numbers = listOf(1, 2, 3, 4, 5)
262
263
// Exactly 2 elements should be even
264
numbers.forExactly(2) { it % 2 shouldBe 0 }
265
266
// At least 3 elements should be less than 6
267
numbers.forAtLeast(3) { it should beLessThan(6) }
268
269
// At most 1 element should be greater than 4
270
numbers.forAtMost(1) { it should beGreaterThan(4) }
271
```
272
273
### Map Testing
274
275
```kotlin
276
import io.kotest.inspectors.*
277
import io.kotest.matchers.*
278
279
val userAges = mapOf(
280
"Alice" to 25,
281
"Bob" to 30,
282
"Charlie" to 35
283
)
284
285
// Test all keys are valid names
286
userAges.forAllKeys { name ->
287
name.length should beGreaterThan(0)
288
name.first().isUpperCase() shouldBe true
289
}
290
291
// Test all values are valid ages
292
userAges.forAllValues { age ->
293
age should beInRange(0..120)
294
}
295
296
// Test all entries as pairs
297
userAges.forAll { (name, age) ->
298
name.isNotEmpty() shouldBe true
299
age should beGreaterThan(0)
300
}
301
```
302
303
### String Testing
304
305
```kotlin
306
import io.kotest.inspectors.*
307
import io.kotest.matchers.*
308
309
// Test all characters in a string
310
"HELLO".forAll { char ->
311
char.isUpperCase() shouldBe true
312
}
313
314
// Test exactly one character matches
315
"Hello World".forOne { char ->
316
char shouldBe 'W'
317
}
318
319
// Test some characters are spaces
320
"Hello World Test".forSome { char ->
321
char shouldBe ' '
322
}
323
324
// Test no characters are digits
325
"HelloWorld".forNone { char ->
326
char.isDigit() shouldBe true
327
}
328
```
329
330
### Array Testing
331
332
```kotlin
333
import io.kotest.inspectors.*
334
import io.kotest.matchers.*
335
336
val temperatures = arrayOf(20.5, 22.0, 19.8, 23.2, 21.1)
337
338
// All temperatures should be reasonable
339
temperatures.forAll { temp ->
340
temp should beInRange(0.0..50.0)
341
}
342
343
// Exactly one temperature should be above 23
344
temperatures.forOne { temp ->
345
temp should beGreaterThan(23.0)
346
}
347
```
348
349
### Complex Object Testing
350
351
```kotlin
352
import io.kotest.inspectors.*
353
import io.kotest.matchers.*
354
355
data class User(val name: String, val age: Int, val email: String)
356
357
val users = listOf(
358
User("Alice", 25, "alice@example.com"),
359
User("Bob", 30, "bob@example.com"),
360
User("Charlie", 35, "charlie@example.com")
361
)
362
363
// All users should have valid data
364
users.forAll { user ->
365
user.name.isNotEmpty() shouldBe true
366
user.age should beInRange(0..120)
367
user.email should contain("@")
368
}
369
370
// Exactly one user should be named "Bob"
371
users.forOne { user ->
372
user.name shouldBe "Bob"
373
}
374
375
// Some users should be over 30
376
users.forSome { user ->
377
user.age should beGreaterThan(30)
378
}
379
```
380
381
### Chaining Inspectors
382
383
```kotlin
384
import io.kotest.inspectors.*
385
import io.kotest.matchers.*
386
387
// Chain multiple inspector calls
388
val data = listOf(1, 2, 3, 4, 5)
389
390
data
391
.forAll { it should beGreaterThan(0) } // All positive
392
.forSome { it % 2 shouldBe 0 } // Some even
393
.forAtMost(2) { it should beGreaterThan(3) } // At most 2 > 3
394
```
395
396
### Single Element Testing
397
398
```kotlin
399
import io.kotest.inspectors.*
400
import io.kotest.matchers.*
401
402
// When you expect exactly one element and want to return it
403
val singleUser = listOf(User("Alice", 25, "alice@example.com"))
404
405
val user = singleUser.forSingle { user ->
406
user.name shouldBe "Alice"
407
user.age shouldBe 25
408
}
409
410
// user is now of type User, not List<User>
411
user.email shouldBe "alice@example.com"
412
```
413
414
## Error Reporting
415
416
The inspector functions provide detailed error messages when assertions fail:
417
418
```kotlin
419
// If this fails, you get a detailed report showing which elements failed
420
listOf(1, 2, 3, 4).forAll { it should beLessThan(3) }
421
// Error: 2 elements failed the predicate:
422
// [2]: expected to be < 3 but was 3
423
// [3]: expected to be < 3 but was 4
424
```
425
426
## Performance Considerations
427
428
- **Inline Functions**: All inspector functions are `inline` for zero runtime overhead
429
- **Short-Circuiting**: Functions like `forOne` and `forNone` stop as soon as the condition is met
430
- **Memory Efficiency**: Sequences are processed lazily without intermediate collections
431
- **Type Safety**: Full compile-time type checking with no runtime type erasure issues