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)