test: v0.2.0 multi-active + layout-slot assertions

Add 42 new assertions covering: bw-compat register without opts,
multi-active open(A)+open(B) leaving both open, per-id close(id),
bw-compat close()/is_open() operating on the focused panel, layout-
slot resolution (left-half / right-half / center default / custom-fn),
Loud-Error on unknown slot name, hit-test dispatch against window
bounds with reverse open-order, is_pausing scanning all open windows.

Existing 12 baseline assertions retained and still pass via the bw-
compat shim. Total 54 pass / 0 fail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Calic
2026-06-15 01:46:35 +02:00
parent 86d57863cc
commit ce46125435
2 changed files with 197 additions and 4 deletions

197
init.lua
View File

@@ -1,5 +1,6 @@
-- lib-core.panel-test v0.1.0 — 10 assertions
-- Exercises: registry lifecycle, theme, errors, pause-gate, context-menu dispatch.
-- lib-core.panel-test v0.2.0 — Panel test suite
-- Exercises: registry lifecycle, theme, errors, pause-gate, context-menu
-- dispatch, multi-active model, layout-slots, hit-test reverse-order.
-- Render paths are NOT tested here: engine.render.* is blocked in test-mode
-- (assert_in_render_phase guard in engine_lua_render.c). Input dispatch is
-- exercised via panel._dispatch_event_for_test(event).
@@ -31,9 +32,14 @@ end
function M.run_tests(_ctx)
-- ==================================================================
-- v0.1.1 baseline tests (bw-compat verification)
-- ==================================================================
-- ------------------------------------------------------------------
-- 1. register + open / close round-trip
-- ------------------------------------------------------------------
panel._test_reset_all()
panel.register("w1", make_widget())
panel.open("w1")
T.assert(panel.is_open(), "register + open makes is_open() true")
@@ -142,6 +148,193 @@ function M.run_tests(_ctx)
panel.close()
panel.unregister("w1")
panel.unregister("w_pause")
-- ==================================================================
-- v0.2.0 — Multi-Active + Layout-Slots + Bw-Compat-Shim
-- ==================================================================
-- ------------------------------------------------------------------
-- W.0 #1: bw-compat register(id, widget) without opts uses center default
-- ------------------------------------------------------------------
panel._test_reset_all()
panel.register("w_bc1", make_widget({ title = "BC" }))
panel.open("w_bc1")
T.assert(panel.is_open(), "is_open() any-open bw-compat")
T.assert(panel.is_open("w_bc1"), "is_open(id) per-id")
local bounds_bc = panel._test_get_window_bounds("w_bc1")
T.assert(bounds_bc ~= nil, "bounds resolved for open window")
-- center slot: x = sw*0.25, w = sw*0.50, h = sh*0.60
T.assert(bounds_bc.x > 0, "default center slot x > 0")
T.assert(bounds_bc.w > 0, "default center slot w > 0")
panel._test_reset_all()
-- ------------------------------------------------------------------
-- W.0 #2: multi-active open(A) + open(B) both stay open
-- ------------------------------------------------------------------
panel.register("w_mA", make_widget({ title = "A" }))
panel.register("w_mB", make_widget({ title = "B" }))
panel.open("w_mA")
panel.open("w_mB")
T.assert(panel.is_open("w_mA"), "A still open after opening B")
T.assert(panel.is_open("w_mB"), "B is open")
local open_ids = panel._test_get_open_ids()
T.equals(#open_ids, 2, "two windows open")
T.equals(open_ids[1], "w_mA", "A first in open_order")
T.equals(open_ids[2], "w_mB", "B second in open_order")
T.equals(panel._test_get_focused_id(), "w_mB",
"B (last-opened) is focused")
panel._test_reset_all()
-- ------------------------------------------------------------------
-- W.0 #3: close(id) per-id closes only that one
-- ------------------------------------------------------------------
panel.register("w_cA", make_widget({ title = "A" }))
panel.register("w_cB", make_widget({ title = "B" }))
panel.open("w_cA")
panel.open("w_cB")
panel.close("w_cA")
T.assert(not panel.is_open("w_cA"), "A closed by per-id close")
T.assert(panel.is_open("w_cB"), "B still open after per-id close(A)")
T.equals(panel._test_get_focused_id(), "w_cB",
"B is focused after A closed")
panel._test_reset_all()
-- ------------------------------------------------------------------
-- W.0 #4: close() bw-compat closes the focused (last-opened)
-- ------------------------------------------------------------------
panel.register("w_fA", make_widget({ title = "A" }))
panel.register("w_fB", make_widget({ title = "B" }))
panel.open("w_fA")
panel.open("w_fB")
panel.close() -- no arg
T.assert(not panel.is_open("w_fB"), "B (focused) closed by close()")
T.assert(panel.is_open("w_fA"), "A still open after close() (bw-compat)")
T.equals(panel._test_get_focused_id(), "w_fA",
"A is now focused after focused-close")
panel._test_reset_all()
-- ------------------------------------------------------------------
-- W.0 #5: is_open() bw-compat = any-open
-- ------------------------------------------------------------------
panel.register("w_io", make_widget({ title = "X" }))
T.assert(not panel.is_open(), "is_open() false when nothing open")
panel.open("w_io")
T.assert(panel.is_open(), "is_open() true after open (bw-compat any)")
panel.close()
T.assert(not panel.is_open(), "is_open() false after close")
panel._test_reset_all()
-- ------------------------------------------------------------------
-- W.0 #6: layout left-half resolves correctly
-- ------------------------------------------------------------------
panel.register("w_lh", make_widget({ title = "L" }), { layout = "left-half" })
panel.open("w_lh")
local b_lh = panel._test_get_window_bounds("w_lh")
local sw_lh, sh_lh = panel._test_get_screen_size()
T.assert(b_lh.x == 0, "left-half x = 0")
T.assert(math.abs(b_lh.w - sw_lh * 0.5) < 0.01, "left-half w = sw/2")
T.assert(math.abs(b_lh.h - sh_lh) < 0.01, "left-half h = sh")
panel._test_reset_all()
-- ------------------------------------------------------------------
-- W.0 #7: layout right-half resolves correctly
-- ------------------------------------------------------------------
panel.register("w_rh", make_widget({ title = "R" }), { layout = "right-half" })
panel.open("w_rh")
local b_rh = panel._test_get_window_bounds("w_rh")
local sw_rh = panel._test_get_screen_size()
T.assert(math.abs(b_rh.x - sw_rh * 0.5) < 0.01, "right-half x = sw/2")
T.assert(math.abs(b_rh.w - sw_rh * 0.5) < 0.01, "right-half w = sw/2")
panel._test_reset_all()
-- ------------------------------------------------------------------
-- W.0 #8: layout center default
-- ------------------------------------------------------------------
panel.register("w_c", make_widget({ title = "C" })) -- no opts = center
panel.open("w_c")
local b_c = panel._test_get_window_bounds("w_c")
local sw_c, sh_c = panel._test_get_screen_size()
T.assert(math.abs(b_c.x - sw_c * 0.25) < 0.01, "center x = sw*0.25")
T.assert(math.abs(b_c.y - sh_c * 0.20) < 0.01, "center y = sh*0.20")
T.assert(math.abs(b_c.w - sw_c * 0.50) < 0.01, "center w = sw*0.50")
T.assert(math.abs(b_c.h - sh_c * 0.60) < 0.01, "center h = sh*0.60")
panel._test_reset_all()
-- ------------------------------------------------------------------
-- W.0 #9: layout custom function
-- ------------------------------------------------------------------
panel.register("w_cu", make_widget({ title = "Cu" }), {
layout = function(_sw, _sh)
return { x = 10, y = 20, w = 100, h = 50 }
end,
})
panel.open("w_cu")
local b_cu = panel._test_get_window_bounds("w_cu")
T.equals(b_cu.x, 10, "custom layout x = 10")
T.equals(b_cu.y, 20, "custom layout y = 20")
T.equals(b_cu.w, 100, "custom layout w = 100")
T.equals(b_cu.h, 50, "custom layout h = 50")
panel._test_reset_all()
-- ------------------------------------------------------------------
-- W.0 #10: Loud-Error on unknown layout-slot
-- ------------------------------------------------------------------
local ok_bog, err_bog = pcall(panel.register, "w_bog",
make_widget({ title = "X" }), { layout = "bogus" })
T.assert(not ok_bog, "register with unknown layout slot errors")
T.assert(err_bog ~= nil and string.find(err_bog, "panel%.register") ~= nil,
"error message mentions panel.register")
T.assert(err_bog ~= nil and string.find(err_bog, "bogus") ~= nil,
"error message mentions the bad slot name")
panel._test_reset_all()
-- ------------------------------------------------------------------
-- W.0 #11: hit-test reverse-open-order
-- ------------------------------------------------------------------
local captured_a, captured_b = nil, nil
local w_hA = make_widget({
title = "A",
handle_input = function(_ctx, event) captured_a = event end,
})
local w_hB = make_widget({
title = "B",
handle_input = function(_ctx, event) captured_b = event end,
})
panel.register("w_hA", w_hA, { layout = "left-half" })
panel.register("w_hB", w_hB, { layout = "right-half" })
panel.open("w_hA")
panel.open("w_hB")
local sw_h, sh_h = panel._test_get_screen_size()
-- Click in left half: hits A only (B's bounds are right-half so click misses)
panel._dispatch_event_for_test({
kind = "click", button = "left",
x = sw_h * 0.25, y = sh_h * 0.5,
})
T.assert(captured_a ~= nil, "A captured click in its left-half bounds")
T.assert(captured_b == nil, "B did not capture click outside its bounds")
-- Reset captures, click in right half
captured_a, captured_b = nil, nil
panel._dispatch_event_for_test({
kind = "click", button = "left",
x = sw_h * 0.75, y = sh_h * 0.5,
})
T.assert(captured_b ~= nil, "B captured click in its right-half bounds")
T.assert(captured_a == nil, "A did not capture click outside its bounds")
panel._test_reset_all()
-- ------------------------------------------------------------------
-- W.0 #12: is_pausing() checks ALL open windows, not just focused
-- ------------------------------------------------------------------
panel.register("w_np", make_widget({ title = "NP" })) -- non-pausing
panel.register("w_p", make_widget({ title = "P", pause_on_open = true }))
panel.open("w_p")
panel.open("w_np") -- focused = non-pausing
T.assert(panel.is_pausing(),
"is_pausing() true when a non-focused open window has pause_on_open")
panel.close("w_p")
T.assert(not panel.is_pausing(),
"is_pausing() false after closing the pausing window (np still open)")
panel._test_reset_all()
end
return M

View File

@@ -1,9 +1,9 @@
{
"id": "lib-core.panel-test",
"role": "test",
"version": "0.1.0",
"version": "0.2.0",
"api_min": "0.1",
"deps": [
{"id": "lib-core.panel", "version": "0.1.1"}
{"id": "lib-core.panel", "version": "0.2.0"}
]
}