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

126 lines
6.9 KiB
GDScript

extends SceneTree
const Adapter = preload("res://campaign/fg4_adapter.gd")
const Contract1Battle = preload("res://fg4/contract1_battle_service.gd")
const Contract2Battle = preload("res://fg4/contract2_battle_service.gd")
const Fixture = preload("res://tests/fg4/contract1_fixture.gd")
var failures: Array[String] = []
func _initialize() -> void:
call_deferred("run_test")
func run_test() -> void:
var adapter_script: Script = Adapter
var fixture_script: Script = Fixture
if not adapter_script.can_instantiate() or not fixture_script.can_instantiate():
failures.append("FG-4 campaign adapter: required script failed to compile")
finish()
return
verify_complete_region_flow()
verify_recovery_flow()
finish()
func finish() -> void:
if failures.is_empty():
print("ABG_FG4_CAMPAIGN_ADAPTER_OK rounds=24 bosses=2 records=2 terminal=RG-04 modes=market,plan,battle,recovery,record,handoff,closed valve=true heat=true construct=true repeat=true spark=true 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().market_1_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 == 1, "real RG-03 Market 1 configures")
expect(Adapter.hash_value(source) == source_hash, "adapter never mutates caller snapshot")
if not configured.ok or configured.view.get("routes", []).is_empty():
return
for market_index in range(1, 13):
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.PRIMARY_PLAN[market_index])
expect(adapter.start_plan(plan_id).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, "pressure_valve_disclosed") and has_kind(terminal.events, "outcome"), "Contract 1 Market %d forwards valve and result authority" % market_index)
expect(adapter.settle_terminal().ok, "Contract 1 Market %d settles" % market_index)
expect(adapter.view_state().mode == "boss_muster" and adapter.view_state().boss_id == "BO-R3-01", "Furnace Muster exposes its fixed identity")
expect(adapter.start_plan("vent_and_brace").ok, "Furnace plan starts")
var furnace := adapter.run_battle_to_terminal()
expect(furnace.view.battle.outcome == "victory", "Furnace reaches visible victory")
expect(has_kind(furnace.events, "side_swap_forecast") and has_kind(furnace.events, "weak_side_vented"), "Furnace forwards pressure and vent events")
expect(adapter.settle_terminal().view.mode == "contract_record", "Furnace 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(has_kind(terminal.events, "repeat_counter_disclosed"), "Contract 2 Market %d forwards repeat authority" % 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-R3-02", "Foreman Muster is distinct")
expect(adapter.start_plan("vary_tags").ok, "Foreman variation plan starts")
var foreman := adapter.run_battle_to_terminal()
expect(foreman.view.battle.outcome == "victory", "Foreman reaches visible victory")
expect(has_kind(foreman.events, "next_spark_disclosed") and has_kind(foreman.events, "repeat_counter_reset"), "Foreman forwards spark and repeat events")
expect(adapter.settle_terminal().view.mode == "region_record", "Foreman opens second Record")
var closed := adapter.continue_result()
expect(closed.ok and closed.view.mode == "region_closed", "Region result closes visibly")
expect(closed.view.region_records_count == 2 and closed.view.unlocked_region_ids.count("RG-04") == 1, "two RG-03 Records and RG-04 persist exactly once")
func verify_recovery_flow() -> void:
var snapshot := Fixture.new().market_1_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()
var configured := adapter.configure(snapshot)
expect(configured.ok and not adapter.view_state().get("routes", []).is_empty(), "bounded recovery snapshot configures")
if not configured.ok or adapter.view_state().get("routes", []).is_empty():
return
var route: Dictionary = adapter.view_state().routes[2]
expect(adapter.prepare_route(String(route.offer_id)).ok, "risk-two recovery route prepares")
var primary := String(Contract1Battle.PRIMARY_PLAN[1])
var secondary := String(Contract1Battle.SECONDARY_PLAN[1])
var wrong_plan := ""
for candidate in Contract1Battle.PLAN_IDS:
if candidate not in [primary, secondary]:
wrong_plan = String(candidate)
break
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-4 campaign adapter: %s" % message)