extends SceneTree const FixtureCleanup := preload("res://tests/helpers/ui_audio_fixture_cleanup.gd") var _checks := 0 var _failures := 0 func _initialize() -> void: call_deferred("_run") func _expect(ok: bool, message: String) -> void: _checks += 1 if not ok: _failures += 1 push_error(message) 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, 42533) clock.set_paused(true) root.size = Vector2i(1440, 810) var main: Control = load("res://scenes/main/main.tscn").instantiate() root.add_child(main) runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false}) await process_frame await process_frame # Build before intentionally preserving departed payroll debt. var build_result: Variant = runtime.submit_command(&"build_facility", {&"definition_id": &"reception", &"origin": Vector3i(-8, 0, 0)}) _expect(build_result.is_success(), "real facility construction starts: " + str(build_result.to_dictionary())) clock.advance_minutes(120) var facilities: Array = runtime.construction_service.get_facilities() _expect(not facilities.is_empty(), "real facility construction completes") if not facilities.is_empty(): var facility_id := StringName(facilities[0][&"instance_id"]) main.call("_on_facility_selected", facility_id) main.get("world_preview").set("selected_entity_id", facility_id) var previous_detail: String = main.get("selected_detail_label").text _expect(main.get("_selected_entity_id") == facility_id, "select existing built facility") _expect(runtime.submit_command(&"demolish_facility", {&"instance_id": facility_id}).is_success(), "real facility demolition commits") main.call("_refresh_selected_entity") _expect(main.get("_selected_entity_id") == &"" and main.get("_selected_entity_kind") == &"" and main.get("world_preview").get("selected_entity_id") == &"", "actual demolition clears ID kind and map highlight") _expect(main.get("selected_entity_icon").texture == null and main.get("selected_detail_label").text != previous_detail, "actual demolition clears icon and stale detail") var guest: GuestObservationPanel = main.call("_ensure_guest_observer") var definition: GuestDefinition = runtime.guest_service.get_definitions()[0] _expect(runtime.submit_command(&"spawn_guest", {&"guest_id": &"departure_guest", &"guest_type_id": definition.guest_type_id, &"gold": 731, &"options": {&"planned_exit_at": clock.absolute_minute + 1000}}).is_success(), "spawn actual guest") guest.selected_guest_id = &"departure_guest" guest.refresh() _expect("731G" in guest.details.text, "selected guest displays authoritative wallet") _expect(runtime.guest_service.begin_leaving(&"departure_guest", clock.absolute_minute + 1, &"TEST_EXIT").get(&"ok", false), "actual leaving transition") guest.refresh() _expect(guest.selected_guest_id == &"departure_guest" and "退館中" in guest.details.text, "leaving guest remains present and displays current state") _expect(runtime.guest_service.despawn_guest(&"departure_guest", clock.absolute_minute + 2).get(&"ok", false), "actual guest despawn") guest.refresh() _expect(not runtime.guest_service.has_guest(&"departure_guest") and not runtime.guest_service.get_persistent_record(&"departure_guest").is_empty(), "history survives without a currently selectable guest") _expect(guest.selected_guest_id != &"departure_guest" and not guest.get("_ids").has(&"departure_guest"), "departed ID is absent while live roster fallback remains valid") if not guest.selected_guest_id.is_empty(): var live_report: Dictionary = runtime.guest_service.get_observation(guest.selected_guest_id) _expect(not live_report.is_empty() and ("%dG" % int(live_report[&"wallet_gold"])) in guest.details.text, "fallback displays the live guest wallet") # Create an empty-roster boundary through real departures, never array erasure. for live: GuestRuntime in runtime.guest_service.get_guests(): _expect(runtime.guest_service.begin_leaving(live.guest_id, clock.absolute_minute + 3, &"TEST_EXIT").get(&"ok", false), "empty-roster fixture begins departure") _expect(runtime.guest_service.despawn_guest(live.guest_id, clock.absolute_minute + 4).get(&"ok", false), "empty-roster fixture completes departure") guest.refresh() _expect(guest.selected_guest_id.is_empty() and guest.guests.selected == -1 and guest.guests.disabled, "empty roster has no current selection or dropdown target") _expect(guest.priority_label.text.is_empty() and guest.decision_label.text.is_empty(), "departed guest leaves no stale current detail values") for need: StringName in guest.bars: _expect(guest.bars[need].value == 0, "departed guest clears current need " + String(need)) var staff: StaffManagementPanel = main.get("staff_management_panel") _expect(runtime.staff_service.create_staff(&"departure_staff", &"cleaner", {&"unpaid_wages": 43}).is_success(), "register ordinary departure employee") staff.select_staff(&"departure_staff") _expect(staff.selected_staff_id == &"departure_staff", "select ordinary employee") _expect(runtime.staff_service.remove_staff(&"departure_staff").is_success(), "permitted ordinary employee removal") staff.refresh() _expect(not runtime.staff_service.has_staff(&"departure_staff") and not staff.roster_buttons.has(&"departure_staff") and staff.selected_staff_id != &"departure_staff", "removed employee no longer selectable") _expect(runtime.staff_service.get_departed_unpaid_wages(&"departure_staff") == 43, "departure preserves payroll history") _expect(runtime.staff_service.create_staff(&"departure_unique", &"cleaner", {&"employment_kind": StaffRuntime.EmploymentKind.UNIQUE}).is_success(), "register protected Unique fixture") staff.select_staff(&"departure_unique") _expect(not runtime.staff_service.remove_staff(&"departure_unique").is_success(), "Unique removal remains forbidden") staff.refresh() _expect(runtime.staff_service.has_staff(&"departure_unique") and staff.selected_staff_id == &"departure_unique", "rejected removal preserves Unique selection") main.call("_set_layer", 1) var before: Dictionary = runtime.create_snapshot() var selection: Dictionary = main.call("_capture_interface_selection") _expect(SimulationDigest.compute(before) == SimulationDigest.compute(runtime.create_snapshot()), "UI metadata capture leaves whole Runtime unchanged") _expect(state.create_snapshot().get(&"active_layer") == 1 and selection.get(&"staff_id") == "departure_unique", "formal layer and selected ID have authoritative sources") guest.clear_selection() _expect(guest.guests.selected == -1, "clear observer has no invalid option index") for version: Variant in [true, 1.5, "1", 0, 2]: main.call("_restore_actor_interface_selection", {"interface_selection": {"version": version, "staff_id": "departure_unique", "staff_open": true}}) _expect(staff.selected_staff_id.is_empty() and not staff.visible, "wrong/old metadata version is ignored: " + str(version)) var original: String = OS.get_environment("THE_TREE_AUDIO_FIXTURE_CONTROL_PROOF") if original.is_empty() or not original.is_absolute_path(): _expect(false, "Runner must provide fresh absolute ordinary control proof") else: var control := original if FileAccess.file_exists(control): _expect(false, "ordinary cleanup proof overwrite forbidden") else: OS.set_environment("THE_TREE_AUDIO_FIXTURE_CONTROL_PROOF", control) var cleanup: Dictionary = await FixtureCleanup.free_owner_and_wait(self, main) OS.set_environment("THE_TREE_AUDIO_FIXTURE_CONTROL_PROOF", original) _expect(bool(cleanup.get(&"passed", false)), "ordinary Main/audio cleanup") print("Selection departure: %d checks, %d failures" % [_checks, _failures]) quit(1 if _failures else 0)