Files
stickman/tests/test_cli_scene.gd

167 lines
6.4 KiB
GDScript

extends SceneTree
const IO := preload("res://scripts/stage_scene_io.gd")
const STAGE_SCENE := preload("res://scenes/sandbox_stage.tscn")
const FIXTURE_PATH := "user://cli_fixture.scene"
var _checks := 0
var _failures := 0
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
_cleanup()
_test_parser()
await _test_load_into_edit()
await _test_play_mode()
await _test_missing_scene_error()
await _test_play_without_scene()
await _test_recovery_skipped()
_cleanup()
print("----------------------------------------")
if _failures == 0:
print("RESULT: ALL PASSED (%d assertions)" % _checks)
quit(0)
else:
print("RESULT: %d FAILURE(S) out of %d assertions" % [_failures, _checks])
quit(1)
func _expect(condition: bool, message: String) -> void:
_checks += 1
if condition:
print("PASS: " + message)
else:
_failures += 1
push_error("CLI scene test failed: " + message)
func _cleanup() -> void:
if FileAccess.file_exists(FIXTURE_PATH):
DirAccess.remove_absolute(FIXTURE_PATH)
if FileAccess.file_exists("user://sandbox_autosave.scene"):
DirAccess.remove_absolute("user://sandbox_autosave.scene")
func _write_fixture() -> void:
var fixture := {
"version": "1.0",
"scene_name": "CLI Fixture",
"camera": {"position": {"x": 0.0, "y": -400.0}, "zoom": 0.5},
"objects": [{
"file_id": "terrain_1",
"type": "terrain",
"position": {"x": 20.0, "y": 30.0},
"rotation": 0.0,
"asset_id": "ground",
"scale": {"x": 1.0, "y": 1.0},
}],
"event_rules": [],
"metadata": {},
}
IO.write_file_safe(FIXTURE_PATH, fixture)
func _make_stage() -> Node2D:
var stage: Node2D = STAGE_SCENE.instantiate()
root.add_child(stage)
return stage
func _test_parser() -> void:
var empty: Dictionary = CliSceneLauncher.parse([])
_expect(String(empty["scene_path"]) == "" and not bool(empty["play"]) and String(empty["error"]) == "", "empty args parse clean")
var full: Dictionary = CliSceneLauncher.parse(["--play", "--scene", "res://x.scene"])
_expect(String(full["scene_path"]) == "res://x.scene" and bool(full["play"]) and String(full["error"]) == "", "--play --scene sets both")
var eq: Dictionary = CliSceneLauncher.parse(["--scene=res://x.scene"])
_expect(String(eq["scene_path"]) == "res://x.scene" and not bool(eq["play"]), "--scene= form sets path")
var positional: Dictionary = CliSceneLauncher.parse(["/abs/x.scene", "--play"])
_expect(String(positional["scene_path"]) == "/abs/x.scene" and bool(positional["play"]), "bare positional plus --play")
var play_only: Dictionary = CliSceneLauncher.parse(["--play"])
_expect(not String(play_only["error"]).is_empty(), "--play alone is an error")
var missing_value: Dictionary = CliSceneLauncher.parse(["--scene"])
_expect(not String(missing_value["error"]).is_empty(), "--scene without value is an error")
var unknown: Dictionary = CliSceneLauncher.parse(["--bogus"])
_expect(not String(unknown["error"]).is_empty(), "unknown option is an error")
var two_pos: Dictionary = CliSceneLauncher.parse(["a.scene", "b.scene"])
_expect(not String(two_pos["error"]).is_empty(), "two positionals are an error")
var flag_and_pos: Dictionary = CliSceneLauncher.parse(["--scene", "a.scene", "b.scene"])
_expect(not String(flag_and_pos["error"]).is_empty(), "--scene plus positional is an error")
func _test_load_into_edit() -> void:
_write_fixture()
var stage: Node2D = _make_stage()
await process_frame
stage._handle_cli_startup(["--scene", FIXTURE_PATH])
_expect(stage._current_scene_path == FIXTURE_PATH, "load adopts the scene path")
_expect(stage._world.get_child_count() == 1, "load reconstructs one object")
_expect(not stage._dirty, "load clears dirty")
_expect(stage._recent_scenes.size() > 0 and stage._recent_scenes[0] == FIXTURE_PATH, "load updates Open Recent")
_expect("cli_fixture.scene" in stage.get_window().title, "title shows the loaded scene file")
_expect(not FileAccess.file_exists(stage.AUTOSAVE_PATH), "clean load leaves no autosave")
stage.queue_free()
await process_frame
func _test_play_mode() -> void:
_write_fixture()
var stage: Node2D = _make_stage()
await process_frame
stage._handle_cli_startup(["--play", "--scene", FIXTURE_PATH])
_expect(stage.current_mode == stage.StageMode.PLAY, "--play enters PLAY mode")
_expect(not FileAccess.file_exists(stage.AUTOSAVE_PATH), "CLI PLAY suppresses the autosave write")
stage.queue_free()
await process_frame
func _test_missing_scene_error() -> void:
var stage: Node2D = _make_stage()
await process_frame
stage._handle_cli_startup(["--scene", "user://definitely_missing_cli.scene"])
_expect(stage._cli_error_dialog != null and stage._cli_error_dialog.visible, "missing scene shows the error dialog")
_expect(not stage._cli_error_dialog.dialog_text.is_empty(), "missing scene error has dialog text")
_expect(stage._world.get_child_count() == 0, "missing scene leaves a blank stage")
_expect(stage.current_mode == stage.StageMode.EDIT, "missing scene stays in EDIT")
stage._cli_error_dialog.hide()
stage.queue_free()
await process_frame
func _test_play_without_scene() -> void:
var stage: Node2D = _make_stage()
await process_frame
stage._handle_cli_startup(["--play"])
_expect(stage._cli_error_dialog != null and stage._cli_error_dialog.visible, "--play without scene shows the error dialog")
_expect(stage._cli_error_dialog.dialog_text == "--play requires --scene <path>.", "--play error text matches the parser contract")
_expect(stage.current_mode == stage.StageMode.EDIT, "--play without scene never enters PLAY")
stage._cli_error_dialog.hide()
stage.queue_free()
await process_frame
func _test_recovery_skipped() -> void:
var stage: Node2D = _make_stage()
await process_frame
_write_fixture()
var autosave := {
"version": "1.0",
"scene_name": "Stale Autosave",
"objects": [],
"event_rules": [],
"metadata": {"autosave": true, "source_path": "", "modified_unix": Time.get_unix_time_from_system()},
}
IO.write_file_safe(stage.AUTOSAVE_PATH, autosave)
_expect(FileAccess.file_exists(stage.AUTOSAVE_PATH), "autosave fixture pre-written")
stage._handle_cli_startup(["--scene", FIXTURE_PATH])
_expect(not FileAccess.file_exists(stage.AUTOSAVE_PATH), "explicit --scene retires the autosave")
var ui: Node = stage.get_node(NodePath("UI"))
_expect(ui.get_node_or_null(NodePath("AutosaveRecoveryDialog")) == null, "no recovery dialog is created for explicit --scene")
_expect(stage._current_scene_path == FIXTURE_PATH, "explicit --scene loads the requested scene")
stage.queue_free()
await process_frame