local DEFAULT_TIMEOUT_SECONDS = 3 local function createLibTest(args) local api = {} local tests = {} local pretty = false local verbose = false local reportPath = nil local printMarker = true local timeoutSeconds = DEFAULT_TIMEOUT_SECONDS local i = 1 while i <= #(args or {}) do local arg = args[i] if arg == "--verbose" then pretty = true verbose = true elseif arg == "--pretty" then pretty = true elseif arg == "--report" then reportPath = args[i + 1] i = i + 1 elseif arg == "--no-marker" then printMarker = false elseif arg == "--timeout" then timeoutSeconds = tonumber(args[i + 1]) i = i + 1 elseif arg == "--no-timeout" then timeoutSeconds = nil end i = i + 1 end local function fail(message) error(message, 2) end local function writeReport(line) if not reportPath then return end local file = fs.open(reportPath, "a") if file then file.writeLine(line) file.close() end end function api.log(message) if verbose then writeReport("LOG " .. tostring(message)) end end function api.test(name, fn) assert(type(name) == "string", "bad argument #1 (string expected)") assert(type(fn) == "function", "bad argument #2 (function expected)") tests[#tests + 1] = { name = name, fn = fn } end function api.assertEquals(actual, expected, message) if actual ~= expected then fail( (message or "assertEquals failed") .. ": expected " .. tostring(expected) .. ", got " .. tostring(actual) ) end end function api.assertTrue(value, message) if not value then fail(message or "assertTrue failed") end end function api.assertErrors(fn, expected) assert(type(fn) == "function", "bad argument #1 (function expected)") local ok, err = pcall(fn) if ok then fail("expected error") end if expected and not string.find(tostring(err), expected, 1, true) then fail("expected error containing " .. expected .. ", got " .. tostring(err)) end end local function runCase(fn) if not timeoutSeconds then return pcall(fn) end local ok, err local finished = false local function runner() ok, err = pcall(fn) finished = true end local function timer() sleep(timeoutSeconds) end parallel.waitForAny(runner, timer) if not finished then return false, "libtest timeout after " .. timeoutSeconds .. "s", true end return ok, err end function api.run() for _, t in ipairs(tests) do api.log("RUN " .. t.name) local ok, err, timedOut = runCase(t.fn) if not ok then if timedOut then api.log("TIMEOUT " .. t.name .. " after " .. timeoutSeconds .. "s (libtest)") end writeReport("KO " .. t.name .. ": " .. tostring(err)) if not pretty then print("FAIL " .. t.name .. ": " .. tostring(err)) end error(err, 0) end writeReport("OK " .. t.name) end if printMarker then print("__TRAPOS_TEST_OK__") end return true end return api end return createLibTest