fix(tests): make theme drift guard iterate ThemeKeys.ALL, not 3 hardcoded pairs

test_committed_tres_matches_builder claimed to catch a builder/artifact
drift in game_theme.tres, but its checks array hardcoded exactly three
variation/state pairs (PrimaryCTA, ParchmentCard, DarkPanel) checking only
bg_color. Every other variation — including all five added for the
creation screen (SelectCard, SkillChip, ChosenTag, PrimaryTag,
PrimaryCard) — could drift from the builder silently, and this test would
keep passing on stale data. Textbook docs/traps.md failure: a test that
cannot fail against the bug it names.

Rewrote it to derive checks from ThemeKeys.ALL: for every variation,
every stylebox state the builder actually set is compared (bg_color,
border_color, border widths, corner radii for StyleBoxFlat), and every
font colour role the builder actually set is compared too. Failures name
the variation and the drifted property.

Verified by deliberately drifting SkillChip's pressed stylebox in
build_game_theme.gd without regenerating the .tres: the new test failed
and named SkillChip/pressed/bg_color+border_color; the old three-pair
version would not have caught it (SkillChip was never in its list).
Reverted the drift; suite is green at 279 again. No pre-existing drift
found in the committed artifact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-13 14:57:28 -05:00
parent 0bbf94289a
commit fe8e24cf39

View File

@@ -33,21 +33,52 @@ func test_committed_tres_matches_builder():
# Catches "palette/builder changed but nobody regenerated game_theme.tres."
# Preloading the builder script and calling its static build_theme() does
# NOT run _init() (that only fires on .new()), so this is side-effect-free.
#
# Drives its checks off ThemeKeys.ALL so every variation is guarded, not just
# whichever three someone remembered to hardcode here. For each variation:
# every stylebox state the builder actually set (get_stylebox_list) is
# compared property-by-property when it's a StyleBoxFlat, and every font
# colour role the builder actually set (get_color_list) is compared too.
# Nothing the builder never touches is asserted on.
var fresh: Theme = Builder.build_theme()
var committed: Theme = load(THEME_PATH)
var checks := [
[ThemeKeys.PRIMARY_CTA, &"normal"],
[ThemeKeys.PARCHMENT_CARD, &"panel"],
[ThemeKeys.DARK_PANEL, &"panel"],
]
for pair in checks:
var variation: StringName = pair[0]
var state: StringName = pair[1]
var fresh_box: StyleBoxFlat = fresh.get_stylebox(state, variation)
var committed_box: StyleBoxFlat = committed.get_stylebox(state, variation)
assert_eq(fresh_box.bg_color, committed_box.bg_color,
"stale game_theme.tres — %s/%s bg_color drifted from the builder; re-run build_game_theme.gd" % [variation, state])
for variation in ThemeKeys.ALL:
for state in fresh.get_stylebox_list(variation):
var fresh_box: StyleBox = fresh.get_stylebox(state, variation)
var committed_box: StyleBox = committed.get_stylebox(state, variation)
assert_eq(committed_box.get_class(), fresh_box.get_class(),
"stale game_theme.tres — %s/%s stylebox type drifted from the builder; re-run build_game_theme.gd" % [variation, state])
if fresh_box is StyleBoxFlat:
var f: StyleBoxFlat = fresh_box
var c: StyleBoxFlat = committed_box
assert_eq(c.bg_color, f.bg_color,
"stale game_theme.tres — %s/%s bg_color drifted from the builder; re-run build_game_theme.gd" % [variation, state])
assert_eq(c.border_color, f.border_color,
"stale game_theme.tres — %s/%s border_color drifted from the builder; re-run build_game_theme.gd" % [variation, state])
assert_eq(c.border_width_left, f.border_width_left,
"stale game_theme.tres — %s/%s border_width_left drifted from the builder; re-run build_game_theme.gd" % [variation, state])
assert_eq(c.border_width_top, f.border_width_top,
"stale game_theme.tres — %s/%s border_width_top drifted from the builder; re-run build_game_theme.gd" % [variation, state])
assert_eq(c.border_width_right, f.border_width_right,
"stale game_theme.tres — %s/%s border_width_right drifted from the builder; re-run build_game_theme.gd" % [variation, state])
assert_eq(c.border_width_bottom, f.border_width_bottom,
"stale game_theme.tres — %s/%s border_width_bottom drifted from the builder; re-run build_game_theme.gd" % [variation, state])
assert_eq(c.corner_radius_top_left, f.corner_radius_top_left,
"stale game_theme.tres — %s/%s corner_radius_top_left drifted from the builder; re-run build_game_theme.gd" % [variation, state])
assert_eq(c.corner_radius_top_right, f.corner_radius_top_right,
"stale game_theme.tres — %s/%s corner_radius_top_right drifted from the builder; re-run build_game_theme.gd" % [variation, state])
assert_eq(c.corner_radius_bottom_right, f.corner_radius_bottom_right,
"stale game_theme.tres — %s/%s corner_radius_bottom_right drifted from the builder; re-run build_game_theme.gd" % [variation, state])
assert_eq(c.corner_radius_bottom_left, f.corner_radius_bottom_left,
"stale game_theme.tres — %s/%s corner_radius_bottom_left drifted from the builder; re-run build_game_theme.gd" % [variation, state])
for color_name in fresh.get_color_list(variation):
var fresh_color: Color = fresh.get_color(color_name, variation)
var committed_color: Color = committed.get_color(color_name, variation)
assert_eq(committed_color, fresh_color,
"stale game_theme.tres — %s/%s drifted from the builder; re-run build_game_theme.gd" % [variation, color_name])
func test_creation_variations_exist_with_the_states_the_screen_needs():