extends SceneTree # Headless gameplay test: run with # godot --headless -s res://tests/test_setup_editor.gd # Drives PlanetSetupEditor's model directly (place/move/delete/save/reload) # rather than through touch input - see the ticket's own note that the # touch layer can stay out of the headless test. Verifies: # 1. placing enemies updates current_setup # 2. moving and deleting update it correctly, including index shifting # 3. saving writes a real res://PlanetSetups/.tres and the registry # picks it up # 4. reopening that file in a fresh editor instance round-trips the # exact points/enemies, and they can be moved/deleted again # 5. the palette has one entry per EnemyDefinitions entry plus the # enemy kind, generated from the registry rather than hardcoded const TEST_SETUP_ID: String = "test_editor_setup" const TEST_SETUP_PATH: String = "res://PlanetSetups/test_editor_setup.tres" var editor: Node var stage: int = 0 var elapsed: float = 0.0 func _initialize() -> void: _cleanup_scratch_file() editor = load("res://surface/PlanetSetupEditor.tscn").instantiate() root.add_child(editor) func _process(delta: float) -> bool: elapsed += delta match stage: 0: # _ready() (palette build, initial new_setup) needs a frame to # flush - same hazard as test_planet_setups.gd. if elapsed < 0.1: return false # #211 took the capture-point tile out: the palette is exactly the # enemy registry now. if editor._palette_buttons.size() != EnemyDefinitions.all().size(): return _fail("palette has %d entries, expected %d enemy definitions" % [ editor._palette_buttons.size(), EnemyDefinitions.all().size() ]) editor.new_setup(TEST_SETUP_ID, "Test Editor Setup", "rocky") editor.add_enemy("chaser", Vector2(100, 200)) editor.add_enemy("chaser", Vector2(500, 500)) editor.add_enemy("sniper", Vector2(-500, -500)) if editor.current_setup.enemy_spawns.size() != 3: return _fail("placing 3 enemies did not land 3") editor.move_enemy(0, Vector2(150, 250)) if editor.current_setup.enemy_spawns[0].position != Vector2(150, 250): return _fail("move_enemy did not update the position") editor.remove_enemy(1) # removes the second chaser if editor.current_setup.enemy_spawns.size() != 2: return _fail("remove_enemy did not shrink enemy_spawns") if editor.current_setup.enemy_spawns[1].enemy_id != "sniper": return _fail("remove_enemy removed the wrong entry (index did not shift)") var result: Dictionary = editor.save_setup() if not result.ok: return _fail("save_setup reported failure: %s" % result.message) if not FileAccess.file_exists(TEST_SETUP_PATH): return _fail("save_setup reported success but wrote no file at %s" % TEST_SETUP_PATH) var found_in_registry: bool = false for setup in PlanetSetups.all(): if setup.setup_id == TEST_SETUP_ID: found_in_registry = true if not found_in_registry: return _fail("saved setup was not picked up by PlanetSetups after save") elapsed = 0.0 stage = 1 return false 1: if elapsed < 0.1: return false # Reopen in a FRESH editor instance, as a re-landing/re-editing # session would. var reopened: Node = load("res://surface/PlanetSetupEditor.tscn").instantiate() root.add_child(reopened) editor = reopened elapsed = 0.0 stage = 2 return false 2: if elapsed < 0.1: return false if not editor.load_setup(TEST_SETUP_ID): return _fail("reopening the saved setup failed") var spawns: Array = editor.current_setup.enemy_spawns if spawns.size() != 2 or spawns[0].enemy_id != "chaser" \ or spawns[0].position != Vector2(150, 250) \ or spawns[1].enemy_id != "sniper" \ or spawns[1].position != Vector2(-500, -500): return _fail("reopened enemy spawns did not match what was saved") # The reopened items can still be moved and deleted. editor.move_enemy(0, Vector2(-600, -600)) if editor.current_setup.enemy_spawns[0].position != Vector2(-600, -600): return _fail("could not move an item after reopening") editor.remove_enemy(1) if editor.current_setup.enemy_spawns.size() != 1: return _fail("could not delete an item after reopening") print("TEST_SETUP_EDITOR: PASS") _cleanup_scratch_file() quit(0) return true return false func _cleanup_scratch_file() -> void: if FileAccess.file_exists(TEST_SETUP_PATH): DirAccess.remove_absolute(ProjectSettings.globalize_path(TEST_SETUP_PATH)) var import_file: String = TEST_SETUP_PATH + ".import" if FileAccess.file_exists(import_file): DirAccess.remove_absolute(ProjectSettings.globalize_path(import_file)) PlanetSetups.rescan() func _fail(message: String) -> bool: print("TEST_SETUP_EDITOR: FAIL (%s)" % message) _cleanup_scratch_file() quit(1) return true