TinyAdventure/addons/gdUnit4/src/core/_TestCase.gd

239 lines
5.8 KiB
GDScript
Raw Normal View History

class_name _TestCase
extends Node
signal completed()
# default timeout 5min
const DEFAULT_TIMEOUT := -1
const ARGUMENT_TIMEOUT := "timeout"
const ARGUMENT_SKIP := "do_skip"
const ARGUMENT_SKIP_REASON := "skip_reason"
var _iterations: int = 1
var _current_iteration: int = -1
var _seed: int
var _fuzzers: Array[GdFunctionArgument] = []
var _test_param_index := -1
var _line_number: int = -1
var _script_path: String
var _skipped := false
var _skip_reason := ""
var _expect_to_interupt := false
var _timer: Timer
var _interupted: bool = false
var _failed := false
var _report: GdUnitReport = null
var _parameter_set_resolver: GdUnitTestParameterSetResolver
var _is_disposed := false
var timeout: int = DEFAULT_TIMEOUT:
set(value):
timeout = value
get:
if timeout == DEFAULT_TIMEOUT:
timeout = GdUnitSettings.test_timeout()
return timeout
@warning_ignore("shadowed_variable_base_class")
func configure(p_name: String, p_line_number: int, p_script_path: String, p_timeout: int=DEFAULT_TIMEOUT, p_fuzzers: Array[GdFunctionArgument]=[], p_iterations: int=1, p_seed: int=-1) -> _TestCase:
set_name(p_name)
_line_number = p_line_number
_fuzzers = p_fuzzers
_iterations = p_iterations
_seed = p_seed
_script_path = p_script_path
timeout = p_timeout
return self
func execute(p_test_parameter := Array(), p_iteration := 0) -> void:
_failure_received(false)
_current_iteration = p_iteration - 1
if _current_iteration == - 1:
_set_failure_handler()
set_timeout()
if not p_test_parameter.is_empty():
update_fuzzers(p_test_parameter, p_iteration)
_execute_test_case(name, p_test_parameter)
else:
_execute_test_case(name, [])
await completed
func execute_paramaterized(p_test_parameter: Array) -> void:
_failure_received(false)
set_timeout()
# We need here to add a empty array to override the `test_parameters` to prevent initial "default" parameters from being used.
# This prevents objects in the argument list from being unnecessarily re-instantiated.
var test_parameters := p_test_parameter.duplicate() # is strictly need to duplicate the paramters before extend
test_parameters.append([])
_execute_test_case(name, test_parameters)
await completed
func dispose() -> void:
if _is_disposed:
return
_is_disposed = true
Engine.remove_meta("GD_TEST_FAILURE")
stop_timer()
_remove_failure_handler()
_fuzzers.clear()
_report = null
@warning_ignore("shadowed_variable_base_class", "redundant_await")
func _execute_test_case(name: String, test_parameter: Array) -> void:
# needs at least on await otherwise it breaks the awaiting chain
await get_parent().callv(name, test_parameter)
await Engine.get_main_loop().process_frame
completed.emit()
func update_fuzzers(input_values: Array, iteration: int) -> void:
for fuzzer :Variant in input_values:
if fuzzer is Fuzzer:
fuzzer._iteration_index = iteration + 1
func set_timeout() -> void:
if is_instance_valid(_timer):
return
var time: float = timeout / 1000.0
_timer = Timer.new()
add_child(_timer)
_timer.set_name("gdunit_test_case_timer_%d" % _timer.get_instance_id())
_timer.timeout.connect(func do_interrupt() -> void:
if is_fuzzed():
_report = GdUnitReport.new().create(GdUnitReport.INTERUPTED, line_number(), GdAssertMessages.fuzzer_interuped(_current_iteration, "timedout"))
else:
_report = GdUnitReport.new().create(GdUnitReport.INTERUPTED, line_number(), GdAssertMessages.test_timeout(timeout))
_interupted = true
completed.emit()
, CONNECT_DEFERRED)
_timer.set_one_shot(true)
_timer.set_wait_time(time)
_timer.set_autostart(false)
_timer.start()
func _set_failure_handler() -> void:
if not GdUnitSignals.instance().gdunit_set_test_failed.is_connected(_failure_received):
GdUnitSignals.instance().gdunit_set_test_failed.connect(_failure_received)
func _remove_failure_handler() -> void:
if GdUnitSignals.instance().gdunit_set_test_failed.is_connected(_failure_received):
GdUnitSignals.instance().gdunit_set_test_failed.disconnect(_failure_received)
func _failure_received(is_failed: bool) -> void:
# is already failed?
if _failed:
return
_failed = is_failed
Engine.set_meta("GD_TEST_FAILURE", is_failed)
func stop_timer() -> void:
# finish outstanding timeouts
if is_instance_valid(_timer):
_timer.stop()
_timer.call_deferred("free")
_timer = null
func expect_to_interupt() -> void:
_expect_to_interupt = true
func is_interupted() -> bool:
return _interupted
func is_expect_interupted() -> bool:
return _expect_to_interupt
func is_parameterized() -> bool:
return _parameter_set_resolver.is_parameterized()
func is_skipped() -> bool:
return _skipped
func report() -> GdUnitReport:
return _report
func skip_info() -> String:
return _skip_reason
func line_number() -> int:
return _line_number
func iterations() -> int:
return _iterations
func seed_value() -> int:
return _seed
func is_fuzzed() -> bool:
return not _fuzzers.is_empty()
func fuzzer_arguments() -> Array[GdFunctionArgument]:
return _fuzzers
func script_path() -> String:
return _script_path
func ResourcePath() -> String:
return _script_path
func generate_seed() -> void:
if _seed != -1:
seed(_seed)
func skip(skipped: bool, reason: String="") -> void:
_skipped = skipped
_skip_reason = reason
func set_function_descriptor(fd: GdFunctionDescriptor) -> void:
_parameter_set_resolver = GdUnitTestParameterSetResolver.new(fd)
func set_test_parameter_index(index: int) -> void:
_test_param_index = index
func test_parameter_index() -> int:
return _test_param_index
func test_case_names() -> PackedStringArray:
return _parameter_set_resolver.build_test_case_names(self)
func load_parameter_sets() -> Array:
return _parameter_set_resolver.load_parameter_sets(self, true)
func parameter_set_resolver() -> GdUnitTestParameterSetResolver:
return _parameter_set_resolver
func _to_string() -> String:
return "%s :%d (%dms)" % [get_name(), _line_number, timeout]