Files
aetherbound-guild/runtime/tests/foundation/risk_board_page_controller_test.gd
T

124 lines
7.2 KiB
GDScript

extends SceneTree
const Controller = preload("res://entry/risk_board_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 formation := _fixture_formation()
var empty: Dictionary = controller.snapshot(company, formation, "", "en")
expect(empty.ok and empty.page_id == "risk_board", "snapshot identifies Risk Board")
expect(empty.company.owned_count == 4 and empty.company.line_capacity == 4, "snapshot copies Company capacity")
expect(empty.contract.contract_id == "CTR-R1-01" and empty.contract.difficulty == "stormbound", "snapshot copies Contract facts")
expect(empty.party.snapshot_id == "snapshot-001" and empty.party.front_position == 0, "snapshot copies frozen Party identity")
expect(empty.party.front_to_rear_ids == ["r-1", "r-2", "r-3", "r-4"], "snapshot preserves frozen order")
expect(empty.party.ordered_recruits[0].recruit.recruit_id == "r-1" and empty.party.ordered_recruits[0].relation.first_threat_target, "snapshot binds Recruit and relation facts")
expect(empty.party.coverage.protection == 2 and empty.options.count == 3, "snapshot copies coverage and exactly three options")
expect(empty.selection.state == "no_selection" and empty.selection.auto_selected == false, "Risk Board has no automatic selection")
expect(empty.commands.review_enabled == false and empty.commands.back_enabled and empty.commands.settings_enabled, "empty selection command boundary is truthful")
var selected: Dictionary = controller.snapshot(company, formation, "risk-2", "zh_CN")
expect(selected.ok and selected.selection.selected_risk_id == "risk-2" and selected.selection.state == "selected", "selection normalizes to a sourced option")
expect(selected.options.items[1].selected and not selected.options.items[0].selected, "selected option is marked in copied view data")
expect(selected.commands.review_enabled, "selected option enables Review")
var stale: Dictionary = controller.snapshot(company, formation, "missing", "en")
expect(stale.ok and stale.selection.selected_risk_id.is_empty() and not stale.commands.review_enabled, "stale local selection falls back to none")
var not_ready := _fixture_formation()
not_ready.status = "ordered"
var rejected_ready: Dictionary = controller.snapshot(company, not_ready)
expect(not rejected_ready.ok and rejected_ready.code == "RISK_READINESS_REQUIRED", "unaccepted Readiness is rejected")
var no_snapshot := _fixture_formation()
no_snapshot.accepted_party_snapshot = {}
var rejected_snapshot: Dictionary = controller.snapshot(company, no_snapshot)
expect(not rejected_snapshot.ok and rejected_snapshot.code == "RISK_PARTY_SNAPSHOT_REQUIRED", "missing accepted Party snapshot is rejected")
var duplicate_option := _fixture_formation()
duplicate_option.risk_options[1].risk_option_id = "risk-1"
var rejected_duplicate: Dictionary = controller.snapshot(company, duplicate_option)
expect(not rejected_duplicate.ok and rejected_duplicate.code == "RISK_OPTION_DUPLICATE", "duplicate risk option is rejected")
var missing: Dictionary = controller.snapshot({}, formation)
expect(not missing.ok and missing.code == "COMPANY_REQUIRED", "missing Company is rejected")
var copied_recruit: Dictionary = selected.party.ordered_recruits[0].recruit
copied_recruit.rendered_name_snapshot.display_name = "changed"
selected.party.relations[0].protected_by_recruit_ids.append("changed")
selected.options.items[0].known_threat.pressure_tags.append("changed")
expect(company.owned_recruits[0].rendered_name_snapshot.display_name == "Ari", "Recruit facts are deep copied")
expect(formation.relations[0].protected_by_recruit_ids.is_empty(), "relation facts are deep copied")
expect(formation.risk_options[0].known_threat.pressure_tags.is_empty(), "option facts are deep copied")
if failures.is_empty():
print("ABG_M23_RISK_BOARD_CONTROLLER_OK company=4 party=4 options=3 selection=normalized auto_selected=false commands=review,back,settings 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": "r-1", "profession_id": "PF-B01", "rendered_name_snapshot": {"display_name": "Ari"}},
{"recruit_id": "r-2", "profession_id": "PF-B05", "rendered_name_snapshot": {"display_name": "Bram"}},
{"recruit_id": "r-3", "profession_id": "PF-B07", "rendered_name_snapshot": {"display_name": "Cera"}},
{"recruit_id": "r-4", "profession_id": "PF-B03", "rendered_name_snapshot": {"display_name": "Dain"}},
],
"active_contract": {
"contract_id": "CTR-R1-01",
"run_id": "run-001",
"difficulty": "stormbound",
"coin": 38,
"line_capacity": 4,
},
}
func _fixture_formation() -> Dictionary:
return {
"status": "ready",
"orientation": "rear_left_front_right",
"front_position": 0,
"line_capacity": 4,
"saved_front_to_rear_ids": ["r-1", "r-2", "r-3", "r-4"],
"relations": [
{"position": 0, "recruit_id": "r-1", "first_threat_target": true, "protected_by_recruit_ids": []},
{"position": 1, "recruit_id": "r-2", "first_threat_target": false, "protected_by_recruit_ids": ["r-1"]},
{"position": 2, "recruit_id": "r-3", "first_threat_target": false, "protected_by_recruit_ids": ["r-1"]},
{"position": 3, "recruit_id": "r-4", "first_threat_target": false, "protected_by_recruit_ids": []},
],
"coverage": {"protection": 2, "long_reach": 2, "sustain": 1, "control": 1},
"first_threat": {"target_position": 0, "target_recruit_id": "r-1", "enemy_count": 3, "wave_count": 2},
"risk_options": [
{"risk_option_id": "risk-1", "risk": 0, "known_threat": {"enemy_count": 2, "wave_count": 1, "pressure_tags": []}, "uncertainty_id": "disclosed", "entry_cost": 0, "reward_class_id": "standard_supplies", "recovery_exposure_id": "low"},
{"risk_option_id": "risk-2", "risk": 1, "known_threat": {"enemy_count": 3, "wave_count": 2, "pressure_tags": ["surge"]}, "uncertainty_id": "one_intent_unresolved", "entry_cost": 2, "reward_class_id": "enhanced_choice", "recovery_exposure_id": "moderate"},
{"risk_option_id": "risk-3", "risk": 2, "known_threat": {"enemy_count": 4, "wave_count": 3, "pressure_tags": ["elite"]}, "uncertainty_id": "elite_response_unresolved", "entry_cost": 4, "reward_class_id": "elite_cache", "recovery_exposure_id": "high"},
],
"accepted_party_snapshot": {
"snapshot_id": "snapshot-001",
"snapshot_hash": "snapshot-hash-001",
"order_hash": "order-hash-001",
"front_to_rear_ids": ["r-1", "r-2", "r-3", "r-4"],
"relations": [
{"position": 0, "recruit_id": "r-1", "first_threat_target": true, "protected_by_recruit_ids": []},
{"position": 1, "recruit_id": "r-2", "first_threat_target": false, "protected_by_recruit_ids": ["r-1"]},
{"position": 2, "recruit_id": "r-3", "first_threat_target": false, "protected_by_recruit_ids": ["r-1"]},
{"position": 3, "recruit_id": "r-4", "first_threat_target": false, "protected_by_recruit_ids": []},
],
"coverage": {"protection": 2, "long_reach": 2, "sustain": 1, "control": 1},
},
}
func expect(condition: bool, message: String) -> void:
if not condition:
failures.append("M23 Risk Board Controller: %s" % message)