commit 985846a9dfdfc055435b9a885d092ce6b464198a Author: Axel Meyer Date: Sun May 24 01:28:22 2026 +0200 Scaffold sporel-module-map-editor-test Headless test module that exercises the lib-core.maps v0.4.0 write APIs end-to-end: load fixture map, paint cells with rotation and auto-allocate the wall layer, set roof flags, save to a temp file, re-load (under a patched id to dodge registry collision), and assert state round-trips. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8c5509c --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# sporel-module-map-editor-test + +Headless asserts for the editor's API chain: load a fresh map, paint and erase cells, set roof flags, save to disk, re-load, verify state round-trips. + +Launches as a `kind=test-module` — all asserts run in `init()` and the module exits. + +```bash +$SPOREL_BIN --module sporel-module-map-editor-test +``` + +Or via the engine's `test-all-modules.sh` aggregator (auto-discovers `kind:test-module`). diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..e503adf --- /dev/null +++ b/init.lua @@ -0,0 +1,88 @@ +-- sporel-module-map-editor-test v0.1.0 +-- Headless asserts for the editor's API chain: +-- load → paint → erase → roof → save → re-load → verify. +-- +-- Pattern: kind=test-module; all assertions run in init(), engine exits after. + +local maps = require("lib-core.maps") + +function init() + -- 1. Load fresh test map. + -- "maps/test_work.map.json" resolves relative to this module's dir via the + -- asset sandbox (engine_path_resolve_asset tries loaded_module.path/). + local map_id = maps.load("maps/test_work.map.json") + maps.set_current(map_id) + + -- 2. Paint a surface cell at (2,3) with atlas=0, tile=1, rot=0. + local gid_grass = maps.encode_gid(0, 1, 0) + maps.set_cell_gid("surface", 2, 3, gid_grass) + engine.test.equals(maps.cell_gid("surface", 2, 3), gid_grass, + "paint surface (2,3) with grass round-trips via cell_gid") + + -- 3. Paint with rotation=2. + local gid_rotated = maps.encode_gid(0, 1, 2) + maps.set_cell_gid("surface", 0, 0, gid_rotated) + engine.test.equals(maps.cell_gid("surface", 0, 0), gid_rotated, + "paint surface (0,0) with rotated grass round-trips") + + -- 4. Auto-allocate wall layer. + engine.test.equals(maps.cell_gid("wall", 1, 1), 0, + "wall layer empty before any write") + maps.set_cell_gid("wall", 1, 1, gid_grass) + engine.test.equals(maps.cell_gid("wall", 1, 1), gid_grass, + "wall layer auto-allocated by set_cell_gid") + + -- 5. Roof set. + maps.set_roof(1, 1, 1) + maps.set_roof(2, 2, 1) + + -- 6. Erase one of the surface cells. + maps.set_cell_gid("surface", 2, 3, 0) + engine.test.equals(maps.cell_gid("surface", 2, 3), 0, + "erase surface (2,3) sets it back to 0") + + -- 7. Save to a path inside the module's writeable area. + -- engine.module.dir_of returns ctx->loaded_module.path — the installed dir + -- of this module. io.open with an absolute path bypasses the asset sandbox. + local module_dir = engine.module.dir_of("sporel-module-map-editor-test") + local out_path = module_dir .. "/maps/test_work_saved.map.json" + maps.save_to_disk(map_id, out_path) + + -- 8. Verify the saved file is readable and contains expected keys. + local f = io.open(out_path, "r") + engine.test.assert(f ~= nil, "saved file is readable") + local content = f:read("*a") + f:close() + engine.test.assert(content:find('"schema_version"') ~= nil, + "saved file has schema_version key") + engine.test.assert(content:find('"surface"') ~= nil, + "saved file has surface key") + engine.test.assert(content:find('"wall"') ~= nil, + "saved file has wall key (auto-allocated)") + engine.test.assert(content:find('"roof"') ~= nil, + "saved file has roof key (auto-allocated)") + + -- 9. Re-load under a patched id to avoid registry collision. + -- Write via absolute path (bypasses sandbox); load via relative path + -- (engine.asset.load_json resolves against loaded_module.path == module_dir). + local rewritten = content:gsub('"id"%s*:%s*"test_work"', '"id":"test_work_reloaded"') + local rl_path = module_dir .. "/maps/test_work_reloaded.map.json" + local rf = io.open(rl_path, "w") + rf:write(rewritten) + rf:close() + maps.load("maps/test_work_reloaded.map.json") + + -- 10. Verify state round-trips. + engine.test.equals(maps.cell_gid("surface", 0, 0, "test_work_reloaded"), gid_rotated, + "save+reload preserves surface (0,0) rotated grass") + engine.test.equals(maps.cell_gid("wall", 1, 1, "test_work_reloaded"), gid_grass, + "save+reload preserves wall (1,1) grass") + engine.test.equals(maps.cell_gid("surface", 2, 3, "test_work_reloaded"), 0, + "save+reload preserves erased cell (0)") + + -- Cleanup temp files. + os.remove(out_path) + os.remove(rl_path) + + engine.print("map-editor-test: all asserts passed") +end diff --git a/manifest.core b/manifest.core new file mode 100644 index 0000000..d4d2f4b --- /dev/null +++ b/manifest.core @@ -0,0 +1,6 @@ +{ + "id": "sporel-module-map-editor-test.core", + "kind": "lib", + "version": "0.1.0", + "license": "Proprietary" +} diff --git a/manifest.module b/manifest.module new file mode 100644 index 0000000..6b7fe8a --- /dev/null +++ b/manifest.module @@ -0,0 +1,14 @@ +{ + "id": "sporel-module-map-editor-test", + "version": "0.1.0", + "kind": "test-module", + "api": "^0.1", + "entry_point": "init.lua", + "asset_aliases": { + "fa_terrain_v1": "lib-asset.prototype-fa-starter" + }, + "deps": [ + {"id":"lib-core.maps","version":"0.4.0"}, + {"id":"lib-asset.prototype-fa-starter","version":"0.2.0"} + ] +} diff --git a/maps/test_work.map.json b/maps/test_work.map.json new file mode 100644 index 0000000..69c08ec --- /dev/null +++ b/maps/test_work.map.json @@ -0,0 +1,11 @@ +{ + "schema_version": 2, + "id": "test_work", + "size": { "w": 4, "h": 4 }, + "atlases": ["fa_terrain_v1"], + "layers": { + "surface": { + "tiles": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + } + } +}