mirror of
https://github.com/Refactorio/RedMew.git
synced 2024-12-14 10:13:13 +02:00
424 lines
12 KiB
Lua
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
|