Skip to content

Commit

Permalink
fixed issue with bad orphan counts due to moved awaiter (#644)
Browse files Browse the repository at this point in the history
  • Loading branch information
bitwes authored Jul 24, 2024
1 parent 61e9dbf commit e264576
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 48 deletions.
6 changes: 3 additions & 3 deletions .gutconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
"res://test/integration/"
],
"should_exit": true,
"should_exit_on_success": false,
"log_level": 3,
"hide_orphans": false,

"should_exit_on_success": false,
"should_maximize": false,
"hide_orphans": true,
"ignore_pause": true,
"log_level": 1,
"double_strategy": "script_only",
"inner_class": "",
"disable_colors": false,
Expand Down
17 changes: 16 additions & 1 deletion addons/gut/gut.gd
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ func _should_skip_script(test_script, collected_script):
# Run all tests in a script. This is the core logic for running tests.
# ------------------------------------------------------------------------------
func _test_the_scripts(indexes=[]):
_orphan_counter.add_counter('total')
_orphan_counter.add_counter('pre_run')

_print_versions(false)
var is_valid = _init_run()
Expand Down Expand Up @@ -817,6 +817,11 @@ func _test_the_scripts(indexes=[]):
# END TEST SCRIPT LOOP

_lgr.set_indent_level(0)
# Give anything that is queued to be freed time to be freed before we count
# the orphans. Without this, the last test's awaiter won't be freed
# yet, which messes with the orphans total. There could also be objects
# the user has queued to be freed as well.
await get_tree().create_timer(.1).timeout
_end_run()


Expand Down Expand Up @@ -1178,10 +1183,20 @@ func show_orphans(should):
_lgr.set_type_enabled(_lgr.types.orphan, should)


# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
func get_logger():
return _lgr


# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
func get_test_script_count():
return _test_script_objects.size()




# ##############################################################################
# The MIT License (MIT)
# =====================
Expand Down
69 changes: 45 additions & 24 deletions addons/gut/orphan_counter.gd
Original file line number Diff line number Diff line change
@@ -1,11 +1,54 @@
# ------------------------------------------------------------------------------
# This is used to track the change in orphans over different intervals.
# You use this by adding a counter at the start of an interval and then
# using get_orphans_since to find out how many orphans have been created since
# that counter was added.
#
# For example, when a test starts, gut adds a counter for "test" which
# creates/sets the counter's value to the current orphan count. At the end of
# the test GUT uses get_orphans_since("test") to find out how many orphans
# were created by the test.
# ------------------------------------------------------------------------------
var _counters = {}

func orphan_count():
return Performance.get_monitor(Performance.OBJECT_ORPHAN_NODE_COUNT)

func add_counter(name):
_counters[name] = orphan_count()

# 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
# be somewhat visible that we've done something wrong.
func get_orphans_since(name):
return orphan_count() - _counters[name] if _counters.has(name) else -1

func get_count(name):
return _counters.get(name, -1)

func print_orphans(name, lgr):
var count = get_orphans_since(name)

if(count > 0):
var o = 'orphan'
if(count > 1):
o = 'orphans'
lgr.orphan(str(count, ' new ', o, ' in ', name, '.'))

func print_all():
var msg = str("Total Orphans ", orphan_count(), "\n", JSON.stringify(_counters, " "))
print(msg)



# ##############################################################################
#(G)odot (U)nit (T)est class
#
# ##############################################################################
# The MIT License (MIT)
# =====================
#
# Copyright (c) 2020 Tom "Butch" Wesley
# Copyright (c) 2024 Tom "Butch" Wesley
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
Expand All @@ -30,26 +73,4 @@
# add_counter is called it adds/resets the value in the dictionary to the
# current number of orphans. Each call to get_counter will return the change
# in orphans since add_counter was last called.
# ##############################################################################
var _counters = {}

func orphan_count():
return Performance.get_monitor(Performance.OBJECT_ORPHAN_NODE_COUNT)

func add_counter(name):
_counters[name] = orphan_count()

# 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
# be somewhat visible that we've done something wrong.
func get_counter(name):
return orphan_count() - _counters[name] if _counters.has(name) else -1

func print_orphans(name, lgr):
var count = get_counter(name)

if(count > 0):
var o = 'orphan'
if(count > 1):
o = 'orphans'
lgr.orphan(str(count, ' new ', o, ' in ', name, '.'))
# ##############################################################################
5 changes: 1 addition & 4 deletions addons/gut/result_exporter.gd
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,6 @@ func _make_results_dict():
return result


# TODO
# time
# errors
func get_results_dictionary(gut, include_scripts=true):
var scripts = []

Expand All @@ -82,7 +79,7 @@ func get_results_dictionary(gut, include_scripts=true):
props.errors = gut.logger.get_errors().size()
props.warnings = gut.logger.get_warnings().size()
props.time = gut.get_elapsed_time()
props.orphans = gut.get_orphan_counter().get_counter('total')
props.orphans = gut.get_orphan_counter().get_orphans_since('pre_run')
result.test_scripts.scripts = scripts

return result
Expand Down
1 change: 1 addition & 0 deletions addons/gut/strutils.gd
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class_name GutStringUtils
var types = {}

func _init_types_dictionary():
types[TYPE_NIL] = 'NIL'
types[TYPE_AABB] = 'AABB'
types[TYPE_ARRAY] = 'ARRAY'
types[TYPE_BASIS] = 'BASIS'
Expand Down
20 changes: 13 additions & 7 deletions addons/gut/summary.gd
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,22 @@ func _log_what_was_run(gut):


