test(@projects/@magic-civilization): 🧪 add culture web unit tests

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-04-26 01:02:50 -07:00
parent 921bc73e55
commit 85fef2b753

View file

@ -0,0 +1,112 @@
extends GutTest
## Verifies the `CultureWeb` GDScript wrapper drives `GdCultureWeb` correctly:
## load → graph queries → per-player gating → research-completion signal.
const CultureWebScript: GDScript = preload(
"res://engine/src/modules/empire/culture_web.gd"
)
const PlayerScript: GDScript = preload("res://engine/src/entities/player.gd")
const SAMPLE_TRADITIONS: Array = [
{
"id": "ancestor_song",
"name": "Ancestor Song",
"pillar": "ancestor_worship",
"era": 1, "tier": 1, "cost": 10,
"requires": [],
"unlocks": {"buildings": ["shrine"], "units": [], "improvements": []},
"flavor": "We sing them so they remember us.",
},
{
"id": "rite_of_remembering",
"name": "Rite of Remembering",
"pillar": "ancestor_worship",
"era": 2, "tier": 2, "cost": 25,
"requires": ["ancestor_song"],
"unlocks": {
"buildings": [], "units": [], "improvements": [],
"mechanics": [
{"key": "happiness_per_shrine", "label": "Happiness Per Shrine +1", "value": 1}
]
},
"flavor": "The dead are louder when we listen.",
},
]
func before_each() -> void:
# Each test rebuilds CultureWeb from the in-test fixture; bypass DataLoader
# by stubbing the bridge directly through the wrapper's lazy build path.
pass
func _make_web() -> CultureWebScript:
var web: CultureWebScript = CultureWebScript.new()
# The wrapper normally calls DataLoader.get_all_culture(); for the test we
# instantiate the bridge ourselves and load the fixture JSON.
if not ClassDB.class_exists("GdCultureWeb"):
fail_test("GdCultureWeb GDExtension class not registered")
return null
var bridge: RefCounted = ClassDB.instantiate("GdCultureWeb") as RefCounted
var ok: bool = bool(bridge.call("load_from_json", JSON.stringify(SAMPLE_TRADITIONS)))
assert_true(ok, "GdCultureWeb.load_from_json should succeed")
# Inject the bridge into the wrapper's KnowledgeWeb for direct testing.
# The wrapper exposes `_web` which is a KnowledgeWeb; we set its `_bridge`
# field via duck-typed `set` so the rest of the API works as in production.
var inner: RefCounted = web._web as RefCounted
inner.set("_bridge", bridge)
inner.set("_node_count", SAMPLE_TRADITIONS.size())
return web
func test_tradition_count_and_pillars() -> void:
var web: CultureWebScript = _make_web()
assert_eq(web.get_tradition_count(), 2)
var pillars: Array[String] = web.get_pillars()
assert_eq(pillars.size(), 1)
assert_eq(pillars[0], "ancestor_worship")
func test_prerequisite_gating() -> void:
var web: CultureWebScript = _make_web()
# Set up a player with no culture researched yet.
GameState.players = [PlayerScript.new(0, "Tester", "dwarf")]
GameState.current_player_index = 0
assert_true(web.can_research("ancestor_song", 0))
assert_false(web.can_research("rite_of_remembering", 0),
"rite_of_remembering needs ancestor_song first")
# Grant the prereq and re-check.
(GameState.players[0] as PlayerScript).add_tradition("ancestor_song")
assert_false(web.can_research("ancestor_song", 0),
"already-researched tradition should not be researchable again")
assert_true(web.can_research("rite_of_remembering", 0))
func test_start_research_emits_signal() -> void:
var web: CultureWebScript = _make_web()
GameState.players = [PlayerScript.new(0, "Tester", "dwarf")]
GameState.current_player_index = 0
watch_signals(EventBus)
var ok: bool = web.start_research("ancestor_song", 0)
assert_true(ok)
assert_signal_emitted_with_parameters(
EventBus, "culture_research_started", ["ancestor_song", 0]
)
var p: PlayerScript = GameState.players[0] as PlayerScript
assert_eq(p.researching_tradition, "ancestor_song")
assert_eq(p.culture_research_progress, 0)
func test_unlocks_typed_buckets_round_trip() -> void:
var web: CultureWebScript = _make_web()
var data: Dictionary = web.get_tradition_data("rite_of_remembering")
assert_false(data.is_empty(), "tradition data should round-trip")
var unlocks: Dictionary = data.get("unlocks", {})
var mechanics: Array = unlocks.get("mechanics", []) as Array
assert_eq(mechanics.size(), 1)
var m: Dictionary = mechanics[0] as Dictionary
assert_eq(String(m.get("key", "")), "happiness_per_shrine")
assert_eq(int(m.get("value", 0)), 1)