Skip to content

Commit 0bc74df

Browse files
committed
Fixes to the tests for the first and firstOrNull functions after review
1 parent ec71d57 commit 0bc74df

File tree

1 file changed

+114
-24
lines changed
  • core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/api

1 file changed

+114
-24
lines changed

core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/api/first.kt

Lines changed: 114 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,32 @@ import org.jetbrains.kotlinx.dataframe.samples.api.name
1111
import org.jetbrains.kotlinx.dataframe.samples.api.weight
1212
import org.junit.Test
1313

14+
/**
15+
* Tests the behavior of the `first` (`firstCol`) and `firstOrNull` functions, including:
16+
*
17+
* - **ColumnsSelectionDsl**: selecting the first column or first column matching a condition, with invocations
18+
* on illegal types, and in case when no column matches the condition.
19+
*
20+
* - **DataColumn**: getting the first value or the first value matching a predicate,
21+
* verifying behavior on empty columns, columns with `null` values, and columns without values matching the predicate.
22+
*
23+
* - **DataFrame**: getting the first row or first matching row,
24+
* verifying behavior on empty DataFrames, DataFrames with `null` values, and
25+
* DataFrames without rows matching the predicate.
26+
*
27+
* - **GroupBy**: reducing each group to its first row or the first row matching a predicate,
28+
* with handling groups that contain no matching rows.
29+
*
30+
* - **Pivot**: reducing each group in the pivot to its first row or the first row matching a predicate,
31+
* with handling groups that contain no matching rows.
32+
*
33+
* - **PivotGroupBy**: reducing each combined [pivot] + [groupBy] group to its first row
34+
* or the first row matching a predicate, with handling [pivot] + [groupBy] combinations that contain no matching rows.
35+
*/
1436
class FirstTests : ColumnsSelectionDslTests() {
1537

38+
// region ColumnsSelectionDsl
39+
1640
@Test
1741
fun `ColumnsSelectionDsl first`() {
1842
shouldThrow<IllegalArgumentException> {
@@ -48,31 +72,39 @@ class FirstTests : ColumnsSelectionDslTests() {
4872
).shouldAllBeEqual()
4973
}
5074

75+
// endregion
76+
77+
// region DataColumn
78+
5179
@Test
5280
fun `first on DataColumn`() {
5381
df.name.lastName.first() shouldBe "Cooper"
5482
df.age.first { it in 18..<40 } shouldBe 20
55-
5683
shouldThrow<IndexOutOfBoundsException> {
5784
df.drop(df.nrow).isHappy.first()
5885
}
86+
shouldThrow<NoSuchElementException> {
87+
df.age.first { it > 50 }
88+
}
5989
}
6090

6191
@Test
6292
fun `firstOrNull on DataColumn`() {
6393
df.name.lastName.firstOrNull() shouldBe "Cooper"
6494
df.drop(2).weight.firstOrNull() shouldBe null
6595
df.drop(df.nrow).age.firstOrNull() shouldBe null
66-
6796
df.age.firstOrNull { it in 21..30 } shouldBe 30
6897
df.age.firstOrNull { it > 50 } shouldBe null
6998
}
7099

100+
// endregion
101+
102+
// region DataFrame
103+
71104
@Test
72105
fun `first on DataFrame`() {
73106
df.first().name.lastName shouldBe "Cooper"
74107
df.first { !isHappy }.name.lastName shouldBe "Daniels"
75-
76108
shouldThrow<NoSuchElementException> {
77109
df.drop(df.nrow).first()
78110
}
@@ -88,19 +120,22 @@ class FirstTests : ColumnsSelectionDslTests() {
88120
fun `firstOrNull on DataFrame`() {
89121
df.firstOrNull()?.name?.lastName shouldBe "Cooper"
90122
df.drop(df.nrow).firstOrNull() shouldBe null
91-
92123
df.firstOrNull { !isHappy }?.name?.lastName shouldBe "Daniels"
93124
df.firstOrNull { age > 50 } shouldBe null
94125
df.drop(df.nrow).firstOrNull { isHappy } shouldBe null
95126
}
96127

128+
// endregion
129+
130+
// region GroupBy
131+
132+
// not tested on an empty dataframe because of #1531
97133
@Test
98134
fun `first on GroupBy`() {
99135
val grouped = df.groupBy { isHappy }
100136
val reducedGrouped = grouped.first()
101137
val firstHappy = reducedGrouped.values()[0]
102138
val firstUnhappy = reducedGrouped.values()[1]
103-
104139
firstHappy shouldBe dataFrameOf(
105140
"isHappy" to columnOf(true),
106141
"name" to columnOf(
@@ -111,12 +146,11 @@ class FirstTests : ColumnsSelectionDslTests() {
111146
"city" to columnOf("London"),
112147
"weight" to columnOf(54),
113148
)[0]
114-
115149
firstUnhappy shouldBe dataFrameOf(
116150
"isHappy" to columnOf(false),
117151
"name" to columnOf(
118152
"firstName" to columnOf("Charlie"),
119-
"lastName" to columnOf("Daniels")
153+
"lastName" to columnOf("Daniels"),
120154
),
121155
"age" to columnOf(20),
122156
"city" to columnOf("Moscow"),
@@ -127,10 +161,9 @@ class FirstTests : ColumnsSelectionDslTests() {
127161
@Test
128162
fun `first on GroupBy with predicate`() {
129163
val grouped = df.groupBy { isHappy }
130-
val reducedGrouped = grouped.first{ it["age"] as Int > 17 && it["city"] != "Moscow" }
164+
val reducedGrouped = grouped.first { it["age"] as Int > 17 && it["city"] != "Moscow" }
131165
val firstHappy = reducedGrouped.values()[0]
132166
val firstUnhappy = reducedGrouped.values()[1]
133-
134167
firstHappy shouldBe dataFrameOf(
135168
"isHappy" to columnOf(true),
136169
"name" to columnOf(
@@ -141,19 +174,50 @@ class FirstTests : ColumnsSelectionDslTests() {
141174
"city" to columnOf("Dubai"),
142175
"weight" to columnOf(87),
143176
)[0]
144-
145177
firstUnhappy shouldBe dataFrameOf(
146178
"isHappy" to columnOf(false),
147179
"name" to columnOf(
148180
"firstName" to columnOf("Alice"),
149-
"lastName" to columnOf("Wolf")
181+
"lastName" to columnOf("Wolf"),
150182
),
151183
"age" to columnOf(20),
152184
"city" to columnOf(null),
153185
"weight" to columnOf(55),
154186
)[0]
155187
}
156188

189+
@Test
190+
fun `first on GroupBy with predicate without match`() {
191+
val grouped = df.groupBy { isHappy }
192+
val reducedGrouped = grouped.first { it["city"] == "London" }
193+
val firstHappy = reducedGrouped.values()[0]
194+
val firstUnhappy = reducedGrouped.values()[1]
195+
firstHappy shouldBe dataFrameOf(
196+
"isHappy" to columnOf(true),
197+
"name" to columnOf(
198+
"firstName" to columnOf("Alice"),
199+
"lastName" to columnOf("Cooper"),
200+
),
201+
"age" to columnOf(15),
202+
"city" to columnOf("London"),
203+
"weight" to columnOf(54),
204+
)[0]
205+
firstUnhappy shouldBe dataFrameOf(
206+
"isHappy" to columnOf(false),
207+
"name" to columnOf(
208+
"firstName" to columnOf(null),
209+
"lastName" to columnOf(null),
210+
),
211+
"age" to columnOf(null),
212+
"city" to columnOf(null),
213+
"weight" to columnOf(null),
214+
)[0]
215+
}
216+
217+
// endregion
218+
219+
// region Pivot
220+
157221
@Test
158222
fun `first on Pivot`() {
159223
val pivot = df.pivot { isHappy }
@@ -163,17 +227,16 @@ class FirstTests : ColumnsSelectionDslTests() {
163227
firstHappy shouldBe dataFrameOf(
164228
"name" to columnOf(
165229
"firstName" to columnOf("Alice"),
166-
"lastName" to columnOf("Cooper")
230+
"lastName" to columnOf("Cooper"),
167231
),
168232
"age" to columnOf(15),
169233
"city" to columnOf("London"),
170234
"weight" to columnOf(54),
171235
)[0]
172-
173236
firstUnhappy shouldBe dataFrameOf(
174237
"name" to columnOf(
175238
"firstName" to columnOf("Charlie"),
176-
"lastName" to columnOf("Daniels")
239+
"lastName" to columnOf("Daniels"),
177240
),
178241
"age" to columnOf(20),
179242
"city" to columnOf("Moscow"),
@@ -187,34 +250,59 @@ class FirstTests : ColumnsSelectionDslTests() {
187250
val reducedPivotAdults = pivot.first { age > 17 }
188251
val firstHappyAdult = reducedPivotAdults.values()[0]
189252
val firstUnhappyAdult = reducedPivotAdults.values()[1]
190-
191253
firstHappyAdult shouldBe dataFrameOf(
192254
"name" to columnOf(
193255
"firstName" to columnOf("Bob"),
194-
"lastName" to columnOf("Dylan")
256+
"lastName" to columnOf("Dylan"),
195257
),
196258
"age" to columnOf(45),
197259
"city" to columnOf("Dubai"),
198260
"weight" to columnOf(87),
199261
)[0]
200-
201262
firstUnhappyAdult shouldBe dataFrameOf(
202263
"name" to columnOf(
203264
"firstName" to columnOf("Charlie"),
204-
"lastName" to columnOf("Daniels")
265+
"lastName" to columnOf("Daniels"),
205266
),
206267
"age" to columnOf(20),
207268
"city" to columnOf("Moscow"),
208269
"weight" to columnOf(null),
209270
)[0]
210271
}
211272

273+
@Test
274+
fun `first on Pivot with predicate without match`() {
275+
val pivot = df.pivot { isHappy }
276+
val reducedPivot = pivot.first { it["city"] == "London" }
277+
val firstHappy = reducedPivot.values()[0]
278+
val firstUnhappy = reducedPivot.values()[1]
279+
firstHappy shouldBe dataFrameOf(
280+
"name" to columnOf(
281+
"firstName" to columnOf("Alice"),
282+
"lastName" to columnOf("Cooper"),
283+
),
284+
"age" to columnOf(15),
285+
"city" to columnOf("London"),
286+
"weight" to columnOf(54),
287+
)[0]
288+
firstUnhappy shouldBe dataFrameOf(
289+
"name" to columnOf(null),
290+
"age" to columnOf(null),
291+
"city" to columnOf(null),
292+
"weight" to columnOf(null),
293+
)[0]
294+
}
295+
296+
// endregion
297+
298+
// region PivotGroupBy
299+
212300
@Test
213301
fun `first on PivotGroupBy`() {
214302
val students = dataFrameOf(
215303
"name" to columnOf("Alice", "Alice", "Alice", "Alice", "Bob", "Bob", "Bob", "Bob"),
216304
"age" to columnOf(15, 15, 20, 20, 15, 15, 20, 20),
217-
"group" to columnOf(1, 2, 1, 2, 1, 2, 1, 2)
305+
"group" to columnOf(1, 2, 1, 2, 1, 2, 1, 2),
218306
)
219307
val studentsPivotGrouped = students.pivot("age").groupBy("name")
220308
val studentsPivotGroupedReduced = studentsPivotGrouped.first().values()
@@ -223,7 +311,7 @@ class FirstTests : ColumnsSelectionDslTests() {
223311
"age" to columnOf(
224312
"15" to columnOf(1, 1),
225313
"20" to columnOf(1, 1),
226-
)
314+
),
227315
)
228316
studentsPivotGroupedReduced shouldBe expectedDf
229317
}
@@ -233,7 +321,7 @@ class FirstTests : ColumnsSelectionDslTests() {
233321
val students = dataFrameOf(
234322
"name" to columnOf("Alice", "Alice", "Alice", "Alice", "Bob", "Bob", "Bob", "Bob"),
235323
"age" to columnOf(15, 15, 20, 20, 15, 15, 20, 20),
236-
"group" to columnOf(1, 2, 1, 2, 1, 2, 1, 2)
324+
"group" to columnOf(1, 2, 1, 2, 1, 2, 1, 2),
237325
)
238326
val studentsPivotGrouped = students.pivot("age").groupBy("name")
239327
val studentsPivotGroupedReduced = studentsPivotGrouped.first { it["group"] == 2 }.values()
@@ -242,7 +330,7 @@ class FirstTests : ColumnsSelectionDslTests() {
242330
"age" to columnOf(
243331
"15" to columnOf(2, 2),
244332
"20" to columnOf(2, 2),
245-
)
333+
),
246334
)
247335
studentsPivotGroupedReduced shouldBe expected
248336
}
@@ -252,7 +340,7 @@ class FirstTests : ColumnsSelectionDslTests() {
252340
val students = dataFrameOf(
253341
"name" to columnOf("Alice", "Alice", "Alice", "Alice", "Bob", "Bob", "Bob", "Bob"),
254342
"age" to columnOf(15, 15, 20, 20, 15, 15, 20, 20),
255-
"group" to columnOf(1, 2, 1, 2, 1, 2, 1, 2)
343+
"group" to columnOf(1, 2, 1, 2, 1, 2, 1, 2),
256344
)
257345
val studentsPivotGrouped = students.pivot("age").groupBy("name")
258346
val studentsPivotGroupedReduced = studentsPivotGrouped.first { it["group"] == 3 }.values()
@@ -261,8 +349,10 @@ class FirstTests : ColumnsSelectionDslTests() {
261349
"age" to columnOf(
262350
"15" to columnOf(null, null),
263351
"20" to columnOf(null, null),
264-
)
352+
),
265353
)
266354
studentsPivotGroupedReduced shouldBe expected
267355
}
356+
357+
// endregion
268358
}

0 commit comments

Comments
 (0)