test(arch): ICU, MaterialShapes and the ambient zone each stay where they belong
Three new rules. `android.icu` may be named only under `data/zones/`, so the platform's name database stays behind its seam. `MaterialShapes` and `androidx.graphics.shapes` may be named only under `ui/worldclock/`, so the showpiece stays the one place that morphs. And nothing under `domain/` or `ui/` may read `ZoneId.systemDefault()` or `TimeZone.getDefault()` — the device's zone is an argument, or the tests cannot pin a single one. All three hold retroactively for M0 through M7.
This commit is contained in:
@@ -260,4 +260,52 @@ class ArchitectureRulesTest {
|
||||
|
||||
assertThat(offenders).isEmpty()
|
||||
}
|
||||
|
||||
/**
|
||||
* M8 D24: ICU is a seam, not an ambient API. Every localised zone name the
|
||||
* app shows comes through `data/zones/`, so an OEM build with a broken ICU
|
||||
* degrades one caption instead of crashing a tab.
|
||||
*/
|
||||
@Test
|
||||
fun `ICU is named only under the zone-names seam`() {
|
||||
val offenders = kotlinSources.usingInCode("android.icu").filterNot {
|
||||
it.contains("de/jeanlucmakiola/clockula/data/zones/")
|
||||
}
|
||||
|
||||
assertThat(offenders).isEmpty()
|
||||
}
|
||||
|
||||
/**
|
||||
* M8 D24: `docs/PLAN.md` §8's "not sprinkled everywhere", made mechanical.
|
||||
* The shape morph is the world clock's one showpiece; the ring screen and
|
||||
* timer progress are sanctioned too, so widening this allowlist is a
|
||||
* deliberate edit rather than a drift.
|
||||
*/
|
||||
@Test
|
||||
fun `MaterialShapes is drawn only on the world clock face`() {
|
||||
val offenders = kotlinSources
|
||||
.usingInCode("MaterialShapes", "androidx.graphics.shapes")
|
||||
.filterNot { it.contains("de/jeanlucmakiola/clockula/ui/worldclock/") }
|
||||
|
||||
assertThat(offenders).isEmpty()
|
||||
}
|
||||
|
||||
/**
|
||||
* M8 D24: the zone is a parameter, from `ZoneProvider` — never an ambient
|
||||
* read at a call site. Scoped to `domain/` and `ui/` on purpose:
|
||||
* `alarm/ring/RingNotifications.kt` formats a snooze time with
|
||||
* `systemDefault()` today, and rewriting it is not M8's business.
|
||||
*/
|
||||
@Test
|
||||
fun `the domain and the ui read no ambient time zone`() {
|
||||
val domainAndUi = kotlinSources.filter {
|
||||
val path = it.invariantSeparatorsPath
|
||||
path.contains("de/jeanlucmakiola/clockula/domain/") ||
|
||||
path.contains("de/jeanlucmakiola/clockula/ui/")
|
||||
}
|
||||
|
||||
val offenders = domainAndUi.usingInCode("ZoneId.systemDefault()", "TimeZone.getDefault()")
|
||||
|
||||
assertThat(offenders).isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,8 +138,13 @@ class FakeAlarmCapabilities(
|
||||
}
|
||||
|
||||
/** The device's zone, which a test can change under a scheduled alarm. */
|
||||
class FakeZoneProvider(var zone: ZoneId = BERLIN) : ZoneProvider {
|
||||
class FakeZoneProvider(
|
||||
var zone: ZoneId = BERLIN,
|
||||
var availableIds: Set<String> = ZoneId.getAvailableZoneIds(),
|
||||
) : ZoneProvider {
|
||||
override fun current(): ZoneId = zone
|
||||
|
||||
override fun available(): Set<String> = availableIds
|
||||
}
|
||||
|
||||
class FakeBootIdProvider(
|
||||
|
||||
Reference in New Issue
Block a user