2020-09-19 13:41:24 +02:00
|
|
|
local Token = require 'utils.token'
|
|
|
|
local Task = require 'utils.task'
|
2020-09-19 15:48:08 +02:00
|
|
|
local ModuleStore = require 'utils.test.module_store'
|
2020-09-20 20:13:07 +02:00
|
|
|
local Builder = require 'utils.test.builder'
|
|
|
|
local Event = require 'utils.event'
|
2020-09-19 13:41:24 +02:00
|
|
|
|
|
|
|
local pcall = pcall
|
|
|
|
|
|
|
|
local Public = {}
|
|
|
|
|
2020-09-20 20:13:07 +02:00
|
|
|
Public.events = {
|
|
|
|
tests_run_finished = Event.generate_event_name('test_run_finished')
|
|
|
|
}
|
|
|
|
|
2020-09-25 21:33:46 +02:00
|
|
|
local run_tests_token
|
|
|
|
|
2020-09-20 20:13:07 +02:00
|
|
|
local function print_summary(count, fail_count)
|
|
|
|
local pass_count = count - fail_count
|
|
|
|
game.print(table.concat {pass_count, ' of ', count, ' tests passed.'})
|
|
|
|
end
|
|
|
|
|
|
|
|
local function mark_module_for_passed(module)
|
|
|
|
local any_fails = false
|
|
|
|
local all_ran = true
|
2020-09-19 13:41:24 +02:00
|
|
|
|
|
|
|
for _, child in pairs(module.children) do
|
2020-09-20 20:13:07 +02:00
|
|
|
local module_any_fails, module_all_ran = mark_module_for_passed(child)
|
|
|
|
any_fails = any_fails or module_any_fails
|
|
|
|
all_ran = all_ran and module_all_ran
|
|
|
|
end
|
|
|
|
|
|
|
|
for _, test in pairs(module.tests) do
|
|
|
|
any_fails = any_fails or (test.passed == false)
|
|
|
|
all_ran = all_ran and (test.passed ~= nil)
|
|
|
|
end
|
|
|
|
|
|
|
|
if any_fails then
|
|
|
|
module.passed = false
|
|
|
|
elseif all_ran then
|
|
|
|
module.passed = true
|
|
|
|
else
|
|
|
|
module.passed = nil
|
2020-09-19 13:41:24 +02:00
|
|
|
end
|
2020-09-20 20:13:07 +02:00
|
|
|
|
|
|
|
return any_fails, all_ran
|
|
|
|
end
|
|
|
|
|
|
|
|
local function mark_modules_for_passed()
|
|
|
|
mark_module_for_passed(ModuleStore.root_module)
|
2020-09-19 13:41:24 +02:00
|
|
|
end
|
|
|
|
|
2020-09-20 20:13:07 +02:00
|
|
|
local function finish_test_run(data)
|
|
|
|
print_summary(data.count, data.fail_count)
|
|
|
|
mark_modules_for_passed()
|
|
|
|
script.raise_event(Public.events.tests_run_finished, {})
|
2020-09-19 13:41:24 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
local function print_error(test_name, error_message)
|
|
|
|
game.print(table.concat {"Failed - '", test_name, "': ", tostring(error_message)}, {r = 1})
|
|
|
|
end
|
|
|
|
|
|
|
|
local function print_success(test_name)
|
|
|
|
game.print(table.concat {"Passed - '", test_name, "'"}, {g = 1})
|
|
|
|
end
|
|
|
|
|
2020-09-25 21:33:46 +02:00
|
|
|
local function print_hook_error(hook)
|
|
|
|
game.print(table.concat {'Failed ', hook.name, " hook -':", tostring(hook.error)}, {r = 1})
|
|
|
|
end
|
|
|
|
|
|
|
|
local function record_hook_error_in_module(hook)
|
|
|
|
if hook.name == 'startup' then
|
|
|
|
hook.module.startup_error = hook.error
|
|
|
|
elseif hook.name == 'teardown' then
|
|
|
|
hook.module.teardown_error = hook.error
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local function run_hook(hook)
|
|
|
|
local steps = hook.steps
|
|
|
|
local current_step = hook.current_step
|
|
|
|
local func
|
|
|
|
if current_step == 0 then
|
|
|
|
func = hook.func
|
|
|
|
else
|
|
|
|
func = steps[current_step].func
|
|
|
|
end
|
|
|
|
local success, return_value = pcall(func, steps)
|
|
|
|
|
|
|
|
if not success then
|
|
|
|
hook.error = return_value
|
|
|
|
print_hook_error(hook)
|
|
|
|
record_hook_error_in_module(hook)
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
if current_step == #steps then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
|
|
|
local function do_hook(hook, data)
|
|
|
|
local hook_success = run_hook(hook)
|
|
|
|
if hook_success == nil then
|
2020-09-26 21:02:53 +02:00
|
|
|
local step_index = hook.current_step + 1
|
|
|
|
local step = hook.steps[step_index]
|
|
|
|
hook.current_step = step_index
|
|
|
|
Task.set_timeout_in_ticks(step.delay or 1, run_tests_token, data)
|
|
|
|
return
|
2020-09-25 21:33:46 +02:00
|
|
|
end
|
|
|
|
|
2020-09-26 21:02:53 +02:00
|
|
|
data.index = data.index + 1
|
2020-09-25 21:33:46 +02:00
|
|
|
Task.set_timeout_in_ticks(1, run_tests_token, data)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2020-09-19 13:41:24 +02:00
|
|
|
local function run_test(test)
|
2020-09-19 16:56:50 +02:00
|
|
|
local steps = test.steps
|
|
|
|
local current_step = test.current_step
|
|
|
|
local func
|
|
|
|
if current_step == 0 then
|
|
|
|
func = test.func
|
|
|
|
else
|
|
|
|
func = steps[current_step].func
|
|
|
|
end
|
|
|
|
local success, return_value = pcall(func, steps)
|
2020-09-19 13:41:24 +02:00
|
|
|
|
|
|
|
if not success then
|
|
|
|
print_error(test.name, return_value)
|
2020-09-20 20:13:07 +02:00
|
|
|
test.passed = false
|
|
|
|
test.error = return_value
|
2020-09-19 13:41:24 +02:00
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2020-09-19 16:56:50 +02:00
|
|
|
if current_step == #steps then
|
2020-09-19 13:41:24 +02:00
|
|
|
print_success(test.name)
|
2020-09-20 20:13:07 +02:00
|
|
|
test.passed = true
|
2020-09-19 13:41:24 +02:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
2020-09-25 21:33:46 +02:00
|
|
|
local function do_test(test, data)
|
2020-09-19 13:41:24 +02:00
|
|
|
local success = run_test(test)
|
|
|
|
|
|
|
|
if success == false then
|
2020-09-19 15:48:08 +02:00
|
|
|
data.count = data.count + 1
|
2020-09-19 13:41:24 +02:00
|
|
|
data.fail_count = data.fail_count + 1
|
2020-09-25 21:33:46 +02:00
|
|
|
data.index = data.index + 1
|
2020-09-19 13:41:24 +02:00
|
|
|
Task.set_timeout_in_ticks(1, run_tests_token, data)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if success == true then
|
2020-09-19 15:48:08 +02:00
|
|
|
data.count = data.count + 1
|
2020-09-25 21:33:46 +02:00
|
|
|
data.index = data.index + 1
|
2020-09-19 13:41:24 +02:00
|
|
|
Task.set_timeout_in_ticks(1, run_tests_token, data)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2020-09-19 16:56:50 +02:00
|
|
|
local step_index = test.current_step + 1
|
|
|
|
test.current_step = step_index
|
|
|
|
local step = test.steps[step_index]
|
|
|
|
Task.set_timeout_in_ticks(step.delay or 1, run_tests_token, data)
|
2020-09-19 13:41:24 +02:00
|
|
|
end
|
|
|
|
|
2020-09-25 21:33:46 +02:00
|
|
|
local function run_tests(data)
|
|
|
|
local index = data.index
|
|
|
|
local runnable = data.runnables[index]
|
|
|
|
|
|
|
|
if runnable == nil then
|
|
|
|
finish_test_run(data)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if runnable.is_hook then
|
|
|
|
do_hook(runnable, data)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
do_test(runnable, data)
|
|
|
|
end
|
|
|
|
|
2020-09-19 13:41:24 +02:00
|
|
|
run_tests_token = Token.register(run_tests)
|
|
|
|
|
2020-09-25 21:33:46 +02:00
|
|
|
local function run(runnables)
|
|
|
|
run_tests({runnables = runnables, index = 1, count = 0, fail_count = 0})
|
2020-09-19 13:41:24 +02:00
|
|
|
end
|
|
|
|
|
2020-09-20 20:13:07 +02:00
|
|
|
function Public.run_module(module)
|
2020-09-25 21:33:46 +02:00
|
|
|
local runnables = Builder.build_module_for_run(module or ModuleStore.root_module)
|
|
|
|
run(runnables)
|
2020-09-20 20:13:07 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
function Public.run_test(test)
|
2020-09-25 21:33:46 +02:00
|
|
|
local runnables = Builder.build_test_for_run(test)
|
|
|
|
run(runnables)
|
2020-09-20 20:13:07 +02:00
|
|
|
end
|
2020-09-19 13:41:24 +02:00
|
|
|
|
|
|
|
return Public
|