1
0
mirror of https://github.com/Refactorio/RedMew.git synced 2024-12-12 10:04:40 +02:00
RedMew/utils/test/viewer.lua
2020-09-29 20:50:24 +01:00

424 lines
12 KiB
Lua

local Gui = require 'utils.gui'
local Builder = require 'utils.test.builder'
local Runner = require 'utils.test.runner'
local Color = require 'resources.color_presets'
local Token = require 'utils.token'
local Task = require 'utils.task'
local Event = require 'utils.event'
local Global = require 'utils.global'
local Public = {}
local info_type_test = {}
local info_type_module = {}
local down_arrow = ''
local right_arrow = ''
local color_success = {g = 1}
local color_failure = {r = 1}
local color_selected = Color.orange
local color_default = Color.white
local main_frame_name = Gui.uid_name()
local close_main_frame_name = Gui.uid_name()
local module_arrow_name = Gui.uid_name()
local module_label_name = Gui.uid_name()
local test_label_name = Gui.uid_name()
local run_all_button_name = Gui.uid_name()
local run_selected_button_name = Gui.uid_name()
local stop_on_error_checkbox_name = Gui.uid_name()
local error_test_box_name = Gui.uid_name()
local selected_test_info_by_player_index = {}
local stop_on_first_error_by_player_index = {}
Global.register(
{
selected_test_info_by_player_index = selected_test_info_by_player_index,
stop_on_first_error_by_player_index = stop_on_first_error_by_player_index
},
function(tbl)
selected_test_info_by_player_index = tbl.selected_test_info_by_player_index
stop_on_first_error_by_player_index = tbl.stop_on_first_error_by_player_index
end
)
local function get_module_state(module)
local passed = module.passed
if passed == false or module.startup_error or module.teardown_error then
return false
end
return passed
end
local function get_test_error(test)
return test.error or ''
end
local function get_module_error(module)
local errors = {}
if module.startup_error then
errors[#errors + 1] = 'startup error: '
errors[#errors + 1] = module.startup_error
errors[#errors + 1] = '\n\n'
end
if module.teardown_error then
errors[#errors + 1] = 'teardown error: '
errors[#errors + 1] = module.teardown_error
end
return table.concat(errors)
end
local function get_text_box_error(player_index)
local test_info = selected_test_info_by_player_index[player_index]
if test_info == nil then
return ''
end
local info_type = test_info.type
if info_type == info_type_test then
return get_test_error(test_info.test)
elseif info_type == info_type_module then
return get_module_error(test_info.module)
end
end
local function set_selected_style(style, selected)
if selected then
style.font_color = color_selected
else
style.font_color = color_default
end
end
local function set_passed_style(style, passed)
if passed == true then
style.font_color = color_success
elseif passed == false then
style.font_color = color_failure
else
style.font_color = color_default
end
end
local function is_test_selected(test, player_index)
local info = selected_test_info_by_player_index[player_index]
if not info then
return false
end
local info_test = info.test
if not info_test then
return false
end
return info_test.id == test.id
end
local function is_module_selected(module, player_index)
local info = selected_test_info_by_player_index[player_index]
if not info then
return false
end
local info_module = info.module
if not info_module then
return false
end
return info_module.id == module.id
end
local function draw_tests_test(container, test, depth)
local flow = container.add {type = 'flow'}
local label = flow.add {type = 'label', name = test_label_name, caption = test.name}
local label_style = label.style
local is_selected = is_test_selected(test, container.player_index)
set_selected_style(label_style, is_selected)
if not is_selected then
set_passed_style(label_style, test.passed)
end
label_style.left_margin = depth * 15 + 10
Gui.set_data(label, {test = test, container = container})
end
local function draw_tests_module(container, module)
local caption = {module.name or 'All Tests', ' (', module.count, ')'}
caption = table.concat(caption)
local flow = container.add {type = 'flow'}
local arrow =
flow.add {
type = 'label',
name = module_arrow_name,
caption = module.is_open and down_arrow or right_arrow
}
arrow.style.left_margin = module.depth * 15
Gui.set_data(arrow, {module = module, container = container})
local label = flow.add {type = 'label', name = module_label_name, caption = caption}
local label_style = label.style
local is_selected = is_module_selected(module, container.player_index)
set_selected_style(label_style, is_selected)
if not is_selected then
set_passed_style(label_style, get_module_state(module))
end
Gui.set_data(label, {module = module, container = container})
if not module.is_open then
return
end
for _, child in pairs(module.children) do
draw_tests_module(container, child)
end
for _, test in pairs(module.tests) do
draw_tests_test(container, test, module.depth + 1)
end
end
local function redraw_tests(container)
Gui.clear(container)
local root_module = Builder.get_root_modules()
draw_tests_module(container, root_module)
end
local function draw_tests(container)
local scroll_pane =
container.add {
type = 'scroll-pane',
horizontal_scroll_policy = 'auto-and-reserve-space',
vertical_scroll_policy = 'auto-and-reserve-space'
}
local scroll_pane_style = scroll_pane.style
scroll_pane_style.horizontally_stretchable = true
scroll_pane_style.height = 350
local list = scroll_pane.add {type = 'flow', direction = 'vertical'}
redraw_tests(list)
end
local function draw_error_text_box(container)
local text = get_text_box_error(container.player_index)
local text_box = container.add {type = 'text-box', name = error_test_box_name, text = text}
local style = text_box.style
style.vertically_stretchable = true
style.horizontally_stretchable = true
style.maximal_width = 800
return text_box
end
local function create_main_frame(center)
local frame = center.add {type = 'frame', name = main_frame_name, caption = 'Test Runner', direction = 'vertical'}
local frame_style = frame.style
frame_style.width = 800
frame_style.height = 600
local top_flow = frame.add {type = 'flow', direction = 'horizontal'}
top_flow.add {type = 'button', name = run_all_button_name, caption = 'Run All'}
top_flow.add {
type = 'button',
name = run_selected_button_name,
caption = 'Run Selected'
}
top_flow.add {
type = 'checkbox',
name = stop_on_error_checkbox_name,
caption = 'Stop on first error',
state = stop_on_first_error_by_player_index[center.player_index] or false
}
draw_tests(frame)
local error_text_box = draw_error_text_box(frame)
Gui.set_data(frame, {error_text_box = error_text_box})
local close_button = frame.add {type = 'button', name = close_main_frame_name, caption = 'Close'}
Gui.set_data(close_button, frame)
end
local function close_main_frame(frame)
Gui.destroy(frame)
end
local function get_error_text_box(player)
local frame = player.gui.center[main_frame_name]
local frame_data = Gui.get_data(frame)
return frame_data.error_text_box
end
local function make_options(player_index)
return {stop_on_first_error = stop_on_first_error_by_player_index[player_index]}
end
local run_module_token =
Token.register(
function(data)
Runner.run_module(data.module, data.player, data.options)
end
)
local run_test_token =
Token.register(
function(data)
Runner.run_test(data.test, data.player, data.options)
end
)
Gui.on_click(
close_main_frame_name,
function(event)
local element = event.element
local frame = Gui.get_data(element)
close_main_frame(frame)
end
)
Gui.on_click(
module_arrow_name,
function(event)
local element = event.element
local data = Gui.get_data(element)
local module = data.module
local container = data.container
module.is_open = not module.is_open
redraw_tests(container)
end
)
Gui.on_click(
module_label_name,
function(event)
local element = event.element
local data = Gui.get_data(element)
local module = data.module
local container = data.container
local player_index = event.player_index
local is_selected = not is_module_selected(module, player_index)
selected_test_info_by_player_index[player_index] = nil
if is_selected then
selected_test_info_by_player_index[player_index] = {type = info_type_module, module = module}
end
local error_text_box = get_error_text_box(event.player)
if is_selected then
error_text_box.text = get_module_error(module)
else
error_text_box.text = ''
end
redraw_tests(container)
end
)
Gui.on_click(
test_label_name,
function(event)
local element = event.element
local data = Gui.get_data(element)
local test = data.test
local container = data.container
local player_index = event.player_index
local is_selected = not is_test_selected(test, player_index)
selected_test_info_by_player_index[player_index] = nil
if is_selected then
selected_test_info_by_player_index[player_index] = {type = info_type_test, test = test}
end
local error_text_box = get_error_text_box(event.player)
if is_selected then
error_text_box.text = get_test_error(test)
else
error_text_box.text = ''
end
redraw_tests(container)
end
)
Gui.on_click(
run_all_button_name,
function(event)
local frame = event.player.gui.center[main_frame_name]
close_main_frame(frame)
local options = make_options(event.player_index)
Task.set_timeout_in_ticks(1, run_module_token, {module = nil, player = event.player, options = options})
end
)
Gui.on_click(
run_selected_button_name,
function(event)
local test_info = selected_test_info_by_player_index[event.player_index]
if test_info == nil then
return
end
local options = make_options(event.player_index)
local info_type = test_info.type
if info_type == info_type_module then
Task.set_timeout_in_ticks(
1,
run_module_token,
{module = test_info.module, player = event.player, options = options}
)
elseif info_type == info_type_test then
Task.set_timeout_in_ticks(
1,
run_test_token,
{test = test_info.test, player = event.player, options = options}
)
else
return
end
local frame = event.player.gui.center[main_frame_name]
close_main_frame(frame)
end
)
Gui.on_checked_state_changed(
stop_on_error_checkbox_name,
function(event)
stop_on_first_error_by_player_index[event.player_index] = event.element.state or nil
end
)
Event.add(
Runner.events.tests_run_finished,
function(event)
Public.open(event.player)
end
)
function Public.open(player)
local center = player.gui.center
local frame = center[main_frame_name]
if frame then
return
end
create_main_frame(center)
end
return Public