All checks were successful
Create tag and build when new code gets to main / Export (push) Successful in 7m6s
178 lines
5.4 KiB
GDScript
178 lines
5.4 KiB
GDScript
extends GdUnitFuncAssert
|
|
|
|
|
|
const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd")
|
|
const DEFAULT_TIMEOUT := 2000
|
|
|
|
|
|
var _current_value_provider :ValueProvider
|
|
var _current_failure_message :String = ""
|
|
var _custom_failure_message :String = ""
|
|
var _additional_failure_message: String = ""
|
|
var _line_number := -1
|
|
var _timeout := DEFAULT_TIMEOUT
|
|
var _interrupted := false
|
|
var _sleep_timer :Timer = null
|
|
|
|
|
|
func _init(instance :Object, func_name :String, args := Array()) -> void:
|
|
_line_number = GdUnitAssertions.get_line_number()
|
|
GdAssertReports.reset_last_error_line_number()
|
|
# save the actual assert instance on the current thread context
|
|
GdUnitThreadManager.get_current_context().set_assert(self)
|
|
# verify at first the function name exists
|
|
if not instance.has_method(func_name):
|
|
@warning_ignore("return_value_discarded")
|
|
report_error("The function '%s' do not exists checked instance '%s'." % [func_name, instance])
|
|
_interrupted = true
|
|
else:
|
|
_current_value_provider = CallBackValueProvider.new(instance, func_name, args)
|
|
|
|
|
|
func _notification(what :int) -> void:
|
|
if what == NOTIFICATION_PREDELETE:
|
|
_interrupted = true
|
|
var main_node :Node = (Engine.get_main_loop() as SceneTree).root
|
|
if is_instance_valid(_current_value_provider):
|
|
_current_value_provider.dispose()
|
|
_current_value_provider = null
|
|
if is_instance_valid(_sleep_timer):
|
|
_sleep_timer.set_wait_time(0.0001)
|
|
_sleep_timer.stop()
|
|
main_node.remove_child(_sleep_timer)
|
|
_sleep_timer.free()
|
|
_sleep_timer = null
|
|
|
|
|
|
func report_success() -> GdUnitFuncAssert:
|
|
GdAssertReports.report_success()
|
|
return self
|
|
|
|
|
|
func report_error(failure :String) -> GdUnitFuncAssert:
|
|
_current_failure_message = GdAssertMessages.build_failure_message(failure, _additional_failure_message, _custom_failure_message)
|
|
GdAssertReports.report_error(_current_failure_message, _line_number)
|
|
return self
|
|
|
|
|
|
func failure_message() -> String:
|
|
return _current_failure_message
|
|
|
|
|
|
func override_failure_message(message: String) -> GdUnitFuncAssert:
|
|
_custom_failure_message = message
|
|
return self
|
|
|
|
|
|
func append_failure_message(message: String) -> GdUnitFuncAssert:
|
|
_additional_failure_message = message
|
|
return self
|
|
|
|
|
|
func wait_until(timeout := 2000) -> GdUnitFuncAssert:
|
|
if timeout <= 0:
|
|
push_warning("Invalid timeout param, alloed timeouts must be grater than 0. Use default timeout instead")
|
|
_timeout = DEFAULT_TIMEOUT
|
|
else:
|
|
_timeout = timeout
|
|
return self
|
|
|
|
|
|
func is_null() -> GdUnitFuncAssert:
|
|
await _validate_callback(cb_is_null)
|
|
return self
|
|
|
|
|
|
func is_not_null() -> GdUnitFuncAssert:
|
|
await _validate_callback(cb_is_not_null)
|
|
return self
|
|
|
|
|
|
func is_false() -> GdUnitFuncAssert:
|
|
await _validate_callback(cb_is_false)
|
|
return self
|
|
|
|
|
|
func is_true() -> GdUnitFuncAssert:
|
|
await _validate_callback(cb_is_true)
|
|
return self
|
|
|
|
|
|
func is_equal(expected: Variant) -> GdUnitFuncAssert:
|
|
await _validate_callback(cb_is_equal, expected)
|
|
return self
|
|
|
|
|
|
func is_not_equal(expected: Variant) -> GdUnitFuncAssert:
|
|
await _validate_callback(cb_is_not_equal, expected)
|
|
return self
|
|
|
|
|
|
# we need actually to define this Callable as functions otherwise we results into leaked scripts here
|
|
# this is actually a Godot bug and needs this kind of workaround
|
|
func cb_is_null(c :Variant, _e :Variant) -> bool: return c == null
|
|
func cb_is_not_null(c :Variant, _e :Variant) -> bool: return c != null
|
|
func cb_is_false(c :Variant, _e :Variant) -> bool: return c == false
|
|
func cb_is_true(c :Variant, _e :Variant) -> bool: return c == true
|
|
func cb_is_equal(c :Variant, e :Variant) -> bool: return GdObjects.equals(c,e)
|
|
func cb_is_not_equal(c :Variant, e :Variant) -> bool: return not GdObjects.equals(c, e)
|
|
|
|
|
|
func do_interrupt() -> void:
|
|
_interrupted = true
|
|
|
|
|
|
func _validate_callback(predicate :Callable, expected :Variant = null) -> void:
|
|
if _interrupted:
|
|
return
|
|
GdUnitMemoryObserver.guard_instance(self)
|
|
var time_scale := Engine.get_time_scale()
|
|
var timer := Timer.new()
|
|
timer.set_name("gdunit_funcassert_interrupt_timer_%d" % timer.get_instance_id())
|
|
var scene_tree := Engine.get_main_loop() as SceneTree
|
|
scene_tree.root.add_child(timer)
|
|
timer.add_to_group("GdUnitTimers")
|
|
@warning_ignore("return_value_discarded")
|
|
timer.timeout.connect(do_interrupt, CONNECT_DEFERRED)
|
|
timer.set_one_shot(true)
|
|
timer.start((_timeout/1000.0)*time_scale)
|
|
_sleep_timer = Timer.new()
|
|
_sleep_timer.set_name("gdunit_funcassert_sleep_timer_%d" % _sleep_timer.get_instance_id() )
|
|
scene_tree.root.add_child(_sleep_timer)
|
|
|
|
while true:
|
|
var current :Variant = await next_current_value()
|
|
# is interupted or predicate success
|
|
if _interrupted or predicate.call(current, expected):
|
|
break
|
|
if is_instance_valid(_sleep_timer):
|
|
_sleep_timer.start(0.05)
|
|
await _sleep_timer.timeout
|
|
|
|
_sleep_timer.stop()
|
|
await scene_tree.process_frame
|
|
if _interrupted:
|
|
# https://github.com/godotengine/godot/issues/73052
|
|
#var predicate_name = predicate.get_method()
|
|
var predicate_name :String = str(predicate).split('::')[1]
|
|
@warning_ignore("return_value_discarded")
|
|
report_error(GdAssertMessages.error_interrupted(
|
|
predicate_name.strip_edges().trim_prefix("cb_"),
|
|
expected,
|
|
LocalTime.elapsed(_timeout)
|
|
)
|
|
)
|
|
else:
|
|
@warning_ignore("return_value_discarded")
|
|
report_success()
|
|
_sleep_timer.free()
|
|
timer.free()
|
|
GdUnitMemoryObserver.unguard_instance(self)
|
|
|
|
|
|
func next_current_value() -> Variant:
|
|
@warning_ignore("redundant_await")
|
|
if is_instance_valid(_current_value_provider):
|
|
return await _current_value_provider.get_value()
|
|
return "invalid value"
|