76 lines
2.2 KiB
GDScript
76 lines
2.2 KiB
GDScript
extends SceneTree
|
|
|
|
var failures: Array[String] = []
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("_run")
|
|
|
|
func _run() -> void:
|
|
var test_directory := "user://save_slot_test_%s" % Time.get_ticks_usec()
|
|
var store := SaveSlotStore.new(test_directory)
|
|
var manager: Node = load("res://simulation/SimulationManager.gd").new()
|
|
manager.debug_logs = false
|
|
root.add_child(manager)
|
|
manager.set_process(false)
|
|
|
|
for step in 8:
|
|
manager.simulate_tick()
|
|
var saved_checksum: String = manager.get_state_checksum()
|
|
_check(store.save(manager), "A valid simulation should save atomically")
|
|
_check(store.has_slot(), "The validated quicksave should be discoverable")
|
|
|
|
for step in 5:
|
|
manager.simulate_tick()
|
|
_check(
|
|
manager.get_state_checksum() != saved_checksum,
|
|
"The scenario should change after the save point"
|
|
)
|
|
_check(store.load_into(manager), "A valid quicksave should load")
|
|
_check(
|
|
manager.get_state_checksum() == saved_checksum,
|
|
"Loading should restore the exact saved simulation"
|
|
)
|
|
|
|
var final_path := store.get_slot_path()
|
|
var backup_path := final_path + ".bak"
|
|
_check(
|
|
DirAccess.rename_absolute(final_path, backup_path) == OK,
|
|
"Test should reproduce the atomic replacement recovery window"
|
|
)
|
|
_check(
|
|
store.load_into(manager),
|
|
"A preserved previous save should recover an interrupted replacement"
|
|
)
|
|
_check(
|
|
DirAccess.rename_absolute(backup_path, final_path) == OK,
|
|
"Test should restore the primary save path"
|
|
)
|
|
|
|
var unchanged_checksum: String = manager.get_state_checksum()
|
|
var file := FileAccess.open(final_path, FileAccess.WRITE)
|
|
file.store_string("{\"schema\":\"broken\"}")
|
|
file.close()
|
|
_check(not store.load_into(manager), "Invalid save data should be rejected")
|
|
_check(
|
|
manager.get_state_checksum() == unchanged_checksum,
|
|
"A rejected save must not partially mutate the simulation"
|
|
)
|
|
_check(
|
|
not store.save(manager, "../escape"),
|
|
"Slot names must not escape the save directory"
|
|
)
|
|
|
|
store.delete_slot()
|
|
DirAccess.remove_absolute(ProjectSettings.globalize_path(test_directory))
|
|
if failures.is_empty():
|
|
print("[TEST] Save-slot persistence passed")
|
|
quit(0)
|
|
return
|
|
for failure in failures:
|
|
push_error("[TEST] " + failure)
|
|
quit(1)
|
|
|
|
func _check(condition: bool, message: String) -> void:
|
|
if not condition:
|
|
failures.append(message)
|