Merge pull request 'Add verified household TV updates and release tooling' (#60) from fm/tv-updater-core into main

This commit is contained in:
justinzeus 2026-11-07 21:33:42 +01:00
commit 57cf17aaad
33 changed files with 3033 additions and 112 deletions

View file

@ -1,66 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
package org.justinvisser.wolfskin.design
import java.io.File
import org.junit.Assert.*
import org.junit.Test
/** The normal JVM gate rejects untokened styling, undersized typography and internal screen wording. */
class OwnedSourceAuditTest {
@Test fun ownedScreensUseTokensReadableTextAndViewerFacingNames() {
val roots = listOf(File("src/main/java"), File("../app/src/wolfskin"))
roots.forEach { assertTrue("Missing owned source root: $it", it.isDirectory) }
val violations = roots.flatMap { root ->
root.walkTopDown().filter { it.isFile && it.extension == "kt" }.flatMap { source ->
audit(source.name, source.readText()).map { "$source:$it" }
}.toList()
}
assertTrue(violations.joinToString("\n"), violations.isEmpty())
}
@Test fun plantedViolationsFailEachDoneBarRule() {
val cases = listOf(
Triple("Screen.kt", "Box(Modifier.width(12.dp))", "unit"),
Triple("Screen.kt", "Box(Modifier.width(12f.dp))", "unit"),
Triple("Screen.kt", "Text(fontSize = 14.sp)", "unit"),
Triple("Screen.kt", "Box(Modifier.width((width + gap).dp))", "unit"),
Triple("Screen.kt", "Text(color = Color(0xFF123456))", "color"),
Triple("Screen.kt", "Text(color = ComposeColor(red = 1f, green = 0f, blue = 0f))", "color"),
Triple("WolfskinTokens.kt", "val tiny = TextStyle(fontSize = 11.5.sp)", "font-floor"),
Triple("Screen.kt", "Text(\"Recs Movies\")", "wording"),
Triple("Screen.kt", "Text(\"DGiC\")", "wording"),
Triple("Screen.kt", "Text(\"Justin Shows\")", "wording"),
Triple("Screen.kt", "Text(\"Next page\")", "wording"),
Triple("Screen.kt", "Text(\"Previous page\")", "wording"),
Triple("Screen.kt", "Text(\"Page 2\")", "wording"),
)
cases.forEach { (name, source, rule) ->
assertTrue("$rule accepted $source", audit(name, source).any { it.endsWith(":$rule") })
}
assertTrue(audit("WolfskinTokens.kt", "val body = TextStyle(fontSize = 12.sp); val fill = Color(0xFF123456)").isEmpty())
assertTrue(audit("Screen.kt", "import androidx.compose.ui.unit.dp\nText(\"This title can’t be read\", style = WolfskinTokens.Type.body)").isEmpty())
}
private fun audit(name: String, source: String): List<String> {
val generated = name == "WolfskinTokens.kt"
return source.lineSequence().mapIndexedNotNull { index, line ->
val code = line.trimStart()
if (code.startsWith("import ") || code.startsWith("//") || code.startsWith("*") || code.startsWith("/*")) return@mapIndexedNotNull null
val rules = buildList {
if (!generated && units.containsMatchIn(line)) add("unit")
if (!generated && colors.containsMatchIn(line)) add("color")
if (fonts.findAll(line).any { it.groupValues[1].toDouble() < 12 }) add("font-floor")
if (strings.findAll(line).any { forbidden.containsMatchIn(it.value) }) add("wording")
}
rules.map { "${index + 1}:$it" }
}.flatten().toList()
}
companion object {
private val units = Regex("\\.(?:dp|sp)\\b")
private val colors = Regex("\\b(?:Compose)?Color\\s*\\(\\s*(?:0[xX]|[0-9.]|(?:red|green|blue|alpha|color)\\s*=)")
private val fonts = Regex("\\bfontSize\\s*=\\s*([0-9]+(?:\\.[0-9]+)?)[fF]?\\.sp\\b")
private val strings = Regex("\"(?:\\\\.|[^\"\\\\])*\"")
private val forbidden = Regex("Recs (?:Movies|Shows)|DGiC|(?:Justin|Mindel|Shared) (?:Movies|Shows)|(?:Next|Previous) page|Page (?:[0-9]|\\$)|\\bpagination\\b", RegexOption.IGNORE_CASE)
}
}