# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ class DirectoryCtrl: extends HBoxContainer var text = '': get: return _txt_path.text set(val): _txt_path.text = val var _txt_path = LineEdit.new() var _btn_dir = Button.new() var _dialog = FileDialog.new() func _init(): _btn_dir.text = '...' _btn_dir.connect('pressed',Callable(self,'_on_dir_button_pressed')) _txt_path.size_flags_horizontal = _txt_path.SIZE_EXPAND_FILL _dialog.mode = _dialog.FILE_MODE_OPEN_DIR _dialog.unresizable = false _dialog.connect("dir_selected",Callable(self,'_on_selected')) _dialog.connect("file_selected",Callable(self,'_on_selected')) _dialog.size = Vector2(1000, 700) func _on_selected(path): text = path func _on_dir_button_pressed(): _dialog.current_dir = _txt_path.text _dialog.popup_centered() func _ready(): add_child(_txt_path) add_child(_btn_dir) add_child(_dialog) func get_line_edit(): return _txt_path # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ class FileCtrl: extends DirectoryCtrl func _init(): _dialog.mode = _dialog.FILE_MODE_OPEN_FILE # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ class Vector2Ctrl: extends VBoxContainer var value = Vector2(-1, -1) : get: return get_value() set(val): set_value(val) var disabled = false : get: return get_disabled() set(val): set_disabled(val) var x_spin = SpinBox.new() var y_spin = SpinBox.new() func _init(): add_child(_make_one('x: ', x_spin)) add_child(_make_one('y: ', y_spin)) func _make_one(txt, spinner): var hbox = HBoxContainer.new() var lbl = Label.new() lbl.text = txt hbox.add_child(lbl) hbox.add_child(spinner) spinner.min_value = -1 spinner.max_value = 10000 spinner.size_flags_horizontal = spinner.SIZE_EXPAND_FILL return hbox func set_value(v): if(v != null): x_spin.value = v[0] y_spin.value = v[1] # Returns array instead of vector2 b/c that is what is stored in # in the dictionary and what is expected everywhere else. func get_value(): return [x_spin.value, y_spin.value] func set_disabled(should): get_parent().visible = !should x_spin.visible = !should y_spin.visible = !should func get_disabled(): pass # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ var _base_container = null var _base_control = null const DIRS_TO_LIST = 6 var _cfg_ctrls = {} var _avail_fonts = ['AnonymousPro', 'CourierPrime', 'LobsterTwo', 'Default'] func _init(cont): _base_container = cont _base_control = HBoxContainer.new() _base_control.size_flags_horizontal = _base_control.SIZE_EXPAND_FILL _base_control.mouse_filter = _base_control.MOUSE_FILTER_PASS # I don't remember what this is all about at all. Could be # garbage. Decided to spend more time typing this message # than figuring it out. var lbl = Label.new() lbl.size_flags_horizontal = lbl.SIZE_EXPAND_FILL lbl.mouse_filter = lbl.MOUSE_FILTER_STOP _base_control.add_child(lbl) # ------------------ # Private # ------------------ func _new_row(key, disp_text, value_ctrl, hint): var ctrl = _base_control.duplicate() var lbl = ctrl.get_child(0) lbl.hint_tooltip = hint lbl.text = disp_text _base_container.add_child(ctrl) _cfg_ctrls[key] = value_ctrl ctrl.add_child(value_ctrl) var rpad = CenterContainer.new() # rpad.custom_minimum_size.x = 5 ctrl.add_child(rpad) return ctrl func _add_title(text): var row = _base_control.duplicate() var lbl = row.get_child(0) lbl.text = text # lbl.align = Label.ALIGNMENT_CENTER _base_container.add_child(row) row.connect('draw', _on_title_cell_draw.bind(row)) func _add_number(key, value, disp_text, v_min, v_max, hint=''): var value_ctrl = SpinBox.new() value_ctrl.value = value value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL value_ctrl.min_value = v_min value_ctrl.max_value = v_max _wire_select_on_focus(value_ctrl.get_line_edit()) _new_row(key, disp_text, value_ctrl, hint) func _add_select(key, value, values, disp_text, hint=''): var value_ctrl = OptionButton.new() var select_idx = 0 for i in range(values.size()): value_ctrl.add_item(values[i]) if(value == values[i]): select_idx = i value_ctrl.selected = select_idx value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL _new_row(key, disp_text, value_ctrl, hint) func _add_value(key, value, disp_text, hint=''): var value_ctrl = LineEdit.new() value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL value_ctrl.text = value _wire_select_on_focus(value_ctrl) _new_row(key, disp_text, value_ctrl, hint) func _add_boolean(key, value, disp_text, hint=''): var value_ctrl = CheckBox.new() value_ctrl.button_pressed = value _new_row(key, disp_text, value_ctrl, hint) func _add_directory(key, value, disp_text, hint=''): var value_ctrl = DirectoryCtrl.new() value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL value_ctrl.text = value _wire_select_on_focus(value_ctrl.get_line_edit()) _new_row(key, disp_text, value_ctrl, hint) func _add_file(key, value, disp_text, hint=''): var value_ctrl = FileCtrl.new() value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL value_ctrl.text = value _wire_select_on_focus(value_ctrl.get_line_edit()) _new_row(key, disp_text, value_ctrl, hint) func _add_color(key, value, disp_text, hint=''): var value_ctrl = ColorPickerButton.new() value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL value_ctrl.color = value _new_row(key, disp_text, value_ctrl, hint) func _add_vector2(key, value, disp_text, hint=''): var value_ctrl = Vector2Ctrl.new() value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL value_ctrl.value = value _wire_select_on_focus(value_ctrl.x_spin.get_line_edit()) _wire_select_on_focus(value_ctrl.y_spin.get_line_edit()) _new_row(key, disp_text, value_ctrl, hint) # ----------------------------- # ------------------ # Events # ------------------ func _wire_select_on_focus(which): pass which.connect('focus_entered', _on_ctrl_focus_highlight.bind(which)) which.connect('focus_exited', _on_ctrl_focus_unhighlight.bind(which)) func _on_ctrl_focus_highlight(which): if(which.has_method('select_all')): which.call_deferred('select_all') func _on_ctrl_focus_unhighlight(which): if(which.has_method('select')): which.select(0, 0) func _on_title_cell_draw(which): which.draw_rect(Rect2(Vector2(0, 0), which.size), Color(0, 0, 0, .15)) # ------------------ # Public # ------------------ func get_config_issues(): var to_return = [] var has_directory = false for i in range(DIRS_TO_LIST): var key = str('directory_', i) var path = _cfg_ctrls[key].text if(path != null and path != ''): has_directory = true if(!DirAccess.dir_exists(path)): to_return.append(str('Test directory ', path, ' does not exist.')) if(!has_directory): to_return.append('You do not have any directories set.') if(!_cfg_ctrls['suffix'].text.ends_with('.gd')): to_return.append("Script suffix must end in '.gd'") return to_return func set_options(options): _add_title("Settings") _add_number("log_level", options.log_level, "Log Level", 0, 3, "Detail level for log messages.\n" + \ "\t0: Errors and failures only.\n" + \ "\t1: Adds all test names + warnings + info\n" + \ "\t2: Shows all asserts\n" + \ "\t3: Adds more stuff probably, maybe not.") _add_boolean('ignore_pause', options.ignore_pause, 'Ignore Pause', "Ignore calls to pause_before_teardown") _add_boolean('hide_orphans', options.hide_orphans, 'Hide Orphans', 'Do not display orphan counts in output.') _add_boolean('should_exit', options.should_exit, 'Exit on Finish', "Exit when tests finished.") _add_boolean('should_exit_on_success', options.should_exit_on_success, 'Exit on Success', "Exit if there are no failures. Does nothing if 'Exit on Finish' is enabled.") _add_title("Panel Output") _add_select('output_font_name', options.panel_options.font_name, _avail_fonts, 'Font', "The name of the font to use when running tests and in the output panel to the left.") _add_number('output_font_size', options.panel_options.font_size, 'Font Size', 5, 100, "The font size to use when running tests and in the output panel to the left.") _add_title('Runner Window') _add_boolean("gut_on_top", options.gut_on_top, "On Top", "The GUT Runner appears above children added during tests.") _add_number('opacity', options.opacity, 'Opacity', 0, 100, "The opacity of GUT when tests are running.") _add_boolean('should_maximize', options.should_maximize, 'Maximize', "Maximize GUT when tests are being run.") _add_boolean('compact_mode', options.compact_mode, 'Compact Mode', 'The runner will be in compact mode. This overrides Maximize.') _add_title('Runner Appearance') _add_select('font_name', options.font_name, _avail_fonts, 'Font', "The font to use for text output in the Gut Runner.") _add_number('font_size', options.font_size, 'Font Size', 5, 100, "The font size for text output in the Gut Runner.") _add_color('font_color', options.font_color, 'Font Color', "The font color for text output in the Gut Runner.") _add_color('background_color', options.background_color, 'Background Color', "The background color for text output in the Gut Runner.") _add_boolean('disable_colors', options.disable_colors, 'Disable Formatting', 'Disable formatting and colors used in the Runner. Does not affect panel output.') _add_title('Test Directories') _add_boolean('include_subdirs', options.include_subdirs, 'Include Subdirs', "Include subdirectories of the directories configured below.") for i in range(DIRS_TO_LIST): var value = '' if(options.dirs.size() > i): value = options.dirs[i] _add_directory(str('directory_', i), value, str('Directory ', i)) _add_title("XML Output") _add_value("junit_xml_file", options.junit_xml_file, "Output Path3D", "Path3D and filename where GUT should create a JUnit compliant XML file. " + "This file will contain the results of the last test run. To avoid " + "overriding the file use Include Timestamp.") _add_boolean("junit_xml_timestamp", options.junit_xml_timestamp, "Include Timestamp", "Include a timestamp in the filename so that each run gets its own xml file.") _add_title('Hooks') _add_file('pre_run_script', options.pre_run_script, 'Pre-Run Hook', 'This script will be run by GUT before any tests are run.') _add_file('post_run_script', options.post_run_script, 'Post-Run Hook', 'This script will be run by GUT after all tests are run.') _add_title('Misc') _add_value('prefix', options.prefix, 'Script Prefix', "The filename prefix for all test scripts.") _add_value('suffix', options.suffix, 'Script Suffix', "Script suffix, including .gd extension. For example '_foo.gd'.") _add_number('paint_after', options.paint_after, 'Paint After', 0.0, 1.0, "How long GUT will wait before pausing for 1 frame to paint the screen. 0 is never.") # since _add_number doesn't set step property, it will default to a step of # 1 and cast values to int. Give it a .5 step and re-set the value. _cfg_ctrls.paint_after.step = .05 _cfg_ctrls.paint_after.value = options.paint_after print('paint after = ', options.paint_after) func get_options(base_opts): var to_return = base_opts.duplicate() # Settings to_return.log_level = _cfg_ctrls.log_level.value to_return.ignore_pause = _cfg_ctrls.ignore_pause.button_pressed to_return.hide_orphans = _cfg_ctrls.hide_orphans.button_pressed to_return.should_exit = _cfg_ctrls.should_exit.button_pressed to_return.should_exit_on_success = _cfg_ctrls.should_exit_on_success.button_pressed #Output to_return.panel_options.font_name = _cfg_ctrls.output_font_name.get_item_text( _cfg_ctrls.output_font_name.selected) to_return.panel_options.font_size = _cfg_ctrls.output_font_size.value # Runner Appearance to_return.font_name = _cfg_ctrls.font_name.get_item_text( _cfg_ctrls.font_name.selected) to_return.font_size = _cfg_ctrls.font_size.value to_return.should_maximize = _cfg_ctrls.should_maximize.button_pressed to_return.compact_mode = _cfg_ctrls.compact_mode.button_pressed to_return.opacity = _cfg_ctrls.opacity.value to_return.background_color = _cfg_ctrls.background_color.color.to_html() to_return.font_color = _cfg_ctrls.font_color.color.to_html() to_return.disable_colors = _cfg_ctrls.disable_colors.button_pressed to_return.gut_on_top = _cfg_ctrls.gut_on_top.button_pressed to_return.paint_after = _cfg_ctrls.paint_after.value # Directories to_return.include_subdirs = _cfg_ctrls.include_subdirs.button_pressed var dirs = [] for i in range(DIRS_TO_LIST): var key = str('directory_', i) var val = _cfg_ctrls[key].text if(val != '' and val != null): dirs.append(val) to_return.dirs = dirs # XML Output to_return.junit_xml_file = _cfg_ctrls.junit_xml_file.text to_return.junit_xml_timestamp = _cfg_ctrls.junit_xml_timestamp.button_pressed # Hooks to_return.pre_run_script = _cfg_ctrls.pre_run_script.text to_return.post_run_script = _cfg_ctrls.post_run_script.text # Misc to_return.prefix = _cfg_ctrls.prefix.text to_return.suffix = _cfg_ctrls.suffix.text return to_return