Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 23: Fix Unit Test CI #24

Merged
merged 4 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 38 additions & 11 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,44 @@ on:
workflow_dispatch:

jobs:
execute-gut:
name: Run GUT tests
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Docker test
# Using main to get latest fix for GLIBC_2.28 for Godot 4.2
uses: ceceppa/godot-gut-ci@main
with:
godot_version: 4.1.3
gut_params: -gdir=res://Tests/
- uses: actions/checkout@v2
- uses: croconut/[email protected]
with:
# required
version: "4.2.1"
# the type of release of godot that the tests should be run with
release_type: "stable"
is-mono: "false"
# the folder with your project.godot file in it
path: "./"
# how long to spend importing assets before tests are run
# import-time: "15"
# how long tests can run in seconds
# test-timeout: "45"
# the ratio of tests that must pass for this action to pass
# e.g. 0.6 means 60% of your tests must pass
minimum-pass: "1"
# the directory containing Gut tests
test-dir: "res://Tests/"
# instead of running GUT's command line tool,
# you can run a test scene if you have one
# set up a scene like in this repo --> located at /tester_GUT_v9.0.1/test/alt_mode/tests.tscn
# set up a script like in this repo --> located at /tester_GUT_v9.0.1/test/alt_mode/cli_test.gd
# ensure that the script exits on test completion
# uses relative path from your godot project directory
# direct-scene: "tester_GUT_v9.0.1/test/alt_mode/tests.tscn"
# default is false, set true to count asserts instead of tests
assert-check: "true"
# not checked by default, set to a number to limit the
# maximum amount of failed tests for a passing test suite
# default is GUTs default: 'res://.gutconfig.json'; set this to load a different config file
# config-file: "res://.gut_editor_config.json"
# designate a custom url to download the godot binary from
# custom-godot-dl-url: ""
# relative path to the xml file to read / write GUT's results from, recommended
# for direct-scene users to check this file if you have issues
result-output-file: "CI_test_results.xml"

Empty file added CI_test_results.xml
Empty file.
3 changes: 3 additions & 0 deletions addons/gut/awaiter.gd
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ func _physics_process(delta):


func _end_wait():
if(_signal_to_wait_on != null and _signal_to_wait_on.is_connected(_signal_callback)):
_signal_to_wait_on.disconnect(_signal_callback)

_wait_time = 0.0
_wait_frames = 0
_signal_to_wait_on = null
Expand Down
216 changes: 108 additions & 108 deletions addons/gut/collected_script.gd
Original file line number Diff line number Diff line change
Expand Up @@ -34,180 +34,180 @@ var was_run = false


var name = '' :
get: return path
set(val):pass
get: return path
set(val):pass


func _init(utils=null,logger=null):
_utils = utils
_lgr = logger
_utils = utils
_lgr = logger


func get_new():
return load_script().new()
return load_script().new()


func load_script():
var to_return = load(path)
var to_return = load(path)

if(inner_class_name != null and inner_class_name != ''):
# If we wanted to do inner classes in inner classses
# 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
# have to change to hold onto the loaded class instead of
# just path information.
to_return = to_return.get(inner_class_name)
if(inner_class_name != null and inner_class_name != ''):
# If we wanted to do inner classes in inner classses
# 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
# have to change to hold onto the loaded class instead of
# just path information.
to_return = to_return.get(inner_class_name)

return to_return
return to_return

# script.gd.InnerClass
func get_filename_and_inner():
var to_return = get_filename()
if(inner_class_name != ''):
to_return += '.' + String(inner_class_name)
return to_return
var to_return = get_filename()
if(inner_class_name != ''):
to_return += '.' + String(inner_class_name)
return to_return


# res://foo/bar.gd.FooBar
func get_full_name():
var to_return = path
if(inner_class_name != ''):
to_return += '.' + String(inner_class_name)
return to_return
var to_return = path
if(inner_class_name != ''):
to_return += '.' + String(inner_class_name)
return to_return


func get_filename():
return path.get_file()
return path.get_file()


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
# 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.
func export_to(config_file, section):
config_file.set_value(section, 'path', path)
config_file.set_value(section, 'inner_class', inner_class_name)
var names = []
for i in range(tests.size()):
names.append(tests[i].name)
config_file.set_value(section, 'tests', names)
config_file.set_value(section, 'path', path)
config_file.set_value(section, 'inner_class', inner_class_name)
var names = []
for i in range(tests.size()):
names.append(tests[i].name)
config_file.set_value(section, 'tests', names)


