0
# Tuple Matchers
1
2
Comprehensive validation matchers for Kotlin's Pair and Triple tuple types, enabling precise assertion of individual components for data structure testing and destructuring validation.
3
4
## Capabilities
5
6
### Pair Matchers
7
8
Assert specific values in Pair tuple components.
9
10
```kotlin { .api }
11
/**
12
* Assert that this pair has the expected first value
13
* @param a The expected first value of the pair
14
* @return The original Pair for chaining
15
*/
16
fun <A> Pair<A, *>.shouldHaveFirst(a: A): Pair<A, *>
17
18
/**
19
* Assert that this pair does not have the specified first value
20
* @param a The value that should not be the first component
21
* @return The original Pair for chaining
22
*/
23
fun <A> Pair<A, *>.shouldNotHaveFirst(a: A): Pair<A, *>
24
25
/**
26
* Assert that this pair has the expected second value
27
* @param b The expected second value of the pair
28
* @return The original Pair for chaining
29
*/
30
fun <B> Pair<*, B>.shouldHaveSecond(b: B): Pair<*, B>
31
32
/**
33
* Assert that this pair does not have the specified second value
34
* @param b The value that should not be the second component
35
* @return The original Pair for chaining
36
*/
37
fun <B> Pair<*, B>.shouldNotHaveSecond(b: B): Pair<*, B>
38
```
39
40
**Usage Examples:**
41
42
```kotlin
43
import io.kotest.matchers.tuples.shouldHaveFirst
44
import io.kotest.matchers.tuples.shouldHaveSecond
45
import io.kotest.matchers.tuples.shouldNotHaveFirst
46
import io.kotest.matchers.tuples.shouldNotHaveSecond
47
48
// Basic pair validation
49
val coordinates = Pair(10, 20)
50
coordinates.shouldHaveFirst(10)
51
coordinates.shouldHaveSecond(20)
52
coordinates.shouldNotHaveFirst(15)
53
coordinates.shouldNotHaveSecond(25)
54
55
// Testing function return values
56
fun parseCoordinate(input: String): Pair<Int, Int> {
57
val parts = input.split(",")
58
return Pair(parts[0].toInt(), parts[1].toInt())
59
}
60
61
val result = parseCoordinate("5,7")
62
result.shouldHaveFirst(5)
63
result.shouldHaveSecond(7)
64
65
// Chaining assertions
66
val nameAge = Pair("Alice", 30)
67
nameAge
68
.shouldHaveFirst("Alice")
69
.shouldHaveSecond(30)
70
```
71
72
### Triple Matchers
73
74
Assert specific values in Triple tuple components.
75
76
```kotlin { .api }
77
/**
78
* Assert that this triple has the expected first value
79
* @param a The expected first value of the triple
80
* @return The original Triple for chaining
81
*/
82
fun <A> Triple<A, *, *>.shouldHaveFirst(a: A): Triple<A, *, *>
83
84
/**
85
* Assert that this triple does not have the specified first value
86
* @param a The value that should not be the first component
87
* @return The original Triple for chaining
88
*/
89
fun <A> Triple<A, *, *>.shouldNotHaveFirst(a: A): Triple<A, *, *>
90
91
/**
92
* Assert that this triple has the expected second value
93
* @param b The expected second value of the triple
94
* @return The original Triple for chaining
95
*/
96
fun <B> Triple<*, B, *>.shouldHaveSecond(b: B): Triple<*, B, *>
97
98
/**
99
* Assert that this triple does not have the specified second value
100
* @param b The value that should not be the second component
101
* @return The original Triple for chaining
102
*/
103
fun <B> Triple<*, B, *>.shouldNotHaveSecond(b: B): Triple<*, B, *>
104
105
/**
106
* Assert that this triple has the expected third value
107
* @param c The expected third value of the triple
108
* @return The original Triple for chaining
109
*/
110
fun <C> Triple<*, *, C>.shouldHaveThird(c: C): Triple<*, *, C>
111
112
/**
113
* Assert that this triple does not have the specified third value
114
* @param c The value that should not be the third component
115
* @return The original Triple for chaining
116
*/
117
fun <C> Triple<*, *, C>.shouldNotHaveThird(c: C): Triple<*, *, C>
118
```
119
120
**Usage Examples:**
121
122
```kotlin
123
import io.kotest.matchers.tuples.shouldHaveFirst
124
import io.kotest.matchers.tuples.shouldHaveSecond
125
import io.kotest.matchers.tuples.shouldHaveThird
126
import io.kotest.matchers.tuples.shouldNotHaveFirst
127
128
// Basic triple validation
129
val coordinates3D = Triple(10, 20, 30)
130
coordinates3D.shouldHaveFirst(10)
131
coordinates3D.shouldHaveSecond(20)
132
coordinates3D.shouldHaveThird(30)
133
134
// Testing complex data structures
135
data class Person(val name: String, val age: Int, val city: String)
136
137
fun personToTriple(person: Person): Triple<String, Int, String> {
138
return Triple(person.name, person.age, person.city)
139
}
140
141
val alice = Person("Alice", 30, "New York")
142
val triple = personToTriple(alice)
143
144
triple
145
.shouldHaveFirst("Alice")
146
.shouldHaveSecond(30)
147
.shouldHaveThird("New York")
148
149
// Testing parsing functions
150
fun parseCSVRow(row: String): Triple<String, Int, Double> {
151
val parts = row.split(",")
152
return Triple(
153
parts[0].trim(),
154
parts[1].trim().toInt(),
155
parts[2].trim().toDouble()
156
)
157
}
158
159
val parsed = parseCSVRow("Product A, 100, 29.99")
160
parsed.shouldHaveFirst("Product A")
161
parsed.shouldHaveSecond(100)
162
parsed.shouldHaveThird(29.99)
163
```
164
165
### Common Patterns
166
167
```kotlin
168
import io.kotest.matchers.tuples.*
169
170
// Map operations producing pairs
171
val items = listOf("apple", "banana", "cherry")
172
val withIndices = items.mapIndexed { index, item -> Pair(index, item) }
173
174
withIndices[0].shouldHaveFirst(0)
175
withIndices[0].shouldHaveSecond("apple")
176
withIndices[1].shouldHaveFirst(1)
177
withIndices[1].shouldHaveSecond("banana")
178
179
// Destructuring validation in tests
180
val (x, y) = parseCoordinate("15,25")
181
val originalPair = Pair(x, y)
182
originalPair.shouldHaveFirst(15)
183
originalPair.shouldHaveSecond(25)
184
185
// Testing database query results (commonly returned as tuples)
186
fun getPersonStats(): Triple<String, Int, Double> {
187
// Simulate database query returning name, count, average
188
return Triple("Department A", 25, 87.5)
189
}
190
191
val stats = getPersonStats()
192
stats
193
.shouldHaveFirst("Department A")
194
.shouldHaveSecond(25)
195
.shouldHaveThird(87.5)
196
197
// Validation with complex nested structures
198
val nestedData = Pair(
199
Triple("user1", "admin", true),
200
Triple("user2", "guest", false)
201
)
202
203
nestedData.first.shouldHaveFirst("user1")
204
nestedData.first.shouldHaveSecond("admin")
205
nestedData.first.shouldHaveThird(true)
206
207
nestedData.second.shouldHaveFirst("user2")
208
nestedData.second.shouldHaveSecond("guest")
209
nestedData.second.shouldHaveThird(false)
210
```
211
212
## Type Definitions
213
214
```kotlin { .api }
215
fun <A> haveFirst(a: A): Matcher<Pair<A, *>> {
216
override fun test(value: Pair<A, *>): MatcherResult
217
}
218
219
fun <B> haveSecond(b: B): Matcher<Pair<*, B>> {
220
override fun test(value: Pair<*, B>): MatcherResult
221
}
222
223
fun <A> haveTripleFirst(a: A): Matcher<Triple<A, *, *>> {
224
override fun test(value: Triple<A, *, *>): MatcherResult
225
}
226
227
fun <B> haveTripleSecond(b: B): Matcher<Triple<*, B, *>> {
228
override fun test(value: Triple<*, B, *>): MatcherResult
229
}
230
231
fun <C> haveTripleThird(c: C): Matcher<Triple<*, *, C>> {
232
override fun test(value: Triple<*, *, C>): MatcherResult
233
}
234
```