From 92850560f83174958c546ea7a9b40db67d94f745 Mon Sep 17 00:00:00 2001 From: autocommit Date: Wed, 3 Jun 2026 05:46:13 -0700 Subject: [PATCH] =?UTF-8?q?test(engine):=20=E2=9C=85=20Add=20unit=20tests?= =?UTF-8?q?=20for=20stand-in=20sprite=20coverage,=20including=20sprite=20l?= =?UTF-8?q?oading,=20rendering,=20and=20edge=20cases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- .../unit/test_standin_sprite_coverage.gd | 84 +++++++++++++++++++ .../unit/test_standin_sprite_coverage.gd.uid | 1 + 2 files changed, 85 insertions(+) create mode 100644 src/game/engine/tests/unit/test_standin_sprite_coverage.gd create mode 100644 src/game/engine/tests/unit/test_standin_sprite_coverage.gd.uid diff --git a/src/game/engine/tests/unit/test_standin_sprite_coverage.gd b/src/game/engine/tests/unit/test_standin_sprite_coverage.gd new file mode 100644 index 00000000..de88094a --- /dev/null +++ b/src/game/engine/tests/unit/test_standin_sprite_coverage.gd @@ -0,0 +1,84 @@ +extends GutTest +## Roster-coverage proof for the OSS stand-in sprites (task: playable Godot +## client without paid art). Asserts that for EVERY renderer sprite slot the +## exact path the renderer computes resolves to a real texture via +## `ThemeAssets.load_sprite()`. +## +## Why load_sprite() and not the renderer's get_unit_sprite(): load_sprite() +## returns null on a true miss and does NOT fall back to the procedural +## renderer or the circle baseline. So a non-null result here proves the +## authored PNG actually wins — a clean launch alone would not, because the +## procedural + SVG fallbacks always backfill the visual. +## +## Rosters are the canonical Game-1 sets from objectives p2-23/24/25/26/27. + +# Gender-bearing dwarf units (p2-23). UnitRenderer computes +# `sprites/units/__.png` (race=dwarf, sex=male/female from +# Player.gender_preset) and falls back to the generic `sprites/units/.png`. +const GENDERED_UNITS: Array[String] = [ + "archer", "berserker", "cavalry", "pikeman", + "runesmith", "spearmen", "warrior", "worker", +] + +# Wild creatures (p2-24): generic `sprites/units/.png`, no race/sex. +const WILD_UNITS: Array[String] = [ + "ancient_hydra", "basilisk_wild", "dire_bear", "dire_wolf", "drake_wild", + "elder_wyrm", "feral_spider", "fire_imp", "frostfang_alpha", "garden_snail", + "lava_elemental", "shambling_dead", "stone_sentinel", "wild_wyvern", "wolf_pack", +] + +# Base buildings (p2-25): `sprites/buildings/.png`. +const BUILDINGS: Array[String] = [ + "ale_hall", "barracks", "bathhouse", "colosseum", "forge", + "library", "marketplace", "monument", "temple", "walls", +] + +# Mundane wonders (p2-26): same `sprites/buildings/.png` path. +const WONDERS: Array[String] = [ + "ancestral_forge", "mead_hall", "first_mineshaft", "clan_moot_stone", + "iron_bulwark", "hall_of_ancestors", "the_deep_road", "bardic_circle", + "archive_of_runes", "royal_runestone", "grand_observatory", "covenant_stone", + "the_great_forge", "iron_crown", "undermount_vault", "hall_of_echoes", + "world_pillar", "well_of_ages", "the_undying_flame", "voice_of_ages", + "silent_cartograph", "shrine_of_names", "the_cold_anvil", "hearthless_hall", +] + + +func before_all() -> void: + DataLoader.load_theme("age-of-dwarves") + ThemeAssets.set_theme("age-of-dwarves") + + +func _assert_resolves(rel_path: String) -> void: + var tex: Texture2D = ThemeAssets.load_sprite(rel_path) + assert_not_null(tex, "stand-in sprite must resolve: %s" % rel_path) + if tex != null: + assert_gt(tex.get_width(), 0, "non-empty texture: %s" % rel_path) + + +func test_gendered_unit_paths_resolve() -> void: + # Generic fallback + both renderer-computed race×sex variants. + for uid: String in GENDERED_UNITS: + _assert_resolves("sprites/units/%s.png" % uid) + _assert_resolves("sprites/units/%s_dwarf_male.png" % uid) + _assert_resolves("sprites/units/%s_dwarf_female.png" % uid) + + +func test_wild_creature_paths_resolve() -> void: + for wid: String in WILD_UNITS: + _assert_resolves("sprites/units/%s.png" % wid) + + +func test_building_paths_resolve() -> void: + for bid: String in BUILDINGS: + _assert_resolves("sprites/buildings/%s.png" % bid) + + +func test_wonder_paths_resolve() -> void: + for wid: String in WONDERS: + _assert_resolves("sprites/buildings/%s.png" % wid) + + +func test_city_tier_paths_resolve() -> void: + for q: int in range(1, 6): + _assert_resolves("sprites/cities/city_q%d.png" % q) diff --git a/src/game/engine/tests/unit/test_standin_sprite_coverage.gd.uid b/src/game/engine/tests/unit/test_standin_sprite_coverage.gd.uid new file mode 100644 index 00000000..d7a68c95 --- /dev/null +++ b/src/game/engine/tests/unit/test_standin_sprite_coverage.gd.uid @@ -0,0 +1 @@ +uid://c28007kotbxhm