136 lines
5.1 KiB
GDScript3
136 lines
5.1 KiB
GDScript3
|
|
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/<id>.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://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://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
|