-- lib-core.notify-test v0.1.0 — 29 assertions -- Exercises: channel create/list, tag routing, catch-all, subscribe/unsubscribe, -- error cases, ring-buffer, log-mirror toggle, severity sugar. local notify = require("lib-core.notify") local T = engine.test local M = {} function M.run_tests(_ctx) notify._test_clear_all() -- ------------------------------------------------------------------ -- 1. create + list round-trip -- ------------------------------------------------------------------ notify.create_channel{ id = "c1", filter = {"a"}, display_mode = "log" } local list = notify.list_channels() T.equals(#list, 1, "list_channels returns 1 channel after create") T.equals(list[1].id, "c1", "listed channel id matches") -- ------------------------------------------------------------------ -- 2. matching post adds to channel history -- ------------------------------------------------------------------ notify.post{ tags = {"a"}, text = "hello" } local h = notify.get_history("c1") T.equals(#h, 1, "matching post adds message to channel history") T.equals(h[1].text, "hello", "message text is preserved in history") -- ------------------------------------------------------------------ -- 3. non-matching post does NOT add to channel history -- ------------------------------------------------------------------ notify.post{ tags = {"b"}, text = "ignored" } h = notify.get_history("c1") T.equals(#h, 1, "non-matching post does not add to channel history") -- ------------------------------------------------------------------ -- 4. empty filter = catch-all -- ------------------------------------------------------------------ notify.create_channel{ id = "catch_all", filter = {}, display_mode = "log" } notify.post{ tags = {"x", "y", "z"}, text = "broadcast" } h = notify.get_history("catch_all") T.equals(#h, 1, "empty filter catches any-tagged message") -- ------------------------------------------------------------------ -- 5. subscribe callback fires on matching post -- ------------------------------------------------------------------ notify.create_channel{ id = "sub_ch", filter = {"ev"}, display_mode = "toast" } local fired = 0 local last_msg = nil local handle = notify.subscribe("sub_ch", function(msg) fired = fired + 1 last_msg = msg end) notify.post{ tags = {"ev"}, text = "event!" } T.equals(fired, 1, "subscribe callback fires once on matching post") T.equals(last_msg.text, "event!", "callback receives correct message") -- ------------------------------------------------------------------ -- 6. unsubscribe stops callback -- ------------------------------------------------------------------ notify.unsubscribe(handle) notify.post{ tags = {"ev"}, text = "after unsub" } T.equals(fired, 1, "unsubscribed callback does not fire on subsequent post") T.equals(#notify._test_get_subscribers("sub_ch"), 0, "subscriber list is empty after unsubscribe") -- ------------------------------------------------------------------ -- 7. post without tags field → loud-error -- ------------------------------------------------------------------ local ok_no_tags = pcall(notify.post, { text = "no tags" }) T.assert(not ok_no_tags, "post without tags field raises an error") -- ------------------------------------------------------------------ -- 8. post with empty tags array → loud-error -- ------------------------------------------------------------------ local ok_empty_tags = pcall(notify.post, { tags = {}, text = "empty tags" }) T.assert(not ok_empty_tags, "post with empty tags array raises an error") -- ------------------------------------------------------------------ -- 9. duplicate channel id → loud-error -- ------------------------------------------------------------------ local ok_dup = pcall(notify.create_channel, { id = "c1", filter = {}, display_mode = "log" }) T.assert(not ok_dup, "create_channel with duplicate id raises an error") -- ------------------------------------------------------------------ -- 10. unknown display_mode → loud-error -- ------------------------------------------------------------------ local ok_bad_mode = pcall(notify.create_channel, { id = "bad_mode_ch", filter = {}, display_mode = "popup" }) T.assert(not ok_bad_mode, "create_channel with unknown display_mode raises an error") -- ------------------------------------------------------------------ -- 11. max_history ring-buffer -- ------------------------------------------------------------------ notify.create_channel{ id = "ring", filter = {"r"}, display_mode = "toast", max_history = 3 } for i = 1, 5 do notify.post{ tags = {"r"}, text = "msg" .. i } end h = notify.get_history("ring") T.equals(#h, 3, "ring-buffer caps history at max_history (3)") T.equals(h[1].text, "msg3", "oldest kept entry is msg3 (msg1+msg2 dropped)") T.equals(h[3].text, "msg5", "newest entry is msg5") -- ------------------------------------------------------------------ -- 12. set_engine_log_mirror toggle -- ------------------------------------------------------------------ T.assert(notify._test_get_log_mirror() == true, "engine_log_mirror is true by default") notify.set_engine_log_mirror(false) T.assert(notify._test_get_log_mirror() == false, "set_engine_log_mirror(false) disables mirror") notify.set_engine_log_mirror(true) T.assert(notify._test_get_log_mirror() == true, "set_engine_log_mirror(true) re-enables mirror") -- non-bool truthy does NOT enable mirror notify.set_engine_log_mirror("yes") T.assert(notify._test_get_log_mirror() == false, "set_engine_log_mirror with non-bool truthy does not enable mirror") -- ------------------------------------------------------------------ -- 13. severity sugar: warn/info set correct severity field -- ------------------------------------------------------------------ notify.create_channel{ id = "sev", filter = {"s"}, display_mode = "log" } notify.warn({"s"}, "a warning") notify.info({"s"}, "an info") h = notify.get_history("sev") T.equals(#h, 2, "warn + info each post one message") T.equals(h[1].severity, "warn", "warn() sets severity to 'warn'") T.equals(h[2].severity, "info", "info() sets severity to 'info'") -- ------------------------------------------------------------------ -- 14. post() does not mutate caller's table -- ------------------------------------------------------------------ notify._test_clear_all() notify.create_channel{ id = "x", filter = {"x"}, display_mode = "log" } local m = { tags = {"x"}, text = "first" } notify.post(m) T.assert(m.id == nil, "post does not mutate caller msg.id") T.assert(m.timestamp == nil, "post does not mutate caller msg.timestamp") -- Re-using the same table for a second post m.text = "second" notify.post(m) h = notify.get_history("x") T.assert(#h == 2, "two posts store as two distinct history entries") T.equals(h[1].text, "first", "first history entry preserved") T.equals(h[2].text, "second", "second history entry distinct") end return M