test: de-duplication + malformed-locale assertions

§19 verifies sources={c, c} is de-duplicated (have=1, not 2).
§20 verifies {sink=c} without sources raises a loud-error
attributing crafting + sources.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Calic
2026-06-14 19:29:51 +02:00
parent ccaed2d0de
commit 17857ccbc2

View File

@@ -1,5 +1,7 @@
-- lib-core.crafting-test — Phase C.1
-- 12 assertions: 5 registry (define_recipe + list + get) + 7 discovery/match/craft.
-- lib-core.crafting-test — Phase C.1 + D.0
-- 20 assertions: 12 base (registry + discovery/match/craft), 6 locale-API
-- (Form-2 happy + greedy-drain + aggregate + Loud-Errors), 2 silent-fail
-- regressions (duplicate-sources de-dup + malformed-locale loud-error).
-- Pattern follows P.2.4 Test-Module-Pattern; TAP output via engine.test.*
local composition = require("lib-core.composition")
@@ -531,6 +533,73 @@ function M.run_tests(ctx)
and string.find(err18, "sink") ~= nil
and string.find(err18, "nil") ~= nil,
"18. Loud-Error: locale.sink=nil → error mentions 'crafting', 'sink', 'nil'")
-- ================================================================
-- §19: Duplicate sources are de-duplicated.
-- Single container with 1 rock; pass {c, c} as sources.
-- count_by_template must NOT double-count → can_craft for a
-- recipe needing 2 rocks reports have=1 (not 2).
-- ================================================================
local c_19 = setup_container{
{ template = "craft_test.rock", count = 1 },
}
composition.define_template{
id = "craft_test.rock_pile_19",
properties = {
stack_mode = "individual",
sprite_path = "sprites/pile.png",
position = {x = 0, y = 0},
},
tags = {"renderable", "item"},
}
crafting.define_recipe{
id = "r2rocks_19",
inputs = { { template = "craft_test.rock", count = 2 } },
output = { template = "craft_test.rock_pile_19", count = 1 },
}
local cc19 = crafting.can_craft("r2rocks_19",
{ sources = {c_19, c_19}, sink = c_19 }, {})
local missing_match_19 = false
if cc19.missing then
for _, m in ipairs(cc19.missing) do
if m.template == "craft_test.rock"
and m.needed == 2 and m.have == 1 then
missing_match_19 = true; break
end
end
end
T.assert(cc19.ok == false and cc19.error == "missing_inputs"
and missing_match_19,
"19. Duplicate sources de-duplicated: sources={c,c} with 1 rock reports have=1 (not 2)")
-- ================================================================
-- §20: Loud-Error — Form-2 table without sources field.
-- Caller typo passes {sink=c} without sources. resolve_locale
-- must loud-error attributing crafting + sources, not silently
-- fall through to the Form-1 bw-compat shim (which would then
-- crash deep inside inventory-list).
-- ================================================================
local c_20 = setup_container{}
composition.define_template{
id = "craft_test.x_20",
properties = {
stack_mode = "individual",
sprite_path = "sprites/x.png",
position = {x = 0, y = 0},
},
tags = {"renderable", "item"},
}
crafting.define_recipe{
id = "rp_20",
inputs = { { template = "craft_test.rock", count = 1 } },
output = { template = "craft_test.x_20", count = 1 },
}
local malformed_20 = { sink = c_20 }
local ok20, err20 = pcall(crafting.craft, "rp_20", malformed_20, {})
T.assert(not ok20 and type(err20) == "string"
and string.find(err20, "crafting") ~= nil
and string.find(err20, "sources") ~= nil,
"20. Loud-Error: locale table without 'sources' field → error mentions 'crafting' and 'sources'")
end
return M