chore(tests): improve test runner system

* Implements an extension to frktest's `lune_console_reporter` for
  displaying status of individual running test cases and suites -- with
  colors :O!
* Include mechanism for running select tests using the test runner
  script.
This commit is contained in:
Erica Marigold 2024-12-02 11:07:59 +00:00
parent 943136bb28
commit 56b38d04e0
Signed by: DevComp
GPG key ID: 429EF1C337871656
6 changed files with 103 additions and 19 deletions

View file

@ -4,21 +4,54 @@ local fs = require("@lune/fs")
local process = require("@lune/process") local process = require("@lune/process")
local frktest = require("@pkg/frktest") local frktest = require("@pkg/frktest")
local reporter = require("../tests/_reporter")
-- HACK: Cast require to allow for dynamic paths in strict mode -- HACK: Cast require to allow for dynamic paths in strict mode
-- A more proper solution would be to use luau.load instead, but -- A more proper solution would be to use luau.load instead, but
-- frktest requires its global state to be modified by test suites -- frktest requires its global state to be modified by test suites
local require = require :: (path: string) -> () -> () local require = require :: (
path: string
) -> (
test: typeof(setmetatable(
{} :: {
case: (name: string, fn: () -> nil) -> (),
suite: (name: string, fn: () -> ()) -> (),
},
{ __index = frktest.test }
))
) -> ()
if process.args[1] ~= nil then local allowed_tests = process.args
require("../tests/" .. process.args[1])() for _, test in fs.readDir("tests") do
else -- If we are given any arguments, we only run those tests, otherwise,
for _, test in fs.readDir("tests") do -- we run all the tests
require("../tests/" .. test)()
end -- So, to include only a certain set of test files, you can provide either
-- the full path to the test file (with or without the extension) or the test
-- file name
local withoutExt = string.sub(test, 1, -6)
local is_allowed = #process.args == 0
or table.find(allowed_tests, `tests/{test}`)
or table.find(allowed_tests, withoutExt)
or table.find(allowed_tests, `tests/{withoutExt}`)
local constructors = {
case = frktest.test.case,
suite = frktest.test.suite,
}
if not is_allowed then
constructors.case = frktest.test.skip.case
constructors.suite = frktest.test.skip.suite
end
-- Ignore files starting with underscores, eg: _reporter.luau
if string.sub(test, 1, 1) == "_" then
continue
end
require("../tests/" .. test)(setmetatable(constructors, { __index = frktest.test }))
end end
frktest._reporters.lune_console_reporter.init() reporter.init()
if not frktest.run() then process.exit(tonumber(frktest.run()))
process.exit(1)
end

55
tests/_reporter.luau Normal file
View file

@ -0,0 +1,55 @@
local stdio = require("@lune/stdio")
local frktest = require("@pkg/frktest")
local Reporter = frktest._reporters.lune_console_reporter
local STYLE = table.freeze({
suite = function(name: string)
return `{stdio.style("bold")}{stdio.color("purple")}SUITE{stdio.style("reset")} {name}`
end,
report = function(name: string, state: "run" | "success" | "error" | "skip")
local state_color: stdio.Color = if state == "run"
then "white"
elseif state == "success" then "green"
elseif state == "error" then "red"
elseif state == "skip" then "yellow"
else error("Invalid test state")
return ` {stdio.style("bold")}{stdio.color(state_color)}{if state == "skip" then "SKIP" else "TEST"}{stdio.style(
"reset"
)} {name}`
end,
})
--- Clears a the previous line, and moves to its beginning
local function clear_last_line(): ()
return stdio.write("\x1b[A\x1b[K\x1b[0G\x1b[?25h")
end
local ReporterExt = {}
function ReporterExt.init()
frktest.test.on_suite_enter(function(suite)
print(STYLE.suite(suite.name))
end)
frktest.test.on_suite_leave(function()
stdio.write("\n")
end)
frktest.test.on_test_enter(function(test)
print(STYLE.report(test.name, "run"))
end)
frktest.test.on_test_leave(function(test)
clear_last_line()
print(STYLE.report(test.name, if test.failed then "error" else "success"))
end)
frktest.test.on_test_skipped(function(test)
print(STYLE.report(test.name, "skip"))
end)
Reporter.init()
end
return setmetatable(ReporterExt, { __index = Reporter })

View file

@ -1,5 +1,4 @@
local frktest = require("@pkg/frktest") local frktest = require("@pkg/frktest")
local test = frktest.test
local check = frktest.assert.check local check = frktest.assert.check
local Option = require("../luau_packages/option") local Option = require("../luau_packages/option")
@ -7,7 +6,7 @@ type Option<T> = Option.Option<T>
local Semver = require("../lib") local Semver = require("../lib")
return function() return function(test: typeof(frktest.test))
test.suite("Semver comparison tests", function() test.suite("Semver comparison tests", function()
test.case("Basic version comparisons", function() test.case("Basic version comparisons", function()
local v1 = Semver.parse("1.2.3"):unwrap() local v1 = Semver.parse("1.2.3"):unwrap()

View file

@ -1,10 +1,9 @@
local frktest = require("@pkg/frktest") local frktest = require("@pkg/frktest")
local test = frktest.test
local check = frktest.assert.check local check = frktest.assert.check
local Semver = require("../lib") local Semver = require("../lib")
return function() return function(test: typeof(frktest.test))
test.suite("Invalid semver parsing tests", function() test.suite("Invalid semver parsing tests", function()
test.case("Rejects missing components", function() test.case("Rejects missing components", function()
local res = Semver.parse("1.2") local res = Semver.parse("1.2")

View file

@ -1,5 +1,4 @@
local frktest = require("@pkg/frktest") local frktest = require("@pkg/frktest")
local test = frktest.test
local check = frktest.assert.check local check = frktest.assert.check
local Option = require("../luau_packages/option") local Option = require("../luau_packages/option")
@ -7,7 +6,7 @@ type Option<T> = Option.Option<T>
local Semver = require("../lib") local Semver = require("../lib")
return function() return function(test: typeof(frktest.test))
test.suite("Basic tests", function() test.suite("Basic tests", function()
test.case("Semver creates valid version objects", function() test.case("Semver creates valid version objects", function()
local res = Semver.parse("1.2.3-beta.1") local res = Semver.parse("1.2.3-beta.1")

View file

@ -1,5 +1,4 @@
local frktest = require("@pkg/frktest") local frktest = require("@pkg/frktest")
local test = frktest.test
local check = frktest.assert.check local check = frktest.assert.check
local Option = require("../luau_packages/option") local Option = require("../luau_packages/option")
@ -7,7 +6,7 @@ type Option<T> = Option.Option<T>
local Semver = require("../lib") local Semver = require("../lib")
return function() return function(test: typeof(frktest.test))
test.suite("Stringification tests", function() test.suite("Stringification tests", function()
test.case("A version constructed with new() when stringified should match expected string", function() test.case("A version constructed with new() when stringified should match expected string", function()
local versionMap: { [string]: Semver.Version } = { local versionMap: { [string]: Semver.Version } = {