0.2.76 - Icon Packs

This commit is contained in:
ponzischeme89
2026-08-18 14:59:29 +12:00
parent 36d171e51b
commit 8c847c59b8
70 changed files with 5267 additions and 673 deletions
+96 -11
View File
@@ -77,7 +77,7 @@ func TestEasterWindowIsTheLongWeekend(t *testing.T) {
// A season is the one thing on this feature nobody on a television can decline, so the
// tests that matter most are the ones asserting that no argument suppresses it.
func TestSeasonOutranksTheViewer(t *testing.T) {
resolved := resolveTheme(themePlum, nil, true, true, date(2026, time.December, 20))
resolved := resolveTheme(themePlum, "", nil, true, true, date(2026, time.December, 20))
if resolved.ID != themeChristmas {
t.Fatalf("applied theme = %q, want %q", resolved.ID, themeChristmas)
}
@@ -98,7 +98,7 @@ func TestSeasonOutranksTheViewer(t *testing.T) {
// grantable per person, and an operator restricting a viewer to one palette must not be a
// way of exempting them from Christmas.
func TestAllowlistDoesNotApplyToSeasons(t *testing.T) {
resolved := resolveTheme(themePlum, []string{themeEmber}, true, true, date(2026, time.October, 31))
resolved := resolveTheme(themePlum, "", []string{themeEmber}, true, true, date(2026, time.October, 31))
if resolved.ID != themeHalloween {
t.Fatalf("applied theme = %q, want %q", resolved.ID, themeHalloween)
}
@@ -110,7 +110,7 @@ func TestAllowlistDoesNotApplyToSeasons(t *testing.T) {
}
func TestSeasonsOffLeavesTheViewersChoice(t *testing.T) {
resolved := resolveTheme(themeEmber, nil, false, true, date(2026, time.December, 20))
resolved := resolveTheme(themeEmber, "", nil, false, true, date(2026, time.December, 20))
if resolved.ID != themeEmber {
t.Fatalf("applied theme = %q, want %q", resolved.ID, themeEmber)
}
@@ -138,7 +138,7 @@ func TestResolveThemeFallbacks(t *testing.T) {
}
for _, testCase := range cases {
t.Run(testCase.name, func(t *testing.T) {
got := resolveTheme(testCase.chosen, testCase.allowed, true, true, ordinary)
got := resolveTheme(testCase.chosen, "", testCase.allowed, true, true, ordinary)
if got.ID != testCase.want {
t.Fatalf("resolveTheme(%q, %v) = %q, want %q",
testCase.chosen, testCase.allowed, got.ID, testCase.want)
@@ -150,14 +150,14 @@ func TestResolveThemeFallbacks(t *testing.T) {
// The revision is the whole delivery mechanism: a television refetches the palette only when
// this moves. If it did not move when a season began, no set in the house would repaint.
func TestThemeRevisionTracksTheAnswer(t *testing.T) {
ordinary := resolveTheme(themePlum, nil, true, true, date(2026, time.June, 14))
christmas := resolveTheme(themePlum, nil, true, true, date(2026, time.December, 20))
ordinary := resolveTheme(themePlum, "", nil, true, true, date(2026, time.June, 14))
christmas := resolveTheme(themePlum, "", nil, true, true, date(2026, time.December, 20))
if ordinary.Revision == christmas.Revision {
t.Fatal("the revision must change when the season does, or nothing refetches")
}
// And it must be stable, or every poll would look like a change and every set would
// fetch the palette six times a minute.
again := resolveTheme(themePlum, nil, true, true, date(2026, time.June, 15))
again := resolveTheme(themePlum, "", nil, true, true, date(2026, time.June, 15))
if ordinary.Revision != again.Revision {
t.Fatalf("the revision moved on an ordinary day: %s then %s", ordinary.Revision, again.Revision)
}
@@ -168,10 +168,10 @@ func TestThemeRevisionTracksTheAnswer(t *testing.T) {
// every day of the year.
func TestDecorationsAreSeasonalAndSeparatelySwitchable(t *testing.T) {
christmas := date(2026, time.December, 20)
if got := resolveTheme(themePlum, nil, true, true, christmas); got.Decoration != decorationSnow {
if got := resolveTheme(themePlum, "", nil, true, true, christmas); got.Decoration != decorationSnow {
t.Fatalf("decoration = %q, want %q", got.Decoration, decorationSnow)
}
off := resolveTheme(themePlum, nil, true, false, christmas)
off := resolveTheme(themePlum, "", nil, true, false, christmas)
if off.Decoration != "" {
t.Fatalf("decorations off still returned %q", off.Decoration)
}
@@ -179,10 +179,10 @@ func TestDecorationsAreSeasonalAndSeparatelySwitchable(t *testing.T) {
t.Fatal("turning decorations off must keep the seasonal palette")
}
// The revision has to move, or a set already snowing is never told to stop.
if off.Revision == resolveTheme(themePlum, nil, true, true, christmas).Revision {
if off.Revision == resolveTheme(themePlum, "", nil, true, true, christmas).Revision {
t.Fatal("the revision must change when the decoration does")
}
ordinary := resolveTheme(themePlum, nil, true, true, date(2026, time.June, 14))
ordinary := resolveTheme(themePlum, "", nil, true, true, date(2026, time.June, 14))
if ordinary.Decoration != "" {
t.Fatalf("a chosen theme carries a decoration: %q", ordinary.Decoration)
}
@@ -277,3 +277,88 @@ func TestNormalizeThemeAllowlist(t *testing.T) {
t.Fatalf("allowlist is not in catalogue order: %v", ordered)
}
}
// --- Icon packs ---------------------------------------------------------------------------
// The gateway's half of the wire contract with ui/theme/MembyIconPacks.kt. Its own
// MembyIconPackTest pins the same three slugs from the television's end; change one
// without the other and a household is sent marks nothing can draw.
func TestIconPackOptionsAreTheKnownPacks(t *testing.T) {
for _, option := range iconPackOptions() {
if !knownIconPack(option.Value) {
t.Fatalf("offered icon pack %q is not one the resolver will accept", option.Value)
}
}
if !knownIconPack(defaultIconPackID) {
t.Fatalf("the default icon pack %q is not selectable", defaultIconPackID)
}
}
// A slug the resolver does not recognise must never reach a television. The set would fall
// back on its own, but a gateway echoing a retired pack would make every screen in the
// house look wrong in the same way while reporting it had done what it was asked.
func TestUnknownIconPackFallsBackToTheShippedMarks(t *testing.T) {
ordinary := time.Date(2026, time.May, 3, 12, 0, 0, 0, time.UTC)
for _, chosen := range []string{"", "tabler", "material "} {
got := resolveTheme(themeMidnight, chosen, nil, true, true, ordinary)
if got.IconSet != defaultIconPackID {
t.Fatalf("resolveTheme(icon %q) = %q, want %q", chosen, got.IconSet, defaultIconPackID)
}
}
}
// The viewer's marks stand on every scheme they can choose, and only a season may replace
// them — the same asymmetry decorations have, and for the same reason: a season is a look,
// where a scheme somebody picked to live with all year must not silently take their marks
// away with no way to tell which choice did it.
func TestOnlyASeasonMayReplaceTheViewersMarks(t *testing.T) {
ordinary := time.Date(2026, time.May, 3, 12, 0, 0, 0, time.UTC)
if got := resolveTheme(themePlum, iconPackLucide, nil, true, true, ordinary); got.IconSet != iconPackLucide {
t.Fatalf("an ordinary day = %q, want the viewer's %q", got.IconSet, iconPackLucide)
}
halloween := time.Date(2026, time.October, 30, 20, 0, 0, 0, time.UTC)
got := resolveTheme(themePlum, iconPackLucide, nil, true, true, halloween)
if !got.Seasonal {
t.Fatalf("expected the Halloween window to be seasonal")
}
if got.IconSet != iconPackFontAwesome {
t.Fatalf("Halloween = %q, want its own %q", got.IconSet, iconPackFontAwesome)
}
if got.Chosen != themePlum {
t.Fatalf("the viewer's own choice should survive underneath a season, got %q", got.Chosen)
}
// Seasons off: the viewer keeps both halves.
if off := resolveTheme(themePlum, iconPackLucide, nil, false, true, halloween); off.IconSet != iconPackLucide {
t.Fatalf("with seasons off = %q, want the viewer's %q", off.IconSet, iconPackLucide)
}
}
// Only seasonal themes may declare marks of their own, the rule that holds the asymmetry
// above in place by construction rather than by a check at the point of use.
func TestOnlySeasonalThemesDeclareAnIconSet(t *testing.T) {
for _, theme := range themeCatalogue {
if theme.Seasonal {
if theme.IconSet != "" && !knownIconPack(theme.IconSet) {
t.Fatalf("%s names an icon pack %q nothing can draw", theme.ID, theme.IconSet)
}
continue
}
if theme.IconSet != "" {
t.Fatalf("selectable theme %s takes the viewer's marks away", theme.ID)
}
}
}
// The revision is the entire delivery mechanism: televisions compare it and refetch only
// when it moves. A pack change the hash did not notice would reach nobody until something
// else about the theme happened to change.
func TestThemeRevisionTracksTheIconSet(t *testing.T) {
ordinary := time.Date(2026, time.May, 3, 12, 0, 0, 0, time.UTC)
material := resolveTheme(themeMidnight, iconPackMaterial, nil, true, true, ordinary)
lucide := resolveTheme(themeMidnight, iconPackLucide, nil, true, true, ordinary)
if material.Revision == lucide.Revision {
t.Fatalf("the same revision %q for two different icon packs", material.Revision)
}
}