fix(test): use composition.reg_id for entity equality in assertions

get_children() returns fresh userdata wrappers on each call; without
an __eq metamethod, Lua pointer equality fails between two wrappers of
the same engine entity. Use composition.reg_id (a stable property on
all composition entities) for same_entity() comparisons in assertions
2b, 3b, 9, 10, 11b.
This commit is contained in:
Calic
2026-06-13 17:35:11 +02:00
parent 3ae9799d4d
commit 73298a99aa

View File

@@ -8,6 +8,21 @@ local T = engine.test
local M = {}
-- entity.get_children() returns fresh userdata wrappers on each call;
-- there is no __eq on entity userdata, so == is Lua-pointer equality
-- (always false for different wrappers of the same engine entity).
-- Compare by composition.reg_id (stable property on all composition
-- entities) instead.
local function same_entity(a, b)
local ra = a and a:get_property("composition.reg_id")
local rb = b and b:get_property("composition.reg_id")
if ra and ra ~= 0 and rb and rb ~= 0 then
return ra == rb
end
-- Fallback for raw entities: pointer equality (may be unreliable).
return a == b
end
-- ----------------------------------------------------------------
-- Template definitions (shared across tests)
-- All template names are unique within this test run.
@@ -120,7 +135,7 @@ function M.run_tests(ctx)
local contents2 = inventory.contents(bag1)
local found_sword1 = false
for _, it in ipairs(contents2) do
if it == sword1 then found_sword1 = true; break end
if same_entity(it, sword1) then found_sword1 = true; break end
end
T.assert(found_sword1,
"2b. after add: contents(container) contains item")
@@ -143,8 +158,8 @@ function M.run_tests(ctx)
local found3_s = false
local found3_p = false
for _, it in ipairs(contents3) do
if it == sword3 then found3_s = true end
if it == potion3 then found3_p = true end
if same_entity(it, sword3) then found3_s = true end
if same_entity(it, potion3) then found3_p = true end
end
T.assert(found3_s and found3_p,
"3b. two adds → both items in contents")
@@ -200,24 +215,18 @@ function M.run_tests(ctx)
"7. add item with stack_mode='stack' → Loud-Error")
-- ================================================================
-- Assertion 8: add to container with kind != "list" → Loud-Error
-- (Template-level catch already fires, but runtime check is the
-- double-belt tested here via a raw entity.create() bypass.)
-- We test the double-belt by attempting to add to a composition
-- entity whose template has a deferred constraint — this cannot
-- be constructed via define_template (it loud-errors), so we test
-- the "no container block" path which is the closest available
-- runtime-only path not gated by template-load.
-- The template-level gate for kind!="list" is covered in
-- composition-test (assertion 6 there). Here we verify inventory
-- itself also loud-errors on a non-container-template entity.
-- Assertion 8: add on non-composition entity (no reg_id) → Loud-Error
-- Uses raw entity.create() (not composition.create) so the entity
-- has no composition.reg_id. composition.get_container returns nil,
-- which propagates through validate_container as a Loud-Error.
-- Distinct from assertion 5 (composition entity, no container block).
-- ================================================================
local plain8 = composition.create{ template = "inv_test.plain_entity" }
local raw8 = entity.create()
local sword8 = composition.create{ template = "inv_test.sword" }
local ok8 = pcall(inventory.add, plain8, sword8)
local ok8 = pcall(inventory.add, raw8, sword8)
T.assert(not ok8,
"8. add to entity with no container block (non-container) → Loud-Error")
"8. add on non-composition entity (no reg_id) → Loud-Error")
-- ================================================================
-- Assertion 9: add sets renderable tag off on item
@@ -230,7 +239,7 @@ function M.run_tests(ctx)
local renderable_before9 = composition.list_by_tag("renderable")
local in_renderable_before9 = false
for _, e in ipairs(renderable_before9) do
if e == sword9 then in_renderable_before9 = true; break end
if same_entity(e, sword9) then in_renderable_before9 = true; break end
end
T.assert(in_renderable_before9,
"9a. item is in renderable index before add")
@@ -240,7 +249,7 @@ function M.run_tests(ctx)
local renderable_after9 = composition.list_by_tag("renderable")
local in_renderable_after9 = false
for _, e in ipairs(renderable_after9) do
if e == sword9 then in_renderable_after9 = true; break end
if same_entity(e, sword9) then in_renderable_after9 = true; break end
end
T.assert(not in_renderable_after9,
"9b. add: item removed from renderable index via composition.set_tag")
@@ -254,7 +263,7 @@ function M.run_tests(ctx)
local renderable_after_remove10 = composition.list_by_tag("renderable")
local restored10 = false
for _, e in ipairs(renderable_after_remove10) do
if e == sword9 then restored10 = true; break end
if same_entity(e, sword9) then restored10 = true; break end
end
T.assert(restored10,
"10. remove: item restored to renderable index via composition.set_tag")
@@ -285,16 +294,13 @@ function M.run_tests(ctx)
local contents11 = inventory.contents(bag11)
T.assert(#contents11 == 2 and
contents11[1] == item11a and
contents11[2] == item11b,
same_entity(contents11[1], item11a) and
same_entity(contents11[2], item11b),
"11b. reconstruction: contents ordered by slot-n, items correct")
-- Next add must land on item.8 (max=7, so 7+1=8), not item.1.
local item11c = composition.create{ template = "inv_test.sword" }
-- item11c starts renderable; set_tag will be called by add.
-- But item11a and item11b were attached directly (bypass add),
-- so we must declare stack_mode; they have it via template.
-- Detach item11c from any parent first (it has none here).
-- item11c has no prior parent; set_tag is invoked by add.
inventory.add(bag11, item11c)
local children11 = bag11:get_children()
T.assert(children11["item.8"] ~= nil,