Files
TheTree_mock/tests/ui/test_selection_departure.gd
T

108 lines
7.7 KiB
GDScript

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)