Files
TheTree_mock/tests/ui/test_business_management.gd
T
Takeshi 5dde0c5ec2 Record original-alignment implementation and traceability checkpoint
Capture current source, content data, tests, asset licenses, and original-specification traceability. Original implementation remains incomplete. The accepted matching UI generation passed 154 suites and 12,253 checks, with eight rendered staff-contract screens reviewed. Latest native Windows and full-original acceptance remain outstanding.
2026-09-30 23:52:24 +09:00

327 lines
18 KiB
GDScript

extends SceneTree
## Real Main controls, paid builds and the Runtime command queue. Dedicated disk
## saves verify that a pending edit cannot be charged/applied twice after Load.
var _checks := 0
var _failures := 0
var _main: Control
var _panel: BusinessManagementPanel
var _runtime: Variant
var _clock: Variant
var _rooms: Array[StringName] = []
var _reception: StringName = &""
var _warehouse: StringName = &""
var _save_path := "user://tests/business_ui_%d/queued_policy" % OS.get_process_id()
func _test_layer_palette() -> void:
_main.call("_set_layer", 0)
var before: Color = _panel.facility_status_label.get_theme_color("font_color")
var selected: bool = _panel.business_open_button.button_pressed
_main.call("_set_layer", 1)
_panel.refresh()
_expect(_panel.facility_status_label.get_theme_color("font_color") == Color("d8eeea"), "BACK panel text survives refresh")
_expect(_panel.business_open_button.get_theme_color("font_hover_color") == Color("d8eeea") and _panel.business_open_button.get_theme_color("font_disabled_color") == Color("8da4a4"), "BACK toggle remains readable for hover and disabled states")
_panel.call("_set_result", "条件未達", false)
_expect(_panel.result_label.get_theme_color("font_color") == Color("ffb498"), "BACK error retains warning colour")
_main.call("_set_layer", 0)
_expect(_panel.facility_status_label.get_theme_color("font_color") == before and _panel.result_label.get_theme_color("font_color") == Color("a7402e"), "FRONT restores panel and warning colours")
_expect(_panel.business_open_button.button_pressed == selected, "palette does not toggle policy")
_panel.call("_set_result", "", true)
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
_clock = root.get_node("GameClock")
_runtime = root.get_node("SimulationRuntime")
var state: Variant = root.get_node("GameState")
_clock.reset(1, 6, 0)
state.reset()
_runtime.initialize(_clock, state, 824260)
_clock.set_paused(true)
root.size = Vector2i(1280, 720)
_main = load("res://scenes/main/main.tscn").instantiate() as Control
_main.set("manual_save_path", "user://tests/business_ui_%d/manual" % OS.get_process_id())
root.add_child(_main)
_runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
await process_frame
await process_frame
_panel = _main.find_child("BusinessManagementPanel", true, false) as BusinessManagementPanel
_expect(_panel != null, "normal Main includes business management")
if _panel == null:
_finish()
return
(_main.get("navigation_buttons")[&"business"] as Button).pressed.emit()
_expect(_panel.visible and _panel.apply_button.disabled and _panel.facility_option.disabled,
"business nav opens a safe empty state before completed construction")
_expect("完成" in _panel.facility_status_label.text, "empty state explains completed facility prerequisite")
_test_layer_palette()
for request: Array in [
[&"reception", Vector3i(-8, 0, 0)],
[&"standard_room", Vector3i(-8, 2, 0)],
[&"standard_room", Vector3i(-6, 2, 0)],
[&"warehouse", Vector3i(-8, 0, 1)],
]:
var before: int = _runtime.construction_service.get_jobs().size()
_main.call("_select_build_definition", request[0])
_main.call("_on_map_cell_clicked", request[1])
_expect(_runtime.construction_service.get_jobs().size() == before + 1, "normal UI pays for construction of %s" % request[0])
if request[0] == &"reception":
_clock.advance_minutes(120)
_clock.advance_minutes(180)
for facility: FacilityInstance in _runtime.facility_service.get_instances():
if facility.definition_id == &"standard_room":
_rooms.append(facility.instance_id)
elif facility.definition_id == &"reception":
_reception = facility.instance_id
elif facility.definition_id == &"warehouse":
_warehouse = facility.instance_id
_expect(_rooms.size() == 2 and not _reception.is_empty() and not _warehouse.is_empty(), "paid builds complete two rooms, free reception and warehouse")
if _rooms.size() != 2 or _reception.is_empty() or _warehouse.is_empty():
_finish()
return
_main.call("_activate_management_mode", &"business")
_panel.refresh()
_test_related_facility_disk_save()
_test_prices_and_drafts()
_test_open_close()
_test_saved_pending_edit()
_test_customer_counts()
await _test_navigation_and_layout()
_finish()
func _test_related_facility_disk_save() -> void:
_clock.set_paused(true)
var linked: CommandResult = _runtime.submit_command(&"set_facility_conditions", {&"facility_id": _rooms[0], &"conditions": {&"related_facility_id": _rooms[1]}})
_expect(linked.is_success(), "built room accepts related facility through Runtime")
var snapshot: Dictionary = _runtime.create_snapshot()
var saved: Dictionary = _runtime.save_to_path(_save_path)
_expect(bool(saved.get(&"ok", false)), "related facility saves to real disk slot")
_runtime.submit_command(&"set_facility_conditions", {&"facility_id": _rooms[0], &"conditions": {&"related_facility_id": &""}})
var loaded: Dictionary = _runtime.load_from_path(_save_path)
_expect(bool(loaded.get(&"ok", false)), "related facility loads through Runtime crosslink validation")
_expect(_runtime.facility_service.get_instance(_rooms[0]).related_facility_id == _rooms[1], "restored room retains the selected dependency")
_expect(_runtime.facility_service.create_snapshot() == snapshot[&"systems"][&"runtime"][&"facilities"], "facility state is exact across disk roundtrip")
_runtime.submit_command(&"set_facility_conditions", {&"facility_id": _rooms[0], &"conditions": {&"related_facility_id": &""}})
func _test_prices_and_drafts() -> void:
_choose(_panel.facility_option, _rooms[0])
_expect(_panel.price_option.item_count == 5 and not _panel.price_option.disabled, "five price modes are available for paid guest rooms")
var row := _row(_rooms[0])
_expect(int(row.get(&"base_price", 0)) == 120 and "120G" in _panel.quote_label.text,
"initial room shows actual 120 G base and current quotation")
var digest: String = _runtime.latest_digest
var cash: int = _runtime.economy_service.get_balance(&"PLAYER_CASH")
for pair: Array in [[&"charitable", 72], [&"affordable", 96], [&"standard", 120], [&"expensive", 180], [&"exorbitant", 300]]:
_choose(_panel.price_option, pair[0])
_expect("設定後 %dG" % pair[1] in _panel.quote_label.text, "%s mode previews authoritative rounded price" % pair[0])
_expect(_runtime.latest_digest == digest and _runtime.economy_service.get_balance(&"PLAYER_CASH") == cash,
"changing drafts and displaying quotes never mutates Runtime or spends cash")
_expect("満足度" in _panel.effect_label.text and "支払えない" in _panel.effect_label.text,
"highest price explains satisfaction and affordability instead of an invented demand forecast")
_choose(_panel.price_option, &"affordable")
_main.call("_activate_management_mode", &"product")
_clock.advance_minutes(1)
_main.call("_activate_management_mode", &"business")
_expect(_selected_mode() == &"affordable" and not _panel.apply_button.disabled,
"unsaved price draft survives time updates and other management panels")
_choose(_panel.facility_option, _rooms[1])
_choose(_panel.price_option, &"expensive")
_choose(_panel.facility_option, _rooms[0])
_expect(_selected_mode() == &"affordable", "separate facilities keep separate price drafts")
_clock.set_paused(false)
_panel.apply_button.pressed.emit()
_expect(_panel.apply_button.disabled and _panel.price_option.disabled and _panel.business_open_button.disabled,
"queued policy disables edits and duplicate submissions for that facility")
_choose(_panel.facility_option, _rooms[1])
_clock.advance_minutes(1)
_clock.set_paused(true)
_expect(_selected_mode() == &"expensive" and _panel.selected_facility_id == _rooms[1],
"completion on one facility preserves the selected other facility draft")
_expect(StringName(_row(_rooms[0]).get(&"price_mode", &"")) == &"affordable" and int(_row(_rooms[0]).get(&"price", 0)) == 96,
"accepted price reaches facility policy and Runtime report")
_panel.apply_button.pressed.emit()
_expect(int(_row(_rooms[1]).get(&"price", 0)) == 180 and "反映" in _panel.result_label.text,
"paused submission applies another facility's own draft with Japanese confirmation")
_expect(_panel.apply_button.disabled, "applied unchanged draft cannot be submitted again")
func _test_open_close() -> void:
_panel.business_open_button.button_pressed = false
_expect(not _panel.apply_button.disabled, "closing admission is an explicit unsaved draft")
_panel.apply_button.pressed.emit()
_expect(not bool(_row(_rooms[1]).get(&"business_open", true)) and "停止" in _panel.facility_status_label.text,
"close reaches actual facility operator state and status text")
_expect("受付済みの料金は変わりません" in _panel.explanation_label.text
and "開始済みのサービス" in _panel.explanation_label.text
and "休業中も給与と施設維持費は発生" in _panel.explanation_label.text,
"UI explains fixed accepted prices, service completion, and continued wages plus upkeep during closure")
_panel.business_open_button.button_pressed = true
_panel.apply_button.pressed.emit()
_expect(bool(_row(_rooms[1]).get(&"business_open", false)), "admission can be reopened through the same controls")
_choose(_panel.facility_option, _reception)
_expect(_panel.price_option.disabled and "利用料金はありません" in _panel.quote_label.text,
"free reception has no editable price")
_panel.business_open_button.button_pressed = false
_panel.apply_button.pressed.emit()
_expect(not bool(_row(_reception).get(&"business_open", true)), "free facility still supports admission control")
_panel.business_open_button.button_pressed = true
_panel.apply_button.pressed.emit()
_expect(bool(_row(_reception).get(&"business_open", false)), "free reception can reopen without sending a price patch")
_choose(_panel.facility_option, _warehouse)
_expect(_panel.price_option.disabled and _panel.business_open_button.text == "営業する"
and "調理と新しい補給" in _panel.explanation_label.text and "荷物は保持" in _panel.explanation_label.text,
"backroom warehouse explains supply pause and retained cargo instead of guest admission")
_panel.business_open_button.button_pressed = false
_panel.apply_button.pressed.emit()
_expect(not bool(_row(_warehouse).get(&"business_open", true)), "warehouse closing updates the real operator policy")
_panel.business_open_button.button_pressed = true
_panel.apply_button.pressed.emit()
_expect(bool(_row(_warehouse).get(&"business_open", false)), "warehouse can reopen through the same business panel")
func _test_saved_pending_edit() -> void:
_choose(_panel.facility_option, _rooms[0])
_choose(_panel.price_option, &"charitable")
_clock.set_paused(false)
_panel.apply_button.pressed.emit()
var pending_before: int = _runtime.command_queue.create_snapshot().get("pending", []).size()
_panel.submit_policy()
_expect(pending_before == 1 and _runtime.command_queue.create_snapshot().get("pending", []).size() == 1,
"a second press cannot enqueue duplicate policy edits")
var saved: Dictionary = _runtime.save_to_path(_save_path)
_expect(bool(saved.get(&"ok", false)), "pending price policy saves to an isolated disk slot")
_clock.advance_minutes(1)
var loaded: Dictionary = _runtime.load_from_path(_save_path)
_expect(bool(loaded.get(&"ok", false)), "pending policy restores from disk")
_panel.refresh()
_expect(_panel.apply_button.disabled and _selected_mode() == &"charitable" and "設定後 72G" in _panel.quote_label.text,
"restored pending edit remains locked and displays its accepted draft, not stale live policy")
_clock.advance_minutes(1)
_clock.set_paused(true)
_panel.refresh()
_expect(int(_row(_rooms[0]).get(&"price", 0)) == 72 and not _panel.price_option.disabled,
"restored policy executes once and unlocks editing")
_choose(_panel.price_option, &"standard")
_panel.apply_button.pressed.emit()
_expect(int(_row(_rooms[0]).get(&"price", 0)) == 120,
"restored command key sequence permits a genuinely new policy edit")
var report := _panel.get_report()
(report[&"facilities"] as Array).clear()
_panel.refresh()
_expect(not (_panel.get_report().get(&"facilities", []) as Array).is_empty(), "read model returned to callers is defensive")
func _test_navigation_and_layout() -> void:
for entry: Array in [[&"ledger", "operating_ledger_panel"], [&"product", "supply_management_panel"], [&"staff", "staff_management_panel"]]:
_main.call("_activate_management_mode", entry[0])
_expect(not _panel.visible and (_main.get(entry[1]) as Control).visible, "%s exclusively replaces business controls" % entry[0])
_main.call("_activate_management_mode", &"business")
_expect(_panel.visible and not (_main.get(entry[1]) as Control).visible, "business exclusively replaces %s controls" % entry[0])
_main.call("_unhandled_key_input", _key(KEY_H))
_expect(not _panel.visible and (_main.get("staff_candidate_panel") as Control).visible, "H replaces business with hiring candidates")
_main.call("_activate_management_mode", &"business")
_choose(_panel.facility_option, _rooms[1])
_main.call("_set_layer", 0)
await process_frame
await process_frame
var side := _main.find_child("SidePanel", true, false) as Control
var guide := _main.find_child("InnOpeningGuide", true, false) as Control
_expect(not side.get_global_rect().intersects(guide.get_global_rect()), "1280x720 business inspector stays clear of opening guidance")
for control: Control in [_panel, _panel.facility_option, _panel.price_option, _panel.business_open_button, _panel.apply_button]:
_expect(control.get_global_rect().position.x >= side.get_global_rect().position.x
and control.get_global_rect().end.x <= side.get_global_rect().end.x, "%s fits inside narrow sidebar" % control.name)
if OS.get_environment("THE_TREE_BUSINESS_UI_CAPTURE") == "1":
var requested_capture := OS.get_environment("THE_TREE_BUSINESS_CAPTURE_DIR")
var capture_dir := ProjectSettings.globalize_path(requested_capture if not requested_capture.is_empty() else "res://artifacts/business-management")
DirAccess.make_dir_recursive_absolute(capture_dir)
await RenderingServer.frame_post_draw
root.get_texture().get_image().save_png(capture_dir.path_join("business-panel.png"))
_choose(_panel.facility_option, _warehouse)
_main.call("_set_layer", 1)
await process_frame
await RenderingServer.frame_post_draw
root.get_texture().get_image().save_png(capture_dir.path_join("warehouse-policy.png"))
if OS.get_environment("THE_TREE_PANEL_SKIN_CAPTURE") == "1":
_main.call("_set_layer", 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/business-skin-back.png")) == OK, "capture BACK management skin")
_main.call("_unhandled_key_input", _key(KEY_ESCAPE))
_expect(not _panel.visible and not bool(_main.get("_management_panel_open")), "Escape closes business inspector and restores full map")
func _row(id: StringName) -> Dictionary:
for row: Dictionary in _runtime.get_business_management_report().get(&"facilities", []):
if StringName(row.get(&"facility_id", &"")) == id:
return row
return {}
func _selected_mode() -> StringName:
return StringName(_panel.price_option.get_item_metadata(_panel.price_option.selected))
func _choose(picker: OptionButton, id: StringName) -> void:
for index: int in picker.item_count:
if StringName(picker.get_item_metadata(index)) == id:
picker.select(index)
picker.item_selected.emit(index)
return
_expect(false, "requested business dropdown value exists: %s" % id)
func _key(code: Key) -> InputEventKey:
var event := InputEventKey.new()
event.keycode = code
event.pressed = true
return event
func _expect(condition: bool, message: String) -> void:
_checks += 1
if not condition:
_failures += 1
push_error(message)
func _finish() -> void:
SaveService.delete_save(_save_path)
if is_instance_valid(_main):
_main.queue_free()
print("Business management UI: %d checks, %d failures" % [_checks, _failures])
quit(1 if _failures > 0 else 0)
func _test_customer_counts() -> void:
# Controlled multi-person read-model fixture; no simulated time advances.
var saved: Dictionary = _runtime.facility_service.create_snapshot()
var room: FacilityInstance = _runtime.facility_service.get_instance(_rooms[1])
room.active_services.clear()
room.customer_capacity = 3
var group := ServiceInstance.new().configure(&"group", &"group_request", room.instance_id, _clock.absolute_minute, 60, [&"group_a", &"group_b"], [])
room.active_services[&"group"] = group
var request := ServiceRequest.new().configure(&"waiting_group", room.instance_id, [&"waiting_a", &"waiting_b", &"waiting_c"], &"default", _clock.absolute_minute)
_expect(_runtime.facility_service.enqueue_request(request).is_success(), "queue a three-person request for the occupancy read model")
var row := _row(room.instance_id)
_expect(row[&"active_count"] == 1 and row[&"active_customer_count"] == 2, "one grouped service reports two users separately from service count")
_expect(row[&"queued_count"] == 1 and row[&"queued_customer_count"] == 3, "one queued request reports three waiting people")
_panel.refresh()
_choose(_panel.facility_option, room.instance_id)
_expect("待ち 3人 / 利用中 2人" in _panel.facility_status_label.text and "上限 3人" in _panel.facility_status_label.text, "business screen shows people and explicit capacity")
room.customer_capacity = -1
_panel.refresh()
_expect("上限 未設定" in _panel.facility_status_label.text, "unset customer limit is never replaced by generic capacity")
room.active_services.clear()
room.customer_capacity = 0
_panel.refresh()
_expect("利用中 0人" in _panel.facility_status_label.text and "上限 0人" in _panel.facility_status_label.text, "zero limit remains distinct from an unspecified limit")
_expect(_runtime.facility_service.restore_snapshot(saved), "discard controlled occupancy fixture without changing later gameplay tests")
_panel.refresh()