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 capture points and 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 # capture point, 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 var expected_palette_size: int = 1 + EnemyDefinitions.all().size() if editor._palette_buttons.size() != expected_palette_size: return _fail("palette has %d entries, expected 1 + %d enemy definitions" % [ editor._palette_buttons.size(), EnemyDefinitions.all().size() ]) editor.new_setup(TEST_SETUP_ID, "Test Editor Setup", "rocky") editor.add_capture_point(Vector2(100, 200)) editor.add_capture_point(Vector2(-300, 50)) editor.add_capture_point(Vector2(0, -400)) editor.add_enemy("chaser", Vector2(500, 500)) editor.add_enemy("sniper", Vector2(-500, -500)) if editor.current_setup.capture_points.size() != 3: return _fail("placing 3 capture points did not land 3") if editor.current_setup.enemy_spawns.size() != 2: return _fail("placing 2 enemies did not land 2") editor.move_capture_point(0, Vector2(150, 250)) if editor.current_setup.capture_points[0] != Vector2(150, 250): return _fail("move_capture_point did not update the position") editor.remove_enemy(0) # removes the chaser spawn if editor.current_setup.enemy_spawns.size() != 1: return _fail("remove_enemy did not shrink enemy_spawns") if editor.current_setup.enemy_spawns[0].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 points: PackedVector2Array = editor.current_setup.capture_points var spawns: Array = editor.current_setup.enemy_spawns if points.size() != 3 or points[0] != Vector2(150, 250) \ or points[1] != Vector2(-300, 50) or points[2] != Vector2(0, -400): return _fail("reopened capture points did not match what was saved: %s" % [points]) if spawns.size() != 1 or spawns[0].enemy_id != "sniper" or spawns[0].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_capture_point(1) if editor.current_setup.capture_points.size() != 2: 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