Files
aetherbound-guild/runtime/tests/foundation/runtime_foundation_test.gd
T

87 lines
3.8 KiB
GDScript

extends SceneTree
const AppServices = preload("res://foundation/app_services.gd")
const ScreenContext = preload("res://foundation/screen_context.gd")
const ScreenStack = preload("res://foundation/screen_stack.gd")
const Tokens = preload("res://foundation/ui_tokens.gd")
const SharedButton = preload("res://ui/shared/shared_button.gd")
var failures: Array[String] = []
func _initialize() -> void:
call_deferred("run_test")
func run_test() -> void:
verify_context_round_trip()
verify_screen_stack()
verify_service_bundle()
await verify_shared_ui_contract()
if failures.is_empty():
print("ABG_M15_FOUNDATION_OK context=true stack=true services=true ui_tokens=true shared_button=true")
quit(0)
else:
for failure in failures:
push_error(failure)
quit(1)
func verify_context_round_trip() -> void:
var context := ScreenContext.new({
"screen_id": "settings",
"caller_id": "battle_pause_controls",
"return_screen_id": "battle",
"return_focus_path": "BattleLive/Settings",
"presentation_mode": "overlay",
"metadata": {"locale": "zh_CN", "operation_id": "op-1"},
})
expect(context.is_overlay(), "overlay context reports its presentation mode")
var restored := ScreenContext.new(context.to_dictionary())
expect(restored.screen_id == "settings" and restored.return_screen_id == "battle", "context preserves route identity")
expect(restored.return_focus_path == "BattleLive/Settings" and restored.metadata.locale == "zh_CN", "context preserves focus and metadata")
func verify_screen_stack() -> void:
var stack = ScreenStack.new()
stack.push(ScreenContext.new({"screen_id": "title"}))
stack.push(ScreenContext.new({"screen_id": "settings", "caller_id": "title"}))
expect(stack.depth() == 2 and stack.contains("settings"), "stack pushes independent screen contexts")
var current = stack.current()
expect(current != null and current.screen_id == "settings", "stack returns the top context")
stack.replace(ScreenContext.new({"screen_id": "credits", "caller_id": "settings"}))
expect(stack.depth() == 2 and stack.current().screen_id == "credits", "stack replaces only the top context")
var popped = stack.pop()
expect(popped != null and popped.screen_id == "credits" and stack.current().screen_id == "title", "stack pops to the previous route")
stack.clear()
expect(stack.depth() == 0 and stack.current() == null, "stack clears without leaving stale context")
func verify_service_bundle() -> void:
var sentinel := RefCounted.new()
var services := AppServices.new({"settings": sentinel})
expect(services.has_service(&"settings") and services.resolve_service(&"settings") == sentinel, "service bundle registers explicit dependencies")
services.register_service(&"audio", sentinel)
expect(services.has_service(&"audio") and services.service_snapshot().screen_stack, "service bundle exposes screen stack and services")
services.register_service(&"audio", null)
expect(not services.has_service(&"audio"), "service bundle removes a cleared dependency")
func verify_shared_ui_contract() -> void:
expect(Tokens.touch_size(Vector2(10, 60)) == Vector2(48, 60), "shared touch token enforces the minimum target")
expect(Tokens.font_size("body", 1.0) == 16 and Tokens.font_size("body", 1.3) >= 20, "shared typography token scales predictably")
var button := SharedButton.new()
button.configure("Apply", "primary")
button.set_view_state(true, true, false)
root.add_child(button)
await process_frame
expect(button.semantic_variant == "primary" and button.selected_state and not button.disabled, "shared button exposes semantic view state")
expect(button.custom_minimum_size.x >= 48.0 and button.custom_minimum_size.y >= 48.0, "shared button keeps the touch target")
button.queue_free()
await process_frame
func expect(condition: bool, message: String) -> void:
if not condition:
failures.append("M15 Foundation: %s" % message)