Files
Fighting_Rthythm_game/tests/test_architecture_refactor.gd
2026-07-02 09:47:52 -07:00

159 lines
6.3 KiB
GDScript

extends SceneTree
var failures: Array[String] = []
func _init() -> void:
_check_event_bus_autoload()
_check_main_is_thin()
_check_player_components()
_check_skill_resources()
_check_stage_and_ui_scenes()
_check_project_layers_and_inputs()
_finish()
func _check_event_bus_autoload() -> void:
_expect(ProjectSettings.has_setting("autoload/EventBus"), "EventBus should be registered as a game autoload")
if ProjectSettings.has_setting("autoload/EventBus"):
var path := str(ProjectSettings.get_setting("autoload/EventBus"))
_expect(path.contains("res://autoload/event_bus.gd"), "EventBus autoload should point at autoload/event_bus.gd")
var event_bus_script := load("res://autoload/event_bus.gd")
_expect(event_bus_script != null, "autoload/event_bus.gd should exist")
func _check_main_is_thin() -> void:
var main_scene: PackedScene = load("res://scenes/main/main.tscn")
_expect(main_scene != null, "main.tscn should load")
if main_scene != null:
var main := main_scene.instantiate()
get_root().add_child(main)
_expect(main.has_node("Stage"), "Main should instance a Stage child")
_expect(main.has_node("UI"), "Main should instance a standalone UI child")
_expect(not main.has_node("RhythmConductor"), "Main should use RhythmManager autoload instead of a RhythmConductor child")
main.free()
var source := _read_text("res://scenes/main/main.gd")
_expect_not_contains(source, "has_signal", "Main should not probe child signals with has_signal")
_expect_not_contains(source, "has_method", "Main should not probe child methods with has_method")
_expect_not_contains(source, ".call(", "Main should not use dynamic call() for game wiring")
func _check_player_components() -> void:
var player_scene: PackedScene = load("res://scenes/characters/player.tscn")
_expect(player_scene != null, "player.tscn should load")
if player_scene != null:
var player := player_scene.instantiate()
get_root().add_child(player)
for node_name: String in [
"StateMachine",
"InputComponent",
"ComboWindow",
"ActionResolver",
"ActionExecutor",
"MotionExecutor",
"BurstComponent",
"ChargeComponent",
"EnergyComponent",
"HealthComponent",
"DamageReceiver",
"DamageEmitter",
]:
_expect(player.has_node(node_name), "Player should have %s child component" % node_name)
player.free()
var source := _read_text("res://scenes/characters/player.gd")
_expect_not_contains(source, "KEY_", "Player should not match raw KEY_* values")
_expect_not_contains(source, "get_first_node_in_group(\"rhythm_conductor\")", "Player should not look up RhythmConductor by group")
_expect_not_contains(source, "PlayerProjectile.new()", "Player should not instantiate projectiles directly")
_expect_not_contains(source, "get_parent()", "Player should not reach upward with get_parent()")
func _check_skill_resources() -> void:
var action_script := load("res://resources/action_data.gd")
_expect(action_script != null, "resources/action_data.gd should exist")
var action_dir := DirAccess.open("res://resources/actions")
_expect(action_dir != null, "resources/actions should exist")
if action_dir != null:
var action_files: Array[String] = []
for file_name: String in action_dir.get_files():
if file_name.ends_with(".tres"):
action_files.append(file_name)
_expect(action_files.size() >= 20, "actions should be saved as migrated .tres resources")
var tracker_script := load("res://scenes/components/combo_window.gd")
var resolver_script := load("res://scenes/combat/action_resolver.gd")
_expect(tracker_script != null, "ComboWindow script should load")
_expect(resolver_script != null, "ActionResolver script should load")
if tracker_script == null or resolver_script == null:
return
var window = tracker_script.new()
window.record(&"A")
var resolved = resolver_script.resolve(window)
_expect(resolved is Resource, "ActionResolver.resolve should return an ActionData Resource, not a Dictionary")
if resolved is Resource:
_expect(resolved.get("input_pattern") is Array, "Resolved ActionData should expose input_pattern")
_expect(str(resolved.get("id")) == "skill_a", "A pattern should resolve to skill_a")
resolver_script.clear_cache()
window.free()
func _check_stage_and_ui_scenes() -> void:
var stage_scene: PackedScene = load("res://scenes/stage/stage.tscn")
_expect(stage_scene != null, "stage.tscn should exist")
if stage_scene != null:
var stage := stage_scene.instantiate()
get_root().add_child(stage)
_expect(stage.has_node("ActorsContainer"), "Stage should own ActorsContainer")
_expect(stage.has_node("ActorsContainer/Player"), "ActorsContainer should own Player")
stage.free()
for scene_path: String in [
"res://scenes/ui/main_ui.tscn",
"res://scenes/ui/rhythm_track.tscn",
"res://scenes/ui/combo_window_hud.tscn",
"res://scenes/ui/energy_bar.tscn",
]:
_expect(load(scene_path) != null, "%s should exist" % scene_path)
func _check_project_layers_and_inputs() -> void:
var expected_layers := {
"layer_names/2d_physics/layer_1": "world",
"layer_names/2d_physics/layer_2": "player_hurtbox",
"layer_names/2d_physics/layer_3": "enemy_hurtbox",
"layer_names/2d_physics/layer_4": "player_hitbox",
"layer_names/2d_physics/layer_5": "enemy_hitbox",
}
for key: String in expected_layers:
_expect(ProjectSettings.has_setting(key), "%s should be configured" % key)
if ProjectSettings.has_setting(key):
_expect(str(ProjectSettings.get_setting(key)) == expected_layers[key], "%s should be named %s" % [key, expected_layers[key]])
for action_name: String in ["move_left", "move_right", "combo_w", "combo_a", "combo_d", "combo_s", "combo_space"]:
_expect(InputMap.has_action(action_name), "InputMap should define %s" % action_name)
_expect(not InputMap.has_action("player_space"), "InputMap should remove duplicate player_space action")
func _read_text(path: String) -> String:
var file := FileAccess.open(path, FileAccess.READ)
if file == null:
failures.append("Could not read %s" % path)
return ""
return file.get_as_text()
func _expect(condition: bool, label: String) -> void:
if not condition:
failures.append(label)
func _expect_not_contains(source: String, needle: String, label: String) -> void:
if source.contains(needle):
failures.append(label)
func _finish() -> void:
if failures.is_empty():
print("PASS architecture refactor")
quit(0)
else:
for failure: String in failures:
push_error(failure)
quit(1)