From f7ab1b90d6000dd3ef926d62322abe793b41e3cf Mon Sep 17 00:00:00 2001 From: autocommit Date: Sun, 26 Apr 2026 03:19:39 -0700 Subject: [PATCH] =?UTF-8?q?feat(empire):=20=E2=9C=A8=20Add/update=20test?= =?UTF-8?q?=20cases=20for=20culture=20web=20and=20diplomacy=20interactions?= =?UTF-8?q?=20with=20unique=20test=20IDs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- .../src/modules/empire/culture_web.gd.uid | 1 + .../src/modules/empire/test_diplomacy.gd | 188 ++++++++++++++++++ .../src/modules/empire/test_diplomacy.gd.uid | 1 + .../unit/empire/test_culture_bridge.gd.uid | 1 + .../unit/empire/test_economy_bridge.gd.uid | 1 + 5 files changed, 192 insertions(+) create mode 100644 src/game/engine/src/modules/empire/culture_web.gd.uid create mode 100644 src/game/engine/src/modules/empire/test_diplomacy.gd create mode 100644 src/game/engine/src/modules/empire/test_diplomacy.gd.uid create mode 100644 src/game/engine/tests/unit/empire/test_culture_bridge.gd.uid create mode 100644 src/game/engine/tests/unit/empire/test_economy_bridge.gd.uid diff --git a/src/game/engine/src/modules/empire/culture_web.gd.uid b/src/game/engine/src/modules/empire/culture_web.gd.uid new file mode 100644 index 00000000..3378f7dc --- /dev/null +++ b/src/game/engine/src/modules/empire/culture_web.gd.uid @@ -0,0 +1 @@ +uid://cbn8vt4kbgpef diff --git a/src/game/engine/src/modules/empire/test_diplomacy.gd b/src/game/engine/src/modules/empire/test_diplomacy.gd new file mode 100644 index 00000000..546949e3 --- /dev/null +++ b/src/game/engine/src/modules/empire/test_diplomacy.gd @@ -0,0 +1,188 @@ +extends GutTest +## Unit tests for Diplomacy GDScript wrapper and happiness.gd traded_luxuries extension. +## +## Diplomacy.process_turn() depends on GdTrade GDExtension — those tests are marked +## pending until the GDExtension surface lands. The helper methods (_apply_relation_changes, +## _apply_trade_changes, _collect_unique_luxury_ids) are pure and tested here without GdTrade. + +const DiplomacyScript: GDScript = preload( + "res://engine/src/modules/empire/diplomacy.gd" +) +const HappinessScript: GDScript = preload( + "res://engine/src/modules/empire/happiness.gd" +) +const PlayerScript: GDScript = preload("res://engine/src/entities/player.gd") + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +func _make_player(idx: int, is_human: bool = false) -> RefCounted: + var p: PlayerScript = PlayerScript.new() + p.index = idx + p.is_human = is_human + p.traded_luxuries = [] + return p + + +func _get_traded(player: RefCounted) -> Array: + return player.get("traded_luxuries") + + +# --------------------------------------------------------------------------- +# _apply_relation_changes +# --------------------------------------------------------------------------- + +func test_relation_change_writes_diplomacy_dict() -> void: + var changes: Array = [{"player_a": 0, "player_b": 1, "new_relation": "war"}] + var diplomacy: Dictionary = {} + # Patch GameState.diplomacy via a local dict — we call the private helper directly + # by calling the static via the loaded script class. + # Because _apply_relation_changes reads GameState.diplomacy directly, we test the + # key format it would produce rather than the autoload side-effect. + var key: String = "%d_%d" % [0, 1] + # Verify _relation_key produces the correct format. + assert_eq(DiplomacyScript._relation_key(0, 1), "0_1") + assert_eq(DiplomacyScript._relation_key(1, 0), "0_1", "min-max order must be consistent") + assert_eq(DiplomacyScript._relation_key(3, 5), "3_5") + assert_eq(DiplomacyScript._relation_key(5, 3), "3_5") + + +func test_relation_key_high_indices() -> void: + assert_eq(DiplomacyScript._relation_key(0, 10), "0_10") + assert_eq(DiplomacyScript._relation_key(10, 0), "0_10") + + +# --------------------------------------------------------------------------- +# _apply_trade_changes +# --------------------------------------------------------------------------- + +func test_apply_trade_changes_populates_traded_luxuries() -> void: + var pa: RefCounted = _make_player(0) + var pb: RefCounted = _make_player(1) + var players: Array = [pa, pb] + + var new_trades: Array = [ + {"player_a": 0, "player_b": 1, "gives_a": "silk", "gives_b": "wine"} + ] + var broken_trades: Array = [] + + DiplomacyScript._apply_trade_changes(players, new_trades, broken_trades) + + # A gives silk → B receives silk + assert_true("silk" in _get_traded(pb), "B should receive silk from A") + # B gives wine → A receives wine + assert_true("wine" in _get_traded(pa), "A should receive wine from B") + + +func test_apply_trade_changes_clears_stale_luxuries() -> void: + var pa: RefCounted = _make_player(0) + pa.set("traded_luxuries", ["stale_gem"]) + var pb: RefCounted = _make_player(1) + var players: Array = [pa, pb] + + # No active trades this turn. + DiplomacyScript._apply_trade_changes(players, [], []) + + assert_eq(_get_traded(pa).size(), 0, "stale traded luxury must be cleared") + + +func test_apply_trade_changes_no_duplicate_entries() -> void: + var pa: RefCounted = _make_player(0) + var pb: RefCounted = _make_player(1) + var players: Array = [pa, pb] + + # Same luxury appears in two separate trades (edge case). + var new_trades: Array = [ + {"player_a": 0, "player_b": 1, "gives_a": "silk", "gives_b": "wine"}, + {"player_a": 0, "player_b": 1, "gives_a": "silk", "gives_b": "wine"}, + ] + DiplomacyScript._apply_trade_changes(players, new_trades, []) + + var silk_count: int = 0 + for luxury: String in _get_traded(pb): + if luxury == "silk": + silk_count += 1 + assert_eq(silk_count, 1, "duplicate luxury from multiple trades must appear only once") + + +func test_apply_trade_changes_skips_invalid_indices() -> void: + var pa: RefCounted = _make_player(0) + var players: Array = [pa] + + # Trade references player index 99 which doesn't exist. + var new_trades: Array = [ + {"player_a": 0, "player_b": 99, "gives_a": "silk", "gives_b": "wine"} + ] + DiplomacyScript._apply_trade_changes(players, new_trades, []) + # Should not crash; pa receives nothing because pb doesn't exist. + assert_eq(_get_traded(pa).size(), 0, "trade with missing partner must not crash or add luxuries") + + +# --------------------------------------------------------------------------- +# happiness.gd:_collect_unique_luxury_ids — traded_luxuries union +# --------------------------------------------------------------------------- + +func _make_game_map_stub() -> RefCounted: + ## Minimal stub: get_tile returns null for all positions. + return RefCounted.new() + + +func test_collect_unique_luxury_ids_includes_traded_luxuries() -> void: + var player: _PlayerShim = _PlayerShim.new() + player.traded_luxuries = ["silk", "wine"] + var result: Array[String] = HappinessScript._collect_unique_luxury_ids(player, _make_game_map_stub()) + assert_true("silk" in result, "traded luxury 'silk' must appear in result") + assert_true("wine" in result, "traded luxury 'wine' must appear in result") + assert_eq(result.size(), 2, "result must contain exactly the 2 traded luxuries") + + +func test_collect_unique_luxury_ids_deduplicates_tile_and_trade() -> void: + var player: _PlayerShim = _PlayerShim.new() + player.traded_luxuries = ["diamond"] + # No cities (tile loop skipped) — diamond appears only via traded_luxuries. + # Duplicate would arise if diamond were also in owned_tiles; with cities=[] we + # test the traded-only dedup path, which is the safe headless route. + var result: Array[String] = HappinessScript._collect_unique_luxury_ids(player, _make_game_map_stub()) + var diamond_count: int = 0 + for id: String in result: + if id == "diamond": + diamond_count += 1 + assert_eq(diamond_count, 1, "diamond must appear exactly once even if added via multiple paths") + + +func test_collect_unique_luxury_ids_empty_when_no_luxuries() -> void: + var player: _PlayerShim = _PlayerShim.new() + var result: Array[String] = HappinessScript._collect_unique_luxury_ids(player, _make_game_map_stub()) + assert_eq(result.size(), 0, "result must be empty when player has no luxuries") + + +func test_collect_unique_luxury_ids_sorted() -> void: + var player: _PlayerShim = _PlayerShim.new() + player.traded_luxuries = ["wine", "gold_vein", "silk"] + var result: Array[String] = HappinessScript._collect_unique_luxury_ids(player, _make_game_map_stub()) + assert_eq(result.size(), 3, "all 3 luxuries must be present") + assert_eq(result[0], "gold_vein", "first element must be 'gold_vein' (alphabetical)") + assert_eq(result[1], "silk", "second element must be 'silk'") + assert_eq(result[2], "wine", "third element must be 'wine'") + + +# --------------------------------------------------------------------------- +# GdTrade-dependent tests — pending until GDExtension surface lands +# --------------------------------------------------------------------------- + +func test_process_turn_pending_gd_trade() -> void: + pending( + "Diplomacy.process_turn() requires GdTrade GDExtension (mc-trade crate)." + + " Mark this test active once trade-rust-dev lands GdTrade." + ) + + +# --------------------------------------------------------------------------- +# Inner helper class — minimal Player property shim for happiness tests +# --------------------------------------------------------------------------- + +class _PlayerShim extends RefCounted: + var traded_luxuries: Array[String] = [] + var cities: Array = [] diff --git a/src/game/engine/src/modules/empire/test_diplomacy.gd.uid b/src/game/engine/src/modules/empire/test_diplomacy.gd.uid new file mode 100644 index 00000000..ad797161 --- /dev/null +++ b/src/game/engine/src/modules/empire/test_diplomacy.gd.uid @@ -0,0 +1 @@ +uid://b5yc6dmj8rpx4 diff --git a/src/game/engine/tests/unit/empire/test_culture_bridge.gd.uid b/src/game/engine/tests/unit/empire/test_culture_bridge.gd.uid new file mode 100644 index 00000000..30bc2b2a --- /dev/null +++ b/src/game/engine/tests/unit/empire/test_culture_bridge.gd.uid @@ -0,0 +1 @@ +uid://csjskjvta1s4a diff --git a/src/game/engine/tests/unit/empire/test_economy_bridge.gd.uid b/src/game/engine/tests/unit/empire/test_economy_bridge.gd.uid new file mode 100644 index 00000000..917d9587 --- /dev/null +++ b/src/game/engine/tests/unit/empire/test_economy_bridge.gd.uid @@ -0,0 +1 @@ +uid://cauoj7wwjhj25