Add save_to_disk round-trip and determinism asserts

Verifies the saved JSON is readable, that two successive saves
produce byte-identical output, and that re-loading the saved file
recovers the same cell values that were written before saving.
Uses engine.module.dir_of to write the round-trip fixture to the
lib maps/ directory (asset sandbox rejects absolute temp paths).
This commit is contained in:
Axel Meyer
2026-05-24 00:43:31 +02:00
parent e399f6c6f8
commit e082a39596

View File

@@ -300,6 +300,63 @@ function M.run_tests(ctx)
local ok_b = pcall(function() maps.set_roof(4, 0, 1) end)
engine.test.assert(not ok_b, "set_roof rejects x out of bounds")
-- ---------- v0.4.0: save_to_disk ----------
-- Map state from Task 1+2: surface(1,2) = gid_painted, wall(2,2) = gid_painted,
-- roof(2,2) = 1. Save and re-load to verify round-trip.
-- Re-establish deterministic state (defensive — earlier asserts may have toggled).
maps.set_cell_gid("surface", 1, 2, gid_painted)
maps.set_cell_gid("wall", 2, 2, gid_painted)
maps.set_roof(2, 2, 1)
-- Pick a temp path. Use TEMP env var for Windows compatibility; fall back to
-- os.tmpname() on POSIX (where it returns a writable path).
local tmp_dir = os.getenv("TEMP") or os.getenv("TMP") or "/tmp"
-- Unique suffix via os.clock() + os.time() to avoid collisions.
local tmp_suffix = string.format("sporel_maps_test_%d_%d", os.time(), math.floor(os.clock() * 1e6) % 1000000)
local out_path = tmp_dir .. "/" .. tmp_suffix .. "_1.json"
local out_path_2 = tmp_dir .. "/" .. tmp_suffix .. "_2.json"
local rl_path = tmp_dir .. "/" .. tmp_suffix .. "_rl.json"
maps.save_to_disk("write_test", out_path)
-- Re-read raw bytes for byte-determinism test
local f1 = io.open(out_path, "r")
engine.test.assert(f1 ~= nil, "save_to_disk wrote a readable file")
local bytes_1 = f1:read("*a")
f1:close()
-- Save a second time; bytes must match exactly
maps.save_to_disk("write_test", out_path_2)
local f2 = io.open(out_path_2, "r")
local bytes_2 = f2:read("*a")
f2:close()
engine.test.equals(bytes_1, bytes_2,
"save_to_disk is byte-deterministic across calls")
-- Verify JSON has expected keys
engine.test.assert(bytes_1:find('"schema_version"') ~= nil, "saved file has schema_version key")
engine.test.assert(bytes_1:find('"surface"') ~= nil, "saved file has surface key")
engine.test.assert(bytes_1:find('"wall"') ~= nil, "saved file has wall key (auto-allocated)")
engine.test.assert(bytes_1:find('"roof"') ~= nil, "saved file has roof key (set in Task 2)")
-- Re-load (with patched id to avoid registry collision).
-- engine.asset.load_json only accepts relative (sandboxed) paths, so write
-- the round-trip file into the maps-test lib's own maps/ directory where
-- the asset resolver can find it by relative path.
local lib_dir = engine.module.dir_of("lib-core.maps-test")
local rewritten = bytes_1:gsub('"id"%s*:%s*"write_test"', '"id":"write_test_reloaded"')
local abs_rl_path = lib_dir .. "/maps/write_test_reloaded.map.json"
local rf = io.open(abs_rl_path, "w"); rf:write(rewritten); rf:close()
maps.load("maps/write_test_reloaded.map.json")
engine.test.equals(maps.cell_gid("surface", 1, 2, "write_test_reloaded"), gid_painted,
"save round-trip preserves surface cell")
engine.test.equals(maps.cell_gid("wall", 2, 2, "write_test_reloaded"), gid_painted,
"save round-trip preserves wall cell")
-- Cleanup
os.remove(out_path); os.remove(out_path_2); os.remove(abs_rl_path)
engine.exit(engine.test.failures())
end