Files
metabuilder/packages/lua_test/seed/scripts/run_suite.lua

178 lines
5.1 KiB
Lua

-- Suite runner
-- Executes test suites with nested suite support
local STATUS = require("test_status")
local run_test = require("run_test")
---@class SuiteRunnerModule
local M = {}
---@class SuiteStats
---@field total number Total test count
---@field passed number Passed test count
---@field failed number Failed test count
---@field skipped number Skipped test count
---@field duration number Suite duration in ms
---@class SuiteResults
---@field name string Suite name
---@field tests TestResult[] Test results
---@field nested SuiteResults[] Nested suite results
---@field stats SuiteStats Statistics
---Run a test suite
---@param suite TestSuite Suite to run
---@param config? TestConfig Run configuration
---@param parentHooks? TestHooks Parent suite hooks
---@return SuiteResults Suite execution results
function M.runSuite(suite, config, parentHooks)
local results = {
name = suite.name,
tests = {},
nested = {},
stats = {
total = 0,
passed = 0,
failed = 0,
skipped = 0,
duration = 0
}
}
config = config or {}
parentHooks = parentHooks or {}
local startTime = os.clock()
-- Combine hooks with parent hooks
local hooks = {
beforeEach = suite.beforeEach or parentHooks.beforeEach,
afterEach = suite.afterEach or parentHooks.afterEach
}
-- Run beforeAll hook
if suite.beforeAll then
local success, err = pcall(suite.beforeAll)
if not success then
for _, test in ipairs(suite.tests) do
results.tests[#results.tests + 1] = {
name = test.name,
status = STATUS.FAILED,
error = "beforeAll failed: " .. tostring(err),
duration = 0
}
results.stats.failed = results.stats.failed + 1
results.stats.total = results.stats.total + 1
end
results.stats.duration = (os.clock() - startTime) * 1000
return results
end
end
-- Check for .only tests
local hasOnly = false
for _, test in ipairs(suite.tests) do
if test.only then
hasOnly = true
break
end
end
-- Run tests
for _, test in ipairs(suite.tests) do
if hasOnly and not test.only then
local skipResult = {
name = test.name,
status = STATUS.SKIPPED,
duration = 0
}
results.tests[#results.tests + 1] = skipResult
results.stats.skipped = results.stats.skipped + 1
elseif config.filter and not string.find(test.name, config.filter, 1, true) then
local skipResult = {
name = test.name,
status = STATUS.SKIPPED,
duration = 0
}
results.tests[#results.tests + 1] = skipResult
results.stats.skipped = results.stats.skipped + 1
else
local testResult = run_test.runTest(test, hooks)
results.tests[#results.tests + 1] = testResult
if testResult.status == STATUS.PASSED then
results.stats.passed = results.stats.passed + 1
elseif testResult.status == STATUS.FAILED then
results.stats.failed = results.stats.failed + 1
if config.stopOnFirstFailure then
break
end
elseif testResult.status == STATUS.SKIPPED then
results.stats.skipped = results.stats.skipped + 1
end
end
results.stats.total = results.stats.total + 1
end
-- Run nested suites
for _, nestedSuite in ipairs(suite.nested) do
local nestedResults = M.runSuite(nestedSuite, config, hooks)
results.nested[#results.nested + 1] = nestedResults
-- Aggregate stats
results.stats.total = results.stats.total + nestedResults.stats.total
results.stats.passed = results.stats.passed + nestedResults.stats.passed
results.stats.failed = results.stats.failed + nestedResults.stats.failed
results.stats.skipped = results.stats.skipped + nestedResults.stats.skipped
end
-- Run afterAll hook
if suite.afterAll then
pcall(suite.afterAll)
end
results.stats.duration = (os.clock() - startTime) * 1000
return results
end
---Run all suites
---@param suites TestSuite[] Array of suites to run
---@param config? TestConfig Run configuration
---@return table All results with aggregated stats
function M.runAll(suites, config)
local allResults = {
suites = {},
stats = {
total = 0,
passed = 0,
failed = 0,
skipped = 0,
duration = 0,
suiteCount = 0
},
timestamp = os.date("%Y-%m-%dT%H:%M:%S")
}
local startTime = os.clock()
for _, suite in ipairs(suites) do
local suiteResults = M.runSuite(suite, config)
allResults.suites[#allResults.suites + 1] = suiteResults
allResults.stats.suiteCount = allResults.stats.suiteCount + 1
allResults.stats.total = allResults.stats.total + suiteResults.stats.total
allResults.stats.passed = allResults.stats.passed + suiteResults.stats.passed
allResults.stats.failed = allResults.stats.failed + suiteResults.stats.failed
allResults.stats.skipped = allResults.stats.skipped + suiteResults.stats.skipped
end
allResults.stats.duration = (os.clock() - startTime) * 1000
allResults.stats.success = allResults.stats.failed == 0
return allResults
end
return M