bc34bc61f7
Beides setzt Konzept 9 um („automatisch in festen Abständen“, Speichern beim Schließen), und beides ließ sich entfernen, ohne dass ein Test rot wurde. - Schließen: Die Hauptszene bekommt NOTIFICATION_WM_CLOSE_REQUEST. Danach meldet ein SaveStore im selben Ordner einen Spielstand und genau eine Aufzeichnung. - Automatisch: Die Hauptszene läuft per _run_tick bis zum Takt vor AUTOSAVE_TICKS, ohne Bilder abzuwarten. Bis dahin gibt es keinen Spielstand, einen Takt später gibt es einen. Entfernt man das Speichern beim Schließen, schlägt der erste Test fehl; entfernt man das automatische Speichern in _run_tick, der zweite. Ohne das Schreiben der Aufzeichnung beim Schließen schlägt der erste ebenfalls fehl. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
104 lines
4.0 KiB
GDScript
104 lines
4.0 KiB
GDScript
extends TestCase
|
|
## Starts the real main scene with its own storage folder and runs a few
|
|
## frames.
|
|
|
|
|
|
func _start_main(directory: String) -> Node:
|
|
var main: Node = load("res://main.tscn").instantiate()
|
|
main.storage_dir = directory
|
|
tree.root.add_child(main)
|
|
return main
|
|
|
|
|
|
func _stop_main(main: Node) -> void:
|
|
tree.root.remove_child(main)
|
|
main.free()
|
|
|
|
|
|
func test_a_new_game_starts_and_the_player_joins() -> void:
|
|
var directory := TestFiles.temporary_dir("main")
|
|
var main := _start_main(directory)
|
|
for frame in 5:
|
|
await tree.process_frame
|
|
var session: GwSession = main.session
|
|
check(session != null and session.is_running(), "a session runs")
|
|
check(not session.is_broken(), "the simulation is healthy")
|
|
check_eq(session.local_player(), 0, "the local player has joined")
|
|
check_eq(main.avatar.position, GridMotion.tile_center(session.spawn_point()), "the figure stands on the spawn")
|
|
check_eq(main.hud.stone_text(), tr("STONE_COUNT") % 0, "the HUD shows the stones")
|
|
_stop_main(main)
|
|
TestFiles.remove_dir(directory)
|
|
|
|
|
|
func test_a_saved_game_is_continued_on_the_next_start() -> void:
|
|
var directory := TestFiles.temporary_dir("continue")
|
|
var first := _start_main(directory)
|
|
await tree.process_frame
|
|
var tick_at_save: int = first.session.tick()
|
|
check(first.save_game(), "the game was saved")
|
|
_stop_main(first)
|
|
|
|
var second := _start_main(directory)
|
|
await tree.process_frame
|
|
check(second.session.tick() > tick_at_save, "the saved world continues")
|
|
check_eq(second.session.local_player(), 0, "the same player rejoins")
|
|
_stop_main(second)
|
|
TestFiles.remove_dir(directory)
|
|
|
|
|
|
func test_closing_the_window_saves_the_game_and_records_the_session() -> void:
|
|
var directory := TestFiles.temporary_dir("close")
|
|
var main := _start_main(directory)
|
|
await tree.process_frame
|
|
main.notification(Node.NOTIFICATION_WM_CLOSE_REQUEST)
|
|
var store := SaveStore.new(directory)
|
|
check(store.has_save(), "the game was saved")
|
|
check_eq(store.recordings().size(), 1, "the session was recorded")
|
|
_stop_main(main)
|
|
TestFiles.remove_dir(directory)
|
|
|
|
|
|
func test_the_game_is_saved_automatically_every_two_minutes() -> void:
|
|
var directory := TestFiles.temporary_dir("autosave")
|
|
var main := _start_main(directory)
|
|
var store := SaveStore.new(directory)
|
|
check(not store.has_save(), "there is no save at the start")
|
|
# No frames are awaited, so only these ticks run.
|
|
while main.session.tick() < main.AUTOSAVE_TICKS - 1:
|
|
main._run_tick()
|
|
check(not store.has_save(), "still no save one tick before the interval ends")
|
|
main._run_tick()
|
|
check(store.has_save(), "saved when the interval ends")
|
|
_stop_main(main)
|
|
TestFiles.remove_dir(directory)
|
|
|
|
|
|
func test_an_unusable_save_is_set_aside_and_a_new_world_starts() -> void:
|
|
var directory := TestFiles.temporary_dir("broken")
|
|
var store := SaveStore.new(directory)
|
|
store.write_save(PackedByteArray([1, 2, 3]))
|
|
var main := _start_main(directory)
|
|
await tree.process_frame
|
|
check(main.session.is_running(), "a new world runs")
|
|
check(main.session.tick() <= 5, "it is new, tick %d" % main.session.tick())
|
|
check(FileAccess.file_exists(directory.path_join(SaveStore.SAVE_FILE + ".broken")), "the unusable save is kept aside")
|
|
check_eq(main.hud.message(), tr("LOAD_FAILED"), "the player is told")
|
|
_stop_main(main)
|
|
TestFiles.remove_dir(directory)
|
|
|
|
|
|
func test_an_unusable_save_that_cannot_be_set_aside_is_never_overwritten() -> void:
|
|
var directory := TestFiles.temporary_dir("stuck")
|
|
var store := SaveStore.new(directory)
|
|
store.write_save(PackedByteArray([1, 2, 3]))
|
|
# A folder under the set-aside name keeps the unusable save from moving.
|
|
DirAccess.make_dir_absolute(directory.path_join(SaveStore.SAVE_FILE + ".broken"))
|
|
var main := _start_main(directory)
|
|
await tree.process_frame
|
|
check(main.session.is_running(), "a new world runs")
|
|
check(not main.save_game(), "saving is refused")
|
|
check_eq(store.read_save(), PackedByteArray([1, 2, 3]), "the unusable save is untouched")
|
|
check_eq(main.hud.message(), tr("LOAD_FAILED"), "the player is told")
|
|
_stop_main(main)
|
|
TestFiles.remove_dir(directory)
|