148 lines
6.2 KiB
GDScript
148 lines
6.2 KiB
GDScript
extends SceneTree
|
|
|
|
const MainScene = preload("res://main.tscn")
|
|
|
|
const SETTINGS_PATH := "user://aetherbound_guild_settings.json"
|
|
const DRAFT_PATH := "user://aetherbound_initial_company_draft.json"
|
|
const COMPANY_PATH := "user://aetherbound_expedition_company.json"
|
|
const LEGACY_SAVE_PATH := "user://aetherbound_guild_p10_3.json"
|
|
|
|
var failures: Array[String] = []
|
|
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("run_test")
|
|
|
|
|
|
func run_test() -> void:
|
|
root.content_scale_mode = Window.CONTENT_SCALE_MODE_CANVAS_ITEMS
|
|
# Single target size (owner policy): every screen is authored at 1280x720.
|
|
root.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_KEEP
|
|
root.content_scale_size = Vector2i(1280, 720)
|
|
root.size = Vector2i(1280, 720)
|
|
_cleanup()
|
|
|
|
var game = MainScene.instantiate()
|
|
game.audio_enabled = false
|
|
root.add_child(game)
|
|
await _frames(60)
|
|
var shell = game.entry_shell
|
|
var setup_apply := await _wait_for_node(shell, "SetupApply")
|
|
expect(setup_apply != null, "fresh launch reaches first-launch setup after Boot")
|
|
await _touch(setup_apply)
|
|
expect(shell.current_screen == "title", "first-launch setup reaches Title")
|
|
var new_game := await _wait_for_node(shell, "TitleNewGame")
|
|
await _touch(new_game)
|
|
var page = shell.initial_company_page
|
|
await _touch(page.find_child("CandidateSelect_0", true, false))
|
|
await _touch(page.find_child("CandidateSelect_2", true, false))
|
|
await _touch(page.find_child("ReviewCompany", true, false))
|
|
expect(page.mode == "review", "choose-two reaches Review through parsed touch")
|
|
await _touch(page.find_child("ReviewRevise", true, false))
|
|
expect(page.mode == "choice" and page.draft.selected_offer_ids.size() == 2, "Revise keeps the saved pair")
|
|
var selected_ids: Array = Array(page.draft.selected_offer_ids).duplicate()
|
|
game.queue_free()
|
|
await _frames(20)
|
|
|
|
var precommit_restart = MainScene.instantiate()
|
|
precommit_restart.audio_enabled = false
|
|
root.add_child(precommit_restart)
|
|
await _frames(60)
|
|
var restarted_shell = precommit_restart.entry_shell
|
|
var restarted_new_game := await _wait_for_node(restarted_shell, "TitleNewGame")
|
|
expect(restarted_new_game != null, "pre-commit restart skips completed setup and reaches Title")
|
|
await _touch(restarted_new_game)
|
|
page = restarted_shell.initial_company_page
|
|
expect(page.draft.selected_offer_ids == selected_ids, "pre-commit restart restores the same selected IDs")
|
|
await _touch(page.find_child("ReviewCompany", true, false))
|
|
await _touch(page.find_child("CreateCompany", true, false))
|
|
expect(restarted_shell.current_screen == "guild_handoff", "Create Company reaches the bounded Guild handoff")
|
|
expect(restarted_shell.find_child("GuildRoster", true, false).get_child_count() == 2, "Guild handoff shows the persistent pair")
|
|
var audio: Node = restarted_shell.audio_service
|
|
expect(audio != null, "runtime audio service is attached to the shell")
|
|
if audio != null:
|
|
expect(int(audio.events.size()) == 144, "audio manifest maps the 144 contract events")
|
|
var families: Array = []
|
|
var page_opens := 0
|
|
var commits := 0
|
|
for record in audio.journal:
|
|
if String(record.get("kind", "")) == "music":
|
|
families.append(String(record.get("name", "")))
|
|
if String(record.get("kind", "")) == "sfx" and String(record.get("name", "")) == "page_open":
|
|
page_opens += 1
|
|
if String(record.get("kind", "")) == "sfx" and String(record.get("name", "")) == "recruit_hire_commit" and String(record.get("suppressed", "")) == "":
|
|
commits += 1
|
|
expect(families.has("title") and families.has("guild"), "page families switch from title to guild, got %s" % str(families))
|
|
expect(int(audio.music_switches) >= 2, "music family switches are counted")
|
|
expect(page_opens >= 3, "page_open cue fires on page entry, got %d" % page_opens)
|
|
expect(commits >= 1, "create-company dispatches the hire commit cue")
|
|
print("ABG_M76_AUDIO_ENTRY_OK families=%d page_open=%d commits=%d switches=%d events=%d" % [families.size(), page_opens, commits, int(audio.music_switches), int(audio.events.size())])
|
|
precommit_restart.queue_free()
|
|
await _frames(20)
|
|
|
|
var committed_restart = MainScene.instantiate()
|
|
committed_restart.audio_enabled = false
|
|
root.add_child(committed_restart)
|
|
await _frames(60)
|
|
var committed_roster := await _wait_for_node(committed_restart.entry_shell, "GuildRoster")
|
|
expect(committed_roster != null and committed_restart.entry_shell.current_screen == "guild_handoff", "post-commit restart resumes directly at Guild")
|
|
expect(committed_roster != null and committed_roster.get_child_count() == 2, "post-commit Guild retains exactly two members")
|
|
var committed_audio: Node = committed_restart.entry_shell.audio_service
|
|
expect(committed_audio != null, "runtime audio service survives page rebuilds")
|
|
if committed_audio != null:
|
|
expect(int(committed_audio.events.size()) == 144, "audio manifest maps the 144 contract events")
|
|
committed_restart.queue_free()
|
|
await _frames(20)
|
|
_cleanup()
|
|
|
|
if failures.is_empty():
|
|
print("ABG_DEV2_FULL_FLOW_TOUCH_OK boot_setup_title_choose_review_revise_precommit_restart_create_guild_postcommit_restart=true parsed_screen_touch=true")
|
|
quit(0)
|
|
else:
|
|
for failure in failures:
|
|
push_error(failure)
|
|
quit(1)
|
|
|
|
|
|
func _touch(control: Control) -> void:
|
|
var center := root.get_final_transform() * control.get_global_rect().get_center()
|
|
var press := InputEventScreenTouch.new()
|
|
press.position = center
|
|
press.pressed = true
|
|
press.index = 0
|
|
Input.parse_input_event(press)
|
|
await _frames(2)
|
|
var release := InputEventScreenTouch.new()
|
|
release.position = center
|
|
release.pressed = false
|
|
release.index = 0
|
|
Input.parse_input_event(release)
|
|
await _frames(5)
|
|
|
|
|
|
func _cleanup() -> void:
|
|
for base in [SETTINGS_PATH, DRAFT_PATH, COMPANY_PATH, LEGACY_SAVE_PATH]:
|
|
for suffix in ["", ".bak", ".candidate", ".bak.candidate", ".corrupt"]:
|
|
var path := "%s%s" % [base, suffix]
|
|
if FileAccess.file_exists(path):
|
|
DirAccess.remove_absolute(path)
|
|
|
|
|
|
func _wait_for_node(shell: Node, node_name: String, max_frames := 600) -> Node:
|
|
for _i in range(max_frames):
|
|
var node := shell.find_child(node_name, true, false)
|
|
if node != null:
|
|
return node
|
|
await process_frame
|
|
return null
|
|
|
|
|
|
func _frames(count: int) -> void:
|
|
for frame in range(count):
|
|
await process_frame
|
|
|
|
|
|
func expect(condition: bool, message: String) -> void:
|
|
if not condition:
|
|
failures.append("DEV-2 full entry flow: %s" % message)
|