151 lines
7.0 KiB
GDScript
151 lines
7.0 KiB
GDScript
extends SceneTree
|
|
|
|
const Controller = preload("res://entry/knockout_review_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 battle := _fixture_battle()
|
|
|
|
var open: Dictionary = controller.snapshot(company, battle, battle.result, "review", "en")
|
|
expect(open.ok and open.page_id == "knockout_review", "snapshot identifies Knockout Review")
|
|
expect(open.company.owned_count == 4 and open.contract.coin == 51, "snapshot copies Company and Contract facts")
|
|
expect(open.battle.status == "result" and open.battle.operation_id == "battle-op-001", "snapshot copies settled Battle identity")
|
|
expect(open.knockouts.ids == ["r-1"] and open.knockouts.count == 1, "snapshot copies knockout IDs")
|
|
expect(open.knockouts.identities[0].recruit.recruit_id == "r-1" and open.knockouts.identities[0].position == 0, "snapshot binds stable Recruit identity and position")
|
|
expect(open.gap.battle_local and open.gap.company_identity_preserved and open.gap.return_rule == "returns_next_stage_same_identity", "snapshot exposes battle-local return rule")
|
|
expect(open.reward.pending and open.acknowledgement.target == "battle_reward_choice", "open reward routes acknowledgement to Reward Choice")
|
|
expect(open.commands.acknowledge_enabled and open.commands.back_enabled, "acknowledgement and Back remain enabled")
|
|
expect(open.receipt.duplicate_safe and open.receipt.receipt_hash == "settlement-hash-001", "settlement receipt identity is duplicate-safe")
|
|
|
|
var copied_recruit: Dictionary = open.knockouts.identities[0].recruit
|
|
copied_recruit.rendered_name_snapshot.display_name = "changed"
|
|
open.reward.draft.options[0].reward_id = "changed"
|
|
open.battle.copy.phase_events[0].caption_id = "changed"
|
|
expect(String(company.owned_recruits[0].rendered_name_snapshot.display_name) == "Ari", "Recruit identity is deeply copied")
|
|
expect(String(battle.reward_draft.options[0].reward_id) == "reward-1", "reward draft is deeply copied")
|
|
expect(String(battle.phase_events[0].caption_id) == "opening", "Battle facts are deeply copied")
|
|
|
|
var no_reward := battle.duplicate(true)
|
|
no_reward.reward_draft = {}
|
|
var recovery: Dictionary = controller.snapshot(company, no_reward, no_reward.result)
|
|
expect(recovery.ok and not recovery.reward.pending and recovery.acknowledgement.target == "battle_recovery", "closed reward routes acknowledgement to Recovery")
|
|
|
|
var no_knockout := battle.duplicate(true)
|
|
no_knockout.knocked_out_ids = []
|
|
no_knockout.result = battle.result.duplicate(true)
|
|
no_knockout.result.knocked_out_ids = []
|
|
var empty_review: Dictionary = controller.snapshot(company, no_knockout, no_knockout.result)
|
|
expect(empty_review.ok and empty_review.knockouts.count == 0 and empty_review.gap.state == "no_knockout", "empty knockout review remains explicit and valid")
|
|
|
|
var missing: Dictionary = controller.snapshot({}, battle, battle.result)
|
|
expect(not missing.ok and missing.code == "COMPANY_REQUIRED", "missing Company is rejected")
|
|
var active := battle.duplicate(true)
|
|
active.status = "active"
|
|
var unsettled: Dictionary = controller.snapshot(company, active, battle.result)
|
|
expect(not unsettled.ok and unsettled.code == "KNOCKOUT_BATTLE_NOT_SETTLED", "unsettled Battle is rejected")
|
|
var unknown := battle.duplicate(true)
|
|
unknown.result = battle.result.duplicate(true)
|
|
unknown.result.knocked_out_ids = ["missing"]
|
|
unknown.knocked_out_ids = ["missing"]
|
|
var unknown_result: Dictionary = controller.snapshot(company, unknown, unknown.result)
|
|
expect(not unknown_result.ok and unknown_result.code == "KNOCKOUT_RECRUIT_UNKNOWN", "unknown knockout identity is rejected")
|
|
var duplicate := battle.duplicate(true)
|
|
duplicate.result = battle.result.duplicate(true)
|
|
duplicate.result.knocked_out_ids = ["r-1", "r-1"]
|
|
duplicate.knocked_out_ids = ["r-1", "r-1"]
|
|
var duplicate_result: Dictionary = controller.snapshot(company, duplicate, duplicate.result)
|
|
expect(not duplicate_result.ok and duplicate_result.code == "KNOCKOUT_RECRUIT_DUPLICATE", "duplicate knockout identity is rejected")
|
|
var missing_receipt_company := company.duplicate(true)
|
|
missing_receipt_company.active_contract.battle_settlement_receipts = []
|
|
var missing_receipt_battle := battle.duplicate(true)
|
|
missing_receipt_battle.erase("settlement_receipt")
|
|
var missing_receipt: Dictionary = controller.snapshot(missing_receipt_company, missing_receipt_battle, missing_receipt_battle.result)
|
|
expect(not missing_receipt.ok and missing_receipt.code == "KNOCKOUT_SETTLEMENT_RECEIPT_REQUIRED", "missing settlement receipt is rejected")
|
|
|
|
if failures.is_empty():
|
|
print("ABG_M28_KNOCKOUT_REVIEW_CONTROLLER_OK company=4 settled=result knockout=r-1 battle_local=true return=same_identity reward=open,none acknowledge=reward,recovery empty=true copies=true receipt=duplicate_safe")
|
|
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", "rendered_name_snapshot": {"display_name": "Ari"}, "profession_id": "PF-B01", "level": 1, "xp": 0},
|
|
{"recruit_id": "r-2", "rendered_name_snapshot": {"display_name": "Bram"}, "profession_id": "PF-B05", "level": 1, "xp": 16},
|
|
{"recruit_id": "r-3", "rendered_name_snapshot": {"display_name": "Cera"}, "profession_id": "PF-B07", "level": 1, "xp": 16},
|
|
{"recruit_id": "r-4", "rendered_name_snapshot": {"display_name": "Dain"}, "profession_id": "PF-B03", "level": 1, "xp": 16},
|
|
],
|
|
"active_contract": {
|
|
"contract_id": "CTR-R1-01",
|
|
"run_id": "run-001",
|
|
"status": "result",
|
|
"coin": 51,
|
|
"line_capacity": 4,
|
|
"contract_hash": "contract-hash-001",
|
|
"battle_settlement_receipts": [_fixture_receipt()],
|
|
},
|
|
}
|
|
|
|
|
|
func _fixture_battle() -> Dictionary:
|
|
return {
|
|
"status": "result",
|
|
"operation_id": "battle-op-001",
|
|
"battle_hash": "battle-hash-001",
|
|
"snapshot_id": "snapshot-001",
|
|
"snapshot_hash": "snapshot-hash-001",
|
|
"front_to_rear_ids": ["r-1", "r-2", "r-3", "r-4"],
|
|
"enemy_ids": ["enemy-1", "enemy-2", "enemy-3"],
|
|
"phase_index": 9,
|
|
"total_phases": 9,
|
|
"phase_events": [{"event_id": "event-0", "event_hash": "event-hash-0", "kind": "opening", "caption_id": "opening"}],
|
|
"knocked_out_ids": ["r-1"],
|
|
"result": {
|
|
"outcome": "victory",
|
|
"outcome_cause": "enemy_line_broken",
|
|
"reward_coin": 27,
|
|
"xp_award": 48,
|
|
"coin_before": 24,
|
|
"coin_after": 51,
|
|
"knocked_out_ids": ["r-1"],
|
|
"result_hash": "result-hash-001",
|
|
},
|
|
"reward_draft": {
|
|
"draft_id": "draft-001",
|
|
"status": "open",
|
|
"options": [
|
|
{"reward_id": "reward-1", "kind": "equipment"},
|
|
{"reward_id": "reward-2", "kind": "coin", "amount": 8},
|
|
],
|
|
},
|
|
"settlement_receipt": _fixture_receipt(),
|
|
}
|
|
|
|
|
|
func _fixture_receipt() -> Dictionary:
|
|
return {
|
|
"operation_id": "battle-op-001",
|
|
"battle_operation_id": "battle-op-001",
|
|
"receipt_hash": "settlement-hash-001",
|
|
"outcome_hash": "outcome-hash-001",
|
|
"outcome": "victory",
|
|
}
|
|
|
|
|
|
func expect(condition: bool, message: String) -> void:
|
|
if not condition:
|
|
failures.append("M28 Knockout Review Controller: %s" % message)
|