@tool extends Control const RUNNER_JSON_PATH = "res://.gut_editor_config.json" const RESULT_FILE = "user://.gut_editor.bbcode" const RESULT_JSON = "user://.gut_editor.json" const SHORTCUTS_PATH = "res://.gut_editor_shortcuts.cfg" var TestScript = load("res://addons/gut/test.gd") var GutConfigGui = load("res://addons/gut/gui/gut_config_gui.gd") var ScriptTextEditors = load("res://addons/gut/gui/script_text_editor_controls.gd") var _interface = null var _is_running = false var _gut_config = load("res://addons/gut/gut_config.gd").new() var _gut_config_gui = null var _gut_plugin = null var _light_color = Color(0, 0, 0, .5) var _panel_button = null var _last_selected_path = null @onready var _ctrls = { output = $layout/RSplit/CResults/TabBar/OutputText.get_rich_text_edit(), output_ctrl = $layout/RSplit/CResults/TabBar/OutputText, run_button = $layout/ControlBar/RunAll, shortcuts_button = $layout/ControlBar/Shortcuts, settings_button = $layout/ControlBar/Settings, run_results_button = $layout/ControlBar/RunResultsBtn, output_button = $layout/ControlBar/OutputBtn, settings = $layout/RSplit/sc/Settings, shortcut_dialog = $BottomPanelShortcuts, light = $layout/RSplit/CResults/ControlBar/Light3D, results = { bar = $layout/RSplit/CResults/ControlBar, passing = $layout/RSplit/CResults/ControlBar/Passing/value, failing = $layout/RSplit/CResults/ControlBar/Failing/value, pending = $layout/RSplit/CResults/ControlBar/Pending/value, errors = $layout/RSplit/CResults/ControlBar/Errors/value, warnings = $layout/RSplit/CResults/ControlBar/Warnings/value, orphans = $layout/RSplit/CResults/ControlBar/Orphans/value }, run_at_cursor = $layout/ControlBar/RunAtCursor, run_results = $layout/RSplit/CResults/TabBar/RunResults } func _init(): _gut_config.load_panel_options(RUNNER_JSON_PATH) func _ready(): _ctrls.results.bar.connect("draw", _on_results_bar_draw.bind(_ctrls.results.bar)) hide_settings(!_ctrls.settings_button.button_pressed) _gut_config_gui = GutConfigGui.new(_ctrls.settings) _gut_config_gui.set_options(_gut_config.options) _apply_options_to_controls() _ctrls.shortcuts_button.icon = get_theme_icon("Shortcut", "EditorIcons") _ctrls.settings_button.icon = get_theme_icon("Tools", "EditorIcons") _ctrls.run_results_button.icon = get_theme_icon("AnimationTrackGroup", "EditorIcons") # Tree _ctrls.output_button.icon = get_theme_icon("Font", "EditorIcons") _ctrls.run_results.set_output_control(_ctrls.output_ctrl) _ctrls.run_results.set_font( _gut_config.options.panel_options.font_name, _gut_config.options.panel_options.font_size ) var check_import = load("res://addons/gut/images/red.png") if check_import == null: _ctrls.run_results.add_centered_text( "GUT got some new images that are not imported yet. Please restart Godot." ) print("GUT got some new images that are not imported yet. Please restart Godot.") else: _ctrls.run_results.add_centered_text("Let's run some tests!") func _apply_options_to_controls(): hide_settings(_gut_config.options.panel_options.hide_settings) hide_result_tree(_gut_config.options.panel_options.hide_result_tree) hide_output_text(_gut_config.options.panel_options.hide_output_text) _ctrls.output_ctrl.set_use_colors(_gut_config.options.panel_options.use_colors) _ctrls.output_ctrl.set_all_fonts(_gut_config.options.panel_options.font_name) _ctrls.output_ctrl.set_font_size(_gut_config.options.panel_options.font_size) _ctrls.run_results.set_font( _gut_config.options.panel_options.font_name, _gut_config.options.panel_options.font_size ) _ctrls.run_results.set_show_orphans(!_gut_config.options.hide_orphans) func _process(delta): if _is_running: if !_interface.is_playing_scene(): _is_running = false _ctrls.output_ctrl.add_text("\ndone") load_result_output() _gut_plugin.make_bottom_panel_item_visible(self) # --------------- # Private # --------------- func load_shortcuts(): _ctrls.shortcut_dialog.load_shortcuts(SHORTCUTS_PATH) _apply_shortcuts() func _is_test_script(script): var from = script.get_base_script() while from and from.resource_path != "res://addons/gut/test.gd": from = from.get_base_script() return from != null func _show_errors(errs): _ctrls.output_ctrl.clear() var text = "Cannot run tests, you have a configuration error:\n" for e in errs: text += str("* ", e, "\n") text += "Check your settings ----->" _ctrls.output_ctrl.add_text(text) hide_output_text(false) hide_settings(false) func _save_config(): _gut_config.options = _gut_config_gui.get_options(_gut_config.options) _gut_config.options.panel_options.hide_settings = !_ctrls.settings_button.button_pressed _gut_config.options.panel_options.hide_result_tree = !_ctrls.run_results_button.button_pressed _gut_config.options.panel_options.hide_output_text = !_ctrls.output_button.button_pressed _gut_config.options.panel_options.use_colors = _ctrls.output_ctrl.get_use_colors() var w_result = _gut_config.write_options(RUNNER_JSON_PATH) if w_result != OK: push_error(str("Could not write options to ", RUNNER_JSON_PATH, ": ", w_result)) return func _run_tests(): var issues = _gut_config_gui.get_config_issues() if issues.size() > 0: _show_errors(issues) return write_file(RESULT_FILE, "Run in progress") _save_config() _apply_options_to_controls() _ctrls.output_ctrl.clear() _ctrls.run_results.clear() _ctrls.run_results.add_centered_text("Running...") _interface.play_custom_scene("res://addons/gut/gui/GutRunner.tscn") _is_running = true _ctrls.output_ctrl.add_text("Running...") func _apply_shortcuts(): _ctrls.run_button.shortcut = _ctrls.shortcut_dialog.get_run_all() _ctrls.run_at_cursor.get_script_button().shortcut = ( _ctrls.shortcut_dialog.get_run_current_script() ) _ctrls.run_at_cursor.get_inner_button().shortcut = ( _ctrls.shortcut_dialog.get_run_current_inner() ) _ctrls.run_at_cursor.get_test_button().shortcut = _ctrls.shortcut_dialog.get_run_current_test() _panel_button.shortcut = _ctrls.shortcut_dialog.get_panel_button() func _run_all(): _gut_config.options.selected = null _gut_config.options.inner_class = null _gut_config.options.unit_test_name = null _run_tests() # --------------- # Events # --------------- func _on_results_bar_draw(bar): bar.draw_rect(Rect2(Vector2(0, 0), bar.size), Color(0, 0, 0, .2)) func _on_Light_draw(): var l = _ctrls.light l.draw_circle(Vector2(l.size.x / 2, l.size.y / 2), l.size.x / 2, _light_color) func _on_editor_script_changed(script): if script: set_current_script(script) func _on_RunAll_pressed(): _run_all() func _on_Shortcuts_pressed(): _ctrls.shortcut_dialog.popup_centered() func _on_bottom_panel_shortcuts_visibility_changed(): _apply_shortcuts() _ctrls.shortcut_dialog.save_shortcuts(SHORTCUTS_PATH) func _on_RunAtCursor_run_tests(what): _gut_config.options.selected = what.script _gut_config.options.inner_class = what.inner_class _gut_config.options.unit_test_name = what.test_method _run_tests() func _on_Settings_pressed(): hide_settings(!_ctrls.settings_button.button_pressed) _save_config() func _on_OutputBtn_pressed(): hide_output_text(!_ctrls.output_button.button_pressed) _save_config() func _on_RunResultsBtn_pressed(): hide_result_tree(!_ctrls.run_results_button.button_pressed) _save_config() # Currently not used, but will be when I figure out how to put # colors into the text results func _on_UseColors_pressed(): pass # --------------- # Public # --------------- func hide_result_tree(should): _ctrls.run_results.visible = !should _ctrls.run_results_button.button_pressed = !should func hide_settings(should): var s_scroll = _ctrls.settings.get_parent() s_scroll.visible = !should # collapse only collapses the first control, so we move # settings around to be the collapsed one if should: s_scroll.get_parent().move_child(s_scroll, 0) else: s_scroll.get_parent().move_child(s_scroll, 1) $layout/RSplit.collapsed = should _ctrls.settings_button.button_pressed = !should func hide_output_text(should): $layout/RSplit/CResults/TabBar/OutputText.visible = !should _ctrls.output_button.button_pressed = !should func load_result_output(): _ctrls.output_ctrl.load_file(RESULT_FILE) var summary = get_file_as_text(RESULT_JSON) var test_json_conv = JSON.new() if test_json_conv.parse(summary) != OK: return var results = test_json_conv.get_data() _ctrls.run_results.load_json_results(results) var summary_json = results["test_scripts"]["props"] _ctrls.results.passing.text = str(summary_json.passing) _ctrls.results.passing.get_parent().visible = true _ctrls.results.failing.text = str(summary_json.failures) _ctrls.results.failing.get_parent().visible = true _ctrls.results.pending.text = str(summary_json.pending) _ctrls.results.pending.get_parent().visible = _ctrls.results.pending.text != "0" _ctrls.results.errors.text = str(summary_json.errors) _ctrls.results.errors.get_parent().visible = _ctrls.results.errors.text != "0" _ctrls.results.warnings.text = str(summary_json.warnings) _ctrls.results.warnings.get_parent().visible = _ctrls.results.warnings.text != "0" _ctrls.results.orphans.text = str(summary_json.orphans) _ctrls.results.orphans.get_parent().visible = ( _ctrls.results.orphans.text != "0" and !_gut_config.options.hide_orphans ) if summary_json.tests == 0: _light_color = Color(1, 0, 0, .75) elif summary_json.failures != 0: _light_color = Color(1, 0, 0, .75) elif summary_json.pending != 0: _light_color = Color(1, 1, 0, .75) else: _light_color = Color(0, 1, 0, .75) _ctrls.light.visible = true _ctrls.light.queue_redraw() func set_current_script(script): if script: if _is_test_script(script): var file = script.resource_path.get_file() _last_selected_path = script.resource_path.get_file() _ctrls.run_at_cursor.activate_for_script(script.resource_path) func set_interface(value): _interface = value _interface.get_script_editor().connect( "editor_script_changed", Callable(self, "_on_editor_script_changed") ) var ste = ScriptTextEditors.new(_interface.get_script_editor()) _ctrls.run_results.set_interface(_interface) _ctrls.run_results.set_script_text_editors(ste) _ctrls.run_at_cursor.set_script_text_editors(ste) set_current_script(_interface.get_script_editor().get_current_script()) func set_plugin(value): _gut_plugin = value func set_panel_button(value): _panel_button = value # ------------------------------------------------------------------------------ # Write a file. # ------------------------------------------------------------------------------ func write_file(path, content): var f = FileAccess.open(path, FileAccess.WRITE) if f != null: f.store_string(content) f = null return FileAccess.get_open_error() # ------------------------------------------------------------------------------ # Returns the text of a file or an empty string if the file could not be opened. # ------------------------------------------------------------------------------ func get_file_as_text(path): var to_return = "" var f = FileAccess.open(path, FileAccess.READ) if f != null: to_return = f.get_as_text() f = null return to_return # ------------------------------------------------------------------------------ # return if_null if value is null otherwise return value # ------------------------------------------------------------------------------ func nvl(value, if_null): if value == null: return if_null else: return value