extends SceneTree const FixtureCleanup := preload("res://tests/helpers/ui_audio_fixture_cleanup.gd") var checks:=0 var failures:=0 func expect(ok: bool, message: String) -> void: checks+=1 if not ok: failures+=1;push_error(message) func _initialize() -> void:call_deferred("run") func run() -> void: var runtime: Variant=root.get_node("SimulationRuntime") var clock: Variant=root.get_node("GameClock") var state: Variant=root.get_node("GameState") clock.reset(1,6,0);state.reset();runtime.initialize(clock,state,42510);clock.set_paused(true) root.size=Vector2i(1280,720) var main: Control=load("res://scenes/main/main.tscn").instantiate() var save_path:="user://tests/rank_ui_%d" % Time.get_ticks_usec() main.set("manual_save_path",save_path);root.add_child(main) runtime.configure_save_policy({&"enabled":false,&"daily_checkpoint_enabled":false}) await process_frame;await process_frame var button: Button=main.get("rank_button") var dialog: ConfirmationDialog=main.get("rank_dialog") expect(button.text=="世界樹ランク 1" and button.is_visible_in_tree(),"rank appears in normal HUD") var command_results: Array[CommandResult]=[] runtime.command_completed.connect(func(result: CommandResult) -> void: command_results.append(result)) var original: Dictionary=runtime.create_snapshot() button.pressed.emit() expect(dialog.visible and dialog.get_ok_button().disabled,"unmet rank conditions cannot be confirmed") expect("5000 / 10000" in dialog.dialog_text and "評判" in dialog.dialog_text,"rank conditions show current facts and deficits") expect(runtime.create_snapshot()==original,"viewing live eligibility does not mutate progression or simulation") var front_text := dialog.get_label().get_theme_color("font_color") var front_panel: Color = dialog.theme.get_stylebox("panel", "AcceptDialog").bg_color var conditions := dialog.dialog_text main.call("_set_layer", 1) dialog.refresh() expect(dialog.get_label().get_theme_color("font_color") == Color("d8eeea") and dialog.theme.get_stylebox("panel", "AcceptDialog").bg_color == Color("202e34"), "rank dialog uses readable BACK palette") expect(dialog.get_ok_button().get_theme_color("font_disabled_color") == Color("8da4a4"), "disabled promotion remains legible in BACK") expect(dialog.dialog_text == conditions and dialog.get_ok_button().disabled, "skin change preserves conditions and disabled gate") if OS.get_environment("THE_TREE_RANK_SKIN_CAPTURE") == "1": await process_frame; await RenderingServer.frame_post_draw expect(root.get_texture().get_image().save_png(ProjectSettings.globalize_path("res://artifacts/facility-dimensions-2026-09-29/rank-skin-back.png")) == OK, "capture BACK rank conditions") main.call("_set_layer", 0) expect(dialog.get_label().get_theme_color("font_color") == front_text and dialog.theme.get_stylebox("panel", "AcceptDialog").bg_color == front_panel, "rank dialog restores FRONT palette") expect(runtime.create_snapshot() == original, "round trip skin change preserves complete simulation snapshot") if OS.get_environment("THE_TREE_RANK_CAPTURE")=="1": await process_frame;await RenderingServer.frame_post_draw expect(root.get_texture().get_image().save_png(ProjectSettings.globalize_path("res://artifacts/facility-dimensions-2026-09-29/rank-conditions.png"))==OK,"capture rank HUD and unmet conditions") dialog.hide() # Controlled boundary inputs verify UI wiring, not natural campaign completion. expect(runtime.submit_command(&"update_progression_metrics",{&"metrics":{&"reputation":25}}).is_success(),"fund reputation boundary fixture") expect(runtime.submit_command(&"change_resources",{&"deltas":{&"gold":5000}}).is_success(),"fund current cash boundary through ledger command") button.pressed.emit() expect(not dialog.get_ok_button().disabled and "10000 / 10000" in dialog.dialog_text,"eligibility uses live cash before another tick") var eligible_snapshot: Dictionary=runtime.create_snapshot() # Explicit recovery-failure injection tests the pre-existing operations gate. runtime.operations_coordinator._enter_external_quarantine(&"tick",clock.absolute_minute,&"test_phase",&"TEST_FAILURE") dialog.refresh() expect(dialog.get_ok_button().disabled and "営業状態の復旧" in dialog.dialog_text,"otherwise eligible rank is blocked and explained during operations quarantine") expect(runtime.restore_snapshot(eligible_snapshot),"recover valid pre-fault game") dialog.refresh() runtime.submit_command(&"change_resources",{&"deltas":{&"gold":-1}}) dialog.confirmed.emit();dialog.hide() expect(runtime.progression_service.current_rank==1 and "昇格できません" in main.get("build_status_label").text,"confirmation revalidates changed conditions instead of trusting prior preview") expect(not command_results.is_empty() and command_results.back().details.get(&"reason",&"")==&"REQUIREMENTS_NOT_MET","changed-cash rejection is eligibility failure, not a malformed UI request") runtime.submit_command(&"change_resources",{&"deltas":{&"gold":1}}) button.pressed.emit() clock.set_paused(false) dialog.confirmed.emit();dialog.hide() clock.set_paused(true) expect(runtime.progression_service.current_rank==1 and int(dialog.get("_pending_id"))!=0,"running-game confirmation queues promotion without pretending it already happened") main.call("_save_manual") expect(SaveService.load_snapshot(save_path)[&"ok"],"pending rank request saves before execution") expect(runtime.restore_snapshot(original),"restore control game while promotion is pending") main.call("_load_manual") button.pressed.emit() expect(int(dialog.get("_pending_id"))!=0 and dialog.get_ok_button().disabled,"loaded pending promotion stays visible and cannot be submitted twice") dialog.hide() clock.advance_one_minute() expect(runtime.progression_service.current_rank==2 and state.world_tree_rank==2,"queued UI promotion commits real rank") expect(runtime.world_service.get_bounds()==ProgressionService.RANK_BOUNDS[2],"promotion expands actual construction bounds") expect(button.text=="世界樹ランク 2" and int(dialog.get("_pending_id"))==0,"completed command updates HUD and clears pending UI state") main.call("_save_manual") expect(SaveService.load_snapshot(save_path)[&"ok"],"promoted game saves through normal UI") expect(runtime.restore_snapshot(original),"restore pre-promotion control state") main.call("_refresh_dashboard") expect(button.text=="世界樹ランク 1","HUD follows restored rank") main.call("_load_manual") expect(button.text=="世界樹ランク 2" and runtime.world_service.get_bounds()==ProgressionService.RANK_BOUNDS[2],"normal load restores promoted HUD and map bounds") SaveService.delete_save(save_path) var _audio_cleanup_final: Dictionary = await FixtureCleanup.free_owner_and_wait(self, main) if not bool(_audio_cleanup_final.get(&"passed", false)): push_error("Ordinary fixture audio cleanup failed: %s" % str(_audio_cleanup_final)) quit(96) return await process_frame print("World tree rank UI: %d checks, %d failures" % [checks,failures]);quit(failures)