Files
aetherbound-guild/runtime/tests/fg3/campaign_adapter_test.gd
T

109 lines
6.1 KiB
GDScript

extends SceneTree
const Adapter = preload("res://campaign/fg3_adapter.gd")
const Contract1Battle = preload("res://fg3/contract1_battle_service.gd")
const Contract2Battle = preload("res://fg3/contract2_battle_service.gd")
const Fixture = preload("res://tests/fg3/contract1_fixture.gd")
var failures: Array[String] = []
func _initialize() -> void:
call_deferred("run_test")
func run_test() -> void:
verify_complete_region_flow()
verify_recovery_flow()
if failures.is_empty():
print("ABG_FG3_CAMPAIGN_ADAPTER_OK market8_to_rg03=true rounds=17 bosses=2 records=2 modes=market,plan,battle,recovery,record,handoff,closed events=source_bound save_authority=unchanged")
quit(0)
else:
for failure in failures:
push_error(failure)
quit(1)
func verify_complete_region_flow() -> void:
var source := Fixture.new().fg3_market_8_snapshot()
var source_hash := Adapter.hash_value(source)
var adapter := Adapter.new()
var configured := adapter.configure(source)
expect(configured.ok and configured.view.mode == "market" and configured.view.market_index == 8, "real saved Market 8 configures")
expect(Adapter.hash_value(source) == source_hash, "adapter never mutates caller snapshot")
if not configured.ok:
return
for market_index in [8, 9, 10, 11, 12]:
var route: Dictionary = adapter.view_state().routes[0]
var prepared := adapter.prepare_route(String(route.offer_id))
expect(prepared.ok and prepared.view.mode == "plan", "Contract 1 Market %d opens response plans" % market_index)
var plan_id := String(Contract1Battle.PREFERRED_PLAN[String(route.route_id)])
var started := adapter.start_plan(plan_id)
expect(started.ok, "Contract 1 Market %d starts authoritative battle" % market_index)
var terminal := adapter.run_battle_to_terminal()
expect(terminal.ok and terminal.view.battle.terminal and terminal.view.battle.outcome == "victory", "Contract 1 Market %d reaches visible victory" % market_index)
expect(has_kind(terminal.events, "wave_arrived") and has_kind(terminal.events, "damage") and has_kind(terminal.events, "outcome"), "Contract 1 Market %d forwards event-bound presentation" % market_index)
var settled := adapter.settle_terminal()
expect(settled.ok, "Contract 1 Market %d settles" % market_index)
expect(adapter.view_state().mode == "boss_muster" and adapter.view_state().plans.size() == 2, "Sluiceback Muster exposes two plans")
expect(adapter.start_plan("follow_index_clear_eggs").ok, "first Boss plan starts")
expect(adapter.run_battle_to_terminal().view.battle.outcome == "victory", "Sluiceback reaches visible victory")
expect(adapter.settle_terminal().view.mode == "contract_record", "first Boss opens first Record")
expect(adapter.continue_result().view.mode == "contract_handoff", "first Record closes into explicit handoff")
expect(adapter.continue_result().view.mode == "market", "handoff opens Contract-2 Market 1")
for market_index in range(1, 13):
var route: Dictionary = adapter.view_state().routes[0]
expect(adapter.prepare_route(String(route.offer_id)).ok, "Contract 2 Market %d prepares" % market_index)
var plan_id := String(Contract2Battle.PRIMARY_PLAN[market_index])
expect(adapter.start_plan(plan_id).ok, "Contract 2 Market %d starts" % market_index)
var terminal := adapter.run_battle_to_terminal()
expect(terminal.view.battle.outcome == "victory", "Contract 2 Market %d reaches visible victory" % market_index)
expect(adapter.settle_terminal().ok, "Contract 2 Market %d settles" % market_index)
expect(adapter.view_state().mode == "boss_muster" and adapter.view_state().boss_id == "BO-R2-02", "Drowned Bell Muster is distinct")
expect(adapter.start_plan("interrupt_pulse_family").ok, "Drowned Bell interrupt plan starts")
var bell_terminal := adapter.run_battle_to_terminal()
expect(bell_terminal.view.battle.outcome == "victory", "Drowned Bell reaches visible victory")
expect(has_kind(bell_terminal.events, "linked_positions_disclosed") and has_kind(bell_terminal.events, "third_pulse_link"), "Drowned Bell forwards pair and triple disclosures")
expect(adapter.settle_terminal().view.mode == "region_record", "Drowned Bell opens second Record")
var closed := adapter.continue_result()
expect(closed.ok and closed.view.mode == "region_closed", "Region result closes visibly")
expect(closed.view.records_count == 2 and closed.view.unlocked_region_ids.count("RG-03") == 1, "two Records and RG-03 persist exactly once")
func verify_recovery_flow() -> void:
var snapshot := Fixture.new().fg3_market_8_snapshot()
var company: Array = Array(snapshot.current_run.company).duplicate()
var deployed_count := mini(4, company.size())
snapshot.current_run.deployed_recruit_ids = company.slice(0, deployed_count)
snapshot.current_run.reserve_recruit_ids = company.slice(deployed_count)
snapshot.current_run.formation_proposal = company.slice(0, deployed_count)
var adapter := Adapter.new()
expect(adapter.configure(snapshot).ok, "bounded recovery snapshot configures")
var route: Dictionary = adapter.view_state().routes[2]
expect(adapter.prepare_route(String(route.offer_id)).ok, "risk-two recovery route prepares")
var preferred := String(Contract1Battle.PREFERRED_PLAN[String(route.route_id)])
var wrong_plan := "hold_line"
if wrong_plan == preferred:
wrong_plan = "guard_center"
expect(adapter.start_plan(wrong_plan).ok, "nonpreferred response starts")
var terminal := adapter.run_battle_to_terminal()
expect(terminal.view.battle.outcome == "defeat" and terminal.view.battle.fallen_recruit_ids.size() == 1, "visible defeat names one Fallen Recruit")
var settled := adapter.settle_terminal()
expect(settled.ok and settled.view.mode == "recovery", "defeat opens recovery presentation")
var survivors: int = settled.view.company.size()
var recovered := adapter.recover()
expect(recovered.ok and recovered.view.mode == "market", "recovery returns to the same Market")
expect(recovered.view.company.size() == survivors, "recovery never resurrects or auto-substitutes")
func has_kind(events: Array, kind: String) -> bool:
for event in events:
if String(event.get("kind", "")) == kind:
return true
return false
func expect(condition: bool, message: String) -> void:
if not condition:
failures.append("FG-3 campaign adapter: %s" % message)