test: v0.2.0 locale_factory + ctx_inner alias assertions

Three new TAP cases cover the locale_factory rollout:

- §10 Form-1 bw-compat: display.create(container) wraps the bare
  handle as a constant locale_factory; _test_get_locale returns the
  same handle, _test_get_rows still resolves single-source
  availability via the Form-1 shim.
- §11 Form-2 locale-factory: display.create(function() -> {sources,
  sink}) returns the locale table per frame; a recipe needing two
  templates split across two source-containers reports aggregate
  availability=true.
- §12 ctx_inner propagation: monkey-patching panel.show_context_menu
  captures the entries-table, then invokes the action callback with
  a dummy menu_ctx. Asserts ctx_inner.locale matches the resolved
  locale and ctx_inner.container points at locale.sink (Form-2) or
  the bare handle (Form-1).

Test count grows 9 -> 12. Added a fresh_container helper so the
multi-container fixtures in §11/§12 do not lose recipes via repeated
_test_clear_all calls.

Depends on lib-core.crafting-display v0.2.0 and lib-core.crafting
v0.2.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Calic
2026-06-14 19:43:59 +02:00
parent b88842161c
commit 6f9ceebe66
2 changed files with 163 additions and 7 deletions

164
init.lua
View File

@@ -1,13 +1,16 @@
-- lib-core.crafting-display-test — v0.1.0
-- 9 assertions covering widget creation, action lifecycle, default-empty,
-- row visibility (is_known filter), per-row availability, resolver overrides,
-- and the panel widget-contract (render(ctx) populating _render_rows).
-- lib-core.crafting-display-test — v0.2.0
-- 12 assertions: 9 v0.1 existing (widget creation, action lifecycle,
-- default-empty, row visibility, per-row availability, resolver
-- overrides, panel widget-contract) + 3 v0.2 new (Form-1 bw-compat
-- entity-handle, Form-2 locale-factory with multi-source aggregate
-- availability, ctx_inner.locale + container alias propagation).
-- Pattern follows P.2.4 Test-Module-Pattern; TAP output via engine.test.*
local composition = require("lib-core.composition")
local inventory = require("lib-core.inventory-list")
local crafting = require("lib-core.crafting")
local display = require("lib-core.crafting-display")
local panel = require("lib-core.panel")
local T = engine.test
local M = {}
@@ -74,6 +77,22 @@ local function setup_container(items)
return container
end
-- fresh_container builds a populated container without touching the
-- recipe-registry. Used in §11 to create a second container after
-- setup_container has already been called for the first one (so the
-- multi-source locale test has two distinct containers without losing
-- the just-defined recipe).
local function fresh_container(items)
local container = composition.create{ template = "craft_display_test.container" }
for _, spec in ipairs(items) do
for _ = 1, spec.count do
local e = composition.create{ template = spec.template }
inventory.add(container, e)
end
end
return container
end
-- ---------------------------------------------------------------------
-- Tests
-- ---------------------------------------------------------------------
@@ -261,6 +280,143 @@ function M.run_tests(_ctx)
and widget9._render_rows[1].recipe_id == "render_r9",
"9. widget.render(ctx) per panel widget contract populates _render_rows"
.. (render_ok and "" or (" (render errored: " .. tostring(render_err) .. ")")))
-- ================================================================
-- §10 (v0.2): Form-1 bw-compat — create(container, opts) with bare
-- handle. _test_get_locale returns the same handle; _test_get_rows
-- still works (single-source availability via Form-1 shim).
-- ================================================================
local container10 = setup_container{
{ template = "craft_display_test.rock", count = 1 },
}
crafting.define_recipe{
id = "form1_r10",
inputs = { { template = "craft_display_test.rock", count = 1 } },
output = { template = "craft_display_test.rock_pick", count = 1 },
name = "Form-1 Recipe",
}
local widget10 = display.create(container10)
local locale10 = display._test_get_locale(widget10)
local rows10 = display._test_get_rows(widget10)
T.assert(locale10 == container10
and #rows10 == 1
and rows10[1].recipe.id == "form1_r10"
and rows10[1].available == true,
"10. Form-1 bw-compat: _test_get_locale returns bare handle; "
.. "rows resolve via Form-1 shim with correct availability")
-- ================================================================
-- §11 (v0.2): Form-2 locale-factory — create(function() -> locale).
-- locale = {sources={c1,c2}, sink=c1}. Recipe needs rock + stick;
-- rock lives in c1, stick in c2. Aggregate availability across
-- sources => row.available == true.
-- ================================================================
-- Re-initialise registry, define recipe first so both containers
-- can be created after via fresh_container without recipe loss.
crafting._test_clear_all()
crafting.define_recipe{
id = "form2_r11",
inputs = {
{ template = "craft_display_test.rock", count = 1 },
{ template = "craft_display_test.stick", count = 1 },
},
output = { template = "craft_display_test.rock_pick", count = 1 },
name = "Form-2 Recipe",
}
local c11_a = fresh_container{
{ template = "craft_display_test.rock", count = 1 },
}
local c11_b = fresh_container{
{ template = "craft_display_test.stick", count = 1 },
}
local locale_table11 = { sources = { c11_a, c11_b }, sink = c11_a }
local widget11 = display.create(function() return locale_table11 end)
local got_locale11 = display._test_get_locale(widget11)
local rows11 = display._test_get_rows(widget11)
T.assert(type(got_locale11) == "table"
and got_locale11.sources ~= nil
and #got_locale11.sources == 2
and got_locale11.sources[1] == c11_a
and got_locale11.sources[2] == c11_b
and got_locale11.sink == c11_a
and #rows11 == 1
and rows11[1].recipe.id == "form2_r11"
and rows11[1].available == true,
"11. Form-2 locale-factory: _test_get_locale returns the locale "
.. "table; aggregate availability across sources is true")
-- ================================================================
-- §12 (v0.2): ctx_inner.locale + container alias propagation.
--
-- The panel.show_context_menu callback path is hard to fire in
-- headless test mode (no real click events + no panel-spy hook).
-- Pragmatic substitute: monkey-patch panel.show_context_menu to
-- capture the entries-table, then invoke the first entry's
-- callback directly with a dummy menu_ctx. The captured ctx_inner
-- must carry locale + the sink-alias.
--
-- Covers both Form-1 (locale == container, alias == container)
-- and Form-2 (locale == table, alias == locale.sink).
-- ================================================================
crafting._test_clear_all()
crafting.define_recipe{
id = "alias_r12",
inputs = { { template = "craft_display_test.rock", count = 1 } },
output = { template = "craft_display_test.rock_pick", count = 1 },
name = "Alias Recipe",
}
local saved_show = panel.show_context_menu
local captured_entries
panel.show_context_menu = function(_x, _y, entries)
captured_entries = entries
end
-- Form-1 path
local container12a = fresh_container{
{ template = "craft_display_test.rock", count = 1 },
}
local widget12a = display.create(container12a)
display.register_action(widget12a, "Craft", function(rid, ctx_inner)
widget12a._captured = { rid = rid, ctx_inner = ctx_inner }
end)
display._invoke_context_menu(widget12a, "alias_r12", 0, 0)
local f1_ok = false
if captured_entries and #captured_entries == 1 then
captured_entries[1].callback({ close_menu = function() end })
local cap = widget12a._captured
f1_ok = cap ~= nil
and cap.rid == "alias_r12"
and cap.ctx_inner.locale == container12a
and cap.ctx_inner.container == container12a
end
-- Form-2 path
captured_entries = nil
local c12b_src1 = fresh_container{
{ template = "craft_display_test.rock", count = 1 },
}
local c12b_src2 = fresh_container{}
local locale_table12 = { sources = { c12b_src1, c12b_src2 }, sink = c12b_src2 }
local widget12b = display.create(function() return locale_table12 end)
display.register_action(widget12b, "Craft", function(rid, ctx_inner)
widget12b._captured = { rid = rid, ctx_inner = ctx_inner }
end)
display._invoke_context_menu(widget12b, "alias_r12", 0, 0)
local f2_ok = false
if captured_entries and #captured_entries == 1 then
captured_entries[1].callback({ close_menu = function() end })
local cap = widget12b._captured
f2_ok = cap ~= nil
and cap.rid == "alias_r12"
and cap.ctx_inner.locale == locale_table12
and cap.ctx_inner.container == c12b_src2 -- sink alias
end
panel.show_context_menu = saved_show
T.assert(f1_ok and f2_ok,
"12. ctx_inner carries locale + container alias: Form-1 (handle == "
.. "locale == container); Form-2 (locale==table, container==sink)")
end
return M