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

93 lines
5.2 KiB
GDScript

extends SceneTree
const Controller = preload("res://entry/party_line_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 preview := _fixture_preview()
var view: Dictionary = controller.snapshot(company, formation, ["r-1", "r-2", "r-3", "r-4"], "r-2", preview, ["r-4", "r-3", "r-2", "r-1"], "en")
expect(view.ok and view.page_id == "party_line", "snapshot identifies Party Line")
expect(view.company.owned_count == 4 and view.company.line_capacity == 4, "snapshot copies Company and capacity facts")
expect(view.contract.contract_id == "CTR-R1-01" and view.contract.difficulty == "stormbound", "snapshot copies Contract facts")
expect(view.formation.orientation == "rear_left_front_right" and view.formation.front_position == 0, "snapshot exposes orientation and front position")
expect(view.order.front_to_rear_ids == ["r-1", "r-2", "r-3", "r-4"] and view.order.selected_recruit_id == "r-2", "snapshot preserves order and selection")
expect(view.order.ordered_recruits[0].recruit.recruit_id == "r-1" and view.order.ordered_recruits[0].relation.first_threat_target, "snapshot binds ordered Recruit and relation facts")
expect(view.preview.coverage.protection == 2 and view.preview.relations.size() == 4, "snapshot copies preview coverage and relations")
expect(view.commands.undo_enabled and view.commands.reset_enabled and view.commands.save_enabled, "snapshot exposes command eligibility")
var fallback: Dictionary = controller.snapshot(company, formation, ["r-1", "r-2", "r-3", "r-4"], "missing", preview, [], "zh_CN")
expect(fallback.ok and fallback.order.selected_recruit_id.is_empty() and fallback.order.selection_reason == "no_selection", "stale selection falls back to no selection")
var duplicate: Dictionary = controller.snapshot(company, formation, ["r-1", "r-1", "r-3", "r-4"], "", preview)
expect(not duplicate.ok and duplicate.code == "FORMATION_RECRUIT_DUPLICATE", "duplicate order is rejected")
var unknown: Dictionary = controller.snapshot(company, formation, ["r-1", "r-2", "r-3", "missing"], "", preview)
expect(not unknown.ok and unknown.code == "FORMATION_RECRUIT_UNKNOWN", "unknown Recruit order is rejected")
var missing: Dictionary = controller.snapshot({}, formation, [], "", preview)
expect(not missing.ok and missing.code == "COMPANY_REQUIRED", "missing Company is rejected")
var no_formation: Dictionary = controller.snapshot(company, {}, ["r-1", "r-2", "r-3", "r-4"], "", preview)
expect(not no_formation.ok and no_formation.code == "FORMATION_REQUIRED", "missing Formation is rejected")
var copied: Dictionary = view.order.ordered_recruits[0].recruit
copied.rendered_name_snapshot.display_name = "changed"
view.preview.relations[0].protected_by_recruit_ids.append("changed")
expect(company.owned_recruits[0].rendered_name_snapshot.display_name == "Ari", "Recruit facts are deep copied")
expect(preview.relations[0].protected_by_recruit_ids.size() == 0, "preview relations are deep copied")
if failures.is_empty():
print("ABG_M21_PARTY_LINE_CONTROLLER_OK company=4 order=4 orientation=rear_left_front_right selection=normalized preview=relations,coverage,threat commands=undo,reset,save 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": "draft",
"orientation": "rear_left_front_right",
"front_position": 0,
"line_capacity": 4,
"base_front_to_rear_ids": ["r-4", "r-3", "r-2", "r-1"],
"first_threat": {"target_position": 0, "target_recruit_id": "r-1", "enemy_count": 3, "wave_count": 2},
}
func _fixture_preview() -> Dictionary:
return {
"ok": true,
"order_hash": "hash-001",
"coverage": {"protection": 2, "long_reach": 2, "sustain": 1, "control": 1},
"relations": [
{"position": 0, "recruit_id": "r-1", "first_threat_target": true, "protected_by_recruit_ids": [], "reach_id": "front_two"},
{"position": 1, "recruit_id": "r-2", "first_threat_target": false, "protected_by_recruit_ids": ["r-1"], "reach_id": "full_line"},
{"position": 2, "recruit_id": "r-3", "first_threat_target": false, "protected_by_recruit_ids": ["r-1"], "reach_id": "full_line"},
{"position": 3, "recruit_id": "r-4", "first_threat_target": false, "protected_by_recruit_ids": [], "reach_id": "front_three"},
],
}
func expect(condition: bool, message: String) -> void:
if not condition:
failures.append("M21 Party Line Controller: %s" % message)