extends SceneTree const CONTENT_PATHS := preload("res://scripts/shared/content_paths.gd") const CLI_LAUNCHER := preload("res://scripts/tools/cli_scene_launcher.gd") const STAGE_SCENE_IO := preload("res://scripts/stage/stage_scene_io.gd") const STAGE_SCENE := preload("res://scenes/stage/sandbox_stage.tscn") const LEGACY_STAGE_PATH: String = "res://tests/.phase14_legacy_paths.scene" const RESAVED_STAGE_PATH: String = "res://tests/.phase14_resaved_paths_resaved.scene" var _checks: int = 0 var _failures: int = 0 func _initialize() -> void: call_deferred("_run") func _run() -> void: _test_path_mapping() _test_moved_stage_file_paths() await _test_legacy_stage_round_trip() _cleanup() print("RESULT: %d checks, %d failures" % [_checks, _failures]) quit(1 if _failures > 0 else 0) func _expect(condition: bool, message: String) -> void: _checks += 1 if condition: print("PASS: " + message) else: _failures += 1 push_error("Content path test failed: " + message) func _test_path_mapping() -> void: _expect(CONTENT_PATHS.canonicalize("res://stickmen/basic.stk") == "res://content/stickmen/basic.stk", "legacy stickman resource paths map into content") _expect(CONTENT_PATHS.canonicalize("res://props/briefcase.prop") == "res://content/props/briefcase.prop", "legacy prop resource paths map into content") _expect(CONTENT_PATHS.canonicalize("res://game_scenes/bend.scene") == "res://content/stages/bend.scene", "legacy stage resource paths map into content") _expect(CONTENT_PATHS.canonicalize("res://unmanaged/asset.stk") == "res://unmanaged/asset.stk", "unknown resource paths pass through") _expect(CONTENT_PATHS.canonicalize("user://stickmen/basic.stk") == "user://stickmen/basic.stk", "user-selected paths pass through") _expect(CONTENT_PATHS.canonicalize("/tmp/external/stickmen/basic.stk") == "/tmp/external/stickmen/basic.stk", "external absolute paths pass through") var project_root: String = ProjectSettings.globalize_path("res://").trim_suffix("/") var old_absolute: String = project_root.path_join("stickmen/basic.stk") var new_absolute: String = project_root.path_join("content/stickmen/basic.stk") _expect(CONTENT_PATHS.canonicalize(old_absolute) == new_absolute, "legacy absolute paths inside the project migrate in place") var cli_result: Dictionary = CLI_LAUNCHER.parse(["--scene", "res://game_scenes/bend.scene"]) _expect(String(cli_result.get("scene_path", "")) == "res://content/stages/bend.scene", "CLI stage paths migrate before playback") func _test_moved_stage_file_paths() -> void: var result: Dictionary = STAGE_SCENE_IO.read_file("res://game_scenes/bend.scene") _expect(bool(result.get("ok", false)), "stage IO opens a stage through its previous project path") func _test_legacy_stage_round_trip() -> void: _cleanup() var legacy_data: Dictionary = { # Keep this fixture at the pre-identity schema so the path test also # exercises the existing legacy-stage migration into the current format. "version": "1.7", "scene_name": "Legacy Asset Paths", "sky_id": "sky_neutral", "background_kind": "sky", "plain_color": "#F5EFE0", "camera": {"position": {"x": 0.0, "y": -400.0}, "zoom": 0.5}, "objects": [ { "file_id": "stickman_1", "type": "stickman", "position": {"x": 0.0, "y": 0.0}, "rotation": 0.0, "stk_path": "res://stickmen/test.stk", "action_queue": [], }, { "file_id": "prop_1", "stage_object_id": "prop_1", "type": "prop", "position": {"x": 180.0, "y": 0.0}, "rotation": 0.0, "asset_id": "res://props/briefcase.prop", "scale": {"x": 1.0, "y": 1.0}, "material_preset": 1, }, ], "event_rules": [], "metadata": {}, } _expect(bool(STAGE_SCENE_IO.write_file_safe(LEGACY_STAGE_PATH, legacy_data).get("ok", false)), "legacy stage fixture writes") var stage: Node2D = STAGE_SCENE.instantiate() as Node2D root.add_child(stage) await process_frame var loaded: bool = bool(stage.call("_load_scene_from_path", LEGACY_STAGE_PATH)) _expect(loaded, "legacy stage with moved stickman and prop assets loads") var world: Node = stage.get("_world") as Node _expect(world != null and world.get_child_count() == 2, "both moved assets are present after load") var scene_data: Dictionary = stage.call("_collect_scene_data", false) as Dictionary var objects: Array = scene_data.get("objects", []) var saved_stickman_path: String = "" var saved_prop_path: String = "" for value: Variant in objects: if not value is Dictionary: continue var entry: Dictionary = value as Dictionary if String(entry.get("type", "")) == "stickman": saved_stickman_path = String(entry.get("stk_path", "")) elif String(entry.get("type", "")) == "prop": saved_prop_path = String(entry.get("asset_id", "")) _expect(saved_stickman_path == "res://content/stickmen/test.stk", "resaved stickman reference uses the canonical path") _expect(saved_prop_path == "res://content/props/briefcase.prop", "resaved prop reference uses the canonical path") _expect(bool(STAGE_SCENE_IO.write_file_safe(RESAVED_STAGE_PATH, scene_data).get("ok", false)), "canonical stage document resaves") var reread: Dictionary = STAGE_SCENE_IO.read_file(RESAVED_STAGE_PATH) _expect(bool(reread.get("ok", false)), "resaved stage document reads successfully") var current_path: String = String(stage.get("_current_scene_path")) _expect(current_path == LEGACY_STAGE_PATH, "unmanaged stage document path remains unchanged") stage.queue_free() await process_frame func _cleanup() -> void: for path: String in [LEGACY_STAGE_PATH, RESAVED_STAGE_PATH]: if FileAccess.file_exists(path): DirAccess.remove_absolute(ProjectSettings.globalize_path(path))