Initial project sync
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
extends SceneTree
|
||||
|
||||
var failures: Array[String] = []
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
_run.call_deferred()
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
var ui_scene: PackedScene = load("res://scenes/ui/main_ui.tscn")
|
||||
var player_scene: PackedScene = load("res://scenes/characters/player.tscn")
|
||||
if ui_scene == null or player_scene == null:
|
||||
failures.append("Debug UI test scenes should load")
|
||||
_finish()
|
||||
return
|
||||
|
||||
var ui := ui_scene.instantiate()
|
||||
var player := player_scene.instantiate()
|
||||
root.add_child(player)
|
||||
root.add_child(ui)
|
||||
await process_frame
|
||||
|
||||
for node_path: String in [
|
||||
"DebugPanel",
|
||||
"DebugPanel/StateAxesLabel",
|
||||
"DebugPanel/ActionLabel",
|
||||
"DebugPanel/AnchorLabel",
|
||||
"DebugPanel/EffectsLabel",
|
||||
"DebugPanel/DefenseLabel",
|
||||
"DebugPanel/PatternsLabel",
|
||||
"DebugPanel/HitLogLabel",
|
||||
"DebugPanel/CalibrationLabel",
|
||||
]:
|
||||
_expect(ui.has_node(node_path), "MainUI should expose %s" % node_path)
|
||||
|
||||
if ui.has_method("bind_debug_actor"):
|
||||
ui.call("bind_debug_actor", player)
|
||||
else:
|
||||
failures.append("MainUI should expose bind_debug_actor(actor)")
|
||||
|
||||
var state_machine: Node = player.get_node("StateMachine")
|
||||
state_machine.call("set_ground_state", &"Airborne")
|
||||
state_machine.call("set_action_phase", &"Startup")
|
||||
state_machine.call("set_life_state", &"Hitstun")
|
||||
state_machine.call("set_defense_state", &"Parrying")
|
||||
|
||||
var action_controller: Node = player.get_node("ActionController")
|
||||
action_controller.set("current_action", load("res://resources/actions/ground_attack_left_1.tres"))
|
||||
action_controller.set("startup_stretch_seconds", 0.125)
|
||||
|
||||
var effect_container: Node = player.get_node("EffectContainer")
|
||||
if _method_arg_count(effect_container, "add_effect") >= 2:
|
||||
effect_container.call("add_effect", load("res://resources/effects/effect_root.tres"), &"debug_test")
|
||||
effect_container.call("add_effect", load("res://resources/effects/effect_temporary_invincible.tres"), &"debug_defense")
|
||||
else:
|
||||
failures.append("EffectContainer.add_effect should accept a source argument for debug UI")
|
||||
effect_container.call("add_effect", load("res://resources/effects/effect_root.tres"))
|
||||
|
||||
if ui.has_method("refresh_debug_panel"):
|
||||
ui.call("refresh_debug_panel")
|
||||
else:
|
||||
failures.append("MainUI should expose refresh_debug_panel()")
|
||||
|
||||
_expect_label_contains(ui, "DebugPanel/StateAxesLabel", "Airborne", "Debug state axes should include GroundState")
|
||||
_expect_label_contains(ui, "DebugPanel/StateAxesLabel", "Startup", "Debug state axes should include ActionPhaseState")
|
||||
_expect_label_contains(ui, "DebugPanel/StateAxesLabel", "Hitstun", "Debug state axes should include LifeState")
|
||||
_expect_label_contains(ui, "DebugPanel/StateAxesLabel", "Parrying", "Debug state axes should include DefenseState")
|
||||
_expect_label_contains(ui, "DebugPanel/ActionLabel", "ground_attack_left_1", "Debug action label should show current action id")
|
||||
_expect_label_contains(ui, "DebugPanel/AnchorLabel", "0.125", "Debug anchor label should show Startup stretch seconds")
|
||||
_expect_label_contains(ui, "DebugPanel/EffectsLabel", "effect_root", "Debug effects label should show active effect ids")
|
||||
_expect_label_contains(ui, "DebugPanel/EffectsLabel", "1.5s", "Debug effects label should show active effect remaining seconds")
|
||||
_expect_label_contains(ui, "DebugPanel/EffectsLabel", "x1", "Debug effects label should show active effect stacks")
|
||||
_expect_label_contains(ui, "DebugPanel/EffectsLabel", "debug_test", "Debug effects label should show active effect source")
|
||||
_expect_label_contains(ui, "DebugPanel/DefenseLabel", "Baseline", "Debug defense label should identify baseline defense")
|
||||
_expect_label_contains(ui, "DebugPanel/DefenseLabel", "Invincible", "Debug defense label should show synthesized defense state")
|
||||
_expect_label_contains(ui, "DebugPanel/DefenseLabel", "damage 0.00", "Debug defense label should show baseline damage multiplier")
|
||||
_expect_label_contains(ui, "DebugPanel/DefenseLabel", "interrupt false", "Debug defense label should show baseline interrupt result")
|
||||
_expect_label_contains(ui, "DebugPanel/PatternsLabel", "A->ground_attack_left_1", "Debug patterns label should show exported legal patterns")
|
||||
_expect_label_contains(ui, "DebugPanel/PatternsLabel", "S->block_start", "Debug patterns label should show standalone S block")
|
||||
_expect_label_not_contains(ui, "DebugPanel/PatternsLabel", "SS->", "Debug patterns label should not show removed S S combo")
|
||||
_expect_label_contains(ui, "DebugPanel/CalibrationLabel", "Diff", "Debug calibration label should show rhythm diff calibration data")
|
||||
|
||||
var bus := root.get_node_or_null("EventBus")
|
||||
if bus != null and bus.has_signal("hit_confirmed"):
|
||||
bus.emit_signal("hit_confirmed", {
|
||||
"damage": 7,
|
||||
"hit_type": &"melee",
|
||||
"action": load("res://resources/actions/ground_attack_left_1.tres"),
|
||||
"defense": {"defense_state": &"Parrying"},
|
||||
"interrupts": false,
|
||||
})
|
||||
else:
|
||||
failures.append("EventBus should expose hit_confirmed(result) for debug hit logs")
|
||||
_expect_label_contains(ui, "DebugPanel/HitLogLabel", "ground_attack_left_1", "Debug hit log should show hit action id")
|
||||
_expect_label_contains(ui, "DebugPanel/HitLogLabel", "dmg 7", "Debug hit log should show resolved damage")
|
||||
_expect_label_contains(ui, "DebugPanel/HitLogLabel", "Parrying", "Debug hit log should show effective defense")
|
||||
_expect_label_contains(ui, "DebugPanel/HitLogLabel", "interrupt false", "Debug hit log should show interrupt result")
|
||||
if bus != null and bus.has_signal("hit_confirmed"):
|
||||
for index: int in range(4):
|
||||
bus.emit_signal("hit_confirmed", {
|
||||
"damage": index + 1,
|
||||
"hit_type": &"melee",
|
||||
"action": load("res://resources/actions/ground_attack_left_1.tres"),
|
||||
"defense": {"defense_state": &"Vulnerable"},
|
||||
"interrupts": true,
|
||||
})
|
||||
if ui.has_method("get_hit_log_entries"):
|
||||
var entries: Array = ui.call("get_hit_log_entries")
|
||||
_expect_int(entries.size(), 5, "Debug UI should retain full hit history beyond the compact label")
|
||||
else:
|
||||
failures.append("MainUI should expose get_hit_log_entries()")
|
||||
if ui.has_method("export_hit_log"):
|
||||
_expect(ui.call("export_hit_log").contains("ground_attack_left_1"), "Debug UI should export hit history text")
|
||||
else:
|
||||
failures.append("MainUI should expose export_hit_log()")
|
||||
|
||||
ui.free()
|
||||
player.free()
|
||||
await _check_main_scene_binds_debug_actor()
|
||||
_finish()
|
||||
|
||||
|
||||
func _expect_label_contains(root_node: Node, path: String, text: String, label: String) -> void:
|
||||
var node := root_node.get_node_or_null(path) as Label
|
||||
if node == null:
|
||||
failures.append("%s: missing %s" % [label, path])
|
||||
return
|
||||
if not node.text.contains(text):
|
||||
failures.append("%s: expected '%s' to contain '%s'" % [label, node.text, text])
|
||||
|
||||
|
||||
func _expect_label_not_contains(root_node: Node, path: String, text: String, label: String) -> void:
|
||||
var node := root_node.get_node_or_null(path) as Label
|
||||
if node == null:
|
||||
failures.append("%s: missing %s" % [label, path])
|
||||
return
|
||||
if node.text.contains(text):
|
||||
failures.append("%s: expected '%s' not to contain '%s'" % [label, node.text, text])
|
||||
|
||||
|
||||
func _method_arg_count(object: Object, method_name: String) -> int:
|
||||
for method: Dictionary in object.get_method_list():
|
||||
if str(method.get("name", "")) != method_name:
|
||||
continue
|
||||
var args = method.get("args", [])
|
||||
return args.size() if args is Array else 0
|
||||
return 0
|
||||
|
||||
|
||||
func _check_main_scene_binds_debug_actor() -> void:
|
||||
var main_scene: PackedScene = load("res://scenes/main/main.tscn")
|
||||
if main_scene == null:
|
||||
failures.append("main.tscn should load")
|
||||
return
|
||||
var main := main_scene.instantiate()
|
||||
root.add_child(main)
|
||||
await process_frame
|
||||
var player: Node = main.call("get_player")
|
||||
var ui: Node = main.get_node("UI")
|
||||
player.get_node("StateMachine").call("set_action_phase", &"Startup")
|
||||
ui.call("refresh_debug_panel")
|
||||
_expect_label_contains(ui, "DebugPanel/StateAxesLabel", "Startup", "Main should bind Player to UI DebugPanel")
|
||||
main.free()
|
||||
|
||||
|
||||
func _expect(condition: bool, label: String) -> void:
|
||||
if not condition:
|
||||
failures.append(label)
|
||||
|
||||
|
||||
func _expect_int(actual: int, expected: int, label: String) -> void:
|
||||
if actual != expected:
|
||||
failures.append("%s: expected %d, got %d" % [label, expected, actual])
|
||||
|
||||
|
||||
func _finish() -> void:
|
||||
if failures.is_empty():
|
||||
print("PASS debug ui")
|
||||
quit(0)
|
||||
else:
|
||||
for failure: String in failures:
|
||||
push_error(failure)
|
||||
quit(1)
|
||||
Reference in New Issue
Block a user