fix(theme-guard): close the drift guard's third miss — the meta-guard's own continue whitelisted the gap
test_committed_tres_matches_builder has now been "fixed" three times (traps.md #12). v1 hardcoded 3 checks; v2 iterated ThemeKeys.ALL but missed the six font roles; v3 added a meta-guard specifically to catch "the builder styles a thing guarded by nothing" — but that meta-guard contained `if fresh.get_type_variation_base(variation) == &"": continue`, which whitelisted exactly the case it was built to catch. The builder styles RichTextLabel directly (build_game_theme.gd's _rich_text()), with no set_type_variation, so it reports base "" and was skipped unconditionally — and RichTextLabel is what renders every line of DM prose the creation screen shows (_origin_text, _detail_blurb). Nothing compared its fonts, font size, or colour, nor the theme-level default_font/default_font_size, against the committed .tres. Adds ThemeKeys.BASE_TYPES for base Control types the builder styles directly, folds it into the drift guard's coverage, replaces the meta-guard's continue with an assertion that names the offending type, and adds the missing theme-level default font/size comparison. Proved with three reverted breaks: a RichTextLabel font-size edit, a theme-level default_font_size edit, and an unregistered "GhostRole" variation — all three now go red and name the drifted property. Also: strengthens test_creation_copy's error-copy sweep to assert a mapped error actually reaches its authored line rather than silently falling through to the generic UNSPOKEN fallback (CreationCopy.UNSPOKEN satisfied all four prior checks, so a renamed validator string could regress silently); and removes two assertions that were true by construction / already true before their test's action ran. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,14 +30,19 @@ func test_default_font_is_set():
|
||||
|
||||
|
||||
func _guarded_variations() -> Array:
|
||||
# EVERY variation the builder touches — the stylebox variations (ThemeKeys.ALL)
|
||||
# AND the six font roles (ThemeKeys.FONT_ROLES), which ALL deliberately excludes
|
||||
# by its own docstring. Iterating ALL alone left every font, font size and font
|
||||
# colour in the theme unguarded: change Palette.CREAM (TitleLogo's font colour,
|
||||
# and nothing else's), skip the rebuild, and the suite stayed green with a stale
|
||||
# .tres shipped. traps.md #12 — "covers everything" must iterate the full set.
|
||||
# EVERY variation OR BASE TYPE the builder touches — the stylebox variations
|
||||
# (ThemeKeys.ALL), the six font roles (ThemeKeys.FONT_ROLES), AND the base
|
||||
# types the builder styles directly with no variation on top
|
||||
# (ThemeKeys.BASE_TYPES — today just RichTextLabel). ALL and FONT_ROLES
|
||||
# deliberately exclude each other's half by their own docstrings; missing
|
||||
# BASE_TYPES here left RichTextLabel's two fonts, its font size and its
|
||||
# font colour — the ONLY things rendering DM prose on the creation screen —
|
||||
# unguarded against a stale .tres. traps.md #12, the third miss: iterating
|
||||
# ALL alone, then ALL+FONT_ROLES, both still left a gap "covers everything"
|
||||
# did not actually cover.
|
||||
var out: Array = ThemeKeys.ALL.keys()
|
||||
out.append_array(ThemeKeys.FONT_ROLES.keys())
|
||||
out.append_array(ThemeKeys.BASE_TYPES.keys())
|
||||
return out
|
||||
|
||||
|
||||
@@ -57,7 +62,22 @@ func test_the_drift_guard_covers_every_variation_the_builder_touches():
|
||||
if not touched:
|
||||
continue
|
||||
if fresh.get_type_variation_base(variation) == &"":
|
||||
continue # a BASE type (the builder styles RichTextLabel directly), not a variation
|
||||
# "" means one of two things, and they must be told apart, not both
|
||||
# waved through: (a) a KNOWN base type the builder styles directly
|
||||
# with no set_type_variation (RichTextLabel today — registered in
|
||||
# ThemeKeys.BASE_TYPES), or (b) a type nobody ever registered at
|
||||
# all — styled with set_stylebox/set_font/set_color but never
|
||||
# given a set_type_variation, which reports the same "" and used
|
||||
# to slip through this `continue` forever. The old guard could not
|
||||
# tell these apart because it treated "" as "definitely (a)" and
|
||||
# skipped it unconditionally — the exact whitelist that let
|
||||
# RichTextLabel through in the first place (traps.md #12, third
|
||||
# miss). Assert (a); anything else IS (b) and must be named.
|
||||
assert_true(variation in ThemeKeys.BASE_TYPES,
|
||||
("the builder styles %s directly (no set_type_variation) and it is not in " +
|
||||
"ThemeKeys.BASE_TYPES — add it there, or if it should be a real variation, " +
|
||||
"give it a set_type_variation(...) base so ALL/FONT_ROLES can guard it") % variation)
|
||||
continue
|
||||
assert_true(variation in guarded,
|
||||
"the builder styles the variation %s but no drift guard walks it — add it to ThemeKeys.ALL or ThemeKeys.FONT_ROLES" % variation)
|
||||
|
||||
@@ -75,6 +95,18 @@ func test_committed_tres_matches_builder():
|
||||
var fresh: Theme = Builder.build_theme()
|
||||
var committed: Theme = load(THEME_PATH)
|
||||
|
||||
# Theme-LEVEL defaults (build_game_theme.gd:69-70) live on the Theme object
|
||||
# itself, not under any type or variation, so no per-variation loop below
|
||||
# ever reaches them — they need their own comparison or a changed
|
||||
# default_font_size (18 -> anything) ships silently. Font by resource_path,
|
||||
# not the Resource: load() caches, so two references to the same .ttf are
|
||||
# `==` even when the builder swapped fonts, unless the .tres happens to
|
||||
# still point at the same file.
|
||||
assert_eq(committed.default_font.resource_path, fresh.default_font.resource_path,
|
||||
"stale game_theme.tres — theme.default_font drifted from the builder; re-run build_game_theme.gd")
|
||||
assert_eq(committed.default_font_size, fresh.default_font_size,
|
||||
"stale game_theme.tres — theme.default_font_size drifted from the builder; re-run build_game_theme.gd")
|
||||
|
||||
for variation in _guarded_variations():
|
||||
for state in fresh.get_stylebox_list(variation):
|
||||
assert_true(committed.has_stylebox(state, variation),
|
||||
|
||||
Reference in New Issue
Block a user