mirror of
https://github.com/rayaman/multi.git
synced 2026-09-04 23:17:35 -04:00
244 lines
6.8 KiB
Lua
244 lines
6.8 KiB
Lua
--[[
|
|
Test suite for multi.lua
|
|
Run with: lua multi_test.lua
|
|
|
|
Requires multi.lua to be in the same directory or on the Lua path.
|
|
Compatible with Lua 5.1, 5.2, 5.3, 5.4, and LuaJIT.
|
|
]]
|
|
package.path = "?/init.lua;?.lua;../?/init.lua;../?.lua;" .. package.path
|
|
|
|
-- ─────────────────────────────────────────────
|
|
-- Minimal test runner
|
|
-- ─────────────────────────────────────────────
|
|
local passed, failed, skipped = 0, 0, 0
|
|
local failures = {}
|
|
|
|
local function test(name, fn)
|
|
local ok, err = pcall(fn)
|
|
if ok then
|
|
passed = passed + 1
|
|
io.write("\x1b[92m ✓\x1b[0m " .. name .. "\n")
|
|
else
|
|
failed = failed + 1
|
|
table.insert(failures, {name = name, err = tostring(err)})
|
|
io.write("\x1b[91m ✗\x1b[0m " .. name .. "\n")
|
|
io.write(" " .. tostring(err) .. "\n")
|
|
end
|
|
end
|
|
|
|
local function skip(name, reason)
|
|
skipped = skipped + 1
|
|
io.write("\x1b[93m -\x1b[0m " .. name .. " [SKIPPED: " .. (reason or "") .. "]\n")
|
|
end
|
|
|
|
local function section(name)
|
|
io.write("\n\x1b[97m── " .. name .. " ──\x1b[0m\n")
|
|
end
|
|
|
|
local function assert_eq(a, b, msg)
|
|
if a ~= b then
|
|
error((msg or "assert_eq failed") .. ": expected " .. tostring(b) .. ", got " .. tostring(a), 2)
|
|
end
|
|
end
|
|
|
|
local function assert_truthy(v, msg)
|
|
if not v then
|
|
error((msg or "expected truthy value, got falsy") .. ": " .. tostring(v), 2)
|
|
end
|
|
end
|
|
|
|
local function assert_falsy(v, msg)
|
|
if v then
|
|
error((msg or "expected falsy value, got truthy") .. ": " .. tostring(v), 2)
|
|
end
|
|
end
|
|
|
|
local function assert_type(v, t, msg)
|
|
if type(v) ~= t then
|
|
error((msg or "type mismatch") .. ": expected " .. t .. ", got " .. type(v), 2)
|
|
end
|
|
end
|
|
|
|
-- ─────────────────────────────────────────────
|
|
-- Load the library
|
|
-- ─────────────────────────────────────────────
|
|
local multi, thread
|
|
local ok, err = pcall(function()
|
|
multi, thread = require("multi"):init()
|
|
end)
|
|
|
|
if not ok then
|
|
io.write("\x1b[91mFATAL: Could not load multi.lua: " .. tostring(err) .. "\x1b[0m\n")
|
|
io.write("Make sure multi.lua is in the same directory or on package.path.\n")
|
|
os.exit(1)
|
|
end
|
|
|
|
-- Helper: run the scheduler for up to `max_ticks` ticks or until `done()` returns true.
|
|
local function run_until(done, max_ticks)
|
|
max_ticks = max_ticks or 10000
|
|
for _ = 1, max_ticks do
|
|
multi:uManager()
|
|
if done and done() then return true end
|
|
end
|
|
return done == nil
|
|
end
|
|
|
|
section("Initialization")
|
|
|
|
test("lanesManager init returns GLOBAL and THREAD", function()
|
|
local GLOBAL, THREAD = require("multi.integration.lanesManager"):init()
|
|
assert_type(GLOBAL, "table")
|
|
assert_type(THREAD, "table")
|
|
end)
|
|
|
|
test("lanesManager sets integration table", function()
|
|
assert_type(multi.integration.GLOBAL, "table")
|
|
assert_type(multi.integration.THREAD, "table")
|
|
end)
|
|
|
|
-- initialize once for rest of tests
|
|
local GLOBAL, THREAD = require("multi.integration.lanesManager"):init()
|
|
|
|
-- ─────────────────────────────────────────────
|
|
section("SystemThreadedQueue")
|
|
|
|
test("queue push/pop", function()
|
|
local q = multi:newSystemThreadedQueue("testQ1")
|
|
|
|
q:push(42)
|
|
local val = q:pop()
|
|
|
|
assert_eq(val, 42)
|
|
end)
|
|
|
|
test("queue peek does not remove", function()
|
|
local q = multi:newSystemThreadedQueue("testQ2")
|
|
|
|
q:push("hello")
|
|
|
|
assert_eq(q:peek(), "hello")
|
|
assert_eq(q:pop(), "hello")
|
|
end)
|
|
|
|
test("queue empty returns nil", function()
|
|
local q = multi:newSystemThreadedQueue("testQ3")
|
|
|
|
assert_eq(q:pop(), nil)
|
|
end)
|
|
|
|
-- ─────────────────────────────────────────────
|
|
section("SystemThreadedTable")
|
|
|
|
test("table set/get", function()
|
|
local t = multi:newSystemThreadedTable("testT1")
|
|
|
|
t.foo = "bar"
|
|
assert_eq(t.foo, "bar")
|
|
end)
|
|
|
|
test("table overwrite", function()
|
|
local t = multi:newSystemThreadedTable("testT2")
|
|
|
|
t.x = 1
|
|
t.x = 2
|
|
|
|
assert_eq(t.x, 2)
|
|
end)
|
|
|
|
-- ─────────────────────────────────────────────
|
|
section("THREAD API")
|
|
|
|
test("THREAD set/get", function()
|
|
THREAD.set("abc", 123)
|
|
assert_eq(THREAD.get("abc"), 123)
|
|
end)
|
|
|
|
test("THREAD getCores > 0", function()
|
|
assert_truthy(THREAD.getCores() > 0)
|
|
end)
|
|
|
|
-- ─────────────────────────────────────────────
|
|
section("SystemThreadedConnection")
|
|
|
|
test("connection fires event", function()
|
|
local conn = multi:newSystemThreadedConnection("conn1"):init()
|
|
|
|
local received = nil
|
|
|
|
conn(function(v)
|
|
received = v
|
|
end)
|
|
|
|
conn:Fire("ping")
|
|
|
|
run_until(function()
|
|
return received ~= nil
|
|
end, 5000)
|
|
|
|
assert_eq(received, "ping")
|
|
end)
|
|
|
|
-- ─────────────────────────────────────────────
|
|
section("SystemThreadedJobQueue")
|
|
|
|
test("job queue executes function", function()
|
|
local jq = multi:newSystemThreadedJobQueue(1)
|
|
|
|
jq:registerFunction("add", function(a, b)
|
|
return a + b
|
|
end)
|
|
|
|
local result = nil
|
|
|
|
jq.OnJobCompleted(function(_, val)
|
|
result = val
|
|
end)
|
|
|
|
jq:pushJob("add", 2, 3)
|
|
|
|
run_until(function()
|
|
return result ~= nil
|
|
end, 10000)
|
|
|
|
assert_eq(result, 5)
|
|
end)
|
|
|
|
-- ─────────────────────────────────────────────
|
|
section("JobQueue newFunction")
|
|
|
|
test("newFunction returns correct result", function()
|
|
local jq = multi:newSystemThreadedJobQueue(1)
|
|
|
|
local fn = jq:newFunction(function(a, b)
|
|
return a * b
|
|
end,true)
|
|
|
|
local result = nil
|
|
|
|
result = fn(3, 4)
|
|
|
|
run_until(function()
|
|
return result ~= nil
|
|
end, 10000)
|
|
|
|
assert_eq(result, 12)
|
|
end)
|
|
|
|
-- ─────────────────────────────────────────────
|
|
-- Summary
|
|
-- ─────────────────────────────────────────────
|
|
section("Results")
|
|
|
|
io.write("\n")
|
|
io.write("Passed: " .. passed .. "\n")
|
|
io.write("Failed: " .. failed .. "\n")
|
|
io.write("Skipped: " .. skipped .. "\n")
|
|
|
|
if failed > 0 then
|
|
io.write("\nFailures:\n")
|
|
for _, f in ipairs(failures) do
|
|
io.write(" - " .. f.name .. "\n")
|
|
io.write(" " .. f.err .. "\n")
|
|
end
|
|
os.exit(1)
|
|
end |