Files
aetherbound-guild/runtime/tests/p10_3/continuous_runtime_test.gd
T

169 lines
8.8 KiB
GDScript

extends SceneTree
const BattleService = preload("res://p10_3/deep_channels_battle_service.gd")
const Controller = preload("res://p10_3/runtime_controller.gd")
const Fixture = preload("res://tests/p10_3/deep_channels_fixture.gd")
const Main = preload("res://main.gd")
const P102Controller = preload("res://p10_2/runtime_controller.gd")
const P102Save = preload("res://p10_2/save_v8_service.gd")
const SaveV9 = preload("res://p10_3/save_v9_service.gd")
const VIEWPORT := Vector2i(844, 390)
var experience
var failures: Array[String] = []
func _initialize() -> void:
call_deferred("run_test")
func run_test() -> void:
root.size = VIEWPORT
root.content_scale_mode = Window.CONTENT_SCALE_MODE_CANVAS_ITEMS
root.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_EXPAND
root.content_scale_size = VIEWPORT
experience = Controller.new()
experience.persistence_enabled = false
experience.battle_auto_advance = false
experience.locale = "zh_CN"
experience.size = Vector2(VIEWPORT)
experience.configure_entry(Fixture.new().migrated_snapshot())
root.add_child(experience)
await settle_frames(12)
expect(experience.p103_mode, "Save v9 activates the P10.3 runtime")
expect(experience.screen == Controller.P103_SCREEN_MARKET, "Market 5 resumes as the first deep-channel screen")
expect(experience.find_child("P103DeepFerry", true, false) != null, "Market 5 renders the deep-channel ferry workspace")
expect(experience.find_children("P102RouteTarget_*", "Button", true, false).size() == 3, "Market 5 exposes three route posts")
var starting_order: Array = Array(experience.region_market.state.current_run.deployed_recruit_ids).duplicate()
if starting_order.size() >= 2:
experience._commit_line_drag(String(starting_order[-1]), String(starting_order[0]))
await settle_frames()
expect(experience.region_market.state.current_run.deployed_recruit_ids != starting_order, "deployment drag commits an atomic new order")
await clear_round(5, 0, "channel_thread_adjacent", "P103ChannelThread")
expect(experience.screen == Controller.P103_SCREEN_MARKET, "Round 5 settlement opens Market 6")
await clear_round(6, 1, "safe_index_advanced", "P103SafeIndexPulse")
expect(experience.screen == Controller.P103_SCREEN_ARTIFACT, "Round 6 settlement opens the Artifact shrine")
expect(experience.find_children("P103ArtifactTarget_*", "Button", true, false).size() == 3, "Artifact shrine exposes three opposed laws")
expect(experience.find_child("P103ArtifactShrine", true, false) != null, "Artifact choice remains inside the ferry world")
experience.choose_p103_artifact("AR-012")
await settle_frames()
expect(experience.screen == Controller.P103_SCREEN_PROMOTION, "Artifact choice opens the eligible promotion anvil")
expect(experience.find_children("P103PromotionTarget_*", "Button", true, false).size() == 2, "promotion anvil exposes two deterministic branches")
expect(experience.find_child("P103PromotionAnvil", true, false) != null, "promotion choice remains inside the ferry world")
experience.choose_p103_promotion("PF-A13")
await settle_frames()
expect(experience.screen == Controller.P103_SCREEN_MARKET, "promotion returns to playable Market 7")
await clear_round(7, 2, "long_company_opening", "P103ArtifactPulse")
var run: Dictionary = experience.region_market.state.current_run
expect(experience.screen == Controller.P103_SCREEN_MARKET_8, "Round 7 settlement reaches visible Market 8")
expect(run.phase == "market_8" and run.market_index == 8 and run.cleared_rounds == 7, "Market 8 is the exact continuation boundary")
expect(run.active_artifact_ids == ["AR-012"], "Market 8 visibly preserves Long Company")
expect(_company_has_profession(run, "PF-A13"), "Market 8 visibly preserves Fieldmender")
expect(experience.find_child("P103DeepFerry", true, false) != null, "Market 8 preserves the restored ferry")
var encoded: Dictionary = SaveV9.new().encode_snapshot(experience.region_market.state.snapshot(), 50)
var decoded: Dictionary = SaveV9.new().decode_text(String(encoded.get("text", "")), 50)
expect(encoded.ok and decoded.ok and decoded.snapshot == experience.region_market.state.snapshot(), "visible Market 8 roundtrips through Save v9")
var market_eight_snapshot: Dictionary = experience.region_market.state.snapshot()
experience.queue_free()
await settle_frames(18)
var game = Main.new()
game.auto_boot = false
game.p100_persistence_enabled = false
root.add_child(game)
await settle_frames()
game.p102_experience = P102Controller.new()
game.p102_experience.persistence_enabled = false
game.p102_experience.size = Vector2(VIEWPORT)
game.p102_experience.configure_entry(Fixture.new().p102_market_5_snapshot())
game.add_child(game.p102_experience)
await settle_frames(12)
expect(is_instance_valid(game.p103_handoff_button), "main exposes one Continue Deep Channels command on stable P10.2 Market 5")
if is_instance_valid(game.p103_handoff_button):
game.p103_handoff_button.emit_signal(&"pressed")
await settle_frames(12)
expect(is_instance_valid(game.p103_experience), "main hands stable P10.2 Market 5 to the P10.3 runtime")
if is_instance_valid(game.p103_experience):
expect(game.p103_experience.p103_mode and int(game.p103_experience.region_market.state.current_run.market_index) == 5, "main handoff migrates into exact P10.3 Market 5")
game.queue_free()
await settle_frames(18)
_cleanup_save_files()
var p102_path := ProjectSettings.globalize_path("user://aetherbound_guild_p10_2.json")
var p103_path := ProjectSettings.globalize_path("user://aetherbound_guild_p10_3.json")
var wrote_v8 := P102Save.new().write_slot(p102_path, Fixture.new().p102_market_5_snapshot(), 60, "")
var wrote_v9 := SaveV9.new().write_slot(p103_path, market_eight_snapshot, 61, "")
expect(wrote_v8.ok and wrote_v9.ok, "resume priority fixture writes valid Save v8 and Save v9 slots")
var resumed = Main.new()
resumed.auto_boot = true
resumed.p100_experience_enabled = true
resumed.p100_persistence_enabled = true
root.add_child(resumed)
await settle_frames(18)
expect(is_instance_valid(resumed.p103_experience), "main prioritizes Save v9 when Save v8 also exists")
expect(not is_instance_valid(resumed.p102_experience), "Save v9 priority does not mount the older P10.2 runtime")
if is_instance_valid(resumed.p103_experience):
expect(resumed.p103_experience.screen == Controller.P103_SCREEN_MARKET_8, "Save v9 priority restores exact Market 8")
resumed.queue_free()
await settle_frames(45)
_cleanup_save_files()
if failures.is_empty():
print("ABG_P10_3_CONTINUOUS_RUNTIME_OK markets=5,6,7,8 rounds=5,6,7 artifact=AR-012 promotion=PF-A13 order=drag widow=event_bound sluice=event_bound artifact_effect=event_bound ferry=world_first save_v9=stable main=handoff resume=v9_priority")
quit(0)
else:
for failure in failures:
push_error(failure)
quit(1)
func clear_round(market_index: int, risk: int, event_kind: String, effect_node: String) -> void:
expect(int(experience.region_market.state.current_run.market_index) == market_index, "Round %d starts at its matching Market" % market_index)
var route: Dictionary = experience.region_market.state.current_run.market_board.battle_offers[risk]
var plan_id := String(BattleService.PREFERRED_PLAN[String(route.route_id)])
experience.tap_region_route(String(route.offer_id))
experience.commit_region_route()
await settle_frames()
expect(experience.screen == Controller.P103_SCREEN_PLAN, "Round %d opens the four-plan workspace" % market_index)
expect(experience.find_children("P102PlanTarget_*", "Button", true, false).size() == 4, "Round %d presents four direct plan targets" % market_index)
experience.choose_region_plan(plan_id)
experience.advance_region_battle_ticks(999)
await settle_frames()
expect(experience.screen == Controller.P103_SCREEN_BATTLE and experience.region_battle_complete, "Round %d reaches its visible result" % market_index)
expect(int(experience.region_event_counts.get(event_kind, 0)) == 1, "Round %d consumes %s exactly once" % [market_index, event_kind])
expect(experience.find_child(effect_node, true, false) != null, "Round %d binds %s to a world effect" % [market_index, event_kind])
experience.settle_region_battle()
await settle_frames()
func _company_has_profession(run: Dictionary, profession_id: String) -> bool:
for recruit_id in run.company:
if String(run.recruit_records[recruit_id].profession_id) == profession_id:
return true
return false
func _cleanup_save_files() -> void:
for save_name in ["user://aetherbound_guild_p10_2.json", "user://aetherbound_guild_p10_3.json"]:
for suffix in ["", ".bak", ".candidate"]:
var path := ProjectSettings.globalize_path(save_name + suffix)
if FileAccess.file_exists(path):
DirAccess.remove_absolute(path)
func settle_frames(count := 5) -> void:
for _index in count:
await process_frame
func expect(condition: bool, message: String) -> void:
if not condition:
failures.append("P10.3 continuous runtime: %s" % message)