124 lines
7.2 KiB
GDScript
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)
|