mirror of
https://github.com/lihop/godot-xterm.git
synced 2025-05-06 04:55:30 +02:00
Update Gut for Godot 4
Copied from Gut repo godot_4 branch commit: ba19a4c1b6f88160641a67a39729144046c6391f
This commit is contained in:
parent
44f7e3801c
commit
b5d3c6c9a5
105 changed files with 8545 additions and 5750 deletions
82
addons/gut/gui/BottomPanelShortcuts.gd
Normal file
82
addons/gut/gui/BottomPanelShortcuts.gd
Normal file
|
@ -0,0 +1,82 @@
|
|||
@tool
|
||||
extends Window
|
||||
|
||||
@onready var _ctrls = {
|
||||
run_all = $Layout/CRunAll/ShortcutButton,
|
||||
run_current_script = $Layout/CRunCurrentScript/ShortcutButton,
|
||||
run_current_inner = $Layout/CRunCurrentInner/ShortcutButton,
|
||||
run_current_test = $Layout/CRunCurrentTest/ShortcutButton,
|
||||
panel_button = $Layout/CPanelButton/ShortcutButton,
|
||||
}
|
||||
|
||||
func _ready():
|
||||
for key in _ctrls:
|
||||
var sc_button = _ctrls[key]
|
||||
sc_button.connect('start_edit', _on_edit_start.bind(sc_button))
|
||||
sc_button.connect('end_edit', _on_edit_end)
|
||||
|
||||
|
||||
# show dialog when running scene from editor.
|
||||
if(get_parent() == get_tree().root):
|
||||
popup_centered()
|
||||
|
||||
# ------------
|
||||
# Events
|
||||
# ------------
|
||||
func _on_Hide_pressed():
|
||||
hide()
|
||||
|
||||
func _on_edit_start(which):
|
||||
for key in _ctrls:
|
||||
var sc_button = _ctrls[key]
|
||||
if(sc_button != which):
|
||||
sc_button.disable_set(true)
|
||||
sc_button.disable_clear(true)
|
||||
|
||||
func _on_edit_end():
|
||||
for key in _ctrls:
|
||||
var sc_button = _ctrls[key]
|
||||
sc_button.disable_set(false)
|
||||
sc_button.disable_clear(false)
|
||||
|
||||
# ------------
|
||||
# Public
|
||||
# ------------
|
||||
func get_run_all():
|
||||
return _ctrls.run_all.get_shortcut()
|
||||
|
||||
func get_run_current_script():
|
||||
return _ctrls.run_current_script.get_shortcut()
|
||||
|
||||
func get_run_current_inner():
|
||||
return _ctrls.run_current_inner.get_shortcut()
|
||||
|
||||
func get_run_current_test():
|
||||
return _ctrls.run_current_test.get_shortcut()
|
||||
|
||||
func get_panel_button():
|
||||
return _ctrls.panel_button.get_shortcut()
|
||||
|
||||
|
||||
func save_shortcuts(path):
|
||||
var f = ConfigFile.new()
|
||||
|
||||
f.set_value('main', 'run_all', _ctrls.run_all.get_shortcut())
|
||||
f.set_value('main', 'run_current_script', _ctrls.run_current_script.get_shortcut())
|
||||
f.set_value('main', 'run_current_inner', _ctrls.run_current_inner.get_shortcut())
|
||||
f.set_value('main', 'run_current_test', _ctrls.run_current_test.get_shortcut())
|
||||
f.set_value('main', 'panel_button', _ctrls.panel_button.get_shortcut())
|
||||
|
||||
f.save(path)
|
||||
|
||||
|
||||
func load_shortcuts(path):
|
||||
var emptyShortcut = Shortcut.new()
|
||||
var f = ConfigFile.new()
|
||||
f.load(path)
|
||||
|
||||
_ctrls.run_all.set_shortcut(f.get_value('main', 'run_all', emptyShortcut))
|
||||
_ctrls.run_current_script.set_shortcut(f.get_value('main', 'run_current_script', emptyShortcut))
|
||||
_ctrls.run_current_inner.set_shortcut(f.get_value('main', 'run_current_inner', emptyShortcut))
|
||||
_ctrls.run_current_test.set_shortcut(f.get_value('main', 'run_current_test', emptyShortcut))
|
||||
_ctrls.panel_button.set_shortcut(f.get_value('main', 'panel_button', emptyShortcut))
|
232
addons/gut/gui/BottomPanelShortcuts.tscn
Normal file
232
addons/gut/gui/BottomPanelShortcuts.tscn
Normal file
|
@ -0,0 +1,232 @@
|
|||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://addons/gut/gui/ShortcutButton.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://addons/gut/gui/BottomPanelShortcuts.gd" type="Script" id=2]
|
||||
|
||||
[node name="BottomPanelShortcuts" type="Window"]
|
||||
visible = true
|
||||
anchor_right = 0.234
|
||||
anchor_bottom = 0.328
|
||||
offset_right = 195.384
|
||||
offset_bottom = 62.2
|
||||
custom_minimum_size = Vector2( 435, 305 )
|
||||
exclusive = true
|
||||
window_title = "GUT Shortcuts"
|
||||
resizable = true
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Layout" type="VBoxContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 5.0
|
||||
offset_right = -5.0
|
||||
offset_bottom = 2.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="TopPad" type="CenterContainer" parent="Layout"]
|
||||
offset_right = 425.0
|
||||
offset_bottom = 5.0
|
||||
custom_minimum_size = Vector2( 0, 5 )
|
||||
|
||||
[node name="Label2" type="Label" parent="Layout"]
|
||||
offset_top = 9.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 29.0
|
||||
custom_minimum_size = Vector2( 0, 20 )
|
||||
text = "Always Active"
|
||||
align = 1
|
||||
valign = 1
|
||||
autowrap = true
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="Layout/Label2"]
|
||||
show_behind_parent = true
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color( 0, 0, 0, 0.196078 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="CPanelButton" type="HBoxContainer" parent="Layout"]
|
||||
offset_top = 33.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 58.0
|
||||
|
||||
[node name="Label" type="Label" parent="Layout/CPanelButton"]
|
||||
offset_right = 138.0
|
||||
offset_bottom = 25.0
|
||||
custom_minimum_size = Vector2( 50, 0 )
|
||||
size_flags_vertical = 7
|
||||
text = "Show/Hide GUT Panel"
|
||||
valign = 1
|
||||
|
||||
[node name="ShortcutButton" parent="Layout/CPanelButton" instance=ExtResource( 1 )]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_left = 142.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 25.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="GutPanelPad" type="CenterContainer" parent="Layout"]
|
||||
offset_top = 62.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 67.0
|
||||
custom_minimum_size = Vector2( 0, 5 )
|
||||
|
||||
[node name="Label" type="Label" parent="Layout"]
|
||||
offset_top = 71.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 91.0
|
||||
custom_minimum_size = Vector2( 0, 20 )
|
||||
text = "Only Active When GUT Panel Shown"
|
||||
align = 1
|
||||
valign = 1
|
||||
autowrap = true
|
||||
|
||||
[node name="ColorRect2" type="ColorRect" parent="Layout/Label"]
|
||||
show_behind_parent = true
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color( 0, 0, 0, 0.196078 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="TopPad2" type="CenterContainer" parent="Layout"]
|
||||
offset_top = 95.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 100.0
|
||||
custom_minimum_size = Vector2( 0, 5 )
|
||||
|
||||
[node name="CRunAll" type="HBoxContainer" parent="Layout"]
|
||||
offset_top = 104.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 129.0
|
||||
|
||||
[node name="Label" type="Label" parent="Layout/CRunAll"]
|
||||
offset_right = 50.0
|
||||
offset_bottom = 25.0
|
||||
custom_minimum_size = Vector2( 50, 0 )
|
||||
size_flags_vertical = 7
|
||||
text = "Run All"
|
||||
valign = 1
|
||||
|
||||
[node name="ShortcutButton" parent="Layout/CRunAll" instance=ExtResource( 1 )]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_left = 54.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 25.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="CRunCurrentScript" type="HBoxContainer" parent="Layout"]
|
||||
offset_top = 133.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 158.0
|
||||
|
||||
[node name="Label" type="Label" parent="Layout/CRunCurrentScript"]
|
||||
offset_right = 115.0
|
||||
offset_bottom = 25.0
|
||||
custom_minimum_size = Vector2( 50, 0 )
|
||||
size_flags_vertical = 7
|
||||
text = "Run Current Script"
|
||||
valign = 1
|
||||
|
||||
[node name="ShortcutButton" parent="Layout/CRunCurrentScript" instance=ExtResource( 1 )]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_left = 119.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 25.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="CRunCurrentInner" type="HBoxContainer" parent="Layout"]
|
||||
offset_top = 162.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 187.0
|
||||
|
||||
[node name="Label" type="Label" parent="Layout/CRunCurrentInner"]
|
||||
offset_right = 150.0
|
||||
offset_bottom = 25.0
|
||||
custom_minimum_size = Vector2( 50, 0 )
|
||||
size_flags_vertical = 7
|
||||
text = "Run Current Inner Class"
|
||||
valign = 1
|
||||
|
||||
[node name="ShortcutButton" parent="Layout/CRunCurrentInner" instance=ExtResource( 1 )]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_left = 154.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 25.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="CRunCurrentTest" type="HBoxContainer" parent="Layout"]
|
||||
offset_top = 191.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 216.0
|
||||
|
||||
[node name="Label" type="Label" parent="Layout/CRunCurrentTest"]
|
||||
offset_right = 106.0
|
||||
offset_bottom = 25.0
|
||||
custom_minimum_size = Vector2( 50, 0 )
|
||||
size_flags_vertical = 7
|
||||
text = "Run Current Test"
|
||||
valign = 1
|
||||
|
||||
[node name="ShortcutButton" parent="Layout/CRunCurrentTest" instance=ExtResource( 1 )]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_left = 110.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 25.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="CenterContainer2" type="CenterContainer" parent="Layout"]
|
||||
offset_top = 220.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 241.0
|
||||
custom_minimum_size = Vector2( 0, 5 )
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ShiftDisclaimer" type="Label" parent="Layout"]
|
||||
offset_top = 245.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 259.0
|
||||
text = "\"Shift\" cannot be the only modifier for a shortcut."
|
||||
align = 2
|
||||
autowrap = true
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Layout"]
|
||||
offset_top = 263.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 293.0
|
||||
|
||||
[node name="CenterContainer" type="CenterContainer" parent="Layout/HBoxContainer"]
|
||||
offset_right = 361.0
|
||||
offset_bottom = 30.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="Hide" type="Button" parent="Layout/HBoxContainer"]
|
||||
offset_left = 365.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 30.0
|
||||
custom_minimum_size = Vector2( 60, 30 )
|
||||
text = "Close"
|
||||
|
||||
[node name="BottomPad" type="CenterContainer" parent="Layout"]
|
||||
offset_top = 297.0
|
||||
offset_right = 425.0
|
||||
offset_bottom = 307.0
|
||||
custom_minimum_size = Vector2( 0, 10 )
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[connection signal="pressed" from="Layout/HBoxContainer/Hide" to="." method="_on_Hide_pressed"]
|
367
addons/gut/gui/GutBottomPanel.gd
Normal file
367
addons/gut/gui/GutBottomPanel.gd
Normal file
|
@ -0,0 +1,367 @@
|
|||
@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
|
339
addons/gut/gui/GutBottomPanel.tscn
Normal file
339
addons/gut/gui/GutBottomPanel.tscn
Normal file
|
@ -0,0 +1,339 @@
|
|||
[gd_scene load_steps=10 format=3 uid="uid://b3bostcslstem"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/gut/gui/GutBottomPanel.gd" id="1"]
|
||||
[ext_resource type="PackedScene" path="res://addons/gut/gui/BottomPanelShortcuts.tscn" id="2"]
|
||||
[ext_resource type="PackedScene" path="res://addons/gut/gui/RunAtCursor.tscn" id="3"]
|
||||
[ext_resource type="Texture2D" path="res://addons/gut/gui/play.png" id="4"]
|
||||
[ext_resource type="PackedScene" path="res://addons/gut/gui/RunResults.tscn" id="5"]
|
||||
[ext_resource type="PackedScene" path="res://addons/gut/gui/OutputText.tscn" id="6"]
|
||||
|
||||
[sub_resource type="Shortcut" id="9"]
|
||||
|
||||
[sub_resource type="Image" id="Image_r56ab"]
|
||||
data = {
|
||||
"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
"format": "LumAlpha8",
|
||||
"height": 16,
|
||||
"mipmaps": false,
|
||||
"width": 16
|
||||
}
|
||||
|
||||
[sub_resource type="ImageTexture" id="2"]
|
||||
image = SubResource("Image_r56ab")
|
||||
|
||||
[node name="GutBottomPanel" type="Control"]
|
||||
custom_minimum_size = Vector2(250, 250)
|
||||
anchor_left = -0.0025866
|
||||
anchor_top = -0.00176575
|
||||
anchor_right = 0.997413
|
||||
anchor_bottom = 0.998234
|
||||
offset_left = 2.64868
|
||||
offset_top = 1.05945
|
||||
offset_right = 2.64862
|
||||
offset_bottom = 1.05945
|
||||
script = ExtResource("1")
|
||||
|
||||
[node name="layout" type="VBoxContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="ControlBar" type="HBoxContainer" parent="layout"]
|
||||
offset_right = 1023.0
|
||||
offset_bottom = 31.0
|
||||
|
||||
[node name="RunAll" type="Button" parent="layout/ControlBar"]
|
||||
offset_right = 85.0
|
||||
offset_bottom = 31.0
|
||||
size_flags_vertical = 11
|
||||
hint_tooltip = "Run all test scripts in the suite."
|
||||
shortcut = SubResource("9")
|
||||
text = "Run All"
|
||||
icon = ExtResource("4")
|
||||
|
||||
[node name="Label" type="Label" parent="layout/ControlBar"]
|
||||
offset_left = 89.0
|
||||
offset_top = 2.0
|
||||
offset_right = 162.0
|
||||
offset_bottom = 28.0
|
||||
hint_tooltip = "When a test script is edited, buttons are displayed to
|
||||
run the opened script or an Inner-Test-Class or a
|
||||
single test. The buttons change based on the location
|
||||
of the cursor in the file.
|
||||
|
||||
These buttons will remain active when editing other
|
||||
items so that you can run tests without having to switch
|
||||
back to the test script.
|
||||
|
||||
You can assign keyboard shortcuts for these buttons
|
||||
using the \"shortcuts\" button in the GUT panel."
|
||||
mouse_filter = 1
|
||||
text = "Current: "
|
||||
|
||||
[node name="RunAtCursor" parent="layout/ControlBar" instance=ExtResource("3")]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_left = 166.0
|
||||
offset_right = 532.0
|
||||
offset_bottom = 31.0
|
||||
|
||||
[node name="CenterContainer2" type="CenterContainer" parent="layout/ControlBar"]
|
||||
offset_left = 536.0
|
||||
offset_right = 903.0
|
||||
offset_bottom = 31.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Sep1" type="ColorRect" parent="layout/ControlBar"]
|
||||
offset_left = 907.0
|
||||
offset_right = 907.0
|
||||
offset_bottom = 31.0
|
||||
|
||||
[node name="RunResultsBtn" type="Button" parent="layout/ControlBar"]
|
||||
offset_left = 911.0
|
||||
offset_right = 935.0
|
||||
offset_bottom = 31.0
|
||||
hint_tooltip = "Show/Hide Results Tree Panel."
|
||||
toggle_mode = true
|
||||
icon = SubResource("2")
|
||||
|
||||
[node name="OutputBtn" type="Button" parent="layout/ControlBar"]
|
||||
offset_left = 939.0
|
||||
offset_right = 963.0
|
||||
offset_bottom = 31.0
|
||||
hint_tooltip = "Show/Hide Output Panel."
|
||||
toggle_mode = true
|
||||
icon = SubResource("2")
|
||||
|
||||
[node name="Settings" type="Button" parent="layout/ControlBar"]
|
||||
offset_left = 967.0
|
||||
offset_right = 991.0
|
||||
offset_bottom = 31.0
|
||||
hint_tooltip = "Show/Hide Settings Panel."
|
||||
toggle_mode = true
|
||||
icon = SubResource("2")
|
||||
|
||||
[node name="Sep2" type="ColorRect" parent="layout/ControlBar"]
|
||||
offset_left = 995.0
|
||||
offset_right = 995.0
|
||||
offset_bottom = 31.0
|
||||
|
||||
[node name="Shortcuts" type="Button" parent="layout/ControlBar"]
|
||||
offset_left = 999.0
|
||||
offset_right = 1023.0
|
||||
offset_bottom = 31.0
|
||||
size_flags_vertical = 11
|
||||
hint_tooltip = "Set shortcuts for GUT buttons. Shortcuts do not work when the GUT panel is not visible."
|
||||
icon = SubResource("2")
|
||||
|
||||
[node name="RSplit" type="HSplitContainer" parent="layout"]
|
||||
offset_top = 35.0
|
||||
offset_right = 1023.0
|
||||
offset_bottom = 599.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
collapsed = true
|
||||
|
||||
[node name="sc" type="ScrollContainer" parent="layout/RSplit"]
|
||||
visible = false
|
||||
offset_left = 593.0
|
||||
offset_right = 1093.0
|
||||
offset_bottom = 555.0
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="Settings" type="VBoxContainer" parent="layout/RSplit/sc"]
|
||||
offset_right = 500.0
|
||||
offset_bottom = 555.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="CResults" type="VBoxContainer" parent="layout/RSplit"]
|
||||
offset_right = 1023.0
|
||||
offset_bottom = 564.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ControlBar" type="HBoxContainer" parent="layout/RSplit/CResults"]
|
||||
offset_right = 1023.0
|
||||
|
||||
[node name="Light3D" type="Control" parent="layout/RSplit/CResults/ControlBar"]
|
||||
visible = false
|
||||
offset_right = 30.0
|
||||
offset_bottom = 35.0
|
||||
|
||||
[node name="Passing" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
|
||||
visible = false
|
||||
offset_left = 34.0
|
||||
offset_right = 107.0
|
||||
offset_bottom = 35.0
|
||||
|
||||
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Passing"]
|
||||
offset_right = 2.0
|
||||
offset_bottom = 35.0
|
||||
|
||||
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Passing"]
|
||||
offset_left = 6.0
|
||||
offset_top = 10.0
|
||||
offset_right = 54.0
|
||||
offset_bottom = 24.0
|
||||
text = "Passing"
|
||||
|
||||
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Passing"]
|
||||
offset_left = 58.0
|
||||
offset_top = 10.0
|
||||
offset_right = 73.0
|
||||
offset_bottom = 24.0
|
||||
text = "---"
|
||||
|
||||
[node name="Failing" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
|
||||
visible = false
|
||||
offset_left = 34.0
|
||||
offset_right = 100.0
|
||||
offset_bottom = 35.0
|
||||
|
||||
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Failing"]
|
||||
offset_right = 2.0
|
||||
offset_bottom = 35.0
|
||||
|
||||
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Failing"]
|
||||
offset_left = 6.0
|
||||
offset_top = 10.0
|
||||
offset_right = 47.0
|
||||
offset_bottom = 24.0
|
||||
text = "Failing"
|
||||
|
||||
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Failing"]
|
||||
offset_left = 51.0
|
||||
offset_top = 10.0
|
||||
offset_right = 66.0
|
||||
offset_bottom = 24.0
|
||||
text = "---"
|
||||
|
||||
[node name="Pending" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
|
||||
visible = false
|
||||
offset_left = 34.0
|
||||
offset_right = 110.0
|
||||
offset_bottom = 35.0
|
||||
|
||||
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Pending"]
|
||||
offset_right = 2.0
|
||||
offset_bottom = 35.0
|
||||
|
||||
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Pending"]
|
||||
offset_left = 6.0
|
||||
offset_top = 10.0
|
||||
offset_right = 57.0
|
||||
offset_bottom = 24.0
|
||||
text = "Pending"
|
||||
|
||||
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Pending"]
|
||||
offset_left = 61.0
|
||||
offset_top = 10.0
|
||||
offset_right = 76.0
|
||||
offset_bottom = 24.0
|
||||
text = "---"
|
||||
|
||||
[node name="Orphans" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
|
||||
visible = false
|
||||
offset_left = 34.0
|
||||
offset_right = 110.0
|
||||
offset_bottom = 35.0
|
||||
|
||||
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Orphans"]
|
||||
offset_right = 2.0
|
||||
offset_bottom = 35.0
|
||||
|
||||
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Orphans"]
|
||||
offset_left = 6.0
|
||||
offset_top = 10.0
|
||||
offset_right = 57.0
|
||||
offset_bottom = 24.0
|
||||
text = "Orphans"
|
||||
|
||||
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Orphans"]
|
||||
offset_left = 61.0
|
||||
offset_top = 10.0
|
||||
offset_right = 76.0
|
||||
offset_bottom = 24.0
|
||||
text = "---"
|
||||
|
||||
[node name="Errors" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
|
||||
visible = false
|
||||
offset_left = 34.0
|
||||
offset_right = 96.0
|
||||
offset_bottom = 35.0
|
||||
|
||||
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Errors"]
|
||||
offset_right = 2.0
|
||||
offset_bottom = 35.0
|
||||
|
||||
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Errors"]
|
||||
offset_left = 6.0
|
||||
offset_top = 10.0
|
||||
offset_right = 43.0
|
||||
offset_bottom = 24.0
|
||||
hint_tooltip = "The number of GUT errors generated. This does not include engine errors."
|
||||
text = "Errors"
|
||||
|
||||
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Errors"]
|
||||
offset_left = 47.0
|
||||
offset_top = 10.0
|
||||
offset_right = 62.0
|
||||
offset_bottom = 24.0
|
||||
text = "---"
|
||||
|
||||
[node name="Warnings" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
|
||||
visible = false
|
||||
offset_left = 34.0
|
||||
offset_right = 118.0
|
||||
offset_bottom = 35.0
|
||||
|
||||
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Warnings"]
|
||||
offset_right = 2.0
|
||||
offset_bottom = 35.0
|
||||
|
||||
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Warnings"]
|
||||
offset_left = 6.0
|
||||
offset_top = 10.0
|
||||
offset_right = 65.0
|
||||
offset_bottom = 24.0
|
||||
text = "Warnings"
|
||||
|
||||
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Warnings"]
|
||||
offset_left = 69.0
|
||||
offset_top = 10.0
|
||||
offset_right = 84.0
|
||||
offset_bottom = 24.0
|
||||
text = "---"
|
||||
|
||||
[node name="CenterContainer" type="CenterContainer" parent="layout/RSplit/CResults/ControlBar"]
|
||||
offset_right = 1023.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="TabBar" type="HSplitContainer" parent="layout/RSplit/CResults"]
|
||||
offset_top = 4.0
|
||||
offset_right = 1023.0
|
||||
offset_bottom = 564.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="RunResults" parent="layout/RSplit/CResults/TabBar" instance=ExtResource("5")]
|
||||
offset_right = 505.0
|
||||
offset_bottom = 560.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="OutputText" parent="layout/RSplit/CResults/TabBar" instance=ExtResource("6")]
|
||||
offset_left = 517.0
|
||||
offset_right = 1023.0
|
||||
offset_bottom = 560.0
|
||||
|
||||
[node name="BottomPanelShortcuts" parent="." instance=ExtResource("2")]
|
||||
visible = false
|
||||
|
||||
[connection signal="pressed" from="layout/ControlBar/RunAll" to="." method="_on_RunAll_pressed"]
|
||||
[connection signal="run_tests" from="layout/ControlBar/RunAtCursor" to="." method="_on_RunAtCursor_run_tests"]
|
||||
[connection signal="pressed" from="layout/ControlBar/RunResultsBtn" to="." method="_on_RunResultsBtn_pressed"]
|
||||
[connection signal="pressed" from="layout/ControlBar/OutputBtn" to="." method="_on_OutputBtn_pressed"]
|
||||
[connection signal="pressed" from="layout/ControlBar/Settings" to="." method="_on_Settings_pressed"]
|
||||
[connection signal="pressed" from="layout/ControlBar/Shortcuts" to="." method="_on_Shortcuts_pressed"]
|
||||
[connection signal="draw" from="layout/RSplit/CResults/ControlBar/Light3D" to="." method="_on_Light_draw"]
|
||||
[connection signal="visibility_changed" from="BottomPanelShortcuts" to="." method="_on_bottom_panel_shortcuts_visibility_changed"]
|
|
@ -1,15 +1,15 @@
|
|||
extends Node2D
|
||||
|
||||
var Gut = load("res://addons/gut/gut.gd")
|
||||
var ResultExporter = load("res://addons/gut/result_exporter.gd")
|
||||
var GutConfig = load("res://addons/gut/gut_config.gd")
|
||||
var Gut = load('res://addons/gut/gut.gd')
|
||||
var ResultExporter = load('res://addons/gut/result_exporter.gd')
|
||||
var GutConfig = load('res://addons/gut/gut_config.gd')
|
||||
|
||||
const RUNNER_JSON_PATH = "res://.gut_editor_config.json"
|
||||
const RESULT_FILE = "user://.gut_editor.bbcode"
|
||||
const RESULT_JSON = "user://.gut_editor.json"
|
||||
const RUNNER_JSON_PATH = 'res://.gut_editor_config.json'
|
||||
const RESULT_FILE = 'user://.gut_editor.bbcode'
|
||||
const RESULT_JSON = 'user://.gut_editor.json'
|
||||
|
||||
var _gut_config = null
|
||||
var _gut = null
|
||||
var _gut = null;
|
||||
var _wrote_results = false
|
||||
# Flag for when this is being used at the command line. Otherwise it is
|
||||
# assumed this is being used by the panel and being launched with
|
||||
|
@ -17,80 +17,100 @@ var _wrote_results = false
|
|||
var _cmdln_mode = false
|
||||
|
||||
@onready var _gut_layer = $GutLayer
|
||||
@onready var _gui = $GutLayer/GutScene
|
||||
|
||||
var auto_run_tests = true
|
||||
|
||||
func _ready():
|
||||
if _gut_config == null:
|
||||
if(_gut_config == null):
|
||||
_gut_config = GutConfig.new()
|
||||
_gut_config.load_options(RUNNER_JSON_PATH)
|
||||
_gut_config.load_panel_options(RUNNER_JSON_PATH)
|
||||
|
||||
# The command line will call run_tests on its own. When used from the panel
|
||||
# we have to kick off the tests ourselves b/c there's no way I know of to
|
||||
# interact with the scene that was run via play_custom_scene.
|
||||
if !_cmdln_mode:
|
||||
call_deferred("run_tests")
|
||||
if(!_cmdln_mode and auto_run_tests):
|
||||
call_deferred('run_tests')
|
||||
|
||||
|
||||
func run_tests():
|
||||
if _gut == null:
|
||||
_gut = Gut.new()
|
||||
func run_tests(show_gui=true):
|
||||
|
||||
_gut.set_add_children_to(self)
|
||||
if _gut_config.options.gut_on_top:
|
||||
if(_gut == null):
|
||||
get_gut()
|
||||
|
||||
_setup_gui(show_gui)
|
||||
|
||||
_gut.add_children_to = self
|
||||
if(_gut_config.options.gut_on_top):
|
||||
_gut_layer.add_child(_gut)
|
||||
else:
|
||||
add_child(_gut)
|
||||
|
||||
if !_cmdln_mode:
|
||||
_gut.connect(
|
||||
"tests_finished",
|
||||
self,
|
||||
"_on_tests_finished",
|
||||
[_gut_config.options.should_exit, _gut_config.options.should_exit_on_success]
|
||||
)
|
||||
if(!_cmdln_mode):
|
||||
_gut.end_run.connect(_on_tests_finished.bind(_gut_config.options.should_exit, _gut_config.options.should_exit_on_success))
|
||||
|
||||
_gut_config.config_gut(_gut)
|
||||
if _gut_config.options.gut_on_top:
|
||||
_gut.get_gui().goto_bottom_right_corner()
|
||||
var run_rest_of_scripts = _gut_config.options.unit_test_name == ''
|
||||
|
||||
var run_rest_of_scripts = _gut_config.options.unit_test_name == ""
|
||||
_gut.test_scripts(run_rest_of_scripts)
|
||||
|
||||
|
||||
func _write_results():
|
||||
# bbcode_text appears to be empty. I'm not 100% sure why. Until that is
|
||||
# figured out we have to just get the text which stinks.
|
||||
var content = _gut.get_gui().get_text_box().text
|
||||
func _setup_gui(show_gui):
|
||||
if(show_gui):
|
||||
_gui.gut = _gut
|
||||
var printer = _gut.logger.get_printer('gui')
|
||||
printer.set_textbox(_gui.get_textbox())
|
||||
else:
|
||||
_gut.logger.disable_printer('gui', true)
|
||||
_gui.visible = false
|
||||
|
||||
var f = File.new()
|
||||
var result = f.open(RESULT_FILE, f.WRITE)
|
||||
if result == OK:
|
||||
var opts = _gut_config.options
|
||||
_gui.set_font_size(opts.font_size)
|
||||
_gui.set_font(opts.font_name)
|
||||
if(opts.font_color != null and opts.font_color.is_valid_html_color()):
|
||||
_gui.set_default_font_color(Color(opts.font_color))
|
||||
if(opts.background_color != null and opts.background_color.is_valid_html_color()):
|
||||
_gui.set_background_color(Color(opts.background_color))
|
||||
|
||||
#_tester.set_modulate(Color(1.0, 1.0, 1.0, min(1.0, float(opts.opacity) / 100)))
|
||||
# if(opts.should_maximize):
|
||||
# _tester.maximize()
|
||||
#if(opts.compact_mode):
|
||||
# _tester.get_gui().compact_mode(true)
|
||||
|
||||
|
||||
|
||||
func _write_results():
|
||||
var content = _gui.get_textbox().text #_gut.logger.get_gui_bbcode()
|
||||
|
||||
var f = FileAccess.open(RESULT_FILE, FileAccess.WRITE)
|
||||
if(f != null):
|
||||
f.store_string(content)
|
||||
f.close()
|
||||
else:
|
||||
print("ERROR Could not save bbcode, result = ", result)
|
||||
push_error('Could not save bbcode, result = ', FileAccess.get_open_error())
|
||||
|
||||
var exporter = ResultExporter.new()
|
||||
var f_result = exporter.write_summary_file(_gut, RESULT_JSON)
|
||||
var f_result = exporter.write_json_file(_gut, RESULT_JSON)
|
||||
_wrote_results = true
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
if !_wrote_results and !_cmdln_mode:
|
||||
if(!_wrote_results and !_cmdln_mode):
|
||||
_write_results()
|
||||
|
||||
|
||||
func _on_tests_finished(should_exit, should_exit_on_success):
|
||||
_write_results()
|
||||
|
||||
if should_exit:
|
||||
if(should_exit):
|
||||
get_tree().quit()
|
||||
elif should_exit_on_success and _gut.get_fail_count() == 0:
|
||||
elif(should_exit_on_success and _gut.get_fail_count() == 0):
|
||||
get_tree().quit()
|
||||
|
||||
|
||||
func get_gut():
|
||||
if _gut == null:
|
||||
if(_gut == null):
|
||||
_gut = Gut.new()
|
||||
return _gut
|
||||
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
[gd_scene load_steps=2 format=2]
|
||||
[gd_scene load_steps=3 format=3 uid="uid://bqy3ikt6vu4b5"]
|
||||
|
||||
[ext_resource path="res://addons/gut/gui/GutRunner.gd" type="Script" id=1]
|
||||
[ext_resource type="Script" path="res://addons/gut/gui/GutRunner.gd" id="1"]
|
||||
[ext_resource type="PackedScene" uid="uid://m28heqtswbuq" path="res://addons/gut/GutScene.tscn" id="2_6ruxb"]
|
||||
|
||||
[node name="GutRunner" type="Node2D"]
|
||||
script = ExtResource( 1 )
|
||||
script = ExtResource("1")
|
||||
|
||||
[node name="GutLayer" type="CanvasLayer" parent="."]
|
||||
layer = 128
|
||||
|
||||
[node name="GutScene" parent="GutLayer" instance=ExtResource("2_6ruxb")]
|
||||
|
|
497
addons/gut/gui/GutSceneTheme.tres
Normal file
497
addons/gut/gui/GutSceneTheme.tres
Normal file
File diff suppressed because one or more lines are too long
303
addons/gut/gui/OutputText.gd
Normal file
303
addons/gut/gui/OutputText.gd
Normal file
|
@ -0,0 +1,303 @@
|
|||
extends VBoxContainer
|
||||
@tool
|
||||
|
||||
class SearchResults:
|
||||
var L = 0
|
||||
var C = 0
|
||||
|
||||
var positions = []
|
||||
var te = null
|
||||
var _last_term = ''
|
||||
|
||||
func _search_te(text, start_position, flags=0):
|
||||
var start_pos = start_position
|
||||
if(start_pos[L] < 0 or start_pos[L] > te.get_line_count()):
|
||||
start_pos[L] = 0
|
||||
if(start_pos[C] < 0):
|
||||
start_pos[L] = 0
|
||||
|
||||
var result = te.search(text, flags, start_pos[L], start_pos[C])
|
||||
if(result.size() == 2 and result[L] == start_position[L] and
|
||||
result[C] == start_position[C] and text == _last_term):
|
||||
if(flags == TextEdit.SEARCH_BACKWARDS):
|
||||
result[C] -= 1
|
||||
else:
|
||||
result[C] += 1
|
||||
result = _search_te(text, result, flags)
|
||||
L = result.y
|
||||
C = result.x
|
||||
elif(result.size() == 2):
|
||||
te.scroll_vertical = result[L]
|
||||
te.select(result[L], result[C], result[L], result[C] + text.length())
|
||||
te.set_caret_column(result[C])
|
||||
te.set_caret_line(result[L])
|
||||
te.center_viewport_to_caret()
|
||||
L = result.y
|
||||
C = result.x
|
||||
|
||||
_last_term = text
|
||||
te.center_viewport_to_caret()
|
||||
return result
|
||||
|
||||
func _cursor_to_pos():
|
||||
var to_return = [0, 0]
|
||||
to_return[L] = te.get_caret_line()
|
||||
to_return[C] = te.get_caret_column()
|
||||
return to_return
|
||||
|
||||
func find_next(term):
|
||||
return _search_te(term, _cursor_to_pos())
|
||||
|
||||
func find_prev(term):
|
||||
var new_pos = _search_te(term, _cursor_to_pos(), TextEdit.SEARCH_BACKWARDS)
|
||||
return new_pos
|
||||
|
||||
func get_next_pos():
|
||||
pass
|
||||
|
||||
func get_prev_pos():
|
||||
pass
|
||||
|
||||
func clear():
|
||||
pass
|
||||
|
||||
func find_all(text):
|
||||
var c_pos = [0, 0]
|
||||
var found = true
|
||||
var last_pos = [0, 0]
|
||||
positions.clear()
|
||||
|
||||
while(found):
|
||||
c_pos = te.search(text, 0, c_pos[L], c_pos[C])
|
||||
|
||||
if(c_pos.size() > 0 and
|
||||
(c_pos[L] > last_pos[L] or
|
||||
(c_pos[L] == last_pos[L] and c_pos[C] > last_pos[C]))):
|
||||
positions.append([c_pos[L], c_pos[C]])
|
||||
c_pos[C] += 1
|
||||
last_pos = c_pos
|
||||
else:
|
||||
found = false
|
||||
|
||||
|
||||
|
||||
@onready var _ctrls = {
|
||||
output = $Output,
|
||||
|
||||
copy_button = $Toolbar/CopyButton,
|
||||
use_colors = $Toolbar/UseColors,
|
||||
clear_button = $Toolbar/ClearButton,
|
||||
word_wrap = $Toolbar/WordWrap,
|
||||
show_search = $Toolbar/ShowSearch,
|
||||
|
||||
search_bar = {
|
||||
bar = $Search,
|
||||
search_term = $Search/SearchTerm,
|
||||
}
|
||||
}
|
||||
var _sr = SearchResults.new()
|
||||
|
||||
func _test_running_setup():
|
||||
_ctrls.use_colors.text = 'use colors'
|
||||
_ctrls.show_search.text = 'search'
|
||||
_ctrls.word_wrap.text = 'ww'
|
||||
|
||||
set_all_fonts("CourierPrime")
|
||||
set_font_size(20)
|
||||
|
||||
load_file('user://.gut_editor.bbcode')
|
||||
|
||||
|
||||
func _ready():
|
||||
_sr.te = _ctrls.output
|
||||
_ctrls.use_colors.icon = get_theme_icon('RichTextEffect', 'EditorIcons')
|
||||
_ctrls.show_search.icon = get_theme_icon('Search', 'EditorIcons')
|
||||
_ctrls.word_wrap.icon = get_theme_icon('Loop', 'EditorIcons')
|
||||
|
||||
_setup_colors()
|
||||
if(get_parent() == get_tree().root):
|
||||
_test_running_setup()
|
||||
|
||||
|
||||
# ------------------
|
||||
# Private
|
||||
# ------------------
|
||||
func _setup_colors():
|
||||
_ctrls.output.clear()
|
||||
var keywords = [
|
||||
['Failed', Color.RED],
|
||||
['Passed', Color.GREEN],
|
||||
['Pending', Color.YELLOW],
|
||||
['Orphans', Color.YELLOW],
|
||||
['WARNING', Color.YELLOW],
|
||||
['ERROR', Color.RED]
|
||||
]
|
||||
|
||||
for keyword in keywords:
|
||||
if (_ctrls.output.syntax_highlighter == null) :
|
||||
_ctrls.output.syntax_highlighter = CodeHighlighter.new()
|
||||
_ctrls.output.syntax_highlighter.add_keyword_color(keyword[0], keyword[1])
|
||||
|
||||
var f_color = null
|
||||
if (_ctrls.output.theme == null) :
|
||||
f_color = get_theme_color("font_color")
|
||||
else :
|
||||
f_color = _ctrls.output.theme.font_color
|
||||
_ctrls.output.add_theme_color_override("font_color_readonly", f_color)
|
||||
_ctrls.output.add_theme_color_override("function_color", f_color)
|
||||
_ctrls.output.add_theme_color_override("member_variable_color", f_color)
|
||||
_ctrls.output.queue_redraw()
|
||||
|
||||
|
||||
func _set_font(font_name, custom_name):
|
||||
var rtl = _ctrls.output
|
||||
if(font_name == null):
|
||||
rtl.set('custom_fonts/' + custom_name, null)
|
||||
else:
|
||||
pass
|
||||
# cuasing issues in 4.0
|
||||
# var dyn_font = FontFile.new()
|
||||
# var font_data = FontFile.new()
|
||||
# font_data.font_path = 'res://addons/gut/fonts/' + font_name + '.ttf'
|
||||
# font_data.antialiased = true
|
||||
# dyn_font.font_data = font_data
|
||||
# rtl.set('custom_fonts/' + custom_name, dyn_font)
|
||||
|
||||
|
||||
# ------------------
|
||||
# Events
|
||||
# ------------------
|
||||
func _on_CopyButton_pressed():
|
||||
copy_to_clipboard()
|
||||
|
||||
|
||||
func _on_UseColors_pressed():
|
||||
_ctrls.output.syntax_highlighter = _ctrls.use_colors.button_pressed
|
||||
|
||||
|
||||
func _on_ClearButton_pressed():
|
||||
clear()
|
||||
|
||||
|
||||
func _on_ShowSearch_pressed():
|
||||
show_search(_ctrls.show_search.button_pressed)
|
||||
|
||||
|
||||
func _on_SearchTerm_focus_entered():
|
||||
_ctrls.search_bar.search_term.call_deferred('select_all')
|
||||
|
||||
func _on_SearchNext_pressed():
|
||||
_sr.find_next(_ctrls.search_bar.search_term.text)
|
||||
|
||||
|
||||
func _on_SearchPrev_pressed():
|
||||
_sr.find_prev(_ctrls.search_bar.search_term.text)
|
||||
|
||||
|
||||
func _on_SearchTerm_text_changed(new_text):
|
||||
if(new_text == ''):
|
||||
_ctrls.output.deselect()
|
||||
else:
|
||||
_sr.find_next(new_text)
|
||||
|
||||
|
||||
func _on_SearchTerm_text_entered(new_text):
|
||||
if(Input.is_physical_key_pressed(KEY_SHIFT)):
|
||||
_sr.find_prev(new_text)
|
||||
else:
|
||||
_sr.find_next(new_text)
|
||||
|
||||
|
||||
func _on_SearchTerm_gui_input(event):
|
||||
if(event is InputEventKey and !event.pressed and event.scancode == KEY_ESCAPE):
|
||||
show_search(false)
|
||||
|
||||
func _on_WordWrap_pressed():
|
||||
_ctrls.output.wrap_enabled = _ctrls.word_wrap.pressed
|
||||
_ctrls.output.queue_redraw()
|
||||
|
||||
# ------------------
|
||||
# Public
|
||||
# ------------------
|
||||
func show_search(should):
|
||||
_ctrls.search_bar.bar.visible = should
|
||||
if(should):
|
||||
_ctrls.search_bar.search_term.grab_focus()
|
||||
_ctrls.search_bar.search_term.select_all()
|
||||
_ctrls.show_search.button_pressed = should
|
||||
|
||||
|
||||
func search(text, start_pos, highlight=true):
|
||||
return _sr.find_next(text)
|
||||
|
||||
|
||||
func copy_to_clipboard():
|
||||
var selected = _ctrls.output.get_selection_text()
|
||||
if(selected != ''):
|
||||
OS.clipboard = selected
|
||||
else:
|
||||
OS.clipboard = _ctrls.output.text
|
||||
|
||||
|
||||
func clear():
|
||||
_ctrls.output.text = ''
|
||||
|
||||
|
||||
func set_all_fonts(base_name):
|
||||
if(base_name == 'Default'):
|
||||
_set_font(null, 'font')
|
||||
# _set_font(null, 'normal_font')
|
||||
# _set_font(null, 'bold_font')
|
||||
# _set_font(null, 'italics_font')
|
||||
# _set_font(null, 'bold_italics_font')
|
||||
else:
|
||||
_set_font(base_name + '-Regular', 'font')
|
||||
# _set_font(base_name + '-Regular', 'normal_font')
|
||||
# _set_font(base_name + '-Bold', 'bold_font')
|
||||
# _set_font(base_name + '-Italic', 'italics_font')
|
||||
# _set_font(base_name + '-BoldItalic', 'bold_italics_font')
|
||||
|
||||
|
||||
func set_font_size(new_size):
|
||||
var rtl = _ctrls.output
|
||||
if(rtl.get('custom_fonts/font') != null):
|
||||
rtl.get('custom_fonts/font').size = new_size
|
||||
# rtl.get('custom_fonts/bold_italics_font').size = new_size
|
||||
# rtl.get('custom_fonts/bold_font').size = new_size
|
||||
# rtl.get('custom_fonts/italics_font').size = new_size
|
||||
# rtl.get('custom_fonts/normal_font').size = new_size
|
||||
|
||||
|
||||
func set_use_colors(value):
|
||||
pass
|
||||
|
||||
|
||||
func get_use_colors():
|
||||
return false;
|
||||
|
||||
|
||||
func get_rich_text_edit():
|
||||
return _ctrls.output
|
||||
|
||||
|
||||
func load_file(path):
|
||||
|
||||
var f = FileAccess.open(path, FileAccess.READ)
|
||||
if(f == null):
|
||||
return
|
||||
|
||||
var t = f.get_as_text()
|
||||
f.close()
|
||||
_ctrls.output.text = t
|
||||
_ctrls.output.scroll_vertical = _ctrls.output.get_line_count()
|
||||
_ctrls.output.set_deferred('scroll_vertical', _ctrls.output.get_line_count())
|
||||
|
||||
|
||||
func add_text(text):
|
||||
if(is_inside_tree()):
|
||||
_ctrls.output.text += text
|
||||
|
||||
|
||||
func scroll_to_line(line):
|
||||
_ctrls.output.scroll_vertical = line
|
||||
_ctrls.output.set_caret_line(line)
|
123
addons/gut/gui/OutputText.tscn
Normal file
123
addons/gut/gui/OutputText.tscn
Normal file
|
@ -0,0 +1,123 @@
|
|||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/gut/gui/OutputText.gd" type="Script" id=1]
|
||||
|
||||
[sub_resource type="Image" id=3]
|
||||
data = {
|
||||
"data": PackedByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ),
|
||||
"format": "LumAlpha8",
|
||||
"height": 16,
|
||||
"mipmaps": false,
|
||||
"width": 16
|
||||
}
|
||||
|
||||
[sub_resource type="ImageTexture" id=2]
|
||||
flags = 4
|
||||
flags = 4
|
||||
image = SubResource( 3 )
|
||||
size = Vector2( 16, 16 )
|
||||
|
||||
[node name="OutputText" type="VBoxContainer"]
|
||||
offset_right = 862.0
|
||||
offset_bottom = 523.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Toolbar" type="HBoxContainer" parent="."]
|
||||
offset_right = 862.0
|
||||
offset_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="ShowSearch" type="Button" parent="Toolbar"]
|
||||
offset_right = 28.0
|
||||
offset_bottom = 24.0
|
||||
toggle_mode = true
|
||||
icon = SubResource( 2 )
|
||||
|
||||
[node name="UseColors" type="Button" parent="Toolbar"]
|
||||
offset_left = 32.0
|
||||
offset_right = 60.0
|
||||
offset_bottom = 24.0
|
||||
hint_tooltip = "Colorize output.
|
||||
It's not the same as everywhere else (long story),
|
||||
but it is better than nothing."
|
||||
toggle_mode = true
|
||||
pressed = true
|
||||
icon = SubResource( 2 )
|
||||
|
||||
[node name="WordWrap" type="Button" parent="Toolbar"]
|
||||
offset_left = 64.0
|
||||
offset_right = 92.0
|
||||
offset_bottom = 24.0
|
||||
hint_tooltip = "Word wrap"
|
||||
toggle_mode = true
|
||||
icon = SubResource( 2 )
|
||||
|
||||
[node name="CenterContainer" type="CenterContainer" parent="Toolbar"]
|
||||
offset_left = 96.0
|
||||
offset_right = 743.0
|
||||
offset_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="CopyButton" type="Button" parent="Toolbar"]
|
||||
offset_left = 747.0
|
||||
offset_right = 798.0
|
||||
offset_bottom = 24.0
|
||||
hint_tooltip = "Copy to clipboard"
|
||||
text = " Copy "
|
||||
|
||||
[node name="ClearButton" type="Button" parent="Toolbar"]
|
||||
offset_left = 802.0
|
||||
offset_right = 862.0
|
||||
offset_bottom = 24.0
|
||||
text = " Clear "
|
||||
|
||||
[node name="Output" type="TextEdit" parent="."]
|
||||
offset_top = 28.0
|
||||
offset_right = 862.0
|
||||
offset_bottom = 523.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
readonly = true
|
||||
highlight_current_line = true
|
||||
syntax_highlighter = true
|
||||
show_line_numbers = true
|
||||
smooth_scrolling = true
|
||||
|
||||
[node name="Search" type="HBoxContainer" parent="."]
|
||||
visible = false
|
||||
offset_top = 499.0
|
||||
offset_right = 862.0
|
||||
offset_bottom = 523.0
|
||||
|
||||
[node name="SearchTerm" type="LineEdit" parent="Search"]
|
||||
offset_right = 804.0
|
||||
offset_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="SearchNext" type="Button" parent="Search"]
|
||||
offset_left = 808.0
|
||||
offset_right = 862.0
|
||||
offset_bottom = 24.0
|
||||
hint_tooltip = "Find next (enter)"
|
||||
text = "Next"
|
||||
|
||||
[node name="SearchPrev" type="Button" parent="Search"]
|
||||
offset_left = 808.0
|
||||
offset_right = 820.0
|
||||
offset_bottom = 20.0
|
||||
hint_tooltip = "Find previous (shift + enter)"
|
||||
text = "Prev"
|
||||
|
||||
[connection signal="pressed" from="Toolbar/ShowSearch" to="." method="_on_ShowSearch_pressed"]
|
||||
[connection signal="pressed" from="Toolbar/UseColors" to="." method="_on_UseColors_pressed"]
|
||||
[connection signal="pressed" from="Toolbar/WordWrap" to="." method="_on_WordWrap_pressed"]
|
||||
[connection signal="pressed" from="Toolbar/CopyButton" to="." method="_on_CopyButton_pressed"]
|
||||
[connection signal="pressed" from="Toolbar/ClearButton" to="." method="_on_ClearButton_pressed"]
|
||||
[connection signal="focus_entered" from="Search/SearchTerm" to="." method="_on_SearchTerm_focus_entered"]
|
||||
[connection signal="gui_input" from="Search/SearchTerm" to="." method="_on_SearchTerm_gui_input"]
|
||||
[connection signal="text_changed" from="Search/SearchTerm" to="." method="_on_SearchTerm_text_changed"]
|
||||
[connection signal="text_submitted" from="Search/SearchTerm" to="." method="_on_SearchTerm_text_entered"]
|
||||
[connection signal="pressed" from="Search/SearchNext" to="." method="_on_SearchNext_pressed"]
|
||||
[connection signal="pressed" from="Search/SearchPrev" to="." method="_on_SearchPrev_pressed"]
|
152
addons/gut/gui/RunAtCursor.gd
Normal file
152
addons/gut/gui/RunAtCursor.gd
Normal file
|
@ -0,0 +1,152 @@
|
|||
@tool
|
||||
extends Control
|
||||
|
||||
|
||||
var ScriptTextEditors = load('res://addons/gut/gui/script_text_editor_controls.gd')
|
||||
|
||||
@onready var _ctrls = {
|
||||
btn_script = $HBox/BtnRunScript,
|
||||
btn_inner = $HBox/BtnRunInnerClass,
|
||||
btn_method = $HBox/BtnRunMethod,
|
||||
lbl_none = $HBox/LblNoneSelected,
|
||||
arrow_1 = $HBox/Arrow1,
|
||||
arrow_2 = $HBox/Arrow2
|
||||
}
|
||||
|
||||
var _editors = null
|
||||
var _cur_editor = null
|
||||
var _last_line = -1
|
||||
var _cur_script_path = null
|
||||
var _last_info = null
|
||||
|
||||
signal run_tests(what)
|
||||
|
||||
|
||||
func _ready():
|
||||
_ctrls.lbl_none.visible = true
|
||||
_ctrls.btn_script.visible = false
|
||||
_ctrls.btn_inner.visible = false
|
||||
_ctrls.btn_method.visible = false
|
||||
|
||||
# ----------------
|
||||
# Private
|
||||
# ----------------
|
||||
func _set_editor(which):
|
||||
_last_line = -1
|
||||
if(_cur_editor != null and _cur_editor.get_ref()):
|
||||
_cur_editor.get_ref().disconnect('cursor_changed',Callable(self,'_on_cursor_changed'))
|
||||
|
||||
if(which != null):
|
||||
_cur_editor = weakref(which)
|
||||
which.connect('cursor_changed',Callable(self,'_on_cursor_changed'),[which])
|
||||
|
||||
_last_line = which.get_caret_line()
|
||||
_last_info = _editors.get_line_info()
|
||||
_update_buttons(_last_info)
|
||||
|
||||
|
||||
func _update_buttons(info):
|
||||
_ctrls.lbl_none.visible = _cur_script_path == null
|
||||
_ctrls.btn_script.visible = _cur_script_path != null
|
||||
|
||||
_ctrls.btn_inner.visible = info.inner_class != null
|
||||
_ctrls.arrow_1.visible = info.inner_class != null
|
||||
_ctrls.btn_inner.text = str(info.inner_class)
|
||||
_ctrls.btn_inner.hint_tooltip = str("Run all tests in Inner-Test-Class ", info.inner_class)
|
||||
|
||||
_ctrls.btn_method.visible = info.test_method != null
|
||||
_ctrls.arrow_2.visible = info.test_method != null
|
||||
_ctrls.btn_method.text = str(info.test_method)
|
||||
_ctrls.btn_method.hint_tooltip = str("Run test ", info.test_method)
|
||||
|
||||
# The button's new size won't take effect until the next frame.
|
||||
# This appears to be what was causing the button to not be clickable the
|
||||
# first time.
|
||||
call_deferred("_update_size")
|
||||
|
||||
func _update_size():
|
||||
custom_minimum_size.x = _ctrls.btn_method.size.x + _ctrls.btn_method.rect_position.x
|
||||
|
||||
# ----------------
|
||||
# Events
|
||||
# ----------------
|
||||
func _on_cursor_changed(which):
|
||||
if(which.get_caret_line() != _last_line):
|
||||
_last_line = which.get_caret_line()
|
||||
_last_info = _editors.get_line_info()
|
||||
_update_buttons(_last_info)
|
||||
|
||||
|
||||
func _on_BtnRunScript_pressed():
|
||||
var info = _last_info.duplicate()
|
||||
info.script = _cur_script_path.get_file()
|
||||
info.inner_class = null
|
||||
info.test_method = null
|
||||
emit_signal("run_tests", info)
|
||||
|
||||
|
||||
func _on_BtnRunInnerClass_pressed():
|
||||
var info = _last_info.duplicate()
|
||||
info.script = _cur_script_path.get_file()
|
||||
info.test_method = null
|
||||
emit_signal("run_tests", info)
|
||||
|
||||
|
||||
func _on_BtnRunMethod_pressed():
|
||||
var info = _last_info.duplicate()
|
||||
info.script = _cur_script_path.get_file()
|
||||
emit_signal("run_tests", info)
|
||||
|
||||
|
||||
# ----------------
|
||||
# Public
|
||||
# ----------------
|
||||
func set_script_text_editors(value):
|
||||
_editors = value
|
||||
|
||||
|
||||
func activate_for_script(path):
|
||||
_ctrls.btn_script.visible = true
|
||||
_ctrls.btn_script.text = path.get_file()
|
||||
_ctrls.btn_script.hint_tooltip = str("Run all tests in script ", path)
|
||||
_cur_script_path = path
|
||||
_editors.refresh()
|
||||
_set_editor(_editors.get_current_text_edit())
|
||||
|
||||
|
||||
func get_script_button():
|
||||
return _ctrls.btn_script
|
||||
|
||||
|
||||
func get_inner_button():
|
||||
return _ctrls.btn_inner
|
||||
|
||||
|
||||
func get_test_button():
|
||||
return _ctrls.btn_method
|
||||
|
||||
|
||||
# not used, thought was configurable but it's just the script prefix
|
||||
func set_method_prefix(value):
|
||||
_editors.set_method_prefix(value)
|
||||
|
||||
|
||||
# not used, thought was configurable but it's just the script prefix
|
||||
func set_inner_class_prefix(value):
|
||||
_editors.set_inner_class_prefix(value)
|
||||
|
||||
|
||||
# Mashed this function in here b/c it has _editors. Probably should be
|
||||
# somewhere else (possibly in script_text_editor_controls).
|
||||
func search_current_editor_for_text(txt):
|
||||
var te = _editors.get_current_text_edit()
|
||||
var result = te.search(txt, 0, 0, 0)
|
||||
var to_return = -1
|
||||
|
||||
if result.size() > 0:
|
||||
to_return = result[TextEdit.SEARCH_RESULT_LINE]
|
||||
|
||||
return to_return
|
||||
|
||||
|
||||
|
80
addons/gut/gui/RunAtCursor.tscn
Normal file
80
addons/gut/gui/RunAtCursor.tscn
Normal file
|
@ -0,0 +1,80 @@
|
|||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/gut/gui/RunAtCursor.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/gut/gui/play.png" type="Texture2D" id=2]
|
||||
[ext_resource path="res://addons/gut/gui/arrow.png" type="Texture2D" id=3]
|
||||
|
||||
[node name="RunAtCursor" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_right = 1.0
|
||||
offset_bottom = -527.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="HBox" type="HBoxContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="LblNoneSelected" type="Label" parent="HBox"]
|
||||
offset_top = 29.0
|
||||
offset_right = 50.0
|
||||
offset_bottom = 43.0
|
||||
text = "<None>"
|
||||
|
||||
[node name="BtnRunScript" type="Button" parent="HBox"]
|
||||
visible = false
|
||||
offset_left = 54.0
|
||||
offset_right = 140.0
|
||||
offset_bottom = 73.0
|
||||
text = "<script>"
|
||||
icon = ExtResource( 2 )
|
||||
|
||||
[node name="Arrow1" type="TextureButton" parent="HBox"]
|
||||
visible = false
|
||||
offset_left = 54.0
|
||||
offset_right = 78.0
|
||||
offset_bottom = 73.0
|
||||
custom_minimum_size = Vector2( 24, 0 )
|
||||
texture_normal = ExtResource( 3 )
|
||||
expand = true
|
||||
stretch_mode = 3
|
||||
|
||||
[node name="BtnRunInnerClass" type="Button" parent="HBox"]
|
||||
visible = false
|
||||
offset_left = 134.0
|
||||
offset_right = 243.0
|
||||
offset_bottom = 73.0
|
||||
text = "<inner class>"
|
||||
icon = ExtResource( 2 )
|
||||
|
||||
[node name="Arrow2" type="TextureButton" parent="HBox"]
|
||||
visible = false
|
||||
offset_left = 54.0
|
||||
offset_right = 78.0
|
||||
offset_bottom = 73.0
|
||||
custom_minimum_size = Vector2( 24, 0 )
|
||||
texture_normal = ExtResource( 3 )
|
||||
expand = true
|
||||
stretch_mode = 3
|
||||
|
||||
[node name="BtnRunMethod" type="Button" parent="HBox"]
|
||||
visible = false
|
||||
offset_left = 247.0
|
||||
offset_right = 337.0
|
||||
offset_bottom = 73.0
|
||||
text = "<method>"
|
||||
icon = ExtResource( 2 )
|
||||
|
||||
[connection signal="pressed" from="HBox/BtnRunScript" to="." method="_on_BtnRunScript_pressed"]
|
||||
[connection signal="pressed" from="HBox/BtnRunInnerClass" to="." method="_on_BtnRunInnerClass_pressed"]
|
||||
[connection signal="pressed" from="HBox/BtnRunMethod" to="." method="_on_BtnRunMethod_pressed"]
|
513
addons/gut/gui/RunResults.gd
Normal file
513
addons/gut/gui/RunResults.gd
Normal file
|
@ -0,0 +1,513 @@
|
|||
extends Control
|
||||
@tool
|
||||
|
||||
var _interface = null
|
||||
var _utils = load('res://addons/gut/utils.gd').new()
|
||||
var _hide_passing = true
|
||||
var _font = null
|
||||
var _font_size = null
|
||||
var _root = null
|
||||
var _max_icon_width = 10
|
||||
var _editors = null # script_text_editor_controls.gd
|
||||
var _show_orphans = true
|
||||
var _output_control = null
|
||||
|
||||
const _col_1_bg_color = Color(0, 0, 0, .1)
|
||||
|
||||
var _icons = {
|
||||
red = load('res://addons/gut/images/red.png'),
|
||||
green = load('res://addons/gut/images/green.png'),
|
||||
yellow = load('res://addons/gut/images/yellow.png'),
|
||||
}
|
||||
|
||||
signal search_for_text(text)
|
||||
|
||||
@onready var _ctrls = {
|
||||
tree = $VBox/Output/Scroll/Tree,
|
||||
lbl_overlay = $VBox/Output/OverlayMessage,
|
||||
chk_hide_passing = $VBox/Toolbar/HidePassing,
|
||||
toolbar = {
|
||||
toolbar = $VBox/Toolbar,
|
||||
collapse = $VBox/Toolbar/Collapse,
|
||||
collapse_all = $VBox/Toolbar/CollapseAll,
|
||||
expand = $VBox/Toolbar/Expand,
|
||||
expand_all = $VBox/Toolbar/ExpandAll,
|
||||
hide_passing = $VBox/Toolbar/HidePassing,
|
||||
show_script = $VBox/Toolbar/ShowScript,
|
||||
scroll_output = $VBox/Toolbar/ScrollOutput
|
||||
}
|
||||
}
|
||||
|
||||
func _test_running_setup():
|
||||
_hide_passing = true
|
||||
_show_orphans = true
|
||||
var _gut_config = load('res://addons/gut/gut_config.gd').new()
|
||||
_gut_config.load_panel_options('res://.gut_editor_config.json')
|
||||
set_font(
|
||||
_gut_config.options.panel_options.font_name,
|
||||
_gut_config.options.panel_options.font_size)
|
||||
|
||||
_ctrls.toolbar.hide_passing.text = '[hp]'
|
||||
load_json_file('user://.gut_editor.json')
|
||||
|
||||
|
||||
func _set_toolbutton_icon(btn, icon_name, text):
|
||||
if(Engine.is_editor_hint()):
|
||||
btn.icon = get_theme_icon(icon_name, 'EditorIcons')
|
||||
else:
|
||||
btn.text = str('[', text, ']')
|
||||
|
||||
|
||||
func _ready():
|
||||
var f = null
|
||||
if ($FontSampler.get_label_settings() == null) :
|
||||
f = get_theme_default_font()
|
||||
else :
|
||||
f = $FontSampler.get_label_settings().font
|
||||
var s_size = f.get_string_size("000 of 000 passed")
|
||||
_root = _ctrls.tree.create_item()
|
||||
_ctrls.tree.set_hide_root(true)
|
||||
_ctrls.tree.columns = 2
|
||||
_ctrls.tree.set_column_expand(0, true)
|
||||
_ctrls.tree.set_column_expand(1, false)
|
||||
_ctrls.tree.set_column_custom_minimum_width(1, s_size.x)
|
||||
|
||||
_set_toolbutton_icon(_ctrls.toolbar.collapse, 'CollapseTree', 'c')
|
||||
_set_toolbutton_icon(_ctrls.toolbar.collapse_all, 'CollapseTree', 'c')
|
||||
_set_toolbutton_icon(_ctrls.toolbar.expand, 'ExpandTree', 'e')
|
||||
_set_toolbutton_icon(_ctrls.toolbar.expand_all, 'ExpandTree', 'e')
|
||||
_set_toolbutton_icon(_ctrls.toolbar.show_script, 'Script', 'ss')
|
||||
_set_toolbutton_icon(_ctrls.toolbar.scroll_output, 'Font', 'so')
|
||||
|
||||
_ctrls.toolbar.hide_passing.set('custom_icons/checked', get_theme_icon('GuiVisibilityHidden', 'EditorIcons'))
|
||||
_ctrls.toolbar.hide_passing.set('custom_icons/unchecked', get_theme_icon('GuiVisibilityVisible', 'EditorIcons'))
|
||||
|
||||
if(get_parent() == get_tree().root):
|
||||
_test_running_setup()
|
||||
|
||||
call_deferred('_update_min_width')
|
||||
|
||||
func _update_min_width():
|
||||
custom_minimum_size.x = _ctrls.toolbar.toolbar.size.x
|
||||
|
||||
func _open_file(path, line_number):
|
||||
if(_interface == null):
|
||||
print('Too soon, wait a bit and try again.')
|
||||
return
|
||||
|
||||
var r = load(path)
|
||||
if(line_number != -1):
|
||||
_interface.edit_script(r, line_number)
|
||||
else:
|
||||
_interface.edit_script(r)
|
||||
|
||||
if(_ctrls.toolbar.show_script.pressed):
|
||||
_interface.set_main_screen_editor('Script')
|
||||
|
||||
|
||||
func _add_script_tree_item(script_path, script_json):
|
||||
var path_info = _get_path_and_inner_class_name_from_test_path(script_path)
|
||||
# print('* adding script ', path_info)
|
||||
var item_text = script_path
|
||||
var parent = _root
|
||||
|
||||
if(path_info.inner_class != ''):
|
||||
parent = _find_script_item_with_path(path_info.path)
|
||||
item_text = path_info.inner_class
|
||||
if(parent == null):
|
||||
parent = _add_script_tree_item(path_info.path, {})
|
||||
|
||||
var item = _ctrls.tree.create_item(parent)
|
||||
item.set_text(0, item_text)
|
||||
var meta = {
|
||||
"type":"script",
|
||||
"path":path_info.path,
|
||||
"inner_class":path_info.inner_class,
|
||||
"json":script_json}
|
||||
item.set_metadata(0, meta)
|
||||
item.set_custom_bg_color(1, _col_1_bg_color)
|
||||
|
||||
return item
|
||||
|
||||
|
||||
func _add_assert_item(text, icon, parent_item):
|
||||
# print(' * adding assert')
|
||||
var assert_item = _ctrls.tree.create_item(parent_item)
|
||||
assert_item.set_icon_max_width(0, _max_icon_width)
|
||||
assert_item.set_text(0, text)
|
||||
assert_item.set_metadata(0, {"type":"assert"})
|
||||
assert_item.set_icon(0, icon)
|
||||
assert_item.set_custom_bg_color(1, _col_1_bg_color)
|
||||
|
||||
return assert_item
|
||||
|
||||
|
||||
func _add_test_tree_item(test_name, test_json, script_item):
|
||||
# print(' * adding test ', test_name)
|
||||
var no_orphans_to_show = !_show_orphans or (_show_orphans and test_json.orphans == 0)
|
||||
if(_hide_passing and test_json['status'] == 'pass' and no_orphans_to_show):
|
||||
return
|
||||
|
||||
var item = _ctrls.tree.create_item(script_item)
|
||||
var status = test_json['status']
|
||||
var meta = {"type":"test", "json":test_json}
|
||||
|
||||
item.set_text(0, test_name)
|
||||
item.set_text(1, status)
|
||||
item.set_text_alignment(1, HORIZONTAL_ALIGNMENT_RIGHT)
|
||||
item.set_custom_bg_color(1, _col_1_bg_color)
|
||||
|
||||
item.set_metadata(0, meta)
|
||||
item.set_icon_max_width(0, _max_icon_width)
|
||||
|
||||
var orphan_text = 'orphans'
|
||||
if(test_json.orphans == 1):
|
||||
orphan_text = 'orphan'
|
||||
orphan_text = str(test_json.orphans, ' ', orphan_text)
|
||||
|
||||
|
||||
if(status == 'pass' and no_orphans_to_show):
|
||||
item.set_icon(0, _icons.green)
|
||||
elif(status == 'pass' and !no_orphans_to_show):
|
||||
item.set_icon(0, _icons.yellow)
|
||||
item.set_text(1, orphan_text)
|
||||
elif(status == 'fail'):
|
||||
item.set_icon(0, _icons.red)
|
||||
else:
|
||||
item.set_icon(0, _icons.yellow)
|
||||
|
||||
if(!_hide_passing):
|
||||
for passing in test_json.passing:
|
||||
_add_assert_item('pass: ' + passing, _icons.green, item)
|
||||
|
||||
for failure in test_json.failing:
|
||||
_add_assert_item("fail: " + failure.replace("\n", ''), _icons.red, item)
|
||||
|
||||
for pending in test_json.pending:
|
||||
_add_assert_item("pending: " + pending.replace("\n", ''), _icons.yellow, item)
|
||||
|
||||
if(status != 'pass' and !no_orphans_to_show):
|
||||
_add_assert_item(orphan_text, _icons.yellow, item)
|
||||
|
||||
return item
|
||||
|
||||
|
||||
func _load_result_tree(j):
|
||||
var scripts = j['test_scripts']['scripts']
|
||||
var script_keys = scripts.keys()
|
||||
# if we made it here, the json is valid and we did something, otherwise the
|
||||
# 'nothing to see here' should be visible.
|
||||
clear_centered_text()
|
||||
|
||||
var _last_script_item = null
|
||||
for key in script_keys:
|
||||
var tests = scripts[key]['tests']
|
||||
var test_keys = tests.keys()
|
||||
var s_item = _add_script_tree_item(key, scripts[key])
|
||||
var bad_count = 0
|
||||
|
||||
for test_key in test_keys:
|
||||
var t_item = _add_test_tree_item(test_key, tests[test_key], s_item)
|
||||
if(tests[test_key].status != 'pass'):
|
||||
bad_count += 1
|
||||
elif(t_item != null):
|
||||
t_item.collapsed = true
|
||||
|
||||
# get_children returns the first child or null. its a dumb name.
|
||||
if(s_item.get_children() == null):
|
||||
# var m = s_item.get_metadata(0)
|
||||
# print('!! Deleting ', m.path, ' ', m.inner_class)
|
||||
s_item.free()
|
||||
else:
|
||||
var total_text = str(test_keys.size(), ' passed')
|
||||
# s_item.set_text_alignment(1, s_item.ALIGN_LEFT)
|
||||
if(bad_count == 0):
|
||||
s_item.collapsed = true
|
||||
else:
|
||||
total_text = str(test_keys.size() - bad_count, ' of ', test_keys.size(), ' passed')
|
||||
s_item.set_text(1, total_text)
|
||||
|
||||
_free_childless_scripts()
|
||||
_show_all_passed()
|
||||
|
||||
|
||||
func _free_childless_scripts():
|
||||
var items = _root.get_children()
|
||||
for item in items:
|
||||
var next_item = item.get_next()
|
||||
if(item.get_children() == null):
|
||||
item.free()
|
||||
item = next_item
|
||||
|
||||
|
||||
func _find_script_item_with_path(path):
|
||||
var items = _root.get_children()
|
||||
var to_return = null
|
||||
|
||||
var idx = 0
|
||||
while(idx < items.size() and to_return == null):
|
||||
var item = items[idx]
|
||||
if(item.get_metadata(0).path == path):
|
||||
to_return = item
|
||||
else:
|
||||
idx += 1
|
||||
|
||||
return to_return
|
||||
|
||||
|
||||
func _get_line_number_from_assert_msg(msg):
|
||||
var line = -1
|
||||
if(msg.find('at line') > 0):
|
||||
line = msg.split("at line")[-1].split(" ")[-1].to_int()
|
||||
return line
|
||||
|
||||
|
||||
func _get_path_and_inner_class_name_from_test_path(path):
|
||||
var to_return = {
|
||||
path = '',
|
||||
inner_class = ''
|
||||
}
|
||||
|
||||
to_return.path = path
|
||||
if !path.ends_with('.gd'):
|
||||
var loc = path.find('.gd')
|
||||
to_return.inner_class = path.split('.')[-1]
|
||||
to_return.path = path.substr(0, loc + 3)
|
||||
return to_return
|
||||
|
||||
|
||||
func _handle_tree_item_select(item, force_scroll):
|
||||
var item_type = item.get_metadata(0).type
|
||||
|
||||
var path = '';
|
||||
var line = -1;
|
||||
var method_name = ''
|
||||
var inner_class = ''
|
||||
|
||||
if(item_type == 'test'):
|
||||
var s_item = item.get_parent()
|
||||
path = s_item.get_metadata(0)['path']
|
||||
inner_class = s_item.get_metadata(0)['inner_class']
|
||||
line = -1
|
||||
method_name = item.get_text(0)
|
||||
elif(item_type == 'assert'):
|
||||
var s_item = item.get_parent().get_parent()
|
||||
path = s_item.get_metadata(0)['path']
|
||||
inner_class = s_item.get_metadata(0)['inner_class']
|
||||
|
||||
line = _get_line_number_from_assert_msg(item.get_text(0))
|
||||
method_name = item.get_parent().get_text(0)
|
||||
elif(item_type == 'script'):
|
||||
path = item.get_metadata(0)['path']
|
||||
if(item.get_parent() != _root):
|
||||
inner_class = item.get_text(0)
|
||||
line = -1
|
||||
method_name = ''
|
||||
else:
|
||||
return
|
||||
|
||||
var path_info = _get_path_and_inner_class_name_from_test_path(path)
|
||||
if(force_scroll or _ctrls.toolbar.show_script.pressed):
|
||||
_goto_code(path, line, method_name, inner_class)
|
||||
if(force_scroll or _ctrls.toolbar.scroll_output.pressed):
|
||||
_goto_output(path, method_name, inner_class)
|
||||
|
||||
|
||||
# starts at beginning of text edit and searches for each search term, moving
|
||||
# through the text as it goes; ensuring that, when done, it found the first
|
||||
# occurance of the last srting that happend after the first occurance of
|
||||
# each string before it. (Generic way of searching for a method name in an
|
||||
# inner class that may have be a duplicate of a method name in a different
|
||||
# inner class)
|
||||
func _get_line_number_for_seq_search(search_strings, te):
|
||||
# var te = _editors.get_current_text_edit()
|
||||
var result = null
|
||||
var line = Vector2i(-1, -1)
|
||||
var s_flags = 0
|
||||
|
||||
var i = 0
|
||||
var string_found = true
|
||||
while(i < search_strings.size() and string_found):
|
||||
result = te.search(search_strings[i], s_flags, line.y, line.x)
|
||||
if(result.x != -1):
|
||||
line = result
|
||||
else:
|
||||
string_found = false
|
||||
i += 1
|
||||
|
||||
return line.y
|
||||
|
||||
|
||||
func _goto_code(path, line, method_name='', inner_class =''):
|
||||
if(_interface == null):
|
||||
print('going to ', [path, line, method_name, inner_class])
|
||||
return
|
||||
|
||||
_open_file(path, line)
|
||||
if(line == -1):
|
||||
var search_strings = []
|
||||
if(inner_class != ''):
|
||||
search_strings.append(inner_class)
|
||||
|
||||
if(method_name != ''):
|
||||
search_strings.append(method_name)
|
||||
|
||||
line = _get_line_number_for_seq_search(search_strings, _editors.get_current_text_edit())
|
||||
if(line != -1):
|
||||
_interface.get_script_editor().goto_line(line)
|
||||
|
||||
|
||||
func _goto_output(path, method_name, inner_class):
|
||||
if(_output_control == null):
|
||||
return
|
||||
|
||||
var search_strings = [path]
|
||||
|
||||
if(inner_class != ''):
|
||||
search_strings.append(inner_class)
|
||||
|
||||
if(method_name != ''):
|
||||
search_strings.append(method_name)
|
||||
|
||||
var line = _get_line_number_for_seq_search(search_strings, _output_control.get_rich_text_edit())
|
||||
if(line != -1):
|
||||
_output_control.scroll_to_line(line)
|
||||
|
||||
|
||||
func _show_all_passed():
|
||||
if(_root.get_children() == null):
|
||||
add_centered_text('Everything passed!')
|
||||
|
||||
|
||||
func _set_collapsed_on_all(item, value):
|
||||
if(item == _root):
|
||||
var node = _root.get_children()
|
||||
while(node != null):
|
||||
node.call_recursive('set_collapsed', value)
|
||||
node = node.get_next()
|
||||
else:
|
||||
item.call_recursive('set_collapsed', value)
|
||||
|
||||
# --------------
|
||||
# Events
|
||||
# --------------
|
||||
func _on_Tree_item_selected():
|
||||
# do not force scroll
|
||||
var item = _ctrls.tree.get_selected()
|
||||
_handle_tree_item_select(item, false)
|
||||
# it just looks better if the left is always selected.
|
||||
if(item.is_selected(1)):
|
||||
item.deselect(1)
|
||||
item.select(0)
|
||||
|
||||
|
||||
func _on_Tree_item_activated():
|
||||
# force scroll
|
||||
print('double clicked')
|
||||
_handle_tree_item_select(_ctrls.tree.get_selected(), true)
|
||||
|
||||
func _on_Collapse_pressed():
|
||||
collapse_selected()
|
||||
|
||||
|
||||
func _on_Expand_pressed():
|
||||
expand_selected()
|
||||
|
||||
|
||||
func _on_CollapseAll_pressed():
|
||||
collapse_all()
|
||||
|
||||
|
||||
func _on_ExpandAll_pressed():
|
||||
expand_all()
|
||||
|
||||
|
||||
func _on_Hide_Passing_pressed():
|
||||
_hide_passing = _ctrls.toolbar.hide_passing.button_pressed
|
||||
|
||||
# --------------
|
||||
# Public
|
||||
# --------------
|
||||
func load_json_file(path):
|
||||
var text = _utils.get_file_as_text(path)
|
||||
if(text != ''):
|
||||
var test_json_conv = JSON.new()
|
||||
test_json_conv.parse(text)
|
||||
var result = test_json_conv.get_data()
|
||||
if(result.error != OK):
|
||||
add_centered_text(str(path, " has invalid json in it \n",
|
||||
'Error ', result.error, "@", result.error_line, "\n",
|
||||
result.error_string))
|
||||
return
|
||||
|
||||
load_json_results(result.result)
|
||||
else:
|
||||
add_centered_text(str(path, ' was empty or does not exist.'))
|
||||
|
||||
|
||||
func load_json_results(j):
|
||||
clear()
|
||||
add_centered_text('Nothing Here')
|
||||
_load_result_tree(j)
|
||||
|
||||
|
||||
func add_centered_text(t):
|
||||
_ctrls.lbl_overlay.text = t
|
||||
|
||||
|
||||
func clear_centered_text():
|
||||
_ctrls.lbl_overlay.text = ''
|
||||
|
||||
|
||||
func clear():
|
||||
_ctrls.tree.clear()
|
||||
_root = _ctrls.tree.create_item()
|
||||
clear_centered_text()
|
||||
|
||||
|
||||
func set_interface(which):
|
||||
_interface = which
|
||||
|
||||
|
||||
func set_script_text_editors(value):
|
||||
_editors = value
|
||||
|
||||
|
||||
func collapse_all():
|
||||
_set_collapsed_on_all(_root, true)
|
||||
|
||||
|
||||
func expand_all():
|
||||
_set_collapsed_on_all(_root, false)
|
||||
|
||||
|
||||
func collapse_selected():
|
||||
var item = _ctrls.tree.get_selected()
|
||||
if(item != null):
|
||||
_set_collapsed_on_all(item, true)
|
||||
|
||||
func expand_selected():
|
||||
var item = _ctrls.tree.get_selected()
|
||||
if(item != null):
|
||||
_set_collapsed_on_all(item, false)
|
||||
|
||||
|
||||
func set_show_orphans(should):
|
||||
_show_orphans = should
|
||||
|
||||
|
||||
func set_font(font_name, size):
|
||||
pass
|
||||
# var dyn_font = FontFile.new()
|
||||
# var font_data = FontFile.new()
|
||||
# font_data.font_path = 'res://addons/gut/fonts/' + font_name + '-Regular.ttf'
|
||||
# font_data.antialiased = true
|
||||
# dyn_font.font_data = font_data
|
||||
#
|
||||
# _font = dyn_font
|
||||
# _font.size = size
|
||||
# _font_size = size
|
||||
|
||||
|
||||
func set_output_control(value):
|
||||
_output_control = value
|
165
addons/gut/gui/RunResults.tscn
Normal file
165
addons/gut/gui/RunResults.tscn
Normal file
|
@ -0,0 +1,165 @@
|
|||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/gut/gui/RunResults.gd" type="Script" id=1]
|
||||
|
||||
[sub_resource type="Image" id=3]
|
||||
data = {
|
||||
"data": PackedByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ),
|
||||
"format": "LumAlpha8",
|
||||
"height": 16,
|
||||
"mipmaps": false,
|
||||
"width": 16
|
||||
}
|
||||
|
||||
[sub_resource type="ImageTexture" id=2]
|
||||
flags = 4
|
||||
flags = 4
|
||||
image = SubResource( 3 )
|
||||
size = Vector2( 16, 16 )
|
||||
|
||||
[node name="RunResults" type="Control"]
|
||||
offset_right = 595.0
|
||||
offset_bottom = 459.0
|
||||
custom_minimum_size = Vector2( 302, 0 )
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="VBox" type="VBoxContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="Toolbar" type="HBoxContainer" parent="VBox"]
|
||||
offset_right = 296.0
|
||||
offset_bottom = 24.0
|
||||
size_flags_horizontal = 0
|
||||
|
||||
[node name="Expand" type="Button" parent="VBox/Toolbar"]
|
||||
offset_right = 28.0
|
||||
offset_bottom = 24.0
|
||||
hint_tooltip = "Expand selected item and all children."
|
||||
icon = SubResource( 2 )
|
||||
|
||||
[node name="Collapse" type="Button" parent="VBox/Toolbar"]
|
||||
offset_left = 32.0
|
||||
offset_right = 60.0
|
||||
offset_bottom = 24.0
|
||||
hint_tooltip = "Collapse selected item and all children."
|
||||
icon = SubResource( 2 )
|
||||
|
||||
[node name="Sep" type="ColorRect" parent="VBox/Toolbar"]
|
||||
offset_left = 64.0
|
||||
offset_right = 66.0
|
||||
offset_bottom = 24.0
|
||||
custom_minimum_size = Vector2( 2, 0 )
|
||||
|
||||
[node name="LblAll" type="Label" parent="VBox/Toolbar"]
|
||||
offset_left = 70.0
|
||||
offset_top = 5.0
|
||||
offset_right = 91.0
|
||||
offset_bottom = 19.0
|
||||
text = "All:"
|
||||
align = 1
|
||||
|
||||
[node name="ExpandAll" type="Button" parent="VBox/Toolbar"]
|
||||
offset_left = 95.0
|
||||
offset_right = 123.0
|
||||
offset_bottom = 24.0
|
||||
hint_tooltip = "Expand All."
|
||||
icon = SubResource( 2 )
|
||||
|
||||
[node name="CollapseAll" type="Button" parent="VBox/Toolbar"]
|
||||
offset_left = 127.0
|
||||
offset_right = 155.0
|
||||
offset_bottom = 24.0
|
||||
hint_tooltip = "Collapse all."
|
||||
icon = SubResource( 2 )
|
||||
|
||||
[node name="Sep2" type="ColorRect" parent="VBox/Toolbar"]
|
||||
offset_left = 159.0
|
||||
offset_right = 161.0
|
||||
offset_bottom = 24.0
|
||||
custom_minimum_size = Vector2( 2, 0 )
|
||||
|
||||
[node name="HidePassing" type="CheckBox" parent="VBox/Toolbar"]
|
||||
offset_left = 165.0
|
||||
offset_right = 189.0
|
||||
offset_bottom = 24.0
|
||||
hint_tooltip = "Show/Hide passing tests. Takes effect on next run."
|
||||
size_flags_horizontal = 4
|
||||
custom_icons/checked = SubResource( 2 )
|
||||
custom_icons/unchecked = SubResource( 2 )
|
||||
pressed = true
|
||||
__meta__ = {
|
||||
"_editor_description_": ""
|
||||
}
|
||||
|
||||
[node name="Sep3" type="ColorRect" parent="VBox/Toolbar"]
|
||||
offset_left = 193.0
|
||||
offset_right = 195.0
|
||||
offset_bottom = 24.0
|
||||
custom_minimum_size = Vector2( 2, 0 )
|
||||
|
||||
[node name="LblSync" type="Label" parent="VBox/Toolbar"]
|
||||
offset_left = 199.0
|
||||
offset_top = 5.0
|
||||
offset_right = 232.0
|
||||
offset_bottom = 19.0
|
||||
text = "Sync:"
|
||||
align = 1
|
||||
|
||||
[node name="ShowScript" type="Button" parent="VBox/Toolbar"]
|
||||
offset_left = 236.0
|
||||
offset_right = 264.0
|
||||
offset_bottom = 24.0
|
||||
hint_tooltip = "Open script and scroll to line when a tree item is clicked."
|
||||
toggle_mode = true
|
||||
pressed = true
|
||||
icon = SubResource( 2 )
|
||||
|
||||
[node name="ScrollOutput" type="Button" parent="VBox/Toolbar"]
|
||||
offset_left = 268.0
|
||||
offset_right = 296.0
|
||||
offset_bottom = 24.0
|
||||
hint_tooltip = "Scroll to related line in the output panel when tree item clicked."
|
||||
toggle_mode = true
|
||||
pressed = true
|
||||
icon = SubResource( 2 )
|
||||
|
||||
[node name="Output" type="Panel" parent="VBox"]
|
||||
self_modulate = Color( 1, 1, 1, 0.541176 )
|
||||
offset_top = 28.0
|
||||
offset_right = 595.0
|
||||
offset_bottom = 459.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="Scroll" type="ScrollContainer" parent="VBox/Output"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="Tree" type="Tree" parent="VBox/Output/Scroll"]
|
||||
offset_right = 595.0
|
||||
offset_bottom = 431.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
columns = 2
|
||||
hide_root = true
|
||||
|
||||
[node name="OverlayMessage" type="Label" parent="VBox/Output"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
align = 1
|
||||
valign = 1
|
||||
|
||||
[node name="FontSampler" type="Label" parent="."]
|
||||
visible = false
|
||||
offset_right = 40.0
|
||||
offset_bottom = 14.0
|
||||
text = "000 of 000 passed"
|
||||
|
||||
[connection signal="pressed" from="VBox/Toolbar/Expand" to="." method="_on_Expand_pressed"]
|
||||
[connection signal="pressed" from="VBox/Toolbar/Collapse" to="." method="_on_Collapse_pressed"]
|
||||
[connection signal="pressed" from="VBox/Toolbar/ExpandAll" to="." method="_on_ExpandAll_pressed"]
|
||||
[connection signal="pressed" from="VBox/Toolbar/CollapseAll" to="." method="_on_CollapseAll_pressed"]
|
||||
[connection signal="pressed" from="VBox/Toolbar/HidePassing" to="." method="_on_Hide_Passing_pressed"]
|
||||
[connection signal="item_activated" from="VBox/Output/Scroll/Tree" to="." method="_on_Tree_item_activated"]
|
||||
[connection signal="item_selected" from="VBox/Output/Scroll/Tree" to="." method="_on_Tree_item_selected"]
|
7
addons/gut/gui/Settings.tscn
Normal file
7
addons/gut/gui/Settings.tscn
Normal file
|
@ -0,0 +1,7 @@
|
|||
[gd_scene format=2]
|
||||
|
||||
[node name="Settings" type="VBoxContainer"]
|
||||
offset_right = 388.0
|
||||
offset_bottom = 586.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
144
addons/gut/gui/ShortcutButton.gd
Normal file
144
addons/gut/gui/ShortcutButton.gd
Normal file
|
@ -0,0 +1,144 @@
|
|||
@tool
|
||||
extends Control
|
||||
|
||||
|
||||
@onready var _ctrls = {
|
||||
shortcut_label = $Layout/lblShortcut,
|
||||
set_button = $Layout/SetButton,
|
||||
save_button = $Layout/SaveButton,
|
||||
cancel_button = $Layout/CancelButton,
|
||||
clear_button = $Layout/ClearButton
|
||||
}
|
||||
|
||||
signal changed
|
||||
signal start_edit
|
||||
signal end_edit
|
||||
|
||||
const NO_SHORTCUT = '<None>'
|
||||
|
||||
var _source_event = InputEventKey.new()
|
||||
var _pre_edit_event = null
|
||||
var _key_disp = NO_SHORTCUT
|
||||
|
||||
var _modifier_keys = [KEY_ALT, KEY_CTRL, KEY_META, KEY_SHIFT]
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
set_process_unhandled_key_input(false)
|
||||
|
||||
|
||||
func _display_shortcut():
|
||||
if(_key_disp == ''):
|
||||
_key_disp = NO_SHORTCUT
|
||||
_ctrls.shortcut_label.text = _key_disp
|
||||
|
||||
|
||||
func _is_shift_only_modifier():
|
||||
return _source_event.shift_pressed and \
|
||||
!(_source_event.alt_pressed or _source_event.command_pressed or \
|
||||
_source_event.ctrl_pressed or _source_event.meta_pressed) and \
|
||||
!_is_modifier(_source_event.keycode)
|
||||
|
||||
|
||||
func _has_modifier(event):
|
||||
return event.alt_pressed or event.command_pressed or \
|
||||
event.ctrl_pressed or event.meta_pressed or \
|
||||
event.shift_pressed
|
||||
|
||||
|
||||
func _is_modifier(keycode):
|
||||
return _modifier_keys.has(keycode)
|
||||
|
||||
|
||||
func _edit_mode(should):
|
||||
set_process_unhandled_key_input(should)
|
||||
_ctrls.set_button.visible = !should
|
||||
_ctrls.save_button.visible = should
|
||||
_ctrls.save_button.disabled = should
|
||||
_ctrls.cancel_button.visible = should
|
||||
_ctrls.clear_button.visible = !should
|
||||
|
||||
if(should and to_s() == ''):
|
||||
_ctrls.shortcut_label.text = 'press buttons'
|
||||
else:
|
||||
_ctrls.shortcut_label.text = to_s()
|
||||
|
||||
if(should):
|
||||
emit_signal("start_edit")
|
||||
else:
|
||||
emit_signal("end_edit")
|
||||
|
||||
# ---------------
|
||||
# Events
|
||||
# ---------------
|
||||
func _unhandled_key_input(event):
|
||||
if(event is InputEventKey):
|
||||
if(event.pressed):
|
||||
if(_has_modifier(event) and !_is_modifier(event.get_keycode_with_modifiers())):
|
||||
_source_event = event
|
||||
_key_disp = OS.get_keycode_string(event.get_keycode_with_modifiers())
|
||||
else:
|
||||
_source_event = InputEventKey.new()
|
||||
_key_disp = NO_SHORTCUT
|
||||
_display_shortcut()
|
||||
_ctrls.save_button.disabled = !is_valid()
|
||||
|
||||
|
||||
func _on_SetButton_pressed():
|
||||
_pre_edit_event = _source_event.duplicate(true)
|
||||
_edit_mode(true)
|
||||
|
||||
|
||||
func _on_SaveButton_pressed():
|
||||
_edit_mode(false)
|
||||
_pre_edit_event = null
|
||||
emit_signal('changed')
|
||||
|
||||
|
||||
func _on_CancelButton_pressed():
|
||||
_edit_mode(false)
|
||||
_source_event = _pre_edit_event
|
||||
_key_disp = to_s()
|
||||
_display_shortcut()
|
||||
|
||||
|
||||
func _on_ClearButton_pressed():
|
||||
clear_shortcut()
|
||||
|
||||
# ---------------
|
||||
# Public
|
||||
# ---------------
|
||||
func to_s():
|
||||
return OS.get_keycode_string(_source_event.get_keycode_with_modifiers())
|
||||
|
||||
|
||||
func is_valid():
|
||||
return _has_modifier(_source_event) and !_is_shift_only_modifier()
|
||||
|
||||
|
||||
func get_shortcut():
|
||||
var to_return = Shortcut.new()
|
||||
to_return.events.append(_source_event)
|
||||
return to_return
|
||||
|
||||
|
||||
func set_shortcut(sc):
|
||||
if(sc == null or sc.events == null || sc.events.size() <= 0):
|
||||
clear_shortcut()
|
||||
else:
|
||||
_source_event = sc.events[0]
|
||||
_key_disp = to_s()
|
||||
_display_shortcut()
|
||||
|
||||
|
||||
func clear_shortcut():
|
||||
_source_event = InputEventKey.new()
|
||||
_key_disp = NO_SHORTCUT
|
||||
_display_shortcut()
|
||||
|
||||
|
||||
func disable_set(should):
|
||||
_ctrls.set_button.disabled = should
|
||||
|
||||
func disable_clear(should):
|
||||
_ctrls.clear_button.disabled = should
|
80
addons/gut/gui/ShortcutButton.tscn
Normal file
80
addons/gut/gui/ShortcutButton.tscn
Normal file
|
@ -0,0 +1,80 @@
|
|||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/gut/gui/ShortcutButton.gd" type="Script" id=1]
|
||||
|
||||
[node name="ShortcutButton" type="Control"]
|
||||
anchor_right = 0.123
|
||||
anchor_bottom = 0.04
|
||||
offset_right = 33.048
|
||||
offset_bottom = 1.0
|
||||
custom_minimum_size = Vector2( 125, 25 )
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Layout" type="HBoxContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="lblShortcut" type="Label" parent="Layout"]
|
||||
offset_right = 50.0
|
||||
offset_bottom = 25.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 7
|
||||
text = "<None>"
|
||||
align = 2
|
||||
valign = 1
|
||||
|
||||
[node name="CenterContainer" type="CenterContainer" parent="Layout"]
|
||||
offset_left = 54.0
|
||||
offset_right = 64.0
|
||||
offset_bottom = 25.0
|
||||
custom_minimum_size = Vector2( 10, 0 )
|
||||
|
||||
[node name="SetButton" type="Button" parent="Layout"]
|
||||
offset_left = 68.0
|
||||
offset_right = 128.0
|
||||
offset_bottom = 25.0
|
||||
custom_minimum_size = Vector2( 60, 0 )
|
||||
text = "Set"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="SaveButton" type="Button" parent="Layout"]
|
||||
visible = false
|
||||
offset_left = 82.0
|
||||
offset_right = 142.0
|
||||
offset_bottom = 25.0
|
||||
custom_minimum_size = Vector2( 60, 0 )
|
||||
text = "Save"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="CancelButton" type="Button" parent="Layout"]
|
||||
visible = false
|
||||
offset_left = 82.0
|
||||
offset_right = 142.0
|
||||
offset_bottom = 25.0
|
||||
custom_minimum_size = Vector2( 60, 0 )
|
||||
text = "Cancel"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ClearButton" type="Button" parent="Layout"]
|
||||
offset_left = 132.0
|
||||
offset_right = 192.0
|
||||
offset_bottom = 25.0
|
||||
custom_minimum_size = Vector2( 60, 0 )
|
||||
text = "Clear"
|
||||
|
||||
[connection signal="pressed" from="Layout/SetButton" to="." method="_on_SetButton_pressed"]
|
||||
[connection signal="pressed" from="Layout/SaveButton" to="." method="_on_SaveButton_pressed"]
|
||||
[connection signal="pressed" from="Layout/CancelButton" to="." method="_on_CancelButton_pressed"]
|
||||
[connection signal="pressed" from="Layout/ClearButton" to="." method="_on_ClearButton_pressed"]
|
BIN
addons/gut/gui/arrow.png
Normal file
BIN
addons/gut/gui/arrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 122 B |
34
addons/gut/gui/arrow.png.import
Normal file
34
addons/gut/gui/arrow.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://6wra5rxmfsrl"
|
||||
path="res://.godot/imported/arrow.png-2b5b2d838b5b3467cf300ac2da1630d9.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/gut/gui/arrow.png"
|
||||
dest_files=["res://.godot/imported/arrow.png-2b5b2d838b5b3467cf300ac2da1630d9.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
426
addons/gut/gui/gut_config_gui.gd
Normal file
426
addons/gut/gui/gut_config_gui.gd
Normal file
|
@ -0,0 +1,426 @@
|
|||
# ------------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
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
|
BIN
addons/gut/gui/play.png
Normal file
BIN
addons/gut/gui/play.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 143 B |
34
addons/gut/gui/play.png.import
Normal file
34
addons/gut/gui/play.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cr6tvdv0ve6cv"
|
||||
path="res://.godot/imported/play.png-5c90e88e8136487a183a099d67a7de24.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/gut/gui/play.png"
|
||||
dest_files=["res://.godot/imported/play.png-5c90e88e8136487a183a099d67a7de24.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
230
addons/gut/gui/script_text_editor_controls.gd
Normal file
230
addons/gut/gui/script_text_editor_controls.gd
Normal file
|
@ -0,0 +1,230 @@
|
|||
# Holds weakrefs to a ScriptTextEditor and related children nodes
|
||||
# that might be useful. Though the TextEdit is really the only one, but
|
||||
# since the tree may change, the first TextEdit under a CodeTextEditor is
|
||||
# the one we use...so we hold a ref to the CodeTextEditor too.
|
||||
class ScriptEditorControlRef:
|
||||
var _text_edit = null
|
||||
var _script_editor = null
|
||||
var _code_editor = null
|
||||
|
||||
func _init(script_edit):
|
||||
_script_editor = weakref(script_edit)
|
||||
_populate_controls()
|
||||
|
||||
|
||||
func _populate_controls():
|
||||
# who knows if the tree will change so get the first instance of each
|
||||
# type of control we care about. Chances are there won't be more than
|
||||
# one of these in the future, but their position in the tree may change.
|
||||
_code_editor = weakref(_get_first_child_named('CodeTextEditor', _script_editor.get_ref()))
|
||||
_text_edit = weakref(_get_first_child_named("CodeEdit", _code_editor.get_ref()))
|
||||
|
||||
|
||||
func _get_first_child_named(obj_name, parent_obj):
|
||||
if(parent_obj == null):
|
||||
return null
|
||||
|
||||
var kids = parent_obj.get_children()
|
||||
var index = 0
|
||||
var to_return = null
|
||||
|
||||
while(index < kids.size() and to_return == null):
|
||||
if(str(kids[index]).find(str("[", obj_name)) != -1):
|
||||
to_return = kids[index]
|
||||
else:
|
||||
to_return = _get_first_child_named(obj_name, kids[index])
|
||||
if(to_return == null):
|
||||
index += 1
|
||||
|
||||
return to_return
|
||||
|
||||
|
||||
func get_script_text_edit():
|
||||
return _script_editor.get_ref()
|
||||
|
||||
|
||||
func get_text_edit():
|
||||
# ScriptTextEditors that are loaded when the project is opened
|
||||
# do not have their children populated yet. So if we may have to
|
||||
# _populate_controls again if we don't have one.
|
||||
if(_text_edit == null):
|
||||
_populate_controls()
|
||||
return _text_edit.get_ref()
|
||||
|
||||
|
||||
func get_script_editor():
|
||||
return _script_editor
|
||||
|
||||
|
||||
func is_visible():
|
||||
var to_return = false
|
||||
if(_script_editor.get_ref()):
|
||||
to_return = _script_editor.get_ref().visible
|
||||
return to_return
|
||||
|
||||
# ##############################################################################
|
||||
#
|
||||
# ##############################################################################
|
||||
|
||||
# Used to make searching for the controls easier and faster.
|
||||
var _script_editors_parent = null
|
||||
# reference the ScriptEditor instance
|
||||
var _script_editor = null
|
||||
# Array of ScriptEditorControlRef containing all the opened ScriptTextEditors
|
||||
# and related controls at the time of the last refresh.
|
||||
var _script_editor_controls = []
|
||||
|
||||
var _method_prefix = 'test_'
|
||||
var _inner_class_prefix = 'Test'
|
||||
|
||||
func _init(script_edit):
|
||||
_script_editor = script_edit
|
||||
refresh()
|
||||
|
||||
|
||||
func _is_script_editor(obj):
|
||||
return str(obj).find('[ScriptTextEditor') != -1
|
||||
|
||||
|
||||
# Find the first ScriptTextEditor and then get its parent. Done this way
|
||||
# because who knows if the parent object will change. This is somewhat
|
||||
# future proofed.
|
||||
func _find_script_editors_parent():
|
||||
var _first_editor = _get_first_child_of_type_name("ScriptTextEditor", _script_editor)
|
||||
if(_first_editor != null):
|
||||
_script_editors_parent = _first_editor.get_parent()
|
||||
|
||||
|
||||
func _populate_editors():
|
||||
if(_script_editors_parent == null):
|
||||
return
|
||||
|
||||
_script_editor_controls.clear()
|
||||
for child in _script_editors_parent.get_children():
|
||||
if(_is_script_editor(child)):
|
||||
var ref = ScriptEditorControlRef.new(child)
|
||||
_script_editor_controls.append(ref)
|
||||
|
||||
# Yes, this is the same as the one above but with a different name. This was
|
||||
# easier than trying to find a place where it could be used by both.
|
||||
func _get_first_child_of_type_name(obj_name, parent_obj):
|
||||
if(parent_obj == null):
|
||||
return null
|
||||
|
||||
var kids = parent_obj.get_children()
|
||||
var index = 0
|
||||
var to_return = null
|
||||
|
||||
while(index < kids.size() and to_return == null):
|
||||
if(str(kids[index]).find(str("[", obj_name)) != -1):
|
||||
to_return = kids[index]
|
||||
else:
|
||||
to_return = _get_first_child_of_type_name(obj_name, kids[index])
|
||||
if(to_return == null):
|
||||
index += 1
|
||||
|
||||
return to_return
|
||||
|
||||
|
||||
func _get_func_name_from_line(text):
|
||||
text = text.strip_edges()
|
||||
var left = text.split("(")[0]
|
||||
var func_name = left.split(" ")[1]
|
||||
return func_name
|
||||
|
||||
|
||||
func _get_class_name_from_line(text):
|
||||
text = text.strip_edges()
|
||||
var right = text.split(" ")[1]
|
||||
var the_name = right.rstrip(":")
|
||||
return the_name
|
||||
|
||||
func refresh():
|
||||
if(_script_editors_parent == null):
|
||||
_find_script_editors_parent()
|
||||
|
||||
if(_script_editors_parent != null):
|
||||
_populate_editors()
|
||||
|
||||
|
||||
func get_current_text_edit():
|
||||
var cur_script_editor = null
|
||||
var idx = 0
|
||||
|
||||
while(idx < _script_editor_controls.size() and cur_script_editor == null):
|
||||
if(_script_editor_controls[idx].is_visible()):
|
||||
cur_script_editor = _script_editor_controls[idx]
|
||||
else:
|
||||
idx += 1
|
||||
|
||||
var to_return = null
|
||||
if(cur_script_editor != null):
|
||||
to_return = cur_script_editor.get_text_edit()
|
||||
|
||||
return to_return
|
||||
|
||||
|
||||
func get_script_editor_controls():
|
||||
var to_return = []
|
||||
for ctrl_ref in _script_editor_controls:
|
||||
to_return.append(ctrl_ref.get_script_text_edit())
|
||||
|
||||
return to_return
|
||||
|
||||
|
||||
func get_line_info():
|
||||
var editor = get_current_text_edit()
|
||||
if(editor == null):
|
||||
return
|
||||
|
||||
var info = {
|
||||
script = null,
|
||||
inner_class = null,
|
||||
test_method = null
|
||||
}
|
||||
|
||||
var line = editor.get_caret_line()
|
||||
var done_func = false
|
||||
var done_inner = false
|
||||
while(line > 0 and (!done_func or !done_inner)):
|
||||
if(editor.can_fold_line(line)):
|
||||
var text = editor.get_line(line)
|
||||
var strip_text = text.strip_edges(true, false) # only left
|
||||
|
||||
if(!done_func and strip_text.begins_with("func ")):
|
||||
var func_name = _get_func_name_from_line(text)
|
||||
if(func_name.begins_with(_method_prefix)):
|
||||
info.test_method = func_name
|
||||
done_func = true
|
||||
# If the func line is left justified then there won't be any
|
||||
# inner classes above it.
|
||||
if(strip_text == text):
|
||||
done_inner = true
|
||||
|
||||
if(!done_inner and strip_text.begins_with("class")):
|
||||
var inner_name = _get_class_name_from_line(text)
|
||||
if(inner_name.begins_with(_inner_class_prefix)):
|
||||
info.inner_class = inner_name
|
||||
done_inner = true
|
||||
# if we found an inner class then we are already past
|
||||
# any test the cursor could be in.
|
||||
done_func = true
|
||||
line -= 1
|
||||
|
||||
return info
|
||||
|
||||
|
||||
func get_method_prefix():
|
||||
return _method_prefix
|
||||
|
||||
|
||||
func set_method_prefix(method_prefix):
|
||||
_method_prefix = method_prefix
|
||||
|
||||
|
||||
func get_inner_class_prefix():
|
||||
return _inner_class_prefix
|
||||
|
||||
|
||||
func set_inner_class_prefix(inner_class_prefix):
|
||||
_inner_class_prefix = inner_class_prefix
|
Loading…
Add table
Add a link
Reference in a new issue