extends SceneTree var _checks := 0 var _failures := 0 var _runtime: Variant var _clock: Variant var _state: Variant var _ids: Dictionary = {} var _serial := 0 func _initialize() -> void: call_deferred("_run") func _run() -> void: _clock = load("res://autoload/game_clock.gd").new() _state = load("res://autoload/game_state.gd").new() _runtime = load("res://autoload/simulation_runtime.gd").new() _clock.reset(1, 6, 0) _state.reset() _expect(_runtime.initialize(_clock, _state, 4405).get(&"valid", false), "runtime initializes") _clock.set_paused(true) for row: Array in [[&"reception", Vector3i(-8, 0, 0)], [&"cafeteria", Vector3i(2, 0, 0)]]: _expect(_cmd(&"build_facility", {&"definition_id": row[0], &"origin": row[1]}).is_success(), "build %s" % row[0]) _clock.advance_minutes(180) _expect(_cmd(&"build_facility", {&"definition_id": &"standard_room", &"origin": Vector3i(-8, 2, 0)}).is_success(), "room builds on completed reception") _clock.advance_minutes(60) for facility: FacilityInstance in _runtime.facility_service.get_instances(): _ids[facility.definition_id] = facility.instance_id _expect(_ids.size() == 3, "three real construction jobs complete") if _ids.size() < 3: _finish() return _catalog_and_report() var kitchen_setup: Dictionary = load("res://tests/fixtures/required_kitchen_setup.gd").ensure(_runtime, _clock, _ids[&"cafeteria"], false) _expect(bool(kitchen_setup.get(&"ok", false)), "public paid kitchen setup/link for controlled logical-attendance business fixture") _immutable_sale() _closed_queue() _save_and_candidates() _finish() func _catalog_and_report() -> void: var report: Dictionary = _runtime.get_business_management_report() _expect(report[&"modes"].size() == 5 and report[&"facilities"].size() == 3, "five price tiers and completed facilities are exposed") for row: Dictionary in report[&"facilities"]: if row[&"facility_id"] == _ids[&"reception"]: _expect(row[&"price"] == 0 and not row[&"can_price"], "reception has no direct charge") elif row[&"facility_id"] == _ids[&"standard_room"]: _expect(row[&"base_price"] == 120, "new room uses documented 120 G rate") else: _expect(row[&"base_price"] == 25, "new cafeteria uses documented 25 G rate") var before: Dictionary = _runtime.create_snapshot() report[&"facilities"][0][&"price"] = 99999 _expect(_runtime.create_snapshot() == before, "read model is detached from authority") var reception: FacilityInstance = _runtime.facility_service.get_instance(_ids[&"reception"]) reception.base_price = 20 # A legacy v7 facility keeps its stored fields. _expect(_cmd(&"register_guest_wallet", {&"guest_id": &"checkin", &"gold": 50}).is_success(), "wallet for reception regression") _expect(_cmd(&"create_service_request", {&"facility_id": reception.instance_id, &"request_id": &"free_checkin", &"guest_ids": [&"checkin"]}).is_success(), "legacy reception accepts new check-in") _expect(_runtime.facility_service.get_request(&"free_checkin").quoted_price == 0, "new quotes at legacy reception are free") func _immutable_sale() -> void: var cafe: FacilityInstance = _runtime.facility_service.get_instance(_ids[&"cafeteria"]) _expect(_cmd(&"set_facility_conditions", {&"facility_id": cafe.instance_id, &"conditions": {&"active_staff_ids": [&"cook", &"server"]}}).is_success(), "staff facility for settlement test") _expect(_cmd(&"add_inventory_stack", {&"owner_inventory_id": cafe.local_inventory_id, &"item_id": SupplyCatalog.BASIC_MEAL, &"quantity": 3}).is_success(), "provide finite meal fixture") _expect(_cmd(&"register_guest_wallet", {&"guest_id": &"payer", &"gold": 200}).is_success(), "payer wallet") _expect(_policy(cafe.instance_id, {&"price_mode": &"expensive"}).is_success(), "set expensive tier") _expect(_cmd(&"create_service_request", {&"facility_id": cafe.instance_id, &"request_id": &"meal.expensive", &"guest_ids": [&"payer"], &"options": {&"service_minutes": 3}}).is_success(), "quote an expensive meal") _expect(_runtime.facility_service.get_request(&"meal.expensive").quoted_price == 38, "25 G at 150% rounds half up to 38 G") _expect(_policy(cafe.instance_id, {&"price_mode": &"charitable"}).is_success(), "price changes before service starts") _clock.advance_minutes(1) var active: Array = _runtime.facility_service.get_active_services(cafe.instance_id) _expect(active.size() == 1 and active[0].price_snapshot == 38, "queue retains old quote and policy") var checkpoint: Dictionary = _runtime.create_snapshot() var cash: int = _state.get_resource(&"gold") _expect(_policy(cafe.instance_id, {&"business_open": false}).is_success(), "operator closes during meal") var inventory: Dictionary = _runtime.inventory_service.create_snapshot() _expect(not _cmd(&"create_service_request", {&"facility_id": cafe.instance_id, &"guest_ids": [&"payer"]}).is_success(), "closed business rejects new reservations") _expect(_runtime.inventory_service.create_snapshot() == inventory, "rejected closed request consumes no stock") _clock.advance_minutes(3) _expect(_state.get_resource(&"gold") == cash + 38 and _runtime.economy_service.get_balance(&"GUEST_WALLET:payer") == 162, "closing still finishes and charges existing quote once") _expect(_runtime.facility_service.get_active_services(cafe.instance_id).is_empty(), "closed facility finishes its existing service") _expect(_runtime.restore_snapshot(checkpoint), "active quote and policy restore together") _expect(_policy(cafe.instance_id, {&"business_open": false}).is_success(), "replay closure") _clock.advance_minutes(3) _expect(_runtime.economy_service.get_balance(&"GUEST_WALLET:payer") == 162, "restored meal also settles once") _expect(_runtime.economy_service.validate_ledger().get(&"ok", false), "settlement ledger reconciles") var report: Dictionary = _runtime.get_business_management_report() for row: Dictionary in report[&"facilities"]: if row[&"facility_id"] == cafe.instance_id: _expect(row[&"today_revenue"] == 38 and row[&"price"] == 15 and not row[&"business_open"], "report shows actual sale, future price, and closure separately") func _closed_queue() -> void: var cafe: FacilityInstance = _runtime.facility_service.get_instance(_ids[&"cafeteria"]) _expect(_policy(cafe.instance_id, {&"business_open": true}).is_success(), "reopen") _expect(_cmd(&"spawn_guest", {&"guest_id": &"queue_guest", &"guest_type_id": &"traveler", &"gold": 200, &"options": {&"current_cell": Vector3i.ZERO, &"planned_exit_at": _clock.absolute_minute + 240}}).is_success(), "spawn real guest actor") var guest: GuestRuntime = _runtime.guest_service.get_guest(&"queue_guest") _runtime.guest_service.transition_guest(guest.guest_id, GuestRuntime.State.ENTERING, _clock.absolute_minute) _runtime.guest_service.transition_guest(guest.guest_id, GuestRuntime.State.DECIDING, _clock.absolute_minute) _expect(_cmd(&"create_service_request", {&"facility_id": cafe.instance_id, &"request_id": &"closing.queue", &"guest_ids": [guest.guest_id]}).is_success(), "guest owns queued meal reservation") var patience: int = guest.patience_remaining var available: int = _runtime.inventory_service.available_quantity(cafe.local_inventory_id, SupplyCatalog.BASIC_MEAL) _expect(_policy(cafe.instance_id, {&"business_open": false}).is_success(), "close queued facility") # Same-tick transition budget may already be exhausted; the release retries. _runtime.call("_release_closed_business_queues", _clock.absolute_minute + 1) guest = _runtime.guest_service.get_guest(&"queue_guest") _expect(guest.queue_request_id.is_empty() and guest.state == GuestRuntime.State.DECIDING, "closure releases guest for a fresh decision") _expect(guest.patience_remaining == patience, "closing does not fake a patience failure") _expect(_runtime.facility_service.get_queue(cafe.instance_id).is_empty() and _runtime.inventory_service.available_quantity(cafe.local_inventory_id, SupplyCatalog.BASIC_MEAL) == available + 1, "queue and reserved stock release together") # Align every service clock before save validation. _clock.advance_minutes(1) func _save_and_candidates() -> void: var cafe: FacilityInstance = _runtime.facility_service.get_instance(_ids[&"cafeteria"]) _expect(_policy(cafe.instance_id, {&"business_open": true, &"price_mode": &"standard"}).is_success(), "reopen at standard rate") var guest: GuestRuntime = _runtime.guest_service.get_guest(&"queue_guest") if guest != null: var low_candidates: Array = _runtime.call("_project_guest_candidates", guest.guest_id) var low: Dictionary = {} for row: Dictionary in low_candidates: if row[&"facility_id"] == cafe.instance_id: low = row _policy(cafe.instance_id, {&"price_mode": &"exorbitant"}) var high: Dictionary = {} for row: Dictionary in _runtime.call("_project_guest_candidates", guest.guest_id): if row[&"facility_id"] == cafe.instance_id: high = row _expect(not low.is_empty() and not high.is_empty() and low[&"estimated_total_gold"] == 25 and high[&"estimated_total_gold"] == 63, "guest candidate quotes track visible price tier") if not low.is_empty() and not high.is_empty(): _expect(_runtime.guest_service.evaluate_candidate(guest.guest_id, low)[&"utility"] > _runtime.guest_service.evaluate_candidate(guest.guest_id, high)[&"utility"], "higher price lowers same guest's utility") var service := ServiceInstance.new() service.quality_snapshot = 55 service.policy_snapshot = {&"price_mode": &"charitable"} var satisfied: int = _runtime.call("_service_satisfaction_sample", service, guest) service.policy_snapshot = {&"price_mode": &"exorbitant"} _expect(satisfied > int(_runtime.call("_service_satisfaction_sample", service, guest)), "price policy affects satisfaction sample") var save_path := "user://tests/business_%d/policy" % OS.get_process_id() _expect(_runtime.save_to_path(save_path).get(&"ok", false), "business policies save to an isolated disk slot") var price_before: int = _runtime.get_business_management_report()[&"facilities"].size() _expect(_runtime.load_from_path(save_path).get(&"ok", false), "business policies and guest ownership load") _expect(_runtime.get_business_management_report()[&"facilities"].size() == price_before, "facility reports remain available after load") cafe = _runtime.facility_service.get_instance(_ids[&"cafeteria"]) _expect(cafe.operator_open and cafe.policy_current[&"price_mode"] == &"exorbitant", "disk restore preserves open state and price mode") var before: Dictionary = _runtime.facility_service.create_snapshot() _expect(not _policy(cafe.instance_id, {&"price_mode": &"unknown", &"business_open": false}).is_success(), "invalid tier rejects entire combined policy") _expect(_runtime.facility_service.create_snapshot() == before, "invalid patch cannot partially close business") func _policy(id: StringName, patch: Dictionary) -> CommandResult: return _cmd(&"set_facility_policy", {&"facility_id": id, &"patch": patch}) func _cmd(type: StringName, payload: Dictionary) -> CommandResult: _serial += 1 return _runtime.submit_command(type, payload, &"player", &"", 75, -1, StringName("business.test.%d" % _serial)) func _expect(ok: bool, message: String) -> void: _checks += 1 if not ok: _failures += 1 push_error(message) func _finish() -> void: print("Business operations: %d checks, %d failures" % [_checks, _failures]) _runtime.free() _clock.free() _state.free() quit(1 if _failures else 0)