extends TestCase func test_the_player_key_is_created_once_and_kept() -> void: var directory := TestFiles.temporary_dir("key") var first := SaveStore.new(directory).player_key() var second := SaveStore.new(directory).player_key() check_eq(first.size(), SaveStore.KEY_BYTES, "sixteen bytes") check_eq(second, first, "the same key on the next start") TestFiles.remove_dir(directory) func test_a_save_is_written_and_read_back() -> void: var directory := TestFiles.temporary_dir("save") var store := SaveStore.new(directory) check(not store.has_save(), "no save at first") check(store.write_save(PackedByteArray([1, 2, 3])), "written") check(store.write_save(PackedByteArray([4, 5])), "overwritten") check(store.has_save(), "a save exists") check_eq(store.read_save(), PackedByteArray([4, 5]), "the newest save is read") check(not FileAccess.file_exists(directory.path_join(SaveStore.SAVE_FILE + ".tmp")), "no temporary file is left") check(not FileAccess.file_exists(directory.path_join(SaveStore.BACKUP_FILE)), "no backup is left") TestFiles.remove_dir(directory) func test_an_empty_save_is_not_written() -> void: var directory := TestFiles.temporary_dir("empty") var store := SaveStore.new(directory) check(not store.write_save(PackedByteArray()), "refused") check(not store.has_save(), "no file") TestFiles.remove_dir(directory) func test_a_save_that_cannot_be_written_keeps_the_previous_one() -> void: var directory := TestFiles.temporary_dir("blocked") var store := SaveStore.new(directory) store.write_save(PackedByteArray([1, 2, 3])) # A folder in place of the temporary file makes the write fail. DirAccess.make_dir_absolute(directory.path_join(SaveStore.SAVE_FILE + ".tmp")) check(not store.write_save(PackedByteArray([4, 5])), "the failed save is reported") check_eq(store.read_save(), PackedByteArray([1, 2, 3]), "the previous save is untouched") check(not store.write_save(PackedByteArray()), "an empty save is refused") check_eq(store.read_save(), PackedByteArray([1, 2, 3]), "still untouched") TestFiles.remove_dir(directory) func test_a_save_that_cannot_be_moved_into_place_keeps_the_previous_one() -> void: var directory := TestFiles.temporary_dir("held") var store := SaveStore.new(directory) store.write_save(PackedByteArray([1, 2, 3])) # The open handle stands for an outside program, for example a virus # scanner. The new save can be written, but Windows refuses to move a file # that is held open. var holder := FileAccess.open(directory.path_join(SaveStore.SAVE_FILE + ".tmp"), FileAccess.WRITE) check(not store.write_save(PackedByteArray([4, 5])), "the failed save is reported") check_eq(store.read_save(), PackedByteArray([1, 2, 3]), "the previous save is untouched") check(not FileAccess.file_exists(directory.path_join(SaveStore.BACKUP_FILE)), "no backup is left") holder.close() TestFiles.remove_dir(directory) func test_a_save_that_cannot_move_the_previous_one_aside_keeps_it() -> void: var directory := TestFiles.temporary_dir("aside-blocked") var store := SaveStore.new(directory) store.write_save(PackedByteArray([1, 2, 3])) # A folder under the backup name keeps the previous save from moving. DirAccess.make_dir_absolute(directory.path_join(SaveStore.BACKUP_FILE)) check(not store.write_save(PackedByteArray([4, 5])), "the failed save is reported") check_eq(store.read_save(), PackedByteArray([1, 2, 3]), "the previous save is untouched") check(not FileAccess.file_exists(directory.path_join(SaveStore.SAVE_FILE + ".tmp")), "no temporary file is left") TestFiles.remove_dir(directory) func test_an_interrupted_save_is_recovered_from_the_backup() -> void: var directory := TestFiles.temporary_dir("recover") # A crash between the two moves of write_save leaves only the backup. var backup := directory.path_join(SaveStore.BACKUP_FILE) var file := FileAccess.open(backup, FileAccess.WRITE) file.store_buffer(PackedByteArray([7, 8, 9])) file.close() var store := SaveStore.new(directory) check(store.has_save(), "the previous save is back") check_eq(store.read_save(), PackedByteArray([7, 8, 9]), "with its content") check(not FileAccess.file_exists(backup), "the backup is moved, not copied") TestFiles.remove_dir(directory) func test_a_backup_never_replaces_an_existing_save() -> void: var directory := TestFiles.temporary_dir("keep") SaveStore.new(directory).write_save(PackedByteArray([1, 2, 3])) var file := FileAccess.open(directory.path_join(SaveStore.BACKUP_FILE), FileAccess.WRITE) file.store_buffer(PackedByteArray([9, 9])) file.close() var store := SaveStore.new(directory) check_eq(store.read_save(), PackedByteArray([1, 2, 3]), "the save is not replaced by the older backup") TestFiles.remove_dir(directory) func test_setting_aside_without_a_save_reports_nothing_moved() -> void: var directory := TestFiles.temporary_dir("nothing") check_eq(SaveStore.new(directory).set_aside_save(), "", "no save, nothing moved") TestFiles.remove_dir(directory) func test_an_unusable_save_can_be_set_aside() -> void: var directory := TestFiles.temporary_dir("aside") var store := SaveStore.new(directory) store.write_save(PackedByteArray([9, 9])) var aside := store.set_aside_save() check(not store.has_save(), "the save is out of the way") check_eq(FileAccess.get_file_as_bytes(aside), PackedByteArray([9, 9]), "its content is kept") TestFiles.remove_dir(directory) func test_only_the_newest_recordings_are_kept() -> void: var directory := TestFiles.temporary_dir("recordings") var store := SaveStore.new(directory) var paths: PackedStringArray = [] for number in SaveStore.KEEP_RECORDINGS + 2: paths.append(store.write_recording(PackedByteArray([number]))) OS.delay_usec(10) var names := store.recordings() check_eq(names.size(), SaveStore.KEEP_RECORDINGS, "only the newest are kept") check(not FileAccess.file_exists(paths[0]), "the oldest is gone") check(not FileAccess.file_exists(paths[1]), "the second oldest is gone") check(FileAccess.file_exists(paths[paths.size() - 1]), "the newest is there") check_eq(store.write_recording(PackedByteArray()), "", "an empty recording is not written") TestFiles.remove_dir(directory)