Files
TheTree_mock/tests/s1/test_path_snapshot_transit_guard.gd
Takeshi b84bade045 Save The Tree implementation and acceptance work in progress
Preserve production code, regression fixtures, audio assets and provenance, test infrastructure, and the original-completion plan and progress ledger. Final game and Windows acceptance remain pending; excluded local artifacts and native experiments are not part of this snapshot.
2026-10-11 15:58:00 +09:00

83 lines
4.8 KiB
GDScript

extends SceneTree
## A corrupt transit ID must reject the entire save projection without losing
## real cabin occupants or making the infrastructure collision check fail open.
var checks := 0
var failures := 0
func _initialize() -> void:
call_deferred("run")
func expect(ok: bool, label: String) -> void:
checks += 1
if not ok:
failures += 1
push_error(label)
func run() -> void:
var path := PathService.new()
var cells: Array[Vector3i] = [Vector3i.ZERO, Vector3i(0, 1, 0)]
expect(path.rebuild_graph(cells), "build a normal graph")
expect(path.configure_elevator(&"lift", cells[0], cells[1], {&"cabin_capacity": 2}), "configure a real cabin")
for actor: StringName in [&"guest:a", &"guest:b"]:
expect(path.project_actor_position(actor, cells[0], 10), "position cabin passenger")
expect(path.enqueue_elevator_request(&"lift", {
&"request_id": StringName("ride." + String(actor)), &"unit_id": actor,
&"floor_from": 0, &"floor_to": 1, &"enqueued_at": 10,
})[&"ok"], "queue real passenger")
expect(path.dequeue_elevator_boarding(&"lift", 0, 11, 2).size() == 2, "board both passengers")
var valid: Dictionary = path.create_snapshot()
expect(valid[&"transit_actor_ids"].size() == 2, "normal save keeps both cabin occupants")
for bad_id: Variant in [123, true, 1.25, Vector3i(3, 2, 1), null]:
path._transit_actor_ids[bad_id] = true
var before := var_to_bytes(path._transit_actor_ids)
var saved: Dictionary = path.create_snapshot()
expect(saved.is_empty(), "unsupported transit ID rejects the whole projection")
expect(var_to_bytes(path._transit_actor_ids) == before, "refusal preserves all transit IDs")
expect(FacilityInfrastructureProjector._has_managed_namespace_collision(SpatialSubslotService.new(), path, {}), "consumer refuses rejected snapshot")
saved[&"caller"] = true
expect(path.create_snapshot().is_empty(), "repeat refusal returns a new empty projection")
path._transit_actor_ids.erase(bad_id)
expect(var_to_bytes(path.create_snapshot()) == var_to_bytes(valid), "correction recovers both original occupants")
var restored := PathService.new()
expect(restored.restore_snapshot(valid) and restored.rebuild_graph(cells), "save restores real passenger references")
expect(var_to_bytes(restored.create_snapshot()) == var_to_bytes(valid), "restored full save matches original")
_test_incomplete_runtime_path_save()
print("Path snapshot transit guard: %d checks, %d failures" % [checks, failures])
quit(1 if failures else 0)
func _test_incomplete_runtime_path_save() -> void:
var clock: Variant = load("res://autoload/game_clock.gd").new()
var state: Variant = load("res://autoload/game_state.gd").new()
var runtime: Variant = load("res://autoload/simulation_runtime.gd").new()
clock.reset(1, 6, 0); state.reset(); clock.set_paused(true)
expect(runtime.initialize(clock, state, 806042)[&"valid"], "save boundary Runtime initializes")
runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
var slot := "user://saves/path_transit_guard"
expect(runtime.save_to_path(slot)[&"ok"], "healthy formal save succeeds")
var members: Dictionary = {}
for name: String in ["manifest.json", "world.bin", "thumbnail.png", "journal.log"]:
members[name] = FileAccess.get_file_as_bytes(slot.path_join(name))
runtime.path_service._transit_actor_ids[123] = true
var raw_transit := var_to_bytes(runtime.path_service._transit_actor_ids)
var before := var_to_bytes(runtime.create_snapshot())
var result: Dictionary = runtime.save_to_path(slot)
expect(not result[&"ok"] and result[&"code"] == &"INVALID_SNAPSHOT", "incomplete Path refuses whole Runtime save")
expect(var_to_bytes(runtime.create_snapshot()) == before, "refusal preserves all typed Runtime fields and events")
expect(var_to_bytes(runtime.path_service._transit_actor_ids) == raw_transit, "refusal preserves corrupt IDs instead of repairing")
clock.set_paused(false)
var auto_before := var_to_bytes(runtime.create_snapshot())
var autosave: Dictionary = runtime._perform_checkpoint_save(slot, {}, true, &"autosave", 17)
expect(not autosave[&"ok"] and autosave[&"code"] == &"INVALID_SNAPSHOT", "shared autosave writer refuses incomplete Path")
expect(var_to_bytes(runtime.create_snapshot()) == auto_before and not clock.paused, "autosave refusal preserves running clock and every state/event field")
var unchanged := true
for name: String in members:
unchanged = unchanged and FileAccess.get_file_as_bytes(slot.path_join(name)) == members[name]
expect(unchanged, "refusal preserves every formal member")
expect(not DirAccess.dir_exists_absolute(slot + ".tmp") and not DirAccess.dir_exists_absolute(slot + ".bak"), "refusal creates no new temporary or backup package")
runtime.path_service._transit_actor_ids.erase(123)
expect(runtime.load_from_path(slot)[&"ok"], "original formal save remains loadable after refusal")
runtime.free(); clock.free(); state.free()