godot-xterm/addons/gut/test_collector.gd
2024-01-06 23:33:15 +13:00

267 lines
6.2 KiB
GDScript

# ------------------------------------------------------------------------------
# This class handles calling out to the test parser and maintaining an array of
# collected_script.gd. This is used for both calling the tests and tracking
# the results of each script and test's execution.
#
# This also handles exporting and importing tests.
# ------------------------------------------------------------------------------
var CollectedScript = load("res://addons/gut/collected_script.gd")
var CollectedTest = load("res://addons/gut/collected_test.gd")
var _test_prefix = "test_"
var _test_class_prefix = "Test"
var _utils = load("res://addons/gut/utils.gd").get_instance()
var _lgr = _utils.get_logger()
# Array of CollectedScripts.
var scripts = []
func _does_inherit_from_test(thing):
var base_script = thing.get_base_script()
var to_return = false
if base_script != null:
var base_path = base_script.get_path()
if base_path == "res://addons/gut/test.gd":
to_return = true
else:
to_return = _does_inherit_from_test(base_script)
return to_return
func _populate_tests(test_script):
var script = test_script.load_script()
if script == null:
print(" !!! ", test_script.path, " could not be loaded")
return false
test_script.is_loaded = true
var methods = script.get_script_method_list()
for i in range(methods.size()):
var name = methods[i]["name"]
if name.begins_with(_test_prefix):
var t = CollectedTest.new()
t.name = name
t.arg_count = methods[i]["args"].size()
test_script.tests.append(t)
func _get_inner_test_class_names(loaded):
var inner_classes = []
var const_map = loaded.get_script_constant_map()
for key in const_map:
var thing = const_map[key]
if _utils.is_gdscript(thing):
if key.begins_with(_test_class_prefix):
if _does_inherit_from_test(thing):
inner_classes.append(key)
else:
_lgr.warn(
str("Ignoring Inner Class ", key, " because it does not extend GutTest")
)
# This could go deeper and find inner classes within inner classes
# but requires more experimentation. Right now I'm keeping it at
# one level since that is what the previous version did and there
# has been no demand for deeper nesting.
# _populate_inner_test_classes(thing)
return inner_classes
func _parse_script(test_script):
var inner_classes = []
var scripts_found = []
var loaded = load(test_script.path)
if _does_inherit_from_test(loaded):
_populate_tests(test_script)
scripts_found.append(test_script.path)
inner_classes = _get_inner_test_class_names(loaded)
else:
return []
for i in range(inner_classes.size()):
var loaded_inner = loaded.get(inner_classes[i])
if _does_inherit_from_test(loaded_inner):
var ts = CollectedScript.new(_utils, _lgr)
ts.path = test_script.path
ts.inner_class_name = inner_classes[i]
_populate_tests(ts)
scripts.append(ts)
scripts_found.append(test_script.path + "[" + inner_classes[i] + "]")
return scripts_found
# -----------------
# Public
# -----------------
func add_script(path):
# SHORTCIRCUIT
if has_script(path):
return []
# SHORTCIRCUIT
if !FileAccess.file_exists(path):
_lgr.error("Could not find script: " + path)
return
var ts = CollectedScript.new(_utils, _lgr)
ts.path = path
# Append right away because if we don't test_doubler.gd.TestInitParameters
# will HARD crash. I couldn't figure out what was causing the issue but
# appending right away, and then removing if it's not valid seems to fix
# things. It might have to do with the ordering of the test classes in
# the test collecter. I'm not really sure.
scripts.append(ts)
var parse_results = _parse_script(ts)
if parse_results.find(path) == -1:
_lgr.warn(str("Ignoring script ", path, " because it does not extend GutTest"))
scripts.remove_at(scripts.find(ts))
return parse_results
func clear():
scripts.clear()
func has_script(path):
var found = false
var idx = 0
while idx < scripts.size() and !found:
if scripts[idx].get_full_name() == path:
found = true
else:
idx += 1
return found
func export_tests(path):
var success = true
var f = ConfigFile.new()
for i in range(scripts.size()):
scripts[i].export_to(f, str("CollectedScript-", i))
var result = f.save(path)
if result != OK:
_lgr.error(str("Could not save exported tests to [", path, "]. Error code: ", result))
success = false
return success
func import_tests(path):
var success = false
var f = ConfigFile.new()
var result = f.load(path)
if result != OK:
_lgr.error(str("Could not load exported tests from [", path, "]. Error code: ", result))
else:
var sections = f.get_sections()
for key in sections:
var ts = CollectedScript.new(_utils, _lgr)
ts.import_from(f, key)
_populate_tests(ts)
scripts.append(ts)
success = true
return success
func get_script_named(name):
return _utils.search_array(scripts, "get_filename_and_inner", name)
func get_test_named(script_name, test_name):
var s = get_script_named(script_name)
if s != null:
return s.get_test_named(test_name)
else:
return null
func to_s():
var to_return = ""
for i in range(scripts.size()):
to_return += scripts[i].to_s() + "\n"
return to_return
# ---------------------
# Accessors
# ---------------------
func get_logger():
return _lgr
func set_logger(logger):
_lgr = logger
func get_test_prefix():
return _test_prefix
func set_test_prefix(test_prefix):
_test_prefix = test_prefix
func get_test_class_prefix():
return _test_class_prefix
func set_test_class_prefix(test_class_prefix):
_test_class_prefix = test_class_prefix
func get_scripts():
return scripts
func get_ran_test_count():
var count = 0
for s in scripts:
count += s.get_ran_test_count()
return count
func get_ran_script_count():
var count = 0
for s in scripts:
if s.was_run:
count += 1
return count
func get_test_count():
var count = 0
for s in scripts:
count += s.tests.size()
return count
func get_assert_count():
var count = 0
for s in scripts:
count += s.get_assert_count()
return count
func get_pass_count():
var count = 0
for s in scripts:
count += s.get_pass_count()
return count
func get_fail_count():
var count = 0
for s in scripts:
count += s.get_fail_count()
return count
func get_pending_count():
var count = 0
for s in scripts:
count += s.get_pending_count()
return count