func _remap_path(source_path):
var to_return = source_path
if(!_utils.file_exists(source_path)):
_lgr.debug('Checking for remap for: ' + source_path)
var remap_path = source_path.get_basename() + '.gd.remap'
if(_utils.file_exists(remap_path)):
var cf = ConfigFile.new()
cf.load(remap_path)
to_return = cf.get_value('remap', 'path')
else:
_lgr.warn('Could not find remap file ' + remap_path)
return to_return
var to_return = source_path
if(!_utils.file_exists(source_path)):
_lgr.debug('Checking for remap for: ' + source_path)
var remap_path = source_path.get_basename() + '.gd.remap'
if(_utils.file_exists(remap_path)):
var cf = ConfigFile.new()
cf.load(remap_path)
to_return = cf.get_value('remap', 'path')
else:
_lgr.warn('Could not find remap file ' + remap_path)
return to_return


func import_from(config_file, section):
path = config_file.get_value(section, 'path')
path = _remap_path(path)
# 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
# out red text. This works around that.
var inner_name = config_file.get_value(section, 'inner_class', 'Placeholder')
if(inner_name != 'Placeholder'):
inner_class_name = inner_name
else: # just being explicit
inner_class_name = StringName("")
path = config_file.get_value(section, 'path')
path = _remap_path(path)
# 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
# out red text. This works around that.
var inner_name = config_file.get_value(section, 'inner_class', 'Placeholder')
if(inner_name != 'Placeholder'):
inner_class_name = inner_name
else: # just being explicit
inner_class_name = StringName("")


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):
for single_test in tests:
single_test.should_skip = single_test.name.ends_with(suffix)
for single_test in tests:
single_test.should_skip = single_test.name.ends_with(suffix)


func get_ran_test_count():
var count = 0
for t in tests:
if(t.was_run):
count += 1
return count
var count = 0
for t in tests:
if(t.was_run):
count += 1
return count


func get_assert_count():
var count = 0
for t in tests:
count += t.pass_texts.size()
count += t.fail_texts.size()
for t in setup_teardown_tests:
count += t.pass_texts.size()
count += t.fail_texts.size()
return count
var count = 0
for t in tests:
count += t.pass_texts.size()
count += t.fail_texts.size()
for t in setup_teardown_tests:
count += t.pass_texts.size()
count += t.fail_texts.size()
return count


func get_pass_count():
var count = 0
for t in tests:
count += t.pass_texts.size()
for t in setup_teardown_tests:
count += t.pass_texts.size()
return count
var count = 0
for t in tests:
count += t.pass_texts.size()
for t in setup_teardown_tests:
count += t.pass_texts.size()
return count


func get_fail_count():
var count = 0
for t in tests:
count += t.fail_texts.size()
for t in setup_teardown_tests:
count += t.fail_texts.size()
return count
var count = 0
for t in tests:
count += t.fail_texts.size()
for t in setup_teardown_tests:
count += t.fail_texts.size()
return count


func get_pending_count():
var count = 0
for t in tests:
count += t.pending_texts.size()
return count
var count = 0
for t in tests:
count += t.pending_texts.size()
return count


func get_passing_test_count():
var count = 0
for t in tests:
if(t.is_passing()):
count += 1
return count
var count = 0
for t in tests:
if(t.is_passing()):
count += 1
return count


func get_failing_test_count():
var count = 0
for t in tests:
if(t.is_failing()):
count += 1
return count
var count = 0
for t in tests:
if(t.is_failing()):
count += 1
return count


func get_risky_count():
var count = 0
if(was_skipped):
count = 1
else:
for t in tests:
if(t.is_risky()):
count += 1
return count
var count = 0
if(was_skipped):
count = 1
else:
for t in tests:
if(t.is_risky()):
count += 1
return count


func to_s():
var to_return = path
if(inner_class_name != null):
to_return += str('.', inner_class_name)
to_return += "\n"
for i in range(tests.size()):
to_return += str(' ', tests[i].to_s())
return to_return
var to_return = path
if(inner_class_name != null):
to_return += str('.', inner_class_name)
to_return += "\n"
for i in range(tests.size()):
to_return += str(' ', tests[i].to_s())
return to_return
3 changes: 2 additions & 1 deletion addons/gut/double_templates/function_template.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{func_decleration}
__gutdbl.spy_on('{method_name}', {param_array})
{vararg_warning}__gutdbl.spy_on('{method_name}', {param_array})
if(__gutdbl.should_call_super('{method_name}', {param_array})):
return {super_call}
else:
return __gutdbl.get_stubbed_return('{method_name}', {param_array})

1 change: 1 addition & 0 deletions addons/gut/double_templates/script_template.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var __gutdbl_values = {
gut = {gut_id},
from_singleton = '{singleton_name}',
is_partial = {is_partial},
doubled_methods = {doubled_methods},
}
var __gutdbl = load('res://addons/gut/double_tools.gd').new(__gutdbl_values)

Expand Down
Loading
Loading