extends SceneTree const Controller = preload("res://entry/guild_page_controller.gd") var failures: Array[String] = [] func _initialize() -> void: call_deferred("run_test") func run_test() -> void: var controller := Controller.new() var company := _fixture_company() var empty_view: Dictionary = controller.snapshot(company, "zh_CN") expect(empty_view.ok and empty_view.page_id == "guild", "snapshot identifies Guild") expect(empty_view.company.owned_count == 2 and empty_view.company.display_recruits.size() == 2, "snapshot copies Company and display recruits") expect(empty_view.contract.state == "empty" and not empty_view.contract.present, "empty Contract state is explicit") expect(empty_view.destinations.contract.enabled and not empty_view.destinations.market.enabled, "empty Guild exposes Contract and locks Market") expect(not empty_view.destinations.party.enabled and empty_view.destinations.party.reason == "contract_required", "empty Guild locks Party with an explicit reason") var active := company.duplicate(true) active.active_contract = { "status": "market", "contract_id": "CTR-R1-01", "run_id": "run-001", "route_id": "windglass_verge", "difficulty": "stormbound", "coin": 38, "line_capacity": 4, } var active_view: Dictionary = controller.snapshot(active, "en") expect(active_view.contract.state == "active" and active_view.contract.active, "active Contract state is explicit") expect(active_view.contract.contract_id == "CTR-R1-01" and active_view.contract.coin == 38 and active_view.contract.difficulty == "stormbound", "active Contract facts are copied") expect(active_view.destinations.market.enabled and active_view.destinations.party.enabled and active_view.destinations.risk.enabled, "active Guild opens downstream destinations") expect(not active_view.destinations.contract.enabled and active_view.destinations.contract.reason == "contract_active", "active Guild blocks a second Contract") var returned := active.duplicate(true) returned.active_contract.status = "returned" var returned_view: Dictionary = controller.snapshot(returned, "zh_CN") expect(returned_view.contract.state == "returned" and returned_view.contract.returned, "returned Contract state is explicit") expect(not returned_view.destinations.market.enabled and returned_view.destinations.market.reason == "contract_returned", "returned Guild keeps Market closed") expect(not returned_view.destinations.contract.enabled and returned_view.destinations.contract.reason == "contract_returned", "returned Guild keeps a later Contract closed") var missing: Dictionary = controller.snapshot({}, "zh_CN") expect(not missing.ok and missing.code == "COMPANY_REQUIRED", "missing Company is rejected") var invalid := company.duplicate(true) invalid.owned_recruits = "invalid" var invalid_view: Dictionary = controller.snapshot(invalid, "zh_CN") expect(not invalid_view.ok and invalid_view.code == "COMPANY_INVALID", "invalid Company is rejected") var unknown := controller.destination_state(empty_view, "unknown") expect(not unknown.enabled and unknown.reason == "unknown_destination", "unknown destination is explicitly blocked") var copied: Dictionary = empty_view.company.display_recruits[0] copied.recruit_id = "changed" copied.rendered_name_snapshot.display_name = "changed" expect(company.owned_recruits[0].recruit_id == "owned-001", "view data is isolated from Company input") expect(company.owned_recruits[0].rendered_name_snapshot.display_name == "Ari", "nested recruit facts are deep copied") if failures.is_empty(): print("ABG_M20_GUILD_CONTROLLER_OK company=2 display_recruits=2 states=empty,active,returned resources=coin38,line4 destinations=contract,market,equipment,party,risk copies=true") quit(0) else: for failure in failures: push_error(failure) quit(1) func _fixture_company() -> Dictionary: return { "company_id": "company-001", "owned_recruits": [ {"recruit_id": "owned-001", "rendered_name_snapshot": {"display_name": "Ari"}, "profession_id": "PF-B01"}, {"recruit_id": "owned-002", "rendered_name_snapshot": {"display_name": "Bram"}, "profession_id": "PF-B02"}, ], "active_contract": {}, } func expect(condition: bool, message: String) -> void: if not condition: failures.append("M20 Guild Controller: %s" % message)