func _log_orphans_and_disclaimer(gut):
var orphan_count = gut.get_orphan_counter()
var lgr = gut.get_logger()
# Do not count any of the _test_script_objects since these will be released
# when GUT is released.
orphan_count._counters.total += gut._test_script_objects.size()
if(orphan_count.get_counter('total') > 0 and lgr.is_type_enabled('orphan')):
orphan_count.print_orphans('total', lgr)
if(!lgr.is_type_enabled('orphan')):
return

var counter = gut.get_orphan_counter()
# Do not count any of the test scripts since these will be released when GUT
# is released.
var do_not_count_orphans = counter.get_count("pre_run") + gut.get_test_script_count()
var total_run_orphans = counter.orphan_count() - do_not_count_orphans

if(total_run_orphans > 0):
lgr.orphan(str("Total orphans in run ", total_run_orphans))
gut.p("Note: This count does not include GUT objects that will be freed upon exit.")
gut.p(" It also does not include any orphans created by global scripts")
gut.p(" loaded before tests were ran.")
gut.p(str("Total orphans = ", orphan_count.orphan_count()))
gut.p(str("Total orphans = ", counter.orphan_count()))
gut.p('')


Expand All @@ -58,6 +63,7 @@ func _log_non_zero_total(text, value, lgr):
else:
return 0


func _log_totals(gut, totals):
var lgr = gut.get_logger()
lgr.log()
Expand Down
15 changes: 12 additions & 3 deletions addons/gut/test.gd
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ var InputSender = GutUtils.InputSender




var _was_ready_called = false
# I haven't decided if we should be using _ready or not. Right now gut.gd will
# call this if _ready was not called (because it was overridden without a super
# call). Maybe gut.gd should just call _do_ready_stuff (after we rename it to
Expand All @@ -89,10 +89,19 @@ func _do_ready_stuff():
_awaiter = GutUtils.Awaiter.new()
add_child(_awaiter)
_was_ready_called = true
var _was_ready_called = false


func _ready():
_do_ready_stuff()


func _notification(what):
# Tests are never expected to re-enter the tree. Tests are removed from the
# tree after they are run.
if(what == NOTIFICATION_EXIT_TREE):
_awaiter.queue_free()


func _str(thing):
return _strutils.type2str(thing)

Expand Down Expand Up @@ -1037,7 +1046,7 @@ func assert_not_freed(obj, title):
# the last thing your test does.
# ------------------------------------------------------------------------------
func assert_no_new_orphans(text=''):
var count = gut.get_orphan_counter().get_counter('test')
var count = gut.get_orphan_counter().get_orphans_since('test')
var msg = ''
if(text != ''):
msg = ': ' + text
Expand Down
26 changes: 23 additions & 3 deletions test/integration/test_everything_together.gd
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ class TestLogging:
_gut = Gut.new()
_gut._should_print_versions = false
_gut.log_level = 0
add_child(_gut)
add_child_autofree(_gut)

func after_each():
remove_child(_gut)

func test_gut_sets_doublers_logger():
assert_eq(_gut.get_doubler().get_logger(), _gut.logger, 'Doubler logger')
Expand All @@ -39,3 +37,25 @@ class TestLogging:

func test_test_colledtor_has_same_logger():
assert_eq(_gut.get_test_collector().get_logger(), _gut.logger)


class TestMemoryMgmt:
extends GutTest

func after_each():
assert_no_new_orphans()

func test_GutTest():
var t = GutTest.new()
add_child(t)
t.free()
assert_no_new_orphans()

func test_GutTest_with_waits():
var t = GutTest.new()
add_child(t)
await wait_frames(10)
t.free()
await wait_frames(10)
assert_no_new_orphans()

6 changes: 3 additions & 3 deletions test/unit/test_orphan_counter.gd
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ func test_can_add_get_counter():
stub(oc, 'orphan_count').to_return(6)
oc.add_counter('one')
stub(oc, 'orphan_count').to_return(10)
assert_eq(oc.get_counter('one'), 4)
assert_eq(oc.get_orphans_since('one'), 4)

func test_print_singular_orphan():
var oc = partial_double(GutUtils.OrphanCounter).new()
Expand Down Expand Up @@ -43,8 +43,8 @@ func test_adding_same_name_overwrites_prev_start_val():
stub(oc, 'orphan_count').to_return(2)
oc.add_counter('one')
stub(oc, 'orphan_count').to_return(10)
assert_eq(oc.get_counter('one'), 8)
assert_eq(oc.get_orphans_since('one'), 8)

func test_getting_count_for_names_that_dne_returns_neg_1():
var oc = GutUtils.OrphanCounter.new()
assert_eq(oc.get_counter('dne'), -1)
assert_eq(oc.get_orphans_since('dne'), -1)
7 changes: 7 additions & 0 deletions test/unit/test_test.gd
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ class TestMiscTests:
gr.test.set_logger(dlog)
assert_eq(gr.test.get_logger(), dlog)

func test_when_leaves_tree_awaiter_is_freed():
add_child(gr.test)
remove_child(gr.test)
await wait_frames(10)
assert_freed(gr.test._awaiter, 'awaiter')


# -------
# Spot check some type comparisons, these were all causing errors. These
# were adjusted from issue 510 sample code.
Expand Down

0 comments on commit e264576

Please sign in to comment.