openmw/scripts/data/integration_tests/testing_util/testing_util.lua

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

243 lines
6.4 KiB
Lua
Raw Normal View History

2021-07-10 13:43:53 +02:00
local core = require('openmw.core')
2022-07-10 17:41:37 +02:00
local util = require('openmw.util')
2021-07-10 13:43:53 +02:00
local M = {}
2025-02-26 23:12:17 +01:00
local menuTestsOrder = {}
local menuTests = {}
2025-02-26 23:12:17 +01:00
local globalTestsOrder = {}
local globalTests = {}
local globalTestRunner = nil
local currentGlobalTest = nil
local currentGlobalTestError = nil
2025-02-26 23:12:17 +01:00
local localTests = {}
local localTestRunner = nil
2021-07-10 13:43:53 +02:00
local currentLocalTest = nil
local currentLocalTestError = nil
local function makeTestCoroutine(fn)
2021-07-10 13:43:53 +02:00
local co = coroutine.create(fn)
return function()
if coroutine.status(co) ~= 'dead' then
coroutine.resume(co)
end
end
end
local function runTests(tests)
for i, test in ipairs(tests) do
local name, fn = unpack(test)
print('TEST_START', i, name)
local status, err = pcall(fn)
if status then
print('TEST_OK', i, name)
else
print('TEST_FAILED', i, name, err)
end
end
core.quit()
end
function M.makeUpdateMenu()
return makeTestCoroutine(function()
print('Running menu tests...')
runTests(menuTestsOrder)
end)
end
function M.makeUpdateGlobal()
return makeTestCoroutine(function()
print('Running global tests...')
runTests(globalTestsOrder)
end)
end
function M.registerMenuTest(name, fn)
menuTests[name] = fn
table.insert(menuTestsOrder, {name, fn})
end
function M.runGlobalTest(name)
currentGlobalTest = name
currentGlobalTestError = nil
core.sendGlobalEvent('runGlobalTest', name)
while currentGlobalTest do
coroutine.yield()
end
if currentGlobalTestError then
error(currentGlobalTestError, 2)
end
end
2025-02-26 23:12:17 +01:00
function M.registerGlobalTest(name, fn)
globalTests[name] = fn
table.insert(globalTestsOrder, {name, fn})
end
function M.updateGlobal()
if globalTestRunner and coroutine.status(globalTestRunner) ~= 'dead' then
coroutine.resume(globalTestRunner)
else
globalTestRunner = nil
end
end
2021-07-10 13:43:53 +02:00
function M.runLocalTest(obj, name)
currentLocalTest = name
currentLocalTestError = nil
obj:sendEvent('runLocalTest', name)
2024-07-31 22:37:17 +02:00
while currentLocalTest do
coroutine.yield()
end
if currentLocalTestError then
error(currentLocalTestError, 2)
end
2021-07-10 13:43:53 +02:00
end
2025-02-26 23:12:17 +01:00
function M.registerLocalTest(name, fn)
localTests[name] = fn
end
function M.updateLocal()
if localTestRunner and coroutine.status(localTestRunner) ~= 'dead' then
if not core.isWorldPaused() then
coroutine.resume(localTestRunner)
end
else
localTestRunner = nil
end
end
function M.expect(cond, msg)
2021-07-10 13:43:53 +02:00
if not cond then
error(msg or '"true" expected', 2)
end
end
function M.expectEqualWithDelta(v1, v2, delta, msg)
if math.abs(v1 - v2) > delta then
error(string.format('%s: %f ~= %f', msg or '', v1, v2), 2)
end
end
function M.expectAlmostEqual(v1, v2, msg)
if math.abs(v1 - v2) / (math.abs(v1) + math.abs(v2)) > 0.05 then
error(string.format('%s: %f ~= %f', msg or '', v1, v2), 2)
end
end
2022-06-06 01:10:33 +02:00
function M.expectGreaterOrEqual(v1, v2, msg)
if not (v1 >= v2) then
error(string.format('%s: %f >= %f', msg or '', v1, v2), 2)
end
end
function M.expectGreaterThan(v1, v2, msg)
if not (v1 > v2) then
error(string.format('%s: %s > %s', msg or '', v1, v2), 2)
end
end
function M.expectLessOrEqual(v1, v2, msg)
if not (v1 <= v2) then
error(string.format('%s: %s <= %s', msg or '', v1, v2), 2)
end
end
function M.expectEqual(v1, v2, msg)
if not (v1 == v2) then
error(string.format('%s: %s ~= %s', msg or '', v1, v2), 2)
end
end
2024-06-25 01:13:58 +02:00
function M.expectNotEqual(v1, v2, msg)
if v1 == v2 then
error(string.format('%s: %s == %s', msg or '', v1, v2), 2)
end
end
2022-07-10 17:41:37 +02:00
---
-- Verifies that given value matches provided matcher.
-- @function expectThat
-- @param value#any any value to match.
-- @param matcher#function a function returing empty string in the case of success or a message explaining the mismatch.
-- @param msg#string a message to prefix failure reason.
-- @usage
-- local matcher = function(actual)
-- if actual == 42 then
-- return ''
-- end
-- return string.format('%s is not 42', actual)
-- end
-- expectThat(42, matcher)
function M.expectThat(value, matcher, msg)
local message = matcher(value)
if message ~= '' then
error(string.format('%s: actual does not match expected: %s', msg or 'Failure', message), 2)
end
end
function M.formatActualExpected(actual, expected)
return string.format('actual: %s, expected: %s', actual, expected)
end
-- used only in menu scripts
M.menuEventHandlers = {
globalTestFinished = function(data)
if data.name ~= currentGlobalTest then
error(string.format('globalTestFinished with incorrect name %s, expected %s', data.name, currentGlobalTest), 2)
end
currentGlobalTest = nil
currentGlobalTestError = data.errMsg
end,
}
2025-02-26 23:18:07 +01:00
-- used only in global scripts
M.globalEventHandlers = {
runGlobalTest = function(name)
fn = globalTests[name]
local types = require('openmw.types')
local world = require('openmw.world')
if not fn then
types.Player.sendMenuEvent(world.players[1], 'globalTestFinished', {name=name, errMsg='Global test is not found'})
return
end
globalTestRunner = coroutine.create(function()
local status, err = pcall(fn)
if status then
err = nil
end
types.Player.sendMenuEvent(world.players[1], 'globalTestFinished', {name=name, errMsg=err})
end)
end,
2025-02-26 23:18:07 +01:00
localTestFinished = function(data)
if data.name ~= currentLocalTest then
error(string.format('localTestFinished with incorrect name %s, expected %s', data.name, currentLocalTest), 2)
2025-02-26 23:18:07 +01:00
end
currentLocalTest = nil
currentLocalTestError = data.errMsg
end,
}
-- used only in local scripts
M.localEventHandlers = {
runLocalTest = function(name)
2021-07-10 13:43:53 +02:00
fn = localTests[name]
if not fn then
2025-02-26 23:12:17 +01:00
core.sendGlobalEvent('localTestFinished', {name=name, errMsg='Local test is not found'})
2021-07-10 13:43:53 +02:00
return
end
localTestRunner = coroutine.create(function()
local status, err = pcall(fn)
2024-07-31 22:37:17 +02:00
if status then
err = nil
end
2021-07-10 13:43:53 +02:00
core.sendGlobalEvent('localTestFinished', {name=name, errMsg=err})
end)
end,
}
return M