feat: replace theme-based text color with WCAG luminance contrast (Closes #7) (#69)

This commit was merged in pull request #69.
This commit is contained in:
2026-03-13 14:08:05 +01:00
parent b819217ff4
commit a9cf04de0e
4 changed files with 148 additions and 12 deletions

View File

@@ -0,0 +1,90 @@
package org.shahondin1624
import androidx.compose.ui.graphics.Color
import org.shahondin1624.model.attributes.AttributeType
import org.shahondin1624.theme.contrastRatio
import org.shahondin1624.theme.contrastTextColor
import org.shahondin1624.theme.relativeLuminance
import kotlin.math.abs
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class ContrastUtilsTest {
@Test
fun whiteLuminanceIsOne() {
val luminance = relativeLuminance(Color.White)
assertTrue(luminance > 0.99, "White luminance should be ~1.0, was $luminance")
}
@Test
fun blackLuminanceIsZero() {
val luminance = relativeLuminance(Color.Black)
assertTrue(luminance < 0.01, "Black luminance should be ~0.0, was $luminance")
}
@Test
fun contrastRatioBlackOnWhiteIs21() {
val ratio = contrastRatio(Color.White, Color.Black)
assertTrue(ratio > 20.9, "Contrast ratio of white/black should be ~21:1, was $ratio")
}
@Test
fun contrastRatioIsSymmetric() {
val ratio1 = contrastRatio(Color.Red, Color.Blue)
val ratio2 = contrastRatio(Color.Blue, Color.Red)
assertTrue(
abs(ratio1 - ratio2) < 0.001,
"Contrast ratio should be symmetric: $ratio1 vs $ratio2"
)
}
@Test
fun contrastTextColorForWhiteIsBlack() {
assertEquals(Color.Black, contrastTextColor(Color.White))
}
@Test
fun contrastTextColorForBlackIsWhite() {
assertEquals(Color.White, contrastTextColor(Color.Black))
}
@Test
fun allAttributeColorsMeetWcagContrast() {
for (type in AttributeType.entries) {
val textColor = contrastTextColor(type.color)
val ratio = contrastRatio(type.color, textColor)
assertTrue(
ratio >= 4.5,
"Attribute ${type.name} (color=${type.color}) with text $textColor " +
"has contrast ratio $ratio, which is below WCAG 4.5:1"
)
}
}
@Test
fun midGrayGetsAppropriateContrast() {
// Mid-gray (0.5, 0.5, 0.5) should get either black or white with sufficient contrast
val midGray = Color(0.5f, 0.5f, 0.5f)
val textColor = contrastTextColor(midGray)
val ratio = contrastRatio(midGray, textColor)
assertTrue(
ratio >= 4.5,
"Mid-gray with text $textColor has contrast ratio $ratio, below WCAG 4.5:1"
)
}
@Test
fun darkBlueGetsWhiteText() {
// Dark blue like Willpower (Color.Blue) should get white text
assertEquals(Color.White, contrastTextColor(Color.Blue))
}
@Test
fun brightYellowGetsBlackText() {
// Bright yellow like Agility Color(239, 229, 138) should get black text
val agility = Color(239 / 255f, 229 / 255f, 138 / 255f)
assertEquals(Color.Black, contrastTextColor(agility))
}
}