spaceship/tests/test_setup_editor.gd
Loïc Wisniewski 6e13b6397c Take planets by killing what defends them
#211 conquest is the fight now: a planet registers the garrison its setup
authors, each defender's own death counts against it, and the last one takes
the world. The capture points - stand in a ring, wait out a timer, once per
ring - are gone, along with the editor palette that placed them.
#212 conquest opens a dialog on the surface naming the research points
recovered; the award travels with the signal, after it is banked.
#209 the prologue's charted sectors go with the breach, so the map the
survivors keep is of where they now are - and "chart 30 sectors" is no
longer complete before they have flown anywhere.
#218 enemy variety is gated on the FLEET, not on wave strength: a starting
fleet meets chasers only at any wave number, and each vessel past three
opens one more kind.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019AJMdB7iuHuLFZM1aBu3GD
2026-09-05 13:31:25 +02:00

132 lines
4.7 KiB
GDScript

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/<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
# 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