test(composition): assert set_tag round-trip + container-block validation
8 new assertions covering v0.2 surface:
- set_tag adds entity to tag-index (assert 15)
- set_tag removes entity from tag-index (assert 16)
- set_tag is idempotent for both add and remove (asserts 17-18)
- set_tag loud-errors on non-composition entity (assert 19)
- define_template accepts container={kind="list"} (assert 20)
- define_template loud-errors on container={kind="grid"} (assert 21)
- define_template loud-errors on container with weight_max (assert 22)
- slots Loud-Error regression: still fires after v0.2 changes (assert 23)
Manifest version bumped to 0.2.0; composition dep bumped to 0.2.0.
This commit is contained in:
92
init.lua
92
init.lua
@@ -1,5 +1,6 @@
|
|||||||
-- lib-core.composition-test — Phase A.1
|
-- lib-core.composition-test — Phase A.1 + B.1
|
||||||
-- 14 assertions: 4 define_template + 4 create + 3 list_by_* + 2 destroy + 1 list_templates.
|
-- 23 assertions: 4 define_template + 4 create + 3 list_by_* + 2 destroy + 1 list_templates
|
||||||
|
-- + 8 B.1 (set_tag round-trip + container-block validation) + 1 slots regression.
|
||||||
-- Pattern follows P.2.4 Test-Module-Pattern; TAP output via engine.test.*
|
-- Pattern follows P.2.4 Test-Module-Pattern; TAP output via engine.test.*
|
||||||
|
|
||||||
local composition = require("lib-core.composition")
|
local composition = require("lib-core.composition")
|
||||||
@@ -106,6 +107,93 @@ function M.run_tests(ctx)
|
|||||||
-- list_templates is non-empty after define
|
-- list_templates is non-empty after define
|
||||||
T.assert(#composition.list_templates() >= 1,
|
T.assert(#composition.list_templates() >= 1,
|
||||||
"list_templates returns at least 1 entry after define_template")
|
"list_templates returns at least 1 entry after define_template")
|
||||||
|
|
||||||
|
-- ================================================================
|
||||||
|
-- B.1 — set_tag + container-block validation (8)
|
||||||
|
-- ================================================================
|
||||||
|
|
||||||
|
-- Need a live entity to test set_tag against.
|
||||||
|
local tagtest_entity = composition.create{ template = "sign" }
|
||||||
|
|
||||||
|
-- 1. set_tag(e, "foo", true) → list_by_tag("foo") contains e.
|
||||||
|
composition.set_tag(tagtest_entity, "foo", true)
|
||||||
|
local foo_list_after_add = composition.list_by_tag("foo")
|
||||||
|
local found_in_foo = false
|
||||||
|
for _, e in ipairs(foo_list_after_add) do
|
||||||
|
if e == tagtest_entity then found_in_foo = true; break end
|
||||||
|
end
|
||||||
|
T.assert(found_in_foo, "set_tag(e,'foo',true) adds e to list_by_tag('foo')")
|
||||||
|
|
||||||
|
-- 2. set_tag(e, "foo", false) → list_by_tag("foo") does not contain e.
|
||||||
|
composition.set_tag(tagtest_entity, "foo", false)
|
||||||
|
local foo_list_after_remove = composition.list_by_tag("foo")
|
||||||
|
local still_in_foo = false
|
||||||
|
for _, e in ipairs(foo_list_after_remove) do
|
||||||
|
if e == tagtest_entity then still_in_foo = true; break end
|
||||||
|
end
|
||||||
|
T.assert(not still_in_foo, "set_tag(e,'foo',false) removes e from list_by_tag('foo')")
|
||||||
|
|
||||||
|
-- 3. set_tag idempotent — double true and double false must not error
|
||||||
|
-- and must not duplicate / extra-remove entries.
|
||||||
|
composition.set_tag(tagtest_entity, "bar", true)
|
||||||
|
composition.set_tag(tagtest_entity, "bar", true) -- second call: idempotent
|
||||||
|
local bar_list = composition.list_by_tag("bar")
|
||||||
|
local bar_count = 0
|
||||||
|
for _, e in ipairs(bar_list) do
|
||||||
|
if e == tagtest_entity then bar_count = bar_count + 1 end
|
||||||
|
end
|
||||||
|
T.equals(bar_count, 1, "set_tag idempotent: double-true does not duplicate in index")
|
||||||
|
|
||||||
|
composition.set_tag(tagtest_entity, "bar", false)
|
||||||
|
composition.set_tag(tagtest_entity, "bar", false) -- second call: idempotent
|
||||||
|
local bar_list_after = composition.list_by_tag("bar")
|
||||||
|
local bar_count_after = 0
|
||||||
|
for _, e in ipairs(bar_list_after) do
|
||||||
|
if e == tagtest_entity then bar_count_after = bar_count_after + 1 end
|
||||||
|
end
|
||||||
|
T.equals(bar_count_after, 0, "set_tag idempotent: double-false does not error or leave stale entry")
|
||||||
|
|
||||||
|
-- 4. set_tag on a foreign (non-composition) entity → Loud-Error.
|
||||||
|
local alien = entity.create()
|
||||||
|
local ok_alien = pcall(composition.set_tag, alien, "any", true)
|
||||||
|
T.assert(not ok_alien, "set_tag loud-errors on entity not created by composition")
|
||||||
|
|
||||||
|
-- 5. define_template with container={kind="list"} → accepted (no error).
|
||||||
|
local ok_container_list = pcall(composition.define_template, {
|
||||||
|
id = "backpack",
|
||||||
|
properties = {
|
||||||
|
sprite_atlas = "sprites/items.png",
|
||||||
|
sprite_uv = "0 0 32 32",
|
||||||
|
position = {x = 0, y = 0},
|
||||||
|
},
|
||||||
|
tags = {"renderable"},
|
||||||
|
container = { kind = "list" },
|
||||||
|
})
|
||||||
|
T.assert(ok_container_list, "define_template accepts container={kind='list'}")
|
||||||
|
|
||||||
|
-- 6. define_template with container={kind="grid"} → Loud-Error.
|
||||||
|
local ok_container_grid = pcall(composition.define_template, {
|
||||||
|
id = "grid_bag",
|
||||||
|
container = { kind = "grid" },
|
||||||
|
})
|
||||||
|
T.assert(not ok_container_grid, "define_template loud-errors on container={kind='grid'}")
|
||||||
|
|
||||||
|
-- 7. define_template with container={kind="list", weight_max=10} → Loud-Error
|
||||||
|
-- (unimplemented constraint field declared).
|
||||||
|
local ok_weight_max = pcall(composition.define_template, {
|
||||||
|
id = "heavy_bag",
|
||||||
|
container = { kind = "list", weight_max = 10 },
|
||||||
|
})
|
||||||
|
T.assert(not ok_weight_max,
|
||||||
|
"define_template loud-errors on container with unimplemented constraint weight_max")
|
||||||
|
|
||||||
|
-- 8. define_template with slots={...} → still Loud-Error (Phase D, regression).
|
||||||
|
local ok_slots_regression = pcall(composition.define_template, {
|
||||||
|
id = "composite_sword",
|
||||||
|
slots = { blade = {} },
|
||||||
|
})
|
||||||
|
T.assert(not ok_slots_regression,
|
||||||
|
"define_template still loud-errors on 'slots' block (Phase D regression)")
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"id": "lib-core.composition-test",
|
"id": "lib-core.composition-test",
|
||||||
"role": "test",
|
"role": "test",
|
||||||
"version": "0.1.0",
|
"version": "0.2.0",
|
||||||
"api_min": "0.1",
|
"api_min": "0.1",
|
||||||
"deps": [
|
"deps": [
|
||||||
{"id": "lib-core.composition", "version": "0.1.0"}
|
{"id": "lib-core.composition", "version": "0.2.0"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user