Format files using GDScript Toolkit

This commit is contained in:
Leroy Hopson 2023-01-21 11:34:39 +13:00
parent 9f269aec8c
commit e563a15ce2
No known key found for this signature in database
GPG key ID: D2747312A6DB51AA
52 changed files with 3459 additions and 2454 deletions

View file

@ -20,24 +20,23 @@ class GuiHandler:
_gui = gui _gui = gui
# Brute force, but flexible. # Brute force, but flexible.
_ctrls.btn_continue = _get_first_child_named('Continue', _gui) _ctrls.btn_continue = _get_first_child_named("Continue", _gui)
_ctrls.path_dir = _get_first_child_named('Path', _gui) _ctrls.path_dir = _get_first_child_named("Path", _gui)
_ctrls.path_file = _get_first_child_named('File', _gui) _ctrls.path_file = _get_first_child_named("File", _gui)
_ctrls.prog_script = _get_first_child_named('ProgressScript', _gui) _ctrls.prog_script = _get_first_child_named("ProgressScript", _gui)
_ctrls.prog_test = _get_first_child_named('ProgressTest', _gui) _ctrls.prog_test = _get_first_child_named("ProgressTest", _gui)
_ctrls.rtl = _get_first_child_named('Output', _gui) _ctrls.rtl = _get_first_child_named("Output", _gui)
_ctrls.rtl_bg = _get_first_child_named('OutputBG', _gui) _ctrls.rtl_bg = _get_first_child_named("OutputBG", _gui)
_ctrls.time_label = _get_first_child_named('TimeLabel', _gui) _ctrls.time_label = _get_first_child_named("TimeLabel", _gui)
_ctrls.btn_continue.visible = false _ctrls.btn_continue.visible = false
_ctrls.btn_continue.pressed.connect(_on_continue_pressed) _ctrls.btn_continue.pressed.connect(_on_continue_pressed)
_ctrls.prog_script.value = 0 _ctrls.prog_script.value = 0
_ctrls.prog_test.value = 0 _ctrls.prog_test.value = 0
_ctrls.path_dir.text = '' _ctrls.path_dir.text = ""
_ctrls.path_file.text = '' _ctrls.path_file.text = ""
_ctrls.time_label.text = '' _ctrls.time_label.text = ""
# ------------------ # ------------------
# Events # Events
@ -46,55 +45,49 @@ class GuiHandler:
_ctrls.btn_continue.visible = false _ctrls.btn_continue.visible = false
_gut.end_teardown_pause() _gut.end_teardown_pause()
func _on_gut_start_run(): func _on_gut_start_run():
if(_ctrls.rtl != null): if _ctrls.rtl != null:
_ctrls.rtl.clear() _ctrls.rtl.clear()
set_num_scripts(_gut.get_test_collector().scripts.size()) set_num_scripts(_gut.get_test_collector().scripts.size())
func _on_gut_end_run(): func _on_gut_end_run():
_ctrls.time_label.text = '' _ctrls.time_label.text = ""
func _on_gut_start_script(script_obj): func _on_gut_start_script(script_obj):
next_script(script_obj.get_full_name(), script_obj.tests.size()) next_script(script_obj.get_full_name(), script_obj.tests.size())
func _on_gut_end_script(): func _on_gut_end_script():
pass pass
func _on_gut_start_test(test_name): func _on_gut_start_test(test_name):
next_test(test_name) next_test(test_name)
func _on_gut_end_test(): func _on_gut_end_test():
pass pass
func _on_gut_start_pause(): func _on_gut_start_pause():
pause_before_teardown() pause_before_teardown()
func _on_gut_end_pause(): func _on_gut_end_pause():
pass pass
# ------------------ # ------------------
# Private # Private
# ------------------ # ------------------
func _get_first_child_named(obj_name, parent_obj): func _get_first_child_named(obj_name, parent_obj):
if(parent_obj == null): if parent_obj == null:
return null return null
var kids = parent_obj.get_children() var kids = parent_obj.get_children()
var index = 0 var index = 0
var to_return = null var to_return = null
while(index < kids.size() and to_return == null): while index < kids.size() and to_return == null:
if(str(kids[index]).find(str(obj_name, ':')) != -1): if str(kids[index]).find(str(obj_name, ":")) != -1:
to_return = kids[index] to_return = kids[index]
else: else:
to_return = _get_first_child_named(obj_name, kids[index]) to_return = _get_first_child_named(obj_name, kids[index])
if(to_return == null): if to_return == null:
index += 1 index += 1
return to_return return to_return
@ -106,7 +99,6 @@ class GuiHandler:
_ctrls.prog_script.value = 0 _ctrls.prog_script.value = 0
_ctrls.prog_script.max_value = val _ctrls.prog_script.max_value = val
func next_script(path, num_tests): func next_script(path, num_tests):
_ctrls.prog_script.value += 1 _ctrls.prog_script.value += 1
_ctrls.prog_test.value = 0 _ctrls.prog_test.value = 0
@ -115,15 +107,12 @@ class GuiHandler:
_ctrls.path_dir.text = path.get_base_dir() _ctrls.path_dir.text = path.get_base_dir()
_ctrls.path_file.text = path.get_file() _ctrls.path_file.text = path.get_file()
func next_test(test_name): func next_test(test_name):
_ctrls.prog_test.value += 1 _ctrls.prog_test.value += 1
func pause_before_teardown(): func pause_before_teardown():
_ctrls.btn_continue.visible = true _ctrls.btn_continue.visible = true
func set_gut(g): func set_gut(g):
_gut = g _gut = g
g.start_run.connect(_on_gut_start_run) g.start_run.connect(_on_gut_start_run)
@ -142,17 +131,17 @@ class GuiHandler:
return _ctrls.rtl return _ctrls.rtl
func set_elapsed_time(t): func set_elapsed_time(t):
_ctrls.time_label.text = str(t, 's') _ctrls.time_label.text = str(t, "s")
func set_bg_color(c): func set_bg_color(c):
_ctrls.rtl_bg.color = c _ctrls.rtl_bg.color = c
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
var _large_handler = null var _large_handler = null
var _min_handler = null var _min_handler = null
var gut = null : var gut = null:
set(val): set(val):
gut = val gut = val
_set_gut(val) _set_gut(val)
@ -165,31 +154,36 @@ func _ready():
$Min.visible = false $Min.visible = false
$Large.visible = !$Min.visible $Large.visible = !$Min.visible
func _process(_delta): func _process(_delta):
if(gut != null and gut.is_running()): if gut != null and gut.is_running():
_large_handler.set_elapsed_time(gut.get_elapsed_time()) _large_handler.set_elapsed_time(gut.get_elapsed_time())
_min_handler.set_elapsed_time(gut.get_elapsed_time()) _min_handler.set_elapsed_time(gut.get_elapsed_time())
func _set_gut(val): func _set_gut(val):
_large_handler.set_gut(val) _large_handler.set_gut(val)
_min_handler.set_gut(val) _min_handler.set_gut(val)
func get_textbox(): func get_textbox():
return _large_handler.get_textbox() return _large_handler.get_textbox()
func set_font_size(new_size): func set_font_size(new_size):
var rtl = _large_handler.get_textbox() var rtl = _large_handler.get_textbox()
if(rtl.get('custom_fonts/normal_font') != null): if rtl.get("custom_fonts/normal_font") != null:
rtl.get('custom_fonts/bold_italics_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/bold_font").size = new_size
rtl.get('custom_fonts/italics_font').size = new_size rtl.get("custom_fonts/italics_font").size = new_size
rtl.get('custom_fonts/normal_font').size = new_size rtl.get("custom_fonts/normal_font").size = new_size
func set_font(font_name): func set_font(font_name):
pass pass
#_set_all_fonts_in_rtl(_large_handler.get_textbox(), font_name) #_set_all_fonts_in_rtl(_large_handler.get_textbox(), font_name)
# Needs rework for 4.0, DynamicFont DNE # Needs rework for 4.0, DynamicFont DNE
func _set_font(rtl, font_name, custom_name): func _set_font(rtl, font_name, custom_name):
pass pass
@ -205,20 +199,20 @@ func _set_font(rtl, font_name, custom_name):
func _set_all_fonts_in_rtl(rtl, base_name): func _set_all_fonts_in_rtl(rtl, base_name):
if(base_name == 'Default'): if base_name == "Default":
_set_font(rtl, null, 'normal_font') _set_font(rtl, null, "normal_font")
_set_font(rtl, null, 'bold_font') _set_font(rtl, null, "bold_font")
_set_font(rtl, null, 'italics_font') _set_font(rtl, null, "italics_font")
_set_font(rtl, null, 'bold_italics_font') _set_font(rtl, null, "bold_italics_font")
else: else:
_set_font(rtl, base_name + '-Regular', 'normal_font') _set_font(rtl, base_name + "-Regular", "normal_font")
_set_font(rtl, base_name + '-Bold', 'bold_font') _set_font(rtl, base_name + "-Bold", "bold_font")
_set_font(rtl, base_name + '-Italic', 'italics_font') _set_font(rtl, base_name + "-Italic", "italics_font")
_set_font(rtl, base_name + '-BoldItalic', 'bold_italics_font') _set_font(rtl, base_name + "-BoldItalic", "bold_italics_font")
func set_default_font_color(color): func set_default_font_color(color):
_large_handler.get_textbox().set('custom_colors/default_color', color) _large_handler.get_textbox().set("custom_colors/default_color", color)
func set_background_color(color): func set_background_color(color):

View file

@ -2,50 +2,62 @@ extends Window
@onready var rtl = $TextDisplay/RichTextLabel @onready var rtl = $TextDisplay/RichTextLabel
func _get_file_as_text(path): func _get_file_as_text(path):
var to_return = null var to_return = null
var f = FileAccess.open(path, FileAccess.READ) var f = FileAccess.open(path, FileAccess.READ)
if(f != null): if f != null:
to_return = f.get_as_text() to_return = f.get_as_text()
else: else:
to_return = str('ERROR: Could not open file. Error code ', FileAccess.get_open_error()) to_return = str("ERROR: Could not open file. Error code ", FileAccess.get_open_error())
return to_return return to_return
func _ready(): func _ready():
rtl.clear() rtl.clear()
func _on_OpenFile_pressed(): func _on_OpenFile_pressed():
$FileDialog.popup_centered() $FileDialog.popup_centered()
func _on_FileDialog_file_selected(path): func _on_FileDialog_file_selected(path):
show_file(path) show_file(path)
func _on_Close_pressed(): func _on_Close_pressed():
self.hide() self.hide()
func show_file(path): func show_file(path):
var text = _get_file_as_text(path) var text = _get_file_as_text(path)
if(text == ''): if text == "":
text = '<Empty File>' text = "<Empty File>"
rtl.set_text(text) rtl.set_text(text)
self.window_title = path self.window_title = path
func show_open(): func show_open():
self.popup_centered() self.popup_centered()
$FileDialog.popup_centered() $FileDialog.popup_centered()
func get_rich_text_label(): func get_rich_text_label():
return $TextDisplay/RichTextLabel return $TextDisplay/RichTextLabel
func _on_Home_pressed(): func _on_Home_pressed():
rtl.scroll_to_line(0) rtl.scroll_to_line(0)
func _on_End_pressed(): func _on_End_pressed():
rtl.scroll_to_line(rtl.get_line_count() -1) rtl.scroll_to_line(rtl.get_line_count() - 1)
func _on_Copy_pressed(): func _on_Copy_pressed():
OS.clipboard = rtl.text OS.clipboard = rtl.text
func _on_file_dialog_visibility_changed(): func _on_file_dialog_visibility_changed():
if rtl.text.length() == 0 and not $FileDialog.visible: if rtl.text.length() == 0 and not $FileDialog.visible:
self.hide() self.hide()

View file

@ -31,29 +31,32 @@
var _to_free = [] var _to_free = []
var _to_queue_free = [] var _to_queue_free = []
func add_free(thing): func add_free(thing):
if(typeof(thing) == TYPE_OBJECT): if typeof(thing) == TYPE_OBJECT:
if(!thing is RefCounted): if !thing is RefCounted:
_to_free.append(thing) _to_free.append(thing)
func add_queue_free(thing): func add_queue_free(thing):
_to_queue_free.append(thing) _to_queue_free.append(thing)
func get_queue_free_count(): func get_queue_free_count():
return _to_queue_free.size() return _to_queue_free.size()
func get_free_count(): func get_free_count():
return _to_free.size() return _to_free.size()
func free_all(): func free_all():
for i in range(_to_free.size()): for i in range(_to_free.size()):
if(is_instance_valid(_to_free[i])): if is_instance_valid(_to_free[i]):
_to_free[i].free() _to_free[i].free()
_to_free.clear() _to_free.clear()
for i in range(_to_queue_free.size()): for i in range(_to_queue_free.size()):
if(is_instance_valid(_to_queue_free[i])): if is_instance_valid(_to_queue_free[i]):
_to_queue_free[i].queue_free() _to_queue_free[i].queue_free()
_to_queue_free.clear() _to_queue_free.clear()

View file

@ -12,14 +12,14 @@ var _elapsed_frames = 0
func _physics_process(delta): func _physics_process(delta):
if(_wait_time != 0.0): if _wait_time != 0.0:
_elapsed_time += delta _elapsed_time += delta
if(_elapsed_time >= _wait_time): if _elapsed_time >= _wait_time:
_end_wait() _end_wait()
if(_wait_frames != 0): if _wait_frames != 0:
_elapsed_frames += 1 _elapsed_frames += 1
if(_elapsed_frames >= _wait_frames): if _elapsed_frames >= _wait_frames:
_end_wait() _end_wait()
@ -32,12 +32,20 @@ func _end_wait():
timeout.emit() timeout.emit()
const ARG_NOT_SET = '_*_argument_*_is_*_not_set_*_' const ARG_NOT_SET = "_*_argument_*_is_*_not_set_*_"
func _signal_callback(
arg1=ARG_NOT_SET, arg2=ARG_NOT_SET, arg3=ARG_NOT_SET,
arg4=ARG_NOT_SET, arg5=ARG_NOT_SET, arg6=ARG_NOT_SET,
arg7=ARG_NOT_SET, arg8=ARG_NOT_SET, arg9=ARG_NOT_SET):
func _signal_callback(
arg1 = ARG_NOT_SET,
arg2 = ARG_NOT_SET,
arg3 = ARG_NOT_SET,
arg4 = ARG_NOT_SET,
arg5 = ARG_NOT_SET,
arg6 = ARG_NOT_SET,
arg7 = ARG_NOT_SET,
arg8 = ARG_NOT_SET,
arg9 = ARG_NOT_SET
):
_signal_to_wait_on.disconnect(_signal_callback) _signal_to_wait_on.disconnect(_signal_callback)
# DO NOT _end_wait here. For other parts of the test to get the signal that # DO NOT _end_wait here. For other parts of the test to get the signal that
# was waited on, we have to wait for a couple more frames. For example, the # was waited on, we have to wait for a couple more frames. For example, the
@ -64,4 +72,3 @@ func wait_for_signal(the_signal, x):
func is_waiting(): func is_waiting():
return _wait_time != 0.0 || _wait_frames != 0 return _wait_time != 0.0 || _wait_frames != 0

View file

@ -1,85 +1,93 @@
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
var _strutils = _utils.Strutils.new() var _strutils = _utils.Strutils.new()
var _max_length = 100 var _max_length = 100
var _should_compare_int_to_float = true var _should_compare_int_to_float = true
const MISSING = '|__missing__gut__compare__value__|' const MISSING = "|__missing__gut__compare__value__|"
const DICTIONARY_DISCLAIMER = 'Dictionaries are compared-by-ref. See assert_eq in wiki.' const DICTIONARY_DISCLAIMER = "Dictionaries are compared-by-ref. See assert_eq in wiki."
func _cannot_compare_text(v1, v2): func _cannot_compare_text(v1, v2):
return str('Cannot compare ', _strutils.types[typeof(v1)], ' with ', return str(
_strutils.types[typeof(v2)], '.') "Cannot compare ", _strutils.types[typeof(v1)], " with ", _strutils.types[typeof(v2)], "."
)
func _make_missing_string(text): func _make_missing_string(text):
return '<missing ' + text + '>' return "<missing " + text + ">"
func _create_missing_result(v1, v2, text): func _create_missing_result(v1, v2, text):
var to_return = null var to_return = null
var v1_str = format_value(v1) var v1_str = format_value(v1)
var v2_str = format_value(v2) var v2_str = format_value(v2)
if(typeof(v1) == TYPE_STRING and v1 == MISSING): if typeof(v1) == TYPE_STRING and v1 == MISSING:
v1_str = _make_missing_string(text) v1_str = _make_missing_string(text)
to_return = _utils.CompareResult.new() to_return = _utils.CompareResult.new()
elif(typeof(v2) == TYPE_STRING and v2 == MISSING): elif typeof(v2) == TYPE_STRING and v2 == MISSING:
v2_str = _make_missing_string(text) v2_str = _make_missing_string(text)
to_return = _utils.CompareResult.new() to_return = _utils.CompareResult.new()
if(to_return != null): if to_return != null:
to_return.summary = str(v1_str, ' != ', v2_str) to_return.summary = str(v1_str, " != ", v2_str)
to_return.are_equal = false to_return.are_equal = false
return to_return return to_return
func simple(v1, v2, missing_string=''): func simple(v1, v2, missing_string = ""):
var missing_result = _create_missing_result(v1, v2, missing_string) var missing_result = _create_missing_result(v1, v2, missing_string)
if(missing_result != null): if missing_result != null:
return missing_result return missing_result
var result = _utils.CompareResult.new() var result = _utils.CompareResult.new()
var cmp_str = null var cmp_str = null
var extra = '' var extra = ""
var tv1 = typeof(v1) var tv1 = typeof(v1)
var tv2 = typeof(v2) var tv2 = typeof(v2)
# print(tv1, '::', tv2, ' ', _strutils.types[tv1], '::', _strutils.types[tv2]) # print(tv1, '::', tv2, ' ', _strutils.types[tv1], '::', _strutils.types[tv2])
if(_should_compare_int_to_float and [TYPE_INT, TYPE_FLOAT].has(tv1) and [TYPE_INT, TYPE_FLOAT].has(tv2)): if (
_should_compare_int_to_float
and [TYPE_INT, TYPE_FLOAT].has(tv1)
and [TYPE_INT, TYPE_FLOAT].has(tv2)
):
result.are_equal = v1 == v2 result.are_equal = v1 == v2
elif([TYPE_STRING, TYPE_STRING_NAME].has(tv1) and [TYPE_STRING, TYPE_STRING_NAME].has(tv2)): elif [TYPE_STRING, TYPE_STRING_NAME].has(tv1) and [TYPE_STRING, TYPE_STRING_NAME].has(tv2):
result.are_equal = v1 == v2 result.are_equal = v1 == v2
elif(_utils.are_datatypes_same(v1, v2)): elif _utils.are_datatypes_same(v1, v2):
result.are_equal = v1 == v2 result.are_equal = v1 == v2
if(typeof(v1) == TYPE_DICTIONARY): if typeof(v1) == TYPE_DICTIONARY:
if(result.are_equal): if result.are_equal:
extra = '. Same dictionary ref. ' extra = ". Same dictionary ref. "
else: else:
extra = '. Different dictionary refs. ' extra = ". Different dictionary refs. "
extra += DICTIONARY_DISCLAIMER extra += DICTIONARY_DISCLAIMER
if(typeof(v1) == TYPE_ARRAY): if typeof(v1) == TYPE_ARRAY:
var array_result = _utils.DiffTool.new(v1, v2, _utils.DIFF.SHALLOW) var array_result = _utils.DiffTool.new(v1, v2, _utils.DIFF.SHALLOW)
result.summary = array_result.get_short_summary() result.summary = array_result.get_short_summary()
if(!array_result.are_equal): if !array_result.are_equal:
extra = ".\n" + array_result.get_short_summary() extra = ".\n" + array_result.get_short_summary()
else: else:
cmp_str = '!=' cmp_str = "!="
result.are_equal = false result.are_equal = false
extra = str('. ', _cannot_compare_text(v1, v2)) extra = str(". ", _cannot_compare_text(v1, v2))
cmp_str = get_compare_symbol(result.are_equal) cmp_str = get_compare_symbol(result.are_equal)
result.summary = str(format_value(v1), ' ', cmp_str, ' ', format_value(v2), extra) result.summary = str(format_value(v1), " ", cmp_str, " ", format_value(v2), extra)
return result return result
func shallow(v1, v2): func shallow(v1, v2):
var result = null var result = null
if(_utils.are_datatypes_same(v1, v2)): if _utils.are_datatypes_same(v1, v2):
if(typeof(v1) in [TYPE_ARRAY, TYPE_DICTIONARY]): if typeof(v1) in [TYPE_ARRAY, TYPE_DICTIONARY]:
result = _utils.DiffTool.new(v1, v2, _utils.DIFF.SHALLOW) result = _utils.DiffTool.new(v1, v2, _utils.DIFF.SHALLOW)
else: else:
result = simple(v1, v2) result = simple(v1, v2)
@ -90,10 +98,10 @@ func shallow(v1, v2):
func deep(v1, v2): func deep(v1, v2):
var result = null var result = null
if(_utils.are_datatypes_same(v1, v2)): if _utils.are_datatypes_same(v1, v2):
if(typeof(v1) in [TYPE_ARRAY, TYPE_DICTIONARY]): if typeof(v1) in [TYPE_ARRAY, TYPE_DICTIONARY]:
result = _utils.DiffTool.new(v1, v2, _utils.DIFF.DEEP) result = _utils.DiffTool.new(v1, v2, _utils.DIFF.DEEP)
else: else:
result = simple(v1, v2) result = simple(v1, v2)
@ -103,17 +111,17 @@ func deep(v1, v2):
return result return result
func format_value(val, max_val_length=_max_length): func format_value(val, max_val_length = _max_length):
return _strutils.truncate_string(_strutils.type2str(val), max_val_length) return _strutils.truncate_string(_strutils.type2str(val), max_val_length)
func compare(v1, v2, diff_type=_utils.DIFF.SIMPLE): func compare(v1, v2, diff_type = _utils.DIFF.SIMPLE):
var result = null var result = null
if(diff_type == _utils.DIFF.SIMPLE): if diff_type == _utils.DIFF.SIMPLE:
result = simple(v1, v2) result = simple(v1, v2)
elif(diff_type == _utils.DIFF.SHALLOW): elif diff_type == _utils.DIFF.SHALLOW:
result = shallow(v1, v2) result = shallow(v1, v2)
elif(diff_type == _utils.DIFF.DEEP): elif diff_type == _utils.DIFF.DEEP:
result = deep(v1, v2) result = deep(v1, v2)
return result return result
@ -128,7 +136,7 @@ func set_should_compare_int_to_float(should_compare_int_float):
func get_compare_symbol(is_equal): func get_compare_symbol(is_equal):
if(is_equal): if is_equal:
return '==' return "=="
else: else:
return '!=' return "!="

View file

@ -1,70 +1,83 @@
var _are_equal = false var _are_equal = false
var are_equal = false : var are_equal = false:
get: get:
return get_are_equal() return get_are_equal()
set(val): set(val):
set_are_equal(val) set_are_equal(val)
var _summary = null var _summary = null
var summary = null : var summary = null:
get: get:
return get_summary() return get_summary()
set(val): set(val):
set_summary(val) set_summary(val)
var _max_differences = 30 var _max_differences = 30
var max_differences = 30 : var max_differences = 30:
get: get:
return get_max_differences() return get_max_differences()
set(val): set(val):
set_max_differences(val) set_max_differences(val)
var _differences = {} var _differences = {}
var differences : var differences:
get: get:
return get_differences() return get_differences()
set(val): set(val):
set_differences(val) set_differences(val)
func _block_set(which, val): func _block_set(which, val):
push_error(str('cannot set ', which, ', value [', val, '] ignored.')) push_error(str("cannot set ", which, ", value [", val, "] ignored."))
func _to_string(): func _to_string():
return str(get_summary()) # could be null, gotta str it. return str(get_summary()) # could be null, gotta str it.
func get_are_equal(): func get_are_equal():
return _are_equal return _are_equal
func set_are_equal(r_eq): func set_are_equal(r_eq):
_are_equal = r_eq _are_equal = r_eq
func get_summary(): func get_summary():
return _summary return _summary
func set_summary(smry): func set_summary(smry):
_summary = smry _summary = smry
func get_total_count(): func get_total_count():
pass pass
func get_different_count(): func get_different_count():
pass pass
func get_short_summary(): func get_short_summary():
return summary return summary
func get_max_differences(): func get_max_differences():
return _max_differences return _max_differences
func set_max_differences(max_diff): func set_max_differences(max_diff):
_max_differences = max_diff _max_differences = max_diff
func get_differences(): func get_differences():
return _differences return _differences
func set_differences(diffs): func set_differences(diffs):
_block_set('differences', diffs) _block_set("differences", diffs)
func get_brackets(): func get_brackets():
return null return null

View file

@ -1,20 +1,24 @@
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
var _strutils = _utils.Strutils.new() var _strutils = _utils.Strutils.new()
const INDENT = ' ' const INDENT = " "
var _max_to_display = 30 var _max_to_display = 30
const ABSOLUTE_MAX_DISPLAYED = 10000 const ABSOLUTE_MAX_DISPLAYED = 10000
const UNLIMITED = -1 const UNLIMITED = -1
func _single_diff(diff, depth=0): func _single_diff(diff, depth = 0):
var to_return = "" var to_return = ""
var brackets = diff.get_brackets() var brackets = diff.get_brackets()
if(brackets != null and !diff.are_equal): if brackets != null and !diff.are_equal:
to_return = '' to_return = ""
to_return += str(brackets.open, "\n", to_return += str(
_strutils.indent_text(differences_to_s(diff.differences, depth), depth+1, INDENT), "\n", brackets.open,
brackets.close) "\n",
_strutils.indent_text(differences_to_s(diff.differences, depth), depth + 1, INDENT),
"\n",
brackets.close
)
else: else:
to_return = str(diff) to_return = str(diff)
@ -22,20 +26,20 @@ func _single_diff(diff, depth=0):
func make_it(diff): func make_it(diff):
var to_return = '' var to_return = ""
if(diff.are_equal): if diff.are_equal:
to_return = diff.summary to_return = diff.summary
else: else:
if(_max_to_display == ABSOLUTE_MAX_DISPLAYED): if _max_to_display == ABSOLUTE_MAX_DISPLAYED:
to_return = str(diff.get_value_1(), ' != ', diff.get_value_2()) to_return = str(diff.get_value_1(), " != ", diff.get_value_2())
else: else:
to_return = diff.get_short_summary() to_return = diff.get_short_summary()
to_return += str("\n", _strutils.indent_text(_single_diff(diff, 0), 1, ' ')) to_return += str("\n", _strutils.indent_text(_single_diff(diff, 0), 1, " "))
return to_return return to_return
func differences_to_s(differences, depth=0): func differences_to_s(differences, depth = 0):
var to_return = '' var to_return = ""
var keys = differences.keys() var keys = differences.keys()
keys.sort() keys.sort()
var limit = min(_max_to_display, differences.size()) var limit = min(_max_to_display, differences.size())
@ -44,10 +48,10 @@ func differences_to_s(differences, depth=0):
var key = keys[i] var key = keys[i]
to_return += str(key, ": ", _single_diff(differences[key], depth)) to_return += str(key, ": ", _single_diff(differences[key], depth))
if(i != limit -1): if i != limit - 1:
to_return += "\n" to_return += "\n"
if(differences.size() > _max_to_display): if differences.size() > _max_to_display:
to_return += str("\n\n... ", differences.size() - _max_to_display, " more.") to_return += str("\n\n... ", differences.size() - _max_to_display, " more.")
return to_return return to_return
@ -59,6 +63,5 @@ func get_max_to_display():
func set_max_to_display(max_to_display): func set_max_to_display(max_to_display):
_max_to_display = max_to_display _max_to_display = max_to_display
if(_max_to_display == UNLIMITED): if _max_to_display == UNLIMITED:
_max_to_display = ABSOLUTE_MAX_DISPLAYED _max_to_display = ABSOLUTE_MAX_DISPLAYED

View file

@ -1,15 +1,11 @@
extends 'res://addons/gut/compare_result.gd' extends "res://addons/gut/compare_result.gd"
const INDENT = ' ' const INDENT = " "
enum { enum { DEEP, SHALLOW, SIMPLE }
DEEP,
SHALLOW,
SIMPLE
}
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
var _strutils = _utils.Strutils.new() var _strutils = _utils.Strutils.new()
var _compare = _utils.Comparator.new() var _compare = _utils.Comparator.new()
var DiffTool = load('res://addons/gut/diff_tool.gd') var DiffTool = load("res://addons/gut/diff_tool.gd")
var _value_1 = null var _value_1 = null
var _value_2 = null var _value_2 = null
@ -17,42 +13,62 @@ var _total_count = 0
var _diff_type = null var _diff_type = null
var _brackets = null var _brackets = null
var _valid = true var _valid = true
var _desc_things = 'somethings' var _desc_things = "somethings"
# -------- comapre_result.gd "interface" --------------------- # -------- comapre_result.gd "interface" ---------------------
func set_are_equal(val): func set_are_equal(val):
_block_set('are_equal', val) _block_set("are_equal", val)
func get_are_equal(): func get_are_equal():
if(!_valid): if !_valid:
return null return null
else: else:
return differences.size() == 0 return differences.size() == 0
func set_summary(val): func set_summary(val):
_block_set('summary', val) _block_set("summary", val)
func get_summary(): func get_summary():
return summarize() return summarize()
func get_different_count(): func get_different_count():
return differences.size() return differences.size()
func get_total_count():
func get_total_count():
return _total_count return _total_count
func get_short_summary(): func get_short_summary():
var text = str(_strutils.truncate_string(str(_value_1), 50), var text = str(
' ', _compare.get_compare_symbol(are_equal), ' ', _strutils.truncate_string(str(_value_1), 50),
_strutils.truncate_string(str(_value_2), 50)) " ",
if(!are_equal): _compare.get_compare_symbol(are_equal),
text += str(' ', get_different_count(), ' of ', get_total_count(), " ",
' ', _desc_things, ' do not match.') _strutils.truncate_string(str(_value_2), 50)
)
if !are_equal:
text += str(
" ",
get_different_count(),
" of ",
get_total_count(),
" ",
_desc_things,
" do not match."
)
return text return text
func get_brackets(): func get_brackets():
return _brackets return _brackets
# -------- comapre_result.gd "interface" --------------------- # -------- comapre_result.gd "interface" ---------------------
@ -61,7 +77,7 @@ func _invalidate():
differences = null differences = null
func _init(v1,v2,diff_type=DEEP): func _init(v1, v2, diff_type = DEEP):
_value_1 = v1 _value_1 = v1
_value_2 = v2 _value_2 = v2
_diff_type = diff_type _diff_type = diff_type
@ -70,41 +86,41 @@ func _init(v1,v2,diff_type=DEEP):
func _find_differences(v1, v2): func _find_differences(v1, v2):
if(_utils.are_datatypes_same(v1, v2)): if _utils.are_datatypes_same(v1, v2):
if(typeof(v1) == TYPE_ARRAY): if typeof(v1) == TYPE_ARRAY:
_brackets = {'open':'[', 'close':']'} _brackets = {"open": "[", "close": "]"}
_desc_things = 'indexes' _desc_things = "indexes"
_diff_array(v1, v2) _diff_array(v1, v2)
elif(typeof(v2) == TYPE_DICTIONARY): elif typeof(v2) == TYPE_DICTIONARY:
_brackets = {'open':'{', 'close':'}'} _brackets = {"open": "{", "close": "}"}
_desc_things = 'keys' _desc_things = "keys"
_diff_dictionary(v1, v2) _diff_dictionary(v1, v2)
else: else:
_invalidate() _invalidate()
_utils.get_logger().error('Only Arrays and Dictionaries are supported.') _utils.get_logger().error("Only Arrays and Dictionaries are supported.")
else: else:
_invalidate() _invalidate()
_utils.get_logger().error('Only Arrays and Dictionaries are supported.') _utils.get_logger().error("Only Arrays and Dictionaries are supported.")
func _diff_array(a1, a2): func _diff_array(a1, a2):
_total_count = max(a1.size(), a2.size()) _total_count = max(a1.size(), a2.size())
for i in range(a1.size()): for i in range(a1.size()):
var result = null var result = null
if(i < a2.size()): if i < a2.size():
if(_diff_type == DEEP): if _diff_type == DEEP:
result = _compare.deep(a1[i], a2[i]) result = _compare.deep(a1[i], a2[i])
else: else:
result = _compare.simple(a1[i], a2[i]) result = _compare.simple(a1[i], a2[i])
else: else:
result = _compare.simple(a1[i], _compare.MISSING, 'index') result = _compare.simple(a1[i], _compare.MISSING, "index")
if(!result.are_equal): if !result.are_equal:
differences[i] = result differences[i] = result
if(a1.size() < a2.size()): if a1.size() < a2.size():
for i in range(a1.size(), a2.size()): for i in range(a1.size(), a2.size()):
differences[i] = _compare.simple(_compare.MISSING, a2[i], 'index') differences[i] = _compare.simple(_compare.MISSING, a2[i], "index")
func _diff_dictionary(d1, d2): func _diff_dictionary(d1, d2):
@ -114,33 +130,33 @@ func _diff_dictionary(d1, d2):
# Process all the keys in d1 # Process all the keys in d1
_total_count += d1_keys.size() _total_count += d1_keys.size()
for key in d1_keys: for key in d1_keys:
if(!d2.has(key)): if !d2.has(key):
differences[key] = _compare.simple(d1[key], _compare.MISSING, 'key') differences[key] = _compare.simple(d1[key], _compare.MISSING, "key")
else: else:
d2_keys.remove_at(d2_keys.find(key)) d2_keys.remove_at(d2_keys.find(key))
var result = null var result = null
if(_diff_type == DEEP): if _diff_type == DEEP:
result = _compare.deep(d1[key], d2[key]) result = _compare.deep(d1[key], d2[key])
else: else:
result = _compare.simple(d1[key], d2[key]) result = _compare.simple(d1[key], d2[key])
if(!result.are_equal): if !result.are_equal:
differences[key] = result differences[key] = result
# Process all the keys in d2 that didn't exist in d1 # Process all the keys in d2 that didn't exist in d1
_total_count += d2_keys.size() _total_count += d2_keys.size()
for i in range(d2_keys.size()): for i in range(d2_keys.size()):
differences[d2_keys[i]] = _compare.simple(_compare.MISSING, d2[d2_keys[i]], 'key') differences[d2_keys[i]] = _compare.simple(_compare.MISSING, d2[d2_keys[i]], "key")
func summarize(): func summarize():
var summary = '' var summary = ""
if(are_equal): if are_equal:
summary = get_short_summary() summary = get_short_summary()
else: else:
var formatter = load('res://addons/gut/diff_formatter.gd').new() var formatter = load("res://addons/gut/diff_formatter.gd").new()
formatter.set_max_to_display(max_differences) formatter.set_max_to_display(max_differences)
summary = formatter.make_it(self) summary = formatter.make_it(self)

View file

@ -1,5 +1,5 @@
var thepath = '' var thepath = ""
var subpath = '' var subpath = ""
var stubber = null var stubber = null
var spy = null var spy = null
var gut = null var gut = null
@ -7,37 +7,44 @@ var from_singleton = null
var is_partial = null var is_partial = null
var double = null var double = null
const NO_DEFAULT_VALUE = '!__gut__no__default__value__!' const NO_DEFAULT_VALUE = "!__gut__no__default__value__!"
func from_id(inst_id): func from_id(inst_id):
if(inst_id == -1): if inst_id == -1:
return null return null
else: else:
return instance_from_id(inst_id) return instance_from_id(inst_id)
func should_call_super(method_name, called_with): func should_call_super(method_name, called_with):
if(stubber != null): if stubber != null:
return stubber.should_call_super(double, method_name, called_with) return stubber.should_call_super(double, method_name, called_with)
else: else:
return false return false
func spy_on(method_name, called_with): func spy_on(method_name, called_with):
if(spy != null): if spy != null:
spy.add_call(double, method_name, called_with) spy.add_call(double, method_name, called_with)
func get_stubbed_return(method_name, called_with): func get_stubbed_return(method_name, called_with):
if(stubber != null): if stubber != null:
return stubber.get_return(double, method_name, called_with) return stubber.get_return(double, method_name, called_with)
else: else:
return null return null
func default_val(method_name, p_index, default_val=NO_DEFAULT_VALUE):
if(stubber != null): func default_val(method_name, p_index, default_val = NO_DEFAULT_VALUE):
if stubber != null:
return stubber.get_default_value(double, method_name, p_index) return stubber.get_default_value(double, method_name, p_index)
else: else:
return null return null
func _init(values=null):
if(values != null): func _init(values = null):
if values != null:
double = values.double double = values.double
thepath = values.thepath thepath = values.thepath
subpath = values.subpath subpath = values.subpath
@ -47,6 +54,5 @@ func _init(values=null):
from_singleton = values.from_singleton from_singleton = values.from_singleton
is_partial = values.is_partial is_partial = values.is_partial
if(gut != null): if gut != null:
gut.get_autofree().add_free(double) gut.get_autofree().add_free(double)

View file

@ -30,8 +30,6 @@
# ----------- # -----------
# ############################################################################## # ##############################################################################
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# A stroke of genius if I do say so. This allows for doubling a scene without # A stroke of genius if I do say so. This allows for doubling a scene without
# having to write any files. By overloading the "instantiate" method we can # having to write any files. By overloading the "instantiate" method we can
@ -39,15 +37,15 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class PackedSceneDouble: class PackedSceneDouble:
extends PackedScene extends PackedScene
var _script = null var _script = null
var _scene = null var _scene = null
func set_script_obj(obj): func set_script_obj(obj):
_script = obj _script = obj
func instantiate(edit_state=0): func instantiate(edit_state = 0):
var inst = _scene.instantiate(edit_state) var inst = _scene.instantiate(edit_state)
if(_script != null): if _script != null:
inst.set_script(_script) inst.set_script(_script)
return inst return inst
@ -55,13 +53,13 @@ class PackedSceneDouble:
_scene = load(path) _scene = load(path)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# START Doubler # START Doubler
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
var _base_script_text = _utils.get_file_as_text('res://addons/gut/double_templates/script_template.txt') var _base_script_text = _utils.get_file_as_text(
"res://addons/gut/double_templates/script_template.txt"
)
var _script_collector = _utils.ScriptCollector.new() var _script_collector = _utils.ScriptCollector.new()
# used by tests for debugging purposes. # used by tests for debugging purposes.
var print_source = false var print_source = false
@ -71,62 +69,92 @@ var inner_class_registry = _utils.InnerClassRegistry.new()
# Properties # Properties
# ############### # ###############
var _stubber = _utils.Stubber.new() var _stubber = _utils.Stubber.new()
func get_stubber(): func get_stubber():
return _stubber return _stubber
func set_stubber(stubber): func set_stubber(stubber):
_stubber = stubber _stubber = stubber
var _lgr = _utils.get_logger() var _lgr = _utils.get_logger()
func get_logger(): func get_logger():
return _lgr return _lgr
func set_logger(logger): func set_logger(logger):
_lgr = logger _lgr = logger
_method_maker.set_logger(logger) _method_maker.set_logger(logger)
var _spy = null var _spy = null
func get_spy(): func get_spy():
return _spy return _spy
func set_spy(spy): func set_spy(spy):
_spy = spy _spy = spy
var _gut = null var _gut = null
func get_gut(): func get_gut():
return _gut return _gut
func set_gut(gut): func set_gut(gut):
_gut = gut _gut = gut
var _strategy = null var _strategy = null
func get_strategy(): func get_strategy():
return _strategy return _strategy
func set_strategy(strategy): func set_strategy(strategy):
_strategy = strategy _strategy = strategy
var _method_maker = _utils.MethodMaker.new() var _method_maker = _utils.MethodMaker.new()
func get_method_maker(): func get_method_maker():
return _method_maker return _method_maker
var _ignored_methods = _utils.OneToMany.new() var _ignored_methods = _utils.OneToMany.new()
func get_ignored_methods(): func get_ignored_methods():
return _ignored_methods return _ignored_methods
# ############### # ###############
# Private # Private
# ############### # ###############
func _init(strategy=_utils.DOUBLE_STRATEGY.SCRIPT_ONLY): func _init(strategy = _utils.DOUBLE_STRATEGY.SCRIPT_ONLY):
set_logger(_utils.get_logger()) set_logger(_utils.get_logger())
_strategy = strategy _strategy = strategy
func _get_indented_line(indents, text): func _get_indented_line(indents, text):
var to_return = '' var to_return = ""
for _i in range(indents): for _i in range(indents):
to_return += "\t" to_return += "\t"
return str(to_return, text, "\n") return str(to_return, text, "\n")
func _stub_to_call_super(parsed, method_name): func _stub_to_call_super(parsed, method_name):
if(_utils.non_super_methods.has(method_name)): if _utils.non_super_methods.has(method_name):
return return
var params = _utils.StubParams.new(parsed.script_path, method_name, parsed.subpath) var params = _utils.StubParams.new(parsed.script_path, method_name, parsed.subpath)
@ -136,43 +164,41 @@ func _stub_to_call_super(parsed, method_name):
func _get_base_script_text(parsed, override_path, partial): func _get_base_script_text(parsed, override_path, partial):
var path = parsed.script_path var path = parsed.script_path
if(override_path != null): if override_path != null:
path = override_path path = override_path
var stubber_id = -1 var stubber_id = -1
if(_stubber != null): if _stubber != null:
stubber_id = _stubber.get_instance_id() stubber_id = _stubber.get_instance_id()
var spy_id = -1 var spy_id = -1
if(_spy != null): if _spy != null:
spy_id = _spy.get_instance_id() spy_id = _spy.get_instance_id()
var gut_id = -1 var gut_id = -1
if(_gut != null): if _gut != null:
gut_id = _gut.get_instance_id() gut_id = _gut.get_instance_id()
var extends_text = parsed.get_extends_text() var extends_text = parsed.get_extends_text()
var values = { var values = {
# Top sections # Top sections
"extends":extends_text, "extends": extends_text,
"constants":'',#obj_info.get_constants_text(), "constants": "", #obj_info.get_constants_text(),
"properties":'',#obj_info.get_properties_text(), "properties": "", #obj_info.get_properties_text(),
# metadata values # metadata values
"path":path, "path": path,
"subpath":_utils.nvl(parsed.subpath, ''), "subpath": _utils.nvl(parsed.subpath, ""),
"stubber_id":stubber_id, "stubber_id": stubber_id,
"spy_id":spy_id, "spy_id": spy_id,
"gut_id":gut_id, "gut_id": gut_id,
"singleton_name":'',#_utils.nvl(obj_info.get_singleton_name(), ''), "singleton_name": "", #_utils.nvl(obj_info.get_singleton_name(), ''),
"is_partial":partial, "is_partial": partial,
} }
return _base_script_text.format(values) return _base_script_text.format(values)
func _create_double(parsed, strategy, override_path, partial): func _create_double(parsed, strategy, override_path, partial):
var base_script = _get_base_script_text(parsed, override_path, partial) var base_script = _get_base_script_text(parsed, override_path, partial)
var super_name = "" var super_name = ""
@ -183,21 +209,24 @@ func _create_double(parsed, strategy, override_path, partial):
dbl_src += base_script dbl_src += base_script
for method in parsed.get_local_methods(): for method in parsed.get_local_methods():
if(!method.is_black_listed() && !_ignored_methods.has(parsed.resource, method.meta.name)): if !method.is_black_listed() && !_ignored_methods.has(parsed.resource, method.meta.name):
var mthd = parsed.get_local_method(method.meta.name) var mthd = parsed.get_local_method(method.meta.name)
dbl_src += _get_func_text(method.meta, path, super_name) dbl_src += _get_func_text(method.meta, path, super_name)
if(strategy == _utils.DOUBLE_STRATEGY.INCLUDE_SUPER): if strategy == _utils.DOUBLE_STRATEGY.INCLUDE_SUPER:
for method in parsed.get_super_methods(): for method in parsed.get_super_methods():
if(!method.is_black_listed() && !_ignored_methods.has(parsed.resource, method.meta.name)): if (
!method.is_black_listed()
&& !_ignored_methods.has(parsed.resource, method.meta.name)
):
_stub_to_call_super(parsed, method.meta.name) _stub_to_call_super(parsed, method.meta.name)
dbl_src += _get_func_text(method.meta, path, super_name) dbl_src += _get_func_text(method.meta, path, super_name)
if(print_source): if print_source:
print(_utils.add_line_numbers(dbl_src)) print(_utils.add_line_numbers(dbl_src))
var DblClass = _utils.create_script_from_source(dbl_src) var DblClass = _utils.create_script_from_source(dbl_src)
if(_stubber != null): if _stubber != null:
_stub_method_default_values(DblClass, parsed, strategy) _stub_method_default_values(DblClass, parsed, strategy)
return DblClass return DblClass
@ -205,19 +234,18 @@ func _create_double(parsed, strategy, override_path, partial):
func _stub_method_default_values(which, parsed, strategy): func _stub_method_default_values(which, parsed, strategy):
for method in parsed.get_local_methods(): for method in parsed.get_local_methods():
if(!method.is_black_listed() && !_ignored_methods.has(parsed.resource, method.meta.name)): if !method.is_black_listed() && !_ignored_methods.has(parsed.resource, method.meta.name):
_stubber.stub_defaults_from_meta(parsed.script_path, method.meta) _stubber.stub_defaults_from_meta(parsed.script_path, method.meta)
func _double_scene_and_script(scene, strategy, partial): func _double_scene_and_script(scene, strategy, partial):
var to_return = PackedSceneDouble.new() var to_return = PackedSceneDouble.new()
to_return.load_scene(scene.get_path()) to_return.load_scene(scene.get_path())
var script_obj = _utils.get_scene_script_object(scene) var script_obj = _utils.get_scene_script_object(scene)
if(script_obj != null): if script_obj != null:
var script_dbl = null var script_dbl = null
if(partial): if partial:
script_dbl = _partial_double(script_obj, strategy, scene.get_path()) script_dbl = _partial_double(script_obj, strategy, scene.get_path())
else: else:
script_dbl = _double(script_obj, strategy, scene.get_path()) script_dbl = _double(script_obj, strategy, scene.get_path())
@ -227,18 +255,18 @@ func _double_scene_and_script(scene, strategy, partial):
func _get_inst_id_ref_str(inst): func _get_inst_id_ref_str(inst):
var ref_str = 'null' var ref_str = "null"
if(inst): if inst:
ref_str = str('instance_from_id(', inst.get_instance_id(),')') ref_str = str("instance_from_id(", inst.get_instance_id(), ")")
return ref_str return ref_str
func _get_func_text(method_hash, path, super_=""): func _get_func_text(method_hash, path, super_ = ""):
var override_count = null; var override_count = null
if(_stubber != null): if _stubber != null:
override_count = _stubber.get_parameter_count(path, method_hash.name) override_count = _stubber.get_parameter_count(path, method_hash.name)
if(override_count != null): if override_count != null:
print(method_hash.name, ' override: ', override_count) print(method_hash.name, " override: ", override_count)
var text = _method_maker.get_function_text(method_hash, path, override_count, super_) + "\n" var text = _method_maker.get_function_text(method_hash, path, override_count, super_) + "\n"
@ -248,11 +276,13 @@ func _get_func_text(method_hash, path, super_=""):
func _parse_script(obj): func _parse_script(obj):
var parsed = null var parsed = null
if(_utils.is_inner_class(obj)): if _utils.is_inner_class(obj):
if(inner_class_registry.has(obj)): if inner_class_registry.has(obj):
parsed = _script_collector.parse(inner_class_registry.get_base_resource(obj), obj) parsed = _script_collector.parse(inner_class_registry.get_base_resource(obj), obj)
else: else:
_lgr.error('Doubling Inner Classes requires you register them first. Call register_inner_classes passing the script that contains the inner class.') _lgr.error(
"Doubling Inner Classes requires you register them first. Call register_inner_classes passing the script that contains the inner class."
)
else: else:
parsed = _script_collector.parse(obj) parsed = _script_collector.parse(obj)
@ -260,15 +290,15 @@ func _parse_script(obj):
# Override path is used with scenes. # Override path is used with scenes.
func _double(obj, strategy, override_path=null): func _double(obj, strategy, override_path = null):
var parsed = _parse_script(obj) var parsed = _parse_script(obj)
if(parsed != null): if parsed != null:
return _create_double(parsed, strategy, override_path, false) return _create_double(parsed, strategy, override_path, false)
func _partial_double(obj, strategy, override_path=null): func _partial_double(obj, strategy, override_path = null):
var parsed = _parse_script(obj) var parsed = _parse_script(obj)
if(parsed != null): if parsed != null:
return _create_double(parsed, strategy, override_path, true) return _create_double(parsed, strategy, override_path, true)
@ -276,35 +306,39 @@ func _partial_double(obj, strategy, override_path=null):
# Public # Public
# ------------------------- # -------------------------
# double a script/object # double a script/object
func double(obj, strategy=_strategy): func double(obj, strategy = _strategy):
return _double(obj, strategy) return _double(obj, strategy)
func partial_double(obj, strategy=_strategy):
func partial_double(obj, strategy = _strategy):
return _partial_double(obj, strategy) return _partial_double(obj, strategy)
# double a scene # double a scene
func double_scene(scene, strategy=_strategy): func double_scene(scene, strategy = _strategy):
return _double_scene_and_script(scene, strategy, false) return _double_scene_and_script(scene, strategy, false)
func partial_double_scene(scene, strategy=_strategy):
func partial_double_scene(scene, strategy = _strategy):
return _double_scene_and_script(scene, strategy, true) return _double_scene_and_script(scene, strategy, true)
func double_gdnative(which): func double_gdnative(which):
return _double(which, _utils.DOUBLE_STRATEGY.INCLUDE_SUPER) return _double(which, _utils.DOUBLE_STRATEGY.INCLUDE_SUPER)
func partial_double_gdnative(which): func partial_double_gdnative(which):
return _partial_double(which, _utils.DOUBLE_STRATEGY.INCLUDE_SUPER) return _partial_double(which, _utils.DOUBLE_STRATEGY.INCLUDE_SUPER)
func double_inner(parent, inner, strategy=_strategy): func double_inner(parent, inner, strategy = _strategy):
var parsed = _script_collector.parse(parent, inner) var parsed = _script_collector.parse(parent, inner)
return _create_double(parsed, strategy, null, false) return _create_double(parsed, strategy, null, false)
func partial_double_inner(parent, inner, strategy=_strategy): func partial_double_inner(parent, inner, strategy = _strategy):
var parsed = _script_collector.parse(parent, inner) var parsed = _script_collector.parse(parent, inner)
return _create_double(parsed, strategy, null, true) return _create_double(parsed, strategy, null, true)

View file

@ -9,51 +9,59 @@ extends Window
panel_button = $Layout/CPanelButton/ShortcutButton, panel_button = $Layout/CPanelButton/ShortcutButton,
} }
func _ready(): func _ready():
for key in _ctrls: for key in _ctrls:
var sc_button = _ctrls[key] var sc_button = _ctrls[key]
sc_button.connect('start_edit', _on_edit_start.bind(sc_button)) sc_button.connect("start_edit", _on_edit_start.bind(sc_button))
sc_button.connect('end_edit', _on_edit_end) sc_button.connect("end_edit", _on_edit_end)
# show dialog when running scene from editor. # show dialog when running scene from editor.
if(get_parent() == get_tree().root): if get_parent() == get_tree().root:
popup_centered() popup_centered()
# ------------ # ------------
# Events # Events
# ------------ # ------------
func _on_Hide_pressed(): func _on_Hide_pressed():
hide() hide()
func _on_edit_start(which): func _on_edit_start(which):
for key in _ctrls: for key in _ctrls:
var sc_button = _ctrls[key] var sc_button = _ctrls[key]
if(sc_button != which): if sc_button != which:
sc_button.disable_set(true) sc_button.disable_set(true)
sc_button.disable_clear(true) sc_button.disable_clear(true)
func _on_edit_end(): func _on_edit_end():
for key in _ctrls: for key in _ctrls:
var sc_button = _ctrls[key] var sc_button = _ctrls[key]
sc_button.disable_set(false) sc_button.disable_set(false)
sc_button.disable_clear(false) sc_button.disable_clear(false)
# ------------ # ------------
# Public # Public
# ------------ # ------------
func get_run_all(): func get_run_all():
return _ctrls.run_all.get_shortcut() return _ctrls.run_all.get_shortcut()
func get_run_current_script(): func get_run_current_script():
return _ctrls.run_current_script.get_shortcut() return _ctrls.run_current_script.get_shortcut()
func get_run_current_inner(): func get_run_current_inner():
return _ctrls.run_current_inner.get_shortcut() return _ctrls.run_current_inner.get_shortcut()
func get_run_current_test(): func get_run_current_test():
return _ctrls.run_current_test.get_shortcut() return _ctrls.run_current_test.get_shortcut()
func get_panel_button(): func get_panel_button():
return _ctrls.panel_button.get_shortcut() return _ctrls.panel_button.get_shortcut()
@ -61,11 +69,11 @@ func get_panel_button():
func save_shortcuts(path): func save_shortcuts(path):
var f = ConfigFile.new() var f = ConfigFile.new()
f.set_value('main', 'run_all', _ctrls.run_all.get_shortcut()) 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_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_inner", _ctrls.run_current_inner.get_shortcut())
f.set_value('main', 'run_current_test', _ctrls.run_current_test.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.set_value("main", "panel_button", _ctrls.panel_button.get_shortcut())
f.save(path) f.save(path)
@ -75,8 +83,8 @@ func load_shortcuts(path):
var f = ConfigFile.new() var f = ConfigFile.new()
f.load(path) f.load(path)
_ctrls.run_all.set_shortcut(f.get_value('main', 'run_all', emptyShortcut)) _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_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_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.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)) _ctrls.panel_button.set_shortcut(f.get_value("main", "panel_button", emptyShortcut))

View file

@ -1,39 +1,37 @@
@tool @tool
extends Control extends Control
const RUNNER_JSON_PATH = 'res://.gut_editor_config.json' const RUNNER_JSON_PATH = "res://.gut_editor_config.json"
const RESULT_FILE = 'user://.gut_editor.bbcode' const RESULT_FILE = "user://.gut_editor.bbcode"
const RESULT_JSON = 'user://.gut_editor.json' const RESULT_JSON = "user://.gut_editor.json"
const SHORTCUTS_PATH = 'res://.gut_editor_shortcuts.cfg' const SHORTCUTS_PATH = "res://.gut_editor_shortcuts.cfg"
var TestScript = load('res://addons/gut/test.gd') var TestScript = load("res://addons/gut/test.gd")
var GutConfigGui = load('res://addons/gut/gui/gut_config_gui.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 ScriptTextEditors = load("res://addons/gut/gui/script_text_editor_controls.gd")
var _interface = null; var _interface = null
var _is_running = false; var _is_running = false
var _gut_config = load('res://addons/gut/gut_config.gd').new() var _gut_config = load("res://addons/gut/gut_config.gd").new()
var _gut_config_gui = null var _gut_config_gui = null
var _gut_plugin = null var _gut_plugin = null
var _light_color = Color(0, 0, 0, .5) var _light_color = Color(0, 0, 0, .5)
var _panel_button = null var _panel_button = null
var _last_selected_path = null var _last_selected_path = null
@onready var _ctrls = { @onready var _ctrls = {
output = $layout/RSplit/CResults/TabBar/OutputText.get_rich_text_edit(), output = $layout/RSplit/CResults/TabBar/OutputText.get_rich_text_edit(),
output_ctrl = $layout/RSplit/CResults/TabBar/OutputText, output_ctrl = $layout/RSplit/CResults/TabBar/OutputText,
run_button = $layout/ControlBar/RunAll, run_button = $layout/ControlBar/RunAll,
shortcuts_button = $layout/ControlBar/Shortcuts, shortcuts_button = $layout/ControlBar/Shortcuts,
settings_button = $layout/ControlBar/Settings, settings_button = $layout/ControlBar/Settings,
run_results_button = $layout/ControlBar/RunResultsBtn, run_results_button = $layout/ControlBar/RunResultsBtn,
output_button = $layout/ControlBar/OutputBtn, output_button = $layout/ControlBar/OutputBtn,
settings = $layout/RSplit/sc/Settings, settings = $layout/RSplit/sc/Settings,
shortcut_dialog = $BottomPanelShortcuts, shortcut_dialog = $BottomPanelShortcuts,
light = $layout/RSplit/CResults/ControlBar/Light3D, light = $layout/RSplit/CResults/ControlBar/Light3D,
results = { results =
{
bar = $layout/RSplit/CResults/ControlBar, bar = $layout/RSplit/CResults/ControlBar,
passing = $layout/RSplit/CResults/ControlBar/Passing/value, passing = $layout/RSplit/CResults/ControlBar/Passing/value,
failing = $layout/RSplit/CResults/ControlBar/Failing/value, failing = $layout/RSplit/CResults/ControlBar/Failing/value,
@ -52,27 +50,37 @@ func _init():
func _ready(): func _ready():
_ctrls.results.bar.connect('draw', _on_results_bar_draw.bind(_ctrls.results.bar)) _ctrls.results.bar.connect("draw", _on_results_bar_draw.bind(_ctrls.results.bar))
hide_settings(!_ctrls.settings_button.button_pressed) hide_settings(!_ctrls.settings_button.button_pressed)
_gut_config_gui = GutConfigGui.new(_ctrls.settings) _gut_config_gui = GutConfigGui.new(_ctrls.settings)
_gut_config_gui.set_options(_gut_config.options) _gut_config_gui.set_options(_gut_config.options)
_apply_options_to_controls() _apply_options_to_controls()
_ctrls.shortcuts_button.icon = get_theme_icon('Shortcut', 'EditorIcons') _ctrls.shortcuts_button.icon = get_theme_icon("Shortcut", "EditorIcons")
_ctrls.settings_button.icon = get_theme_icon('Tools', 'EditorIcons') _ctrls.settings_button.icon = get_theme_icon("Tools", "EditorIcons")
_ctrls.run_results_button.icon = get_theme_icon('AnimationTrackGroup', 'EditorIcons') # Tree _ctrls.run_results_button.icon = get_theme_icon("AnimationTrackGroup", "EditorIcons") # Tree
_ctrls.output_button.icon = get_theme_icon('Font', 'EditorIcons') _ctrls.output_button.icon = get_theme_icon("Font", "EditorIcons")
_ctrls.run_results.set_output_control(_ctrls.output_ctrl) _ctrls.run_results.set_output_control(_ctrls.output_ctrl)
_ctrls.run_results.set_font( (
_gut_config.options.panel_options.font_name, _ctrls
_gut_config.options.panel_options.font_size) . 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') var check_import = load("res://addons/gut/images/red.png")
if(check_import == null): 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.') _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: else:
_ctrls.run_results.add_centered_text("Let's run some tests!") _ctrls.run_results.add_centered_text("Let's run some tests!")
@ -86,24 +94,30 @@ func _apply_options_to_controls():
_ctrls.output_ctrl.set_all_fonts(_gut_config.options.panel_options.font_name) _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.output_ctrl.set_font_size(_gut_config.options.panel_options.font_size)
_ctrls.run_results.set_font( (
_gut_config.options.panel_options.font_name, _ctrls
_gut_config.options.panel_options.font_size) . 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) _ctrls.run_results.set_show_orphans(!_gut_config.options.hide_orphans)
func _process(delta): func _process(delta):
if(_is_running): if _is_running:
if(!_interface.is_playing_scene()): if !_interface.is_playing_scene():
_is_running = false _is_running = false
_ctrls.output_ctrl.add_text("\ndone") _ctrls.output_ctrl.add_text("\ndone")
load_result_output() load_result_output()
_gut_plugin.make_bottom_panel_item_visible(self) _gut_plugin.make_bottom_panel_item_visible(self)
# --------------- # ---------------
# Private # Private
# --------------- # ---------------
func load_shortcuts(): func load_shortcuts():
_ctrls.shortcut_dialog.load_shortcuts(SHORTCUTS_PATH) _ctrls.shortcut_dialog.load_shortcuts(SHORTCUTS_PATH)
_apply_shortcuts() _apply_shortcuts()
@ -111,7 +125,7 @@ func load_shortcuts():
func _is_test_script(script): func _is_test_script(script):
var from = script.get_base_script() var from = script.get_base_script()
while(from and from.resource_path != 'res://addons/gut/test.gd'): while from and from.resource_path != "res://addons/gut/test.gd":
from = from.get_base_script() from = from.get_base_script()
return from != null return from != null
@ -121,7 +135,7 @@ func _show_errors(errs):
_ctrls.output_ctrl.clear() _ctrls.output_ctrl.clear()
var text = "Cannot run tests, you have a configuration error:\n" var text = "Cannot run tests, you have a configuration error:\n"
for e in errs: for e in errs:
text += str('* ', e, "\n") text += str("* ", e, "\n")
text += "Check your settings ----->" text += "Check your settings ----->"
_ctrls.output_ctrl.add_text(text) _ctrls.output_ctrl.add_text(text)
hide_output_text(false) hide_output_text(false)
@ -136,39 +150,40 @@ func _save_config():
_gut_config.options.panel_options.use_colors = _ctrls.output_ctrl.get_use_colors() _gut_config.options.panel_options.use_colors = _ctrls.output_ctrl.get_use_colors()
var w_result = _gut_config.write_options(RUNNER_JSON_PATH) var w_result = _gut_config.write_options(RUNNER_JSON_PATH)
if(w_result != OK): if w_result != OK:
push_error(str('Could not write options to ', RUNNER_JSON_PATH, ': ', w_result)) push_error(str("Could not write options to ", RUNNER_JSON_PATH, ": ", w_result))
return; return
func _run_tests(): func _run_tests():
var issues = _gut_config_gui.get_config_issues() var issues = _gut_config_gui.get_config_issues()
if(issues.size() > 0): if issues.size() > 0:
_show_errors(issues) _show_errors(issues)
return return
write_file(RESULT_FILE, 'Run in progress') write_file(RESULT_FILE, "Run in progress")
_save_config() _save_config()
_apply_options_to_controls() _apply_options_to_controls()
_ctrls.output_ctrl.clear() _ctrls.output_ctrl.clear()
_ctrls.run_results.clear() _ctrls.run_results.clear()
_ctrls.run_results.add_centered_text('Running...') _ctrls.run_results.add_centered_text("Running...")
_interface.play_custom_scene('res://addons/gut/gui/GutRunner.tscn') _interface.play_custom_scene("res://addons/gut/gui/GutRunner.tscn")
_is_running = true _is_running = true
_ctrls.output_ctrl.add_text('Running...') _ctrls.output_ctrl.add_text("Running...")
func _apply_shortcuts(): func _apply_shortcuts():
_ctrls.run_button.shortcut = _ctrls.shortcut_dialog.get_run_all() _ctrls.run_button.shortcut = _ctrls.shortcut_dialog.get_run_all()
_ctrls.run_at_cursor.get_script_button().shortcut = \ _ctrls.run_at_cursor.get_script_button().shortcut = (
_ctrls.shortcut_dialog.get_run_current_script() _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_inner_button().shortcut = (
_ctrls.run_at_cursor.get_test_button().shortcut = \ _ctrls . shortcut_dialog . get_run_current_inner()
_ctrls.shortcut_dialog.get_run_current_test() )
_ctrls.run_at_cursor.get_test_button().shortcut = _ctrls.shortcut_dialog.get_run_current_test()
_panel_button.shortcut = _ctrls.shortcut_dialog.get_panel_button() _panel_button.shortcut = _ctrls.shortcut_dialog.get_panel_button()
@ -194,7 +209,7 @@ func _on_Light_draw():
func _on_editor_script_changed(script): func _on_editor_script_changed(script):
if(script): if script:
set_current_script(script) set_current_script(script)
@ -205,10 +220,12 @@ func _on_RunAll_pressed():
func _on_Shortcuts_pressed(): func _on_Shortcuts_pressed():
_ctrls.shortcut_dialog.popup_centered() _ctrls.shortcut_dialog.popup_centered()
func _on_bottom_panel_shortcuts_visibility_changed(): func _on_bottom_panel_shortcuts_visibility_changed():
_apply_shortcuts() _apply_shortcuts()
_ctrls.shortcut_dialog.save_shortcuts(SHORTCUTS_PATH) _ctrls.shortcut_dialog.save_shortcuts(SHORTCUTS_PATH)
func _on_RunAtCursor_run_tests(what): func _on_RunAtCursor_run_tests(what):
_gut_config.options.selected = what.script _gut_config.options.selected = what.script
_gut_config.options.inner_class = what.inner_class _gut_config.options.inner_class = what.inner_class
@ -228,7 +245,7 @@ func _on_OutputBtn_pressed():
func _on_RunResultsBtn_pressed(): func _on_RunResultsBtn_pressed():
hide_result_tree(! _ctrls.run_results_button.button_pressed) hide_result_tree(!_ctrls.run_results_button.button_pressed)
_save_config() _save_config()
@ -237,6 +254,7 @@ func _on_RunResultsBtn_pressed():
func _on_UseColors_pressed(): func _on_UseColors_pressed():
pass pass
# --------------- # ---------------
# Public # Public
# --------------- # ---------------
@ -251,7 +269,7 @@ func hide_settings(should):
# collapse only collapses the first control, so we move # collapse only collapses the first control, so we move
# settings around to be the collapsed one # settings around to be the collapsed one
if(should): if should:
s_scroll.get_parent().move_child(s_scroll, 0) s_scroll.get_parent().move_child(s_scroll, 0)
else: else:
s_scroll.get_parent().move_child(s_scroll, 1) s_scroll.get_parent().move_child(s_scroll, 1)
@ -270,13 +288,13 @@ func load_result_output():
var summary = get_file_as_text(RESULT_JSON) var summary = get_file_as_text(RESULT_JSON)
var test_json_conv = JSON.new() var test_json_conv = JSON.new()
if (test_json_conv.parse(summary) != OK): if test_json_conv.parse(summary) != OK:
return return
var results = test_json_conv.get_data() var results = test_json_conv.get_data()
_ctrls.run_results.load_json_results(results) _ctrls.run_results.load_json_results(results)
var summary_json = results['test_scripts']['props'] var summary_json = results["test_scripts"]["props"]
_ctrls.results.passing.text = str(summary_json.passing) _ctrls.results.passing.text = str(summary_json.passing)
_ctrls.results.passing.get_parent().visible = true _ctrls.results.passing.get_parent().visible = true
@ -284,22 +302,24 @@ func load_result_output():
_ctrls.results.failing.get_parent().visible = true _ctrls.results.failing.get_parent().visible = true
_ctrls.results.pending.text = str(summary_json.pending) _ctrls.results.pending.text = str(summary_json.pending)
_ctrls.results.pending.get_parent().visible = _ctrls.results.pending.text != '0' _ctrls.results.pending.get_parent().visible = _ctrls.results.pending.text != "0"
_ctrls.results.errors.text = str(summary_json.errors) _ctrls.results.errors.text = str(summary_json.errors)
_ctrls.results.errors.get_parent().visible = _ctrls.results.errors.text != '0' _ctrls.results.errors.get_parent().visible = _ctrls.results.errors.text != "0"
_ctrls.results.warnings.text = str(summary_json.warnings) _ctrls.results.warnings.text = str(summary_json.warnings)
_ctrls.results.warnings.get_parent().visible = _ctrls.results.warnings.text != '0' _ctrls.results.warnings.get_parent().visible = _ctrls.results.warnings.text != "0"
_ctrls.results.orphans.text = str(summary_json.orphans) _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 _ctrls.results.orphans.get_parent().visible = (
_ctrls.results.orphans.text != "0" and !_gut_config.options.hide_orphans
)
if(summary_json.tests == 0): if summary_json.tests == 0:
_light_color = Color(1, 0, 0, .75) _light_color = Color(1, 0, 0, .75)
elif(summary_json.failures != 0): elif summary_json.failures != 0:
_light_color = Color(1, 0, 0, .75) _light_color = Color(1, 0, 0, .75)
elif(summary_json.pending != 0): elif summary_json.pending != 0:
_light_color = Color(1, 1, 0, .75) _light_color = Color(1, 1, 0, .75)
else: else:
_light_color = Color(0, 1, 0, .75) _light_color = Color(0, 1, 0, .75)
@ -308,8 +328,8 @@ func load_result_output():
func set_current_script(script): func set_current_script(script):
if(script): if script:
if(_is_test_script(script)): if _is_test_script(script):
var file = script.resource_path.get_file() var file = script.resource_path.get_file()
_last_selected_path = script.resource_path.get_file() _last_selected_path = script.resource_path.get_file()
_ctrls.run_at_cursor.activate_for_script(script.resource_path) _ctrls.run_at_cursor.activate_for_script(script.resource_path)
@ -317,7 +337,11 @@ func set_current_script(script):
func set_interface(value): func set_interface(value):
_interface = value _interface = value
_interface.get_script_editor().connect("editor_script_changed",Callable(self,'_on_editor_script_changed')) (
_interface
. get_script_editor()
. connect("editor_script_changed", Callable(self, "_on_editor_script_changed"))
)
var ste = ScriptTextEditors.new(_interface.get_script_editor()) var ste = ScriptTextEditors.new(_interface.get_script_editor())
_ctrls.run_results.set_interface(_interface) _ctrls.run_results.set_interface(_interface)
@ -333,14 +357,15 @@ func set_plugin(value):
func set_panel_button(value): func set_panel_button(value):
_panel_button = value _panel_button = value
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Write a file. # Write a file.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func write_file(path, content): func write_file(path, content):
var f = FileAccess.open(path, FileAccess.WRITE) var f = FileAccess.open(path, FileAccess.WRITE)
if(f != null): if f != null:
f.store_string(content) f.store_string(content)
f = null; f = null
return FileAccess.get_open_error() return FileAccess.get_open_error()
@ -349,9 +374,9 @@ func write_file(path, content):
# Returns the text of a file or an empty string if the file could not be opened. # Returns the text of a file or an empty string if the file could not be opened.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func get_file_as_text(path): func get_file_as_text(path):
var to_return = '' var to_return = ""
var f = FileAccess.open(path, FileAccess.READ) var f = FileAccess.open(path, FileAccess.READ)
if(f != null): if f != null:
to_return = f.get_as_text() to_return = f.get_as_text()
f = null f = null
return to_return return to_return
@ -361,7 +386,7 @@ func get_file_as_text(path):
# return if_null if value is null otherwise return value # return if_null if value is null otherwise return value
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func nvl(value, if_null): func nvl(value, if_null):
if(value == null): if value == null:
return if_null return if_null
else: else:
return value return value

View file

@ -1,15 +1,15 @@
extends Node2D extends Node2D
var Gut = load('res://addons/gut/gut.gd') var Gut = load("res://addons/gut/gut.gd")
var ResultExporter = load('res://addons/gut/result_exporter.gd') var ResultExporter = load("res://addons/gut/result_exporter.gd")
var GutConfig = load('res://addons/gut/gut_config.gd') var GutConfig = load("res://addons/gut/gut_config.gd")
const RUNNER_JSON_PATH = 'res://.gut_editor_config.json' const RUNNER_JSON_PATH = "res://.gut_editor_config.json"
const RESULT_FILE = 'user://.gut_editor.bbcode' const RESULT_FILE = "user://.gut_editor.bbcode"
const RESULT_JSON = 'user://.gut_editor.json' const RESULT_JSON = "user://.gut_editor.json"
var _gut_config = null var _gut_config = null
var _gut = null; var _gut = null
var _wrote_results = false var _wrote_results = false
# Flag for when this is being used at the command line. Otherwise it is # 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 # assumed this is being used by the panel and being launched with
@ -21,55 +21,63 @@ var _cmdln_mode = false
var auto_run_tests = true var auto_run_tests = true
func _ready(): func _ready():
if(_gut_config == null): if _gut_config == null:
_gut_config = GutConfig.new() _gut_config = GutConfig.new()
_gut_config.load_panel_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 # 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 # 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. # interact with the scene that was run via play_custom_scene.
if(!_cmdln_mode and auto_run_tests): if !_cmdln_mode and auto_run_tests:
call_deferred('run_tests') call_deferred("run_tests")
func run_tests(show_gui=true): func run_tests(show_gui = true):
if _gut == null:
if(_gut == null):
get_gut() get_gut()
_setup_gui(show_gui) _setup_gui(show_gui)
_gut.add_children_to = self _gut.add_children_to = self
if(_gut_config.options.gut_on_top): if _gut_config.options.gut_on_top:
_gut_layer.add_child(_gut) _gut_layer.add_child(_gut)
else: else:
add_child(_gut) add_child(_gut)
if(!_cmdln_mode): if !_cmdln_mode:
_gut.end_run.connect(_on_tests_finished.bind(_gut_config.options.should_exit, _gut_config.options.should_exit_on_success)) (
_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) _gut_config.config_gut(_gut)
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) _gut.test_scripts(run_rest_of_scripts)
func _setup_gui(show_gui): func _setup_gui(show_gui):
if(show_gui): if show_gui:
_gui.gut = _gut _gui.gut = _gut
var printer = _gut.logger.get_printer('gui') var printer = _gut.logger.get_printer("gui")
printer.set_textbox(_gui.get_textbox()) printer.set_textbox(_gui.get_textbox())
else: else:
_gut.logger.disable_printer('gui', true) _gut.logger.disable_printer("gui", true)
_gui.visible = false _gui.visible = false
var opts = _gut_config.options var opts = _gut_config.options
_gui.set_font_size(opts.font_size) _gui.set_font_size(opts.font_size)
_gui.set_font(opts.font_name) _gui.set_font(opts.font_name)
if(opts.font_color != null and opts.font_color.is_valid_html_color()): if opts.font_color != null and opts.font_color.is_valid_html_color():
_gui.set_default_font_color(Color(opts.font_color)) _gui.set_default_font_color(Color(opts.font_color))
if(opts.background_color != null and opts.background_color.is_valid_html_color()): if opts.background_color != null and opts.background_color.is_valid_html_color():
_gui.set_background_color(Color(opts.background_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))) #_tester.set_modulate(Color(1.0, 1.0, 1.0, min(1.0, float(opts.opacity) / 100)))
@ -79,16 +87,15 @@ func _setup_gui(show_gui):
# _tester.get_gui().compact_mode(true) # _tester.get_gui().compact_mode(true)
func _write_results(): func _write_results():
var content = _gui.get_textbox().text #_gut.logger.get_gui_bbcode() var content = _gui.get_textbox().text #_gut.logger.get_gui_bbcode()
var f = FileAccess.open(RESULT_FILE, FileAccess.WRITE) var f = FileAccess.open(RESULT_FILE, FileAccess.WRITE)
if(f != null): if f != null:
f.store_string(content) f.store_string(content)
f.close() f.close()
else: else:
push_error('Could not save bbcode, result = ', FileAccess.get_open_error()) push_error("Could not save bbcode, result = ", FileAccess.get_open_error())
var exporter = ResultExporter.new() var exporter = ResultExporter.new()
var f_result = exporter.write_json_file(_gut, RESULT_JSON) var f_result = exporter.write_json_file(_gut, RESULT_JSON)
@ -96,21 +103,21 @@ func _write_results():
func _exit_tree(): func _exit_tree():
if(!_wrote_results and !_cmdln_mode): if !_wrote_results and !_cmdln_mode:
_write_results() _write_results()
func _on_tests_finished(should_exit, should_exit_on_success): func _on_tests_finished(should_exit, should_exit_on_success):
_write_results() _write_results()
if(should_exit): if should_exit:
get_tree().quit() 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() get_tree().quit()
func get_gut(): func get_gut():
if(_gut == null): if _gut == null:
_gut = Gut.new() _gut = Gut.new()
return _gut return _gut

View file

@ -1,32 +1,37 @@
extends VBoxContainer extends VBoxContainer
@tool @tool
class SearchResults: class SearchResults:
var L = 0 var L = 0
var C = 0 var C = 0
var positions = [] var positions = []
var te = null var te = null
var _last_term = '' var _last_term = ""
func _search_te(text, start_position, flags=0): func _search_te(text, start_position, flags = 0):
var start_pos = start_position var start_pos = start_position
if(start_pos[L] < 0 or start_pos[L] > te.get_line_count()): if start_pos[L] < 0 or start_pos[L] > te.get_line_count():
start_pos[L] = 0 start_pos[L] = 0
if(start_pos[C] < 0): if start_pos[C] < 0:
start_pos[L] = 0 start_pos[L] = 0
var result = te.search(text, flags, start_pos[L], start_pos[C]) var result = te.search(text, flags, start_pos[L], start_pos[C])
if(result.size() == 2 and result[L] == start_position[L] and if (
result[C] == start_position[C] and text == _last_term): result.size() == 2
if(flags == TextEdit.SEARCH_BACKWARDS): and result[L] == start_position[L]
and result[C] == start_position[C]
and text == _last_term
):
if flags == TextEdit.SEARCH_BACKWARDS:
result[C] -= 1 result[C] -= 1
else: else:
result[C] += 1 result[C] += 1
result = _search_te(text, result, flags) result = _search_te(text, result, flags)
L = result.y L = result.y
C = result.x C = result.x
elif(result.size() == 2): elif result.size() == 2:
te.scroll_vertical = result[L] te.scroll_vertical = result[L]
te.select(result[L], result[C], result[L], result[C] + text.length()) te.select(result[L], result[C], result[L], result[C] + text.length())
te.set_caret_column(result[C]) te.set_caret_column(result[C])
@ -67,12 +72,13 @@ class SearchResults:
var last_pos = [0, 0] var last_pos = [0, 0]
positions.clear() positions.clear()
while(found): while found:
c_pos = te.search(text, 0, c_pos[L], c_pos[C]) c_pos = te.search(text, 0, c_pos[L], c_pos[C])
if(c_pos.size() > 0 and if (
(c_pos[L] > last_pos[L] or c_pos.size() > 0
(c_pos[L] == last_pos[L] and c_pos[C] > last_pos[C]))): 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]]) positions.append([c_pos[L], c_pos[C]])
c_pos[C] += 1 c_pos[C] += 1
last_pos = c_pos last_pos = c_pos
@ -80,42 +86,41 @@ class SearchResults:
found = false found = false
@onready var _ctrls = { @onready var _ctrls = {
output = $Output, output = $Output,
copy_button = $Toolbar/CopyButton, copy_button = $Toolbar/CopyButton,
use_colors = $Toolbar/UseColors, use_colors = $Toolbar/UseColors,
clear_button = $Toolbar/ClearButton, clear_button = $Toolbar/ClearButton,
word_wrap = $Toolbar/WordWrap, word_wrap = $Toolbar/WordWrap,
show_search = $Toolbar/ShowSearch, show_search = $Toolbar/ShowSearch,
search_bar =
search_bar = { {
bar = $Search, bar = $Search,
search_term = $Search/SearchTerm, search_term = $Search/SearchTerm,
} }
} }
var _sr = SearchResults.new() var _sr = SearchResults.new()
func _test_running_setup(): func _test_running_setup():
_ctrls.use_colors.text = 'use colors' _ctrls.use_colors.text = "use colors"
_ctrls.show_search.text = 'search' _ctrls.show_search.text = "search"
_ctrls.word_wrap.text = 'ww' _ctrls.word_wrap.text = "ww"
set_all_fonts("CourierPrime") set_all_fonts("CourierPrime")
set_font_size(20) set_font_size(20)
load_file('user://.gut_editor.bbcode') load_file("user://.gut_editor.bbcode")
func _ready(): func _ready():
_sr.te = _ctrls.output _sr.te = _ctrls.output
_ctrls.use_colors.icon = get_theme_icon('RichTextEffect', 'EditorIcons') _ctrls.use_colors.icon = get_theme_icon("RichTextEffect", "EditorIcons")
_ctrls.show_search.icon = get_theme_icon('Search', 'EditorIcons') _ctrls.show_search.icon = get_theme_icon("Search", "EditorIcons")
_ctrls.word_wrap.icon = get_theme_icon('Loop', 'EditorIcons') _ctrls.word_wrap.icon = get_theme_icon("Loop", "EditorIcons")
_setup_colors() _setup_colors()
if(get_parent() == get_tree().root): if get_parent() == get_tree().root:
_test_running_setup() _test_running_setup()
@ -125,23 +130,23 @@ func _ready():
func _setup_colors(): func _setup_colors():
_ctrls.output.clear() _ctrls.output.clear()
var keywords = [ var keywords = [
['Failed', Color.RED], ["Failed", Color.RED],
['Passed', Color.GREEN], ["Passed", Color.GREEN],
['Pending', Color.YELLOW], ["Pending", Color.YELLOW],
['Orphans', Color.YELLOW], ["Orphans", Color.YELLOW],
['WARNING', Color.YELLOW], ["WARNING", Color.YELLOW],
['ERROR', Color.RED] ["ERROR", Color.RED]
] ]
for keyword in keywords: for keyword in keywords:
if (_ctrls.output.syntax_highlighter == null) : if _ctrls.output.syntax_highlighter == null:
_ctrls.output.syntax_highlighter = CodeHighlighter.new() _ctrls.output.syntax_highlighter = CodeHighlighter.new()
_ctrls.output.syntax_highlighter.add_keyword_color(keyword[0], keyword[1]) _ctrls.output.syntax_highlighter.add_keyword_color(keyword[0], keyword[1])
var f_color = null var f_color = null
if (_ctrls.output.theme == null) : if _ctrls.output.theme == null:
f_color = get_theme_color("font_color") f_color = get_theme_color("font_color")
else : else:
f_color = _ctrls.output.theme.font_color f_color = _ctrls.output.theme.font_color
_ctrls.output.add_theme_color_override("font_color_readonly", f_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("function_color", f_color)
@ -151,8 +156,8 @@ func _setup_colors():
func _set_font(font_name, custom_name): func _set_font(font_name, custom_name):
var rtl = _ctrls.output var rtl = _ctrls.output
if(font_name == null): if font_name == null:
rtl.set('custom_fonts/' + custom_name, null) rtl.set("custom_fonts/" + custom_name, null)
else: else:
pass pass
# cuasing issues in 4.0 # cuasing issues in 4.0
@ -184,7 +189,8 @@ func _on_ShowSearch_pressed():
func _on_SearchTerm_focus_entered(): func _on_SearchTerm_focus_entered():
_ctrls.search_bar.search_term.call_deferred('select_all') _ctrls.search_bar.search_term.call_deferred("select_all")
func _on_SearchNext_pressed(): func _on_SearchNext_pressed():
_sr.find_next(_ctrls.search_bar.search_term.text) _sr.find_next(_ctrls.search_bar.search_term.text)
@ -195,63 +201,67 @@ func _on_SearchPrev_pressed():
func _on_SearchTerm_text_changed(new_text): func _on_SearchTerm_text_changed(new_text):
if(new_text == ''): if new_text == "":
_ctrls.output.deselect() _ctrls.output.deselect()
else: else:
_sr.find_next(new_text) _sr.find_next(new_text)
func _on_SearchTerm_text_entered(new_text): func _on_SearchTerm_text_entered(new_text):
if(Input.is_physical_key_pressed(KEY_SHIFT)): if Input.is_physical_key_pressed(KEY_SHIFT):
_sr.find_prev(new_text) _sr.find_prev(new_text)
else: else:
_sr.find_next(new_text) _sr.find_next(new_text)
func _on_SearchTerm_gui_input(event): func _on_SearchTerm_gui_input(event):
if(event is InputEventKey and !event.pressed and event.scancode == KEY_ESCAPE): if event is InputEventKey and !event.pressed and event.scancode == KEY_ESCAPE:
show_search(false) show_search(false)
func _on_WordWrap_pressed(): func _on_WordWrap_pressed():
_ctrls.output.wrap_enabled = _ctrls.word_wrap.pressed _ctrls.output.wrap_enabled = _ctrls.word_wrap.pressed
_ctrls.output.queue_redraw() _ctrls.output.queue_redraw()
# ------------------ # ------------------
# Public # Public
# ------------------ # ------------------
func show_search(should): func show_search(should):
_ctrls.search_bar.bar.visible = should _ctrls.search_bar.bar.visible = should
if(should): if should:
_ctrls.search_bar.search_term.grab_focus() _ctrls.search_bar.search_term.grab_focus()
_ctrls.search_bar.search_term.select_all() _ctrls.search_bar.search_term.select_all()
_ctrls.show_search.button_pressed = should _ctrls.show_search.button_pressed = should
func search(text, start_pos, highlight=true): func search(text, start_pos, highlight = true):
return _sr.find_next(text) return _sr.find_next(text)
func copy_to_clipboard(): func copy_to_clipboard():
var selected = _ctrls.output.get_selection_text() var selected = _ctrls.output.get_selection_text()
if(selected != ''): if selected != "":
OS.clipboard = selected OS.clipboard = selected
else: else:
OS.clipboard = _ctrls.output.text OS.clipboard = _ctrls.output.text
func clear(): func clear():
_ctrls.output.text = '' _ctrls.output.text = ""
func set_all_fonts(base_name): func set_all_fonts(base_name):
if(base_name == 'Default'): if base_name == "Default":
_set_font(null, 'font') _set_font(null, "font")
# _set_font(null, 'normal_font') # _set_font(null, 'normal_font')
# _set_font(null, 'bold_font') # _set_font(null, 'bold_font')
# _set_font(null, 'italics_font') # _set_font(null, 'italics_font')
# _set_font(null, 'bold_italics_font') # _set_font(null, 'bold_italics_font')
else: else:
_set_font(base_name + '-Regular', 'font') _set_font(base_name + "-Regular", "font")
# _set_font(base_name + '-Regular', 'normal_font') # _set_font(base_name + '-Regular', 'normal_font')
# _set_font(base_name + '-Bold', 'bold_font') # _set_font(base_name + '-Bold', 'bold_font')
# _set_font(base_name + '-Italic', 'italics_font') # _set_font(base_name + '-Italic', 'italics_font')
@ -260,8 +270,10 @@ func set_all_fonts(base_name):
func set_font_size(new_size): func set_font_size(new_size):
var rtl = _ctrls.output var rtl = _ctrls.output
if(rtl.get('custom_fonts/font') != null): if rtl.get("custom_fonts/font") != null:
rtl.get('custom_fonts/font').size = new_size rtl.get("custom_fonts/font").size = new_size
# rtl.get('custom_fonts/bold_italics_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/bold_font').size = new_size
# rtl.get('custom_fonts/italics_font').size = new_size # rtl.get('custom_fonts/italics_font').size = new_size
@ -273,7 +285,7 @@ func set_use_colors(value):
func get_use_colors(): func get_use_colors():
return false; return false
func get_rich_text_edit(): func get_rich_text_edit():
@ -281,20 +293,19 @@ func get_rich_text_edit():
func load_file(path): func load_file(path):
var f = FileAccess.open(path, FileAccess.READ) var f = FileAccess.open(path, FileAccess.READ)
if(f == null): if f == null:
return return
var t = f.get_as_text() var t = f.get_as_text()
f.close() f.close()
_ctrls.output.text = t _ctrls.output.text = t
_ctrls.output.scroll_vertical = _ctrls.output.get_line_count() _ctrls.output.scroll_vertical = _ctrls.output.get_line_count()
_ctrls.output.set_deferred('scroll_vertical', _ctrls.output.get_line_count()) _ctrls.output.set_deferred("scroll_vertical", _ctrls.output.get_line_count())
func add_text(text): func add_text(text):
if(is_inside_tree()): if is_inside_tree():
_ctrls.output.text += text _ctrls.output.text += text

View file

@ -1,8 +1,7 @@
@tool @tool
extends Control extends Control
var ScriptTextEditors = load("res://addons/gut/gui/script_text_editor_controls.gd")
var ScriptTextEditors = load('res://addons/gut/gui/script_text_editor_controls.gd')
@onready var _ctrls = { @onready var _ctrls = {
btn_script = $HBox/BtnRunScript, btn_script = $HBox/BtnRunScript,
@ -28,17 +27,18 @@ func _ready():
_ctrls.btn_inner.visible = false _ctrls.btn_inner.visible = false
_ctrls.btn_method.visible = false _ctrls.btn_method.visible = false
# ---------------- # ----------------
# Private # Private
# ---------------- # ----------------
func _set_editor(which): func _set_editor(which):
_last_line = -1 _last_line = -1
if(_cur_editor != null and _cur_editor.get_ref()): if _cur_editor != null and _cur_editor.get_ref():
_cur_editor.get_ref().disconnect('cursor_changed',Callable(self,'_on_cursor_changed')) _cur_editor.get_ref().disconnect("cursor_changed", Callable(self, "_on_cursor_changed"))
if(which != null): if which != null:
_cur_editor = weakref(which) _cur_editor = weakref(which)
which.connect('cursor_changed',Callable(self,'_on_cursor_changed'),[which]) which.connect("cursor_changed", Callable(self, "_on_cursor_changed"), [which])
_last_line = which.get_caret_line() _last_line = which.get_caret_line()
_last_info = _editors.get_line_info() _last_info = _editors.get_line_info()
@ -64,14 +64,16 @@ func _update_buttons(info):
# first time. # first time.
call_deferred("_update_size") call_deferred("_update_size")
func _update_size(): func _update_size():
custom_minimum_size.x = _ctrls.btn_method.size.x + _ctrls.btn_method.rect_position.x custom_minimum_size.x = _ctrls.btn_method.size.x + _ctrls.btn_method.rect_position.x
# ---------------- # ----------------
# Events # Events
# ---------------- # ----------------
func _on_cursor_changed(which): func _on_cursor_changed(which):
if(which.get_caret_line() != _last_line): if which.get_caret_line() != _last_line:
_last_line = which.get_caret_line() _last_line = which.get_caret_line()
_last_info = _editors.get_line_info() _last_info = _editors.get_line_info()
_update_buttons(_last_info) _update_buttons(_last_info)
@ -147,6 +149,3 @@ func search_current_editor_for_text(txt):
to_return = result[TextEdit.SEARCH_RESULT_LINE] to_return = result[TextEdit.SEARCH_RESULT_LINE]
return to_return return to_return

View file

@ -2,22 +2,22 @@ extends Control
@tool @tool
var _interface = null var _interface = null
var _utils = load('res://addons/gut/utils.gd').new() var _utils = load("res://addons/gut/utils.gd").new()
var _hide_passing = true var _hide_passing = true
var _font = null var _font = null
var _font_size = null var _font_size = null
var _root = null var _root = null
var _max_icon_width = 10 var _max_icon_width = 10
var _editors = null # script_text_editor_controls.gd var _editors = null # script_text_editor_controls.gd
var _show_orphans = true var _show_orphans = true
var _output_control = null var _output_control = null
const _col_1_bg_color = Color(0, 0, 0, .1) const _col_1_bg_color = Color(0, 0, 0, .1)
var _icons = { var _icons = {
red = load('res://addons/gut/images/red.png'), red = load("res://addons/gut/images/red.png"),
green = load('res://addons/gut/images/green.png'), green = load("res://addons/gut/images/green.png"),
yellow = load('res://addons/gut/images/yellow.png'), yellow = load("res://addons/gut/images/yellow.png"),
} }
signal search_for_text(text) signal search_for_text(text)
@ -26,7 +26,8 @@ signal search_for_text(text)
tree = $VBox/Output/Scroll/Tree, tree = $VBox/Output/Scroll/Tree,
lbl_overlay = $VBox/Output/OverlayMessage, lbl_overlay = $VBox/Output/OverlayMessage,
chk_hide_passing = $VBox/Toolbar/HidePassing, chk_hide_passing = $VBox/Toolbar/HidePassing,
toolbar = { toolbar =
{
toolbar = $VBox/Toolbar, toolbar = $VBox/Toolbar,
collapse = $VBox/Toolbar/Collapse, collapse = $VBox/Toolbar/Collapse,
collapse_all = $VBox/Toolbar/CollapseAll, collapse_all = $VBox/Toolbar/CollapseAll,
@ -38,31 +39,32 @@ signal search_for_text(text)
} }
} }
func _test_running_setup(): func _test_running_setup():
_hide_passing = true _hide_passing = true
_show_orphans = true _show_orphans = true
var _gut_config = load('res://addons/gut/gut_config.gd').new() var _gut_config = load("res://addons/gut/gut_config.gd").new()
_gut_config.load_panel_options('res://.gut_editor_config.json') _gut_config.load_panel_options("res://.gut_editor_config.json")
set_font( set_font(
_gut_config.options.panel_options.font_name, _gut_config.options.panel_options.font_name, _gut_config.options.panel_options.font_size
_gut_config.options.panel_options.font_size) )
_ctrls.toolbar.hide_passing.text = '[hp]' _ctrls.toolbar.hide_passing.text = "[hp]"
load_json_file('user://.gut_editor.json') load_json_file("user://.gut_editor.json")
func _set_toolbutton_icon(btn, icon_name, text): func _set_toolbutton_icon(btn, icon_name, text):
if(Engine.is_editor_hint()): if Engine.is_editor_hint():
btn.icon = get_theme_icon(icon_name, 'EditorIcons') btn.icon = get_theme_icon(icon_name, "EditorIcons")
else: else:
btn.text = str('[', text, ']') btn.text = str("[", text, "]")
func _ready(): func _ready():
var f = null var f = null
if ($FontSampler.get_label_settings() == null) : if $FontSampler.get_label_settings() == null:
f = get_theme_default_font() f = get_theme_default_font()
else : else:
f = $FontSampler.get_label_settings().font f = $FontSampler.get_label_settings().font
var s_size = f.get_string_size("000 of 000 passed") var s_size = f.get_string_size("000 of 000 passed")
_root = _ctrls.tree.create_item() _root = _ctrls.tree.create_item()
@ -72,37 +74,49 @@ func _ready():
_ctrls.tree.set_column_expand(1, false) _ctrls.tree.set_column_expand(1, false)
_ctrls.tree.set_column_custom_minimum_width(1, s_size.x) _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, "CollapseTree", "c")
_set_toolbutton_icon(_ctrls.toolbar.collapse_all, '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, "ExpandTree", "e")
_set_toolbutton_icon(_ctrls.toolbar.expand_all, '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.show_script, "Script", "ss")
_set_toolbutton_icon(_ctrls.toolbar.scroll_output, 'Font', 'so') _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')) _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): if get_parent() == get_tree().root:
_test_running_setup() _test_running_setup()
call_deferred('_update_min_width') call_deferred("_update_min_width")
func _update_min_width(): func _update_min_width():
custom_minimum_size.x = _ctrls.toolbar.toolbar.size.x custom_minimum_size.x = _ctrls.toolbar.toolbar.size.x
func _open_file(path, line_number): func _open_file(path, line_number):
if(_interface == null): if _interface == null:
print('Too soon, wait a bit and try again.') print("Too soon, wait a bit and try again.")
return return
var r = load(path) var r = load(path)
if(line_number != -1): if line_number != -1:
_interface.edit_script(r, line_number) _interface.edit_script(r, line_number)
else: else:
_interface.edit_script(r) _interface.edit_script(r)
if(_ctrls.toolbar.show_script.pressed): if _ctrls.toolbar.show_script.pressed:
_interface.set_main_screen_editor('Script') _interface.set_main_screen_editor("Script")
func _add_script_tree_item(script_path, script_json): func _add_script_tree_item(script_path, script_json):
@ -111,19 +125,20 @@ func _add_script_tree_item(script_path, script_json):
var item_text = script_path var item_text = script_path
var parent = _root var parent = _root
if(path_info.inner_class != ''): if path_info.inner_class != "":
parent = _find_script_item_with_path(path_info.path) parent = _find_script_item_with_path(path_info.path)
item_text = path_info.inner_class item_text = path_info.inner_class
if(parent == null): if parent == null:
parent = _add_script_tree_item(path_info.path, {}) parent = _add_script_tree_item(path_info.path, {})
var item = _ctrls.tree.create_item(parent) var item = _ctrls.tree.create_item(parent)
item.set_text(0, item_text) item.set_text(0, item_text)
var meta = { var meta = {
"type":"script", "type": "script",
"path":path_info.path, "path": path_info.path,
"inner_class":path_info.inner_class, "inner_class": path_info.inner_class,
"json":script_json} "json": script_json
}
item.set_metadata(0, meta) item.set_metadata(0, meta)
item.set_custom_bg_color(1, _col_1_bg_color) item.set_custom_bg_color(1, _col_1_bg_color)
@ -135,7 +150,7 @@ func _add_assert_item(text, icon, parent_item):
var assert_item = _ctrls.tree.create_item(parent_item) var assert_item = _ctrls.tree.create_item(parent_item)
assert_item.set_icon_max_width(0, _max_icon_width) assert_item.set_icon_max_width(0, _max_icon_width)
assert_item.set_text(0, text) assert_item.set_text(0, text)
assert_item.set_metadata(0, {"type":"assert"}) assert_item.set_metadata(0, {"type": "assert"})
assert_item.set_icon(0, icon) assert_item.set_icon(0, icon)
assert_item.set_custom_bg_color(1, _col_1_bg_color) assert_item.set_custom_bg_color(1, _col_1_bg_color)
@ -145,12 +160,12 @@ func _add_assert_item(text, icon, parent_item):
func _add_test_tree_item(test_name, test_json, script_item): func _add_test_tree_item(test_name, test_json, script_item):
# print(' * adding test ', test_name) # print(' * adding test ', test_name)
var no_orphans_to_show = !_show_orphans or (_show_orphans and test_json.orphans == 0) 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): if _hide_passing and test_json["status"] == "pass" and no_orphans_to_show:
return return
var item = _ctrls.tree.create_item(script_item) var item = _ctrls.tree.create_item(script_item)
var status = test_json['status'] var status = test_json["status"]
var meta = {"type":"test", "json":test_json} var meta = {"type": "test", "json": test_json}
item.set_text(0, test_name) item.set_text(0, test_name)
item.set_text(1, status) item.set_text(1, status)
@ -160,40 +175,39 @@ func _add_test_tree_item(test_name, test_json, script_item):
item.set_metadata(0, meta) item.set_metadata(0, meta)
item.set_icon_max_width(0, _max_icon_width) item.set_icon_max_width(0, _max_icon_width)
var orphan_text = 'orphans' var orphan_text = "orphans"
if(test_json.orphans == 1): if test_json.orphans == 1:
orphan_text = 'orphan' orphan_text = "orphan"
orphan_text = str(test_json.orphans, ' ', orphan_text) orphan_text = str(test_json.orphans, " ", orphan_text)
if status == "pass" and no_orphans_to_show:
if(status == 'pass' and no_orphans_to_show):
item.set_icon(0, _icons.green) item.set_icon(0, _icons.green)
elif(status == 'pass' and !no_orphans_to_show): elif status == "pass" and !no_orphans_to_show:
item.set_icon(0, _icons.yellow) item.set_icon(0, _icons.yellow)
item.set_text(1, orphan_text) item.set_text(1, orphan_text)
elif(status == 'fail'): elif status == "fail":
item.set_icon(0, _icons.red) item.set_icon(0, _icons.red)
else: else:
item.set_icon(0, _icons.yellow) item.set_icon(0, _icons.yellow)
if(!_hide_passing): if !_hide_passing:
for passing in test_json.passing: for passing in test_json.passing:
_add_assert_item('pass: ' + passing, _icons.green, item) _add_assert_item("pass: " + passing, _icons.green, item)
for failure in test_json.failing: for failure in test_json.failing:
_add_assert_item("fail: " + failure.replace("\n", ''), _icons.red, item) _add_assert_item("fail: " + failure.replace("\n", ""), _icons.red, item)
for pending in test_json.pending: for pending in test_json.pending:
_add_assert_item("pending: " + pending.replace("\n", ''), _icons.yellow, item) _add_assert_item("pending: " + pending.replace("\n", ""), _icons.yellow, item)
if(status != 'pass' and !no_orphans_to_show): if status != "pass" and !no_orphans_to_show:
_add_assert_item(orphan_text, _icons.yellow, item) _add_assert_item(orphan_text, _icons.yellow, item)
return item return item
func _load_result_tree(j): func _load_result_tree(j):
var scripts = j['test_scripts']['scripts'] var scripts = j["test_scripts"]["scripts"]
var script_keys = scripts.keys() var script_keys = scripts.keys()
# if we made it here, the json is valid and we did something, otherwise the # if we made it here, the json is valid and we did something, otherwise the
# 'nothing to see here' should be visible. # 'nothing to see here' should be visible.
@ -201,30 +215,30 @@ func _load_result_tree(j):
var _last_script_item = null var _last_script_item = null
for key in script_keys: for key in script_keys:
var tests = scripts[key]['tests'] var tests = scripts[key]["tests"]
var test_keys = tests.keys() var test_keys = tests.keys()
var s_item = _add_script_tree_item(key, scripts[key]) var s_item = _add_script_tree_item(key, scripts[key])
var bad_count = 0 var bad_count = 0
for test_key in test_keys: for test_key in test_keys:
var t_item = _add_test_tree_item(test_key, tests[test_key], s_item) var t_item = _add_test_tree_item(test_key, tests[test_key], s_item)
if(tests[test_key].status != 'pass'): if tests[test_key].status != "pass":
bad_count += 1 bad_count += 1
elif(t_item != null): elif t_item != null:
t_item.collapsed = true t_item.collapsed = true
# get_children returns the first child or null. its a dumb name. # get_children returns the first child or null. its a dumb name.
if(s_item.get_children() == null): if s_item.get_children() == null:
# var m = s_item.get_metadata(0) # var m = s_item.get_metadata(0)
# print('!! Deleting ', m.path, ' ', m.inner_class) # print('!! Deleting ', m.path, ' ', m.inner_class)
s_item.free() s_item.free()
else: else:
var total_text = str(test_keys.size(), ' passed') var total_text = str(test_keys.size(), " passed")
# s_item.set_text_alignment(1, s_item.ALIGN_LEFT) # s_item.set_text_alignment(1, s_item.ALIGN_LEFT)
if(bad_count == 0): if bad_count == 0:
s_item.collapsed = true s_item.collapsed = true
else: else:
total_text = str(test_keys.size() - bad_count, ' of ', test_keys.size(), ' passed') total_text = str(test_keys.size() - bad_count, " of ", test_keys.size(), " passed")
s_item.set_text(1, total_text) s_item.set_text(1, total_text)
_free_childless_scripts() _free_childless_scripts()
@ -235,7 +249,7 @@ func _free_childless_scripts():
var items = _root.get_children() var items = _root.get_children()
for item in items: for item in items:
var next_item = item.get_next() var next_item = item.get_next()
if(item.get_children() == null): if item.get_children() == null:
item.free() item.free()
item = next_item item = next_item
@ -245,9 +259,9 @@ func _find_script_item_with_path(path):
var to_return = null var to_return = null
var idx = 0 var idx = 0
while(idx < items.size() and to_return == null): while idx < items.size() and to_return == null:
var item = items[idx] var item = items[idx]
if(item.get_metadata(0).path == path): if item.get_metadata(0).path == path:
to_return = item to_return = item
else: else:
idx += 1 idx += 1
@ -257,21 +271,18 @@ func _find_script_item_with_path(path):
func _get_line_number_from_assert_msg(msg): func _get_line_number_from_assert_msg(msg):
var line = -1 var line = -1
if(msg.find('at line') > 0): if msg.find("at line") > 0:
line = msg.split("at line")[-1].split(" ")[-1].to_int() line = msg.split("at line")[-1].split(" ")[-1].to_int()
return line return line
func _get_path_and_inner_class_name_from_test_path(path): func _get_path_and_inner_class_name_from_test_path(path):
var to_return = { var to_return = {path = "", inner_class = ""}
path = '',
inner_class = ''
}
to_return.path = path to_return.path = path
if !path.ends_with('.gd'): if !path.ends_with(".gd"):
var loc = path.find('.gd') var loc = path.find(".gd")
to_return.inner_class = path.split('.')[-1] to_return.inner_class = path.split(".")[-1]
to_return.path = path.substr(0, loc + 3) to_return.path = path.substr(0, loc + 3)
return to_return return to_return
@ -279,37 +290,37 @@ func _get_path_and_inner_class_name_from_test_path(path):
func _handle_tree_item_select(item, force_scroll): func _handle_tree_item_select(item, force_scroll):
var item_type = item.get_metadata(0).type var item_type = item.get_metadata(0).type
var path = ''; var path = ""
var line = -1; var line = -1
var method_name = '' var method_name = ""
var inner_class = '' var inner_class = ""
if(item_type == 'test'): if item_type == "test":
var s_item = item.get_parent() var s_item = item.get_parent()
path = s_item.get_metadata(0)['path'] path = s_item.get_metadata(0)["path"]
inner_class = s_item.get_metadata(0)['inner_class'] inner_class = s_item.get_metadata(0)["inner_class"]
line = -1 line = -1
method_name = item.get_text(0) method_name = item.get_text(0)
elif(item_type == 'assert'): elif item_type == "assert":
var s_item = item.get_parent().get_parent() var s_item = item.get_parent().get_parent()
path = s_item.get_metadata(0)['path'] path = s_item.get_metadata(0)["path"]
inner_class = s_item.get_metadata(0)['inner_class'] inner_class = s_item.get_metadata(0)["inner_class"]
line = _get_line_number_from_assert_msg(item.get_text(0)) line = _get_line_number_from_assert_msg(item.get_text(0))
method_name = item.get_parent().get_text(0) method_name = item.get_parent().get_text(0)
elif(item_type == 'script'): elif item_type == "script":
path = item.get_metadata(0)['path'] path = item.get_metadata(0)["path"]
if(item.get_parent() != _root): if item.get_parent() != _root:
inner_class = item.get_text(0) inner_class = item.get_text(0)
line = -1 line = -1
method_name = '' method_name = ""
else: else:
return return
var path_info = _get_path_and_inner_class_name_from_test_path(path) var path_info = _get_path_and_inner_class_name_from_test_path(path)
if(force_scroll or _ctrls.toolbar.show_script.pressed): if force_scroll or _ctrls.toolbar.show_script.pressed:
_goto_code(path, line, method_name, inner_class) _goto_code(path, line, method_name, inner_class)
if(force_scroll or _ctrls.toolbar.scroll_output.pressed): if force_scroll or _ctrls.toolbar.scroll_output.pressed:
_goto_output(path, method_name, inner_class) _goto_output(path, method_name, inner_class)
@ -327,9 +338,9 @@ func _get_line_number_for_seq_search(search_strings, te):
var i = 0 var i = 0
var string_found = true var string_found = true
while(i < search_strings.size() and string_found): while i < search_strings.size() and string_found:
result = te.search(search_strings[i], s_flags, line.y, line.x) result = te.search(search_strings[i], s_flags, line.y, line.x)
if(result.x != -1): if result.x != -1:
line = result line = result
else: else:
string_found = false string_found = false
@ -338,55 +349,56 @@ func _get_line_number_for_seq_search(search_strings, te):
return line.y return line.y
func _goto_code(path, line, method_name='', inner_class =''): func _goto_code(path, line, method_name = "", inner_class = ""):
if(_interface == null): if _interface == null:
print('going to ', [path, line, method_name, inner_class]) print("going to ", [path, line, method_name, inner_class])
return return
_open_file(path, line) _open_file(path, line)
if(line == -1): if line == -1:
var search_strings = [] var search_strings = []
if(inner_class != ''): if inner_class != "":
search_strings.append(inner_class) search_strings.append(inner_class)
if(method_name != ''): if method_name != "":
search_strings.append(method_name) search_strings.append(method_name)
line = _get_line_number_for_seq_search(search_strings, _editors.get_current_text_edit()) line = _get_line_number_for_seq_search(search_strings, _editors.get_current_text_edit())
if(line != -1): if line != -1:
_interface.get_script_editor().goto_line(line) _interface.get_script_editor().goto_line(line)
func _goto_output(path, method_name, inner_class): func _goto_output(path, method_name, inner_class):
if(_output_control == null): if _output_control == null:
return return
var search_strings = [path] var search_strings = [path]
if(inner_class != ''): if inner_class != "":
search_strings.append(inner_class) search_strings.append(inner_class)
if(method_name != ''): if method_name != "":
search_strings.append(method_name) search_strings.append(method_name)
var line = _get_line_number_for_seq_search(search_strings, _output_control.get_rich_text_edit()) var line = _get_line_number_for_seq_search(search_strings, _output_control.get_rich_text_edit())
if(line != -1): if line != -1:
_output_control.scroll_to_line(line) _output_control.scroll_to_line(line)
func _show_all_passed(): func _show_all_passed():
if(_root.get_children() == null): if _root.get_children() == null:
add_centered_text('Everything passed!') add_centered_text("Everything passed!")
func _set_collapsed_on_all(item, value): func _set_collapsed_on_all(item, value):
if(item == _root): if item == _root:
var node = _root.get_children() var node = _root.get_children()
while(node != null): while node != null:
node.call_recursive('set_collapsed', value) node.call_recursive("set_collapsed", value)
node = node.get_next() node = node.get_next()
else: else:
item.call_recursive('set_collapsed', value) item.call_recursive("set_collapsed", value)
# -------------- # --------------
# Events # Events
@ -396,16 +408,17 @@ func _on_Tree_item_selected():
var item = _ctrls.tree.get_selected() var item = _ctrls.tree.get_selected()
_handle_tree_item_select(item, false) _handle_tree_item_select(item, false)
# it just looks better if the left is always selected. # it just looks better if the left is always selected.
if(item.is_selected(1)): if item.is_selected(1):
item.deselect(1) item.deselect(1)
item.select(0) item.select(0)
func _on_Tree_item_activated(): func _on_Tree_item_activated():
# force scroll # force scroll
print('double clicked') print("double clicked")
_handle_tree_item_select(_ctrls.tree.get_selected(), true) _handle_tree_item_select(_ctrls.tree.get_selected(), true)
func _on_Collapse_pressed(): func _on_Collapse_pressed():
collapse_selected() collapse_selected()
@ -425,29 +438,39 @@ func _on_ExpandAll_pressed():
func _on_Hide_Passing_pressed(): func _on_Hide_Passing_pressed():
_hide_passing = _ctrls.toolbar.hide_passing.button_pressed _hide_passing = _ctrls.toolbar.hide_passing.button_pressed
# -------------- # --------------
# Public # Public
# -------------- # --------------
func load_json_file(path): func load_json_file(path):
var text = _utils.get_file_as_text(path) var text = _utils.get_file_as_text(path)
if(text != ''): if text != "":
var test_json_conv = JSON.new() var test_json_conv = JSON.new()
test_json_conv.parse(text) test_json_conv.parse(text)
var result = test_json_conv.get_data() var result = test_json_conv.get_data()
if(result.error != OK): if result.error != OK:
add_centered_text(str(path, " has invalid json in it \n", add_centered_text(
'Error ', result.error, "@", result.error_line, "\n", str(
result.error_string)) path,
" has invalid json in it \n",
"Error ",
result.error,
"@",
result.error_line,
"\n",
result.error_string
)
)
return return
load_json_results(result.result) load_json_results(result.result)
else: else:
add_centered_text(str(path, ' was empty or does not exist.')) add_centered_text(str(path, " was empty or does not exist."))
func load_json_results(j): func load_json_results(j):
clear() clear()
add_centered_text('Nothing Here') add_centered_text("Nothing Here")
_load_result_tree(j) _load_result_tree(j)
@ -456,7 +479,7 @@ func add_centered_text(t):
func clear_centered_text(): func clear_centered_text():
_ctrls.lbl_overlay.text = '' _ctrls.lbl_overlay.text = ""
func clear(): func clear():
@ -483,12 +506,13 @@ func expand_all():
func collapse_selected(): func collapse_selected():
var item = _ctrls.tree.get_selected() var item = _ctrls.tree.get_selected()
if(item != null): if item != null:
_set_collapsed_on_all(item, true) _set_collapsed_on_all(item, true)
func expand_selected(): func expand_selected():
var item = _ctrls.tree.get_selected() var item = _ctrls.tree.get_selected()
if(item != null): if item != null:
_set_collapsed_on_all(item, false) _set_collapsed_on_all(item, false)
@ -498,6 +522,8 @@ func set_show_orphans(should):
func set_font(font_name, size): func set_font(font_name, size):
pass pass
# var dyn_font = FontFile.new() # var dyn_font = FontFile.new()
# var font_data = FontFile.new() # var font_data = FontFile.new()
# font_data.font_path = 'res://addons/gut/fonts/' + font_name + '-Regular.ttf' # font_data.font_path = 'res://addons/gut/fonts/' + font_name + '-Regular.ttf'

View file

@ -1,7 +1,6 @@
@tool @tool
extends Control extends Control
@onready var _ctrls = { @onready var _ctrls = {
shortcut_label = $Layout/lblShortcut, shortcut_label = $Layout/lblShortcut,
set_button = $Layout/SetButton, set_button = $Layout/SetButton,
@ -14,7 +13,7 @@ signal changed
signal start_edit signal start_edit
signal end_edit signal end_edit
const NO_SHORTCUT = '<None>' const NO_SHORTCUT = "<None>"
var _source_event = InputEventKey.new() var _source_event = InputEventKey.new()
var _pre_edit_event = null var _pre_edit_event = null
@ -22,28 +21,39 @@ var _key_disp = NO_SHORTCUT
var _modifier_keys = [KEY_ALT, KEY_CTRL, KEY_META, KEY_SHIFT] var _modifier_keys = [KEY_ALT, KEY_CTRL, KEY_META, KEY_SHIFT]
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready(): func _ready():
set_process_unhandled_key_input(false) set_process_unhandled_key_input(false)
func _display_shortcut(): func _display_shortcut():
if(_key_disp == ''): if _key_disp == "":
_key_disp = NO_SHORTCUT _key_disp = NO_SHORTCUT
_ctrls.shortcut_label.text = _key_disp _ctrls.shortcut_label.text = _key_disp
func _is_shift_only_modifier(): func _is_shift_only_modifier():
return _source_event.shift_pressed and \ return (
!(_source_event.alt_pressed or _source_event.command_pressed or \ _source_event.shift_pressed
_source_event.ctrl_pressed or _source_event.meta_pressed) and \ and !(
!_is_modifier(_source_event.keycode) _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): func _has_modifier(event):
return event.alt_pressed or event.command_pressed or \ return (
event.ctrl_pressed or event.meta_pressed or \ event.alt_pressed
event.shift_pressed or event.command_pressed
or event.ctrl_pressed
or event.meta_pressed
or event.shift_pressed
)
func _is_modifier(keycode): func _is_modifier(keycode):
@ -58,23 +68,24 @@ func _edit_mode(should):
_ctrls.cancel_button.visible = should _ctrls.cancel_button.visible = should
_ctrls.clear_button.visible = !should _ctrls.clear_button.visible = !should
if(should and to_s() == ''): if should and to_s() == "":
_ctrls.shortcut_label.text = 'press buttons' _ctrls.shortcut_label.text = "press buttons"
else: else:
_ctrls.shortcut_label.text = to_s() _ctrls.shortcut_label.text = to_s()
if(should): if should:
emit_signal("start_edit") emit_signal("start_edit")
else: else:
emit_signal("end_edit") emit_signal("end_edit")
# --------------- # ---------------
# Events # Events
# --------------- # ---------------
func _unhandled_key_input(event): func _unhandled_key_input(event):
if(event is InputEventKey): if event is InputEventKey:
if(event.pressed): if event.pressed:
if(_has_modifier(event) and !_is_modifier(event.get_keycode_with_modifiers())): if _has_modifier(event) and !_is_modifier(event.get_keycode_with_modifiers()):
_source_event = event _source_event = event
_key_disp = OS.get_keycode_string(event.get_keycode_with_modifiers()) _key_disp = OS.get_keycode_string(event.get_keycode_with_modifiers())
else: else:
@ -92,7 +103,7 @@ func _on_SetButton_pressed():
func _on_SaveButton_pressed(): func _on_SaveButton_pressed():
_edit_mode(false) _edit_mode(false)
_pre_edit_event = null _pre_edit_event = null
emit_signal('changed') emit_signal("changed")
func _on_CancelButton_pressed(): func _on_CancelButton_pressed():
@ -105,6 +116,7 @@ func _on_CancelButton_pressed():
func _on_ClearButton_pressed(): func _on_ClearButton_pressed():
clear_shortcut() clear_shortcut()
# --------------- # ---------------
# Public # Public
# --------------- # ---------------
@ -123,7 +135,7 @@ func get_shortcut():
func set_shortcut(sc): func set_shortcut(sc):
if(sc == null or sc.events == null || sc.events.size() <= 0): if sc == null or sc.events == null || sc.events.size() <= 0:
clear_shortcut() clear_shortcut()
else: else:
_source_event = sc.events[0] _source_event = sc.events[0]
@ -140,5 +152,6 @@ func clear_shortcut():
func disable_set(should): func disable_set(should):
_ctrls.set_button.disabled = should _ctrls.set_button.disabled = should
func disable_clear(should): func disable_clear(should):
_ctrls.clear_button.disabled = should _ctrls.clear_button.disabled = should

View file

@ -3,7 +3,7 @@
class DirectoryCtrl: class DirectoryCtrl:
extends HBoxContainer extends HBoxContainer
var text = '': var text = "":
get: get:
return _txt_path.text return _txt_path.text
set(val): set(val):
@ -14,35 +14,33 @@ class DirectoryCtrl:
var _dialog = FileDialog.new() var _dialog = FileDialog.new()
func _init(): func _init():
_btn_dir.text = '...' _btn_dir.text = "..."
_btn_dir.connect('pressed',Callable(self,'_on_dir_button_pressed')) _btn_dir.connect("pressed", Callable(self, "_on_dir_button_pressed"))
_txt_path.size_flags_horizontal = _txt_path.SIZE_EXPAND_FILL _txt_path.size_flags_horizontal = _txt_path.SIZE_EXPAND_FILL
_dialog.mode = _dialog.FILE_MODE_OPEN_DIR _dialog.mode = _dialog.FILE_MODE_OPEN_DIR
_dialog.unresizable = false _dialog.unresizable = false
_dialog.connect("dir_selected",Callable(self,'_on_selected')) _dialog.connect("dir_selected", Callable(self, "_on_selected"))
_dialog.connect("file_selected",Callable(self,'_on_selected')) _dialog.connect("file_selected", Callable(self, "_on_selected"))
_dialog.size = Vector2(1000, 700) _dialog.size = Vector2(1000, 700)
func _on_selected(path): func _on_selected(path):
text = path text = path
func _on_dir_button_pressed(): func _on_dir_button_pressed():
_dialog.current_dir = _txt_path.text _dialog.current_dir = _txt_path.text
_dialog.popup_centered() _dialog.popup_centered()
func _ready(): func _ready():
add_child(_txt_path) add_child(_txt_path)
add_child(_btn_dir) add_child(_btn_dir)
add_child(_dialog) add_child(_dialog)
func get_line_edit(): func get_line_edit():
return _txt_path return _txt_path
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class FileCtrl: class FileCtrl:
@ -51,17 +49,18 @@ class FileCtrl:
func _init(): func _init():
_dialog.mode = _dialog.FILE_MODE_OPEN_FILE _dialog.mode = _dialog.FILE_MODE_OPEN_FILE
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class Vector2Ctrl: class Vector2Ctrl:
extends VBoxContainer extends VBoxContainer
var value = Vector2(-1, -1) : var value = Vector2(-1, -1):
get: get:
return get_value() return get_value()
set(val): set(val):
set_value(val) set_value(val)
var disabled = false : var disabled = false:
get: get:
return get_disabled() return get_disabled()
set(val): set(val):
@ -70,8 +69,8 @@ class Vector2Ctrl:
var y_spin = SpinBox.new() var y_spin = SpinBox.new()
func _init(): func _init():
add_child(_make_one('x: ', x_spin)) add_child(_make_one("x: ", x_spin))
add_child(_make_one('y: ', y_spin)) add_child(_make_one("y: ", y_spin))
func _make_one(txt, spinner): func _make_one(txt, spinner):
var hbox = HBoxContainer.new() var hbox = HBoxContainer.new()
@ -85,7 +84,7 @@ class Vector2Ctrl:
return hbox return hbox
func set_value(v): func set_value(v):
if(v != null): if v != null:
x_spin.value = v[0] x_spin.value = v[0]
y_spin.value = v[1] y_spin.value = v[1]
@ -103,14 +102,13 @@ class Vector2Ctrl:
pass pass
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
var _base_container = null var _base_container = null
var _base_control = null var _base_control = null
const DIRS_TO_LIST = 6 const DIRS_TO_LIST = 6
var _cfg_ctrls = {} var _cfg_ctrls = {}
var _avail_fonts = ['AnonymousPro', 'CourierPrime', 'LobsterTwo', 'Default'] var _avail_fonts = ["AnonymousPro", "CourierPrime", "LobsterTwo", "Default"]
func _init(cont): func _init(cont):
@ -158,10 +156,10 @@ func _add_title(text):
# lbl.align = Label.ALIGNMENT_CENTER # lbl.align = Label.ALIGNMENT_CENTER
_base_container.add_child(row) _base_container.add_child(row)
row.connect('draw', _on_title_cell_draw.bind(row)) row.connect("draw", _on_title_cell_draw.bind(row))
func _add_number(key, value, disp_text, v_min, v_max, hint=''): func _add_number(key, value, disp_text, v_min, v_max, hint = ""):
var value_ctrl = SpinBox.new() var value_ctrl = SpinBox.new()
value_ctrl.value = value value_ctrl.value = value
value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL
@ -172,12 +170,12 @@ func _add_number(key, value, disp_text, v_min, v_max, hint=''):
_new_row(key, disp_text, value_ctrl, hint) _new_row(key, disp_text, value_ctrl, hint)
func _add_select(key, value, values, disp_text, hint=''): func _add_select(key, value, values, disp_text, hint = ""):
var value_ctrl = OptionButton.new() var value_ctrl = OptionButton.new()
var select_idx = 0 var select_idx = 0
for i in range(values.size()): for i in range(values.size()):
value_ctrl.add_item(values[i]) value_ctrl.add_item(values[i])
if(value == values[i]): if value == values[i]:
select_idx = i select_idx = i
value_ctrl.selected = select_idx value_ctrl.selected = select_idx
value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL
@ -185,7 +183,7 @@ func _add_select(key, value, values, disp_text, hint=''):
_new_row(key, disp_text, value_ctrl, hint) _new_row(key, disp_text, value_ctrl, hint)
func _add_value(key, value, disp_text, hint=''): func _add_value(key, value, disp_text, hint = ""):
var value_ctrl = LineEdit.new() var value_ctrl = LineEdit.new()
value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL
value_ctrl.text = value value_ctrl.text = value
@ -194,14 +192,14 @@ func _add_value(key, value, disp_text, hint=''):
_new_row(key, disp_text, value_ctrl, hint) _new_row(key, disp_text, value_ctrl, hint)
func _add_boolean(key, value, disp_text, hint=''): func _add_boolean(key, value, disp_text, hint = ""):
var value_ctrl = CheckBox.new() var value_ctrl = CheckBox.new()
value_ctrl.button_pressed = value value_ctrl.button_pressed = value
_new_row(key, disp_text, value_ctrl, hint) _new_row(key, disp_text, value_ctrl, hint)
func _add_directory(key, value, disp_text, hint=''): func _add_directory(key, value, disp_text, hint = ""):
var value_ctrl = DirectoryCtrl.new() var value_ctrl = DirectoryCtrl.new()
value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL
value_ctrl.text = value value_ctrl.text = value
@ -210,7 +208,7 @@ func _add_directory(key, value, disp_text, hint=''):
_new_row(key, disp_text, value_ctrl, hint) _new_row(key, disp_text, value_ctrl, hint)
func _add_file(key, value, disp_text, hint=''): func _add_file(key, value, disp_text, hint = ""):
var value_ctrl = FileCtrl.new() var value_ctrl = FileCtrl.new()
value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL
value_ctrl.text = value value_ctrl.text = value
@ -219,7 +217,7 @@ func _add_file(key, value, disp_text, hint=''):
_new_row(key, disp_text, value_ctrl, hint) _new_row(key, disp_text, value_ctrl, hint)
func _add_color(key, value, disp_text, hint=''): func _add_color(key, value, disp_text, hint = ""):
var value_ctrl = ColorPickerButton.new() var value_ctrl = ColorPickerButton.new()
value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL
value_ctrl.color = value value_ctrl.color = value
@ -227,7 +225,7 @@ func _add_color(key, value, disp_text, hint=''):
_new_row(key, disp_text, value_ctrl, hint) _new_row(key, disp_text, value_ctrl, hint)
func _add_vector2(key, value, disp_text, hint=''): func _add_vector2(key, value, disp_text, hint = ""):
var value_ctrl = Vector2Ctrl.new() var value_ctrl = Vector2Ctrl.new()
value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL
value_ctrl.value = value value_ctrl.value = value
@ -235,6 +233,8 @@ func _add_vector2(key, value, disp_text, hint=''):
_wire_select_on_focus(value_ctrl.y_spin.get_line_edit()) _wire_select_on_focus(value_ctrl.y_spin.get_line_edit())
_new_row(key, disp_text, value_ctrl, hint) _new_row(key, disp_text, value_ctrl, hint)
# ----------------------------- # -----------------------------
@ -243,17 +243,17 @@ func _add_vector2(key, value, disp_text, hint=''):
# ------------------ # ------------------
func _wire_select_on_focus(which): func _wire_select_on_focus(which):
pass pass
which.connect('focus_entered', _on_ctrl_focus_highlight.bind(which)) which.connect("focus_entered", _on_ctrl_focus_highlight.bind(which))
which.connect('focus_exited', _on_ctrl_focus_unhighlight.bind(which)) which.connect("focus_exited", _on_ctrl_focus_unhighlight.bind(which))
func _on_ctrl_focus_highlight(which): func _on_ctrl_focus_highlight(which):
if(which.has_method('select_all')): if which.has_method("select_all"):
which.call_deferred('select_all') which.call_deferred("select_all")
func _on_ctrl_focus_unhighlight(which): func _on_ctrl_focus_unhighlight(which):
if(which.has_method('select')): if which.has_method("select"):
which.select(0, 0) which.select(0, 0)
@ -269,17 +269,17 @@ func get_config_issues():
var has_directory = false var has_directory = false
for i in range(DIRS_TO_LIST): for i in range(DIRS_TO_LIST):
var key = str('directory_', i) var key = str("directory_", i)
var path = _cfg_ctrls[key].text var path = _cfg_ctrls[key].text
if(path != null and path != ''): if path != null and path != "":
has_directory = true has_directory = true
if(!DirAccess.dir_exists(path)): if !DirAccess.dir_exists(path):
to_return.append(str('Test directory ', path, ' does not exist.')) to_return.append(str("Test directory ", path, " does not exist."))
if(!has_directory): if !has_directory:
to_return.append('You do not have any directories set.') to_return.append("You do not have any directories set.")
if(!_cfg_ctrls['suffix'].text.ends_with('.gd')): if !_cfg_ctrls["suffix"].text.ends_with(".gd"):
to_return.append("Script suffix must end in '.gd'") to_return.append("Script suffix must end in '.gd'")
return to_return return to_return
@ -287,90 +287,186 @@ func get_config_issues():
func set_options(options): func set_options(options):
_add_title("Settings") _add_title("Settings")
_add_number("log_level", options.log_level, "Log Level", 0, 3, _add_number(
"Detail level for log messages.\n" + \ "log_level",
"\t0: Errors and failures only.\n" + \ options.log_level,
"\t1: Adds all test names + warnings + info\n" + \ "Log Level",
"\t2: Shows all asserts\n" + \ 0,
"\t3: Adds more stuff probably, maybe not.") 3,
_add_boolean('ignore_pause', options.ignore_pause, 'Ignore Pause', (
"Ignore calls to pause_before_teardown") "Detail level for log messages.\n"
_add_boolean('hide_orphans', options.hide_orphans, 'Hide Orphans', + "\t0: Errors and failures only.\n"
'Do not display orphan counts in output.') + "\t1: Adds all test names + warnings + info\n"
_add_boolean('should_exit', options.should_exit, 'Exit on Finish', + "\t2: Shows all asserts\n"
"Exit when tests finished.") + "\t3: Adds more stuff probably, maybe not."
_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_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_title("Panel Output")
_add_select('output_font_name', options.panel_options.font_name, _avail_fonts, 'Font', _add_select(
"The name of the font to use when running tests and in the output panel to the left.") "output_font_name",
_add_number('output_font_size', options.panel_options.font_size, 'Font Size', 5, 100, options.panel_options.font_name,
"The font size to use when running tests and in the output panel to the left.") _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 Window') _add_title("Runner Appearance")
_add_boolean("gut_on_top", options.gut_on_top, "On Top", _add_select(
"The GUT Runner appears above children added during tests.") "font_name",
_add_number('opacity', options.opacity, 'Opacity', 0, 100, options.font_name,
"The opacity of GUT when tests are running.") _avail_fonts,
_add_boolean('should_maximize', options.should_maximize, 'Maximize', "Font",
"Maximize GUT when tests are being run.") "The font to use for text output in the Gut Runner."
_add_boolean('compact_mode', options.compact_mode, 'Compact Mode', )
'The runner will be in compact mode. This overrides Maximize.') _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('Runner Appearance') _add_title("Test Directories")
_add_select('font_name', options.font_name, _avail_fonts, 'Font', _add_boolean(
"The font to use for text output in the Gut Runner.") "include_subdirs",
_add_number('font_size', options.font_size, 'Font Size', 5, 100, options.include_subdirs,
"The font size for text output in the Gut Runner.") "Include Subdirs",
_add_color('font_color', options.font_color, 'Font Color', "Include subdirectories of the directories configured below."
"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): for i in range(DIRS_TO_LIST):
var value = '' var value = ""
if(options.dirs.size() > i): if options.dirs.size() > i:
value = options.dirs[i] value = options.dirs[i]
_add_directory(str('directory_', i), value, str('Directory ', i)) _add_directory(str("directory_", i), value, str("Directory ", i))
_add_title("XML Output") _add_title("XML Output")
_add_value("junit_xml_file", options.junit_xml_file, "Output Path3D", _add_value(
"Path3D and filename where GUT should create a JUnit compliant XML file. " + "junit_xml_file",
"This file will contain the results of the last test run. To avoid " + options.junit_xml_file,
"overriding the file use Include Timestamp.") "Output Path3D",
_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.") "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('Hooks') _add_title("Misc")
_add_file('pre_run_script', options.pre_run_script, 'Pre-Run Hook', _add_value(
'This script will be run by GUT before any tests are run.') "prefix", options.prefix, "Script Prefix", "The filename prefix for all test scripts."
_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_value(
"suffix",
options.suffix,
_add_title('Misc') "Script Suffix",
_add_value('prefix', options.prefix, 'Script Prefix', "Script suffix, including .gd extension. For example '_foo.gd'."
"The filename prefix for all test scripts.") )
_add_value('suffix', options.suffix, 'Script Suffix', _add_number(
"Script suffix, including .gd extension. For example '_foo.gd'.") "paint_after",
_add_number('paint_after', options.paint_after, 'Paint After', 0.0, 1.0, options.paint_after,
"How long GUT will wait before pausing for 1 frame to paint the screen. 0 is never.") "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 # 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. # 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.step = .05
_cfg_ctrls.paint_after.value = options.paint_after _cfg_ctrls.paint_after.value = options.paint_after
print('paint after = ', options.paint_after) print("paint after = ", options.paint_after)
func get_options(base_opts): func get_options(base_opts):
var to_return = base_opts.duplicate() var to_return = base_opts.duplicate()
@ -383,13 +479,13 @@ func get_options(base_opts):
to_return.should_exit_on_success = _cfg_ctrls.should_exit_on_success.button_pressed to_return.should_exit_on_success = _cfg_ctrls.should_exit_on_success.button_pressed
#Output #Output
to_return.panel_options.font_name = _cfg_ctrls.output_font_name.get_item_text( to_return.panel_options.font_name = (
_cfg_ctrls.output_font_name.selected) _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 to_return.panel_options.font_size = _cfg_ctrls.output_font_size.value
# Runner Appearance # Runner Appearance
to_return.font_name = _cfg_ctrls.font_name.get_item_text( to_return.font_name = _cfg_ctrls.font_name.get_item_text(_cfg_ctrls.font_name.selected)
_cfg_ctrls.font_name.selected)
to_return.font_size = _cfg_ctrls.font_size.value to_return.font_size = _cfg_ctrls.font_size.value
to_return.should_maximize = _cfg_ctrls.should_maximize.button_pressed to_return.should_maximize = _cfg_ctrls.should_maximize.button_pressed
to_return.compact_mode = _cfg_ctrls.compact_mode.button_pressed to_return.compact_mode = _cfg_ctrls.compact_mode.button_pressed
@ -400,14 +496,13 @@ func get_options(base_opts):
to_return.gut_on_top = _cfg_ctrls.gut_on_top.button_pressed to_return.gut_on_top = _cfg_ctrls.gut_on_top.button_pressed
to_return.paint_after = _cfg_ctrls.paint_after.value to_return.paint_after = _cfg_ctrls.paint_after.value
# Directories # Directories
to_return.include_subdirs = _cfg_ctrls.include_subdirs.button_pressed to_return.include_subdirs = _cfg_ctrls.include_subdirs.button_pressed
var dirs = [] var dirs = []
for i in range(DIRS_TO_LIST): for i in range(DIRS_TO_LIST):
var key = str('directory_', i) var key = str("directory_", i)
var val = _cfg_ctrls[key].text var val = _cfg_ctrls[key].text
if(val != '' and val != null): if val != "" and val != null:
dirs.append(val) dirs.append(val)
to_return.dirs = dirs to_return.dirs = dirs

View file

@ -11,57 +11,52 @@ class ScriptEditorControlRef:
_script_editor = weakref(script_edit) _script_editor = weakref(script_edit)
_populate_controls() _populate_controls()
func _populate_controls(): func _populate_controls():
# who knows if the tree will change so get the first instance of each # 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 # 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. # 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())) _code_editor = weakref(_get_first_child_named("CodeTextEditor", _script_editor.get_ref()))
_text_edit = weakref(_get_first_child_named("CodeEdit", _code_editor.get_ref())) _text_edit = weakref(_get_first_child_named("CodeEdit", _code_editor.get_ref()))
func _get_first_child_named(obj_name, parent_obj): func _get_first_child_named(obj_name, parent_obj):
if(parent_obj == null): if parent_obj == null:
return null return null
var kids = parent_obj.get_children() var kids = parent_obj.get_children()
var index = 0 var index = 0
var to_return = null var to_return = null
while(index < kids.size() and to_return == null): while index < kids.size() and to_return == null:
if(str(kids[index]).find(str("[", obj_name)) != -1): if str(kids[index]).find(str("[", obj_name)) != -1:
to_return = kids[index] to_return = kids[index]
else: else:
to_return = _get_first_child_named(obj_name, kids[index]) to_return = _get_first_child_named(obj_name, kids[index])
if(to_return == null): if to_return == null:
index += 1 index += 1
return to_return return to_return
func get_script_text_edit(): func get_script_text_edit():
return _script_editor.get_ref() return _script_editor.get_ref()
func get_text_edit(): func get_text_edit():
# ScriptTextEditors that are loaded when the project is opened # ScriptTextEditors that are loaded when the project is opened
# do not have their children populated yet. So if we may have to # do not have their children populated yet. So if we may have to
# _populate_controls again if we don't have one. # _populate_controls again if we don't have one.
if(_text_edit == null): if _text_edit == null:
_populate_controls() _populate_controls()
return _text_edit.get_ref() return _text_edit.get_ref()
func get_script_editor(): func get_script_editor():
return _script_editor return _script_editor
func is_visible(): func is_visible():
var to_return = false var to_return = false
if(_script_editor.get_ref()): if _script_editor.get_ref():
to_return = _script_editor.get_ref().visible to_return = _script_editor.get_ref().visible
return to_return return to_return
# ############################################################################## # ##############################################################################
# #
# ############################################################################## # ##############################################################################
@ -74,8 +69,9 @@ var _script_editor = null
# and related controls at the time of the last refresh. # and related controls at the time of the last refresh.
var _script_editor_controls = [] var _script_editor_controls = []
var _method_prefix = 'test_' var _method_prefix = "test_"
var _inner_class_prefix = 'Test' var _inner_class_prefix = "Test"
func _init(script_edit): func _init(script_edit):
_script_editor = script_edit _script_editor = script_edit
@ -83,7 +79,7 @@ func _init(script_edit):
func _is_script_editor(obj): func _is_script_editor(obj):
return str(obj).find('[ScriptTextEditor') != -1 return str(obj).find("[ScriptTextEditor") != -1
# Find the first ScriptTextEditor and then get its parent. Done this way # Find the first ScriptTextEditor and then get its parent. Done this way
@ -91,36 +87,37 @@ func _is_script_editor(obj):
# future proofed. # future proofed.
func _find_script_editors_parent(): func _find_script_editors_parent():
var _first_editor = _get_first_child_of_type_name("ScriptTextEditor", _script_editor) var _first_editor = _get_first_child_of_type_name("ScriptTextEditor", _script_editor)
if(_first_editor != null): if _first_editor != null:
_script_editors_parent = _first_editor.get_parent() _script_editors_parent = _first_editor.get_parent()
func _populate_editors(): func _populate_editors():
if(_script_editors_parent == null): if _script_editors_parent == null:
return return
_script_editor_controls.clear() _script_editor_controls.clear()
for child in _script_editors_parent.get_children(): for child in _script_editors_parent.get_children():
if(_is_script_editor(child)): if _is_script_editor(child):
var ref = ScriptEditorControlRef.new(child) var ref = ScriptEditorControlRef.new(child)
_script_editor_controls.append(ref) _script_editor_controls.append(ref)
# Yes, this is the same as the one above but with a different name. This was # 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. # 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): func _get_first_child_of_type_name(obj_name, parent_obj):
if(parent_obj == null): if parent_obj == null:
return null return null
var kids = parent_obj.get_children() var kids = parent_obj.get_children()
var index = 0 var index = 0
var to_return = null var to_return = null
while(index < kids.size() and to_return == null): while index < kids.size() and to_return == null:
if(str(kids[index]).find(str("[", obj_name)) != -1): if str(kids[index]).find(str("[", obj_name)) != -1:
to_return = kids[index] to_return = kids[index]
else: else:
to_return = _get_first_child_of_type_name(obj_name, kids[index]) to_return = _get_first_child_of_type_name(obj_name, kids[index])
if(to_return == null): if to_return == null:
index += 1 index += 1
return to_return return to_return
@ -139,11 +136,12 @@ func _get_class_name_from_line(text):
var the_name = right.rstrip(":") var the_name = right.rstrip(":")
return the_name return the_name
func refresh(): func refresh():
if(_script_editors_parent == null): if _script_editors_parent == null:
_find_script_editors_parent() _find_script_editors_parent()
if(_script_editors_parent != null): if _script_editors_parent != null:
_populate_editors() _populate_editors()
@ -151,14 +149,14 @@ func get_current_text_edit():
var cur_script_editor = null var cur_script_editor = null
var idx = 0 var idx = 0
while(idx < _script_editor_controls.size() and cur_script_editor == null): while idx < _script_editor_controls.size() and cur_script_editor == null:
if(_script_editor_controls[idx].is_visible()): if _script_editor_controls[idx].is_visible():
cur_script_editor = _script_editor_controls[idx] cur_script_editor = _script_editor_controls[idx]
else: else:
idx += 1 idx += 1
var to_return = null var to_return = null
if(cur_script_editor != null): if cur_script_editor != null:
to_return = cur_script_editor.get_text_edit() to_return = cur_script_editor.get_text_edit()
return to_return return to_return
@ -174,36 +172,32 @@ func get_script_editor_controls():
func get_line_info(): func get_line_info():
var editor = get_current_text_edit() var editor = get_current_text_edit()
if(editor == null): if editor == null:
return return
var info = { var info = {script = null, inner_class = null, test_method = null}
script = null,
inner_class = null,
test_method = null
}
var line = editor.get_caret_line() var line = editor.get_caret_line()
var done_func = false var done_func = false
var done_inner = false var done_inner = false
while(line > 0 and (!done_func or !done_inner)): while line > 0 and (!done_func or !done_inner):
if(editor.can_fold_line(line)): if editor.can_fold_line(line):
var text = editor.get_line(line) var text = editor.get_line(line)
var strip_text = text.strip_edges(true, false) # only left var strip_text = text.strip_edges(true, false) # only left
if(!done_func and strip_text.begins_with("func ")): if !done_func and strip_text.begins_with("func "):
var func_name = _get_func_name_from_line(text) var func_name = _get_func_name_from_line(text)
if(func_name.begins_with(_method_prefix)): if func_name.begins_with(_method_prefix):
info.test_method = func_name info.test_method = func_name
done_func = true done_func = true
# If the func line is left justified then there won't be any # If the func line is left justified then there won't be any
# inner classes above it. # inner classes above it.
if(strip_text == text): if strip_text == text:
done_inner = true done_inner = true
if(!done_inner and strip_text.begins_with("class")): if !done_inner and strip_text.begins_with("class"):
var inner_name = _get_class_name_from_line(text) var inner_name = _get_class_name_from_line(text)
if(inner_name.begins_with(_inner_class_prefix)): if inner_name.begins_with(_inner_class_prefix):
info.inner_class = inner_name info.inner_class = inner_name
done_inner = true done_inner = true
# if we found an inner class then we are already past # if we found an inner class then we are already past

File diff suppressed because it is too large Load diff

View file

@ -39,12 +39,13 @@
# ############################################################################## # ##############################################################################
extends SceneTree extends SceneTree
var Optparse = load('res://addons/gut/optparse.gd') var Optparse = load("res://addons/gut/optparse.gd")
var Gut = load('res://addons/gut/gut.gd') var Gut = load("res://addons/gut/gut.gd")
var GutRunner = load('res://addons/gut/gui/GutRunner.tscn') var GutRunner = load("res://addons/gut/gui/GutRunner.tscn")
var json = JSON.new() var json = JSON.new()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Helper class to resolve the various different places where an option can # Helper class to resolve the various different places where an option can
# be set. Using the get_value method will enforce the order of precedence of: # be set. Using the get_value method will enforce the order of precedence of:
@ -61,7 +62,6 @@ class OptionResolver:
var cmd_opts = {} var cmd_opts = {}
var config_opts = {} var config_opts = {}
func get_value(key): func get_value(key):
return _nvl(cmd_opts[key], _nvl(config_opts[key], base_opts[key])) return _nvl(cmd_opts[key], _nvl(config_opts[key], base_opts[key]))
@ -78,21 +78,31 @@ class OptionResolver:
return new_hash return new_hash
func _nvl(a, b): func _nvl(a, b):
if(a == null): if a == null:
return b return b
else: else:
return a return a
func _string_it(h): func _string_it(h):
var to_return = '' var to_return = ""
for key in h: for key in h:
to_return += str('(',key, ':', _nvl(h[key], 'NULL'), ')') to_return += str("(", key, ":", _nvl(h[key], "NULL"), ")")
return to_return return to_return
func to_s(): func to_s():
return str("base:\n", _string_it(base_opts), "\n", \ return str(
"config:\n", _string_it(config_opts), "\n", \ "base:\n",
"cmd:\n", _string_it(cmd_opts), "\n", \ _string_it(base_opts),
"resolved:\n", _string_it(get_resolved_values())) "\n",
"config:\n",
_string_it(config_opts),
"\n",
"cmd:\n",
_string_it(cmd_opts),
"\n",
"resolved:\n",
_string_it(get_resolved_values())
)
func get_resolved_values(): func get_resolved_values():
var to_return = {} var to_return = {}
@ -101,23 +111,24 @@ class OptionResolver:
return to_return return to_return
func to_s_verbose(): func to_s_verbose():
var to_return = '' var to_return = ""
var resolved = get_resolved_values() var resolved = get_resolved_values()
for key in base_opts: for key in base_opts:
to_return += str(key, "\n") to_return += str(key, "\n")
to_return += str(' default: ', _nvl(base_opts[key], 'NULL'), "\n") to_return += str(" default: ", _nvl(base_opts[key], "NULL"), "\n")
to_return += str(' config: ', _nvl(config_opts[key], ' --'), "\n") to_return += str(" config: ", _nvl(config_opts[key], " --"), "\n")
to_return += str(' cmd: ', _nvl(cmd_opts[key], ' --'), "\n") to_return += str(" cmd: ", _nvl(cmd_opts[key], " --"), "\n")
to_return += str(' final: ', _nvl(resolved[key], 'NULL'), "\n") to_return += str(" final: ", _nvl(resolved[key], "NULL"), "\n")
return to_return return to_return
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Here starts the actual script that uses the Options class to kick off Gut # Here starts the actual script that uses the Options class to kick off Gut
# and run your tests. # and run your tests.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
var _gut_config = load('res://addons/gut/gut_config.gd').new() var _gut_config = load("res://addons/gut/gut_config.gd").new()
# instance of gut # instance of gut
var _tester = null var _tester = null
# array of command line options specified # array of command line options specified
@ -126,87 +137,156 @@ var _final_opts = []
func setup_options(options, font_names): func setup_options(options, font_names):
var opts = Optparse.new() var opts = Optparse.new()
opts.set_banner(('This is the command line interface for the unit testing tool Gut. With this ' + opts.set_banner(
'interface you can run one or more test scripts from the command line. In order ' + (
'for the Gut options to not clash with any other godot options, each option starts ' + "This is the command line interface for the unit testing tool Gut. With this "
'with a "g". Also, any option that requires a value will take the form of ' + + "interface you can run one or more test scripts from the command line. In order "
'"-g<name>=<value>". There cannot be any spaces between the option, the "=", or ' + + "for the Gut options to not clash with any other godot options, each option starts "
'inside a specified value or godot will think you are trying to run a scene.')) + 'with a "g". Also, any option that requires a value will take the form of '
+ '"-g<name>=<value>". There cannot be any spaces between the option, the "=", or '
+ "inside a specified value or godot will think you are trying to run a scene."
)
)
opts.add('-gtest', [], 'Comma delimited list of full paths to test scripts to run.') opts.add("-gtest", [], "Comma delimited list of full paths to test scripts to run.")
opts.add('-gdir', options.dirs, 'Comma delimited list of directories to add tests from.') opts.add("-gdir", options.dirs, "Comma delimited list of directories to add tests from.")
opts.add('-gprefix', options.prefix, 'Prefix used to find tests when specifying -gdir. Default "[default]".') opts.add(
opts.add('-gsuffix', options.suffix, 'Test script suffix, including .gd extension. Default "[default]".') "-gprefix",
opts.add('-ghide_orphans', false, 'Display orphan counts for tests and scripts. Default "[default]".') options.prefix,
opts.add('-gmaximize', false, 'Maximizes test runner window to fit the viewport.') 'Prefix used to find tests when specifying -gdir. Default "[default]".'
opts.add('-gcompact_mode', false, 'The runner will be in compact mode. This overrides -gmaximize.') )
opts.add('-gexit', false, 'Exit after running tests. If not specified you have to manually close the window.') opts.add(
opts.add('-gexit_on_success', false, 'Only exit if all tests pass.') "-gsuffix",
opts.add('-glog', options.log_level, 'Log level. Default [default]') options.suffix,
opts.add('-gignore_pause', false, 'Ignores any calls to gut.pause_before_teardown.') 'Test script suffix, including .gd extension. Default "[default]".'
opts.add('-gselect', '', ('Select a script to run initially. The first script that ' + )
'was loaded using -gtest or -gdir that contains the specified ' + opts.add(
'string will be executed. You may run others by interacting ' + "-ghide_orphans",
'with the GUI.')) false,
opts.add('-gunit_test_name', '', ('Name of a test to run. Any test that contains the specified ' + 'Display orphan counts for tests and scripts. Default "[default]".'
'text will be run, all others will be skipped.')) )
opts.add('-gh', false, 'Print this help, then quit') opts.add("-gmaximize", false, "Maximizes test runner window to fit the viewport.")
opts.add('-gconfig', 'res://.gutconfig.json', 'A config file that contains configuration information. Default is res://.gutconfig.json') opts.add(
opts.add('-ginner_class', '', 'Only run inner classes that contain this string') "-gcompact_mode", false, "The runner will be in compact mode. This overrides -gmaximize."
opts.add('-gopacity', options.opacity, 'Set opacity of test runner window. Use range 0 - 100. 0 = transparent, 100 = opaque.') )
opts.add('-gpo', false, 'Print option values from all sources and the value used, then quit.') opts.add(
opts.add('-ginclude_subdirs', false, 'Include subdirectories of -gdir.') "-gexit",
opts.add('-gdouble_strategy', 'partial', 'Default strategy to use when doubling. Valid values are [partial, full]. Default "[default]"') false,
opts.add('-gdisable_colors', false, 'Disable command line colors.') "Exit after running tests. If not specified you have to manually close the window."
opts.add('-gpre_run_script', '', 'pre-run hook script path') )
opts.add('-gpost_run_script', '', 'post-run hook script path') opts.add("-gexit_on_success", false, "Only exit if all tests pass.")
opts.add('-gprint_gutconfig_sample', false, 'Print out json that can be used to make a gutconfig file then quit.') opts.add("-glog", options.log_level, "Log level. Default [default]")
opts.add("-gignore_pause", false, "Ignores any calls to gut.pause_before_teardown.")
opts.add(
"-gselect",
"",
(
"Select a script to run initially. The first script that "
+ "was loaded using -gtest or -gdir that contains the specified "
+ "string will be executed. You may run others by interacting "
+ "with the GUI."
)
)
opts.add(
"-gunit_test_name",
"",
(
"Name of a test to run. Any test that contains the specified "
+ "text will be run, all others will be skipped."
)
)
opts.add("-gh", false, "Print this help, then quit")
opts.add(
"-gconfig",
"res://.gutconfig.json",
"A config file that contains configuration information. Default is res://.gutconfig.json"
)
opts.add("-ginner_class", "", "Only run inner classes that contain this string")
opts.add(
"-gopacity",
options.opacity,
"Set opacity of test runner window. Use range 0 - 100. 0 = transparent, 100 = opaque."
)
opts.add("-gpo", false, "Print option values from all sources and the value used, then quit.")
opts.add("-ginclude_subdirs", false, "Include subdirectories of -gdir.")
opts.add(
"-gdouble_strategy",
"partial",
'Default strategy to use when doubling. Valid values are [partial, full]. Default "[default]"'
)
opts.add("-gdisable_colors", false, "Disable command line colors.")
opts.add("-gpre_run_script", "", "pre-run hook script path")
opts.add("-gpost_run_script", "", "post-run hook script path")
opts.add(
"-gprint_gutconfig_sample",
false,
"Print out json that can be used to make a gutconfig file then quit."
)
opts.add('-gfont_name', options.font_name, str('Valid values are: ', font_names, '. Default "[default]"')) opts.add(
opts.add('-gfont_size', options.font_size, 'Font size, default "[default]"') "-gfont_name",
opts.add('-gbackground_color', options.background_color, 'Background color as an html color, default "[default]"') options.font_name,
opts.add('-gfont_color',options.font_color, 'Font color as an html color, default "[default]"') str("Valid values are: ", font_names, '. Default "[default]"')
opts.add('-gpaint_after', options.paint_after, 'Delay before GUT will add a 1 frame pause to paint the screen/GUI. default [default]') )
opts.add("-gfont_size", options.font_size, 'Font size, default "[default]"')
opts.add(
"-gbackground_color",
options.background_color,
'Background color as an html color, default "[default]"'
)
opts.add("-gfont_color", options.font_color, 'Font color as an html color, default "[default]"')
opts.add(
"-gpaint_after",
options.paint_after,
"Delay before GUT will add a 1 frame pause to paint the screen/GUI. default [default]"
)
opts.add('-gjunit_xml_file', options.junit_xml_file, 'Export results of run to this file in the Junit XML format.') opts.add(
opts.add('-gjunit_xml_timestamp', options.junit_xml_timestamp, 'Include a timestamp in the -gjunit_xml_file, default [default]') "-gjunit_xml_file",
options.junit_xml_file,
"Export results of run to this file in the Junit XML format."
)
opts.add(
"-gjunit_xml_timestamp",
options.junit_xml_timestamp,
"Include a timestamp in the -gjunit_xml_file, default [default]"
)
return opts return opts
# Parses options, applying them to the _tester or setting values # Parses options, applying them to the _tester or setting values
# in the options struct. # in the options struct.
func extract_command_line_options(from, to): func extract_command_line_options(from, to):
to.config_file = from.get_value('-gconfig') to.config_file = from.get_value("-gconfig")
to.dirs = from.get_value('-gdir') to.dirs = from.get_value("-gdir")
to.disable_colors = from.get_value('-gdisable_colors') to.disable_colors = from.get_value("-gdisable_colors")
to.double_strategy = from.get_value('-gdouble_strategy') to.double_strategy = from.get_value("-gdouble_strategy")
to.ignore_pause = from.get_value('-gignore_pause') to.ignore_pause = from.get_value("-gignore_pause")
to.include_subdirs = from.get_value('-ginclude_subdirs') to.include_subdirs = from.get_value("-ginclude_subdirs")
to.inner_class = from.get_value('-ginner_class') to.inner_class = from.get_value("-ginner_class")
to.log_level = from.get_value('-glog') to.log_level = from.get_value("-glog")
to.opacity = from.get_value('-gopacity') to.opacity = from.get_value("-gopacity")
to.post_run_script = from.get_value('-gpost_run_script') to.post_run_script = from.get_value("-gpost_run_script")
to.pre_run_script = from.get_value('-gpre_run_script') to.pre_run_script = from.get_value("-gpre_run_script")
to.prefix = from.get_value('-gprefix') to.prefix = from.get_value("-gprefix")
to.selected = from.get_value('-gselect') to.selected = from.get_value("-gselect")
to.should_exit = from.get_value('-gexit') to.should_exit = from.get_value("-gexit")
to.should_exit_on_success = from.get_value('-gexit_on_success') to.should_exit_on_success = from.get_value("-gexit_on_success")
to.should_maximize = from.get_value('-gmaximize') to.should_maximize = from.get_value("-gmaximize")
to.compact_mode = from.get_value('-gcompact_mode') to.compact_mode = from.get_value("-gcompact_mode")
to.hide_orphans = from.get_value('-ghide_orphans') to.hide_orphans = from.get_value("-ghide_orphans")
to.suffix = from.get_value('-gsuffix') to.suffix = from.get_value("-gsuffix")
to.tests = from.get_value('-gtest') to.tests = from.get_value("-gtest")
to.unit_test_name = from.get_value('-gunit_test_name') to.unit_test_name = from.get_value("-gunit_test_name")
to.font_size = from.get_value('-gfont_size') to.font_size = from.get_value("-gfont_size")
to.font_name = from.get_value('-gfont_name') to.font_name = from.get_value("-gfont_name")
to.background_color = from.get_value('-gbackground_color') to.background_color = from.get_value("-gbackground_color")
to.font_color = from.get_value('-gfont_color') to.font_color = from.get_value("-gfont_color")
to.paint_after = from.get_value('-gpaint_after') to.paint_after = from.get_value("-gpaint_after")
to.junit_xml_file = from.get_value('-gjunit_xml_file')
to.junit_xml_timestamp = from.get_value('-gjunit_xml_timestamp')
to.junit_xml_file = from.get_value("-gjunit_xml_file")
to.junit_xml_timestamp = from.get_value("-gjunit_xml_timestamp")
func _print_gutconfigs(values): func _print_gutconfigs(values):
@ -214,21 +294,23 @@ func _print_gutconfigs(values):
You do not need to specify all values in your own file. The values supplied in You do not need to specify all values in your own file. The values supplied in
this sample are what would be used if you ran gut w/o the -gprint_gutconfig_sample this sample are what would be used if you ran gut w/o the -gprint_gutconfig_sample
option (option priority: command-line, super.gutconfig, default).""" option (option priority: command-line, super.gutconfig, default)."""
print("\n", header.replace("\n", ' '), "\n\n") print("\n", header.replace("\n", " "), "\n\n")
var resolved = values var resolved = values
# remove_at some options that don't make sense to be in config # remove_at some options that don't make sense to be in config
resolved.erase("config_file") resolved.erase("config_file")
resolved.erase("show_help") resolved.erase("show_help")
print("Here's a config with all the properties set based off of your current command and config.") print(
print(json.stringify(resolved, ' ')) "Here's a config with all the properties set based off of your current command and config."
)
print(json.stringify(resolved, " "))
for key in resolved: for key in resolved:
resolved[key] = null resolved[key] = null
print("\n\nAnd here's an empty config for you fill in what you want.") print("\n\nAnd here's an empty config for you fill in what you want.")
print(json.stringify(resolved, ' ')) print(json.stringify(resolved, " "))
# parse options and run Gut # parse options and run Gut
@ -236,36 +318,40 @@ func _run_gut():
var opt_resolver = OptionResolver.new() var opt_resolver = OptionResolver.new()
opt_resolver.set_base_opts(_gut_config.default_options) opt_resolver.set_base_opts(_gut_config.default_options)
print("\n\n", ' --- Gut ---') print("\n\n", " --- Gut ---")
var o = setup_options(_gut_config.default_options, _gut_config.valid_fonts) var o = setup_options(_gut_config.default_options, _gut_config.valid_fonts)
var all_options_valid = o.parse() var all_options_valid = o.parse()
extract_command_line_options(o, opt_resolver.cmd_opts) extract_command_line_options(o, opt_resolver.cmd_opts)
var load_result = _gut_config.load_options_no_defaults( var load_result = _gut_config.load_options_no_defaults(opt_resolver.get_value("config_file"))
opt_resolver.get_value('config_file'))
# SHORTCIRCUIT # SHORTCIRCUIT
if(!all_options_valid or load_result == -1): if !all_options_valid or load_result == -1:
quit(1) quit(1)
else: else:
opt_resolver.config_opts = _gut_config.options opt_resolver.config_opts = _gut_config.options
if(o.get_value('-gh')): if o.get_value("-gh"):
print(_utils.get_version_text()) print(_utils.get_version_text())
o.print_help() o.print_help()
quit() quit()
elif(o.get_value('-gpo')): elif o.get_value("-gpo"):
print('All command line options and where they are specified. ' + print(
'The "final" value shows which value will actually be used ' + (
'based on order of precedence (default < super.gutconfig < cmd line).' + "\n") "All command line options and where they are specified. "
+ 'The "final" value shows which value will actually be used '
+ "based on order of precedence (default < super.gutconfig < cmd line)."
+ "\n"
)
)
print(opt_resolver.to_s_verbose()) print(opt_resolver.to_s_verbose())
quit() quit()
elif(o.get_value('-gprint_gutconfig_sample')): elif o.get_value("-gprint_gutconfig_sample"):
_print_gutconfigs(opt_resolver.get_resolved_values()) _print_gutconfigs(opt_resolver.get_resolved_values())
quit() quit()
else: else:
_final_opts = opt_resolver.get_resolved_values(); _final_opts = opt_resolver.get_resolved_values()
_gut_config.options = _final_opts _gut_config.options = _final_opts
var runner = GutRunner.instantiate() var runner = GutRunner.instantiate()
@ -275,31 +361,40 @@ func _run_gut():
get_root().add_child(runner) get_root().add_child(runner)
_tester = runner.get_gut() _tester = runner.get_gut()
_tester.connect('end_run', Callable(self,'_on_tests_finished').bind(_final_opts.should_exit, _final_opts.should_exit_on_success)) _tester.connect(
"end_run",
(
Callable(self, "_on_tests_finished")
. bind(_final_opts.should_exit, _final_opts.should_exit_on_success)
)
)
runner.run_tests() runner.run_tests()
# exit if option is set. # exit if option is set.
func _on_tests_finished(should_exit, should_exit_on_success): func _on_tests_finished(should_exit, should_exit_on_success):
if(_final_opts.dirs.size() == 0): if _final_opts.dirs.size() == 0:
if(_tester.get_summary().get_totals().scripts == 0): if _tester.get_summary().get_totals().scripts == 0:
var lgr = _tester.get_logger() var lgr = _tester.get_logger()
lgr.error('No directories configured. Add directories with options or a super.gutconfig.json file. Use the -gh option for more information.') lgr.error(
"No directories configured. Add directories with options or a super.gutconfig.json file. Use the -gh option for more information."
)
if(_tester.get_fail_count()): if _tester.get_fail_count():
set_exit_code(1) set_exit_code(1)
# Overwrite the exit code with the post_script # Overwrite the exit code with the post_script
var post_inst = _tester.get_post_run_script_instance() var post_inst = _tester.get_post_run_script_instance()
if(post_inst != null and post_inst.get_exit_code() != null): if post_inst != null and post_inst.get_exit_code() != null:
set_exit_code(post_inst.get_exit_code()) set_exit_code(post_inst.get_exit_code())
if(should_exit or (should_exit_on_success and _tester.get_fail_count() == 0)): if should_exit or (should_exit_on_success and _tester.get_fail_count() == 0):
quit() quit()
else: else:
print("Tests finished, exit manually") print("Tests finished, exit manually")
func set_exit_code(val): func set_exit_code(val):
pass pass
# OS.exit_code doesn't exist anymore, but when we find a solution it just # OS.exit_code doesn't exist anymore, but when we find a solution it just
@ -310,7 +405,7 @@ func set_exit_code(val):
# MAIN # MAIN
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func _init(): func _init():
if(!_utils.is_version_ok()): if !_utils.is_version_ok():
print("\n\n", _utils.get_version_text()) print("\n\n", _utils.get_version_text())
push_error(_utils.get_bad_version_text()) push_error(_utils.get_bad_version_text())
set_exit_code(1) set_exit_code(1)

View file

@ -1,51 +1,46 @@
var Gut = load('res://addons/gut/gut.gd') var Gut = load("res://addons/gut/gut.gd")
# Do not want a ref to _utils here due to use by editor plugin. # Do not want a ref to _utils here due to use by editor plugin.
# _utils needs to be split so that constants and what not do not # _utils needs to be split so that constants and what not do not
# have to rely on the weird singleton thing I made. # have to rely on the weird singleton thing I made.
enum DOUBLE_STRATEGY{ enum DOUBLE_STRATEGY { FULL, PARTIAL }
FULL,
PARTIAL
}
var valid_fonts = ["AnonymousPro", "CourierPro", "LobsterTwo", "Default"]
var valid_fonts = ['AnonymousPro', 'CourierPro', 'LobsterTwo', 'Default']
var default_options = { var default_options = {
background_color = Color(.15, .15, .15, 1).to_html(), background_color = Color(.15, .15, .15, 1).to_html(),
config_file = 'res://.gutconfig.json', config_file = "res://.gutconfig.json",
dirs = [], dirs = [],
disable_colors = false, disable_colors = false,
double_strategy = 'partial', double_strategy = "partial",
font_color = Color(.8, .8, .8, 1).to_html(), font_color = Color(.8, .8, .8, 1).to_html(),
font_name = 'CourierPrime', font_name = "CourierPrime",
font_size = 16, font_size = 16,
hide_orphans = false, hide_orphans = false,
ignore_pause = false, ignore_pause = false,
include_subdirs = false, include_subdirs = false,
inner_class = '', inner_class = "",
junit_xml_file = '', junit_xml_file = "",
junit_xml_timestamp = false, junit_xml_timestamp = false,
log_level = 1, log_level = 1,
opacity = 100, opacity = 100,
paint_after = .1, paint_after = .1,
post_run_script = '', post_run_script = "",
pre_run_script = '', pre_run_script = "",
prefix = 'test_', prefix = "test_",
selected = '', selected = "",
should_exit = false, should_exit = false,
should_exit_on_success = false, should_exit_on_success = false,
should_maximize = false, should_maximize = false,
compact_mode = false, compact_mode = false,
show_help = false, show_help = false,
suffix = '.gd', suffix = ".gd",
tests = [], tests = [],
unit_test_name = '', unit_test_name = "",
gut_on_top = true, gut_on_top = true,
} }
var default_panel_options = { var default_panel_options = {
font_name = 'CourierPrime', font_name = "CourierPrime",
font_size = 30, font_size = 30,
hide_result_tree = false, hide_result_tree = false,
hide_output_text = false, hide_output_text = false,
@ -67,30 +62,30 @@ func _null_copy(h):
func _load_options_from_config_file(file_path, into): func _load_options_from_config_file(file_path, into):
# SHORTCIRCUIT # SHORTCIRCUIT
if(!FileAccess.file_exists(file_path)): if !FileAccess.file_exists(file_path):
if(file_path != 'res://.gutconfig.json'): if file_path != "res://.gutconfig.json":
print('ERROR: Config File "', file_path, '" does not exist.') print('ERROR: Config File "', file_path, '" does not exist.')
return -1 return -1
else: else:
return 1 return 1
var f = FileAccess.open(file_path, FileAccess.READ) var f = FileAccess.open(file_path, FileAccess.READ)
if(f == null): if f == null:
var result = FileAccess.get_open_error() var result = FileAccess.get_open_error()
push_error(str("Could not load data ", file_path, ' ', result)) push_error(str("Could not load data ", file_path, " ", result))
return result return result
var json = f.get_as_text() var json = f.get_as_text()
f = null # close file f = null # close file
var test_json_conv = JSON.new() var test_json_conv = JSON.new()
test_json_conv.parse(json) test_json_conv.parse(json)
var results = test_json_conv.get_data() var results = test_json_conv.get_data()
# SHORTCIRCUIT # SHORTCIRCUIT
if(results == null): if results == null:
print("\n\n",'!! ERROR parsing file: ', file_path) print("\n\n", "!! ERROR parsing file: ", file_path)
print(' at line ', results.error_line, ':') print(" at line ", results.error_line, ":")
print(' ', results.error_string) print(" ", results.error_string)
return -1 return -1
# Get all the options out of the config file using the option name. The # Get all the options out of the config file using the option name. The
@ -99,28 +94,27 @@ func _load_options_from_config_file(file_path, into):
return 1 return 1
func _load_dict_into(source, dest): func _load_dict_into(source, dest):
for key in dest: for key in dest:
if(source.has(key)): if source.has(key):
if(source[key] != null): if source[key] != null:
if(typeof(source[key]) == TYPE_DICTIONARY): if typeof(source[key]) == TYPE_DICTIONARY:
_load_dict_into(source[key], dest[key]) _load_dict_into(source[key], dest[key])
else: else:
dest[key] = source[key] dest[key] = source[key]
func write_options(path): func write_options(path):
var content = json.stringify(options, ' ') var content = json.stringify(options, " ")
var f = FileAccess.open(path, FileAccess.WRITE) var f = FileAccess.open(path, FileAccess.WRITE)
var result = FileAccess.get_open_error() var result = FileAccess.get_open_error()
if(f != null): if f != null:
f.store_string(content) f.store_string(content)
f.close() f.close()
else: else:
print('ERROR: could not open file ', path, ' ', result) print("ERROR: could not open file ", path, " ", result)
return result return result
@ -129,12 +123,12 @@ func write_options(path):
func _apply_options(opts, _tester): func _apply_options(opts, _tester):
_tester.include_subdirectories = opts.include_subdirs _tester.include_subdirectories = opts.include_subdirs
if(opts.inner_class != ''): if opts.inner_class != "":
_tester.inner_class_name = opts.inner_class _tester.inner_class_name = opts.inner_class
_tester.log_level = opts.log_level _tester.log_level = opts.log_level
_tester.ignore_pause_before_teardown = opts.ignore_pause _tester.ignore_pause_before_teardown = opts.ignore_pause
if(opts.selected != ''): if opts.selected != "":
_tester.select_script(opts.selected) _tester.select_script(opts.selected)
for i in range(opts.dirs.size()): for i in range(opts.dirs.size()):
@ -143,9 +137,9 @@ func _apply_options(opts, _tester):
for i in range(opts.tests.size()): for i in range(opts.tests.size()):
_tester.add_script(opts.tests[i]) _tester.add_script(opts.tests[i])
if(opts.double_strategy == 'include super'): if opts.double_strategy == "include super":
_tester.double_strategy = DOUBLE_STRATEGY.FULL _tester.double_strategy = DOUBLE_STRATEGY.FULL
elif(opts.double_strategy == 'script only'): elif opts.double_strategy == "script only":
_tester.double_strategy = DOUBLE_STRATEGY.PARTIAL _tester.double_strategy = DOUBLE_STRATEGY.PARTIAL
_tester.unit_test_name = opts.unit_test_name _tester.unit_test_name = opts.unit_test_name
@ -167,13 +161,16 @@ func config_gut(gut):
func load_options(path): func load_options(path):
return _load_options_from_config_file(path, options) return _load_options_from_config_file(path, options)
func load_panel_options(path): func load_panel_options(path):
options['panel_options'] = default_panel_options.duplicate() options["panel_options"] = default_panel_options.duplicate()
return _load_options_from_config_file(path, options) return _load_options_from_config_file(path, options)
func load_options_no_defaults(path): func load_options_no_defaults(path):
options = _null_copy(default_options) options = _null_copy(default_options)
return _load_options_from_config_file(path, options) return _load_options_from_config_file(path, options)
func apply_options(gut): func apply_options(gut):
_apply_options(options, gut) _apply_options(options, gut)

View file

@ -5,9 +5,9 @@ var _bottom_panel = null
func _enter_tree(): func _enter_tree():
_bottom_panel = preload('res://addons/gut/gui/GutBottomPanel.tscn').instantiate() _bottom_panel = preload("res://addons/gut/gui/GutBottomPanel.tscn").instantiate()
var button = add_control_to_bottom_panel(_bottom_panel, 'GUT') var button = add_control_to_bottom_panel(_bottom_panel, "GUT")
button.shortcut_in_tooltip = true button.shortcut_in_tooltip = true
await get_tree().create_timer(3).timeout await get_tree().create_timer(3).timeout

View file

@ -1,7 +1,8 @@
# Temporary base script for gut.gd to hold the things to be remvoed and added # Temporary base script for gut.gd to hold the things to be remvoed and added
# to some utility somewhere. # to some utility somewhere.
extends Node extends Node
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# deletes all files in a given directory # deletes all files in a given directory
@ -10,32 +11,34 @@ func directory_delete_files(path):
var d = DirAccess.open(path) var d = DirAccess.open(path)
# SHORTCIRCUIT # SHORTCIRCUIT
if(d == null): if d == null:
return return
# Traversing a directory is kinda odd. You have to start the process of listing # Traversing a directory is kinda odd. You have to start the process of listing
# the contents of a directory with list_dir_begin then use get_next until it # the contents of a directory with list_dir_begin then use get_next until it
# returns an empty string. Then I guess you should end it. # returns an empty string. Then I guess you should end it.
d.list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547 d.list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547
var thing = d.get_next() # could be a dir or a file or something else maybe? var thing = d.get_next() # could be a dir or a file or something else maybe?
var full_path = '' var full_path = ""
while(thing != ''): while thing != "":
full_path = path + "/" + thing full_path = path + "/" + thing
#file_exists returns fasle for directories #file_exists returns fasle for directories
if(d.file_exists(full_path)): if d.file_exists(full_path):
d.remove(full_path) d.remove(full_path)
thing = d.get_next() thing = d.get_next()
d.list_dir_end() d.list_dir_end()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# deletes the file at the specified path # deletes the file at the specified path
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func file_delete(path): func file_delete(path):
var d = DirAccess.open(path.get_base_dir()) var d = DirAccess.open(path.get_base_dir())
if(d != null): if d != null:
d.remove(path) d.remove(path)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Checks to see if the passed in file has any data in it. # Checks to see if the passed in file has any data in it.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -43,22 +46,25 @@ func is_file_empty(path):
var f = FileAccess.open(path, FileAccess.READ) var f = FileAccess.open(path, FileAccess.READ)
var result = FileAccess.get_open_error() var result = FileAccess.get_open_error()
var empty = true var empty = true
if(result == OK): if result == OK:
empty = f.get_length() == 0 empty = f.get_length() == 0
f = null f = null
return empty return empty
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func get_file_as_text(path): func get_file_as_text(path):
return _utils.get_file_as_text(path) return _utils.get_file_as_text(path)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Creates an empty file at the specified path # Creates an empty file at the specified path
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func file_touch(path): func file_touch(path):
FileAccess.open(path, FileAccess.WRITE) FileAccess.open(path, FileAccess.WRITE)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Call _process or _fixed_process, if they exist, on obj and all it's children # Call _process or _fixed_process, if they exist, on obj and all it's children
# and their children and so and so forth. Delta will be passed through to all # and their children and so and so forth. Delta will be passed through to all
@ -66,9 +72,9 @@ func file_touch(path):
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func simulate(obj, times, delta): func simulate(obj, times, delta):
for _i in range(times): for _i in range(times):
if(obj.has_method("_process")): if obj.has_method("_process"):
obj._process(delta) obj._process(delta)
if(obj.has_method("_physics_process")): if obj.has_method("_physics_process"):
obj._physics_process(delta) obj._physics_process(delta)
for kid in obj.get_children(): for kid in obj.get_children():

View file

@ -5,37 +5,47 @@ class_name GutHookScript
# #
# To use, inherit from this script and then implement the run method. # To use, inherit from this script and then implement the run method.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
var JunitXmlExport = load('res://addons/gut/junit_xml_export.gd') var JunitXmlExport = load("res://addons/gut/junit_xml_export.gd")
# This is the instance of GUT that is running the tests. You can get # This is the instance of GUT that is running the tests. You can get
# information about the run from this object. This is set by GUT when the # information about the run from this object. This is set by GUT when the
# script is instantiated. # script is instantiated.
var gut = null var gut = null
# the exit code to be used by gut_cmdln. See set method. # the exit code to be used by gut_cmdln. See set method.
var _exit_code = null var _exit_code = null
var _should_abort = false var _should_abort = false
# Virtual method that will be called by GUT after instantiating # Virtual method that will be called by GUT after instantiating
# this script. # this script.
func run(): func run():
gut.logger.error("Run method not overloaded. Create a 'run()' method in your hook script to run your code.") (
gut
. logger
. error(
"Run method not overloaded. Create a 'run()' method in your hook script to run your code."
)
)
# Set the exit code when running from the command line. If not set then the # Set the exit code when running from the command line. If not set then the
# default exit code will be returned (0 when no tests fail, 1 when any tests # default exit code will be returned (0 when no tests fail, 1 when any tests
# fail). # fail).
func set_exit_code(code): func set_exit_code(code):
_exit_code = code _exit_code = code
func get_exit_code(): func get_exit_code():
return _exit_code return _exit_code
# Usable by pre-run script to cause the run to end AFTER the run() method # Usable by pre-run script to cause the run to end AFTER the run() method
# finishes. post-run script will not be ran. # finishes. post-run script will not be ran.
func abort(): func abort():
_should_abort = true _should_abort = true
func should_abort(): func should_abort():
return _should_abort return _should_abort

View file

@ -3,23 +3,24 @@ var _registry = {}
func _create_reg_entry(base_path, subpath): func _create_reg_entry(base_path, subpath):
var to_return = { var to_return = {
"base_path":base_path, "base_path": base_path,
"subpath":subpath, "subpath": subpath,
"base_resource":load(base_path), "base_resource": load(base_path),
"full_path":str("'", base_path, "'", subpath) "full_path": str("'", base_path, "'", subpath)
} }
return to_return return to_return
func _register_inners(base_path, obj, prev_inner = ''):
func _register_inners(base_path, obj, prev_inner = ""):
var const_map = obj.get_script_constant_map() var const_map = obj.get_script_constant_map()
var consts = const_map.keys() var consts = const_map.keys()
var const_idx = 0 var const_idx = 0
while(const_idx < consts.size()): while const_idx < consts.size():
var key = consts[const_idx] var key = consts[const_idx]
var thing = const_map[key] var thing = const_map[key]
if(typeof(thing) == TYPE_OBJECT): if typeof(thing) == TYPE_OBJECT:
var cur_inner = str(prev_inner, ".", key) var cur_inner = str(prev_inner, ".", key)
_registry[thing] = _create_reg_entry(base_path, cur_inner) _registry[thing] = _create_reg_entry(base_path, cur_inner)
_register_inners(base_path, thing, cur_inner) _register_inners(base_path, thing, cur_inner)
@ -33,21 +34,23 @@ func register(base_script):
func get_extends_path(inner_class): func get_extends_path(inner_class):
if(_registry.has(inner_class)): if _registry.has(inner_class):
return _registry[inner_class].full_path return _registry[inner_class].full_path
else: else:
return null return null
# returns the subpath for the inner class. This includes the leading "." in # returns the subpath for the inner class. This includes the leading "." in
# the path. # the path.
func get_subpath(inner_class): func get_subpath(inner_class):
if(_registry.has(inner_class)): if _registry.has(inner_class):
return _registry[inner_class].subpath return _registry[inner_class].subpath
else: else:
return '' return ""
func get_base_path(inner_class): func get_base_path(inner_class):
if(_registry.has(inner_class)): if _registry.has(inner_class):
return _registry[inner_class].base_path return _registry[inner_class].base_path
@ -56,7 +59,7 @@ func has(inner_class):
func get_base_resource(inner_class): func get_base_resource(inner_class):
if(_registry.has(inner_class)): if _registry.has(inner_class):
return _registry[inner_class].base_resource return _registry[inner_class].base_resource

View file

@ -30,7 +30,6 @@
# ----------- # -----------
# ############################################################################## # ##############################################################################
# Implemented InputEvent* convenience methods # Implemented InputEvent* convenience methods
# InputEventAction # InputEventAction
# InputEventKey # InputEventKey
@ -46,10 +45,9 @@
# InputEventScreenDrag # InputEventScreenDrag
# InputEventScreenTouch # InputEventScreenTouch
static func _to_scancode(which): static func _to_scancode(which):
var key_code = which var key_code = which
if(typeof(key_code) == TYPE_STRING): if typeof(key_code) == TYPE_STRING:
key_code = key_code.to_upper().to_ascii_buffer()[0] key_code = key_code.to_upper().to_ascii_buffer()[0]
return key_code return key_code
@ -57,7 +55,7 @@ static func _to_scancode(which):
static func new_mouse_button_event(position, global_position, pressed, button_index): static func new_mouse_button_event(position, global_position, pressed, button_index):
var event = InputEventMouseButton.new() var event = InputEventMouseButton.new()
event.position = position event.position = position
if(global_position != null): if global_position != null:
event.global_position = global_position event.global_position = global_position
event.pressed = pressed event.pressed = pressed
event.button_index = button_index event.button_index = button_index
@ -79,58 +77,58 @@ static func key_down(which):
return event return event
static func action_up(which, strength=1.0): static func action_up(which, strength = 1.0):
var event = InputEventAction.new() var event = InputEventAction.new()
event.action = which event.action = which
event.strength = strength event.strength = strength
return event return event
static func action_down(which, strength=1.0): static func action_down(which, strength = 1.0):
var event = InputEventAction.new() var event = InputEventAction.new()
event.action = which event.action = which
event.strength = strength event.strength = strength
event.pressed = true event.pressed = true
return event return event
static func mouse_left_button_down(position, global_position=null): static func mouse_left_button_down(position, global_position = null):
var event = new_mouse_button_event(position, global_position, true, MOUSE_BUTTON_LEFT) var event = new_mouse_button_event(position, global_position, true, MOUSE_BUTTON_LEFT)
return event return event
static func mouse_left_button_up(position, global_position=null): static func mouse_left_button_up(position, global_position = null):
var event = new_mouse_button_event(position, global_position, false, MOUSE_BUTTON_LEFT) var event = new_mouse_button_event(position, global_position, false, MOUSE_BUTTON_LEFT)
return event return event
static func mouse_double_click(position, global_position=null): static func mouse_double_click(position, global_position = null):
var event = new_mouse_button_event(position, global_position, false, MOUSE_BUTTON_LEFT) var event = new_mouse_button_event(position, global_position, false, MOUSE_BUTTON_LEFT)
event.double_click = true event.double_click = true
return event return event
static func mouse_right_button_down(position, global_position=null): static func mouse_right_button_down(position, global_position = null):
var event = new_mouse_button_event(position, global_position, true, MOUSE_BUTTON_RIGHT) var event = new_mouse_button_event(position, global_position, true, MOUSE_BUTTON_RIGHT)
return event return event
static func mouse_right_button_up(position, global_position=null): static func mouse_right_button_up(position, global_position = null):
var event = new_mouse_button_event(position, global_position, false, MOUSE_BUTTON_RIGHT) var event = new_mouse_button_event(position, global_position, false, MOUSE_BUTTON_RIGHT)
return event return event
static func mouse_motion(position, global_position=null): static func mouse_motion(position, global_position = null):
var event = InputEventMouseMotion.new() var event = InputEventMouseMotion.new()
event.position = position event.position = position
if(global_position != null): if global_position != null:
event.global_position = global_position event.global_position = global_position
return event return event
static func mouse_relative_motion(offset, last_motion_event=null, speed=Vector2(0, 0)): static func mouse_relative_motion(offset, last_motion_event = null, speed = Vector2(0, 0)):
var event = null var event = null
if(last_motion_event == null): if last_motion_event == null:
event = mouse_motion(offset) event = mouse_motion(offset)
event.velocity = speed event.velocity = speed
else: else:

View file

@ -66,12 +66,12 @@ class InputQueueItem:
# TODO should this be done in _physics_process instead or should it be # TODO should this be done in _physics_process instead or should it be
# configurable? # configurable?
func _physics_process(delta): func _physics_process(delta):
if(frame_delay > 0 and _delay_started): if frame_delay > 0 and _delay_started:
_waited_frames += 1 _waited_frames += 1
if(_waited_frames >= frame_delay): if _waited_frames >= frame_delay:
emit_signal("event_ready") emit_signal("event_ready")
func _init(t_delay,f_delay): func _init(t_delay, f_delay):
time_delay = t_delay time_delay = t_delay
frame_delay = f_delay frame_delay = f_delay
_is_ready = time_delay == 0 and frame_delay == 0 _is_ready = time_delay == 0 and frame_delay == 0
@ -88,18 +88,18 @@ class InputQueueItem:
func start(): func start():
_delay_started = true _delay_started = true
if(time_delay > 0): if time_delay > 0:
var t = _delay_timer(time_delay) var t = _delay_timer(time_delay)
t.connect("timeout",Callable(self,"_on_time_timeout")) t.connect("timeout", Callable(self, "_on_time_timeout"))
# ############################################################################## # ##############################################################################
# #
# ############################################################################## # ##############################################################################
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
var InputFactory = load("res://addons/gut/input_factory.gd") var InputFactory = load("res://addons/gut/input_factory.gd")
const INPUT_WARN = 'If using Input as a reciever it will not respond to *_down events until a *_up event is recieved. Call the appropriate *_up event or use hold_for(...) to automatically release after some duration.' const INPUT_WARN = "If using Input as a reciever it will not respond to *_down events until a *_up event is recieved. Call the appropriate *_up event or use hold_for(...) to automatically release after some duration."
var _lgr = _utils.get_logger() var _lgr = _utils.get_logger()
var _receivers = [] var _receivers = []
@ -122,44 +122,65 @@ var _auto_flush_input = false
signal idle signal idle
func _init(r=null): func _init(r = null):
if(r != null): if r != null:
add_receiver(r) add_receiver(r)
func _send_event(event): func _send_event(event):
if(event is InputEventKey): if event is InputEventKey:
if((event.pressed and !event.echo) and is_key_pressed(event.keycode)): if (event.pressed and !event.echo) and is_key_pressed(event.keycode):
_lgr.warn(str("InputSender: key_down called for ", event.as_text(), " when that key is already pressed. ", INPUT_WARN)) _lgr.warn(
str(
"InputSender: key_down called for ",
event.as_text(),
" when that key is already pressed. ",
INPUT_WARN
)
)
_pressed_keys[event.keycode] = event.pressed _pressed_keys[event.keycode] = event.pressed
elif(event is InputEventAction): elif event is InputEventAction:
if(event.pressed and is_action_pressed(event.action)): if event.pressed and is_action_pressed(event.action):
_lgr.warn(str("InputSender: action_down called for ", event.action, " when that action is already pressed. ", INPUT_WARN)) _lgr.warn(
str(
"InputSender: action_down called for ",
event.action,
" when that action is already pressed. ",
INPUT_WARN
)
)
_pressed_actions[event.action] = event.pressed _pressed_actions[event.action] = event.pressed
elif(event is InputEventMouseButton): elif event is InputEventMouseButton:
if(event.pressed and is_mouse_button_pressed(event.button_index)): if event.pressed and is_mouse_button_pressed(event.button_index):
_lgr.warn(str("InputSender: mouse_button_down called for ", event.button_index, " when that mouse button is already pressed. ", INPUT_WARN)) _lgr.warn(
str(
"InputSender: mouse_button_down called for ",
event.button_index,
" when that mouse button is already pressed. ",
INPUT_WARN
)
)
_pressed_mouse_buttons[event.button_index] = event _pressed_mouse_buttons[event.button_index] = event
for r in _receivers: for r in _receivers:
if(r == Input): if r == Input:
Input.parse_input_event(event) Input.parse_input_event(event)
if(_auto_flush_input): if _auto_flush_input:
Input.flush_buffered_events() Input.flush_buffered_events()
else: else:
if(r.has_method("_input")): if r.has_method("_input"):
r._input(event) r._input(event)
if(r.has_method("_gui_input")): if r.has_method("_gui_input"):
r._gui_input(event) r._gui_input(event)
if(r.has_method("_unhandled_input")): if r.has_method("_unhandled_input"):
r._unhandled_input(event) r._unhandled_input(event)
func _send_or_record_event(event): func _send_or_record_event(event):
_last_event = event _last_event = event
if(_next_queue_item != null): if _next_queue_item != null:
_next_queue_item.events.append(event) _next_queue_item.events.append(event)
else: else:
_send_event(event) _send_event(event)
@ -172,7 +193,7 @@ func _on_queue_item_ready(item):
var done_event = _input_queue.pop_front() var done_event = _input_queue.pop_front()
done_event.queue_free() done_event.queue_free()
if(_input_queue.size() == 0): if _input_queue.size() == 0:
_next_queue_item = null _next_queue_item = null
emit_signal("idle") emit_signal("idle")
else: else:
@ -184,7 +205,7 @@ func _add_queue_item(item):
_next_queue_item = item _next_queue_item = item
_input_queue.append(item) _input_queue.append(item)
Engine.get_main_loop().root.add_child(item) Engine.get_main_loop().root.add_child(item)
if(_input_queue.size() == 1): if _input_queue.size() == 1:
item.start() item.start()
@ -197,13 +218,13 @@ func get_receivers():
func wait(t): func wait(t):
if(typeof(t) == TYPE_STRING): if typeof(t) == TYPE_STRING:
var suffix = t.substr(t.length() -1, 1) var suffix = t.substr(t.length() - 1, 1)
var val = t.rstrip('s').rstrip('f').to_float() var val = t.rstrip("s").rstrip("f").to_float()
if(suffix.to_lower() == 's'): if suffix.to_lower() == "s":
wait_secs(val) wait_secs(val)
elif(suffix.to_lower() == 'f'): elif suffix.to_lower() == "f":
wait_frames(val) wait_frames(val)
else: else:
wait_secs(t) wait_secs(t)
@ -239,71 +260,71 @@ func key_down(which):
func key_echo(): func key_echo():
if(_last_event != null and _last_event is InputEventKey): if _last_event != null and _last_event is InputEventKey:
var new_key = _last_event.duplicate() var new_key = _last_event.duplicate()
new_key.echo = true new_key.echo = true
_send_or_record_event(new_key) _send_or_record_event(new_key)
return self return self
func action_up(which, strength=1.0): func action_up(which, strength = 1.0):
var event = InputFactory.action_up(which, strength) var event = InputFactory.action_up(which, strength)
_send_or_record_event(event) _send_or_record_event(event)
return self return self
func action_down(which, strength=1.0): func action_down(which, strength = 1.0):
var event = InputFactory.action_down(which, strength) var event = InputFactory.action_down(which, strength)
_send_or_record_event(event) _send_or_record_event(event)
return self return self
func mouse_left_button_down(position, global_position=null): func mouse_left_button_down(position, global_position = null):
var event = InputFactory.mouse_left_button_down(position, global_position) var event = InputFactory.mouse_left_button_down(position, global_position)
_send_or_record_event(event) _send_or_record_event(event)
return self return self
func mouse_left_button_up(position, global_position=null): func mouse_left_button_up(position, global_position = null):
var event = InputFactory.mouse_left_button_up(position, global_position) var event = InputFactory.mouse_left_button_up(position, global_position)
_send_or_record_event(event) _send_or_record_event(event)
return self return self
func mouse_double_click(position, global_position=null): func mouse_double_click(position, global_position = null):
var event = InputFactory.mouse_double_click(position, global_position) var event = InputFactory.mouse_double_click(position, global_position)
event.double_click = true event.double_click = true
_send_or_record_event(event) _send_or_record_event(event)
return self return self
func mouse_right_button_down(position, global_position=null): func mouse_right_button_down(position, global_position = null):
var event = InputFactory.mouse_right_button_down(position, global_position) var event = InputFactory.mouse_right_button_down(position, global_position)
_send_or_record_event(event) _send_or_record_event(event)
return self return self
func mouse_right_button_up(position, global_position=null): func mouse_right_button_up(position, global_position = null):
var event = InputFactory.mouse_right_button_up(position, global_position) var event = InputFactory.mouse_right_button_up(position, global_position)
_send_or_record_event(event) _send_or_record_event(event)
return self return self
func mouse_motion(position, global_position=null): func mouse_motion(position, global_position = null):
var event = InputFactory.mouse_motion(position, global_position) var event = InputFactory.mouse_motion(position, global_position)
_last_mouse_motion = event _last_mouse_motion = event
_send_or_record_event(event) _send_or_record_event(event)
return self return self
func mouse_relative_motion(offset, speed=Vector2(0, 0)): func mouse_relative_motion(offset, speed = Vector2(0, 0)):
var event = InputFactory.mouse_relative_motion(offset, _last_mouse_motion, speed) var event = InputFactory.mouse_relative_motion(offset, _last_mouse_motion, speed)
_last_mouse_motion = event _last_mouse_motion = event
_send_or_record_event(event) _send_or_record_event(event)
return self return self
func mouse_set_position(position, global_position=null): func mouse_set_position(position, global_position = null):
_last_mouse_motion = InputFactory.mouse_motion(position, global_position) _last_mouse_motion = InputFactory.mouse_motion(position, global_position)
return self return self
@ -315,25 +336,25 @@ func send_event(event):
func release_all(): func release_all():
for key in _pressed_keys: for key in _pressed_keys:
if(_pressed_keys[key]): if _pressed_keys[key]:
_send_event(InputFactory.key_up(key)) _send_event(InputFactory.key_up(key))
_pressed_keys.clear() _pressed_keys.clear()
for key in _pressed_actions: for key in _pressed_actions:
if(_pressed_actions[key]): if _pressed_actions[key]:
_send_event(InputFactory.action_up(key)) _send_event(InputFactory.action_up(key))
_pressed_actions.clear() _pressed_actions.clear()
for key in _pressed_mouse_buttons: for key in _pressed_mouse_buttons:
var event = _pressed_mouse_buttons[key].duplicate() var event = _pressed_mouse_buttons[key].duplicate()
if(event.pressed): if event.pressed:
event.pressed = false event.pressed = false
_send_event(event) _send_event(event)
_pressed_mouse_buttons.clear() _pressed_mouse_buttons.clear()
func hold_for(duration): func hold_for(duration):
if(_last_event != null and _last_event.pressed): if _last_event != null and _last_event.pressed:
var next_event = _last_event.duplicate() var next_event = _last_event.duplicate()
next_event.pressed = false next_event.pressed = false
wait(duration) wait(duration)
@ -356,16 +377,20 @@ func clear():
_pressed_actions.clear() _pressed_actions.clear()
_pressed_mouse_buttons.clear() _pressed_mouse_buttons.clear()
func is_idle(): func is_idle():
return _input_queue.size() == 0 return _input_queue.size() == 0
func is_key_pressed(which): func is_key_pressed(which):
var event = InputFactory.key_up(which) var event = InputFactory.key_up(which)
return _pressed_keys.has(event.keycode) and _pressed_keys[event.keycode] return _pressed_keys.has(event.keycode) and _pressed_keys[event.keycode]
func is_action_pressed(which): func is_action_pressed(which):
return _pressed_actions.has(which) and _pressed_actions[which] return _pressed_actions.has(which) and _pressed_actions[which]
func is_mouse_button_pressed(which): func is_mouse_button_pressed(which):
return _pressed_mouse_buttons.has(which) and _pressed_mouse_buttons[which] return _pressed_mouse_buttons.has(which) and _pressed_mouse_buttons[which]

View file

@ -1,10 +1,11 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Creates an export of a test run in the JUnit XML format. # Creates an export of a test run in the JUnit XML format.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
var _exporter = _utils.ResultExporter.new() var _exporter = _utils.ResultExporter.new()
func indent(s, ind): func indent(s, ind):
var to_return = ind + s var to_return = ind + s
to_return = to_return.replace("\n", "\n" + ind) to_return = to_return.replace("\n", "\n" + ind)
@ -14,16 +15,17 @@ func indent(s, ind):
func add_attr(name, value): func add_attr(name, value):
return str(name, '="', value, '" ') return str(name, '="', value, '" ')
func _export_test_result(test): func _export_test_result(test):
var to_return = '' var to_return = ""
# Right now the pending and failure messages won't fit in the message # Right now the pending and failure messages won't fit in the message
# attribute because they can span multiple lines and need to be escaped. # attribute because they can span multiple lines and need to be escaped.
if(test.status == 'pending'): if test.status == "pending":
var skip_tag = str("<skipped message=\"pending\">", test.pending[0], "</skipped>") var skip_tag = str('<skipped message="pending">', test.pending[0], "</skipped>")
to_return += skip_tag to_return += skip_tag
elif(test.status == 'fail'): elif test.status == "fail":
var fail_tag = str("<failure message=\"failed\">", test.failing[0], "</failure>") var fail_tag = str('<failure message="failed">', test.failing[0], "</failure>")
to_return += fail_tag to_return += fail_tag
return to_return return to_return
@ -70,15 +72,15 @@ func _export_scripts(exp_results):
func get_results_xml(gut): func get_results_xml(gut):
var exp_results = _exporter.get_results_dictionary(gut) var exp_results = _exporter.get_results_dictionary(gut)
var to_return = '<?xml version="1.0" encoding="UTF-8"?>' + "\n" var to_return = '<?xml version="1.0" encoding="UTF-8"?>' + "\n"
to_return += '<testsuites ' to_return += "<testsuites "
to_return += add_attr("name", 'GutTests') to_return += add_attr("name", "GutTests")
to_return += add_attr("failures", exp_results.test_scripts.props.failures) to_return += add_attr("failures", exp_results.test_scripts.props.failures)
to_return += add_attr('tests', exp_results.test_scripts.props.tests) to_return += add_attr("tests", exp_results.test_scripts.props.tests)
to_return += ">\n" to_return += ">\n"
to_return += indent(_export_scripts(exp_results), " ") to_return += indent(_export_scripts(exp_results), " ")
to_return += '</testsuites>' to_return += "</testsuites>"
return to_return return to_return
@ -86,9 +88,8 @@ func write_file(gut, path):
var xml = get_results_xml(gut) var xml = get_results_xml(gut)
var f_result = _utils.write_file(path, xml) var f_result = _utils.write_file(path, xml)
if(f_result != OK): if f_result != OK:
var msg = str("Error: ", f_result, ". Could not create export file ", path) var msg = str("Error: ", f_result, ". Could not create export file ", path)
_utils.get_logger().error(msg) _utils.get_logger().error(msg)
return f_result return f_result

View file

@ -30,40 +30,38 @@
# various message types (error, warning, etc). # various message types (error, warning, etc).
# ############################################################################## # ##############################################################################
var types = { var types = {
debug = 'debug', debug = "debug",
deprecated = 'deprecated', deprecated = "deprecated",
error = 'error', error = "error",
failed = 'failed', failed = "failed",
info = 'info', info = "info",
normal = 'normal', normal = "normal",
orphan = 'orphan', orphan = "orphan",
passed = 'passed', passed = "passed",
pending = 'pending', pending = "pending",
warn ='warn', warn = "warn",
} }
var fmts = { var fmts = {
red = 'red', red = "red",
yellow = 'yellow', yellow = "yellow",
green = 'green', green = "green",
bold = "bold",
bold = 'bold', underline = "underline",
underline = 'underline',
none = null none = null
} }
var _type_data = { var _type_data = {
types.debug: {disp='DEBUG', enabled=true, fmt=fmts.none}, types.debug: {disp = "DEBUG", enabled = true, fmt = fmts.none},
types.deprecated: {disp='DEPRECATED', enabled=true, fmt=fmts.none}, types.deprecated: {disp = "DEPRECATED", enabled = true, fmt = fmts.none},
types.error: {disp='ERROR', enabled=true, fmt=fmts.red}, types.error: {disp = "ERROR", enabled = true, fmt = fmts.red},
types.failed: {disp='Failed', enabled=true, fmt=fmts.red}, types.failed: {disp = "Failed", enabled = true, fmt = fmts.red},
types.info: {disp='INFO', enabled=true, fmt=fmts.bold}, types.info: {disp = "INFO", enabled = true, fmt = fmts.bold},
types.normal: {disp='NORMAL', enabled=true, fmt=fmts.none}, types.normal: {disp = "NORMAL", enabled = true, fmt = fmts.none},
types.orphan: {disp='Orphans', enabled=true, fmt=fmts.yellow}, types.orphan: {disp = "Orphans", enabled = true, fmt = fmts.yellow},
types.passed: {disp='Passed', enabled=true, fmt=fmts.green}, types.passed: {disp = "Passed", enabled = true, fmt = fmts.green},
types.pending: {disp='Pending', enabled=true, fmt=fmts.yellow}, types.pending: {disp = "Pending", enabled = true, fmt = fmts.yellow},
types.warn: {disp='WARNING', enabled=true, fmt=fmts.yellow}, types.warn: {disp = "WARNING", enabled = true, fmt = fmts.yellow},
} }
var _logs = { var _logs = {
@ -74,24 +72,20 @@ var _logs = {
types.deprecated: [], types.deprecated: [],
} }
var _printers = { var _printers = {terminal = null, gui = null, console = null}
terminal = null,
gui = null,
console = null
}
var _gut = null var _gut = null
var _utils = null var _utils = null
var _indent_level = 0 var _indent_level = 0
var _indent_string = ' ' var _indent_string = " "
var _skip_test_name_for_testing = false var _skip_test_name_for_testing = false
var _less_test_names = false var _less_test_names = false
var _yield_calls = 0 var _yield_calls = 0
var _last_yield_text = '' var _last_yield_text = ""
func _init(): func _init():
_utils = load('res://addons/gut/utils.gd').get_instance() _utils = load("res://addons/gut/utils.gd").get_instance()
_printers.terminal = _utils.Printers.TerminalPrinter.new() _printers.terminal = _utils.Printers.TerminalPrinter.new()
_printers.console = _utils.Printers.ConsolePrinter.new() _printers.console = _utils.Printers.ConsolePrinter.new()
# There were some problems in the timing of disabling this at the right # There were some problems in the timing of disabling this at the right
@ -99,20 +93,22 @@ func _init():
# by plugin_control.gd based on settings. # by plugin_control.gd based on settings.
_printers.console.set_disabled(true) _printers.console.set_disabled(true)
func get_indent_text(): func get_indent_text():
var pad = '' var pad = ""
for i in range(_indent_level): for i in range(_indent_level):
pad += _indent_string pad += _indent_string
return pad return pad
func _indent_text(text): func _indent_text(text):
var to_return = text var to_return = text
var ending_newline = '' var ending_newline = ""
if(text.ends_with("\n")): if text.ends_with("\n"):
ending_newline = "\n" ending_newline = "\n"
to_return = to_return.left(to_return.length() -1) to_return = to_return.left(to_return.length() - 1)
var pad = get_indent_text() var pad = get_indent_text()
to_return = to_return.replace("\n", "\n" + pad) to_return = to_return.replace("\n", "\n" + pad)
@ -120,231 +116,278 @@ func _indent_text(text):
return pad + to_return return pad + to_return
func _should_print_to_printer(key_name): func _should_print_to_printer(key_name):
return _printers[key_name] != null and !_printers[key_name].get_disabled() return _printers[key_name] != null and !_printers[key_name].get_disabled()
func _print_test_name(): func _print_test_name():
if(_gut == null): if _gut == null:
return return
var cur_test = _gut.get_current_test_object() var cur_test = _gut.get_current_test_object()
if(cur_test == null): if cur_test == null:
return false return false
if(!cur_test.has_printed_name): if !cur_test.has_printed_name:
_output('* ' + cur_test.name + "\n") _output("* " + cur_test.name + "\n")
cur_test.has_printed_name = true cur_test.has_printed_name = true
func _output(text, fmt=null):
func _output(text, fmt = null):
for key in _printers: for key in _printers:
if(_should_print_to_printer(key)): if _should_print_to_printer(key):
var info = ''#str(self, ':', key, ':', _printers[key], '| ') var info = "" #str(self, ':', key, ':', _printers[key], '| ')
_printers[key].send(info + text, fmt) _printers[key].send(info + text, fmt)
func _log(text, fmt=fmts.none):
func _log(text, fmt = fmts.none):
_print_test_name() _print_test_name()
var indented = _indent_text(text) var indented = _indent_text(text)
_output(indented, fmt) _output(indented, fmt)
# --------------- # ---------------
# Get Methods # Get Methods
# --------------- # ---------------
func get_warnings(): func get_warnings():
return get_log_entries(types.warn) return get_log_entries(types.warn)
func get_errors(): func get_errors():
return get_log_entries(types.error) return get_log_entries(types.error)
func get_infos(): func get_infos():
return get_log_entries(types.info) return get_log_entries(types.info)
func get_debugs(): func get_debugs():
return get_log_entries(types.debug) return get_log_entries(types.debug)
func get_deprecated(): func get_deprecated():
return get_log_entries(types.deprecated) return get_log_entries(types.deprecated)
func get_count(log_type=null):
func get_count(log_type = null):
var count = 0 var count = 0
if(log_type == null): if log_type == null:
for key in _logs: for key in _logs:
count += _logs[key].size() count += _logs[key].size()
else: else:
count = _logs[log_type].size() count = _logs[log_type].size()
return count return count
func get_log_entries(log_type): func get_log_entries(log_type):
return _logs[log_type] return _logs[log_type]
# --------------- # ---------------
# Log methods # Log methods
# --------------- # ---------------
func _output_type(type, text): func _output_type(type, text):
var td = _type_data[type] var td = _type_data[type]
if(!td.enabled): if !td.enabled:
return return
_print_test_name() _print_test_name()
if(type != types.normal): if type != types.normal:
if(_logs.has(type)): if _logs.has(type):
_logs[type].append(text) _logs[type].append(text)
var start = str('[', td.disp, ']') var start = str("[", td.disp, "]")
if(text != null and text != ''): if text != null and text != "":
start += ': ' start += ": "
else: else:
start += ' ' start += " "
var indented_start = _indent_text(start) var indented_start = _indent_text(start)
var indented_end = _indent_text(text) var indented_end = _indent_text(text)
indented_end = indented_end.lstrip(_indent_string) indented_end = indented_end.lstrip(_indent_string)
_output(indented_start, td.fmt) _output(indented_start, td.fmt)
_output(indented_end + "\n") _output(indented_end + "\n")
func debug(text): func debug(text):
_output_type(types.debug, text) _output_type(types.debug, text)
# supply some text or the name of the deprecated method and the replacement. # supply some text or the name of the deprecated method and the replacement.
func deprecated(text, alt_method=null): func deprecated(text, alt_method = null):
var msg = text var msg = text
if(alt_method): if alt_method:
msg = str('The method ', text, ' is deprecated, use ', alt_method , ' instead.') msg = str("The method ", text, " is deprecated, use ", alt_method, " instead.")
return _output_type(types.deprecated, msg) return _output_type(types.deprecated, msg)
func error(text): func error(text):
_output_type(types.error, text) _output_type(types.error, text)
func failed(text): func failed(text):
_output_type(types.failed, text) _output_type(types.failed, text)
func info(text): func info(text):
_output_type(types.info, text) _output_type(types.info, text)
func orphan(text): func orphan(text):
_output_type(types.orphan, text) _output_type(types.orphan, text)
func passed(text): func passed(text):
_output_type(types.passed, text) _output_type(types.passed, text)
func pending(text): func pending(text):
_output_type(types.pending, text) _output_type(types.pending, text)
func warn(text): func warn(text):
_output_type(types.warn, text) _output_type(types.warn, text)
func log(text='', fmt=fmts.none):
func log(text = "", fmt = fmts.none):
end_yield() end_yield()
if(text == ''): if text == "":
_output("\n") _output("\n")
else: else:
_log(text + "\n", fmt) _log(text + "\n", fmt)
return null return null
func lograw(text, fmt=fmts.none):
func lograw(text, fmt = fmts.none):
return _output(text, fmt) return _output(text, fmt)
# Print the test name if we aren't skipping names of tests that pass (basically # Print the test name if we aren't skipping names of tests that pass (basically
# what _less_test_names means)) # what _less_test_names means))
func log_test_name(): func log_test_name():
# suppress output if we haven't printed the test name yet and # suppress output if we haven't printed the test name yet and
# what to print is the test name. # what to print is the test name.
if(!_less_test_names): if !_less_test_names:
_print_test_name() _print_test_name()
# --------------- # ---------------
# Misc # Misc
# --------------- # ---------------
func get_gut(): func get_gut():
return _gut return _gut
func set_gut(gut): func set_gut(gut):
_gut = gut _gut = gut
if(_gut == null): if _gut == null:
_printers.gui = null _printers.gui = null
else: else:
if(_printers.gui == null): if _printers.gui == null:
_printers.gui = _utils.Printers.GutGuiPrinter.new() _printers.gui = _utils.Printers.GutGuiPrinter.new()
func get_indent_level(): func get_indent_level():
return _indent_level return _indent_level
func set_indent_level(indent_level): func set_indent_level(indent_level):
_indent_level = indent_level _indent_level = indent_level
func get_indent_string(): func get_indent_string():
return _indent_string return _indent_string
func set_indent_string(indent_string): func set_indent_string(indent_string):
_indent_string = indent_string _indent_string = indent_string
func clear(): func clear():
for key in _logs: for key in _logs:
_logs[key].clear() _logs[key].clear()
func inc_indent(): func inc_indent():
_indent_level += 1 _indent_level += 1
func dec_indent(): func dec_indent():
_indent_level = max(0, _indent_level -1) _indent_level = max(0, _indent_level - 1)
func is_type_enabled(type): func is_type_enabled(type):
return _type_data[type].enabled return _type_data[type].enabled
func set_type_enabled(type, is_enabled): func set_type_enabled(type, is_enabled):
_type_data[type].enabled = is_enabled _type_data[type].enabled = is_enabled
func get_less_test_names(): func get_less_test_names():
return _less_test_names return _less_test_names
func set_less_test_names(less_test_names): func set_less_test_names(less_test_names):
_less_test_names = less_test_names _less_test_names = less_test_names
func disable_printer(name, is_disabled): func disable_printer(name, is_disabled):
_printers[name].set_disabled(is_disabled) _printers[name].set_disabled(is_disabled)
func is_printer_disabled(name): func is_printer_disabled(name):
return _printers[name].get_disabled() return _printers[name].get_disabled()
func disable_formatting(is_disabled): func disable_formatting(is_disabled):
for key in _printers: for key in _printers:
_printers[key].set_format_enabled(!is_disabled) _printers[key].set_format_enabled(!is_disabled)
func disable_all_printers(is_disabled): func disable_all_printers(is_disabled):
for p in _printers: for p in _printers:
disable_printer(p, is_disabled) disable_printer(p, is_disabled)
func get_printer(printer_key): func get_printer(printer_key):
return _printers[printer_key] return _printers[printer_key]
func _yield_text_terminal(text): func _yield_text_terminal(text):
var printer = _printers['terminal'] var printer = _printers["terminal"]
if(_yield_calls != 0): if _yield_calls != 0:
printer.clear_line() printer.clear_line()
printer.back(_last_yield_text.length()) printer.back(_last_yield_text.length())
printer.send(text, fmts.yellow) printer.send(text, fmts.yellow)
func _end_yield_terminal(): func _end_yield_terminal():
var printer = _printers['terminal'] var printer = _printers["terminal"]
printer.clear_line() printer.clear_line()
printer.back(_last_yield_text.length()) printer.back(_last_yield_text.length())
func _yield_text_gui(text): func _yield_text_gui(text):
pass pass
# var lbl = _gut.get_gui().get_waiting_label() # var lbl = _gut.get_gui().get_waiting_label()
# lbl.visible = true # lbl.visible = true
# lbl.set_bbcode('[color=yellow]' + text + '[/color]') # lbl.set_bbcode('[color=yellow]' + text + '[/color]')
func _end_yield_gui(): func _end_yield_gui():
pass pass
# var lbl = _gut.get_gui().get_waiting_label() # var lbl = _gut.get_gui().get_waiting_label()
# lbl.visible = false # lbl.visible = false
# lbl.set_text('') # lbl.set_text('')
# This is used for displaying the "yield detected" and "yielding to" messages. # This is used for displaying the "yield detected" and "yielding to" messages.
func yield_msg(text): func yield_msg(text):
if(_type_data.warn.enabled): if _type_data.warn.enabled:
self.log(text, fmts.yellow) self.log(text, fmts.yellow)
# This is used for the animated "waiting" message # This is used for the animated "waiting" message
func yield_text(text): func yield_text(text):
_yield_text_terminal(text) _yield_text_terminal(text)
@ -352,14 +395,16 @@ func yield_text(text):
_last_yield_text = text _last_yield_text = text
_yield_calls += 1 _yield_calls += 1
# This is used for the animated "waiting" message # This is used for the animated "waiting" message
func end_yield(): func end_yield():
if(_yield_calls == 0): if _yield_calls == 0:
return return
_end_yield_terminal() _end_yield_terminal()
_end_yield_gui() _end_yield_gui()
_yield_calls = 0 _yield_calls = 0
_last_yield_text = '' _last_yield_text = ""
func get_gui_bbcode(): func get_gui_bbcode():
return _printers.gui.get_bbcode() return _printers.gui.get_bbcode()

View file

@ -2,7 +2,7 @@ class CallParameters:
var p_name = null var p_name = null
var default = null var default = null
func _init(n,d): func _init(n, d):
p_name = n p_name = n
default = d default = d
@ -26,9 +26,9 @@ class CallParameters:
# }] # }]
# default_args [] # default_args []
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
var _lgr = _utils.get_logger() var _lgr = _utils.get_logger()
const PARAM_PREFIX = 'p_' const PARAM_PREFIX = "p_"
# ------------------------------------------------------ # ------------------------------------------------------
# _supported_defaults # _supported_defaults
@ -40,26 +40,25 @@ const PARAM_PREFIX = 'p_'
# but things like Vectors and Colors do since only the parameters to create a # but things like Vectors and Colors do since only the parameters to create a
# new Vector or Color are included in the metadata. # new Vector or Color are included in the metadata.
# ------------------------------------------------------ # ------------------------------------------------------
# TYPE_NIL = 0 — Variable is of type nil (only applied for null). # TYPE_NIL = 0 — Variable is of type nil (only applied for null).
# TYPE_BOOL = 1 — Variable is of type bool. # TYPE_BOOL = 1 — Variable is of type bool.
# TYPE_INT = 2 — Variable is of type int. # TYPE_INT = 2 — Variable is of type int.
# TYPE_FLOAT = 3 — Variable is of type float/real. # TYPE_FLOAT = 3 — Variable is of type float/real.
# TYPE_STRING = 4 — Variable is of type String. # TYPE_STRING = 4 — Variable is of type String.
# TYPE_VECTOR2 = 5 — Variable is of type Vector2. # TYPE_VECTOR2 = 5 — Variable is of type Vector2.
# TYPE_RECT2 = 6 — Variable is of type Rect2. # TYPE_RECT2 = 6 — Variable is of type Rect2.
# TYPE_VECTOR3 = 7 — Variable is of type Vector3. # TYPE_VECTOR3 = 7 — Variable is of type Vector3.
# TYPE_COLOR = 14 — Variable is of type Color. # TYPE_COLOR = 14 — Variable is of type Color.
# TYPE_OBJECT = 17 — Variable is of type Object. # TYPE_OBJECT = 17 — Variable is of type Object.
# TYPE_DICTIONARY = 18 — Variable is of type Dictionary. # TYPE_DICTIONARY = 18 — Variable is of type Dictionary.
# TYPE_ARRAY = 19 — Variable is of type Array. # TYPE_ARRAY = 19 — Variable is of type Array.
# TYPE_PACKED_VECTOR2_ARRAY = 24 — Variable is of type PackedVector2Array. # TYPE_PACKED_VECTOR2_ARRAY = 24 — Variable is of type PackedVector2Array.
# TYPE_TRANSFORM3D = 13 — Variable is of type Transform3D. # TYPE_TRANSFORM3D = 13 — Variable is of type Transform3D.
# TYPE_TRANSFORM2D = 8 — Variable is of type Transform2D. # TYPE_TRANSFORM2D = 8 — Variable is of type Transform2D.
# TYPE_RID = 16 — Variable is of type RID. # TYPE_RID = 16 — Variable is of type RID.
# TYPE_PACKED_INT32_ARRAY = 21 — Variable is of type PackedInt32Array. # TYPE_PACKED_INT32_ARRAY = 21 — Variable is of type PackedInt32Array.
# TYPE_PACKED_FLOAT32_ARRAY = 22 — Variable is of type PackedFloat32Array. # TYPE_PACKED_FLOAT32_ARRAY = 22 — Variable is of type PackedFloat32Array.
# TYPE_PACKED_STRING_ARRAY = 23 — Variable is of type PackedStringArray. # TYPE_PACKED_STRING_ARRAY = 23 — Variable is of type PackedStringArray.
# TYPE_PLANE = 9 — Variable is of type Plane. # TYPE_PLANE = 9 — Variable is of type Plane.
# TYPE_QUATERNION = 10 — Variable is of type Quaternion. # TYPE_QUATERNION = 10 — Variable is of type Quaternion.
@ -73,48 +72,56 @@ const PARAM_PREFIX = 'p_'
# ------------------------------------------------------ # ------------------------------------------------------
var _supported_defaults = [] var _supported_defaults = []
func _init(): func _init():
for _i in range(TYPE_MAX): for _i in range(TYPE_MAX):
_supported_defaults.append(null) _supported_defaults.append(null)
# These types do not require a prefix for defaults # These types do not require a prefix for defaults
_supported_defaults[TYPE_NIL] = '' _supported_defaults[TYPE_NIL] = ""
_supported_defaults[TYPE_BOOL] = '' _supported_defaults[TYPE_BOOL] = ""
_supported_defaults[TYPE_INT] = '' _supported_defaults[TYPE_INT] = ""
_supported_defaults[TYPE_FLOAT] = '' _supported_defaults[TYPE_FLOAT] = ""
_supported_defaults[TYPE_OBJECT] = '' _supported_defaults[TYPE_OBJECT] = ""
_supported_defaults[TYPE_ARRAY] = '' _supported_defaults[TYPE_ARRAY] = ""
_supported_defaults[TYPE_STRING] = '' _supported_defaults[TYPE_STRING] = ""
_supported_defaults[TYPE_STRING_NAME] = '' _supported_defaults[TYPE_STRING_NAME] = ""
_supported_defaults[TYPE_DICTIONARY] = '' _supported_defaults[TYPE_DICTIONARY] = ""
_supported_defaults[TYPE_PACKED_VECTOR2_ARRAY] = '' _supported_defaults[TYPE_PACKED_VECTOR2_ARRAY] = ""
_supported_defaults[TYPE_RID] = '' _supported_defaults[TYPE_RID] = ""
# These require a prefix for whatever default is provided # These require a prefix for whatever default is provided
_supported_defaults[TYPE_VECTOR2] = 'Vector2' _supported_defaults[TYPE_VECTOR2] = "Vector2"
_supported_defaults[TYPE_VECTOR2I] = 'Vector2i' _supported_defaults[TYPE_VECTOR2I] = "Vector2i"
_supported_defaults[TYPE_RECT2] = 'Rect2' _supported_defaults[TYPE_RECT2] = "Rect2"
_supported_defaults[TYPE_RECT2I] = 'Rect2i' _supported_defaults[TYPE_RECT2I] = "Rect2i"
_supported_defaults[TYPE_VECTOR3] = 'Vector3' _supported_defaults[TYPE_VECTOR3] = "Vector3"
_supported_defaults[TYPE_COLOR] = 'Color' _supported_defaults[TYPE_COLOR] = "Color"
_supported_defaults[TYPE_TRANSFORM2D] = 'Transform2D' _supported_defaults[TYPE_TRANSFORM2D] = "Transform2D"
_supported_defaults[TYPE_TRANSFORM3D] = 'Transform3D' _supported_defaults[TYPE_TRANSFORM3D] = "Transform3D"
_supported_defaults[TYPE_PACKED_INT32_ARRAY] = 'PackedInt32Array' _supported_defaults[TYPE_PACKED_INT32_ARRAY] = "PackedInt32Array"
_supported_defaults[TYPE_PACKED_FLOAT32_ARRAY] = 'PackedFloat32Array' _supported_defaults[TYPE_PACKED_FLOAT32_ARRAY] = "PackedFloat32Array"
_supported_defaults[TYPE_PACKED_STRING_ARRAY] = 'PackedStringArray' _supported_defaults[TYPE_PACKED_STRING_ARRAY] = "PackedStringArray"
# ############### # ###############
# Private # Private
# ############### # ###############
var _func_text = _utils.get_file_as_text('res://addons/gut/double_templates/function_template.txt') var _func_text = _utils.get_file_as_text("res://addons/gut/double_templates/function_template.txt")
var _init_text = _utils.get_file_as_text('res://addons/gut/double_templates/init_template.txt') var _init_text = _utils.get_file_as_text("res://addons/gut/double_templates/init_template.txt")
func _is_supported_default(type_flag): func _is_supported_default(type_flag):
return type_flag >= 0 and type_flag < _supported_defaults.size() and _supported_defaults[type_flag] != null return (
type_flag >= 0
and type_flag < _supported_defaults.size()
and _supported_defaults[type_flag] != null
)
func _make_stub_default(method, index): func _make_stub_default(method, index):
return str('__gutdbl.default_val("', method, '",', index, ')') return str('__gutdbl.default_val("', method, '",', index, ")")
func _make_arg_array(method_meta, override_size): func _make_arg_array(method_meta, override_size):
var to_return = [] var to_return = []
@ -128,14 +135,14 @@ func _make_arg_array(method_meta, override_size):
to_return.append(CallParameters.new(PARAM_PREFIX + pname, dflt_text)) to_return.append(CallParameters.new(PARAM_PREFIX + pname, dflt_text))
# Add in extra parameters from stub settings. # Add in extra parameters from stub settings.
if(override_size != null): if override_size != null:
for i in range(method_meta.args.size(), override_size): for i in range(method_meta.args.size(), override_size):
var pname = str(PARAM_PREFIX, 'arg', i) var pname = str(PARAM_PREFIX, "arg", i)
print('-------- ', i, ' ', pname) print("-------- ", i, " ", pname)
var dflt_text = _make_stub_default(method_meta.name, i) var dflt_text = _make_stub_default(method_meta.name, i)
to_return.append(CallParameters.new(pname, dflt_text)) to_return.append(CallParameters.new(pname, dflt_text))
return [has_unsupported_defaults, to_return]; return [has_unsupported_defaults, to_return]
# Creates a list of parameters with defaults of null unless a default value is # Creates a list of parameters with defaults of null unless a default value is
@ -145,37 +152,37 @@ func _make_arg_array(method_meta, override_size):
# If a default is found that we don't know how to handle then this method will # If a default is found that we don't know how to handle then this method will
# return null. # return null.
func _get_arg_text(arg_array): func _get_arg_text(arg_array):
var text = '' var text = ""
for i in range(arg_array.size()): for i in range(arg_array.size()):
text += str(arg_array[i].p_name, '=', arg_array[i].default) text += str(arg_array[i].p_name, "=", arg_array[i].default)
if(i != arg_array.size() -1): if i != arg_array.size() - 1:
text += ', ' text += ", "
return text return text
# creates a call to the function in meta in the super's class. # creates a call to the function in meta in the super's class.
func _get_super_call_text(method_name, args, super_name=""): func _get_super_call_text(method_name, args, super_name = ""):
var params = '' var params = ""
for i in range(args.size()): for i in range(args.size()):
params += args[i].p_name params += args[i].p_name
if(i != args.size() -1): if i != args.size() - 1:
params += ', ' params += ", "
return str(super_name, 'await super(', params, ')') return str(super_name, "await super(", params, ")")
func _get_spy_call_parameters_text(args): func _get_spy_call_parameters_text(args):
var called_with = 'null' var called_with = "null"
if(args.size() > 0): if args.size() > 0:
called_with = '[' called_with = "["
for i in range(args.size()): for i in range(args.size()):
called_with += args[i].p_name called_with += args[i].p_name
if(i < args.size() - 1): if i < args.size() - 1:
called_with += ', ' called_with += ", "
called_with += ']' called_with += "]"
return called_with return called_with
@ -184,24 +191,26 @@ func _get_spy_call_parameters_text(args):
# Public # Public
# ############### # ###############
func _get_init_text(meta, args, method_params, param_array): func _get_init_text(meta, args, method_params, param_array):
var text = null var text = null
var decleration = str('func ', meta.name, '(', method_params, ')') var decleration = str("func ", meta.name, "(", method_params, ")")
var super_params = '' var super_params = ""
if(args.size() > 0): if args.size() > 0:
for i in range(args.size()): for i in range(args.size()):
super_params += args[i].p_name super_params += args[i].p_name
if(i != args.size() -1): if i != args.size() - 1:
super_params += ', ' super_params += ", "
text = _init_text.format(
text = _init_text.format({ {
"func_decleration":decleration, "func_decleration": decleration,
"super_params":super_params, "super_params": super_params,
"param_array":param_array, "param_array": param_array,
"method_name":meta.name "method_name": meta.name
}) }
)
return text return text
@ -212,47 +221,48 @@ func _get_init_text(meta, args, method_params, param_array):
# printed and the declaration will return null. # printed and the declaration will return null.
# #
# path is no longer used # path is no longer used
func get_function_text(meta, path=null, override_size=null, super_name=""): func get_function_text(meta, path = null, override_size = null, super_name = ""):
var method_params = '' var method_params = ""
var text = null var text = null
if(override_size != null): if override_size != null:
print('!!!!!! ', override_size) print("!!!!!! ", override_size)
var result = _make_arg_array(meta, override_size) var result = _make_arg_array(meta, override_size)
var has_unsupported = result[0] var has_unsupported = result[0]
var args = result[1] var args = result[1]
var param_array = _get_spy_call_parameters_text(args) var param_array = _get_spy_call_parameters_text(args)
if(has_unsupported): if has_unsupported:
# This will cause a runtime error. This is the most convenient way to # This will cause a runtime error. This is the most convenient way to
# to stop running before the error gets more obscure. _make_arg_array # to stop running before the error gets more obscure. _make_arg_array
# generates a gut error when unsupported defaults are found. # generates a gut error when unsupported defaults are found.
method_params = null method_params = null
else: else:
method_params = _get_arg_text(args); method_params = _get_arg_text(args)
if(param_array == 'null'): if param_array == "null":
param_array = '[]' param_array = "[]"
if(method_params != null): if method_params != null:
if(meta.name == '_init'): if meta.name == "_init":
text = _get_init_text(meta, args, method_params, param_array) text = _get_init_text(meta, args, method_params, param_array)
else: else:
var decleration = str('func ', meta.name, '(', method_params, '):') var decleration = str("func ", meta.name, "(", method_params, "):")
# decleration = str('# ', meta, "\n", decleration) # decleration = str('# ', meta, "\n", decleration)
text = _func_text.format({ text = _func_text.format(
"func_decleration":decleration, {
"method_name":meta.name, "func_decleration": decleration,
"param_array":param_array, "method_name": meta.name,
"super_call":_get_super_call_text(meta.name, args, super_name) "param_array": param_array,
}) "super_call": _get_super_call_text(meta.name, args, super_name)
}
)
return text return text
func get_logger(): func get_logger():
return _lgr return _lgr
func set_logger(logger): func set_logger(logger):
_lgr = logger _lgr = logger

View file

@ -5,34 +5,39 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
var _items = {} var _items = {}
# return the size of _items or the size of an element in _items if "one" was # return the size of _items or the size of an element in _items if "one" was
# specified. # specified.
func size(one=null): func size(one = null):
var to_return = 0 var to_return = 0
if(one == null): if one == null:
to_return = _items.size() to_return = _items.size()
elif(_items.has(one)): elif _items.has(one):
to_return = _items[one].size() to_return = _items[one].size()
return to_return return to_return
# Add an element to "one" if it does not already exist # Add an element to "one" if it does not already exist
func add(one, many_item): func add(one, many_item):
if(_items.has(one) and !_items[one].has(many_item)): if _items.has(one) and !_items[one].has(many_item):
_items[one].append(many_item) _items[one].append(many_item)
else: else:
_items[one] = [many_item] _items[one] = [many_item]
func clear(): func clear():
_items.clear() _items.clear()
func has(one, many_item): func has(one, many_item):
var to_return = false var to_return = false
if(_items.has(one)): if _items.has(one):
to_return = _items[one].has(many_item) to_return = _items[one].has(many_item)
return to_return return to_return
func to_s(): func to_s():
var to_return = '' var to_return = ""
for key in _items: for key in _items:
to_return += str(key, ": ", _items[key], "\n") to_return += str(key, ": ", _items[key], "\n")
return to_return return to_return

View file

@ -52,7 +52,7 @@ class CmdLineParser:
func _init(): func _init():
for i in range(OS.get_cmdline_args().size()): for i in range(OS.get_cmdline_args().size()):
var opt_val = OS.get_cmdline_args()[i].split('=') var opt_val = OS.get_cmdline_args()[i].split("=")
_opts.append(opt_val) _opts.append(opt_val)
# Parse out multiple comma delimited values from a command line # Parse out multiple comma delimited values from a command line
@ -60,13 +60,13 @@ class CmdLineParser:
# additional values are comma separated. # additional values are comma separated.
func _parse_array_value(full_option): func _parse_array_value(full_option):
var value = _parse_option_value(full_option) var value = _parse_option_value(full_option)
var split = value.split(',') var split = value.split(",")
return split return split
# Parse out the value of an option. Values are separated from # Parse out the value of an option. Values are separated from
# the option name with "=" # the option name with "="
func _parse_option_value(full_option): func _parse_option_value(full_option):
if(full_option.size() > 1): if full_option.size() > 1:
return full_option[1] return full_option[1]
else: else:
return null return null
@ -77,13 +77,13 @@ class CmdLineParser:
var found = false var found = false
var idx = 0 var idx = 0
while(idx < _opts.size() and !found): while idx < _opts.size() and !found:
if(_opts[idx][0] == name): if _opts[idx][0] == name:
found = true found = true
else: else:
idx += 1 idx += 1
if(found): if found:
return idx return idx
else: else:
return -1 return -1
@ -92,7 +92,7 @@ class CmdLineParser:
_used_options.append(option) _used_options.append(option)
var to_return = [] var to_return = []
var opt_loc = find_option(option) var opt_loc = find_option(option)
if(opt_loc != -1): if opt_loc != -1:
to_return = _parse_array_value(_opts[opt_loc]) to_return = _parse_array_value(_opts[opt_loc])
_opts.remove_at(opt_loc) _opts.remove_at(opt_loc)
@ -105,7 +105,7 @@ class CmdLineParser:
_used_options.append(option) _used_options.append(option)
var to_return = null var to_return = null
var opt_loc = find_option(option) var opt_loc = find_option(option)
if(opt_loc != -1): if opt_loc != -1:
to_return = _parse_option_value(_opts[opt_loc]) to_return = _parse_option_value(_opts[opt_loc])
_opts.remove_at(opt_loc) _opts.remove_at(opt_loc)
@ -133,42 +133,44 @@ class CmdLineParser:
to_return.remove_at(script_option + 1) to_return.remove_at(script_option + 1)
to_return.remove_at(script_option) to_return.remove_at(script_option)
while(_used_options.size() > 0): while _used_options.size() > 0:
var index = to_return.find(_used_options[0].split("=")[0]) var index = to_return.find(_used_options[0].split("=")[0])
if(index != -1): if index != -1:
to_return.remove_at(index) to_return.remove_at(index)
_used_options.remove_at(0) _used_options.remove_at(0)
return to_return return to_return
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# Simple class to hold a command line option # Simple class to hold a command line option
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
class Option: class Option:
var value = null var value = null
var option_name = '' var option_name = ""
var default = null var default = null
var description = '' var description = ""
func _init(name,default_value,desc=''): func _init(name, default_value, desc = ""):
option_name = name option_name = name
default = default_value default = default_value
description = desc description = desc
value = null#default_value value = null #default_value
func pad(to_pad, size, pad_with=' '): func pad(to_pad, size, pad_with = " "):
var to_return = to_pad var to_return = to_pad
for _i in range(to_pad.length(), size): for _i in range(to_pad.length(), size):
to_return += pad_with to_return += pad_with
return to_return return to_return
func to_s(min_space=0): func to_s(min_space = 0):
var subbed_desc = description var subbed_desc = description
if(subbed_desc.find('[default]') != -1): if subbed_desc.find("[default]") != -1:
subbed_desc = subbed_desc.replace('[default]', str(default)) subbed_desc = subbed_desc.replace("[default]", str(default))
return pad(option_name, min_space) + subbed_desc return pad(option_name, min_space) + subbed_desc
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# The high level interface between this script and the command line options # The high level interface between this script and the command line options
# supplied. Uses Option class and CmdLineParser to extract information from # supplied. Uses Option class and CmdLineParser to extract information from
@ -176,47 +178,53 @@ class Option:
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
var options = [] var options = []
var _opts = [] var _opts = []
var _banner = '' var _banner = ""
func add(name, default, desc): func add(name, default, desc):
options.append(Option.new(name, default, desc)) options.append(Option.new(name, default, desc))
func get_value(name): func get_value(name):
var found = false var found = false
var idx = 0 var idx = 0
while(idx < options.size() and !found): while idx < options.size() and !found:
if(options[idx].option_name == name): if options[idx].option_name == name:
found = true found = true
else: else:
idx += 1 idx += 1
if(found): if found:
return options[idx].value return options[idx].value
else: else:
print("COULD NOT FIND OPTION " + name) print("COULD NOT FIND OPTION " + name)
return null return null
func set_banner(banner): func set_banner(banner):
_banner = banner _banner = banner
func print_help(): func print_help():
var longest = 0 var longest = 0
for i in range(options.size()): for i in range(options.size()):
if(options[i].option_name.length() > longest): if options[i].option_name.length() > longest:
longest = options[i].option_name.length() longest = options[i].option_name.length()
print('---------------------------------------------------------') print("---------------------------------------------------------")
print(_banner) print(_banner)
print("\nOptions\n-------") print("\nOptions\n-------")
for i in range(options.size()): for i in range(options.size()):
print(' ' + options[i].to_s(longest + 2)) print(" " + options[i].to_s(longest + 2))
print('---------------------------------------------------------') print("---------------------------------------------------------")
func print_options(): func print_options():
for i in range(options.size()): for i in range(options.size()):
print(options[i].option_name + '=' + str(options[i].value)) print(options[i].option_name + "=" + str(options[i].value))
func parse(): func parse():
var parser = CmdLineParser.new() var parser = CmdLineParser.new()
@ -228,24 +236,30 @@ func parse():
# Without this check, you can't tell the difference between the # Without this check, you can't tell the difference between the
# defaults and what was specified, so you can't punch through # defaults and what was specified, so you can't punch through
# higher level options. # higher level options.
if(parser.was_specified(options[i].option_name)): if parser.was_specified(options[i].option_name):
if(t == TYPE_INT): if t == TYPE_INT:
options[i].value = int(parser.get_value(options[i].option_name)) options[i].value = int(parser.get_value(options[i].option_name))
elif(t == TYPE_STRING): elif t == TYPE_STRING:
options[i].value = parser.get_value(options[i].option_name) options[i].value = parser.get_value(options[i].option_name)
elif(t == TYPE_ARRAY): elif t == TYPE_ARRAY:
options[i].value = parser.get_array_value(options[i].option_name) options[i].value = parser.get_array_value(options[i].option_name)
elif(t == TYPE_BOOL): elif t == TYPE_BOOL:
options[i].value = parser.was_specified(options[i].option_name) options[i].value = parser.was_specified(options[i].option_name)
elif(t == TYPE_FLOAT): elif t == TYPE_FLOAT:
options[i].value = parser.get_value(options[i].option_name) options[i].value = parser.get_value(options[i].option_name)
elif(t == TYPE_NIL): elif t == TYPE_NIL:
print(options[i].option_name + ' cannot be processed, it has a nil datatype') print(options[i].option_name + " cannot be processed, it has a nil datatype")
else: else:
print(options[i].option_name + ' cannot be processed, it has unknown datatype:' + str(t)) print(
(
options[i].option_name
+ " cannot be processed, it has unknown datatype:"
+ str(t)
)
)
var unused = parser.get_unused_options() var unused = parser.get_unused_options()
if(unused.size() > 0): if unused.size() > 0:
print("Unrecognized options: ", unused) print("Unrecognized options: ", unused)
return false return false

View file

@ -33,23 +33,27 @@
# ############################################################################## # ##############################################################################
var _counters = {} var _counters = {}
func orphan_count(): func orphan_count():
return Performance.get_monitor(Performance.OBJECT_ORPHAN_NODE_COUNT) return Performance.get_monitor(Performance.OBJECT_ORPHAN_NODE_COUNT)
func add_counter(name): func add_counter(name):
_counters[name] = orphan_count() _counters[name] = orphan_count()
# Returns the number of orphans created since add_counter was last called for # Returns the number of orphans created since add_counter was last called for
# the name. Returns -1 to avoid blowing up with an invalid name but still # the name. Returns -1 to avoid blowing up with an invalid name but still
# be somewhat visible that we've done something wrong. # be somewhat visible that we've done something wrong.
func get_counter(name): func get_counter(name):
return orphan_count() - _counters[name] if _counters.has(name) else -1 return orphan_count() - _counters[name] if _counters.has(name) else -1
func print_orphans(name, lgr): func print_orphans(name, lgr):
var count = get_counter(name) var count = get_counter(name)
if(count > 0): if count > 0:
var o = 'orphan' var o = "orphan"
if(count > 1): if count > 1:
o = 'orphans' o = "orphans"
lgr.orphan(str(count, ' new ', o, ' in ', name, '.')) lgr.orphan(str(count, " new ", o, " in ", name, "."))

View file

@ -56,11 +56,11 @@ static func named_parameters(names, values):
var entry = {} var entry = {}
var parray = values[i] var parray = values[i]
if(typeof(parray) != TYPE_ARRAY): if typeof(parray) != TYPE_ARRAY:
parray = [values[i]] parray = [values[i]]
for j in range(names.size()): for j in range(names.size()):
if(j >= parray.size()): if j >= parray.size():
entry[names[j]] = null entry[names[j]] = null
else: else:
entry[names[j]] = parray[j] entry[names[j]] = parray[j]

View file

@ -1,37 +1,44 @@
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
var _params = null var _params = null
var _call_count = 0 var _call_count = 0
var _logger = null var _logger = null
func _init(params=null):
func _init(params = null):
_params = params _params = params
_logger = _utils.get_logger() _logger = _utils.get_logger()
if(typeof(_params) != TYPE_ARRAY): if typeof(_params) != TYPE_ARRAY:
_logger.error('You must pass an array to parameter_handler constructor.') _logger.error("You must pass an array to parameter_handler constructor.")
_params = null _params = null
func next_parameters(): func next_parameters():
_call_count += 1 _call_count += 1
return _params[_call_count -1] return _params[_call_count - 1]
func get_current_parameters(): func get_current_parameters():
return _params[_call_count] return _params[_call_count]
func is_done(): func is_done():
var done = true var done = true
if(_params != null): if _params != null:
done = _call_count == _params.size() done = _call_count == _params.size()
return done return done
func get_logger(): func get_logger():
return _logger return _logger
func set_logger(logger): func set_logger(logger):
_logger = logger _logger = logger
func get_call_count(): func get_call_count():
return _call_count return _call_count
func get_parameter_count(): func get_parameter_count():
return _params.size() return _params.size()

View file

@ -4,8 +4,8 @@
class Printer: class Printer:
var _format_enabled = true var _format_enabled = true
var _disabled = false var _disabled = false
var _printer_name = 'NOT SET' var _printer_name = "NOT SET"
var _show_name = false # used for debugging, set manually var _show_name = false # used for debugging, set manually
func get_format_enabled(): func get_format_enabled():
return _format_enabled return _format_enabled
@ -13,16 +13,16 @@ class Printer:
func set_format_enabled(format_enabled): func set_format_enabled(format_enabled):
_format_enabled = format_enabled _format_enabled = format_enabled
func send(text, fmt=null): func send(text, fmt = null):
if(_disabled): if _disabled:
return return
var formatted = text var formatted = text
if(fmt != null and _format_enabled): if fmt != null and _format_enabled:
formatted = format_text(text, fmt) formatted = format_text(text, fmt)
if(_show_name): if _show_name:
formatted = str('(', _printer_name, ')') + formatted formatted = str("(", _printer_name, ")") + formatted
_output(formatted) _output(formatted)
@ -41,6 +41,7 @@ class Printer:
func format_text(text, fmt): func format_text(text, fmt):
return text return text
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Responsible for sending text to a GUT gui. # Responsible for sending text to a GUT gui.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -48,20 +49,16 @@ class GutGuiPrinter:
extends Printer extends Printer
var _textbox = null var _textbox = null
var _colors = { var _colors = {red = Color.RED, yellow = Color.YELLOW, green = Color.GREEN}
red = Color.RED,
yellow = Color.YELLOW,
green = Color.GREEN
}
func _init(): func _init():
_printer_name = 'gui' _printer_name = "gui"
func _wrap_with_tag(text, tag): func _wrap_with_tag(text, tag):
return str('[', tag, ']', text, '[/', tag, ']') return str("[", tag, "]", text, "[/", tag, "]")
func _color_text(text, c_word): func _color_text(text, c_word):
return '[color=' + c_word + ']' + text + '[/color]' return "[color=" + c_word + "]" + text + "[/color]"
# Remember, we have to use push and pop because the output from the tests # Remember, we have to use push and pop because the output from the tests
# can contain [] in it which can mess up the formatting. There is no way # can contain [] in it which can mess up the formatting. There is no way
@ -80,14 +77,14 @@ class GutGuiPrinter:
# are in the output. Good luck, and I hope I typed enough to not go too # are in the output. Good luck, and I hope I typed enough to not go too
# far that rabbit hole before finding out it's not worth it. # far that rabbit hole before finding out it's not worth it.
func format_text(text, fmt): func format_text(text, fmt):
if(_textbox == null): if _textbox == null:
return return
if(fmt == 'bold'): if fmt == "bold":
_textbox.push_bold() _textbox.push_bold()
elif(fmt == 'underline'): elif fmt == "underline":
_textbox.push_underline() _textbox.push_underline()
elif(_colors.has(fmt)): elif _colors.has(fmt):
_textbox.push_color(_colors[fmt]) _textbox.push_color(_colors[fmt])
else: else:
# just pushing something to pop. # just pushing something to pop.
@ -96,10 +93,10 @@ class GutGuiPrinter:
_textbox.add_text(text) _textbox.add_text(text)
_textbox.pop() _textbox.pop()
return '' return ""
func _output(text): func _output(text):
if(_textbox == null): if _textbox == null:
return return
_textbox.add_text(text) _textbox.add_text(text)
@ -121,6 +118,7 @@ class GutGuiPrinter:
func get_disabled(): func get_disabled():
return _disabled and _textbox != null return _disabled and _textbox != null
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# This AND TerminalPrinter should not be enabled at the same time since it will # This AND TerminalPrinter should not be enabled at the same time since it will
# result in duplicate output. printraw does not print to the console so i had # result in duplicate output. printraw does not print to the console so i had
@ -128,20 +126,21 @@ class GutGuiPrinter:
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class ConsolePrinter: class ConsolePrinter:
extends Printer extends Printer
var _buffer = '' var _buffer = ""
func _init(): func _init():
_printer_name = 'console' _printer_name = "console"
# suppresses output until it encounters a newline to keep things # suppresses output until it encounters a newline to keep things
# inline as much as possible. # inline as much as possible.
func _output(text): func _output(text):
if(text.ends_with("\n")): if text.ends_with("\n"):
print(_buffer + text.left(text.length() -1)) print(_buffer + text.left(text.length() - 1))
_buffer = '' _buffer = ""
else: else:
_buffer += text _buffer += text
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Prints text to terminal, formats some words. # Prints text to terminal, formats some words.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -149,21 +148,18 @@ class TerminalPrinter:
extends Printer extends Printer
var escape = PackedByteArray([0x1b]).get_string_from_ascii() var escape = PackedByteArray([0x1b]).get_string_from_ascii()
var cmd_colors = { var cmd_colors = {
red = escape + '[31m', red = escape + "[31m",
yellow = escape + '[33m', yellow = escape + "[33m",
green = escape + '[32m', green = escape + "[32m",
underline = escape + "[4m",
underline = escape + '[4m', bold = escape + "[1m",
bold = escape + '[1m', default = escape + "[0m",
clear_line = escape + "[2K"
default = escape + '[0m',
clear_line = escape + '[2K'
} }
func _init(): func _init():
_printer_name = 'terminal' _printer_name = "terminal"
func _output(text): func _output(text):
# Note, printraw does not print to the console. # Note, printraw does not print to the console.
@ -176,7 +172,7 @@ class TerminalPrinter:
send(cmd_colors.clear_line) send(cmd_colors.clear_line)
func back(n): func back(n):
send(escape + str('[', n, 'D')) send(escape + str("[", n, "D"))
func forward(n): func forward(n):
send(escape + str('[', n, 'C')) send(escape + str("[", n, "C"))

View file

@ -4,56 +4,62 @@
# of a run and exporting it in a specific format. This can also serve as a # of a run and exporting it in a specific format. This can also serve as a
# unofficial GUT export format. # unofficial GUT export format.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
var json = JSON.new() var json = JSON.new()
func _export_tests(summary_script): func _export_tests(summary_script):
var to_return = {} var to_return = {}
var tests = summary_script.get_tests() var tests = summary_script.get_tests()
for key in tests.keys(): for key in tests.keys():
to_return[key] = { to_return[key] = {
"status":tests[key].get_status(), "status": tests[key].get_status(),
"passing":tests[key].pass_texts, "passing": tests[key].pass_texts,
"failing":tests[key].fail_texts, "failing": tests[key].fail_texts,
"pending":tests[key].pending_texts, "pending": tests[key].pending_texts,
"orphans":tests[key].orphans "orphans": tests[key].orphans
} }
return to_return return to_return
# TODO # TODO
# errors # errors
func _export_scripts(summary): func _export_scripts(summary):
if(summary == null): if summary == null:
return {} return {}
var scripts = {} var scripts = {}
for s in summary.get_scripts(): for s in summary.get_scripts():
scripts[s.name] = { scripts[s.name] = {
'props':{ "props":
"tests":s._tests.size(), {
"pending":s.get_pending_count(), "tests": s._tests.size(),
"failures":s.get_fail_count(), "pending": s.get_pending_count(),
"failures": s.get_fail_count(),
}, },
"tests":_export_tests(s) "tests": _export_tests(s)
} }
return scripts return scripts
func _make_results_dict(): func _make_results_dict():
var result = { var result = {
'test_scripts':{ "test_scripts":
"props":{ {
"pending":0, "props":
"failures":0, {
"passing":0, "pending": 0,
"tests":0, "failures": 0,
"time":0, "passing": 0,
"orphans":0, "tests": 0,
"errors":0, "time": 0,
"warnings":0 "orphans": 0,
"errors": 0,
"warnings": 0
}, },
"scripts":[] "scripts": []
} }
} }
return result return result
@ -62,15 +68,15 @@ func _make_results_dict():
# TODO # TODO
# time # time
# errors # errors
func get_results_dictionary(gut, include_scripts=true): func get_results_dictionary(gut, include_scripts = true):
var summary = gut.get_summary() var summary = gut.get_summary()
var scripts = [] var scripts = []
if(include_scripts): if include_scripts:
scripts = _export_scripts(summary) scripts = _export_scripts(summary)
var result = _make_results_dict() var result = _make_results_dict()
if(summary != null): if summary != null:
var totals = summary.get_totals() var totals = summary.get_totals()
var props = result.test_scripts.props var props = result.test_scripts.props
@ -80,8 +86,8 @@ func get_results_dictionary(gut, include_scripts=true):
props.tests = totals.tests props.tests = totals.tests
props.errors = gut.logger.get_errors().size() props.errors = gut.logger.get_errors().size()
props.warnings = gut.logger.get_warnings().size() props.warnings = gut.logger.get_warnings().size()
props.time = gut.get_elapsed_time() props.time = gut.get_elapsed_time()
props.orphans = gut.get_orphan_counter().get_counter('total') props.orphans = gut.get_orphan_counter().get_counter("total")
result.test_scripts.scripts = scripts result.test_scripts.scripts = scripts
return result return result
@ -89,23 +95,22 @@ func get_results_dictionary(gut, include_scripts=true):
func write_json_file(gut, path): func write_json_file(gut, path):
var dict = get_results_dictionary(gut) var dict = get_results_dictionary(gut)
var json_text = json.stringify(dict, ' ') var json_text = json.stringify(dict, " ")
var f_result = _utils.write_file(path, json_text) var f_result = _utils.write_file(path, json_text)
if(f_result != OK): if f_result != OK:
var msg = str("Error: ", f_result, ". Could not create export file ", path) var msg = str("Error: ", f_result, ". Could not create export file ", path)
_utils.get_logger().error(msg) _utils.get_logger().error(msg)
return f_result return f_result
func write_summary_file(gut, path): func write_summary_file(gut, path):
var dict = get_results_dictionary(gut, false) var dict = get_results_dictionary(gut, false)
var json_text = json.stringify(dict, ' ') var json_text = json.stringify(dict, " ")
var f_result = _utils.write_file(path, json_text) var f_result = _utils.write_file(path, json_text)
if(f_result != OK): if f_result != OK:
var msg = str("Error: ", f_result, ". Could not create export file ", path) var msg = str("Error: ", f_result, ". Could not create export file ", path)
_utils.get_logger().error(msg) _utils.get_logger().error(msg)

View file

@ -4,27 +4,26 @@
# overloaded or do not have a "super" equivalent so we can't just pass # overloaded or do not have a "super" equivalent so we can't just pass
# through. # through.
const BLACKLIST = [ const BLACKLIST = [
'_draw', "_draw",
'_enter_tree', "_enter_tree",
'_exit_tree', "_exit_tree",
'_get_minimum_size', # Nonexistent function _get_minimum_size "_get_minimum_size", # Nonexistent function _get_minimum_size
'_get', # probably "_get", # probably
'_input', "_input",
'_notification', "_notification",
'_physics_process', "_physics_process",
'_process', "_process",
'_set', "_set",
'_to_string', # nonexistant function super._to_string "_to_string", # nonexistant function super._to_string
'_unhandled_input', "_unhandled_input",
'_unhandled_key_input', "_unhandled_key_input",
'draw_mesh', # issue with one parameter, value is `Null((..), (..), (..))`` "draw_mesh", # issue with one parameter, value is `Null((..), (..), (..))``
'emit_signal', # can't handle extra parameters to be sent with signal. "emit_signal", # can't handle extra parameters to be sent with signal.
'get_path', "get_path",
'get_script', "get_script",
'get', "get",
'has_method', "has_method",
"print_orphan_nodes"
'print_orphan_nodes'
] ]
@ -36,14 +35,16 @@ const BLACKLIST = [
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class ParsedMethod: class ParsedMethod:
var _meta = {} var _meta = {}
var meta = _meta : var meta = _meta:
get: return _meta get:
set(val): return; return _meta
set(val):
return
var _parameters = [] var _parameters = []
var is_local = false var is_local = false
const NO_DEFAULT = '__no__default__' const NO_DEFAULT = "__no__default__"
func _init(metadata): func _init(metadata):
_meta = metadata _meta = metadata
@ -52,39 +53,35 @@ class ParsedMethod:
var arg = _meta.args[i] var arg = _meta.args[i]
# Add a "default" property to the metadata so we don't have to do # Add a "default" property to the metadata so we don't have to do
# weird default position math again. # weird default position math again.
if(i >= start_default): if i >= start_default:
arg['default'] = _meta.default_args[start_default - i] arg["default"] = _meta.default_args[start_default - i]
else: else:
arg['default'] = NO_DEFAULT arg["default"] = NO_DEFAULT
_parameters.append(arg) _parameters.append(arg)
func is_black_listed(): func is_black_listed():
return BLACKLIST.find(_meta.name) != -1 return BLACKLIST.find(_meta.name) != -1
func to_s(): func to_s():
var s = _meta.name + "(" var s = _meta.name + "("
for i in range(_meta.args.size()): for i in range(_meta.args.size()):
var arg = _meta.args[i] var arg = _meta.args[i]
if(str(arg.default) != NO_DEFAULT): if str(arg.default) != NO_DEFAULT:
var val = str(arg.default) var val = str(arg.default)
if(val == ''): if val == "":
val = '""' val = '""'
s += str(arg.name, ' = ', val) s += str(arg.name, " = ", val)
else: else:
s += str(arg.name) s += str(arg.name)
if(i != _meta.args.size() -1): if i != _meta.args.size() - 1:
s += ', ' s += ", "
s += ")" s += ")"
return s return s
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Doesn't know if a method is local and in super, but not sure if that will # Doesn't know if a method is local and in super, but not sure if that will
# ever matter. # ever matter.
@ -92,111 +89,114 @@ class ParsedMethod:
class ParsedScript: class ParsedScript:
# All methods indexed by name. # All methods indexed by name.
var _methods_by_name = {} var _methods_by_name = {}
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
var _script_path = null var _script_path = null
var script_path = _script_path : var script_path = _script_path:
get: return _script_path get:
set(val): return; return _script_path
set(val):
return
var _subpath = null var _subpath = null
var subpath = null : var subpath = null:
get: return _subpath get:
set(val): return; return _subpath
set(val):
return
var _resource = null var _resource = null
var resource = null : var resource = null:
get: return _resource get:
set(val): return; return _resource
set(val):
return
var _native_instance = null var _native_instance = null
var is_native = false : var is_native = false:
get: return _native_instance != null get:
set(val): return; return _native_instance != null
set(val):
return
func unreference(): func unreference():
if(_native_instance != null): if _native_instance != null:
_native_instance.free() _native_instance.free()
return super() return super()
func _init(script_or_inst, inner_class = null):
func _init(script_or_inst, inner_class=null):
var to_load = script_or_inst var to_load = script_or_inst
if(_utils.is_native_class(to_load)): if _utils.is_native_class(to_load):
_resource = to_load _resource = to_load
_native_instance = to_load.new() _native_instance = to_load.new()
else: else:
if(!script_or_inst is Resource): if !script_or_inst is Resource:
to_load = load(script_or_inst.get_script().get_path()) to_load = load(script_or_inst.get_script().get_path())
_script_path = to_load.resource_path _script_path = to_load.resource_path
if(inner_class != null): if inner_class != null:
_subpath = _find_subpath(to_load, inner_class) _subpath = _find_subpath(to_load, inner_class)
if(inner_class == null): if inner_class == null:
_resource = to_load _resource = to_load
else: else:
_resource = inner_class _resource = inner_class
to_load = inner_class to_load = inner_class
_parse_methods(to_load) _parse_methods(to_load)
func _has_flag_to_be_ignored(flags): func _has_flag_to_be_ignored(flags):
return false return false
# I think this is getting anything that has the 1 flag set...I think # I think this is getting anything that has the 1 flag set...I think
return flags & (1 << 2) == 0 && \ return flags & (1 << 2) == 0 && flags & (1 << 4) == 0 && flags & (1 << 6) == 0
flags & (1 << 4) == 0 && \
flags & (1 << 6) == 0
func _print_flags(meta): func _print_flags(meta):
print(str(meta.name, ':').rpad(30), str(meta.flags).rpad(4), ' = ', _utils.dec2bistr(meta.flags, 10)) print(
str(meta.name, ":").rpad(30),
str(meta.flags).rpad(4),
" = ",
_utils.dec2bistr(meta.flags, 10)
)
func _get_native_methods(base_type): func _get_native_methods(base_type):
var to_return = [] var to_return = []
if(base_type != null): if base_type != null:
var source = str('extends ', base_type) var source = str("extends ", base_type)
var inst = _utils.create_script_from_source(source).new() var inst = _utils.create_script_from_source(source).new()
to_return = inst.get_method_list() to_return = inst.get_method_list()
if(! inst is RefCounted): if !inst is RefCounted:
inst.free() inst.free()
return to_return return to_return
func _parse_methods(thing): func _parse_methods(thing):
var methods = [] var methods = []
if(is_native): if is_native:
methods = _native_instance.get_method_list() methods = _native_instance.get_method_list()
else: else:
var base_type = thing.get_instance_base_type() var base_type = thing.get_instance_base_type()
methods = _get_native_methods(base_type) methods = _get_native_methods(base_type)
for m in methods: for m in methods:
if(!_has_flag_to_be_ignored(m.flags)): if !_has_flag_to_be_ignored(m.flags):
var parsed = ParsedMethod.new(m) var parsed = ParsedMethod.new(m)
_methods_by_name[m.name] = parsed _methods_by_name[m.name] = parsed
# _init must always be included so that we can initialize # _init must always be included so that we can initialize
# double_tools # double_tools
if(m.name == '_init'): if m.name == "_init":
parsed.is_local = true parsed.is_local = true
# This loop will overwrite all entries in _methods_by_name with the local # This loop will overwrite all entries in _methods_by_name with the local
# method object so there is only ever one listing for a function with # method object so there is only ever one listing for a function with
# the right "is_local" flag. # the right "is_local" flag.
if(!is_native): if !is_native:
methods = thing.get_script_method_list() methods = thing.get_script_method_list()
for m in methods: for m in methods:
var parsed_method = ParsedMethod.new(m) var parsed_method = ParsedMethod.new(m)
parsed_method.is_local = true parsed_method.is_local = true
_methods_by_name[m.name] = parsed_method _methods_by_name[m.name] = parsed_method
func _find_subpath(parent_script, inner): func _find_subpath(parent_script, inner):
var const_map = parent_script.get_script_constant_map() var const_map = parent_script.get_script_constant_map()
var consts = const_map.keys() var consts = const_map.keys()
@ -204,115 +204,106 @@ class ParsedScript:
var found = false var found = false
var to_return = null var to_return = null
while(const_idx < consts.size() and !found): while const_idx < consts.size() and !found:
var key = consts[const_idx] var key = consts[const_idx]
var const_val = const_map[key] var const_val = const_map[key]
if(typeof(const_val) == TYPE_OBJECT): if typeof(const_val) == TYPE_OBJECT:
if(const_val == inner): if const_val == inner:
found = true found = true
to_return = key to_return = key
else: else:
to_return = _find_subpath(const_val, inner) to_return = _find_subpath(const_val, inner)
if(to_return != null): if to_return != null:
to_return = str(key, '.', to_return) to_return = str(key, ".", to_return)
found = true found = true
const_idx += 1 const_idx += 1
return to_return return to_return
func get_method(name): func get_method(name):
return _methods_by_name[name] return _methods_by_name[name]
func is_method_blacklisted(m_name): func is_method_blacklisted(m_name):
if(_methods_by_name.has(m_name)): if _methods_by_name.has(m_name):
return _methods_by_name[m_name].is_black_listed() return _methods_by_name[m_name].is_black_listed()
func get_super_method(name): func get_super_method(name):
var to_return = get_method(name) var to_return = get_method(name)
if(to_return.is_local): if to_return.is_local:
to_return = null to_return = null
return to_return return to_return
func get_local_method(name): func get_local_method(name):
var to_return = get_method(name) var to_return = get_method(name)
if(!to_return.is_local): if !to_return.is_local:
to_return = null to_return = null
return to_return return to_return
func get_sorted_method_names(): func get_sorted_method_names():
var keys = _methods_by_name.keys() var keys = _methods_by_name.keys()
keys.sort() keys.sort()
return keys return keys
func get_local_method_names(): func get_local_method_names():
var names = [] var names = []
for method in _methods_by_name: for method in _methods_by_name:
if(_methods_by_name[method].is_local): if _methods_by_name[method].is_local:
names.append(method) names.append(method)
return names return names
func get_super_method_names(): func get_super_method_names():
var names = [] var names = []
for method in _methods_by_name: for method in _methods_by_name:
if(!_methods_by_name[method].is_local): if !_methods_by_name[method].is_local:
names.append(method) names.append(method)
return names return names
func get_local_methods(): func get_local_methods():
var to_return = [] var to_return = []
for key in _methods_by_name: for key in _methods_by_name:
var method = _methods_by_name[key] var method = _methods_by_name[key]
if(method.is_local): if method.is_local:
to_return.append(method) to_return.append(method)
return to_return return to_return
func get_super_methods(): func get_super_methods():
var to_return = [] var to_return = []
for key in _methods_by_name: for key in _methods_by_name:
var method = _methods_by_name[key] var method = _methods_by_name[key]
if(!method.is_local): if !method.is_local:
to_return.append(method) to_return.append(method)
return to_return return to_return
func get_extends_text(): func get_extends_text():
var text = null var text = null
if(is_native): if is_native:
text = str("extends ", _native_instance.get_class()) text = str("extends ", _native_instance.get_class())
else: else:
text = str("extends '", _script_path, "'") text = str("extends '", _script_path, "'")
if(_subpath != null): if _subpath != null:
text += '.' + _subpath text += "." + _subpath
return text return text
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
var scripts = {} var scripts = {}
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
func _get_instance_id(thing): func _get_instance_id(thing):
var inst_id = null var inst_id = null
if(_utils.is_native_class(thing)): if _utils.is_native_class(thing):
var id_str = str(thing).replace("<", '').replace(">", '').split('#')[1] var id_str = str(thing).replace("<", "").replace(">", "").split("#")[1]
inst_id = id_str.to_int() inst_id = id_str.to_int()
elif(typeof(thing) == TYPE_STRING): elif typeof(thing) == TYPE_STRING:
if(FileAccess.file_exists(thing)): if FileAccess.file_exists(thing):
inst_id = load(thing).get_instance_id() inst_id = load(thing).get_instance_id()
else: else:
inst_id = thing.get_instance_id() inst_id = thing.get_instance_id()
@ -320,27 +311,26 @@ func _get_instance_id(thing):
return inst_id return inst_id
func parse(thing, inner_thing=null): func parse(thing, inner_thing = null):
var key = -1 var key = -1
if(inner_thing == null): if inner_thing == null:
key = _get_instance_id(thing) key = _get_instance_id(thing)
else: else:
key = _get_instance_id(inner_thing) key = _get_instance_id(inner_thing)
var parsed = null var parsed = null
if(key != null): if key != null:
if(scripts.has(key)): if scripts.has(key):
parsed = scripts[key] parsed = scripts[key]
else: else:
var obj = instance_from_id(_get_instance_id(thing)) var obj = instance_from_id(_get_instance_id(thing))
var inner = null var inner = null
if(inner_thing != null): if inner_thing != null:
inner = instance_from_id(_get_instance_id(inner_thing)) inner = instance_from_id(_get_instance_id(inner_thing))
if(obj is Resource or _utils.is_native_class(obj)): if obj is Resource or _utils.is_native_class(obj):
parsed = ParsedScript.new(obj, inner) parsed = ParsedScript.new(obj, inner)
scripts[key] = parsed scripts[key] = parsed
return parsed return parsed

View file

@ -26,7 +26,7 @@
# Some arbitrary string that should never show up by accident. If it does, then # Some arbitrary string that should never show up by accident. If it does, then
# shame on you. # shame on you.
const ARG_NOT_SET = '_*_argument_*_is_*_not_set_*_' const ARG_NOT_SET = "_*_argument_*_is_*_not_set_*_"
# This hash holds the objects that are being watched, the signals that are being # This hash holds the objects that are being watched, the signals that are being
# watched, and an array of arrays that contains arguments that were passed # watched, and an array of arrays that contains arguments that were passed
@ -52,19 +52,21 @@ const ARG_NOT_SET = '_*_argument_*_is_*_not_set_*_'
# - some_signal on ref2 was never emitted. # - some_signal on ref2 was never emitted.
# - other_signal on ref2 was emitted 3 times, each time with 3 parameters. # - other_signal on ref2 was emitted 3 times, each time with 3 parameters.
var _watched_signals = {} var _watched_signals = {}
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
var _lgr = _utils.get_logger() var _lgr = _utils.get_logger()
func _add_watched_signal(obj, name): func _add_watched_signal(obj, name):
# SHORTCIRCUIT - ignore dupes # SHORTCIRCUIT - ignore dupes
if(_watched_signals.has(obj) and _watched_signals[obj].has(name)): if _watched_signals.has(obj) and _watched_signals[obj].has(name):
return return
if(!_watched_signals.has(obj)): if !_watched_signals.has(obj):
_watched_signals[obj] = {name:[]} _watched_signals[obj] = {name: []}
else: else:
_watched_signals[obj][name] = [] _watched_signals[obj][name] = []
obj.connect(name,Callable(self,'_on_watched_signal').bind(obj,name)) obj.connect(name, Callable(self, "_on_watched_signal").bind(obj, name))
# This handles all the signals that are watched. It supports up to 9 parameters # This handles all the signals that are watched. It supports up to 9 parameters
# which could be emitted by the signal and the two parameters used when it is # which could be emitted by the signal and the two parameters used when it is
@ -75,39 +77,53 @@ func _add_watched_signal(obj, name):
# Based on the documentation of emit_signal, it appears you can only pass up # Based on the documentation of emit_signal, it appears you can only pass up
# to 4 parameters when firing a signal. I haven't verified this, but this should # to 4 parameters when firing a signal. I haven't verified this, but this should
# future proof this some if the value ever grows. # future proof this some if the value ever grows.
func _on_watched_signal(arg1=ARG_NOT_SET, arg2=ARG_NOT_SET, arg3=ARG_NOT_SET, \ func _on_watched_signal(
arg4=ARG_NOT_SET, arg5=ARG_NOT_SET, arg6=ARG_NOT_SET, \ arg1 = ARG_NOT_SET,
arg7=ARG_NOT_SET, arg8=ARG_NOT_SET, arg9=ARG_NOT_SET, \ arg2 = ARG_NOT_SET,
arg10=ARG_NOT_SET, arg11=ARG_NOT_SET): arg3 = ARG_NOT_SET,
arg4 = ARG_NOT_SET,
arg5 = ARG_NOT_SET,
arg6 = ARG_NOT_SET,
arg7 = ARG_NOT_SET,
arg8 = ARG_NOT_SET,
arg9 = ARG_NOT_SET,
arg10 = ARG_NOT_SET,
arg11 = ARG_NOT_SET
):
var args = [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11] var args = [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11]
# strip off any unused vars. # strip off any unused vars.
var idx = args.size() -1 var idx = args.size() - 1
while(str(args[idx]) == ARG_NOT_SET): while str(args[idx]) == ARG_NOT_SET:
args.remove_at(idx) args.remove_at(idx)
idx -= 1 idx -= 1
# retrieve object and signal name from the array and remove_at them. These # retrieve object and signal name from the array and remove_at them. These
# will always be at the end since they are added when the connect happens. # will always be at the end since they are added when the connect happens.
var signal_name = args[args.size() -1] var signal_name = args[args.size() - 1]
args.pop_back() args.pop_back()
var object = args[args.size() -1] var object = args[args.size() - 1]
args.pop_back() args.pop_back()
if(_watched_signals.has(object)): if _watched_signals.has(object):
_watched_signals[object][signal_name].append(args) _watched_signals[object][signal_name].append(args)
else: else:
_lgr.error(str("signal_watcher._on_watched_signal: Got signal for unwatched object: ", object, '::', signal_name)) _lgr.error(
str(
"signal_watcher._on_watched_signal: Got signal for unwatched object: ",
object,
"::",
signal_name
)
)
# This parameter stuff should go into test.gd not here. This thing works # This parameter stuff should go into test.gd not here. This thing works
# just fine the way it is. # just fine the way it is.
func _obj_name_pair(obj_or_signal, signal_name=null): func _obj_name_pair(obj_or_signal, signal_name = null):
var to_return = { var to_return = {"object": obj_or_signal, "signal_name": signal_name}
'object' : obj_or_signal, if obj_or_signal is Signal:
'signal_name' : signal_name to_return.object = obj_or_signal.get_object()
}
if(obj_or_signal is Signal):
to_return.object = obj_or_signal.get_object()
to_return.signal_name = obj_or_signal.get_name() to_return.signal_name = obj_or_signal.get_name()
return to_return return to_return
@ -116,72 +132,82 @@ func _obj_name_pair(obj_or_signal, signal_name=null):
func does_object_have_signal(object, signal_name): func does_object_have_signal(object, signal_name):
var signals = object.get_signal_list() var signals = object.get_signal_list()
for i in range(signals.size()): for i in range(signals.size()):
if(signals[i]['name'] == signal_name): if signals[i]["name"] == signal_name:
return true return true
return false return false
func watch_signals(object): func watch_signals(object):
var signals = object.get_signal_list() var signals = object.get_signal_list()
for i in range(signals.size()): for i in range(signals.size()):
_add_watched_signal(object, signals[i]['name']) _add_watched_signal(object, signals[i]["name"])
func watch_signal(object, signal_name): func watch_signal(object, signal_name):
var did = false var did = false
if(does_object_have_signal(object, signal_name)): if does_object_have_signal(object, signal_name):
_add_watched_signal(object, signal_name) _add_watched_signal(object, signal_name)
did = true did = true
else: else:
_utils.get_logger().warn(str(object, ' does not have signal ', signal_name)) _utils.get_logger().warn(str(object, " does not have signal ", signal_name))
return did return did
func get_emit_count(object, signal_name): func get_emit_count(object, signal_name):
var to_return = -1 var to_return = -1
if(is_watching(object, signal_name)): if is_watching(object, signal_name):
to_return = _watched_signals[object][signal_name].size() to_return = _watched_signals[object][signal_name].size()
return to_return return to_return
func did_emit(object, signal_name=null):
func did_emit(object, signal_name = null):
var vals = _obj_name_pair(object, signal_name) var vals = _obj_name_pair(object, signal_name)
var did = false var did = false
if(is_watching(vals.object, vals.signal_name)): if is_watching(vals.object, vals.signal_name):
did = get_emit_count(vals.object, vals.signal_name) != 0 did = get_emit_count(vals.object, vals.signal_name) != 0
return did return did
func print_object_signals(object): func print_object_signals(object):
var list = object.get_signal_list() var list = object.get_signal_list()
for i in range(list.size()): for i in range(list.size()):
print(list[i].name, "\n ", list[i]) print(list[i].name, "\n ", list[i])
func get_signal_parameters(object, signal_name, index=-1):
func get_signal_parameters(object, signal_name, index = -1):
var params = null var params = null
if(is_watching(object, signal_name)): if is_watching(object, signal_name):
var all_params = _watched_signals[object][signal_name] var all_params = _watched_signals[object][signal_name]
if(all_params.size() > 0): if all_params.size() > 0:
if(index == -1): if index == -1:
index = all_params.size() -1 index = all_params.size() - 1
params = all_params[index] params = all_params[index]
return params return params
func is_watching_object(object): func is_watching_object(object):
return _watched_signals.has(object) return _watched_signals.has(object)
func is_watching(object, signal_name): func is_watching(object, signal_name):
return _watched_signals.has(object) and _watched_signals[object].has(signal_name) return _watched_signals.has(object) and _watched_signals[object].has(signal_name)
func clear(): func clear():
for obj in _watched_signals: for obj in _watched_signals:
if(_utils.is_not_freed(obj)): if _utils.is_not_freed(obj):
for signal_name in _watched_signals[obj]: for signal_name in _watched_signals[obj]:
obj.disconnect(signal_name, Callable(self,'_on_watched_signal')) obj.disconnect(signal_name, Callable(self, "_on_watched_signal"))
_watched_signals.clear() _watched_signals.clear()
# Returns a list of all the signal names that were emitted by the object. # Returns a list of all the signal names that were emitted by the object.
# If the object is not being watched then an empty list is returned. # If the object is not being watched then an empty list is returned.
func get_signals_emitted(obj): func get_signals_emitted(obj):
var emitted = [] var emitted = []
if(is_watching_object(obj)): if is_watching_object(obj):
for signal_name in _watched_signals[obj]: for signal_name in _watched_signals[obj]:
if(_watched_signals[obj][signal_name].size() > 0): if _watched_signals[obj][signal_name].size() > 0:
emitted.append(signal_name) emitted.append(signal_name)
return emitted return emitted

View file

@ -9,100 +9,119 @@
# }, # },
# } # }
var _calls = {} var _calls = {}
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
var _lgr = _utils.get_logger() var _lgr = _utils.get_logger()
var _compare = _utils.Comparator.new() var _compare = _utils.Comparator.new()
func _find_parameters(call_params, params_to_find): func _find_parameters(call_params, params_to_find):
var found = false var found = false
var idx = 0 var idx = 0
while(idx < call_params.size() and !found): while idx < call_params.size() and !found:
var result = _compare.deep(call_params[idx], params_to_find) var result = _compare.deep(call_params[idx], params_to_find)
if(result.are_equal): if result.are_equal:
found = true found = true
else: else:
idx += 1 idx += 1
return found return found
func _get_params_as_string(params): func _get_params_as_string(params):
var to_return = '' var to_return = ""
if(params == null): if params == null:
return '' return ""
for i in range(params.size()): for i in range(params.size()):
if(params[i] == null): if params[i] == null:
to_return += 'null' to_return += "null"
else: else:
if(typeof(params[i]) == TYPE_STRING): if typeof(params[i]) == TYPE_STRING:
to_return += str('"', params[i], '"') to_return += str('"', params[i], '"')
else: else:
to_return += str(params[i]) to_return += str(params[i])
if(i != params.size() -1): if i != params.size() - 1:
to_return += ', ' to_return += ", "
return to_return return to_return
func add_call(variant, method_name, parameters=null):
if(!_calls.has(variant)): func add_call(variant, method_name, parameters = null):
if !_calls.has(variant):
_calls[variant] = {} _calls[variant] = {}
if(!_calls[variant].has(method_name)): if !_calls[variant].has(method_name):
_calls[variant][method_name] = [] _calls[variant][method_name] = []
_calls[variant][method_name].append(parameters) _calls[variant][method_name].append(parameters)
func was_called(variant, method_name, parameters=null):
func was_called(variant, method_name, parameters = null):
var to_return = false var to_return = false
if(_calls.has(variant) and _calls[variant].has(method_name)): if _calls.has(variant) and _calls[variant].has(method_name):
if(parameters): if parameters:
to_return = _find_parameters(_calls[variant][method_name], parameters) to_return = _find_parameters(_calls[variant][method_name], parameters)
else: else:
to_return = true to_return = true
return to_return return to_return
func get_call_parameters(variant, method_name, index=-1):
func get_call_parameters(variant, method_name, index = -1):
var to_return = null var to_return = null
var get_index = -1 var get_index = -1
if(_calls.has(variant) and _calls[variant].has(method_name)): if _calls.has(variant) and _calls[variant].has(method_name):
var call_size = _calls[variant][method_name].size() var call_size = _calls[variant][method_name].size()
if(index == -1): if index == -1:
# get the most recent call by default # get the most recent call by default
get_index = call_size -1 get_index = call_size - 1
else: else:
get_index = index get_index = index
if(get_index < call_size): if get_index < call_size:
to_return = _calls[variant][method_name][get_index] to_return = _calls[variant][method_name][get_index]
else: else:
_lgr.error(str('Specified index ', index, ' is outside range of the number of registered calls: ', call_size)) _lgr.error(
str(
"Specified index ",
index,
" is outside range of the number of registered calls: ",
call_size
)
)
return to_return return to_return
func call_count(instance, method_name, parameters=null):
func call_count(instance, method_name, parameters = null):
var to_return = 0 var to_return = 0
if(was_called(instance, method_name)): if was_called(instance, method_name):
if(parameters): if parameters:
for i in range(_calls[instance][method_name].size()): for i in range(_calls[instance][method_name].size()):
if(_calls[instance][method_name][i] == parameters): if _calls[instance][method_name][i] == parameters:
to_return += 1 to_return += 1
else: else:
to_return = _calls[instance][method_name].size() to_return = _calls[instance][method_name].size()
return to_return return to_return
func clear(): func clear():
_calls = {} _calls = {}
func get_call_list_as_string(instance): func get_call_list_as_string(instance):
var to_return = '' var to_return = ""
if(_calls.has(instance)): if _calls.has(instance):
for method in _calls[instance]: for method in _calls[instance]:
for i in range(_calls[instance][method].size()): for i in range(_calls[instance][method].size()):
to_return += str(method, '(', _get_params_as_string(_calls[instance][method][i]), ")\n") to_return += str(
method, "(", _get_params_as_string(_calls[instance][method][i]), ")\n"
)
return to_return return to_return
func get_logger(): func get_logger():
return _lgr return _lgr
func set_logger(logger): func set_logger(logger):
_lgr = logger _lgr = logger

View file

@ -1,57 +1,59 @@
class_name GutStringUtils class_name GutStringUtils
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
# Hash containing all the built in types in Godot. This provides an English # Hash containing all the built in types in Godot. This provides an English
# name for the types that corosponds with the type constants defined in the # name for the types that corosponds with the type constants defined in the
# engine. # engine.
var types = {} var types = {}
func _init_types_dictionary(): func _init_types_dictionary():
types[TYPE_NIL] = 'TYPE_NIL' types[TYPE_NIL] = "TYPE_NIL"
types[TYPE_BOOL] = 'Bool' types[TYPE_BOOL] = "Bool"
types[TYPE_INT] = 'Int' types[TYPE_INT] = "Int"
types[TYPE_FLOAT] = 'Float/Real' types[TYPE_FLOAT] = "Float/Real"
types[TYPE_STRING] = 'String' types[TYPE_STRING] = "String"
types[TYPE_VECTOR2] = 'Vector2' types[TYPE_VECTOR2] = "Vector2"
types[TYPE_RECT2] = 'Rect2' types[TYPE_RECT2] = "Rect2"
types[TYPE_VECTOR3] = 'Vector3' types[TYPE_VECTOR3] = "Vector3"
#types[8] = 'Matrix32' #types[8] = 'Matrix32'
types[TYPE_PLANE] = 'Plane' types[TYPE_PLANE] = "Plane"
types[TYPE_QUATERNION] = 'QUAT' types[TYPE_QUATERNION] = "QUAT"
types[TYPE_AABB] = 'AABB' types[TYPE_AABB] = "AABB"
#types[12] = 'Matrix3' #types[12] = 'Matrix3'
types[TYPE_TRANSFORM3D] = 'Transform3D' types[TYPE_TRANSFORM3D] = "Transform3D"
types[TYPE_COLOR] = 'Color' types[TYPE_COLOR] = "Color"
#types[15] = 'Image' #types[15] = 'Image'
types[TYPE_NODE_PATH] = 'Node Path3D' types[TYPE_NODE_PATH] = "Node Path3D"
types[TYPE_RID] = 'RID' types[TYPE_RID] = "RID"
types[TYPE_OBJECT] = 'TYPE_OBJECT' types[TYPE_OBJECT] = "TYPE_OBJECT"
#types[19] = 'TYPE_INPUT_EVENT' #types[19] = 'TYPE_INPUT_EVENT'
types[TYPE_DICTIONARY] = 'Dictionary' types[TYPE_DICTIONARY] = "Dictionary"
types[TYPE_ARRAY] = 'Array' types[TYPE_ARRAY] = "Array"
types[TYPE_PACKED_BYTE_ARRAY] = 'TYPE_PACKED_BYTE_ARRAY' types[TYPE_PACKED_BYTE_ARRAY] = "TYPE_PACKED_BYTE_ARRAY"
types[TYPE_PACKED_INT32_ARRAY] = 'TYPE_PACKED_INT32_ARRAY' types[TYPE_PACKED_INT32_ARRAY] = "TYPE_PACKED_INT32_ARRAY"
types[TYPE_PACKED_FLOAT32_ARRAY] = 'TYPE_PACKED_FLOAT32_ARRAY' types[TYPE_PACKED_FLOAT32_ARRAY] = "TYPE_PACKED_FLOAT32_ARRAY"
types[TYPE_PACKED_STRING_ARRAY] = 'TYPE_PACKED_STRING_ARRAY' types[TYPE_PACKED_STRING_ARRAY] = "TYPE_PACKED_STRING_ARRAY"
types[TYPE_PACKED_VECTOR2_ARRAY] = 'TYPE_PACKED_VECTOR2_ARRAY' types[TYPE_PACKED_VECTOR2_ARRAY] = "TYPE_PACKED_VECTOR2_ARRAY"
types[TYPE_PACKED_VECTOR3_ARRAY] = 'TYPE_PACKED_VECTOR3_ARRAY' types[TYPE_PACKED_VECTOR3_ARRAY] = "TYPE_PACKED_VECTOR3_ARRAY"
types[TYPE_PACKED_COLOR_ARRAY] = 'TYPE_PACKED_COLOR_ARRAY' types[TYPE_PACKED_COLOR_ARRAY] = "TYPE_PACKED_COLOR_ARRAY"
types[TYPE_MAX] = 'TYPE_MAX' types[TYPE_MAX] = "TYPE_MAX"
types[TYPE_STRING_NAME] = 'TYPE_STRING_NAME' types[TYPE_STRING_NAME] = "TYPE_STRING_NAME"
# Types to not be formatted when using _str # Types to not be formatted when using _str
var _str_ignore_types = [ var _str_ignore_types = [TYPE_INT, TYPE_FLOAT, TYPE_STRING, TYPE_NIL, TYPE_BOOL]
TYPE_INT, TYPE_FLOAT, TYPE_STRING,
TYPE_NIL, TYPE_BOOL
]
func _init(): func _init():
_init_types_dictionary() _init_types_dictionary()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func _get_filename(path): func _get_filename(path):
return path.split('/')[-1] return path.split("/")[-1]
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Gets the filename of an object passed in. This does not return the # Gets the filename of an object passed in. This does not return the
@ -60,29 +62,32 @@ func _get_filename(path):
func _get_obj_filename(thing): func _get_obj_filename(thing):
var filename = null var filename = null
if(thing == null or if (
_utils.is_native_class(thing) or thing == null
!is_instance_valid(thing) or or _utils.is_native_class(thing)
str(thing) == '<Object#null>' or or !is_instance_valid(thing)
typeof(thing) != TYPE_OBJECT or or str(thing) == "<Object#null>"
_utils.is_double(thing)): or typeof(thing) != TYPE_OBJECT
or _utils.is_double(thing)
):
return return
if(thing.get_script() == null): if thing.get_script() == null:
if(thing is PackedScene): if thing is PackedScene:
filename = _get_filename(thing.resource_path) filename = _get_filename(thing.resource_path)
else: else:
# If it isn't a packed scene and it doesn't have a script then # If it isn't a packed scene and it doesn't have a script then
# we do nothing. This just reads better. # we do nothing. This just reads better.
pass pass
elif(!_utils.is_native_class(thing)): elif !_utils.is_native_class(thing):
var dict = inst_to_dict(thing) var dict = inst_to_dict(thing)
filename = _get_filename(dict['@path']) filename = _get_filename(dict["@path"])
if(str(dict['@subpath']) != ''): if str(dict["@subpath"]) != "":
filename += str('/', dict['@subpath']) filename += str("/", dict["@subpath"])
return filename return filename
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Better object/thing to string conversion. Includes extra details about # Better object/thing to string conversion. Includes extra details about
# whatever is passed in when it can/should. # whatever is passed in when it can/should.
@ -91,49 +96,50 @@ func type2str(thing):
var filename = _get_obj_filename(thing) var filename = _get_obj_filename(thing)
var str_thing = str(thing) var str_thing = str(thing)
if(thing == null): if thing == null:
# According to str there is a difference between null and an Object # According to str there is a difference between null and an Object
# that is somehow null. To avoid getting '[Object:null]' as output # that is somehow null. To avoid getting '[Object:null]' as output
# always set it to str(null) instead of str(thing). A null object # always set it to str(null) instead of str(thing). A null object
# will pass typeof(thing) == TYPE_OBJECT check so this has to be # will pass typeof(thing) == TYPE_OBJECT check so this has to be
# before that. # before that.
str_thing = str(null) str_thing = str(null)
elif(typeof(thing) == TYPE_FLOAT): elif typeof(thing) == TYPE_FLOAT:
if(!'.' in str_thing): if !"." in str_thing:
str_thing += '.0' str_thing += ".0"
elif(typeof(thing) == TYPE_STRING): elif typeof(thing) == TYPE_STRING:
str_thing = str('"', thing, '"') str_thing = str('"', thing, '"')
elif(typeof(thing) in _str_ignore_types): elif typeof(thing) in _str_ignore_types:
# do nothing b/c we already have str(thing) in # do nothing b/c we already have str(thing) in
# to_return. I think this just reads a little # to_return. I think this just reads a little
# better this way. # better this way.
pass pass
elif(typeof(thing) == TYPE_OBJECT): elif typeof(thing) == TYPE_OBJECT:
if(_utils.is_native_class(thing)): if _utils.is_native_class(thing):
str_thing = _utils.get_native_class_name(thing) str_thing = _utils.get_native_class_name(thing)
elif(_utils.is_double(thing)): elif _utils.is_double(thing):
var double_path = _get_filename(thing.__gutdbl.thepath) var double_path = _get_filename(thing.__gutdbl.thepath)
if(thing.__gutdbl.subpath != ''): if thing.__gutdbl.subpath != "":
double_path += str('/', thing.__gutdbl.subpath) double_path += str("/", thing.__gutdbl.subpath)
elif(thing.__gutdbl.from_singleton != ''): elif thing.__gutdbl.from_singleton != "":
double_path = thing.__gutdbl.from_singleton + " Singleton" double_path = thing.__gutdbl.from_singleton + " Singleton"
var double_type = "double" var double_type = "double"
if(thing.__gutdbl.is_partial): if thing.__gutdbl.is_partial:
double_type = "partial-double" double_type = "partial-double"
str_thing += str("(", double_type, " of ", double_path, ")") str_thing += str("(", double_type, " of ", double_path, ")")
filename = null filename = null
elif(types.has(typeof(thing))): elif types.has(typeof(thing)):
if(!str_thing.begins_with('(')): if !str_thing.begins_with("("):
str_thing = '(' + str_thing + ')' str_thing = "(" + str_thing + ")"
str_thing = str(types[typeof(thing)], str_thing) str_thing = str(types[typeof(thing)], str_thing)
if(filename != null): if filename != null:
str_thing += str('(', filename, ')') str_thing += str("(", filename, ")")
return str_thing return str_thing
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Returns the string truncated with an '...' in it. Shows the start and last # Returns the string truncated with an '...' in it. Shows the start and last
# 10 chars. If the string is smaller than max_size the entire string is # 10 chars. If the string is smaller than max_size the entire string is
@ -141,28 +147,31 @@ func type2str(thing):
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func truncate_string(src, max_size): func truncate_string(src, max_size):
var to_return = src var to_return = src
if(src.length() > max_size - 10 and max_size != -1): if src.length() > max_size - 10 and max_size != -1:
to_return = str(src.substr(0, max_size - 10), '...', src.substr(src.length() - 10, src.length())) to_return = str(
src.substr(0, max_size - 10), "...", src.substr(src.length() - 10, src.length())
)
return to_return return to_return
func _get_indent_text(times, pad): func _get_indent_text(times, pad):
var to_return = '' var to_return = ""
for i in range(times): for i in range(times):
to_return += pad to_return += pad
return to_return return to_return
func indent_text(text, times, pad): func indent_text(text, times, pad):
if(times == 0): if times == 0:
return text return text
var to_return = text var to_return = text
var ending_newline = '' var ending_newline = ""
if(text.ends_with("\n")): if text.ends_with("\n"):
ending_newline = "\n" ending_newline = "\n"
to_return = to_return.left(to_return.length() -1) to_return = to_return.left(to_return.length() - 1)
var padding = _get_indent_text(times, pad) var padding = _get_indent_text(times, pad)
to_return = to_return.replace("\n", "\n" + padding) to_return = to_return.replace("\n", "\n" + padding)

View file

@ -1,4 +1,4 @@
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
var _lgr = _utils.get_logger() var _lgr = _utils.get_logger()
var return_val = null var return_val = null
@ -27,39 +27,42 @@ var parameter_defaults = null
var _parameter_override_only = true var _parameter_override_only = true
# -- # --
const NOT_SET = '|_1_this_is_not_set_1_|' const NOT_SET = "|_1_this_is_not_set_1_|"
func _init(target=null,method=null,subpath=null):
func _init(target = null, method = null, subpath = null):
stub_target = target stub_target = target
stub_method = method stub_method = method
if(typeof(target) == TYPE_STRING): if typeof(target) == TYPE_STRING:
if(target.is_absolute_path()): if target.is_absolute_path():
stub_target = load(str(target)) stub_target = load(str(target))
else: else:
_lgr.warn(str(target, ' is not a valid path')) _lgr.warn(str(target, " is not a valid path"))
if(stub_target is PackedScene): if stub_target is PackedScene:
stub_target = _utils.get_scene_script_object(stub_target) stub_target = _utils.get_scene_script_object(stub_target)
elif(_utils.is_native_class(stub_target)): elif _utils.is_native_class(stub_target):
print("Got a native class: ", stub_target) print("Got a native class: ", stub_target)
# this is used internally to stub default parameters for everything that is # this is used internally to stub default parameters for everything that is
# doubled...or something. Look for stub_defaults_from_meta for usage. This # doubled...or something. Look for stub_defaults_from_meta for usage. This
# behavior is not to be used by end users. # behavior is not to be used by end users.
if(typeof(method) == TYPE_DICTIONARY): if typeof(method) == TYPE_DICTIONARY:
_load_defaults_from_metadata(method) _load_defaults_from_metadata(method)
func _load_defaults_from_metadata(meta): func _load_defaults_from_metadata(meta):
stub_method = meta.name stub_method = meta.name
var values = meta.default_args.duplicate() var values = meta.default_args.duplicate()
while (values.size() < meta.args.size()): while values.size() < meta.args.size():
values.push_front(null) values.push_front(null)
param_defaults(values) param_defaults(values)
func to_return(val): func to_return(val):
if(stub_method == '_init'): if stub_method == "_init":
_lgr.error("You cannot stub _init to do nothing. Super's _init is always called.") _lgr.error("You cannot stub _init to do nothing. Super's _init is always called.")
else: else:
return_val = val return_val = val
@ -74,7 +77,7 @@ func to_do_nothing():
func to_call_super(): func to_call_super():
if(stub_method == '_init'): if stub_method == "_init":
_lgr.error("You cannot stub _init to call super. Super's _init is always called.") _lgr.error("You cannot stub _init to call super. Super's _init is always called.")
else: else:
call_super = true call_super = true
@ -82,11 +85,22 @@ func to_call_super():
return self return self
func when_passed(p1=NOT_SET,p2=NOT_SET,p3=NOT_SET,p4=NOT_SET,p5=NOT_SET,p6=NOT_SET,p7=NOT_SET,p8=NOT_SET,p9=NOT_SET,p10=NOT_SET): func when_passed(
parameters = [p1,p2,p3,p4,p5,p6,p7,p8,p9,p10] p1 = NOT_SET,
p2 = NOT_SET,
p3 = NOT_SET,
p4 = NOT_SET,
p5 = NOT_SET,
p6 = NOT_SET,
p7 = NOT_SET,
p8 = NOT_SET,
p9 = NOT_SET,
p10 = NOT_SET
):
parameters = [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10]
var idx = 0 var idx = 0
while(idx < parameters.size()): while idx < parameters.size():
if(str(parameters[idx]) == NOT_SET): if str(parameters[idx]) == NOT_SET:
parameters.remove_at(idx) parameters.remove_at(idx)
else: else:
idx += 1 idx += 1
@ -110,28 +124,30 @@ func has_param_override():
func is_param_override_only(): func is_param_override_only():
var to_return = false var to_return = false
if(has_param_override()): if has_param_override():
to_return = _parameter_override_only to_return = _parameter_override_only
return to_return return to_return
func to_s(): func to_s():
var base_string = str(stub_target, '.', stub_method) var base_string = str(stub_target, ".", stub_method)
if(has_param_override()): if has_param_override():
base_string += str(' (param count override=', parameter_count, ' defaults=', parameter_defaults) base_string += str(
if(is_param_override_only()): " (param count override=", parameter_count, " defaults=", parameter_defaults
)
if is_param_override_only():
base_string += " ONLY" base_string += " ONLY"
if(is_script_default): if is_script_default:
base_string += " script default" base_string += " script default"
base_string += ') ' base_string += ") "
if(call_super): if call_super:
base_string += " to call SUPER" base_string += " to call SUPER"
if(parameters != null): if parameters != null:
base_string += str(' with params (', parameters, ') returns ', return_val) base_string += str(" with params (", parameters, ") returns ", return_val)
else: else:
base_string += str(' returns ', return_val) base_string += str(" returns ", return_val)
return base_string return base_string

View file

@ -12,14 +12,16 @@
# } # }
# } # }
var returns = {} var returns = {}
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
var _lgr = _utils.get_logger() var _lgr = _utils.get_logger()
var _strutils = _utils.Strutils.new() var _strutils = _utils.Strutils.new()
var _class_db_name_hash = {} var _class_db_name_hash = {}
func _init(): func _init():
_class_db_name_hash = _make_crazy_dynamic_over_engineered_class_db_hash() _class_db_name_hash = _make_crazy_dynamic_over_engineered_class_db_hash()
# So, I couldn't figure out how to get to a reference for a GDNative Class # So, I couldn't figure out how to get to a reference for a GDNative Class
# using a string. ClassDB has all thier names...so I made a hash using those # using a string. ClassDB has all thier names...so I made a hash using those
# names and the classes. Then I dynmaically make a script that has that as # names and the classes. Then I dynmaically make a script that has that as
@ -28,12 +30,12 @@ func _init():
func _make_crazy_dynamic_over_engineered_class_db_hash(): func _make_crazy_dynamic_over_engineered_class_db_hash():
var text = "var all_the_classes = {\n" var text = "var all_the_classes = {\n"
for classname in ClassDB.get_class_list(): for classname in ClassDB.get_class_list():
if(ClassDB.can_instantiate(classname)): if ClassDB.can_instantiate(classname):
text += str('"', classname, '": ', classname, ", \n") text += str('"', classname, '": ', classname, ", \n")
else: else:
text += str('# ', classname, "\n") text += str("# ", classname, "\n")
text += "}" text += "}"
var inst = _utils.create_script_from_source(text).new() var inst = _utils.create_script_from_source(text).new()
return inst.all_the_classes return inst.all_the_classes
@ -44,27 +46,27 @@ func _find_matches(obj, method):
# Search for what is passed in first. This could be a class or an instance. # Search for what is passed in first. This could be a class or an instance.
# We want to find the instance before we find the class. If we do not have # We want to find the instance before we find the class. If we do not have
# an entry for the instance then see if we have an entry for the class. # an entry for the instance then see if we have an entry for the class.
if(returns.has(obj) and returns[obj].has(method)): if returns.has(obj) and returns[obj].has(method):
matches = returns[obj][method] matches = returns[obj][method]
elif(_utils.is_instance(obj)): elif _utils.is_instance(obj):
var parent = obj.get_script() var parent = obj.get_script()
var found = false var found = false
while(parent != null and !found): while parent != null and !found:
found = returns.has(parent) found = returns.has(parent)
if(!found): if !found:
last_not_null_parent = parent last_not_null_parent = parent
parent = parent.get_base_script() parent = parent.get_base_script()
# Could not find the script so check to see if a native class of this # Could not find the script so check to see if a native class of this
# type was stubbed. # type was stubbed.
if(!found): if !found:
var base_type = last_not_null_parent.get_instance_base_type() var base_type = last_not_null_parent.get_instance_base_type()
if(_class_db_name_hash.has(base_type)): if _class_db_name_hash.has(base_type):
parent = _class_db_name_hash[base_type] parent = _class_db_name_hash[base_type]
found = returns.has(parent) found = returns.has(parent)
if(found and returns[parent].has(method)): if found and returns[parent].has(method):
matches = returns[parent][method] matches = returns[parent][method]
return matches return matches
@ -74,11 +76,11 @@ func _find_matches(obj, method):
# passed in obj is. # passed in obj is.
# #
# obj can be an instance, class, or a path. # obj can be an instance, class, or a path.
func _find_stub(obj, method, parameters=null, find_overloads=false): func _find_stub(obj, method, parameters = null, find_overloads = false):
var to_return = null var to_return = null
var matches = _find_matches(obj, method) var matches = _find_matches(obj, method)
if(matches == null): if matches == null:
return null return null
var param_match = null var param_match = null
@ -87,43 +89,43 @@ func _find_stub(obj, method, parameters=null, find_overloads=false):
for i in range(matches.size()): for i in range(matches.size()):
var cur_stub = matches[i] var cur_stub = matches[i]
if(cur_stub.parameters == parameters): if cur_stub.parameters == parameters:
param_match = cur_stub param_match = cur_stub
if(cur_stub.parameters == null and !cur_stub.is_param_override_only()): if cur_stub.parameters == null and !cur_stub.is_param_override_only():
null_match = cur_stub null_match = cur_stub
if(cur_stub.has_param_override()): if cur_stub.has_param_override():
if(overload_match == null || overload_match.is_script_default): if overload_match == null || overload_match.is_script_default:
overload_match = cur_stub overload_match = cur_stub
if(find_overloads and overload_match != null): if find_overloads and overload_match != null:
to_return = overload_match to_return = overload_match
# We have matching parameter values so return the stub value for that # We have matching parameter values so return the stub value for that
elif(param_match != null): elif param_match != null:
to_return = param_match to_return = param_match
# We found a case where the parameters were not specified so return # We found a case where the parameters were not specified so return
# parameters for that. Only do this if the null match is not *just* # parameters for that. Only do this if the null match is not *just*
# a paramerter override stub. # a paramerter override stub.
elif(null_match != null): elif null_match != null:
to_return = null_match to_return = null_match
return to_return return to_return
# ############## # ##############
# Public # Public
# ############## # ##############
func add_stub(stub_params): func add_stub(stub_params):
stub_params._lgr = _lgr stub_params._lgr = _lgr
var key = stub_params.stub_target var key = stub_params.stub_target
if(!returns.has(key)): if !returns.has(key):
returns[key] = {} returns[key] = {}
if(!returns[key].has(stub_params.stub_method)): if !returns[key].has(stub_params.stub_method):
returns[key][stub_params.stub_method] = [] returns[key][stub_params.stub_method] = []
returns[key][stub_params.stub_method].append(stub_params) returns[key][stub_params.stub_method].append(stub_params)
@ -144,34 +146,42 @@ func add_stub(stub_params):
# obj: this should be an instance of a doubled object. # obj: this should be an instance of a doubled object.
# method: the method called # method: the method called
# parameters: optional array of parameter vales to find a return value for. # parameters: optional array of parameter vales to find a return value for.
func get_return(obj, method, parameters=null): func get_return(obj, method, parameters = null):
var stub_info = _find_stub(obj, method, parameters) var stub_info = _find_stub(obj, method, parameters)
if(stub_info != null): if stub_info != null:
return stub_info.return_val return stub_info.return_val
else: else:
_lgr.warn(str('Call to [', method, '] was not stubbed for the supplied parameters ', parameters, '. Null was returned.')) _lgr.warn(
str(
"Call to [",
method,
"] was not stubbed for the supplied parameters ",
parameters,
". Null was returned."
)
)
return null return null
func should_call_super(obj, method, parameters=null): func should_call_super(obj, method, parameters = null):
if(_utils.non_super_methods.has(method)): if _utils.non_super_methods.has(method):
return false return false
var stub_info = _find_stub(obj, method, parameters) var stub_info = _find_stub(obj, method, parameters)
var is_partial = false var is_partial = false
if(typeof(obj) != TYPE_STRING): # some stubber tests test with strings if typeof(obj) != TYPE_STRING: # some stubber tests test with strings
is_partial = obj.__gutdbl.is_partial is_partial = obj.__gutdbl.is_partial
var should = is_partial var should = is_partial
if(stub_info != null): if stub_info != null:
should = stub_info.call_super should = stub_info.call_super
elif(!is_partial): elif !is_partial:
# this log message is here because of how the generated doubled scripts # this log message is here because of how the generated doubled scripts
# are structured. With this log msg here, you will only see one # are structured. With this log msg here, you will only see one
# "unstubbed" info instead of multiple. # "unstubbed" info instead of multiple.
_lgr.info('Unstubbed call to ' + method + '::' + _strutils.type2str(obj)) _lgr.info("Unstubbed call to " + method + "::" + _strutils.type2str(obj))
should = false should = false
return should return should
@ -181,7 +191,7 @@ func get_parameter_count(obj, method):
var to_return = null var to_return = null
var stub_info = _find_stub(obj, method, null, true) var stub_info = _find_stub(obj, method, null, true)
if(stub_info != null and stub_info.has_param_override()): if stub_info != null and stub_info.has_param_override():
to_return = stub_info.parameter_count to_return = stub_info.parameter_count
return to_return return to_return
@ -191,10 +201,11 @@ func get_default_value(obj, method, p_index):
var to_return = null var to_return = null
var stub_info = _find_stub(obj, method, null, true) var stub_info = _find_stub(obj, method, null, true)
if(stub_info != null and if (
stub_info.parameter_defaults != null and stub_info != null
stub_info.parameter_defaults.size() > p_index): and stub_info.parameter_defaults != null
and stub_info.parameter_defaults.size() > p_index
):
to_return = stub_info.parameter_defaults[p_index] to_return = stub_info.parameter_defaults[p_index]
return to_return return to_return
@ -213,7 +224,7 @@ func set_logger(logger):
func to_s(): func to_s():
var text = '' var text = ""
for thing in returns: for thing in returns:
text += str("-- ", thing, " --\n") text += str("-- ", thing, " --\n")
for method in returns[thing]: for method in returns[thing]:
@ -221,8 +232,8 @@ func to_s():
for i in range(returns[thing][method].size()): for i in range(returns[thing][method].size()):
text += "\t\t" + returns[thing][method][i].to_s() + "\n" text += "\t\t" + returns[thing][method][i].to_s() + "\n"
if(text == ''): if text == "":
text = 'Stubber is empty'; text = "Stubber is empty"
return text return text

View file

@ -28,37 +28,37 @@ class Test:
func did_something(): func did_something():
return is_passing() or is_failing() or is_pending() return is_passing() or is_failing() or is_pending()
# NOTE: The "failed" and "pending" text must match what is outputted by # NOTE: The "failed" and "pending" text must match what is outputted by
# the logger in order for text highlighting to occur in summary. # the logger in order for text highlighting to occur in summary.
func to_s(): func to_s():
var pad = ' ' var pad = " "
var to_return = '' var to_return = ""
for i in range(fail_texts.size()): for i in range(fail_texts.size()):
to_return += str(pad, '[Failed]: ', fail_texts[i], "\n") to_return += str(pad, "[Failed]: ", fail_texts[i], "\n")
for i in range(pending_texts.size()): for i in range(pending_texts.size()):
to_return += str(pad, '[Pending]: ', pending_texts[i], "\n") to_return += str(pad, "[Pending]: ", pending_texts[i], "\n")
return to_return return to_return
func get_status(): func get_status():
var to_return = 'no asserts' var to_return = "no asserts"
if(pending_texts.size() > 0): if pending_texts.size() > 0:
to_return = 'pending' to_return = "pending"
elif(fail_texts.size() > 0): elif fail_texts.size() > 0:
to_return = 'fail' to_return = "fail"
elif(pass_texts.size() > 0): elif pass_texts.size() > 0:
to_return = 'pass' to_return = "pass"
return to_return return to_return
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Contains all the results for a single test-script/inner class. Persists the # Contains all the results for a single test-script/inner class. Persists the
# names of the tests and results and the order in which the tests were run. # names of the tests and results and the order in which the tests were run.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class TestScript: class TestScript:
var name = 'NOT_SET' var name = "NOT_SET"
var was_skipped = false var was_skipped = false
var skip_reason = '' var skip_reason = ""
var _tests = {} var _tests = {}
var _test_order = [] var _test_order = []
@ -86,30 +86,29 @@ class TestScript:
func get_passing_test_count(): func get_passing_test_count():
var count = 0 var count = 0
for key in _tests: for key in _tests:
if(_tests[key].is_passing()): if _tests[key].is_passing():
count += 1 count += 1
return count return count
func get_failing_test_count(): func get_failing_test_count():
var count = 0 var count = 0
for key in _tests: for key in _tests:
if(_tests[key].is_failing()): if _tests[key].is_failing():
count += 1 count += 1
return count return count
func get_risky_count(): func get_risky_count():
var count = 0 var count = 0
if(was_skipped): if was_skipped:
count = 1 count = 1
else: else:
for key in _tests: for key in _tests:
if(!_tests[key].did_something()): if !_tests[key].did_something():
count += 1 count += 1
return count return count
func get_test_obj(obj_name): func get_test_obj(obj_name):
if(!_tests.has(obj_name)): if !_tests.has(obj_name):
var to_add = Test.new() var to_add = Test.new()
_tests[obj_name] = to_add _tests[obj_name] = to_add
_test_order.append(obj_name) _test_order.append(obj_name)
@ -133,6 +132,7 @@ class TestScript:
func get_tests(): func get_tests():
return _tests return _tests
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Summary Class # Summary Class
# #
@ -141,47 +141,57 @@ class TestScript:
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
var _scripts = [] var _scripts = []
func add_script(name): func add_script(name):
_scripts.append(TestScript.new(name)) _scripts.append(TestScript.new(name))
func get_scripts(): func get_scripts():
return _scripts return _scripts
func get_current_script(): func get_current_script():
return _scripts[_scripts.size() - 1] return _scripts[_scripts.size() - 1]
func add_test(test_name): func add_test(test_name):
# print('-- test_name = ', test_name) # print('-- test_name = ', test_name)
# print('-- current script = ', get_current_script()) # print('-- current script = ', get_current_script())
# print('-- test_obj = ', get_current_script().get_test_obj(test_name)) # print('-- test_obj = ', get_current_script().get_test_obj(test_name))
return get_current_script().get_test_obj(test_name) return get_current_script().get_test_obj(test_name)
func add_pass(test_name, reason = ''):
func add_pass(test_name, reason = ""):
get_current_script().add_pass(test_name, reason) get_current_script().add_pass(test_name, reason)
func add_fail(test_name, reason = ''):
func add_fail(test_name, reason = ""):
get_current_script().add_fail(test_name, reason) get_current_script().add_fail(test_name, reason)
func add_pending(test_name, reason = ''):
func add_pending(test_name, reason = ""):
get_current_script().add_pending(test_name, reason) get_current_script().add_pending(test_name, reason)
func get_test_text(test_name): func get_test_text(test_name):
return test_name + "\n" + get_current_script().get_test_obj(test_name).to_s() return test_name + "\n" + get_current_script().get_test_obj(test_name).to_s()
# Gets the count of unique script names minus the .<Inner Class Name> at the # Gets the count of unique script names minus the .<Inner Class Name> at the
# end. Used for displaying the number of scripts without including all the # end. Used for displaying the number of scripts without including all the
# Inner Classes. # Inner Classes.
func get_non_inner_class_script_count(): func get_non_inner_class_script_count():
var counter = load('res://addons/gut/thing_counter.gd').new() var counter = load("res://addons/gut/thing_counter.gd").new()
for i in range(_scripts.size()): for i in range(_scripts.size()):
var ext_loc = _scripts[i].name.rfind('.gd.') var ext_loc = _scripts[i].name.rfind(".gd.")
var to_add = _scripts[i].name var to_add = _scripts[i].name
if(ext_loc != -1): if ext_loc != -1:
to_add = _scripts[i].name.substr(0, ext_loc + 3) to_add = _scripts[i].name.substr(0, ext_loc + 3)
counter.add(to_add) counter.add(to_add)
return counter.get_unique_count() return counter.get_unique_count()
func get_totals(): func get_totals():
var totals = { var totals = {
passing = 0, passing = 0,
@ -217,34 +227,38 @@ func log_summary_text(lgr):
for s in range(_scripts.size()): for s in range(_scripts.size()):
lgr.set_indent_level(0) lgr.set_indent_level(0)
if(_scripts[s].was_skipped or _scripts[s].get_fail_count() > 0 or _scripts[s].get_pending_count() > 0): if (
_scripts[s].was_skipped
or _scripts[s].get_fail_count() > 0
or _scripts[s].get_pending_count() > 0
):
lgr.log(_scripts[s].name, lgr.fmts.underline) lgr.log(_scripts[s].name, lgr.fmts.underline)
if(_scripts[s].was_skipped): if _scripts[s].was_skipped:
lgr.inc_indent() lgr.inc_indent()
var skip_msg = str('[Risky] Script was skipped: ', _scripts[s].skip_reason) var skip_msg = str("[Risky] Script was skipped: ", _scripts[s].skip_reason)
lgr.log(skip_msg, lgr.fmts.yellow) lgr.log(skip_msg, lgr.fmts.yellow)
lgr.dec_indent() lgr.dec_indent()
for t in range(_scripts[s]._test_order.size()): for t in range(_scripts[s]._test_order.size()):
var tname = _scripts[s]._test_order[t] var tname = _scripts[s]._test_order[t]
var test = _scripts[s].get_test_obj(tname) var test = _scripts[s].get_test_obj(tname)
if(!test.is_passing()): if !test.is_passing():
found_failing_or_pending = true found_failing_or_pending = true
lgr.log(str('- ', tname)) lgr.log(str("- ", tname))
lgr.inc_indent() lgr.inc_indent()
for i in range(test.fail_texts.size()): for i in range(test.fail_texts.size()):
lgr.failed(test.fail_texts[i]) lgr.failed(test.fail_texts[i])
for i in range(test.pending_texts.size()): for i in range(test.pending_texts.size()):
lgr.pending(test.pending_texts[i]) lgr.pending(test.pending_texts[i])
if(!test.did_something()): if !test.did_something():
lgr.log('[Risky] Did not assert', lgr.fmts.yellow) lgr.log("[Risky] Did not assert", lgr.fmts.yellow)
lgr.dec_indent() lgr.dec_indent()
lgr.set_indent_level(0) lgr.set_indent_level(0)
if(!found_failing_or_pending): if !found_failing_or_pending:
lgr.log('All tests passed', lgr.fmts.green) lgr.log("All tests passed", lgr.fmts.green)
# just picked a non-printable char, dunno if it is a good or bad choice. # just picked a non-printable char, dunno if it is a good or bad choice.
var npws = PackedByteArray([31]).get_string_from_ascii() var npws = PackedByteArray([31]).get_string_from_ascii()
@ -252,15 +266,22 @@ func log_summary_text(lgr):
lgr.log() lgr.log()
var _totals = get_totals() var _totals = get_totals()
lgr.log("Totals", lgr.fmts.yellow) lgr.log("Totals", lgr.fmts.yellow)
lgr.log(str('Scripts: ', get_non_inner_class_script_count())) lgr.log(str("Scripts: ", get_non_inner_class_script_count()))
lgr.log(str('Passing tests ', _totals.passing_tests)) lgr.log(str("Passing tests ", _totals.passing_tests))
lgr.log(str('Failing tests ', _totals.failing_tests)) lgr.log(str("Failing tests ", _totals.failing_tests))
lgr.log(str('Risky tests ', _totals.risky)) lgr.log(str("Risky tests ", _totals.risky))
var pnd=str('Pending: ', _totals.pending) var pnd = str("Pending: ", _totals.pending)
# add a non printable character so this "pending" isn't highlighted in the # add a non printable character so this "pending" isn't highlighted in the
# editor's output panel. # editor's output panel.
lgr.log(str(npws, pnd)) lgr.log(str(npws, pnd))
lgr.log(str('Asserts: ', _totals.passing, ' of ', _totals.passing + _totals.failing, ' passed')) lgr.log(
str(
"Asserts: ",
_totals.passing,
" of ",
_totals.passing + _totals.failing,
" passed"
)
)
lgr.set_indent_level(orig_indent) lgr.set_indent_level(orig_indent)

File diff suppressed because it is too large Load diff

View file

@ -35,24 +35,24 @@ class Test:
# This class also facilitates all the exporting and importing of tests. # This class also facilitates all the exporting and importing of tests.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class TestScript: class TestScript:
var inner_class_name:StringName var inner_class_name: StringName
var tests = [] var tests = []
var path:String var path: String
var _utils = null var _utils = null
var _lgr = null var _lgr = null
var is_loaded = false var is_loaded = false
func _init(utils=null,logger=null): func _init(utils = null, logger = null):
_utils = utils _utils = utils
_lgr = logger _lgr = logger
func to_s(): func to_s():
var to_return = path var to_return = path
if(inner_class_name != null): if inner_class_name != null:
to_return += str('.', inner_class_name) to_return += str(".", inner_class_name)
to_return += "\n" to_return += "\n"
for i in range(tests.size()): for i in range(tests.size()):
to_return += str(' ', tests[i].name, "\n") to_return += str(" ", tests[i].name, "\n")
return to_return return to_return
func get_new(): func get_new():
@ -61,7 +61,7 @@ class TestScript:
func load_script(): func load_script():
var to_return = load(path) var to_return = load(path)
if(inner_class_name != null and inner_class_name != ''): if inner_class_name != null and inner_class_name != "":
# If we wanted to do inner classes in inner classses # If we wanted to do inner classes in inner classses
# then this would have to become some kind of loop or recursive # then this would have to become some kind of loop or recursive
# call to go all the way down the chain or this class would # call to go all the way down the chain or this class would
@ -73,120 +73,123 @@ class TestScript:
func get_filename_and_inner(): func get_filename_and_inner():
var to_return = get_filename() var to_return = get_filename()
if(inner_class_name != ''): if inner_class_name != "":
to_return += '.' + String(inner_class_name) to_return += "." + String(inner_class_name)
return to_return return to_return
func get_full_name(): func get_full_name():
var to_return = path var to_return = path
if(inner_class_name != ''): if inner_class_name != "":
to_return += '.' + String(inner_class_name) to_return += "." + String(inner_class_name)
return to_return return to_return
func get_filename(): func get_filename():
return path.get_file() return path.get_file()
func has_inner_class(): func has_inner_class():
return inner_class_name != '' return inner_class_name != ""
# Note: although this no longer needs to export the inner_class names since # Note: although this no longer needs to export the inner_class names since
# they are pulled from metadata now, it is easier to leave that in # they are pulled from metadata now, it is easier to leave that in
# so we don't have to cut the export down to unique script names. # so we don't have to cut the export down to unique script names.
func export_to(config_file, section): func export_to(config_file, section):
config_file.set_value(section, 'path', path) config_file.set_value(section, "path", path)
config_file.set_value(section, 'inner_class', inner_class_name) config_file.set_value(section, "inner_class", inner_class_name)
var names = [] var names = []
for i in range(tests.size()): for i in range(tests.size()):
names.append(tests[i].name) names.append(tests[i].name)
config_file.set_value(section, 'tests', names) config_file.set_value(section, "tests", names)
func _remap_path(source_path): func _remap_path(source_path):
var to_return = source_path var to_return = source_path
if(!_utils.file_exists(source_path)): if !_utils.file_exists(source_path):
_lgr.debug('Checking for remap for: ' + source_path) _lgr.debug("Checking for remap for: " + source_path)
var remap_path = source_path.get_basename() + '.gd.remap' var remap_path = source_path.get_basename() + ".gd.remap"
if(_utils.file_exists(remap_path)): if _utils.file_exists(remap_path):
var cf = ConfigFile.new() var cf = ConfigFile.new()
cf.load(remap_path) cf.load(remap_path)
to_return = cf.get_value('remap', 'path') to_return = cf.get_value("remap", "path")
else: else:
_lgr.warn('Could not find remap file ' + remap_path) _lgr.warn("Could not find remap file " + remap_path)
return to_return return to_return
func import_from(config_file, section): func import_from(config_file, section):
path = config_file.get_value(section, 'path') path = config_file.get_value(section, "path")
path = _remap_path(path) path = _remap_path(path)
# Null is an acceptable value, but you can't pass null as a default to # Null is an acceptable value, but you can't pass null as a default to
# get_value since it thinks you didn't send a default...then it spits # get_value since it thinks you didn't send a default...then it spits
# out red text. This works around that. # out red text. This works around that.
var inner_name = config_file.get_value(section, 'inner_class', 'Placeholder') var inner_name = config_file.get_value(section, "inner_class", "Placeholder")
if(inner_name != 'Placeholder'): if inner_name != "Placeholder":
inner_class_name = inner_name inner_class_name = inner_name
else: # just being explicit else: # just being explicit
inner_class_name = StringName("") inner_class_name = StringName("")
func get_test_named(name): func get_test_named(name):
return _utils.search_array(tests, 'name', name) return _utils.search_array(tests, "name", name)
func mark_tests_to_skip_with_suffix(suffix): func mark_tests_to_skip_with_suffix(suffix):
for single_test in tests: for single_test in tests:
single_test.should_skip = single_test.name.ends_with(suffix) single_test.should_skip = single_test.name.ends_with(suffix)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# start test_collector, I don't think I like the name. # start test_collector, I don't think I like the name.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
var scripts = [] var scripts = []
var _test_prefix = 'test_' var _test_prefix = "test_"
var _test_class_prefix = 'Test' var _test_class_prefix = "Test"
var _utils = load('res://addons/gut/utils.gd').get_instance() var _utils = load("res://addons/gut/utils.gd").get_instance()
var _lgr = _utils.get_logger() var _lgr = _utils.get_logger()
func _does_inherit_from_test(thing): func _does_inherit_from_test(thing):
var base_script = thing.get_base_script() var base_script = thing.get_base_script()
var to_return = false var to_return = false
if(base_script != null): if base_script != null:
var base_path = base_script.get_path() var base_path = base_script.get_path()
if(base_path == 'res://addons/gut/test.gd'): if base_path == "res://addons/gut/test.gd":
to_return = true to_return = true
else: else:
to_return = _does_inherit_from_test(base_script) to_return = _does_inherit_from_test(base_script)
return to_return return to_return
func _populate_tests(test_script:TestScript): func _populate_tests(test_script: TestScript):
var script = test_script.load_script() var script = test_script.load_script()
if(script == null): if script == null:
print(' !!! ', test_script.path, ' could not be loaded') print(" !!! ", test_script.path, " could not be loaded")
return false return false
test_script.is_loaded = true test_script.is_loaded = true
var methods = script.get_script_method_list() var methods = script.get_script_method_list()
for i in range(methods.size()): for i in range(methods.size()):
var name = methods[i]['name'] var name = methods[i]["name"]
if(name.begins_with(_test_prefix)): if name.begins_with(_test_prefix):
var t = Test.new() var t = Test.new()
t.name = name t.name = name
t.arg_count = methods[i]['args'].size() t.arg_count = methods[i]["args"].size()
test_script.tests.append(t) test_script.tests.append(t)
func _get_inner_test_class_names(loaded): func _get_inner_test_class_names(loaded):
var inner_classes = [] var inner_classes = []
var const_map = loaded.get_script_constant_map() var const_map = loaded.get_script_constant_map()
for key in const_map: for key in const_map:
var thing = const_map[key] var thing = const_map[key]
if(_utils.is_gdscript(thing)): if _utils.is_gdscript(thing):
if(key.begins_with(_test_class_prefix)): if key.begins_with(_test_class_prefix):
if(_does_inherit_from_test(thing)): if _does_inherit_from_test(thing):
inner_classes.append(key) inner_classes.append(key)
else: else:
_lgr.warn(str('Ignoring Inner Class ', key, _lgr.warn(
' because it does not extend res://addons/gut/test.gd')) str(
"Ignoring Inner Class ",
key,
" because it does not extend res://addons/gut/test.gd"
)
)
# This could go deeper and find inner classes within inner classes # This could go deeper and find inner classes within inner classes
# but requires more experimentation. Right now I'm keeping it at # but requires more experimentation. Right now I'm keeping it at
@ -195,40 +198,42 @@ func _get_inner_test_class_names(loaded):
# _populate_inner_test_classes(thing) # _populate_inner_test_classes(thing)
return inner_classes return inner_classes
func _parse_script(test_script): func _parse_script(test_script):
var inner_classes = [] var inner_classes = []
var scripts_found = [] var scripts_found = []
var loaded = load(test_script.path) var loaded = load(test_script.path)
if(_does_inherit_from_test(loaded)): if _does_inherit_from_test(loaded):
_populate_tests(test_script) _populate_tests(test_script)
scripts_found.append(test_script.path) scripts_found.append(test_script.path)
inner_classes = _get_inner_test_class_names(loaded) inner_classes = _get_inner_test_class_names(loaded)
for i in range(inner_classes.size()): for i in range(inner_classes.size()):
var loaded_inner = loaded.get(inner_classes[i]) var loaded_inner = loaded.get(inner_classes[i])
if(_does_inherit_from_test(loaded_inner)): if _does_inherit_from_test(loaded_inner):
var ts = TestScript.new(_utils, _lgr) var ts = TestScript.new(_utils, _lgr)
ts.path = test_script.path ts.path = test_script.path
ts.inner_class_name = inner_classes[i] ts.inner_class_name = inner_classes[i]
_populate_tests(ts) _populate_tests(ts)
scripts.append(ts) scripts.append(ts)
scripts_found.append(test_script.path + '[' + inner_classes[i] +']') scripts_found.append(test_script.path + "[" + inner_classes[i] + "]")
return scripts_found return scripts_found
# ----------------- # -----------------
# Public # Public
# ----------------- # -----------------
func add_script(path): func add_script(path):
# print('Adding ', path) # print('Adding ', path)
# SHORTCIRCUIT # SHORTCIRCUIT
if(has_script(path)): if has_script(path):
return [] return []
# SHORTCIRCUIT # SHORTCIRCUIT
if(!FileAccess.file_exists(path)): if !FileAccess.file_exists(path):
_lgr.error('Could not find script: ' + path) _lgr.error("Could not find script: " + path)
return return
var ts = TestScript.new(_utils, _lgr) var ts = TestScript.new(_utils, _lgr)
@ -236,36 +241,40 @@ func add_script(path):
scripts.append(ts) scripts.append(ts)
return _parse_script(ts) return _parse_script(ts)
func clear(): func clear():
scripts.clear() scripts.clear()
func has_script(path): func has_script(path):
var found = false var found = false
var idx = 0 var idx = 0
while(idx < scripts.size() and !found): while idx < scripts.size() and !found:
if(scripts[idx].get_full_name() == path): if scripts[idx].get_full_name() == path:
found = true found = true
else: else:
idx += 1 idx += 1
return found return found
func export_tests(path): func export_tests(path):
var success = true var success = true
var f = ConfigFile.new() var f = ConfigFile.new()
for i in range(scripts.size()): for i in range(scripts.size()):
scripts[i].export_to(f, str('TestScript-', i)) scripts[i].export_to(f, str("TestScript-", i))
var result = f.save(path) var result = f.save(path)
if(result != OK): if result != OK:
_lgr.error(str('Could not save exported tests to [', path, ']. Error code: ', result)) _lgr.error(str("Could not save exported tests to [", path, "]. Error code: ", result))
success = false success = false
return success return success
func import_tests(path): func import_tests(path):
var success = false var success = false
var f = ConfigFile.new() var f = ConfigFile.new()
var result = f.load(path) var result = f.load(path)
if(result != OK): if result != OK:
_lgr.error(str('Could not load exported tests from [', path, ']. Error code: ', result)) _lgr.error(str("Could not load exported tests from [", path, "]. Error code: ", result))
else: else:
var sections = f.get_sections() var sections = f.get_sections()
for key in sections: for key in sections:
@ -276,39 +285,48 @@ func import_tests(path):
success = true success = true
return success return success
func get_script_named(name): func get_script_named(name):
return _utils.search_array(scripts, 'get_filename_and_inner', name) return _utils.search_array(scripts, "get_filename_and_inner", name)
func get_test_named(script_name, test_name): func get_test_named(script_name, test_name):
var s = get_script_named(script_name) var s = get_script_named(script_name)
if(s != null): if s != null:
return s.get_test_named(test_name) return s.get_test_named(test_name)
else: else:
return null return null
func to_s(): func to_s():
var to_return = '' var to_return = ""
for i in range(scripts.size()): for i in range(scripts.size()):
to_return += scripts[i].to_s() + "\n" to_return += scripts[i].to_s() + "\n"
return to_return return to_return
# --------------------- # ---------------------
# Accessors # Accessors
# --------------------- # ---------------------
func get_logger(): func get_logger():
return _lgr return _lgr
func set_logger(logger): func set_logger(logger):
_lgr = logger _lgr = logger
func get_test_prefix(): func get_test_prefix():
return _test_prefix return _test_prefix
func set_test_prefix(test_prefix): func set_test_prefix(test_prefix):
_test_prefix = test_prefix _test_prefix = test_prefix
func get_test_class_prefix(): func get_test_class_prefix():
return _test_class_prefix return _test_class_prefix
func set_test_class_prefix(test_class_prefix): func set_test_class_prefix(test_class_prefix):
_test_class_prefix = test_class_prefix _test_class_prefix = test_class_prefix

View file

@ -1,29 +1,35 @@
var things = {} var things = {}
func get_unique_count(): func get_unique_count():
return things.size() return things.size()
func add(thing): func add(thing):
if(things.has(thing)): if things.has(thing):
things[thing] += 1 things[thing] += 1
else: else:
things[thing] = 1 things[thing] = 1
func has(thing): func has(thing):
return things.has(thing) return things.has(thing)
func get(thing): func get(thing):
var to_return = 0 var to_return = 0
if(things.has(thing)): if things.has(thing):
to_return = things[thing] to_return = things[thing]
return to_return return to_return
func sum(): func sum():
var count = 0 var count = 0
for key in things: for key in things:
count += things[key] count += things[key]
return count return count
func to_s(): func to_s():
var to_return = "" var to_return = ""
for key in things: for key in things:
@ -31,13 +37,15 @@ func to_s():
to_return += str("sum: ", sum()) to_return += str("sum: ", sum())
return to_return return to_return
func get_max_count(): func get_max_count():
var max_val = null var max_val = null
for key in things: for key in things:
if(max_val == null or things[key] > max_val): if max_val == null or things[key] > max_val:
max_val = things[key] max_val = things[key]
return max_val return max_val
func add_array_items(array): func add_array_items(array):
for i in range(array.size()): for i in range(array.size()):
add(array[i]) add(array[i])

View file

@ -33,11 +33,13 @@
# ############################################################################## # ##############################################################################
extends Node extends Node
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# The instance name as a function since you can't have static variables. # The instance name as a function since you can't have static variables.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
static func INSTANCE_NAME(): static func INSTANCE_NAME():
return '__GutUtilsInstName__' return "__GutUtilsInstName__"
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Gets the root node without having to be in the tree and pushing out an error # Gets the root node without having to be in the tree and pushing out an error
@ -45,12 +47,13 @@ static func INSTANCE_NAME():
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
static func get_root_node(): static func get_root_node():
var main_loop = Engine.get_main_loop() var main_loop = Engine.get_main_loop()
if(main_loop != null): if main_loop != null:
return main_loop.root return main_loop.root
else: else:
push_error('No Main Loop Yet') push_error("No Main Loop Yet")
return null return null
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Get the ONE instance of utils # Get the ONE instance of utils
# Since we can't have static variables we have to store the instance in the # Since we can't have static variables we have to store the instance in the
@ -60,52 +63,52 @@ static func get_root_node():
static func get_instance(): static func get_instance():
var the_root = get_root_node() var the_root = get_root_node()
var inst = null var inst = null
if(the_root.has_node(INSTANCE_NAME())): if the_root.has_node(INSTANCE_NAME()):
inst = the_root.get_node(INSTANCE_NAME()) inst = the_root.get_node(INSTANCE_NAME())
else: else:
inst = load('res://addons/gut/utils.gd').new() inst = load("res://addons/gut/utils.gd").new()
inst.set_name(INSTANCE_NAME()) inst.set_name(INSTANCE_NAME())
the_root.add_child(inst) the_root.add_child(inst)
return inst return inst
var Logger = load('res://addons/gut/logger.gd') # everything should use get_logger
var Logger = load("res://addons/gut/logger.gd") # everything should use get_logger
var _lgr = null var _lgr = null
var json = JSON.new() var json = JSON.new()
var _test_mode = false var _test_mode = false
var AutoFree = load('res://addons/gut/autofree.gd') var AutoFree = load("res://addons/gut/autofree.gd")
var Awaiter = load('res://addons/gut/awaiter.gd') var Awaiter = load("res://addons/gut/awaiter.gd")
var Comparator = load('res://addons/gut/comparator.gd') var Comparator = load("res://addons/gut/comparator.gd")
var CompareResult = load('res://addons/gut/compare_result.gd') var CompareResult = load("res://addons/gut/compare_result.gd")
var DiffTool = load('res://addons/gut/diff_tool.gd') var DiffTool = load("res://addons/gut/diff_tool.gd")
var Doubler = load('res://addons/gut/doubler.gd') var Doubler = load("res://addons/gut/doubler.gd")
var Gut = load('res://addons/gut/gut.gd') var Gut = load("res://addons/gut/gut.gd")
var HookScript = load('res://addons/gut/hook_script.gd') var HookScript = load("res://addons/gut/hook_script.gd")
var InnerClassRegistry = load('res://addons/gut/inner_class_registry.gd') var InnerClassRegistry = load("res://addons/gut/inner_class_registry.gd")
var InputFactory = load("res://addons/gut/input_factory.gd") var InputFactory = load("res://addons/gut/input_factory.gd")
var InputSender = load("res://addons/gut/input_sender.gd") var InputSender = load("res://addons/gut/input_sender.gd")
var JunitXmlExport = load('res://addons/gut/junit_xml_export.gd') var JunitXmlExport = load("res://addons/gut/junit_xml_export.gd")
var MethodMaker = load('res://addons/gut/method_maker.gd') var MethodMaker = load("res://addons/gut/method_maker.gd")
var OneToMany = load('res://addons/gut/one_to_many.gd') var OneToMany = load("res://addons/gut/one_to_many.gd")
var OrphanCounter = load('res://addons/gut/orphan_counter.gd') var OrphanCounter = load("res://addons/gut/orphan_counter.gd")
var ParameterFactory = load('res://addons/gut/parameter_factory.gd') var ParameterFactory = load("res://addons/gut/parameter_factory.gd")
var ParameterHandler = load('res://addons/gut/parameter_handler.gd') var ParameterHandler = load("res://addons/gut/parameter_handler.gd")
var Printers = load('res://addons/gut/printers.gd') var Printers = load("res://addons/gut/printers.gd")
var ResultExporter = load('res://addons/gut/result_exporter.gd') var ResultExporter = load("res://addons/gut/result_exporter.gd")
var ScriptCollector = load('res://addons/gut/script_parser.gd') var ScriptCollector = load("res://addons/gut/script_parser.gd")
var Spy = load('res://addons/gut/spy.gd') var Spy = load("res://addons/gut/spy.gd")
var Strutils = load('res://addons/gut/strutils.gd') var Strutils = load("res://addons/gut/strutils.gd")
var Stubber = load('res://addons/gut/stubber.gd') var Stubber = load("res://addons/gut/stubber.gd")
var StubParams = load('res://addons/gut/stub_params.gd') var StubParams = load("res://addons/gut/stub_params.gd")
var Summary = load('res://addons/gut/summary.gd') var Summary = load("res://addons/gut/summary.gd")
var Test = load('res://addons/gut/test.gd') var Test = load("res://addons/gut/test.gd")
var TestCollector = load('res://addons/gut/test_collector.gd') var TestCollector = load("res://addons/gut/test_collector.gd")
var ThingCounter = load('res://addons/gut/thing_counter.gd') var ThingCounter = load("res://addons/gut/thing_counter.gd")
# Source of truth for the GUT version # Source of truth for the GUT version
var version = '7.4.1' var version = "7.4.1"
# The required Godot version as an array. # The required Godot version as an array.
var req_godot = [3, 2, 0] var req_godot = [3, 2, 0]
@ -131,15 +134,19 @@ var non_super_methods = [
func _ready() -> void: func _ready() -> void:
_http_request_latest_version() _http_request_latest_version()
func _http_request_latest_version() -> void: func _http_request_latest_version() -> void:
return return
var http_request = HTTPRequest.new() var http_request = HTTPRequest.new()
http_request.name = "http_request" http_request.name = "http_request"
add_child(http_request) add_child(http_request)
http_request.connect("request_completed",Callable(self,"_on_http_request_latest_version_completed")) http_request.connect(
"request_completed", Callable(self, "_on_http_request_latest_version_completed")
)
# Perform a GET request. The URL below returns JSON as of writing. # Perform a GET request. The URL below returns JSON as of writing.
var __error = http_request.request("https://api.github.com/repos/bitwes/Gut/releases/latest") var __error = http_request.request("https://api.github.com/repos/bitwes/Gut/releases/latest")
func _on_http_request_latest_version_completed(result, response_code, headers, body): func _on_http_request_latest_version_completed(result, response_code, headers, body):
if not result == HTTPRequest.RESULT_SUCCESS: if not result == HTTPRequest.RESULT_SUCCESS:
return return
@ -155,29 +162,24 @@ func _on_http_request_latest_version_completed(result, response_code, headers, b
should_display_latest_version = true should_display_latest_version = true
const GUT_METADATA = "__gutdbl"
const GUT_METADATA = '__gutdbl'
# Note, these cannot change since places are checking for TYPE_INT to determine # Note, these cannot change since places are checking for TYPE_INT to determine
# how to process parameters. # how to process parameters.
enum DOUBLE_STRATEGY{ enum DOUBLE_STRATEGY { SCRIPT_ONLY, INCLUDE_SUPER }
SCRIPT_ONLY,
INCLUDE_SUPER enum DIFF { DEEP, SHALLOW, SIMPLE }
}
enum DIFF {
DEEP,
SHALLOW,
SIMPLE
}
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Blurb of text with GUT and Godot versions. # Blurb of text with GUT and Godot versions.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func get_version_text(): func get_version_text():
var v_info = Engine.get_version_info() var v_info = Engine.get_version_info()
var gut_version_info = str('GUT version: ', version) var gut_version_info = str("GUT version: ", version)
var godot_version_info = str('Godot version: ', v_info.major, '.', v_info.minor, '.', v_info.patch) var godot_version_info = str(
"Godot version: ", v_info.major, ".", v_info.minor, ".", v_info.patch
)
return godot_version_info + "\n" + gut_version_info return godot_version_info + "\n" + gut_version_info
@ -185,24 +187,26 @@ func get_version_text():
# Returns a nice string for erroring out when we have a bad Godot version. # Returns a nice string for erroring out when we have a bad Godot version.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func get_bad_version_text(): func get_bad_version_text():
var ver = '.'.join(PackedStringArray(req_godot)) var ver = ".".join(PackedStringArray(req_godot))
var info = Engine.get_version_info() var info = Engine.get_version_info()
var gd_version = str(info.major, '.', info.minor, '.', info.patch) var gd_version = str(info.major, ".", info.minor, ".", info.patch)
return 'GUT ' + version + ' requires Godot ' + ver + ' or greater. Godot version is ' + gd_version return (
"GUT " + version + " requires Godot " + ver + " or greater. Godot version is " + gd_version
)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Checks the Godot version against req_godot array. # Checks the Godot version against req_godot array.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func is_version_ok(engine_info=Engine.get_version_info(),required=req_godot): func is_version_ok(engine_info = Engine.get_version_info(), required = req_godot):
var is_ok = null var is_ok = null
var engine_array = [engine_info.major, engine_info.minor, engine_info.patch] var engine_array = [engine_info.major, engine_info.minor, engine_info.patch]
var idx = 0 var idx = 0
while(is_ok == null and idx < engine_array.size()): while is_ok == null and idx < engine_array.size():
if(engine_array[idx] > required[idx]): if engine_array[idx] > required[idx]:
is_ok = true is_ok = true
elif(engine_array[idx] < required[idx]): elif engine_array[idx] < required[idx]:
is_ok = false is_ok = false
idx += 1 idx += 1
@ -211,21 +215,21 @@ func is_version_ok(engine_info=Engine.get_version_info(),required=req_godot):
return nvl(is_ok, true) return nvl(is_ok, true)
func godot_version(engine_info=Engine.get_version_info()): func godot_version(engine_info = Engine.get_version_info()):
return str(engine_info.major, '.', engine_info.minor, '.', engine_info.patch) return str(engine_info.major, ".", engine_info.minor, ".", engine_info.patch)
func is_godot_version(expected, engine_info=Engine.get_version_info()): func is_godot_version(expected, engine_info = Engine.get_version_info()):
var engine_array = [engine_info.major, engine_info.minor, engine_info.patch] var engine_array = [engine_info.major, engine_info.minor, engine_info.patch]
var expected_array = expected.split('.') var expected_array = expected.split(".")
if(expected_array.size() > engine_array.size()): if expected_array.size() > engine_array.size():
return false return false
var is_version = true var is_version = true
var i = 0 var i = 0
while(i < expected_array.size() and i < engine_array.size() and is_version): while i < expected_array.size() and i < engine_array.size() and is_version:
if(expected_array[i] == str(engine_array[i])): if expected_array[i] == str(engine_array[i]):
i += 1 i += 1
else: else:
is_version = false is_version = false
@ -233,8 +237,8 @@ func is_godot_version(expected, engine_info=Engine.get_version_info()):
return is_version return is_version
func is_godot_version_gte(expected, engine_info=Engine.get_version_info()): func is_godot_version_gte(expected, engine_info = Engine.get_version_info()):
return is_version_ok(engine_info, expected.split('.')) return is_version_ok(engine_info, expected.split("."))
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -244,20 +248,19 @@ func is_godot_version_gte(expected, engine_info=Engine.get_version_info()):
# are not caused by getting bad warn/error/etc counts. # are not caused by getting bad warn/error/etc counts.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func get_logger(): func get_logger():
if(_test_mode): if _test_mode:
return Logger.new() return Logger.new()
else: else:
if(_lgr == null): if _lgr == null:
_lgr = Logger.new() _lgr = Logger.new()
return _lgr return _lgr
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# return if_null if value is null otherwise return value # return if_null if value is null otherwise return value
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func nvl(value, if_null): func nvl(value, if_null):
if(value == null): if value == null:
return if_null return if_null
else: else:
return value return value
@ -272,7 +275,7 @@ func nvl(value, if_null):
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func is_freed(obj): func is_freed(obj):
var wr = weakref(obj) var wr = weakref(obj)
return !(wr.get_ref() and str(obj) != '<Freed Object>') return !(wr.get_ref() and str(obj) != "<Freed Object>")
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -287,8 +290,8 @@ func is_not_freed(obj):
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func is_double(obj): func is_double(obj):
var to_return = false var to_return = false
if(typeof(obj) == TYPE_OBJECT and is_instance_valid(obj)): if typeof(obj) == TYPE_OBJECT and is_instance_valid(obj):
to_return = obj.has_method('__gutdbl_check_method__') to_return = obj.has_method("__gutdbl_check_method__")
return to_return return to_return
@ -296,13 +299,19 @@ func is_double(obj):
# Checks if the passed in is an instance of a class # Checks if the passed in is an instance of a class
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func is_instance(obj): func is_instance(obj):
return typeof(obj) == TYPE_OBJECT and !is_native_class(obj) and !obj.has_method('new') and !obj.has_method('instantiate') return (
typeof(obj) == TYPE_OBJECT
and !is_native_class(obj)
and !obj.has_method("new")
and !obj.has_method("instantiate")
)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Checks if the passed in is a GDScript # Checks if the passed in is a GDScript
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func is_gdscript(obj): func is_gdscript(obj):
return typeof(obj) == TYPE_OBJECT and str(obj).begins_with('<GDScript#') return typeof(obj) == TYPE_OBJECT and str(obj).begins_with("<GDScript#")
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -312,7 +321,7 @@ func is_gdscript(obj):
# for gdscripts inside a gdscript. # for gdscripts inside a gdscript.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func is_inner_class(obj): func is_inner_class(obj):
return is_gdscript(obj) and obj.resource_path == '' return is_gdscript(obj) and obj.resource_path == ""
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -320,7 +329,7 @@ func is_inner_class(obj):
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func extract_property_from_array(source, property): func extract_property_from_array(source, property):
var to_return = [] var to_return = []
for i in (source.size()): for i in source.size():
to_return.append(source[i].get(property)) to_return.append(source[i].get(property))
return to_return return to_return
@ -337,17 +346,18 @@ func file_exists(path):
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func write_file(path, content): func write_file(path, content):
var f = FileAccess.open(path, FileAccess.WRITE) var f = FileAccess.open(path, FileAccess.WRITE)
if(f != null): if f != null:
f.store_string(content) f.store_string(content)
f = null; f = null
return FileAccess.get_open_error() return FileAccess.get_open_error()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# true if what is passed in is null or an empty string. # true if what is passed in is null or an empty string.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func is_null_or_empty(text): func is_null_or_empty(text):
return text == null or text == '' return text == null or text == ""
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -356,10 +366,10 @@ func is_null_or_empty(text):
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func get_native_class_name(thing): func get_native_class_name(thing):
var to_return = null var to_return = null
if(is_native_class(thing)): if is_native_class(thing):
var newone = thing.new() var newone = thing.new()
to_return = newone.get_class() to_return = newone.get_class()
if(!newone is RefCounted): if !newone is RefCounted:
newone.free() newone.free()
return to_return return to_return
@ -369,7 +379,7 @@ func get_native_class_name(thing):
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func is_native_class(thing): func is_native_class(thing):
var it_is = false var it_is = false
if(typeof(thing) == TYPE_OBJECT): if typeof(thing) == TYPE_OBJECT:
it_is = str(thing).begins_with("<GDScriptNativeClass#") it_is = str(thing).begins_with("<GDScriptNativeClass#")
return it_is return it_is
@ -378,13 +388,14 @@ func is_native_class(thing):
# Returns the text of a file or an empty string if the file could not be opened. # Returns the text of a file or an empty string if the file could not be opened.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func get_file_as_text(path): func get_file_as_text(path):
var to_return = '' var to_return = ""
var f = FileAccess.open(path, FileAccess.READ) var f = FileAccess.open(path, FileAccess.READ)
if(f != null): if f != null:
to_return = f.get_as_text() to_return = f.get_as_text()
f = null f = null
return to_return return to_return
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Loops through an array of things and calls a method or checks a property on # Loops through an array of things and calls a method or checks a property on
# each element until it finds the returned value. -1 is returned if not found # each element until it finds the returned value. -1 is returned if not found
@ -394,25 +405,26 @@ func search_array_idx(ar, prop_method, value):
var found = false var found = false
var idx = 0 var idx = 0
while(idx < ar.size() and !found): while idx < ar.size() and !found:
var item = ar[idx] var item = ar[idx]
var prop = item.get(prop_method) var prop = item.get(prop_method)
if(!(prop is Callable)): if !(prop is Callable):
if(item.get(prop_method) == value): if item.get(prop_method) == value:
found = true found = true
elif(prop != null): elif prop != null:
var called_val = prop.call() var called_val = prop.call()
if(called_val == value): if called_val == value:
found = true found = true
if(!found): if !found:
idx += 1 idx += 1
if(found): if found:
return idx return idx
else: else:
return -1 return -1
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Loops through an array of things and calls a method or checks a property on # Loops through an array of things and calls a method or checks a property on
# each element until it finds the returned value. The item in the array is # each element until it finds the returned value. The item in the array is
@ -421,7 +433,7 @@ func search_array_idx(ar, prop_method, value):
func search_array(ar, prop_method, value): func search_array(ar, prop_method, value):
var idx = search_array_idx(ar, prop_method, value) var idx = search_array_idx(ar, prop_method, value)
if(idx != -1): if idx != -1:
return ar[idx] return ar[idx]
else: else:
return null return null
@ -432,7 +444,7 @@ func are_datatypes_same(got, expected):
func pretty_print(dict): func pretty_print(dict):
print(json.stringify(dict, ' ')) print(json.stringify(dict, " "))
func get_script_text(obj): func get_script_text(obj):
@ -452,9 +464,9 @@ func dec2bistr(decimal_value, max_bits = 31):
var temp var temp
var count = max_bits var count = max_bits
while(count >= 0): while count >= 0:
temp = decimal_value >> count temp = decimal_value >> count
if(temp & 1): if temp & 1:
binary_string = binary_string + "1" binary_string = binary_string + "1"
else: else:
binary_string = binary_string + "0" binary_string = binary_string + "0"
@ -464,28 +476,31 @@ func dec2bistr(decimal_value, max_bits = 31):
func add_line_numbers(contents): func add_line_numbers(contents):
if(contents == null): if contents == null:
return '' return ""
var to_return = "" var to_return = ""
var lines = contents.split("\n") var lines = contents.split("\n")
var line_num = 1 var line_num = 1
for line in lines: for line in lines:
var line_str = str(line_num).lpad(6, ' ') var line_str = str(line_num).lpad(6, " ")
to_return += str(line_str, ' |', line, "\n") to_return += str(line_str, " |", line, "\n")
line_num += 1 line_num += 1
return to_return return to_return
func pp(dict, indent=''):
var text = json.stringify(dict, ' ') func pp(dict, indent = ""):
var text = json.stringify(dict, " ")
print(text) print(text)
var _created_script_count = 0 var _created_script_count = 0
func create_script_from_source(source, override_path=null):
func create_script_from_source(source, override_path = null):
_created_script_count += 1 _created_script_count += 1
var r_path = ''#str('workaround for godot issue #65263 (', _created_script_count, ')') var r_path = "" #str('workaround for godot issue #65263 (', _created_script_count, ')')
if(override_path != null): if override_path != null:
r_path = override_path r_path = override_path
var DynamicScript = GDScript.new() var DynamicScript = GDScript.new()
@ -505,12 +520,15 @@ func get_scene_script_object(scene):
var root_node_path = NodePath(".") var root_node_path = NodePath(".")
var node_idx = 0 var node_idx = 0
while(node_idx < state.get_node_count() and to_return == null): while node_idx < state.get_node_count() and to_return == null:
# Assumes that the first node we encounter that has a root node path, one # Assumes that the first node we encounter that has a root node path, one
# property, and that property is named 'script' is the GDScript for the # property, and that property is named 'script' is the GDScript for the
# scene. This could be flawed. # scene. This could be flawed.
if(state.get_node_path(node_idx) == root_node_path and state.get_node_property_count(node_idx) == 1): if (
if(state.get_node_property_name(node_idx, 0) == 'script'): state.get_node_path(node_idx) == root_node_path
and state.get_node_property_count(node_idx) == 1
):
if state.get_node_property_name(node_idx, 0) == "script":
to_return = state.get_node_property_value(node_idx, 0) to_return = state.get_node_property_value(node_idx, 0)
node_idx += 1 node_idx += 1

View file

@ -71,16 +71,15 @@ class TestTheme:
func _get_pixelv(src: Vector2) -> Color: func _get_pixelv(src: Vector2) -> Color:
var screen := get_tree().root.get_texture().get_data() var screen := get_tree().root.get_texture().get_data()
false # screen.lock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed false # screen.lock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed
screen.flip_y() screen.flip_y()
var pixel := screen.get_pixelv(src) var pixel := screen.get_pixelv(src)
false # screen.unlock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed false # screen.unlock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed
return pixel return pixel
func _check_colors(theme: Theme): func _check_colors(theme: Theme):
var cell_size := Vector2( var cell_size := Vector2(
int(terminal.size.x / terminal.get_cols()), int(terminal.size.x / terminal.get_cols()), int(terminal.size.y / terminal.get_rows())
int(terminal.size.y / terminal.get_rows())
) )
var src := cell_size / 2 var src := cell_size / 2

View file

@ -137,7 +137,7 @@ func test_emits_exited_signal_when_child_process_exits():
class Helper: class Helper:
static func _get_pts() -> Array: static func _get_pts() -> Array:
assert(false) #,"Abstract method") assert(false) #,"Abstract method")
return [] return []
static func _get_winsize(fd: int) -> Dictionary: static func _get_winsize(fd: int) -> Dictionary:
@ -161,7 +161,7 @@ class Helper:
true, true,
output output
) )
assert(exit_code == 0) #,"Failed to run python command for this test.") assert(exit_code == 0) #,"Failed to run python command for this test.")
var size = str_to_var("Vector2" + output[0].strip_edges()) var size = str_to_var("Vector2" + output[0].strip_edges())
return {rows = int(size.x), cols = int(size.y)} return {rows = int(size.x), cols = int(size.y)}
@ -228,8 +228,8 @@ class LinuxHelper:
static func _get_pts() -> Array: static func _get_pts() -> Array:
var dir := Directory.new() var dir := Directory.new()
if dir.open("/dev/pts") != OK or dir.list_dir_begin() != OK:# TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547 if dir.open("/dev/pts") != OK or dir.list_dir_begin() != OK: # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547
assert(false) #,"Could not open /dev/pts.") assert(false) #,"Could not open /dev/pts.")
var pts := [] var pts := []
var file_name: String = dir.get_next() var file_name: String = dir.get_next()
@ -249,5 +249,5 @@ class MacOSHelper:
# TODO: Implement for macOS. # TODO: Implement for macOS.
# On macOS there is no /dev/pts directory, rather new ptys are created # On macOS there is no /dev/pts directory, rather new ptys are created
# under /dev/ttysXYZ. # under /dev/ttysXYZ.
assert(false) #,"Not implemented") assert(false) #,"Not implemented")
return [] return []