Skip to content

Commit 3c92afb

Browse files
committed
adds junit tests for format
1 parent 03ab7b1 commit 3c92afb

File tree

1 file changed

+298
-0
lines changed
  • core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/api

1 file changed

+298
-0
lines changed
Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
package org.jetbrains.kotlinx.dataframe.api
2+
3+
import io.kotest.matchers.shouldBe
4+
import io.kotest.matchers.shouldNotBe
5+
import io.kotest.matchers.string.shouldContain
6+
import org.jetbrains.kotlinx.dataframe.api.FormattingDsl.blue
7+
import org.jetbrains.kotlinx.dataframe.api.FormattingDsl.red
8+
import org.jetbrains.kotlinx.dataframe.api.FormattingDsl.rgb
9+
import org.jetbrains.kotlinx.dataframe.io.DisplayConfiguration
10+
import org.jetbrains.kotlinx.dataframe.samples.api.TestBase
11+
import org.jetbrains.kotlinx.dataframe.samples.api.age
12+
import org.jetbrains.kotlinx.dataframe.samples.api.firstName
13+
import org.jetbrains.kotlinx.dataframe.samples.api.isHappy
14+
import org.jetbrains.kotlinx.dataframe.samples.api.name
15+
import org.jetbrains.kotlinx.dataframe.samples.api.weight
16+
import org.junit.Ignore
17+
import org.junit.Test
18+
19+
class FormatTests : TestBase() {
20+
21+
@Test
22+
fun `basic format with background color`() {
23+
val formatted = df.format { age }.with { background(red) }
24+
val html = formatted.toHtml().toString()
25+
26+
// Should contain CSS background-color styling
27+
html shouldContain "background-color:#ff0000"
28+
// Format operation should produce a FormattedFrame
29+
formatted::class.simpleName shouldBe "FormattedFrame"
30+
}
31+
32+
@Test
33+
fun `format with text color`() {
34+
val formatted = df.format { age }.with { textColor(blue) }
35+
val html = formatted.toHtml().toString()
36+
37+
html shouldContain "color:#0000ff"
38+
formatted::class.simpleName shouldBe "FormattedFrame"
39+
}
40+
41+
@Test
42+
fun `format with multiple attributes using and`() {
43+
val formatted = df.format { age }.with { background(white) and textColor(black) and bold }
44+
val html = formatted.toHtml().toString()
45+
46+
html shouldContain "background-color:#ffffff"
47+
html shouldContain "color"
48+
html shouldContain "font-weight"
49+
html shouldContain "bold"
50+
}
51+
52+
@Test
53+
fun `format with italic and underline`() {
54+
val formatted = df.format { age }.with { italic and underline }
55+
val html = formatted.toHtml().toString()
56+
57+
html shouldContain "font-style"
58+
html shouldContain "italic"
59+
html shouldContain "text-decoration"
60+
html shouldContain "underline"
61+
}
62+
63+
// TODO #1356
64+
@Ignore
65+
@Test
66+
fun `format with italic and underline in nested group`() {
67+
val formatted = df.format { name.firstName }.with { italic and underline }
68+
val html = formatted.toHtml().toString()
69+
70+
html shouldContain "font-style"
71+
html shouldContain "italic"
72+
html shouldContain "text-decoration"
73+
html shouldContain "underline"
74+
}
75+
76+
@Test
77+
fun `format with custom rgb color`() {
78+
val customColor = rgb(128, 64, 192)
79+
val formatted = df.format { age }.with { background(customColor) }
80+
val html = formatted.toHtml().toString()
81+
82+
// Custom color should be applied
83+
html shouldContain "background-color:#8040c0"
84+
}
85+
86+
@Test
87+
fun `format with custom attribute`() {
88+
val formatted = df.format { age }.with { attr("text-align", "center") }
89+
val html = formatted.toHtml().toString()
90+
91+
val occurrences = html.split("text-align:center").size - 1
92+
occurrences shouldBe 7
93+
}
94+
95+
@Test
96+
fun `format with where clause`() {
97+
val formatted = df.format { age }.where { it > 30 }.with { background(red) }
98+
val html = formatted.toHtml().toString()
99+
100+
// Should contain styling but only for cells where age > 30
101+
val occurrences = html.split("background-color:#ff0000").size - 1
102+
occurrences shouldBe 2 // Two cells where age > 30
103+
}
104+
105+
@Test
106+
fun `format with at specific rows`() {
107+
val formatted = df.format { age }.at(0, 2, 4, 9999).with { background(green) }
108+
val html = formatted.toHtml().toString()
109+
110+
val occurrences = html.split("background-color:#00ff00").size - 1
111+
occurrences shouldBe 3
112+
}
113+
114+
@Test
115+
fun `format with at range`() {
116+
val formatted = df.format { age }.at(1..3).with { background(blue) }
117+
val html = formatted.toHtml().toString()
118+
119+
val occurrences = html.split("background-color:#0000ff").size - 1
120+
occurrences shouldBe 3
121+
}
122+
123+
@Test
124+
fun `format with notNull filter`() {
125+
val formatted = df.format { weight }.notNull().with { background(green) }
126+
val html = formatted.toHtml().toString()
127+
128+
// Should only format non-null weight values
129+
val occurrences = html.split("background-color:#00ff00").size - 1
130+
occurrences shouldBe 5
131+
}
132+
133+
@Test
134+
fun `format with notNull shorthand`() {
135+
val formatted = df.format { weight }.notNull { background(red) and bold }
136+
val html = formatted.toHtml().toString()
137+
138+
html.split("background-color:#ff0000").size - 1 shouldBe 5
139+
html.split("font-weight:bold").size - 1 shouldBe 5
140+
}
141+
142+
@Test
143+
fun `format with perRowCol`() {
144+
val formatted = df.format { age }.perRowCol { row, col ->
145+
if (col[row] > 25) background(red) else background(green)
146+
}
147+
val html = formatted.toHtml().toString()
148+
149+
// Should contain formatting based on age values
150+
val occurrences = html.split("background-color:#00ff00").size - 1
151+
occurrences shouldBe 3
152+
153+
formatted::class.simpleName shouldBe "FormattedFrame"
154+
}
155+
156+
@Test
157+
fun `format with linearBg`() {
158+
val formatted = df.format { age }.linearBg(15 to blue, 45 to red)
159+
val html = formatted.toHtml().toString()
160+
161+
html shouldContain "background-color:#0000ff"
162+
html shouldContain "background-color:#2a00d4"
163+
html shouldContain "background-color:#d4002a"
164+
html shouldContain "background-color:#7f007f"
165+
html shouldContain "background-color:#2a00d4"
166+
html shouldContain "background-color:#7f007f"
167+
html shouldContain "background-color:#ff0000"
168+
formatted::class.simpleName shouldBe "FormattedFrame"
169+
}
170+
171+
@Test
172+
fun `format with linear color interpolation`() {
173+
val formatted = df.format { age }.with { value ->
174+
textColor(linear(value, 15 to blue, 45 to red))
175+
}
176+
val html = formatted.toHtml().toString()
177+
178+
html shouldContain "color:#0000ff"
179+
html shouldContain "color:#2a00d4"
180+
html shouldContain "color:#d4002a"
181+
html shouldContain "color:#7f007f"
182+
html shouldContain "color:#2a00d4"
183+
html shouldContain "color:#7f007f"
184+
html shouldContain "color:#ff0000"
185+
formatted::class.simpleName shouldBe "FormattedFrame"
186+
}
187+
188+
@Test
189+
fun `chained format operations`() {
190+
val formatted = df
191+
.format().with { background(white) and textColor(black) }
192+
.format { age }.with { background(red) }
193+
.format { isHappy }.with { background(if (it) green else red) }
194+
195+
val html = formatted.toHtml().toString()
196+
197+
// Should contain all applied styles
198+
html.split("background-color:#ffffff").size - 1 shouldBe 35
199+
html.split("background-color:#ff0000").size - 1 shouldBe 9
200+
html.split("background-color:#00ff00").size - 1 shouldBe 5
201+
html.split("color:#000000").size - 1 shouldBe 98 // includes attributes outside cells
202+
formatted::class.simpleName shouldBe "FormattedFrame"
203+
}
204+
205+
@Test
206+
fun `format all columns`() {
207+
val formatted = df.format().with { bold and textColor(black) }
208+
val html = formatted.toHtml().toString()
209+
210+
html.split("font-weight:bold").size - 1 shouldBe 49 // All cells formatted
211+
html.split("color:#000000").size - 1 shouldBe 98 // includes attributes outside cells
212+
}
213+
214+
@Test
215+
fun `format by column names`() {
216+
val formatted = df.format("age", "weight").with { background(blue) }
217+
val html = formatted.toHtml().toString()
218+
219+
html.split("background-color:#0000ff").size - 1 shouldBe 14 // 7 rows * 2 columns (age, weight)
220+
}
221+
222+
@Test
223+
fun `format with complex perRowCol logic`() {
224+
val formatted = df.format { age }.perRowCol { row, col ->
225+
val value = col[row]
226+
when {
227+
value < 20 -> textColor(blue)
228+
value < 30 -> textColor(green)
229+
else -> textColor(red)
230+
}
231+
}
232+
val html = formatted.toHtml().toString()
233+
234+
// Ages: 15(blue), 45(red), 20(green), 40(red), 30(green), 20(green), 30(green)
235+
html.split("color:#0000ff").size - 1 shouldBe 2 // blue: age < 20
236+
html.split("color:#00ff00").size - 1 shouldBe 4 // green: 20 <= age < 30
237+
html.split("color:#ff0000").size - 1 shouldBe 8 // red: age >= 30
238+
formatted::class.simpleName shouldBe "FormattedFrame"
239+
}
240+
241+
@Test
242+
fun `toStandaloneHtml includes CSS definitions`() {
243+
val formatted = df.format { age }.with { background(red) }
244+
val standaloneHtml = formatted.toStandaloneHtml().toString()
245+
val regularHtml = formatted.toHtml().toString()
246+
247+
// Standalone should be longer and contain more CSS/script definitions
248+
standaloneHtml.length shouldNotBe regularHtml.length
249+
standaloneHtml.split("<!DOCTYPE html>").size - 1 shouldBe 0
250+
standaloneHtml.split("<html>").size - 1 shouldBe 1
251+
standaloneHtml.split("<head>").size - 1 shouldBe 1
252+
standaloneHtml.split("<style>").size - 1 shouldBe 0
253+
}
254+
255+
@Test
256+
fun `format with custom display configuration`() {
257+
val config = DisplayConfiguration.DEFAULT.copy(rowsLimit = 3)
258+
val formatted = df.format { age }.with { background(red) }
259+
val html = formatted.toHtml(config).toString()
260+
261+
html.split("background-color:#ff0000").size - 1 shouldBe 3 // Limited to 3 rows by config
262+
}
263+
264+
@Test
265+
fun `documentation example - simple formatting`() {
266+
// Simple formatting example
267+
val formatted = df
268+
.format { age }.with { background(red) }
269+
.format { weight }.notNull().with { textColor(blue) }
270+
271+
val html = formatted.toHtml().toString()
272+
273+
// Should contain both background and text color formatting
274+
html.split("background-color:#ff0000").size - 1 shouldBe 7 // age column, 7 rows
275+
html.split("color:#0000ff").size - 1 shouldBe 10 // weight column, actual count from test
276+
formatted::class.simpleName shouldBe "FormattedFrame"
277+
}
278+
279+
@Test
280+
fun `format returns FormattedFrame`() {
281+
val formatted = df.format { age }.with { background(red) }
282+
283+
// Should be a FormattedFrame, not a regular DataFrame
284+
formatted::class.simpleName shouldBe "FormattedFrame"
285+
}
286+
287+
@Test
288+
fun `format with null values handled correctly`() {
289+
val formatted = df.format { weight }.with { value ->
290+
if (value != null) background(green) else null
291+
}
292+
val html = formatted.toHtml().toString()
293+
294+
// Should handle null values gracefully
295+
html.split("background-color:#00ff00").size - 1 shouldBe 5 // Only non-null weight values get formatted
296+
formatted::class.simpleName shouldBe "FormattedFrame"
297+
}
298+
}

0 commit comments

Comments
 (0)