ab81f66ef0
F2 wechselt im Spiel den Stil und meldet ihn, --style=NAME wählt ihn beim Start, und das Spiel merkt sich die Wahl in den Einstellungen. Das Bildschirmfoto-Werkzeug nimmt Bilder in einem bestimmten Stil und von der Vitrine auf und zeigt eine zweite Figur mit Namen. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
201 lines
9.0 KiB
GDScript
201 lines
9.0 KiB
GDScript
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)
|
|
|
|
|
|
func test_a_key_that_cannot_be_read_right_now_is_not_replaced() -> void:
|
|
var directory := TestFiles.temporary_dir("held-key")
|
|
var key := SaveStore.new(directory).player_key()
|
|
var store := HeldFileStore.new(directory)
|
|
store.unreadable = SaveStore.KEY_FILE
|
|
check_eq(store.player_key(), PackedByteArray(), "no key for now")
|
|
check_eq(store.last_read_error, ERR_FILE_CANT_READ, "the reason is kept")
|
|
check_eq(SaveStore.new(directory).player_key(), key, "the key on disk is the old one")
|
|
TestFiles.remove_dir(directory)
|
|
|
|
|
|
func test_a_damaged_key_is_replaced() -> void:
|
|
var directory := TestFiles.temporary_dir("damaged-key")
|
|
var file := FileAccess.open(directory.path_join(SaveStore.KEY_FILE), FileAccess.WRITE)
|
|
file.store_buffer(PackedByteArray([1, 2, 3]))
|
|
file.close()
|
|
var store := SaveStore.new(directory)
|
|
var key := store.player_key()
|
|
check_eq(key.size(), SaveStore.KEY_BYTES, "a new key")
|
|
check_eq(SaveStore.new(directory).player_key(), key, "which is kept")
|
|
TestFiles.remove_dir(directory)
|
|
|
|
|
|
func test_a_save_that_cannot_be_read_right_now_reports_why() -> void:
|
|
var directory := TestFiles.temporary_dir("held-save")
|
|
SaveStore.new(directory).write_save(PackedByteArray([1, 2, 3]))
|
|
var store := HeldFileStore.new(directory)
|
|
store.unreadable = SaveStore.SAVE_FILE
|
|
check_eq(store.read_save(), PackedByteArray(), "nothing read")
|
|
check_eq(store.last_read_error, ERR_FILE_CANT_READ, "the reason")
|
|
store.unreadable = ""
|
|
check_eq(store.read_save(), PackedByteArray([1, 2, 3]), "readable again later")
|
|
check_eq(store.last_read_error, OK, "no error now")
|
|
TestFiles.remove_dir(directory)
|
|
|
|
|
|
func test_the_settings_are_kept() -> void:
|
|
var directory := TestFiles.temporary_dir("settings")
|
|
var store := SaveStore.new(directory)
|
|
check_eq(store.player_name(), "", "no name at first")
|
|
store.set_player_name("Ada")
|
|
store.set_last_address("192.168.1.20")
|
|
var later := SaveStore.new(directory)
|
|
check_eq(later.player_name(), "Ada", "name")
|
|
check_eq(later.last_address(), "192.168.1.20", "address")
|
|
TestFiles.remove_dir(directory)
|
|
|
|
|
|
func test_settings_that_cannot_be_read_right_now_are_not_overwritten() -> void:
|
|
var directory := TestFiles.temporary_dir("held-settings")
|
|
var store := SaveStore.new(directory)
|
|
store.set_player_name("Ada")
|
|
store.set_last_address("192.168.1.20")
|
|
var held := HeldFileStore.new(directory)
|
|
held.unreadable = SaveStore.SETTINGS_FILE
|
|
check_eq(held.player_name(), "", "nothing read for now")
|
|
held.set_player_name("Grace")
|
|
var later := SaveStore.new(directory)
|
|
check_eq(later.player_name(), "Ada", "the name on disk is the old one")
|
|
check_eq(later.last_address(), "192.168.1.20", "the address is kept")
|
|
TestFiles.remove_dir(directory)
|
|
|
|
|
|
func test_the_chosen_style_is_kept() -> void:
|
|
var directory := TestFiles.temporary_dir("style")
|
|
var store := SaveStore.new(directory)
|
|
check_eq(store.style(), "", "no style at first")
|
|
store.set_style("pastel")
|
|
check_eq(SaveStore.new(directory).style(), "pastel", "kept for the next start")
|
|
TestFiles.remove_dir(directory)
|