mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-29 00:16:54 +01:00
- contrib/plugins/reskate-test calls every plugin API and says what worked: ptest all, ptest <module>, ptest list. Its 45 checks cover the base set, timers, the level, package files, JSON, require, the console, storage and the sandbox. It is the example to copy for a plugin. - contrib/plugins/reskate-hostile attacks the sandbox, one attack per command (hostile list): loops, memory and buffer bombs, caught errors, error and log floods, timers, recursion, an unload that never ends, and 17 ways out. Each must end stopped or refused. - dingosdk_plugin_tests runs both from the repository: every reskate-test check passes, and every hostile attack is stopped or refused with nothing escaping. - Taken from Domination (PR 279) for the plugin API to use: the trick watch (when a trick starts, lands and what it scored, or a slam breaks it; Domination's spots left out) in Extension/Skater/trick_watch.h with its tests, the score HUD reader in score_hud.h, and teleport_local_skater_heading, whose hunks are the PR's own. Neither is wired to anything yet.
105 lines
3.3 KiB
Lua
105 lines
3.3 KiB
Lua
-- The test runner: each file in checks/ is a module of checks, and `ptest` runs them. A check
|
|
-- passes when its function returns without an error; a later check passes when it calls done(true)
|
|
-- in time. Only failures and the summary are printed, to stay under the 50 lines a second a plugin has.
|
|
local harness = {}
|
|
local modules, order = {}, {}
|
|
local running = nil
|
|
|
|
function harness.module(name)
|
|
if not modules[name] then
|
|
modules[name] = {}
|
|
table.insert(order, name)
|
|
end
|
|
local list = modules[name]
|
|
local m = {}
|
|
function m.check(title, fn)
|
|
table.insert(list, {title = title, fn = fn})
|
|
end
|
|
-- fn(done): call done(ok, why) within `within` ms of the run starting.
|
|
function m.later(title, within, fn)
|
|
table.insert(list, {title = title, fn = fn, within = within})
|
|
end
|
|
return m
|
|
end
|
|
|
|
-- What the call raised; an error when it was allowed.
|
|
function harness.refused(fn, ...)
|
|
local ok, err = pcall(fn, ...)
|
|
if ok then error("was allowed", 2) end
|
|
return tostring(err)
|
|
end
|
|
|
|
function harness.names()
|
|
return table.clone(order)
|
|
end
|
|
|
|
function harness.has(name)
|
|
return modules[name] ~= nil
|
|
end
|
|
|
|
local function finish(run)
|
|
running = nil
|
|
local shown = 0
|
|
for _, line in run.failures do
|
|
shown += 1
|
|
if shown > 20 then
|
|
reskate.console.print("FAIL ... and " .. (#run.failures - 20) .. " more")
|
|
break
|
|
end
|
|
reskate.console.print("FAIL " .. line)
|
|
end
|
|
local parts = {}
|
|
for _, name in run.names do
|
|
local tally = run.per[name]
|
|
table.insert(parts, name .. " " .. tally.passed .. "/" .. tally.total)
|
|
end
|
|
reskate.console.print("ptest: " .. run.passed .. " passed, " .. run.failed .. " failed (" .. table.concat(parts, ", ") .. ")")
|
|
end
|
|
|
|
local function record(run, name, title, ok, why)
|
|
local tally = run.per[name]
|
|
if ok then
|
|
run.passed += 1
|
|
tally.passed += 1
|
|
else
|
|
run.failed += 1
|
|
table.insert(run.failures, name .. ": " .. title .. ": " .. tostring(why or "failed"))
|
|
end
|
|
end
|
|
|
|
function harness.run(names)
|
|
if running then
|
|
reskate.console.print("ptest: a run is still going on")
|
|
return
|
|
end
|
|
local run = {names = names, passed = 0, failed = 0, pending = 0, failures = {}, per = {}}
|
|
running = run
|
|
for _, name in names do
|
|
run.per[name] = {passed = 0, total = #modules[name]}
|
|
end
|
|
for _, name in names do
|
|
for _, item in modules[name] do
|
|
if item.within then
|
|
run.pending += 1
|
|
local finished = false
|
|
local function done(ok, why)
|
|
if finished then return end
|
|
finished = true
|
|
record(run, name, item.title, ok, why)
|
|
run.pending -= 1
|
|
if run.pending == 0 then finish(run) end
|
|
end
|
|
reskate.time.after(item.within, function() done(false, "did not finish within " .. item.within .. " ms") end)
|
|
local ok, err = pcall(item.fn, done)
|
|
if not ok then done(false, err) end
|
|
else
|
|
local ok, err = pcall(item.fn)
|
|
record(run, name, item.title, ok, err)
|
|
end
|
|
end
|
|
end
|
|
if run.pending == 0 then finish(run) end
|
|
end
|
|
|
|
return harness
|