feat(empire): ✨ Add/update test cases for culture web and diplomacy interactions with unique test IDs
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
47a071015e
commit
f7ab1b90d6
5 changed files with 192 additions and 0 deletions
1
src/game/engine/src/modules/empire/culture_web.gd.uid
Normal file
1
src/game/engine/src/modules/empire/culture_web.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cbn8vt4kbgpef
|
||||
188
src/game/engine/src/modules/empire/test_diplomacy.gd
Normal file
188
src/game/engine/src/modules/empire/test_diplomacy.gd
Normal file
|
|
@ -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 = []
|
||||
1
src/game/engine/src/modules/empire/test_diplomacy.gd.uid
Normal file
1
src/game/engine/src/modules/empire/test_diplomacy.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b5yc6dmj8rpx4
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://csjskjvta1s4a
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://cauoj7wwjhj25
|
||||
Loading…
Add table
Reference in a new issue