reinstalling GDUnit from assetlib
Some checks failed
Create tag and build when new code gets to main / Export (push) Failing after 6m41s
Some checks failed
Create tag and build when new code gets to main / Export (push) Failing after 6m41s
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
class_name Comparator
|
||||
extends Resource
|
||||
|
||||
enum {
|
||||
EQUAL,
|
||||
LESS_THAN,
|
||||
LESS_EQUAL,
|
||||
GREATER_THAN,
|
||||
GREATER_EQUAL,
|
||||
BETWEEN_EQUAL,
|
||||
NOT_BETWEEN_EQUAL,
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://buiskkw1yyuw3
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
## Factory class providing convenient static methods to create various fuzzer instances.[br]
|
||||
##
|
||||
## Fuzzers is a utility class that simplifies the creation of different fuzzer types
|
||||
## for testing purposes. It provides static factory methods that create pre-configured
|
||||
## fuzzers with sensible defaults, making it easier to set up fuzz testing in your
|
||||
## test suites without manually instantiating each fuzzer type.[br]
|
||||
##
|
||||
## This class acts as a central access point for all fuzzer types, improving code
|
||||
## readability and reducing boilerplate in test cases.[br]
|
||||
##
|
||||
## @tutorial(Fuzzing Testing): https://en.wikipedia.org/wiki/Fuzzing
|
||||
class_name Fuzzers
|
||||
extends Resource
|
||||
|
||||
|
||||
## Generates random strings with length between [param min_length] and
|
||||
## [param max_length] (inclusive), using characters from [param charset].
|
||||
## See [StringFuzzer] for detailed documentation and examples.
|
||||
static func rand_str(min_length: int, max_length: int, charset := StringFuzzer.DEFAULT_CHARSET) -> StringFuzzer:
|
||||
return StringFuzzer.new(min_length, max_length, charset)
|
||||
|
||||
|
||||
## Creates a [BoolFuzzer] for generating random boolean values.[br]
|
||||
##
|
||||
## See [BoolFuzzer] for detailed documentation and examples.
|
||||
static func boolean() -> BoolFuzzer:
|
||||
return BoolFuzzer.new()
|
||||
|
||||
|
||||
## Creates an [IntFuzzer] for generating random integers within a range.[br]
|
||||
##
|
||||
## Generates random integers between [param from] and [param to] (inclusive)
|
||||
## using [constant IntFuzzer.NORMAL] mode.
|
||||
## See [IntFuzzer] for detailed documentation and examples.
|
||||
static func rangei(from: int, to: int) -> IntFuzzer:
|
||||
return IntFuzzer.new(from, to)
|
||||
|
||||
|
||||
## Creates a [FloatFuzzer] for generating random floats within a range.[br]
|
||||
##
|
||||
## Generates random float values between [param from] and [param to] (inclusive).
|
||||
## See [FloatFuzzer] for detailed documentation and examples.
|
||||
static func rangef(from: float, to: float) -> FloatFuzzer:
|
||||
return FloatFuzzer.new(from, to)
|
||||
|
||||
|
||||
## Creates a [Vector2Fuzzer] for generating random 2D vectors within a range.[br]
|
||||
##
|
||||
## Generates random Vector2 values where each component is bounded by
|
||||
## [param from] and [param to] (inclusive).
|
||||
## See [Vector2Fuzzer] for detailed documentation and examples.
|
||||
static func rangev2(from: Vector2, to: Vector2) -> Vector2Fuzzer:
|
||||
return Vector2Fuzzer.new(from, to)
|
||||
|
||||
|
||||
## Creates a [Vector3Fuzzer] for generating random 3D vectors within a range.[br]
|
||||
##
|
||||
## Generates random Vector3 values where each component is bounded by
|
||||
## [param from] and [param to] (inclusive).
|
||||
## See [Vector3Fuzzer] for detailed documentation and examples.
|
||||
static func rangev3(from: Vector3, to: Vector3) -> Vector3Fuzzer:
|
||||
return Vector3Fuzzer.new(from, to)
|
||||
|
||||
|
||||
## Creates an [IntFuzzer] that generates only even integers.[br]
|
||||
##
|
||||
## Generates random even integers between [param from] and [param to] (inclusive)
|
||||
## using [constant IntFuzzer.EVEN] mode.
|
||||
## See [IntFuzzer] for detailed documentation about even number generation.
|
||||
static func eveni(from: int, to: int) -> IntFuzzer:
|
||||
return IntFuzzer.new(from, to, IntFuzzer.EVEN)
|
||||
|
||||
|
||||
## Creates an [IntFuzzer] that generates only odd integers.[br]
|
||||
##
|
||||
## Generates random odd integers between [param from] and [param to] (inclusive)
|
||||
## using [constant IntFuzzer.ODD] mode.
|
||||
## See [IntFuzzer] for detailed documentation about odd number generation.
|
||||
static func oddi(from: int, to: int) -> IntFuzzer:
|
||||
return IntFuzzer.new(from, to, IntFuzzer.ODD)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://drfioswpw8u2u
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
## An Assertion Tool to verify array values
|
||||
@abstract class_name GdUnitArrayAssert
|
||||
extends GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is null.
|
||||
@abstract func is_null() -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not null.
|
||||
@abstract func is_not_null() -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array is equal to the given one.
|
||||
@abstract func is_equal(...expected: Array) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array is equal to the given one, ignoring case considerations.
|
||||
@abstract func is_equal_ignoring_case(...expected: Array) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array is not equal to the given one.
|
||||
@abstract func is_not_equal(...expected: Array) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array is not equal to the given one, ignoring case considerations.
|
||||
@abstract func is_not_equal_ignoring_case(...expected: Array) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Overrides the default failure message by given custom message.
|
||||
@abstract func override_failure_message(message: String) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Appends a custom message to the failure message.
|
||||
@abstract func append_failure_message(message: String) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array is empty, it has a size of 0.
|
||||
@abstract func is_empty() -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array is not empty, it has a size of minimum 1.
|
||||
@abstract func is_not_empty() -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array is the same. [br]
|
||||
## Compares the current by object reference equals
|
||||
@abstract func is_same(expected: Variant) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array is NOT the same. [br]
|
||||
## Compares the current by object reference equals
|
||||
@abstract func is_not_same(expected: Variant) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array has a size of given value.
|
||||
@abstract func has_size(expectd: int) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array contains the given values, in any order.[br]
|
||||
## The values are compared by deep parameter comparision, for object reference compare you have to use [method contains_same]
|
||||
@abstract func contains(...expected: Array) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array contains exactly only the given values and nothing else, in same order.[br]
|
||||
## The values are compared by deep parameter comparision, for object reference compare you have to use [method contains_same_exactly]
|
||||
@abstract func contains_exactly(...expected: Array) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array contains exactly only the given values and nothing else, in any order.[br]
|
||||
## The values are compared by deep parameter comparision, for object reference compare you have to use [method contains_same_exactly_in_any_order]
|
||||
@abstract func contains_exactly_in_any_order(...expected: Array) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array contains the given values, in any order.[br]
|
||||
## The values are compared by object reference, for deep parameter comparision use [method contains]
|
||||
@abstract func contains_same(...expected: Array) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array contains exactly only the given values and nothing else, in same order.[br]
|
||||
## The values are compared by object reference, for deep parameter comparision use [method contains_exactly]
|
||||
@abstract func contains_same_exactly(...expected: Array) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array contains exactly only the given values and nothing else, in any order.[br]
|
||||
## The values are compared by object reference, for deep parameter comparision use [method contains_exactly_in_any_order]
|
||||
@abstract func contains_same_exactly_in_any_order(...expected: Array) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array do NOT contains the given values, in any order.[br]
|
||||
## The values are compared by deep parameter comparision, for object reference compare you have to use [method not_contains_same]
|
||||
## [b]Example:[/b]
|
||||
## [codeblock]
|
||||
## # will succeed
|
||||
## assert_array([1, 2, 3, 4, 5]).not_contains(6)
|
||||
## # will fail
|
||||
## assert_array([1, 2, 3, 4, 5]).not_contains(2, 6)
|
||||
## [/codeblock]
|
||||
@abstract func not_contains(...expected: Array) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Verifies that the current Array do NOT contains the given values, in any order.[br]
|
||||
## The values are compared by object reference, for deep parameter comparision use [method not_contains]
|
||||
## [b]Example:[/b]
|
||||
## [codeblock]
|
||||
## # will succeed
|
||||
## assert_array([1, 2, 3, 4, 5]).not_contains(6)
|
||||
## # will fail
|
||||
## assert_array([1, 2, 3, 4, 5]).not_contains(2, 6)
|
||||
## [/codeblock]
|
||||
@abstract func not_contains_same(...expected: Array) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Extracts all values by given function name and optional arguments into a new ArrayAssert.
|
||||
## If the elements not accessible by `func_name` the value is converted to `"n.a"`, expecting null values
|
||||
@abstract func extract(func_name: String, ...func_args: Array) -> GdUnitArrayAssert
|
||||
|
||||
|
||||
## Extracts all values by given extractor's into a new ArrayAssert.
|
||||
## If the elements not extractable than the value is converted to `"n.a"`, expecting null values
|
||||
## -- The argument type is Array[GdUnitValueExtractor]
|
||||
@abstract func extractv(...extractors: Array) -> GdUnitArrayAssert
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://byeulsiqvaugq
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
## Base interface of all GdUnit asserts
|
||||
@abstract class_name GdUnitAssert
|
||||
extends RefCounted
|
||||
|
||||
|
||||
## Verifies that the current value is null.
|
||||
@abstract func is_null() -> GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not null.
|
||||
@abstract func is_not_null() -> GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is equal to expected one.
|
||||
@abstract func is_equal(expected: Variant) -> GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not equal to expected one.
|
||||
@abstract func is_not_equal(expected: Variant) -> GdUnitAssert
|
||||
|
||||
|
||||
## Overrides the default failure message by given custom message.[br]
|
||||
## This function allows you to replace the automatically generated failure message with a more specific
|
||||
## or user-friendly message that better describes the test failure context.[br]
|
||||
## Usage:
|
||||
## [codeblock]
|
||||
## # Override with custom context-specific message
|
||||
## func test_player_inventory():
|
||||
## assert_that(player.get_item_count("sword"))\
|
||||
## .override_failure_message("Player should have exactly one sword")\
|
||||
## .is_equal(1)
|
||||
## [/codeblock]
|
||||
@abstract func override_failure_message(message: String) -> GdUnitAssert
|
||||
|
||||
|
||||
## Appends a custom message to the failure message.[br]
|
||||
## This can be used to add additional information to the generated failure message
|
||||
## while keeping the original assertion details for better debugging context.[br]
|
||||
## Usage:
|
||||
## [codeblock]
|
||||
## # Add context to existing failure message
|
||||
## func test_player_health():
|
||||
## assert_that(player.health)\
|
||||
## .append_failure_message("Player was damaged by: %s" % last_damage_source)\
|
||||
## .is_greater(0)
|
||||
## [/codeblock]
|
||||
@abstract func append_failure_message(message: String) -> GdUnitAssert
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://bmy2nu4w22wia
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
class_name GdUnitAwaiter
|
||||
extends RefCounted
|
||||
|
||||
|
||||
# Waits for a specified signal in an interval of 50ms sent from the <source>, and terminates with an error after the specified timeout has elapsed.
|
||||
# source: the object from which the signal is emitted
|
||||
# signal_name: signal name
|
||||
# args: the expected signal arguments as an array
|
||||
# timeout: the timeout in ms, default is set to 2000ms
|
||||
func await_signal_on(source :Object, signal_name :String, args :Array = [], timeout_millis :int = 2000) -> Variant:
|
||||
# fail fast if the given source instance invalid
|
||||
var assert_that := GdUnitAssertImpl.new(signal_name)
|
||||
var line_number := GdUnitAssertions.get_line_number()
|
||||
if not is_instance_valid(source):
|
||||
@warning_ignore("return_value_discarded")
|
||||
assert_that.report_error(GdAssertMessages.error_await_signal_on_invalid_instance(source, signal_name, args), line_number)
|
||||
return await (Engine.get_main_loop() as SceneTree).process_frame
|
||||
# fail fast if the given source instance invalid
|
||||
if not is_instance_valid(source):
|
||||
@warning_ignore("return_value_discarded")
|
||||
assert_that.report_error(GdAssertMessages.error_await_signal_on_invalid_instance(source, signal_name, args), line_number)
|
||||
return await await_idle_frame()
|
||||
var awaiter := GdUnitSignalAwaiter.new(timeout_millis)
|
||||
var value :Variant = await awaiter.on_signal(source, signal_name, args)
|
||||
if awaiter.is_interrupted():
|
||||
var failure := "await_signal_on(%s, %s) timed out after %sms" % [signal_name, args, timeout_millis]
|
||||
@warning_ignore("return_value_discarded")
|
||||
assert_that.report_error(failure, line_number)
|
||||
return value
|
||||
|
||||
|
||||
# Waits for a specified signal sent from the <source> between idle frames and aborts with an error after the specified timeout has elapsed
|
||||
# source: the object from which the signal is emitted
|
||||
# signal_name: signal name
|
||||
# args: the expected signal arguments as an array
|
||||
# timeout: the timeout in ms, default is set to 2000ms
|
||||
func await_signal_idle_frames(source :Object, signal_name :String, args :Array = [], timeout_millis :int = 2000) -> Variant:
|
||||
var line_number := GdUnitAssertions.get_line_number()
|
||||
# fail fast if the given source instance invalid
|
||||
if not is_instance_valid(source):
|
||||
@warning_ignore("return_value_discarded")
|
||||
GdUnitAssertImpl.new(signal_name)\
|
||||
.report_error(GdAssertMessages.error_await_signal_on_invalid_instance(source, signal_name, args), line_number)
|
||||
return await await_idle_frame()
|
||||
var awaiter := GdUnitSignalAwaiter.new(timeout_millis, true)
|
||||
var value :Variant = await awaiter.on_signal(source, signal_name, args)
|
||||
if awaiter.is_interrupted():
|
||||
var failure := "await_signal_idle_frames(%s, %s) timed out after %sms" % [signal_name, args, timeout_millis]
|
||||
@warning_ignore("return_value_discarded")
|
||||
GdUnitAssertImpl.new(signal_name).report_error(failure, line_number)
|
||||
return value
|
||||
|
||||
|
||||
# Waits for for a given amount of milliseconds
|
||||
# example:
|
||||
# # waits for 100ms
|
||||
# await GdUnitAwaiter.await_millis(myNode, 100).completed
|
||||
# use this waiter and not `await get_tree().create_timer().timeout to prevent errors when a test case is timed out
|
||||
func await_millis(milliSec :int) -> void:
|
||||
var timer :Timer = Timer.new()
|
||||
timer.set_name("gdunit_await_millis_timer_%d" % timer.get_instance_id())
|
||||
(Engine.get_main_loop() as SceneTree).root.add_child(timer)
|
||||
timer.add_to_group("GdUnitTimers")
|
||||
timer.set_one_shot(true)
|
||||
timer.start(milliSec / 1000.0)
|
||||
await timer.timeout
|
||||
timer.queue_free()
|
||||
|
||||
|
||||
# Waits until the next idle frame
|
||||
func await_idle_frame() -> void:
|
||||
await (Engine.get_main_loop() as SceneTree).process_frame
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://c1jp2le4lldby
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
## An Assertion Tool to verify boolean values
|
||||
@abstract class_name GdUnitBoolAssert
|
||||
extends GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is null.
|
||||
@abstract func is_null() -> GdUnitBoolAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not null.
|
||||
@abstract func is_not_null() -> GdUnitBoolAssert
|
||||
|
||||
|
||||
## Verifies that the current value is equal to the given one.
|
||||
@abstract func is_equal(expected: Variant) -> GdUnitBoolAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not equal to the given one.
|
||||
@abstract func is_not_equal(expected: Variant) -> GdUnitBoolAssert
|
||||
|
||||
|
||||
## Overrides the default failure message by given custom message.
|
||||
@abstract func override_failure_message(message: String) -> GdUnitBoolAssert
|
||||
|
||||
|
||||
## Appends a custom message to the failure message.
|
||||
@abstract func append_failure_message(message: String) -> GdUnitBoolAssert
|
||||
|
||||
|
||||
## Verifies that the current value is true.
|
||||
@abstract func is_true() -> GdUnitBoolAssert
|
||||
|
||||
|
||||
## Verifies that the current value is false.
|
||||
@abstract func is_false() -> GdUnitBoolAssert
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://bftfpffmfb1il
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
class_name GdUnitConstants
|
||||
extends RefCounted
|
||||
|
||||
const NO_ARG :Variant = "<--null-->"
|
||||
|
||||
const EXPECT_ASSERT_REPORT_FAILURES := "expect_assert_report_failures"
|
||||
|
||||
## The maximum number of report history files to store
|
||||
const DEFAULT_REPORT_HISTORY_COUNT = 20
|
||||
const REPORT_DIR_PREFIX = "report_"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://dkap7kpfh2bhg
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
## An Assertion Tool to verify dictionary
|
||||
@abstract class_name GdUnitDictionaryAssert
|
||||
extends GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is null.
|
||||
@abstract func is_null() -> GdUnitDictionaryAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not null.
|
||||
@abstract func is_not_null() -> GdUnitDictionaryAssert
|
||||
|
||||
|
||||
## Verifies that the current dictionary is equal to the given one, ignoring order.
|
||||
@abstract func is_equal(expected: Variant) -> GdUnitDictionaryAssert
|
||||
|
||||
|
||||
## Verifies that the current dictionary is not equal to the given one, ignoring order.
|
||||
@abstract func is_not_equal(expected: Variant) -> GdUnitDictionaryAssert
|
||||
|
||||
|
||||
## Overrides the default failure message by given custom message.
|
||||
@abstract func override_failure_message(message: String) -> GdUnitDictionaryAssert
|
||||
|
||||
|
||||
## Appends a custom message to the failure message.
|
||||
@abstract func append_failure_message(message: String) -> GdUnitDictionaryAssert
|
||||
|
||||
|
||||
## Verifies that the current dictionary is empty, it has a size of 0.
|
||||
@abstract func is_empty() -> GdUnitDictionaryAssert
|
||||
|
||||
|
||||
## Verifies that the current dictionary is not empty, it has a size of minimum 1.
|
||||
@abstract func is_not_empty() -> GdUnitDictionaryAssert
|
||||
|
||||
|
||||
## Verifies that the current dictionary is the same. [br]
|
||||
## Compares the current by object reference equals
|
||||
@abstract func is_same(expected: Variant) -> GdUnitDictionaryAssert
|
||||
|
||||
|
||||
## Verifies that the current dictionary is NOT the same. [br]
|
||||
## Compares the current by object reference equals
|
||||
@abstract func is_not_same(expected: Variant) -> GdUnitDictionaryAssert
|
||||
|
||||
|
||||
## Verifies that the current dictionary has a size of given value.
|
||||
@abstract func has_size(expected: int) -> GdUnitDictionaryAssert
|
||||
|
||||
|
||||
## Verifies that the current dictionary contains the given key(s).[br]
|
||||
## The keys are compared by deep parameter comparision, for object reference compare you have to use [method contains_same_keys]
|
||||
@abstract func contains_keys(...expected: Array) -> GdUnitDictionaryAssert
|
||||
|
||||
|
||||
## Verifies that the current dictionary contains the given key and value.[br]
|
||||
## The key and value are compared by deep parameter comparision, for object reference compare you have to use [method contains_same_key_value]
|
||||
@abstract func contains_key_value(key: Variant, value: Variant) -> GdUnitDictionaryAssert
|
||||
|
||||
|
||||
## Verifies that the current dictionary not contains the given key(s).[br]
|
||||
## The keys are compared by deep parameter comparision, for object reference compare you have to use [method not_contains_same_keys]
|
||||
@abstract func not_contains_keys(...expected: Array) -> GdUnitDictionaryAssert
|
||||
|
||||
|
||||
## Verifies that the current dictionary contains the given key(s).[br]
|
||||
## The keys are compared by object reference, for deep parameter comparision use [method contains_keys]
|
||||
@abstract func contains_same_keys(expected: Array) -> GdUnitDictionaryAssert
|
||||
|
||||
|
||||
## Verifies that the current dictionary contains the given key and value.[br]
|
||||
## The key and value are compared by object reference, for deep parameter comparision use [method contains_key_value]
|
||||
@abstract func contains_same_key_value(key: Variant, value: Variant) -> GdUnitDictionaryAssert
|
||||
|
||||
|
||||
## Verifies that the current dictionary not contains the given key(s).
|
||||
## The keys are compared by object reference, for deep parameter comparision use [method not_contains_keys]
|
||||
@abstract func not_contains_same_keys(...expected: Array) -> GdUnitDictionaryAssert
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://8s1lymhdvlpu
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
## An assertion tool to verify GDUnit asserts.
|
||||
## This assert is for internal use only, to verify that failed asserts work as expected.
|
||||
@abstract class_name GdUnitFailureAssert
|
||||
extends GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is null.
|
||||
@abstract func is_null() -> GdUnitFailureAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not null.
|
||||
@abstract func is_not_null() -> GdUnitFailureAssert
|
||||
|
||||
|
||||
## Verifies that the current value is equal to the given one.
|
||||
@abstract func is_equal(expected: Variant) -> GdUnitFailureAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not equal to expected one.
|
||||
@abstract func is_not_equal(expected: Variant) -> GdUnitFailureAssert
|
||||
|
||||
|
||||
## Overrides the default failure message by given custom message.
|
||||
@abstract func override_failure_message(message: String) -> GdUnitFailureAssert
|
||||
|
||||
|
||||
## Appends a custom message to the failure message.
|
||||
@abstract func append_failure_message(message: String) -> GdUnitFailureAssert
|
||||
|
||||
|
||||
## Verifies if the executed assert was successful
|
||||
@abstract func is_success() -> GdUnitFailureAssert
|
||||
|
||||
|
||||
## Verifies if the executed assert has failed
|
||||
@abstract func is_failed() -> GdUnitFailureAssert
|
||||
|
||||
|
||||
## Verifies the failure line is equal to expected one.
|
||||
@abstract func has_line(expected: int) -> GdUnitFailureAssert
|
||||
|
||||
|
||||
## Verifies the failure message is equal to expected one.
|
||||
@abstract func has_message(expected: String) -> GdUnitFailureAssert
|
||||
|
||||
|
||||
## Verifies that the failure message starts with the expected message.
|
||||
@abstract func starts_with_message(expected: String) -> GdUnitFailureAssert
|
||||
|
||||
|
||||
## Verifies that the failure message contains the expected message.
|
||||
@abstract func contains_message(expected: String) -> GdUnitFailureAssert
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://x54vf4fue301
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
@abstract class_name GdUnitFileAssert
|
||||
extends GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is null.
|
||||
@abstract func is_null() -> GdUnitFileAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not null.
|
||||
@abstract func is_not_null() -> GdUnitFileAssert
|
||||
|
||||
|
||||
## Verifies that the current value is equal to the given one.
|
||||
@abstract func is_equal(expected: Variant) -> GdUnitFileAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not equal to expected one.
|
||||
@abstract func is_not_equal(expected: Variant) -> GdUnitFileAssert
|
||||
|
||||
|
||||
## Overrides the default failure message by given custom message.
|
||||
@abstract func override_failure_message(message: String) -> GdUnitFileAssert
|
||||
|
||||
|
||||
## Appends a custom message to the failure message.
|
||||
@abstract func append_failure_message(message: String) -> GdUnitFileAssert
|
||||
|
||||
|
||||
@abstract func is_file() -> GdUnitFileAssert
|
||||
|
||||
|
||||
@abstract func exists() -> GdUnitFileAssert
|
||||
|
||||
|
||||
@abstract func is_script() -> GdUnitFileAssert
|
||||
|
||||
|
||||
@abstract func contains_exactly(expected_rows :Array) -> GdUnitFileAssert
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://vt1hx0i6pg4h
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
## An Assertion Tool to verify float values
|
||||
@abstract class_name GdUnitFloatAssert
|
||||
extends GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is null.
|
||||
@abstract func is_null() -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not null.
|
||||
@abstract func is_not_null() -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Verifies that the current value is equal to the given one.
|
||||
@abstract func is_equal(expected: Variant) -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not equal to expected one.
|
||||
@abstract func is_not_equal(expected: Variant) -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Verifies that the current and expected value are approximately equal.
|
||||
@abstract func is_equal_approx(expected: float, approx: float) -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Overrides the default failure message by given custom message.
|
||||
@abstract func override_failure_message(message: String) -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Appends a custom message to the failure message.
|
||||
@abstract func append_failure_message(message: String) -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Verifies that the current value is less than the given one.
|
||||
@abstract func is_less(expected: float) -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Verifies that the current value is less than or equal the given one.
|
||||
@abstract func is_less_equal(expected: float) -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Verifies that the current value is greater than the given one.
|
||||
@abstract func is_greater(expected: float) -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Verifies that the current value is greater than or equal the given one.
|
||||
@abstract func is_greater_equal(expected: float) -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Verifies that the current value is negative.
|
||||
@abstract func is_negative() -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not negative.
|
||||
@abstract func is_not_negative() -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Verifies that the current value is equal to zero.
|
||||
@abstract func is_zero() -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not equal to zero.
|
||||
@abstract func is_not_zero() -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Verifies that the current value is in the given set of values.
|
||||
@abstract func is_in(expected: Array) -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not in the given set of values.
|
||||
@abstract func is_not_in(expected: Array) -> GdUnitFloatAssert
|
||||
|
||||
|
||||
## Verifies that the current value is between the given boundaries (inclusive).
|
||||
@abstract func is_between(from: float, to: float) -> GdUnitFloatAssert
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://l487wamffax1
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
## An Assertion Tool to verify function callback values
|
||||
@abstract class_name GdUnitFuncAssert
|
||||
extends GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is null.
|
||||
@abstract func is_null() -> GdUnitFuncAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not null.
|
||||
@abstract func is_not_null() -> GdUnitFuncAssert
|
||||
|
||||
|
||||
## Verifies that the current value is equal to the given one.
|
||||
@abstract func is_equal(expected: Variant) -> GdUnitFuncAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not equal to expected one.
|
||||
@abstract func is_not_equal(expected: Variant) -> GdUnitFuncAssert
|
||||
|
||||
|
||||
## Overrides the default failure message by given custom message.
|
||||
@abstract func override_failure_message(message: String) -> GdUnitFuncAssert
|
||||
|
||||
|
||||
## Appends a custom message to the failure message.
|
||||
@abstract func append_failure_message(message: String) -> GdUnitFuncAssert
|
||||
|
||||
|
||||
## Verifies that the current value is true.
|
||||
@abstract func is_true() -> GdUnitFuncAssert
|
||||
|
||||
|
||||
## Verifies that the current value is false.
|
||||
@abstract func is_false() -> GdUnitFuncAssert
|
||||
|
||||
|
||||
## Sets the timeout in ms to wait the function returnd the expected value, if the time over a failure is emitted.[br]
|
||||
## e.g.[br]
|
||||
## do wait until 5s the function `is_state` is returns 10 [br]
|
||||
## [code]assert_func(instance, "is_state").wait_until(5000).is_equal(10)[/code]
|
||||
@abstract func wait_until(timeout: int) -> GdUnitFuncAssert
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://bvvptcdhi1g14
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
## An assertion tool to verify for Godot runtime errors like assert() and push notifications like push_error().
|
||||
@abstract class_name GdUnitGodotErrorAssert
|
||||
extends GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is null.
|
||||
@abstract func is_null() -> GdUnitGodotErrorAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not null.
|
||||
@abstract func is_not_null() -> GdUnitGodotErrorAssert
|
||||
|
||||
|
||||
## Verifies that the current value is equal to the given one.
|
||||
@abstract func is_equal(expected: Variant) -> GdUnitGodotErrorAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not equal to expected one.
|
||||
@abstract func is_not_equal(expected: Variant) -> GdUnitGodotErrorAssert
|
||||
|
||||
|
||||
## Overrides the default failure message by given custom message.
|
||||
@abstract func override_failure_message(message: String) -> GdUnitGodotErrorAssert
|
||||
|
||||
|
||||
## Appends a custom message to the failure message.
|
||||
@abstract func append_failure_message(message: String) -> GdUnitGodotErrorAssert
|
||||
|
||||
|
||||
## Verifies if the executed code runs without any runtime errors
|
||||
## Usage:
|
||||
## [codeblock]
|
||||
## await assert_error(<callable>).is_success()
|
||||
## [/codeblock]
|
||||
@abstract func is_success() -> GdUnitGodotErrorAssert
|
||||
|
||||
|
||||
## Verifies if the executed code runs into a runtime error
|
||||
## Usage:
|
||||
## [codeblock]
|
||||
## await assert_error(<callable>).is_runtime_error(<expected error message>)
|
||||
## [/codeblock]
|
||||
@abstract func is_runtime_error(expected_error: Variant) -> GdUnitGodotErrorAssert
|
||||
|
||||
|
||||
## Verifies if the executed code has a push_warning() used
|
||||
## Usage:
|
||||
## [codeblock]
|
||||
## await assert_error(<callable>).is_push_warning(<expected push warning message>)
|
||||
## [/codeblock]
|
||||
@abstract func is_push_warning(expected_warning: Variant) -> GdUnitGodotErrorAssert
|
||||
|
||||
|
||||
## Verifies if the executed code has a push_error() used
|
||||
## Usage:
|
||||
## [codeblock]
|
||||
## await assert_error(<callable>).is_push_error(<expected push error message>)
|
||||
## [/codeblock]
|
||||
@abstract func is_push_error(expected_error: Variant) -> GdUnitGodotErrorAssert
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://bwkv3a1hhdt88
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
## An Assertion Tool to verify integer values
|
||||
@abstract class_name GdUnitIntAssert
|
||||
extends GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is null.
|
||||
@abstract func is_null() -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not null.
|
||||
@abstract func is_not_null() -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Verifies that the current value is equal to the given one.
|
||||
@abstract func is_equal(expected: Variant) -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not equal to expected one.
|
||||
@abstract func is_not_equal(expected: Variant) -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Overrides the default failure message by given custom message.
|
||||
@abstract func override_failure_message(message: String) -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Appends a custom message to the failure message.
|
||||
@abstract func append_failure_message(message: String) -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Verifies that the current value is less than the given one.
|
||||
@abstract func is_less(expected: int) -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Verifies that the current value is less than or equal the given one.
|
||||
@abstract func is_less_equal(expected: int) -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Verifies that the current value is greater than the given one.
|
||||
@abstract func is_greater(expected: int) -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Verifies that the current value is greater than or equal the given one.
|
||||
@abstract func is_greater_equal(expected: int) -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Verifies that the current value is even.
|
||||
@abstract func is_even() -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Verifies that the current value is odd.
|
||||
@abstract func is_odd() -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Verifies that the current value is negative.
|
||||
@abstract func is_negative() -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not negative.
|
||||
@abstract func is_not_negative() -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Verifies that the current value is equal to zero.
|
||||
@abstract func is_zero() -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not equal to zero.
|
||||
@abstract func is_not_zero() -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Verifies that the current value is in the given set of values.
|
||||
@abstract func is_in(expected: Array) -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not in the given set of values.
|
||||
@abstract func is_not_in(expected: Array) -> GdUnitIntAssert
|
||||
|
||||
|
||||
## Verifies that the current value is between the given boundaries (inclusive).
|
||||
@abstract func is_between(from: int, to: int) -> GdUnitIntAssert
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://ghuy35olsym1
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
## An Assertion Tool to verify Object values
|
||||
@abstract class_name GdUnitObjectAssert
|
||||
extends GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is null.
|
||||
@abstract func is_null() -> GdUnitObjectAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not null.
|
||||
@abstract func is_not_null() -> GdUnitObjectAssert
|
||||
|
||||
|
||||
## Verifies that the current value is equal to the given one.
|
||||
@abstract func is_equal(expected: Variant) -> GdUnitObjectAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not equal to expected one.
|
||||
@abstract func is_not_equal(expected: Variant) -> GdUnitObjectAssert
|
||||
|
||||
|
||||
## Overrides the default failure message by given custom message.
|
||||
@abstract func override_failure_message(message: String) -> GdUnitObjectAssert
|
||||
|
||||
|
||||
## Appends a custom message to the failure message.
|
||||
@abstract func append_failure_message(message: String) -> GdUnitObjectAssert
|
||||
|
||||
|
||||
## Verifies that the current object is the same as the given one.
|
||||
@abstract func is_same(expected: Variant) -> GdUnitObjectAssert
|
||||
|
||||
|
||||
## Verifies that the current object is not the same as the given one.
|
||||
@abstract func is_not_same(expected: Variant) -> GdUnitObjectAssert
|
||||
|
||||
|
||||
## Verifies that the current object is an instance of the given type.
|
||||
@abstract func is_instanceof(type: Variant) -> GdUnitObjectAssert
|
||||
|
||||
|
||||
## Verifies that the current object is not an instance of the given type.
|
||||
@abstract func is_not_instanceof(type: Variant) -> GdUnitObjectAssert
|
||||
|
||||
|
||||
## Checks whether the current object inherits from the specified type.
|
||||
@abstract func is_inheriting(type: Variant) -> GdUnitObjectAssert
|
||||
|
||||
|
||||
## Checks whether the current object does NOT inherit from the specified type.
|
||||
@abstract func is_not_inheriting(type: Variant) -> GdUnitObjectAssert
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://dmunl8xg53sym
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
## An Assertion Tool to verify Results
|
||||
@abstract class_name GdUnitResultAssert
|
||||
extends GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is null.
|
||||
@abstract func is_null() -> GdUnitResultAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not null.
|
||||
@abstract func is_not_null() -> GdUnitResultAssert
|
||||
|
||||
|
||||
## Verifies that the current value is equal to the given one.
|
||||
@abstract func is_equal(expected: Variant) -> GdUnitResultAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not equal to expected one.
|
||||
@abstract func is_not_equal(expected: Variant) -> GdUnitResultAssert
|
||||
|
||||
|
||||
## Overrides the default failure message by given custom message.
|
||||
@abstract func override_failure_message(message: String) -> GdUnitResultAssert
|
||||
|
||||
|
||||
## Appends a custom message to the failure message.
|
||||
@abstract func append_failure_message(message: String) -> GdUnitResultAssert
|
||||
|
||||
|
||||
## Verifies that the result is ends up with empty
|
||||
@abstract func is_empty() -> GdUnitResultAssert
|
||||
|
||||
|
||||
## Verifies that the result is ends up with success
|
||||
@abstract func is_success() -> GdUnitResultAssert
|
||||
|
||||
|
||||
## Verifies that the result is ends up with warning
|
||||
@abstract func is_warning() -> GdUnitResultAssert
|
||||
|
||||
|
||||
## Verifies that the result is ends up with error
|
||||
@abstract func is_error() -> GdUnitResultAssert
|
||||
|
||||
|
||||
## Verifies that the result contains the given message
|
||||
@abstract func contains_message(expected: String) -> GdUnitResultAssert
|
||||
|
||||
|
||||
## Verifies that the result contains the given value
|
||||
@abstract func is_value(expected: Variant) -> GdUnitResultAssert
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://b4n45twg8y2ar
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
## The Scene Runner is a tool used for simulating interactions on a scene.
|
||||
## With this tool, you can simulate input events such as keyboard or mouse input and/or simulate scene processing over a certain number of frames.
|
||||
## This tool is typically used for integration testing a scene.
|
||||
@abstract class_name GdUnitSceneRunner
|
||||
extends RefCounted
|
||||
|
||||
|
||||
## Simulates that an action has been pressed.[br]
|
||||
## [member action] : the action e.g. [code]"ui_up"[/code][br]
|
||||
## [member event_index] : [url=https://docs.godotengine.org/en/4.4/classes/class_inputeventaction.html#class-inputeventaction-property-event-index]default=-1[/url][br]
|
||||
@abstract func simulate_action_pressed(action: String, event_index := -1) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates that an action is pressed.[br]
|
||||
## [member action] : the action e.g. [code]"ui_up"[/code][br]
|
||||
## [member event_index] : [url=https://docs.godotengine.org/en/4.4/classes/class_inputeventaction.html#class-inputeventaction-property-event-index]default=-1[/url][br]
|
||||
@abstract func simulate_action_press(action: String, event_index := -1) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates that an action has been released.[br]
|
||||
## [member action] : the action e.g. [code]"ui_up"[/code][br]
|
||||
## [member event_index] : [url=https://docs.godotengine.org/en/4.4/classes/class_inputeventaction.html#class-inputeventaction-property-event-index]default=-1[/url][br]
|
||||
@abstract func simulate_action_release(action: String, event_index := -1) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates that a key has been pressed.[br]
|
||||
## [member key_code] : the key code e.g. [constant KEY_ENTER][br]
|
||||
## [member shift_pressed] : false by default set to true if simmulate shift is press[br]
|
||||
## [member ctrl_pressed] : false by default set to true if simmulate control is press[br]
|
||||
## [codeblock]
|
||||
## func test_key_presssed():
|
||||
## var runner = scene_runner("res://scenes/simple_scene.tscn")
|
||||
## await runner.simulate_key_pressed(KEY_SPACE)
|
||||
## [/codeblock]
|
||||
@abstract func simulate_key_pressed(key_code: int, shift_pressed := false, ctrl_pressed := false) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates that a key is pressed.[br]
|
||||
## [member key_code] : the key code e.g. [constant KEY_ENTER][br]
|
||||
## [member shift_pressed] : false by default set to true if simmulate shift is press[br]
|
||||
## [member ctrl_pressed] : false by default set to true if simmulate control is press[br]
|
||||
@abstract func simulate_key_press(key_code: int, shift_pressed := false, ctrl_pressed := false) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates that a key has been released.[br]
|
||||
## [member key_code] : the key code e.g. [constant KEY_ENTER][br]
|
||||
## [member shift_pressed] : false by default set to true if simmulate shift is press[br]
|
||||
## [member ctrl_pressed] : false by default set to true if simmulate control is press[br]
|
||||
@abstract func simulate_key_release(key_code: int, shift_pressed := false, ctrl_pressed := false) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Sets the mouse position to the specified vector, provided in pixels and relative to an origin at the upper left corner of the currently focused Window Manager game window.[br]
|
||||
## [member position] : The absolute position in pixels as Vector2
|
||||
@abstract func set_mouse_position(position: Vector2) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Returns the mouse's position in this Viewport using the coordinate system of this Viewport.
|
||||
@abstract func get_mouse_position() -> Vector2
|
||||
|
||||
|
||||
## Gets the current global mouse position of the current window
|
||||
@abstract func get_global_mouse_position() -> Vector2
|
||||
|
||||
|
||||
## Simulates a mouse moved to final position.[br]
|
||||
## [member position] : The final mouse position
|
||||
@abstract func simulate_mouse_move(position: Vector2) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates a mouse move to the relative coordinates (offset).[br]
|
||||
## [color=yellow]You must use [b]await[/b] to wait until the simulated mouse movement is complete.[/color][br]
|
||||
## [br]
|
||||
## [member relative] : The relative position, indicating the mouse position offset.[br]
|
||||
## [member time] : The time to move the mouse by the relative position in seconds (default is 1 second).[br]
|
||||
## [member trans_type] : Sets the type of transition used (default is TRANS_LINEAR).[br]
|
||||
## [codeblock]
|
||||
## func test_move_mouse():
|
||||
## var runner = scene_runner("res://scenes/simple_scene.tscn")
|
||||
## await runner.simulate_mouse_move_relative(Vector2(100,100))
|
||||
## [/codeblock]
|
||||
@abstract func simulate_mouse_move_relative(relative: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates a mouse move to the absolute coordinates.[br]
|
||||
## [color=yellow]You must use [b]await[/b] to wait until the simulated mouse movement is complete.[/color][br]
|
||||
## [br]
|
||||
## [member position] : The final position of the mouse.[br]
|
||||
## [member time] : The time to move the mouse to the final position in seconds (default is 1 second).[br]
|
||||
## [member trans_type] : Sets the type of transition used (default is TRANS_LINEAR).[br]
|
||||
## [codeblock]
|
||||
## func test_move_mouse():
|
||||
## var runner = scene_runner("res://scenes/simple_scene.tscn")
|
||||
## await runner.simulate_mouse_move_absolute(Vector2(100,100))
|
||||
## [/codeblock]
|
||||
@abstract func simulate_mouse_move_absolute(position: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates a mouse button pressed.[br]
|
||||
## [member button_index] : The mouse button identifier, one of the [enum MouseButton] or button wheel constants.
|
||||
## [member double_click] : Set to true to simulate a double-click
|
||||
@abstract func simulate_mouse_button_pressed(button_index: MouseButton, double_click := false) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates a mouse button press (holding)[br]
|
||||
## [member button_index] : The mouse button identifier, one of the [enum MouseButton] or button wheel constants.
|
||||
## [member double_click] : Set to true to simulate a double-click
|
||||
@abstract func simulate_mouse_button_press(button_index: MouseButton, double_click := false) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates a mouse button released.[br]
|
||||
## [member button_index] : The mouse button identifier, one of the [enum MouseButton] or button wheel constants.
|
||||
@abstract func simulate_mouse_button_release(button_index: MouseButton) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates a screen touch is pressed.[br]
|
||||
## [member index] : The touch index in the case of a multi-touch event.[br]
|
||||
## [member position] : The position to touch the screen.[br]
|
||||
## [member double_tap] : If true, the touch's state is a double tab.
|
||||
@abstract func simulate_screen_touch_pressed(index: int, position: Vector2, double_tap := false) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates a screen touch press without releasing it immediately, effectively simulating a "hold" action.[br]
|
||||
## [member index] : The touch index in the case of a multi-touch event.[br]
|
||||
## [member position] : The position to touch the screen.[br]
|
||||
## [member double_tap] : If true, the touch's state is a double tab.
|
||||
@abstract func simulate_screen_touch_press(index: int, position: Vector2, double_tap := false) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates a screen touch is released.[br]
|
||||
## [member index] : The touch index in the case of a multi-touch event.[br]
|
||||
## [member double_tap] : If true, the touch's state is a double tab.
|
||||
@abstract func simulate_screen_touch_release(index: int, double_tap := false) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates a touch drag and drop event to a relative position.[br]
|
||||
## [color=yellow]You must use [b]await[/b] to wait until the simulated drag&drop is complete.[/color][br]
|
||||
## [br]
|
||||
## [member index] : The touch index in the case of a multi-touch event.[br]
|
||||
## [member relative] : The relative position, indicating the drag&drop position offset.[br]
|
||||
## [member time] : The time to move to the relative position in seconds (default is 1 second).[br]
|
||||
## [member trans_type] : Sets the type of transition used (default is TRANS_LINEAR).[br]
|
||||
## [codeblock]
|
||||
## func test_touch_drag_drop():
|
||||
## var runner = scene_runner("res://scenes/simple_scene.tscn")
|
||||
## # start drag at position 50,50
|
||||
## runner.simulate_screen_touch_drag_begin(1, Vector2(50, 50))
|
||||
## # and drop it at final at 150,50 relative (50,50 + 100,0)
|
||||
## await runner.simulate_screen_touch_drag_relative(1, Vector2(100,0))
|
||||
## [/codeblock]
|
||||
@abstract func simulate_screen_touch_drag_relative(index: int, relative: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates a touch screen drop to the absolute coordinates (offset).[br]
|
||||
## [color=yellow]You must use [b]await[/b] to wait until the simulated drop is complete.[/color][br]
|
||||
## [br]
|
||||
## [member index] : The touch index in the case of a multi-touch event.[br]
|
||||
## [member position] : The final position, indicating the drop position.[br]
|
||||
## [member time] : The time to move to the final position in seconds (default is 1 second).[br]
|
||||
## [member trans_type] : Sets the type of transition used (default is TRANS_LINEAR).[br]
|
||||
## [codeblock]
|
||||
## func test_touch_drag_drop():
|
||||
## var runner = scene_runner("res://scenes/simple_scene.tscn")
|
||||
## # start drag at position 50,50
|
||||
## runner.simulate_screen_touch_drag_begin(1, Vector2(50, 50))
|
||||
## # and drop it at 100,50
|
||||
## await runner.simulate_screen_touch_drag_absolute(1, Vector2(100,50))
|
||||
## [/codeblock]
|
||||
@abstract func simulate_screen_touch_drag_absolute(index: int, position: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates a complete drag and drop event from one position to another.[br]
|
||||
## This is ideal for testing complex drag-and-drop scenarios that require a specific start and end position.[br]
|
||||
## [color=yellow]You must use [b]await[/b] to wait until the simulated drop is complete.[/color][br]
|
||||
## [br]
|
||||
## [member index] : The touch index in the case of a multi-touch event.[br]
|
||||
## [member position] : The drag start position, indicating the drag position.[br]
|
||||
## [member drop_position] : The drop position, indicating the drop position.[br]
|
||||
## [member time] : The time to move to the final position in seconds (default is 1 second).[br]
|
||||
## [member trans_type] : Sets the type of transition used (default is TRANS_LINEAR).[br]
|
||||
## [codeblock]
|
||||
## func test_touch_drag_drop():
|
||||
## var runner = scene_runner("res://scenes/simple_scene.tscn")
|
||||
## # start drag at position 50,50 and drop it at 100,50
|
||||
## await runner.simulate_screen_touch_drag_drop(1, Vector2(50, 50), Vector2(100,50))
|
||||
## [/codeblock]
|
||||
@abstract func simulate_screen_touch_drag_drop(index: int, position: Vector2, drop_position: Vector2, time: float = 1.0, trans_type: Tween.TransitionType = Tween.TRANS_LINEAR) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates a touch screen drag event to given position.[br]
|
||||
## [member index] : The touch index in the case of a multi-touch event.[br]
|
||||
## [member position] : The drag start position, indicating the drag position.[br]
|
||||
@abstract func simulate_screen_touch_drag(index: int, position: Vector2) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Returns the actual position of the touchscreen drag position by given index.
|
||||
## [member index] : The touch index in the case of a multi-touch event.[br]
|
||||
@abstract func get_screen_touch_drag_position(index: int) -> Vector2
|
||||
|
||||
|
||||
## Sets how fast or slow the scene simulation is processed (clock ticks versus the real).[br]
|
||||
## It defaults to 1.0. A value of 2.0 means the game moves twice as fast as real life,
|
||||
## whilst a value of 0.5 means the game moves at half the regular speed.
|
||||
## [member time_factor] : A float representing the simulation speed.[br]
|
||||
## - Default is 1.0, meaning the simulation runs at normal speed.[br]
|
||||
## - A value of 2.0 means the simulation runs twice as fast as real time.[br]
|
||||
## - A value of 0.5 means the simulation runs at half the regular speed.[br]
|
||||
@abstract func set_time_factor(time_factor: float = 1.0) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates scene processing for a certain number of frames.[br]
|
||||
## [member frames] : amount of frames to process[br]
|
||||
## [member delta_milli] : the time delta between a frame in milliseconds
|
||||
@abstract func simulate_frames(frames: int, delta_milli: int = -1) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates scene processing until the given signal is emitted by the scene.[br]
|
||||
## [member signal_name] : the signal to stop the simulation[br]
|
||||
## [member args] : optional signal arguments to be matched for stop[br]
|
||||
@abstract func simulate_until_signal(signal_name: String, ...args: Array) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Simulates scene processing until the given signal is emitted by the given object.[br]
|
||||
## [member source] : the object that should emit the signal[br]
|
||||
## [member signal_name] : the signal to stop the simulation[br]
|
||||
## [member args] : optional signal arguments to be matched for stop
|
||||
@abstract func simulate_until_object_signal(source: Object, signal_name: String, ...args: Array) -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Waits for all input events to be processed by flushing any buffered input events
|
||||
## and then awaiting a full cycle of both the process and physics frames.[br]
|
||||
## [br]
|
||||
## This is typically used to ensure that any simulated or queued inputs are fully
|
||||
## processed before proceeding with the next steps in the scene.[br]
|
||||
## It's essential for reliable input simulation or when synchronizing logic based
|
||||
## on inputs.[br]
|
||||
##
|
||||
## Usage Example:
|
||||
## [codeblock]
|
||||
## await await_input_processed() # Ensure all inputs are processed before continuing
|
||||
## [/codeblock]
|
||||
@abstract func await_input_processed() -> void
|
||||
|
||||
|
||||
## The await_func function pauses execution until a specified function in the scene returns a value.[br]
|
||||
## It returns a [GdUnitFuncAssert], which provides a suite of assertion methods to verify the returned value.[br]
|
||||
## [member func_name] : The name of the function to wait for.[br]
|
||||
## [member args] : Optional function arguments
|
||||
## [br]
|
||||
## Usage Example:
|
||||
## [codeblock]
|
||||
## # Waits for 'calculate_score' function and verifies the result is equal to 100.
|
||||
## await_func("calculate_score").is_equal(100)
|
||||
## [/codeblock]
|
||||
@abstract func await_func(func_name: String, ...args: Array) -> GdUnitFuncAssert
|
||||
|
||||
|
||||
## The await_func_on function extends the functionality of await_func by allowing you to specify a source node within the scene.[br]
|
||||
## It waits for a specified function on that node to return a value and returns a [GdUnitFuncAssert] object for assertions.[br]
|
||||
## [member source] : The object where implements the function.[br]
|
||||
## [member func_name] : The name of the function to wait for.[br]
|
||||
## [member args] : optional function arguments
|
||||
## [br]
|
||||
## Usage Example:
|
||||
## [codeblock]
|
||||
## # Waits for 'calculate_score' function and verifies the result is equal to 100.
|
||||
## var my_instance := ScoreCalculator.new()
|
||||
## await_func(my_instance, "calculate_score").is_equal(100)
|
||||
## [/codeblock]
|
||||
@abstract func await_func_on(source: Object, func_name: String, ...args: Array) -> GdUnitFuncAssert
|
||||
|
||||
|
||||
## Waits for the specified signal to be emitted by the scene. If the signal is not emitted within the given timeout, the operation fails.[br]
|
||||
## [member signal_name] : The name of the signal to wait for[br]
|
||||
## [member args] : The signal arguments as an array[br]
|
||||
## [member timeout] : The maximum duration (in milliseconds) to wait for the signal to be emitted before failing
|
||||
@abstract func await_signal(signal_name: String, args := [], timeout := 2000 ) -> void
|
||||
|
||||
|
||||
## Waits for the specified signal to be emitted by a particular source node. If the signal is not emitted within the given timeout, the operation fails.[br]
|
||||
## [member source] : the object from which the signal is emitted[br]
|
||||
## [member signal_name] : The name of the signal to wait for[br]
|
||||
## [member args] : The signal arguments as an array[br]
|
||||
## [member timeout] : tThe maximum duration (in milliseconds) to wait for the signal to be emitted before failing
|
||||
@abstract func await_signal_on(source: Object, signal_name: String, args := [], timeout := 2000 ) -> void
|
||||
|
||||
|
||||
## Restores the scene window to a windowed mode and brings it to the foreground.[br]
|
||||
## This ensures that the scene is visible and active during testing, making it easier to observe and interact with.
|
||||
@abstract func move_window_to_foreground() -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Minimizes the scene window to a windowed mode and brings it to the background.[br]
|
||||
## This ensures that the scene is hidden during testing.
|
||||
@abstract func move_window_to_background() -> GdUnitSceneRunner
|
||||
|
||||
|
||||
## Return the current value of the property with the name <name>.[br]
|
||||
## [member name] : name of property[br]
|
||||
## [member return] : the value of the property
|
||||
@abstract func get_property(name: String) -> Variant
|
||||
|
||||
|
||||
## Set the value <value> of the property with the name <name>.[br]
|
||||
## [member name] : name of property[br]
|
||||
## [member value] : value of property[br]
|
||||
## [member return] : true|false depending on valid property name.
|
||||
@abstract func set_property(name: String, value: Variant) -> bool
|
||||
|
||||
|
||||
## executes the function specified by <name> in the scene and returns the result.[br]
|
||||
## [member name] : the name of the function to execute[br]
|
||||
## [member args] : optional function arguments[br]
|
||||
## [member return] : the function result
|
||||
@abstract func invoke(name: String, ...args: Array) -> Variant
|
||||
|
||||
|
||||
## Searches for the specified node with the name in the current scene and returns it, otherwise null.[br]
|
||||
## [member name] : the name of the node to find[br]
|
||||
## [member recursive] : enables/disables seraching recursive[br]
|
||||
## [member return] : the node if find otherwise null
|
||||
@abstract func find_child(name: String, recursive: bool = true, owned: bool = false) -> Node
|
||||
|
||||
|
||||
## Access to current running scene
|
||||
@abstract func scene() -> Node
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://dn20c5e8kb3q3
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
## An Assertion Tool to verify for emitted signals until a waiting time
|
||||
@abstract class_name GdUnitSignalAssert
|
||||
extends GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is null.
|
||||
@abstract func is_null() -> GdUnitSignalAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not null.
|
||||
@abstract func is_not_null() -> GdUnitSignalAssert
|
||||
|
||||
|
||||
## Verifies that the current value is equal to the given one.
|
||||
@abstract func is_equal(expected: Variant) -> GdUnitSignalAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not equal to expected one.
|
||||
@abstract func is_not_equal(expected: Variant) -> GdUnitSignalAssert
|
||||
|
||||
|
||||
## Overrides the default failure message by given custom message.
|
||||
@abstract func override_failure_message(message: String) -> GdUnitSignalAssert
|
||||
|
||||
|
||||
## Appends a custom message to the failure message.
|
||||
@abstract func append_failure_message(message: String) -> GdUnitSignalAssert
|
||||
|
||||
|
||||
## Verifies that given signal is emitted until waiting time
|
||||
@abstract func is_emitted(name: String, args := []) -> GdUnitSignalAssert
|
||||
|
||||
|
||||
## Verifies that given signal is NOT emitted until waiting time
|
||||
@abstract func is_not_emitted(name: String, args := []) -> GdUnitSignalAssert
|
||||
|
||||
|
||||
## Verifies the signal exists checked the emitter
|
||||
@abstract func is_signal_exists(name: String) -> GdUnitSignalAssert
|
||||
|
||||
|
||||
## Sets the assert signal timeout in ms, if the time over a failure is reported.[br]
|
||||
## e.g.[br]
|
||||
## do wait until 5s the instance has emitted the signal `signal_a`[br]
|
||||
## [code]assert_signal(instance).wait_until(5000).is_emitted("signal_a")[/code]
|
||||
@abstract func wait_until(timeout: int) -> GdUnitSignalAssert
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://572nse6u4l86
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
## An Assertion Tool to verify String values
|
||||
@abstract class_name GdUnitStringAssert
|
||||
extends GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is null.
|
||||
@abstract func is_null() -> GdUnitStringAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not null.
|
||||
@abstract func is_not_null() -> GdUnitStringAssert
|
||||
|
||||
|
||||
## Verifies that the current value is equal to the given one.
|
||||
@abstract func is_equal(expected: Variant) -> GdUnitStringAssert
|
||||
|
||||
|
||||
## Verifies that the current String is equal to the given one, ignoring case considerations.
|
||||
@abstract func is_equal_ignoring_case(expected: Variant) -> GdUnitStringAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not equal to expected one.
|
||||
@abstract func is_not_equal(expected: Variant) -> GdUnitStringAssert
|
||||
|
||||
|
||||
## Verifies that the current String is not equal to the given one, ignoring case considerations.
|
||||
@abstract func is_not_equal_ignoring_case(expected: Variant) -> GdUnitStringAssert
|
||||
|
||||
|
||||
## Overrides the default failure message by given custom message.
|
||||
@abstract func override_failure_message(message: String) -> GdUnitStringAssert
|
||||
|
||||
|
||||
## Appends a custom message to the failure message.
|
||||
@abstract func append_failure_message(message: String) -> GdUnitStringAssert
|
||||
|
||||
|
||||
## Verifies that the current String is empty, it has a length of 0.
|
||||
@abstract func is_empty() -> GdUnitStringAssert
|
||||
|
||||
|
||||
## Verifies that the current String is not empty, it has a length of minimum 1.
|
||||
@abstract func is_not_empty() -> GdUnitStringAssert
|
||||
|
||||
|
||||
## Verifies that the current String contains the given String.
|
||||
@abstract func contains(expected: String) -> GdUnitStringAssert
|
||||
|
||||
|
||||
## Verifies that the current String does not contain the given String.
|
||||
@abstract func not_contains(expected: String) -> GdUnitStringAssert
|
||||
|
||||
|
||||
## Verifies that the current String does not contain the given String, ignoring case considerations.
|
||||
@abstract func contains_ignoring_case(expected: String) -> GdUnitStringAssert
|
||||
|
||||
|
||||
## Verifies that the current String does not contain the given String, ignoring case considerations.
|
||||
@abstract func not_contains_ignoring_case(expected: String) -> GdUnitStringAssert
|
||||
|
||||
|
||||
## Verifies that the current String starts with the given prefix.
|
||||
@abstract func starts_with(expected: String) -> GdUnitStringAssert
|
||||
|
||||
|
||||
## Verifies that the current String ends with the given suffix.
|
||||
@abstract func ends_with(expected: String) -> GdUnitStringAssert
|
||||
|
||||
|
||||
## Verifies that the current String has the expected length by used comparator.
|
||||
@abstract func has_length(length: int, comparator: int = Comparator.EQUAL) -> GdUnitStringAssert
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://ip241g801xri
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://cgbfa4cflb5nl
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
## A tuple implementation to hold two or many values
|
||||
class_name GdUnitTuple
|
||||
extends RefCounted
|
||||
|
||||
const NO_ARG :Variant = GdUnitConstants.NO_ARG
|
||||
|
||||
var __values :Array = Array()
|
||||
|
||||
|
||||
func _init(arg0:Variant,
|
||||
arg1 :Variant=NO_ARG,
|
||||
arg2 :Variant=NO_ARG,
|
||||
arg3 :Variant=NO_ARG,
|
||||
arg4 :Variant=NO_ARG,
|
||||
arg5 :Variant=NO_ARG,
|
||||
arg6 :Variant=NO_ARG,
|
||||
arg7 :Variant=NO_ARG,
|
||||
arg8 :Variant=NO_ARG,
|
||||
arg9 :Variant=NO_ARG) -> void:
|
||||
__values = GdArrayTools.filter_value([arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9], NO_ARG)
|
||||
|
||||
|
||||
func values() -> Array:
|
||||
return __values
|
||||
|
||||
|
||||
func _to_string() -> String:
|
||||
return "tuple(%s)" % str(__values)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://mjqw2uww51fk
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
## This is the base interface for value extraction
|
||||
class_name GdUnitValueExtractor
|
||||
extends RefCounted
|
||||
|
||||
|
||||
## Extracts a value by given implementation
|
||||
func extract_value(value :Variant) -> Variant:
|
||||
push_error("Uninplemented func 'extract_value'")
|
||||
return value
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://2dylh01qtb66
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
## An Assertion Tool to verify Vector values
|
||||
@abstract class_name GdUnitVectorAssert
|
||||
extends GdUnitAssert
|
||||
|
||||
|
||||
## Verifies that the current value is null.
|
||||
@abstract func is_null() -> GdUnitVectorAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not null.
|
||||
@abstract func is_not_null() -> GdUnitVectorAssert
|
||||
|
||||
|
||||
## Verifies that the current value is equal to the given one.
|
||||
@abstract func is_equal(expected: Variant) -> GdUnitVectorAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not equal to expected one.
|
||||
@abstract func is_not_equal(expected: Variant) -> GdUnitVectorAssert
|
||||
|
||||
|
||||
## Verifies that the current and expected value are approximately equal.
|
||||
@abstract func is_equal_approx(expected: Variant, approx: Variant) -> GdUnitVectorAssert
|
||||
|
||||
|
||||
## Overrides the default failure message by given custom message.
|
||||
@abstract func override_failure_message(message: String) -> GdUnitVectorAssert
|
||||
|
||||
|
||||
## Appends a custom message to the failure message.
|
||||
@abstract func append_failure_message(message: String) -> GdUnitVectorAssert
|
||||
|
||||
|
||||
## Verifies that the current value is less than the given one.
|
||||
@abstract func is_less(expected: Variant) -> GdUnitVectorAssert
|
||||
|
||||
|
||||
## Verifies that the current value is less than or equal the given one.
|
||||
@abstract func is_less_equal(expected: Variant) -> GdUnitVectorAssert
|
||||
|
||||
|
||||
## Verifies that the current value is greater than the given one.
|
||||
@abstract func is_greater(expected: Variant) -> GdUnitVectorAssert
|
||||
|
||||
|
||||
## Verifies that the current value is greater than or equal the given one.
|
||||
@abstract func is_greater_equal(expected: Variant) -> GdUnitVectorAssert
|
||||
|
||||
|
||||
## Verifies that the current value is between the given boundaries (inclusive).
|
||||
@abstract func is_between(from: Variant, to: Variant) -> GdUnitVectorAssert
|
||||
|
||||
|
||||
## Verifies that the current value is not between the given boundaries (inclusive).
|
||||
@abstract func is_not_between(from: Variant, to: Variant) -> GdUnitVectorAssert
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://bcx6bgypklb3e
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# a value provider unsing a callback to get `next` value from a certain function
|
||||
class_name CallBackValueProvider
|
||||
extends ValueProvider
|
||||
|
||||
var _cb :Callable
|
||||
var _args :Array
|
||||
|
||||
|
||||
func _init(instance :Object, func_name :String, args :Array = Array(), force_error := true) -> void:
|
||||
_cb = Callable(instance, func_name);
|
||||
_args = args
|
||||
if force_error and not _cb.is_valid():
|
||||
push_error("Can't find function '%s' checked instance %s" % [func_name, instance])
|
||||
|
||||
|
||||
func get_value() -> Variant:
|
||||
if not _cb.is_valid():
|
||||
return null
|
||||
if _args.is_empty():
|
||||
return await _cb.call()
|
||||
return await _cb.callv(_args)
|
||||
|
||||
|
||||
func dispose() -> void:
|
||||
_cb = Callable()
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://r43u2usutiss
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# default value provider, simple returns the initial value
|
||||
class_name DefaultValueProvider
|
||||
extends ValueProvider
|
||||
|
||||
var _value: Variant
|
||||
|
||||
|
||||
func _init(value: Variant) -> void:
|
||||
_value = value
|
||||
|
||||
|
||||
func get_value() -> Variant:
|
||||
return _value
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://coauynw7rnsij
|
||||
|
||||
@@ -0,0 +1,692 @@
|
||||
class_name GdAssertMessages
|
||||
extends Resource
|
||||
|
||||
const WARN_COLOR = "#EFF883"
|
||||
const ERROR_COLOR = "#CD5C5C"
|
||||
const VALUE_COLOR = "#1E90FF"
|
||||
const SUB_COLOR := Color(1, 0, 0, .15)
|
||||
const ADD_COLOR := Color(0, 1, 0, .15)
|
||||
|
||||
|
||||
# Dictionary of control characters and their readable representations
|
||||
const CONTROL_CHARS = {
|
||||
"\n": "<LF>", # Line Feed
|
||||
"\r": "<CR>", # Carriage Return
|
||||
"\t": "<TAB>", # Tab
|
||||
"\b": "<BS>", # Backspace
|
||||
"\f": "<FF>", # Form Feed
|
||||
"\v": "<VT>", # Vertical Tab
|
||||
"\a": "<BEL>", # Bell
|
||||
"": "<ESC>" # Escape
|
||||
}
|
||||
|
||||
|
||||
static func format_dict(value :Variant) -> String:
|
||||
if not value is Dictionary:
|
||||
return str(value)
|
||||
|
||||
var dict_value: Dictionary = value
|
||||
if dict_value.is_empty():
|
||||
return "{ }"
|
||||
var as_rows := var_to_str(value).split("\n")
|
||||
for index in range( 1, as_rows.size()-1):
|
||||
as_rows[index] = " " + as_rows[index]
|
||||
as_rows[-1] = " " + as_rows[-1]
|
||||
return "\n".join(as_rows)
|
||||
|
||||
|
||||
# improved version of InputEvent as text
|
||||
static func input_event_as_text(event :InputEvent) -> String:
|
||||
var text := ""
|
||||
if event is InputEventKey:
|
||||
var key_event := event as InputEventKey
|
||||
text += "InputEventKey : key='%s', pressed=%s, keycode=%d, physical_keycode=%s" % [
|
||||
event.as_text(), key_event.pressed, key_event.keycode, key_event.physical_keycode]
|
||||
else:
|
||||
text += event.as_text()
|
||||
if event is InputEventMouse:
|
||||
var mouse_event := event as InputEventMouse
|
||||
text += ", global_position %s" % mouse_event.global_position
|
||||
if event is InputEventWithModifiers:
|
||||
var mouse_event := event as InputEventWithModifiers
|
||||
text += ", shift=%s, alt=%s, control=%s, meta=%s, command=%s" % [
|
||||
mouse_event.shift_pressed,
|
||||
mouse_event.alt_pressed,
|
||||
mouse_event.ctrl_pressed,
|
||||
mouse_event.meta_pressed,
|
||||
mouse_event.command_or_control_autoremap]
|
||||
return text
|
||||
|
||||
|
||||
static func _colored_string_div(characters: String) -> String:
|
||||
return colored_array_div(characters.to_utf32_buffer().to_int32_array())
|
||||
|
||||
|
||||
static func colored_array_div(characters: PackedInt32Array) -> String:
|
||||
if characters.is_empty():
|
||||
return "<empty>"
|
||||
var result := PackedInt32Array()
|
||||
var index := 0
|
||||
var missing_chars := PackedInt32Array()
|
||||
var additional_chars := PackedInt32Array()
|
||||
|
||||
while index < characters.size():
|
||||
var character := characters[index]
|
||||
match character:
|
||||
GdDiffTool.DIV_ADD:
|
||||
index += 1
|
||||
@warning_ignore("return_value_discarded")
|
||||
additional_chars.append(characters[index])
|
||||
GdDiffTool.DIV_SUB:
|
||||
index += 1
|
||||
@warning_ignore("return_value_discarded")
|
||||
missing_chars.append(characters[index])
|
||||
_:
|
||||
if not missing_chars.is_empty():
|
||||
result.append_array(format_chars(missing_chars, SUB_COLOR))
|
||||
missing_chars = PackedInt32Array()
|
||||
if not additional_chars.is_empty():
|
||||
result.append_array(format_chars(additional_chars, ADD_COLOR))
|
||||
additional_chars = PackedInt32Array()
|
||||
@warning_ignore("return_value_discarded")
|
||||
result.append(character)
|
||||
index += 1
|
||||
|
||||
result.append_array(format_chars(missing_chars, SUB_COLOR))
|
||||
result.append_array(format_chars(additional_chars, ADD_COLOR))
|
||||
return result.to_byte_array().get_string_from_utf32()
|
||||
|
||||
|
||||
static func _typed_value(value :Variant) -> String:
|
||||
return GdDefaultValueDecoder.decode(value)
|
||||
|
||||
|
||||
static func _warning(error :String) -> String:
|
||||
return "[color=%s]%s[/color]" % [WARN_COLOR, error]
|
||||
|
||||
|
||||
static func _error(error :String) -> String:
|
||||
return "[color=%s]%s[/color]" % [ERROR_COLOR, error]
|
||||
|
||||
|
||||
static func _nerror(number :Variant) -> String:
|
||||
match typeof(number):
|
||||
TYPE_INT:
|
||||
return "[color=%s]%d[/color]" % [ERROR_COLOR, number]
|
||||
TYPE_FLOAT:
|
||||
return "[color=%s]%f[/color]" % [ERROR_COLOR, number]
|
||||
_:
|
||||
return "[color=%s]%s[/color]" % [ERROR_COLOR, str(number)]
|
||||
|
||||
|
||||
static func _colored_value(value :Variant) -> String:
|
||||
match typeof(value):
|
||||
TYPE_STRING, TYPE_STRING_NAME:
|
||||
return "'[color=%s]%s[/color]'" % [VALUE_COLOR, _colored_string_div(str(value))]
|
||||
TYPE_INT:
|
||||
return "'[color=%s]%d[/color]'" % [VALUE_COLOR, value]
|
||||
TYPE_FLOAT:
|
||||
return "'[color=%s]%s[/color]'" % [VALUE_COLOR, _typed_value(value)]
|
||||
TYPE_COLOR:
|
||||
return "'[color=%s]%s[/color]'" % [VALUE_COLOR, _typed_value(value)]
|
||||
TYPE_OBJECT:
|
||||
if value == null:
|
||||
return "'[color=%s]<null>[/color]'" % [VALUE_COLOR]
|
||||
if value is InputEvent:
|
||||
var ie: InputEvent = value
|
||||
return "[color=%s]<%s>[/color]" % [VALUE_COLOR, input_event_as_text(ie)]
|
||||
var obj_value: Object = value
|
||||
if obj_value.has_method("_to_string"):
|
||||
return "[color=%s]<%s>[/color]" % [VALUE_COLOR, str(value)]
|
||||
return "[color=%s]<%s>[/color]" % [VALUE_COLOR, obj_value.get_class()]
|
||||
TYPE_DICTIONARY:
|
||||
return "'[color=%s]%s[/color]'" % [VALUE_COLOR, format_dict(value)]
|
||||
_:
|
||||
if GdArrayTools.is_array_type(value):
|
||||
return "'[color=%s]%s[/color]'" % [VALUE_COLOR, _typed_value(value)]
|
||||
return "'[color=%s]%s[/color]'" % [VALUE_COLOR, value]
|
||||
|
||||
|
||||
|
||||
static func _index_report_as_table(index_reports :Array) -> String:
|
||||
var table := "[table=3]$cells[/table]"
|
||||
var header := "[cell][right][b]$text[/b][/right]\t[/cell]"
|
||||
var cell := "[cell][right]$text[/right]\t[/cell]"
|
||||
var cells := header.replace("$text", "Index") + header.replace("$text", "Current") + header.replace("$text", "Expected")
|
||||
for report :Variant in index_reports:
|
||||
var index :String = str(report["index"])
|
||||
var current :String = str(report["current"])
|
||||
var expected :String = str(report["expected"])
|
||||
cells += cell.replace("$text", index) + cell.replace("$text", current) + cell.replace("$text", expected)
|
||||
return table.replace("$cells", cells)
|
||||
|
||||
|
||||
static func orphan_detected_on_suite_setup(count :int) -> String:
|
||||
return "%s\n Detected <%d> orphan nodes during test suite setup stage! [b]Check before() and after()![/b]" % [
|
||||
_warning("WARNING:"), count]
|
||||
|
||||
|
||||
static func orphan_detected_on_test_setup(count :int) -> String:
|
||||
return "%s\n Detected <%d> orphan nodes during test setup! [b]Check before_test() and after_test()![/b]" % [
|
||||
_warning("WARNING:"), count]
|
||||
|
||||
|
||||
static func orphan_detected_on_test(count :int) -> String:
|
||||
return "%s\n Detected <%d> orphan nodes during test execution!" % [
|
||||
_warning("WARNING:"), count]
|
||||
|
||||
|
||||
static func fuzzer_interuped(iterations: int, error: String) -> String:
|
||||
return "%s %s %s\n %s" % [
|
||||
_error("Found an error after"),
|
||||
_colored_value(iterations + 1),
|
||||
_error("test iterations"),
|
||||
error]
|
||||
|
||||
|
||||
static func test_timeout(timeout :int) -> String:
|
||||
return "%s\n %s" % [_error("Timeout !"), _colored_value("Test timed out after %s" % LocalTime.elapsed(timeout))]
|
||||
|
||||
|
||||
# gdlint:disable = mixed-tabs-and-spaces
|
||||
static func test_suite_skipped(hint :String, skip_count :int) -> String:
|
||||
return """
|
||||
%s
|
||||
Skipped %s tests
|
||||
Reason: %s
|
||||
""".dedent().trim_prefix("\n")\
|
||||
% [_error("The Entire test-suite is skipped!"), _colored_value(skip_count), _colored_value(hint)]
|
||||
|
||||
|
||||
static func test_skipped(hint :String) -> String:
|
||||
return """
|
||||
%s
|
||||
Reason: %s
|
||||
""".dedent().trim_prefix("\n")\
|
||||
% [_error("This test is skipped!"), _colored_value(hint)]
|
||||
|
||||
|
||||
static func error_not_implemented() -> String:
|
||||
return _error("Test not implemented!")
|
||||
|
||||
|
||||
static func error_is_null(current :Variant) -> String:
|
||||
return "%s %s but was %s" % [_error("Expecting:"), _colored_value(null), _colored_value(current)]
|
||||
|
||||
|
||||
static func error_is_not_null() -> String:
|
||||
return "%s %s" % [_error("Expecting: not to be"), _colored_value(null)]
|
||||
|
||||
|
||||
static func error_equal(current :Variant, expected :Variant, index_reports :Array = []) -> String:
|
||||
var report := """
|
||||
%s
|
||||
%s
|
||||
but was
|
||||
%s""".dedent().trim_prefix("\n") % [_error("Expecting:"), _colored_value(expected), _colored_value(current)]
|
||||
if not index_reports.is_empty():
|
||||
report += "\n\n%s\n%s" % [_error("Differences found:"), _index_report_as_table(index_reports)]
|
||||
return report
|
||||
|
||||
|
||||
static func error_not_equal(current :Variant, expected :Variant) -> String:
|
||||
return "%s\n %s\n not equal to\n %s" % [_error("Expecting:"), _colored_value(expected), _colored_value(current)]
|
||||
|
||||
|
||||
static func error_not_equal_case_insensetiv(current :Variant, expected :Variant) -> String:
|
||||
return "%s\n %s\n not equal to (case insensitiv)\n %s" % [
|
||||
_error("Expecting:"), _colored_value(expected), _colored_value(current)]
|
||||
|
||||
|
||||
static func error_is_empty(current :Variant) -> String:
|
||||
return "%s\n must be empty but was\n %s" % [_error("Expecting:"), _colored_value(current)]
|
||||
|
||||
|
||||
static func error_is_not_empty() -> String:
|
||||
return "%s\n must not be empty" % [_error("Expecting:")]
|
||||
|
||||
|
||||
static func error_is_same(current :Variant, expected :Variant) -> String:
|
||||
return "%s\n %s\n to refer to the same object\n %s" % [_error("Expecting:"), _colored_value(expected), _colored_value(current)]
|
||||
|
||||
|
||||
@warning_ignore("unused_parameter")
|
||||
static func error_not_same(_current :Variant, expected :Variant) -> String:
|
||||
return "%s\n %s" % [_error("Expecting not same:"), _colored_value(expected)]
|
||||
|
||||
|
||||
static func error_not_same_error(current :Variant, expected :Variant) -> String:
|
||||
return "%s\n %s\n but was\n %s" % [_error("Expecting error message:"), _colored_value(expected), _colored_value(current)]
|
||||
|
||||
|
||||
static func error_is_instanceof(current: GdUnitResult, expected :GdUnitResult) -> String:
|
||||
return "%s\n %s\n But it was %s" % [_error("Expected instance of:"),\
|
||||
_colored_value(expected.or_else(null)), _colored_value(current.or_else(null))]
|
||||
|
||||
|
||||
# -- Boolean Assert specific messages -----------------------------------------------------
|
||||
static func error_is_true(current :Variant) -> String:
|
||||
return "%s %s but is %s" % [_error("Expecting:"), _colored_value(true), _colored_value(current)]
|
||||
|
||||
|
||||
static func error_is_false(current :Variant) -> String:
|
||||
return "%s %s but is %s" % [_error("Expecting:"), _colored_value(false), _colored_value(current)]
|
||||
|
||||
|
||||
# - Integer/Float Assert specific messages -----------------------------------------------------
|
||||
|
||||
static func error_is_even(current :Variant) -> String:
|
||||
return "%s\n %s must be even" % [_error("Expecting:"), _colored_value(current)]
|
||||
|
||||
|
||||
static func error_is_odd(current :Variant) -> String:
|
||||
return "%s\n %s must be odd" % [_error("Expecting:"), _colored_value(current)]
|
||||
|
||||
|
||||
static func error_is_negative(current :Variant) -> String:
|
||||
return "%s\n %s be negative" % [_error("Expecting:"), _colored_value(current)]
|
||||
|
||||
|
||||
static func error_is_not_negative(current :Variant) -> String:
|
||||
return "%s\n %s be not negative" % [_error("Expecting:"), _colored_value(current)]
|
||||
|
||||
|
||||
static func error_is_zero(current :Variant) -> String:
|
||||
return "%s\n equal to 0 but is %s" % [_error("Expecting:"), _colored_value(current)]
|
||||
|
||||
|
||||
static func error_is_not_zero() -> String:
|
||||
return "%s\n not equal to 0" % [_error("Expecting:")]
|
||||
|
||||
|
||||
static func error_is_wrong_type(current_type :Variant.Type, expected_type :Variant.Type) -> String:
|
||||
return "%s\n Expecting type %s but is %s" % [
|
||||
_error("Unexpected type comparison:"),
|
||||
_colored_value(GdObjects.type_as_string(current_type)),
|
||||
_colored_value(GdObjects.type_as_string(expected_type))]
|
||||
|
||||
|
||||
static func error_is_value(operation :int, current :Variant, expected :Variant, expected2 :Variant = null) -> String:
|
||||
match operation:
|
||||
Comparator.EQUAL:
|
||||
return "%s\n %s but was '%s'" % [_error("Expecting:"), _colored_value(expected), _nerror(current)]
|
||||
Comparator.LESS_THAN:
|
||||
return "%s\n %s but was '%s'" % [_error("Expecting to be less than:"), _colored_value(expected), _nerror(current)]
|
||||
Comparator.LESS_EQUAL:
|
||||
return "%s\n %s but was '%s'" % [_error("Expecting to be less than or equal:"), _colored_value(expected), _nerror(current)]
|
||||
Comparator.GREATER_THAN:
|
||||
return "%s\n %s but was '%s'" % [_error("Expecting to be greater than:"), _colored_value(expected), _nerror(current)]
|
||||
Comparator.GREATER_EQUAL:
|
||||
return "%s\n %s but was '%s'" % [_error("Expecting to be greater than or equal:"), _colored_value(expected), _nerror(current)]
|
||||
Comparator.BETWEEN_EQUAL:
|
||||
return "%s\n %s\n in range between\n %s <> %s" % [
|
||||
_error("Expecting:"), _colored_value(current), _colored_value(expected), _colored_value(expected2)]
|
||||
Comparator.NOT_BETWEEN_EQUAL:
|
||||
return "%s\n %s\n not in range between\n %s <> %s" % [
|
||||
_error("Expecting:"), _colored_value(current), _colored_value(expected), _colored_value(expected2)]
|
||||
return "TODO create expected message"
|
||||
|
||||
|
||||
static func error_is_in(current :Variant, expected :Array) -> String:
|
||||
return "%s\n %s\n is in\n %s" % [_error("Expecting:"), _colored_value(current), _colored_value(str(expected))]
|
||||
|
||||
|
||||
static func error_is_not_in(current :Variant, expected :Array) -> String:
|
||||
return "%s\n %s\n is not in\n %s" % [_error("Expecting:"), _colored_value(current), _colored_value(str(expected))]
|
||||
|
||||
|
||||
# - StringAssert ---------------------------------------------------------------------------------
|
||||
static func error_equal_ignoring_case(current :Variant, expected :Variant) -> String:
|
||||
return "%s\n %s\n but was\n %s (ignoring case)" % [_error("Expecting:"), _colored_value(expected), _colored_value(current)]
|
||||
|
||||
|
||||
static func error_contains(current :Variant, expected :Variant) -> String:
|
||||
return "%s\n %s\n do contains\n %s" % [_error("Expecting:"), _colored_value(current), _colored_value(expected)]
|
||||
|
||||
|
||||
static func error_not_contains(current :Variant, expected :Variant) -> String:
|
||||
return "%s\n %s\n not do contain\n %s" % [_error("Expecting:"), _colored_value(current), _colored_value(expected)]
|
||||
|
||||
|
||||
static func error_contains_ignoring_case(current :Variant, expected :Variant) -> String:
|
||||
return "%s\n %s\n contains\n %s\n (ignoring case)" % [_error("Expecting:"), _colored_value(current), _colored_value(expected)]
|
||||
|
||||
|
||||
static func error_not_contains_ignoring_case(current :Variant, expected :Variant) -> String:
|
||||
return "%s\n %s\n not do contains\n %s\n (ignoring case)" % [_error("Expecting:"), _colored_value(current), _colored_value(expected)]
|
||||
|
||||
|
||||
static func error_starts_with(current :Variant, expected :Variant) -> String:
|
||||
return "%s\n %s\n to start with\n %s" % [_error("Expecting:"), _colored_value(current), _colored_value(expected)]
|
||||
|
||||
|
||||
static func error_ends_with(current :Variant, expected :Variant) -> String:
|
||||
return "%s\n %s\n to end with\n %s" % [_error("Expecting:"), _colored_value(current), _colored_value(expected)]
|
||||
|
||||
|
||||
static func error_has_length(current :Variant, expected: int, compare_operator :int) -> String:
|
||||
@warning_ignore("unsafe_method_access")
|
||||
var current_length :Variant = current.length() if current != null else null
|
||||
match compare_operator:
|
||||
Comparator.EQUAL:
|
||||
return "%s\n %s but was '%s' in\n %s" % [
|
||||
_error("Expecting size:"), _colored_value(expected), _nerror(current_length), _colored_value(current)]
|
||||
Comparator.LESS_THAN:
|
||||
return "%s\n %s but was '%s' in\n %s" % [
|
||||
_error("Expecting size to be less than:"), _colored_value(expected), _nerror(current_length), _colored_value(current)]
|
||||
Comparator.LESS_EQUAL:
|
||||
return "%s\n %s but was '%s' in\n %s" % [
|
||||
_error("Expecting size to be less than or equal:"), _colored_value(expected),
|
||||
_nerror(current_length), _colored_value(current)]
|
||||
Comparator.GREATER_THAN:
|
||||
return "%s\n %s but was '%s' in\n %s" % [
|
||||
_error("Expecting size to be greater than:"), _colored_value(expected),
|
||||
_nerror(current_length), _colored_value(current)]
|
||||
Comparator.GREATER_EQUAL:
|
||||
return "%s\n %s but was '%s' in\n %s" % [
|
||||
_error("Expecting size to be greater than or equal:"), _colored_value(expected),
|
||||
_nerror(current_length), _colored_value(current)]
|
||||
return "TODO create expected message"
|
||||
|
||||
|
||||
# - ArrayAssert specific messgaes ---------------------------------------------------
|
||||
|
||||
static func error_arr_contains(current: Variant, expected: Variant, not_expect: Variant, not_found: Variant, by_reference: bool) -> String:
|
||||
var failure_message := "Expecting contains SAME elements:" if by_reference else "Expecting contains elements:"
|
||||
var error := "%s\n %s\n do contains (in any order)\n %s" % [
|
||||
_error(failure_message), _colored_value(current), _colored_value(expected)]
|
||||
if not is_empty(not_expect):
|
||||
error += "\nbut some elements where not expected:\n %s" % _colored_value(not_expect)
|
||||
if not is_empty(not_found):
|
||||
var prefix := "but" if is_empty(not_expect) else "and"
|
||||
error += "\n%s could not find elements:\n %s" % [prefix, _colored_value(not_found)]
|
||||
return error
|
||||
|
||||
|
||||
static func error_arr_contains_exactly(
|
||||
current: Variant,
|
||||
expected: Variant,
|
||||
not_expect: Variant,
|
||||
not_found: Variant, compare_mode: GdObjects.COMPARE_MODE) -> String:
|
||||
var failure_message := (
|
||||
"Expecting contains exactly elements:" if compare_mode == GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST
|
||||
else "Expecting contains SAME exactly elements:"
|
||||
)
|
||||
if is_empty(not_expect) and is_empty(not_found):
|
||||
var arr_current: Array = current
|
||||
var arr_expected: Array = expected
|
||||
var diff := _find_first_diff(arr_current, arr_expected)
|
||||
return "%s\n %s\n do contains (in same order)\n %s\n but has different order %s" % [
|
||||
_error(failure_message), _colored_value(current), _colored_value(expected), diff]
|
||||
|
||||
var error := "%s\n %s\n do contains (in same order)\n %s" % [
|
||||
_error(failure_message), _colored_value(current), _colored_value(expected)]
|
||||
if not is_empty(not_expect):
|
||||
error += "\nbut some elements where not expected:\n %s" % _colored_value(not_expect)
|
||||
if not is_empty(not_found):
|
||||
var prefix := "but" if is_empty(not_expect) else "and"
|
||||
error += "\n%s could not find elements:\n %s" % [prefix, _colored_value(not_found)]
|
||||
return error
|
||||
|
||||
|
||||
static func error_arr_contains_exactly_in_any_order(
|
||||
current: Variant,
|
||||
expected: Variant,
|
||||
not_expect: Variant,
|
||||
not_found: Variant,
|
||||
compare_mode: GdObjects.COMPARE_MODE) -> String:
|
||||
|
||||
var failure_message := (
|
||||
"Expecting contains exactly elements:" if compare_mode == GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST
|
||||
else "Expecting contains SAME exactly elements:"
|
||||
)
|
||||
var error := "%s\n %s\n do contains exactly (in any order)\n %s" % [
|
||||
_error(failure_message), _colored_value(current), _colored_value(expected)]
|
||||
if not is_empty(not_expect):
|
||||
error += "\nbut some elements where not expected:\n %s" % _colored_value(not_expect)
|
||||
if not is_empty(not_found):
|
||||
var prefix := "but" if is_empty(not_expect) else "and"
|
||||
error += "\n%s could not find elements:\n %s" % [prefix, _colored_value(not_found)]
|
||||
return error
|
||||
|
||||
|
||||
static func error_arr_not_contains(current: Variant, expected: Variant, found: Variant, compare_mode: GdObjects.COMPARE_MODE) -> String:
|
||||
var failure_message := "Expecting:" if compare_mode == GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST else "Expecting SAME:"
|
||||
var error := "%s\n %s\n do not contains\n %s" % [
|
||||
_error(failure_message), _colored_value(current), _colored_value(expected)]
|
||||
if not is_empty(found):
|
||||
error += "\n but found elements:\n %s" % _colored_value(found)
|
||||
return error
|
||||
|
||||
|
||||
# - DictionaryAssert specific messages ----------------------------------------------
|
||||
static func error_contains_keys(current :Array, expected :Array, keys_not_found :Array, compare_mode :GdObjects.COMPARE_MODE) -> String:
|
||||
var failure := (
|
||||
"Expecting contains keys:" if compare_mode == GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST
|
||||
else "Expecting contains SAME keys:"
|
||||
)
|
||||
return "%s\n %s\n to contains:\n %s\n but can't find key's:\n %s" % [
|
||||
_error(failure), _colored_value(current), _colored_value(expected), _colored_value(keys_not_found)]
|
||||
|
||||
|
||||
static func error_not_contains_keys(current :Array, expected :Array, keys_not_found :Array, compare_mode :GdObjects.COMPARE_MODE) -> String:
|
||||
var failure := (
|
||||
"Expecting NOT contains keys:" if compare_mode == GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST
|
||||
else "Expecting NOT contains SAME keys"
|
||||
)
|
||||
return "%s\n %s\n do not contains:\n %s\n but contains key's:\n %s" % [
|
||||
_error(failure), _colored_value(current), _colored_value(expected), _colored_value(keys_not_found)]
|
||||
|
||||
|
||||
static func error_contains_key_value(key :Variant, value :Variant, current_value :Variant, compare_mode :GdObjects.COMPARE_MODE) -> String:
|
||||
var failure := (
|
||||
"Expecting contains key and value:" if compare_mode == GdObjects.COMPARE_MODE.PARAMETER_DEEP_TEST
|
||||
else "Expecting contains SAME key and value:"
|
||||
)
|
||||
return "%s\n %s : %s\n but contains\n %s : %s" % [
|
||||
_error(failure), _colored_value(key), _colored_value(value), _colored_value(key), _colored_value(current_value)]
|
||||
|
||||
|
||||
# - ResultAssert specific errors ----------------------------------------------------
|
||||
static func error_result_is_empty(current :GdUnitResult) -> String:
|
||||
return _result_error_message(current, GdUnitResult.EMPTY)
|
||||
|
||||
|
||||
static func error_result_is_success(current :GdUnitResult) -> String:
|
||||
return _result_error_message(current, GdUnitResult.SUCCESS)
|
||||
|
||||
|
||||
static func error_result_is_warning(current :GdUnitResult) -> String:
|
||||
return _result_error_message(current, GdUnitResult.WARN)
|
||||
|
||||
|
||||
static func error_result_is_error(current :GdUnitResult) -> String:
|
||||
return _result_error_message(current, GdUnitResult.ERROR)
|
||||
|
||||
|
||||
static func error_result_has_message(current :String, expected :String) -> String:
|
||||
return "%s\n %s\n but was\n %s." % [_error("Expecting:"), _colored_value(expected), _colored_value(current)]
|
||||
|
||||
|
||||
static func error_result_has_message_on_success(expected :String) -> String:
|
||||
return "%s\n %s\n but the GdUnitResult is a success." % [_error("Expecting:"), _colored_value(expected)]
|
||||
|
||||
|
||||
static func error_result_is_value(current :Variant, expected :Variant) -> String:
|
||||
return "%s\n %s\n but was\n %s." % [_error("Expecting to contain same value:"), _colored_value(expected), _colored_value(current)]
|
||||
|
||||
|
||||
static func _result_error_message(current :GdUnitResult, expected_type :int) -> String:
|
||||
if current == null:
|
||||
return _error("Expecting the result must be a %s but was <null>." % result_type(expected_type))
|
||||
if current.is_success():
|
||||
return _error("Expecting the result must be a %s but was SUCCESS." % result_type(expected_type))
|
||||
var error := "Expecting the result must be a %s but was %s:" % [result_type(expected_type), result_type(current._state)]
|
||||
return "%s\n %s" % [_error(error), _colored_value(result_message(current))]
|
||||
|
||||
|
||||
static func error_interrupted(func_name :String, expected :Variant, elapsed :String) -> String:
|
||||
func_name = humanized(func_name)
|
||||
if expected == null:
|
||||
return "%s %s but timed out after %s" % [_error("Expected:"), func_name, elapsed]
|
||||
return "%s %s %s but timed out after %s" % [_error("Expected:"), func_name, _colored_value(expected), elapsed]
|
||||
|
||||
|
||||
static func error_wait_signal(signal_name :String, args :Array, elapsed :String) -> String:
|
||||
if args.is_empty():
|
||||
return "%s %s but timed out after %s" % [
|
||||
_error("Expecting emit signal:"), _colored_value(signal_name + "()"), elapsed]
|
||||
return "%s %s but timed out after %s" % [
|
||||
_error("Expecting emit signal:"), _colored_value(signal_name + "(" + str(args) + ")"), elapsed]
|
||||
|
||||
|
||||
static func error_signal_emitted(signal_name :String, args :Array, elapsed :String) -> String:
|
||||
if args.is_empty():
|
||||
return "%s %s but is emitted after %s" % [
|
||||
_error("Expecting do not emit signal:"), _colored_value(signal_name + "()"), elapsed]
|
||||
return "%s %s but is emitted after %s" % [
|
||||
_error("Expecting do not emit signal:"), _colored_value(signal_name + "(" + str(args) + ")"), elapsed]
|
||||
|
||||
|
||||
static func error_await_signal_on_invalid_instance(source :Variant, signal_name :String, args :Array) -> String:
|
||||
return "%s\n await_signal_on(%s, %s, %s)" % [
|
||||
_error("Invalid source! Can't await on signal:"), _colored_value(source), signal_name, args]
|
||||
|
||||
|
||||
static func result_type(type :int) -> String:
|
||||
match type:
|
||||
GdUnitResult.SUCCESS: return "SUCCESS"
|
||||
GdUnitResult.WARN: return "WARNING"
|
||||
GdUnitResult.ERROR: return "ERROR"
|
||||
GdUnitResult.EMPTY: return "EMPTY"
|
||||
return "UNKNOWN"
|
||||
|
||||
|
||||
static func result_message(result :GdUnitResult) -> String:
|
||||
match result._state:
|
||||
GdUnitResult.SUCCESS: return ""
|
||||
GdUnitResult.WARN: return result.warn_message()
|
||||
GdUnitResult.ERROR: return result.error_message()
|
||||
GdUnitResult.EMPTY: return ""
|
||||
return "UNKNOWN"
|
||||
# -----------------------------------------------------------------------------------
|
||||
|
||||
# - Spy|Mock specific errors ----------------------------------------------------
|
||||
static func error_no_more_interactions(summary :Dictionary) -> String:
|
||||
var interactions := PackedStringArray()
|
||||
for args :Array in summary.keys():
|
||||
var times :int = summary[args]
|
||||
@warning_ignore("return_value_discarded")
|
||||
interactions.append(_format_arguments(args, times))
|
||||
return "%s\n%s\n%s" % [_error("Expecting no more interactions!"), _error("But found interactions on:"), "\n".join(interactions)]
|
||||
|
||||
|
||||
static func error_validate_interactions(current_interactions: Dictionary, expected_interactions: Dictionary) -> String:
|
||||
var collected_interactions := PackedStringArray()
|
||||
for args: Array in current_interactions.keys():
|
||||
var times: int = current_interactions[args]
|
||||
@warning_ignore("return_value_discarded")
|
||||
collected_interactions.append(_format_arguments(args, times))
|
||||
|
||||
var arguments: Array = expected_interactions.keys()[0]
|
||||
var interactions: int = expected_interactions.values()[0]
|
||||
var expected_interaction := _format_arguments(arguments, interactions)
|
||||
return "%s\n%s\n%s\n%s" % [
|
||||
_error("Expecting interaction on:"), expected_interaction, _error("But found interactions on:"), "\n".join(collected_interactions)]
|
||||
|
||||
|
||||
static func _format_arguments(args :Array, times :int) -> String:
|
||||
var fname :String = args[0]
|
||||
var fargs := args.slice(1) as Array
|
||||
var typed_args := _to_typed_args(fargs)
|
||||
var fsignature := _colored_value("%s(%s)" % [fname, ", ".join(typed_args)])
|
||||
return " %s %d time's" % [fsignature, times]
|
||||
|
||||
|
||||
static func _to_typed_args(args :Array) -> PackedStringArray:
|
||||
var typed := PackedStringArray()
|
||||
for arg :Variant in args:
|
||||
@warning_ignore("return_value_discarded")
|
||||
typed.append(_format_arg(arg) + " :" + GdObjects.type_as_string(typeof(arg)))
|
||||
return typed
|
||||
|
||||
|
||||
static func _format_arg(arg :Variant) -> String:
|
||||
if arg is InputEvent:
|
||||
var ie: InputEvent = arg
|
||||
return input_event_as_text(ie)
|
||||
return str(arg)
|
||||
|
||||
|
||||
static func _find_first_diff(left :Array, right :Array) -> String:
|
||||
for index in left.size():
|
||||
var l :Variant = left[index]
|
||||
var r :Variant = "<no entry>" if index >= right.size() else right[index]
|
||||
if not GdObjects.equals(l, r):
|
||||
return "at position %s\n '%s' vs '%s'" % [_colored_value(index), _typed_value(l), _typed_value(r)]
|
||||
return ""
|
||||
|
||||
|
||||
static func error_has_size(current :Variant, expected: int) -> String:
|
||||
@warning_ignore("unsafe_method_access")
|
||||
var current_size :Variant = null if current == null else current.size()
|
||||
return "%s\n %s\n but was\n %s" % [_error("Expecting size:"), _colored_value(expected), _colored_value(current_size)]
|
||||
|
||||
|
||||
static func error_contains_exactly(current: Array, expected: Array) -> String:
|
||||
return "%s\n %s\n but was\n %s" % [_error("Expecting exactly equal:"), _colored_value(expected), _colored_value(current)]
|
||||
|
||||
|
||||
static func format_chars(characters: PackedInt32Array, type: Color) -> PackedInt32Array:
|
||||
if characters.size() == 0:# or characters[0] == 10:
|
||||
return characters
|
||||
|
||||
# Replace each control character with its readable form
|
||||
var formatted_text := characters.to_byte_array().get_string_from_utf32()
|
||||
for control_char: String in CONTROL_CHARS:
|
||||
var replace_text: String = CONTROL_CHARS[control_char]
|
||||
formatted_text = formatted_text.replace(control_char, replace_text)
|
||||
|
||||
# Handle special ASCII control characters (0x00-0x1F, 0x7F)
|
||||
var ascii_text := ""
|
||||
for i in formatted_text.length():
|
||||
var character := formatted_text[i]
|
||||
var code := character.unicode_at(0)
|
||||
if code < 0x20 and not CONTROL_CHARS.has(character): # Control characters not handled above
|
||||
ascii_text += "<0x%02X>" % code
|
||||
elif code == 0x7F: # DEL character
|
||||
ascii_text += "<DEL>"
|
||||
else:
|
||||
ascii_text += character
|
||||
|
||||
var message := "[bgcolor=#%s][color=white]%s[/color][/bgcolor]" % [
|
||||
type.to_html(),
|
||||
ascii_text
|
||||
]
|
||||
|
||||
var result := PackedInt32Array()
|
||||
result.append_array(message.to_utf32_buffer().to_int32_array())
|
||||
return result
|
||||
|
||||
|
||||
static func format_invalid(value :String) -> String:
|
||||
return "[bgcolor=#%s][color=with]%s[/color][/bgcolor]" % [SUB_COLOR.to_html(), value]
|
||||
|
||||
|
||||
static func humanized(value :String) -> String:
|
||||
return value.replace("_", " ")
|
||||
|
||||
|
||||
static func build_failure_message(failure :String, additional_failure_message: String, custom_failure_message: String) -> String:
|
||||
var message := failure if custom_failure_message.is_empty() else custom_failure_message
|
||||
if additional_failure_message.is_empty():
|
||||
return message
|
||||
return """
|
||||
%s
|
||||
[color=LIME_GREEN][b]Additional info:[/b][/color]
|
||||
%s""".dedent().trim_prefix("\n") % [message, additional_failure_message]
|
||||
|
||||
|
||||
static func is_empty(value: Variant) -> bool:
|
||||
var arry_value: Array = value
|
||||
return arry_value != null and arry_value.is_empty()
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://vl7cfc01g5wl
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
class_name GdAssertReports
|
||||
extends RefCounted
|
||||
|
||||
const LAST_ERROR = "last_assert_error_message"
|
||||
const LAST_ERROR_LINE = "last_assert_error_line"
|
||||
|
||||
|
||||
static func report_success() -> void:
|
||||
GdUnitSignals.instance().gdunit_set_test_failed.emit(false)
|
||||
GdAssertReports.set_last_error_line_number(-1)
|
||||
Engine.remove_meta(LAST_ERROR)
|
||||
|
||||
|
||||
static func report_warning(message :String, line_number :int) -> void:
|
||||
GdUnitSignals.instance().gdunit_set_test_failed.emit(false)
|
||||
send_report(GdUnitReport.new().create(GdUnitReport.WARN, line_number, message))
|
||||
|
||||
|
||||
static func report_error(message:String, line_number :int) -> void:
|
||||
GdUnitSignals.instance().gdunit_set_test_failed.emit(true)
|
||||
GdAssertReports.set_last_error_line_number(line_number)
|
||||
Engine.set_meta(LAST_ERROR, message)
|
||||
# if we expect to fail we handle as success test
|
||||
if _do_expect_assert_failing():
|
||||
return
|
||||
send_report(GdUnitReport.new().create(GdUnitReport.FAILURE, line_number, message))
|
||||
|
||||
|
||||
static func reset_last_error_line_number() -> void:
|
||||
Engine.remove_meta(LAST_ERROR_LINE)
|
||||
|
||||
|
||||
static func set_last_error_line_number(line_number :int) -> void:
|
||||
Engine.set_meta(LAST_ERROR_LINE, line_number)
|
||||
|
||||
|
||||
static func get_last_error_line_number() -> int:
|
||||
if Engine.has_meta(LAST_ERROR_LINE):
|
||||
return Engine.get_meta(LAST_ERROR_LINE)
|
||||
return -1
|
||||
|
||||
|
||||
static func _do_expect_assert_failing() -> bool:
|
||||
if Engine.has_meta(GdUnitConstants.EXPECT_ASSERT_REPORT_FAILURES):
|
||||
return Engine.get_meta(GdUnitConstants.EXPECT_ASSERT_REPORT_FAILURES)
|
||||
return false
|
||||
|
||||
|
||||
static func current_failure() -> String:
|
||||
return Engine.get_meta(LAST_ERROR)
|
||||
|
||||
|
||||
static func send_report(report :GdUnitReport) -> void:
|
||||
GdUnitThreadManager.get_current_context().get_execution_context().add_report(report)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://brxvavm3ml0om
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://bx7cehfdh2x4w
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
class_name GdUnitAssertImpl
|
||||
extends GdUnitAssert
|
||||
|
||||
|
||||
var _current :Variant
|
||||
var _current_failure_message :String = ""
|
||||
var _custom_failure_message :String = ""
|
||||
var _additional_failure_message: String = ""
|
||||
|
||||
|
||||
func _init(current :Variant) -> void:
|
||||
_current = current
|
||||
# save the actual assert instance on the current thread context
|
||||
GdUnitThreadManager.get_current_context().set_assert(self)
|
||||
GdAssertReports.reset_last_error_line_number()
|
||||
|
||||
|
||||
|
||||
func failure_message() -> String:
|
||||
return _current_failure_message
|
||||
|
||||
|
||||
func current_value() -> Variant:
|
||||
return _current
|
||||
|
||||
|
||||
func report_success() -> GdUnitAssert:
|
||||
GdAssertReports.report_success()
|
||||
return self
|
||||
|
||||
|
||||
func report_error(failure :String, failure_line_number: int = -1) -> GdUnitAssert:
|
||||
var line_number := failure_line_number if failure_line_number != -1 else GdUnitAssertions.get_line_number()
|
||||
GdAssertReports.set_last_error_line_number(line_number)
|
||||
_current_failure_message = GdAssertMessages.build_failure_message(failure, _additional_failure_message, _custom_failure_message)
|
||||
GdAssertReports.report_error(_current_failure_message, line_number)
|
||||
Engine.set_meta("GD_TEST_FAILURE", true)
|
||||
return self
|
||||
|
||||
|
||||
func do_fail() -> GdUnitAssert:
|
||||
return report_error(GdAssertMessages.error_not_implemented())
|
||||
|
||||
|
||||
func override_failure_message(message: String) -> GdUnitAssert:
|
||||
_custom_failure_message = message
|
||||
return self
|
||||
|
||||
|
||||
func append_failure_message(message: String) -> GdUnitAssert:
|
||||
_additional_failure_message = message
|
||||
return self
|
||||
|
||||
|
||||
func is_null() -> GdUnitAssert:
|
||||
var current :Variant = current_value()
|
||||
if current != null:
|
||||
return report_error(GdAssertMessages.error_is_null(current))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_not_null() -> GdUnitAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null:
|
||||
return report_error(GdAssertMessages.error_is_not_null())
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_equal(expected: Variant) -> GdUnitAssert:
|
||||
var current: Variant = current_value()
|
||||
if not GdObjects.equals(current, expected):
|
||||
return report_error(GdAssertMessages.error_equal(current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_not_equal(expected: Variant) -> GdUnitAssert:
|
||||
var current: Variant = current_value()
|
||||
if GdObjects.equals(current, expected):
|
||||
return report_error(GdAssertMessages.error_not_equal(current, expected))
|
||||
return report_success()
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://cq38mcld2thyl
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# Preloads all GdUnit assertions
|
||||
class_name GdUnitAssertions
|
||||
extends RefCounted
|
||||
|
||||
|
||||
@warning_ignore("return_value_discarded")
|
||||
func _init() -> void:
|
||||
# preload all gdunit assertions to speedup testsuite loading time
|
||||
# gdlint:disable=private-method-call
|
||||
@warning_ignore_start("return_value_discarded")
|
||||
GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitAssertImpl.gd")
|
||||
GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitBoolAssertImpl.gd")
|
||||
GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitStringAssertImpl.gd")
|
||||
GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitIntAssertImpl.gd")
|
||||
GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitFloatAssertImpl.gd")
|
||||
GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitVectorAssertImpl.gd")
|
||||
GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitArrayAssertImpl.gd")
|
||||
GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitDictionaryAssertImpl.gd")
|
||||
GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitFileAssertImpl.gd")
|
||||
GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitObjectAssertImpl.gd")
|
||||
GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitResultAssertImpl.gd")
|
||||
GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitFuncAssertImpl.gd")
|
||||
GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitSignalAssertImpl.gd")
|
||||
GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitFailureAssertImpl.gd")
|
||||
GdUnitAssertions.__lazy_load("res://addons/gdUnit4/src/asserts/GdUnitGodotErrorAssertImpl.gd")
|
||||
@warning_ignore_restore("return_value_discarded")
|
||||
|
||||
|
||||
### We now load all used asserts and tool scripts into the cache according to the principle of "lazy loading"
|
||||
### in order to noticeably reduce the loading time of the test suite.
|
||||
# We go this hard way to increase the loading performance to avoid reparsing all the used scripts
|
||||
# for more detailed info -> https://github.com/godotengine/godot/issues/67400
|
||||
# gdlint:disable=function-name
|
||||
static func __lazy_load(script_path :String) -> GDScript:
|
||||
return ResourceLoader.load(script_path, "GDScript", ResourceLoader.CACHE_MODE_REUSE)
|
||||
|
||||
|
||||
static func validate_value_type(value :Variant, type :Variant.Type) -> bool:
|
||||
return value == null or typeof(value) == type
|
||||
|
||||
|
||||
# Scans the current stack trace for the root cause to extract the line number
|
||||
static func get_line_number() -> int:
|
||||
var stack_trace := get_stack()
|
||||
if stack_trace == null or stack_trace.is_empty():
|
||||
return -1
|
||||
for index in stack_trace.size():
|
||||
var stack_info :Dictionary = stack_trace[index]
|
||||
var function :String = stack_info.get("function")
|
||||
# we catch helper asserts to skip over to return the correct line number
|
||||
if function.begins_with("assert_"):
|
||||
continue
|
||||
if function.begins_with("test_"):
|
||||
return stack_info.get("line")
|
||||
var source :String = stack_info.get("source")
|
||||
if source.is_empty() \
|
||||
or source.begins_with("user://") \
|
||||
or source.ends_with("GdUnitAssert.gd") \
|
||||
or source.ends_with("GdUnitAssertions.gd") \
|
||||
or source.ends_with("AssertImpl.gd") \
|
||||
or source.ends_with("GdUnitTestSuite.gd") \
|
||||
or source.ends_with("GdUnitSceneRunnerImpl.gd") \
|
||||
or source.ends_with("GdUnitObjectInteractions.gd") \
|
||||
or source.ends_with("GdUnitObjectInteractionsVerifier.gd") \
|
||||
or source.ends_with("GdUnitAwaiter.gd"):
|
||||
continue
|
||||
return stack_info.get("line")
|
||||
return -1
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://61d7pdgldg0r
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
extends GdUnitBoolAssert
|
||||
|
||||
var _base: GdUnitAssertImpl
|
||||
|
||||
|
||||
func _init(current :Variant) -> void:
|
||||
_base = GdUnitAssertImpl.new(current)
|
||||
# save the actual assert instance on the current thread context
|
||||
GdUnitThreadManager.get_current_context().set_assert(self)
|
||||
if not GdUnitAssertions.validate_value_type(current, TYPE_BOOL):
|
||||
@warning_ignore("return_value_discarded")
|
||||
report_error("GdUnitBoolAssert inital error, unexpected type <%s>" % GdObjects.typeof_as_string(current))
|
||||
|
||||
|
||||
func _notification(event :int) -> void:
|
||||
if event == NOTIFICATION_PREDELETE:
|
||||
if _base != null:
|
||||
_base.notification(event)
|
||||
_base = null
|
||||
|
||||
|
||||
func current_value() -> Variant:
|
||||
return _base.current_value()
|
||||
|
||||
|
||||
func report_success() -> GdUnitBoolAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.report_success()
|
||||
return self
|
||||
|
||||
|
||||
func report_error(error :String) -> GdUnitBoolAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.report_error(error)
|
||||
return self
|
||||
|
||||
|
||||
func failure_message() -> String:
|
||||
return _base.failure_message()
|
||||
|
||||
|
||||
func override_failure_message(message: String) -> GdUnitBoolAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.override_failure_message(message)
|
||||
return self
|
||||
|
||||
|
||||
func append_failure_message(message: String) -> GdUnitBoolAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.append_failure_message(message)
|
||||
return self
|
||||
|
||||
|
||||
func is_null() -> GdUnitBoolAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_null()
|
||||
return self
|
||||
|
||||
|
||||
func is_not_null() -> GdUnitBoolAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_not_null()
|
||||
return self
|
||||
|
||||
|
||||
func is_equal(expected: Variant) -> GdUnitBoolAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_equal(expected)
|
||||
return self
|
||||
|
||||
|
||||
func is_not_equal(expected: Variant) -> GdUnitBoolAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_not_equal(expected)
|
||||
return self
|
||||
|
||||
|
||||
func is_true() -> GdUnitBoolAssert:
|
||||
if current_value() != true:
|
||||
return report_error(GdAssertMessages.error_is_true(current_value()))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_false() -> GdUnitBoolAssert:
|
||||
if current_value() == true || current_value() == null:
|
||||
return report_error(GdAssertMessages.error_is_false(current_value()))
|
||||
return report_success()
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://cxndss6mdq7de
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://dqrp7csbeyvon
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
extends GdUnitFailureAssert
|
||||
|
||||
const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd")
|
||||
|
||||
var _is_failed := false
|
||||
var _failure_message: String
|
||||
var _current_failure_message := ""
|
||||
var _custom_failure_message := ""
|
||||
var _additional_failure_message := ""
|
||||
|
||||
|
||||
func _set_do_expect_fail(enabled :bool = true) -> void:
|
||||
Engine.set_meta(GdUnitConstants.EXPECT_ASSERT_REPORT_FAILURES, enabled)
|
||||
|
||||
|
||||
func execute_and_await(assertion :Callable, do_await := true) -> GdUnitFailureAssert:
|
||||
# do not report any failure from the original assertion we want to test
|
||||
_set_do_expect_fail(true)
|
||||
var thread_context := GdUnitThreadManager.get_current_context()
|
||||
thread_context.set_assert(null)
|
||||
@warning_ignore("return_value_discarded")
|
||||
GdUnitSignals.instance().gdunit_set_test_failed.connect(_on_test_failed)
|
||||
# execute the given assertion as callable
|
||||
if do_await:
|
||||
await assertion.call()
|
||||
else:
|
||||
assertion.call()
|
||||
_set_do_expect_fail(false)
|
||||
# get the assert instance from current tread context
|
||||
var current_assert := thread_context.get_assert()
|
||||
if not is_instance_of(current_assert, GdUnitAssert):
|
||||
_is_failed = true
|
||||
_failure_message = "Invalid Callable! It must be a callable of 'GdUnitAssert'"
|
||||
return self
|
||||
@warning_ignore("unsafe_method_access")
|
||||
_failure_message = current_assert.failure_message()
|
||||
return self
|
||||
|
||||
|
||||
func execute(assertion :Callable) -> GdUnitFailureAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
execute_and_await(assertion, false)
|
||||
return self
|
||||
|
||||
|
||||
func _on_test_failed(value :bool) -> void:
|
||||
_is_failed = value
|
||||
|
||||
|
||||
func is_equal(_expected: Variant) -> GdUnitFailureAssert:
|
||||
return _report_error("Not implemented")
|
||||
|
||||
|
||||
func is_not_equal(_expected: Variant) -> GdUnitFailureAssert:
|
||||
return _report_error("Not implemented")
|
||||
|
||||
|
||||
func is_null() -> GdUnitFailureAssert:
|
||||
return _report_error("Not implemented")
|
||||
|
||||
|
||||
func is_not_null() -> GdUnitFailureAssert:
|
||||
return _report_error("Not implemented")
|
||||
|
||||
|
||||
func override_failure_message(message: String) -> GdUnitFailureAssert:
|
||||
_custom_failure_message = message
|
||||
return self
|
||||
|
||||
|
||||
func append_failure_message(message: String) -> GdUnitFailureAssert:
|
||||
_additional_failure_message = message
|
||||
return self
|
||||
|
||||
|
||||
func is_success() -> GdUnitFailureAssert:
|
||||
if _is_failed:
|
||||
return _report_error("Expect: assertion ends successfully.")
|
||||
return self
|
||||
|
||||
|
||||
func is_failed() -> GdUnitFailureAssert:
|
||||
if not _is_failed:
|
||||
return _report_error("Expect: assertion fails.")
|
||||
return self
|
||||
|
||||
|
||||
func has_line(expected :int) -> GdUnitFailureAssert:
|
||||
var current := GdAssertReports.get_last_error_line_number()
|
||||
if current != expected:
|
||||
return _report_error("Expect: to failed on line '%d'\n but was '%d'." % [expected, current])
|
||||
return self
|
||||
|
||||
|
||||
func has_message(expected :String) -> GdUnitFailureAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
is_failed()
|
||||
var expected_error := GdUnitTools.normalize_text(GdUnitTools.richtext_normalize(expected))
|
||||
var current_error := GdUnitTools.normalize_text(GdUnitTools.richtext_normalize(_failure_message))
|
||||
if current_error != expected_error:
|
||||
var diffs := GdDiffTool.string_diff(current_error, expected_error)
|
||||
var current := GdAssertMessages.colored_array_div(diffs[1])
|
||||
return _report_error(GdAssertMessages.error_not_same_error(current, expected_error))
|
||||
return self
|
||||
|
||||
|
||||
func contains_message(expected :String) -> GdUnitFailureAssert:
|
||||
var expected_error := GdUnitTools.normalize_text(expected)
|
||||
var current_error := GdUnitTools.normalize_text(GdUnitTools.richtext_normalize(_failure_message))
|
||||
if not current_error.contains(expected_error):
|
||||
var diffs := GdDiffTool.string_diff(current_error, expected_error)
|
||||
var current := GdAssertMessages.colored_array_div(diffs[1])
|
||||
return _report_error(GdAssertMessages.error_not_same_error(current, expected_error))
|
||||
return self
|
||||
|
||||
|
||||
func starts_with_message(expected :String) -> GdUnitFailureAssert:
|
||||
var expected_error := GdUnitTools.normalize_text(expected)
|
||||
var current_error := GdUnitTools.normalize_text(GdUnitTools.richtext_normalize(_failure_message))
|
||||
if current_error.find(expected_error) != 0:
|
||||
var diffs := GdDiffTool.string_diff(current_error, expected_error)
|
||||
var current := GdAssertMessages.colored_array_div(diffs[1])
|
||||
return _report_error(GdAssertMessages.error_not_same_error(current, expected_error))
|
||||
return self
|
||||
|
||||
|
||||
func _report_error(error_message :String, failure_line_number: int = -1) -> GdUnitAssert:
|
||||
var line_number := failure_line_number if failure_line_number != -1 else GdUnitAssertions.get_line_number()
|
||||
_current_failure_message = GdAssertMessages.build_failure_message(error_message, _additional_failure_message, _custom_failure_message)
|
||||
GdAssertReports.report_error(_current_failure_message, line_number)
|
||||
return self
|
||||
|
||||
|
||||
func _report_success() -> GdUnitFailureAssert:
|
||||
GdAssertReports.report_success()
|
||||
return self
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://cbrj7dsr235i0
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
extends GdUnitFileAssert
|
||||
|
||||
const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd")
|
||||
|
||||
var _base: GdUnitAssertImpl
|
||||
|
||||
|
||||
func _init(current :Variant) -> void:
|
||||
_base = GdUnitAssertImpl.new(current)
|
||||
# save the actual assert instance on the current thread context
|
||||
GdUnitThreadManager.get_current_context().set_assert(self)
|
||||
if not GdUnitAssertions.validate_value_type(current, TYPE_STRING):
|
||||
@warning_ignore("return_value_discarded")
|
||||
report_error("GdUnitFileAssert inital error, unexpected type <%s>" % GdObjects.typeof_as_string(current))
|
||||
|
||||
|
||||
func _notification(event :int) -> void:
|
||||
if event == NOTIFICATION_PREDELETE:
|
||||
if _base != null:
|
||||
_base.notification(event)
|
||||
_base = null
|
||||
|
||||
|
||||
func current_value() -> String:
|
||||
return _base.current_value()
|
||||
|
||||
|
||||
func report_success() -> GdUnitFileAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.report_success()
|
||||
return self
|
||||
|
||||
|
||||
func report_error(error :String) -> GdUnitFileAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.report_error(error)
|
||||
return self
|
||||
|
||||
|
||||
func failure_message() -> String:
|
||||
return _base.failure_message()
|
||||
|
||||
|
||||
func override_failure_message(message: String) -> GdUnitFileAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.override_failure_message(message)
|
||||
return self
|
||||
|
||||
|
||||
func append_failure_message(message: String) -> GdUnitFileAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.append_failure_message(message)
|
||||
return self
|
||||
|
||||
|
||||
func is_null() -> GdUnitFileAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_null()
|
||||
return self
|
||||
|
||||
|
||||
func is_not_null() -> GdUnitFileAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_not_null()
|
||||
return self
|
||||
|
||||
|
||||
func is_equal(expected: Variant) -> GdUnitFileAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_equal(expected)
|
||||
return self
|
||||
|
||||
|
||||
func is_not_equal(expected: Variant) -> GdUnitFileAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_not_equal(expected)
|
||||
return self
|
||||
|
||||
|
||||
func is_file() -> GdUnitFileAssert:
|
||||
var current := current_value()
|
||||
if FileAccess.open(current, FileAccess.READ) == null:
|
||||
return report_error("Is not a file '%s', error code %s" % [current, FileAccess.get_open_error()])
|
||||
return report_success()
|
||||
|
||||
|
||||
func exists() -> GdUnitFileAssert:
|
||||
var current := current_value()
|
||||
if not FileAccess.file_exists(current):
|
||||
return report_error("The file '%s' not exists" %current)
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_script() -> GdUnitFileAssert:
|
||||
var current := current_value()
|
||||
if FileAccess.open(current, FileAccess.READ) == null:
|
||||
return report_error("Can't acces the file '%s'! Error code %s" % [current, FileAccess.get_open_error()])
|
||||
|
||||
var script := load(current)
|
||||
if not script is GDScript:
|
||||
return report_error("The file '%s' is not a GdScript" % current)
|
||||
return report_success()
|
||||
|
||||
|
||||
func contains_exactly(expected_rows: Array) -> GdUnitFileAssert:
|
||||
var current := current_value()
|
||||
if FileAccess.open(current, FileAccess.READ) == null:
|
||||
return report_error("Can't acces the file '%s'! Error code %s" % [current, FileAccess.get_open_error()])
|
||||
|
||||
var script: GDScript = load(current)
|
||||
if script is GDScript:
|
||||
var source_code := GdScriptParser.to_unix_format(script.source_code)
|
||||
var rows := Array(source_code.split("\n"))
|
||||
@warning_ignore("return_value_discarded")
|
||||
GdUnitArrayAssertImpl.new(rows).contains_exactly(expected_rows)
|
||||
return self
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://2s6h0titid8y
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
extends GdUnitFloatAssert
|
||||
|
||||
var _base: GdUnitAssertImpl
|
||||
|
||||
|
||||
func _init(current :Variant) -> void:
|
||||
_base = GdUnitAssertImpl.new(current)
|
||||
# save the actual assert instance on the current thread context
|
||||
GdUnitThreadManager.get_current_context().set_assert(self)
|
||||
if not GdUnitAssertions.validate_value_type(current, TYPE_FLOAT):
|
||||
@warning_ignore("return_value_discarded")
|
||||
report_error("GdUnitFloatAssert inital error, unexpected type <%s>" % GdObjects.typeof_as_string(current))
|
||||
|
||||
|
||||
func _notification(event :int) -> void:
|
||||
if event == NOTIFICATION_PREDELETE:
|
||||
if _base != null:
|
||||
_base.notification(event)
|
||||
_base = null
|
||||
|
||||
|
||||
func current_value() -> Variant:
|
||||
return _base.current_value()
|
||||
|
||||
|
||||
func report_success() -> GdUnitFloatAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.report_success()
|
||||
return self
|
||||
|
||||
|
||||
func report_error(error :String) -> GdUnitFloatAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.report_error(error)
|
||||
return self
|
||||
|
||||
|
||||
func failure_message() -> String:
|
||||
return _base.failure_message()
|
||||
|
||||
|
||||
func override_failure_message(message: String) -> GdUnitFloatAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.override_failure_message(message)
|
||||
return self
|
||||
|
||||
|
||||
func append_failure_message(message: String) -> GdUnitFloatAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.append_failure_message(message)
|
||||
return self
|
||||
|
||||
|
||||
func is_null() -> GdUnitFloatAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_null()
|
||||
return self
|
||||
|
||||
|
||||
func is_not_null() -> GdUnitFloatAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_not_null()
|
||||
return self
|
||||
|
||||
|
||||
func is_equal(expected: Variant) -> GdUnitFloatAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_equal(expected)
|
||||
return self
|
||||
|
||||
|
||||
func is_not_equal(expected: Variant) -> GdUnitFloatAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_not_equal(expected)
|
||||
return self
|
||||
|
||||
|
||||
@warning_ignore("shadowed_global_identifier")
|
||||
func is_equal_approx(expected :float, approx :float) -> GdUnitFloatAssert:
|
||||
return is_between(expected-approx, expected+approx)
|
||||
|
||||
|
||||
func is_less(expected :float) -> GdUnitFloatAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null or current >= expected:
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.LESS_THAN, current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_less_equal(expected :float) -> GdUnitFloatAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null or current > expected:
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.LESS_EQUAL, current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_greater(expected :float) -> GdUnitFloatAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null or current <= expected:
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.GREATER_THAN, current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_greater_equal(expected :float) -> GdUnitFloatAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null or current < expected:
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.GREATER_EQUAL, current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_negative() -> GdUnitFloatAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null or current >= 0.0:
|
||||
return report_error(GdAssertMessages.error_is_negative(current))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_not_negative() -> GdUnitFloatAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null or current < 0.0:
|
||||
return report_error(GdAssertMessages.error_is_not_negative(current))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_zero() -> GdUnitFloatAssert:
|
||||
var current :Variant = current_value()
|
||||
@warning_ignore("unsafe_cast")
|
||||
if current == null or not is_equal_approx(0.00000000, current as float):
|
||||
return report_error(GdAssertMessages.error_is_zero(current))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_not_zero() -> GdUnitFloatAssert:
|
||||
var current :Variant = current_value()
|
||||
@warning_ignore("unsafe_cast")
|
||||
if current == null or is_equal_approx(0.00000000, current as float):
|
||||
return report_error(GdAssertMessages.error_is_not_zero())
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_in(expected :Array) -> GdUnitFloatAssert:
|
||||
var current :Variant = current_value()
|
||||
if not expected.has(current):
|
||||
return report_error(GdAssertMessages.error_is_in(current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_not_in(expected :Array) -> GdUnitFloatAssert:
|
||||
var current :Variant = current_value()
|
||||
if expected.has(current):
|
||||
return report_error(GdAssertMessages.error_is_not_in(current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_between(from :float, to :float) -> GdUnitFloatAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null or current < from or current > to:
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.BETWEEN_EQUAL, current, from, to))
|
||||
return report_success()
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://dvce6xeybbh1i
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://c2jdw0vv5nldq
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
extends GdUnitGodotErrorAssert
|
||||
|
||||
var _current_failure_message := ""
|
||||
var _custom_failure_message := ""
|
||||
var _additional_failure_message := ""
|
||||
var _callable: Callable
|
||||
|
||||
|
||||
func _init(callable: Callable) -> void:
|
||||
# save the actual assert instance on the current thread context
|
||||
GdUnitThreadManager.get_current_context().set_assert(self)
|
||||
GdAssertReports.reset_last_error_line_number()
|
||||
_callable = callable
|
||||
|
||||
|
||||
func _execute() -> Array[ErrorLogEntry]:
|
||||
# execute the given code and monitor for runtime errors
|
||||
if _callable == null or not _callable.is_valid():
|
||||
@warning_ignore("return_value_discarded")
|
||||
_report_error("Invalid Callable '%s'" % _callable)
|
||||
else:
|
||||
await _callable.call()
|
||||
return await _error_monitor().scan(true)
|
||||
|
||||
|
||||
func _error_monitor() -> GodotGdErrorMonitor:
|
||||
return GdUnitThreadManager.get_current_context().get_execution_context().error_monitor
|
||||
|
||||
|
||||
func failure_message() -> String:
|
||||
return _current_failure_message
|
||||
|
||||
|
||||
func _report_success() -> GdUnitAssert:
|
||||
GdAssertReports.report_success()
|
||||
return self
|
||||
|
||||
|
||||
func _report_error(error_message: String, failure_line_number: int = -1) -> GdUnitAssert:
|
||||
var line_number := failure_line_number if failure_line_number != -1 else GdUnitAssertions.get_line_number()
|
||||
_current_failure_message = GdAssertMessages.build_failure_message(error_message, _additional_failure_message, _custom_failure_message)
|
||||
GdAssertReports.report_error(_current_failure_message, line_number)
|
||||
return self
|
||||
|
||||
|
||||
func _has_log_entry(log_entries: Array[ErrorLogEntry], type: ErrorLogEntry.TYPE, error: Variant) -> bool:
|
||||
for entry in log_entries:
|
||||
if entry._type == type and GdObjects.equals(entry._message, error):
|
||||
# Erase the log entry we already handled it by this assertion, otherwise it will report at twice
|
||||
_error_monitor().erase_log_entry(entry)
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func _to_list(log_entries: Array[ErrorLogEntry]) -> String:
|
||||
if log_entries.is_empty():
|
||||
return "no errors"
|
||||
if log_entries.size() == 1:
|
||||
return log_entries[0]._message
|
||||
var value := ""
|
||||
for entry in log_entries:
|
||||
value += "'%s'\n" % entry._message
|
||||
return value
|
||||
|
||||
|
||||
func is_null() -> GdUnitGodotErrorAssert:
|
||||
return _report_error("Not implemented")
|
||||
|
||||
|
||||
func is_not_null() -> GdUnitGodotErrorAssert:
|
||||
return _report_error("Not implemented")
|
||||
|
||||
|
||||
func is_equal(_expected: Variant) -> GdUnitGodotErrorAssert:
|
||||
return _report_error("Not implemented")
|
||||
|
||||
|
||||
func is_not_equal(_expected: Variant) -> GdUnitGodotErrorAssert:
|
||||
return _report_error("Not implemented")
|
||||
|
||||
|
||||
func override_failure_message(message: String) -> GdUnitGodotErrorAssert:
|
||||
_custom_failure_message = message
|
||||
return self
|
||||
|
||||
|
||||
func append_failure_message(message: String) -> GdUnitGodotErrorAssert:
|
||||
_additional_failure_message = message
|
||||
return self
|
||||
|
||||
|
||||
func is_success() -> GdUnitGodotErrorAssert:
|
||||
var log_entries := await _execute()
|
||||
if log_entries.is_empty():
|
||||
return _report_success()
|
||||
return _report_error("""
|
||||
Expecting: no error's are ocured.
|
||||
but found: '%s'
|
||||
""".dedent().trim_prefix("\n") % _to_list(log_entries))
|
||||
|
||||
|
||||
func is_runtime_error(expected_error: Variant) -> GdUnitGodotErrorAssert:
|
||||
var result := GdUnitArgumentMatchers.is_variant_string_matching(expected_error)
|
||||
if result.is_error():
|
||||
return _report_error(result.error_message())
|
||||
var log_entries := await _execute()
|
||||
if _has_log_entry(log_entries, ErrorLogEntry.TYPE.SCRIPT_ERROR, expected_error):
|
||||
return _report_success()
|
||||
return _report_error("""
|
||||
Expecting: a runtime error is triggered.
|
||||
message: '%s'
|
||||
found: %s
|
||||
""".dedent().trim_prefix("\n") % [expected_error, _to_list(log_entries)])
|
||||
|
||||
|
||||
func is_push_warning(expected_warning: Variant) -> GdUnitGodotErrorAssert:
|
||||
var result := GdUnitArgumentMatchers.is_variant_string_matching(expected_warning)
|
||||
if result.is_error():
|
||||
return _report_error(result.error_message())
|
||||
var log_entries := await _execute()
|
||||
if _has_log_entry(log_entries, ErrorLogEntry.TYPE.PUSH_WARNING, expected_warning):
|
||||
return _report_success()
|
||||
return _report_error("""
|
||||
Expecting: push_warning() is called.
|
||||
message: '%s'
|
||||
found: %s
|
||||
""".dedent().trim_prefix("\n") % [expected_warning, _to_list(log_entries)])
|
||||
|
||||
|
||||
func is_push_error(expected_error: Variant) -> GdUnitGodotErrorAssert:
|
||||
var result := GdUnitArgumentMatchers.is_variant_string_matching(expected_error)
|
||||
if result.is_error():
|
||||
return _report_error(result.error_message())
|
||||
var log_entries := await _execute()
|
||||
if _has_log_entry(log_entries, ErrorLogEntry.TYPE.PUSH_ERROR, expected_error):
|
||||
return _report_success()
|
||||
return _report_error("""
|
||||
Expecting: push_error() is called.
|
||||
message: '%s'
|
||||
found: %s
|
||||
""".dedent().trim_prefix("\n") % [expected_error, _to_list(log_entries)])
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://cyi6ooahncq7q
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
extends GdUnitIntAssert
|
||||
|
||||
var _base: GdUnitAssertImpl
|
||||
|
||||
|
||||
func _init(current :Variant) -> void:
|
||||
_base = GdUnitAssertImpl.new(current)
|
||||
# save the actual assert instance on the current thread context
|
||||
GdUnitThreadManager.get_current_context().set_assert(self)
|
||||
if not GdUnitAssertions.validate_value_type(current, TYPE_INT):
|
||||
@warning_ignore("return_value_discarded")
|
||||
report_error("GdUnitIntAssert inital error, unexpected type <%s>" % GdObjects.typeof_as_string(current))
|
||||
|
||||
|
||||
func _notification(event :int) -> void:
|
||||
if event == NOTIFICATION_PREDELETE:
|
||||
if _base != null:
|
||||
_base.notification(event)
|
||||
_base = null
|
||||
|
||||
|
||||
func current_value() -> Variant:
|
||||
return _base.current_value()
|
||||
|
||||
|
||||
func report_success() -> GdUnitIntAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.report_success()
|
||||
return self
|
||||
|
||||
|
||||
func report_error(error :String) -> GdUnitIntAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.report_error(error)
|
||||
return self
|
||||
|
||||
|
||||
func failure_message() -> String:
|
||||
return _base.failure_message()
|
||||
|
||||
|
||||
func override_failure_message(message: String) -> GdUnitIntAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.override_failure_message(message)
|
||||
return self
|
||||
|
||||
|
||||
func append_failure_message(message: String) -> GdUnitIntAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.append_failure_message(message)
|
||||
return self
|
||||
|
||||
|
||||
func is_null() -> GdUnitIntAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_null()
|
||||
return self
|
||||
|
||||
|
||||
func is_not_null() -> GdUnitIntAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_not_null()
|
||||
return self
|
||||
|
||||
|
||||
func is_equal(expected: Variant) -> GdUnitIntAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_equal(expected)
|
||||
return self
|
||||
|
||||
|
||||
func is_not_equal(expected: Variant) -> GdUnitIntAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_not_equal(expected)
|
||||
return self
|
||||
|
||||
|
||||
func is_less(expected :int) -> GdUnitIntAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null or current >= expected:
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.LESS_THAN, current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_less_equal(expected :int) -> GdUnitIntAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null or current > expected:
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.LESS_EQUAL, current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_greater(expected :int) -> GdUnitIntAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null or current <= expected:
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.GREATER_THAN, current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_greater_equal(expected :int) -> GdUnitIntAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null or current < expected:
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.GREATER_EQUAL, current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_even() -> GdUnitIntAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null or current % 2 != 0:
|
||||
return report_error(GdAssertMessages.error_is_even(current))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_odd() -> GdUnitIntAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null or current % 2 == 0:
|
||||
return report_error(GdAssertMessages.error_is_odd(current))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_negative() -> GdUnitIntAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null or current >= 0:
|
||||
return report_error(GdAssertMessages.error_is_negative(current))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_not_negative() -> GdUnitIntAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null or current < 0:
|
||||
return report_error(GdAssertMessages.error_is_not_negative(current))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_zero() -> GdUnitIntAssert:
|
||||
var current :Variant = current_value()
|
||||
if current != 0:
|
||||
return report_error(GdAssertMessages.error_is_zero(current))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_not_zero() -> GdUnitIntAssert:
|
||||
var current :Variant= current_value()
|
||||
if current == 0:
|
||||
return report_error(GdAssertMessages.error_is_not_zero())
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_in(expected :Array) -> GdUnitIntAssert:
|
||||
var current :Variant = current_value()
|
||||
if not expected.has(current):
|
||||
return report_error(GdAssertMessages.error_is_in(current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_not_in(expected :Array) -> GdUnitIntAssert:
|
||||
var current :Variant = current_value()
|
||||
if expected.has(current):
|
||||
return report_error(GdAssertMessages.error_is_not_in(current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_between(from :int, to :int) -> GdUnitIntAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null or current < from or current > to:
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.BETWEEN_EQUAL, current, from, to))
|
||||
return report_success()
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://j4mpmwm2hw61
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
extends GdUnitObjectAssert
|
||||
|
||||
var _base: GdUnitAssertImpl
|
||||
|
||||
|
||||
func _init(current: Variant) -> void:
|
||||
_base = GdUnitAssertImpl.new(current)
|
||||
# save the actual assert instance on the current thread context
|
||||
GdUnitThreadManager.get_current_context().set_assert(self)
|
||||
if (current != null
|
||||
and (GdUnitAssertions.validate_value_type(current, TYPE_BOOL)
|
||||
or GdUnitAssertions.validate_value_type(current, TYPE_INT)
|
||||
or GdUnitAssertions.validate_value_type(current, TYPE_FLOAT)
|
||||
or GdUnitAssertions.validate_value_type(current, TYPE_STRING))):
|
||||
@warning_ignore("return_value_discarded")
|
||||
report_error("GdUnitObjectAssert inital error, unexpected type <%s>" % GdObjects.typeof_as_string(current))
|
||||
|
||||
|
||||
func _notification(event: int) -> void:
|
||||
if event == NOTIFICATION_PREDELETE:
|
||||
if _base != null:
|
||||
_base.notification(event)
|
||||
_base = null
|
||||
|
||||
|
||||
func current_value() -> Variant:
|
||||
return _base.current_value()
|
||||
|
||||
|
||||
func report_success() -> GdUnitObjectAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.report_success()
|
||||
return self
|
||||
|
||||
|
||||
func report_error(error: String) -> GdUnitObjectAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.report_error(error)
|
||||
return self
|
||||
|
||||
|
||||
func failure_message() -> String:
|
||||
return _base.failure_message()
|
||||
|
||||
|
||||
func override_failure_message(message: String) -> GdUnitObjectAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.override_failure_message(message)
|
||||
return self
|
||||
|
||||
|
||||
func append_failure_message(message: String) -> GdUnitObjectAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.append_failure_message(message)
|
||||
return self
|
||||
|
||||
|
||||
func is_equal(expected: Variant) -> GdUnitObjectAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_equal(expected)
|
||||
return self
|
||||
|
||||
|
||||
func is_not_equal(expected: Variant) -> GdUnitObjectAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_not_equal(expected)
|
||||
return self
|
||||
|
||||
|
||||
func is_null() -> GdUnitObjectAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_null()
|
||||
return self
|
||||
|
||||
|
||||
func is_not_null() -> GdUnitObjectAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_not_null()
|
||||
return self
|
||||
|
||||
|
||||
@warning_ignore("shadowed_global_identifier")
|
||||
func is_same(expected: Variant) -> GdUnitObjectAssert:
|
||||
var current: Variant = current_value()
|
||||
if not is_same(current, expected):
|
||||
return report_error(GdAssertMessages.error_is_same(current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_not_same(expected: Variant) -> GdUnitObjectAssert:
|
||||
var current: Variant = current_value()
|
||||
if is_same(current, expected):
|
||||
return report_error(GdAssertMessages.error_not_same(current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_instanceof(type: Variant) -> GdUnitObjectAssert:
|
||||
var current: Variant = current_value()
|
||||
if current == null or not is_instance_of(current, type):
|
||||
var result_expected := GdObjects.extract_class_name(type)
|
||||
var result_current := GdObjects.extract_class_name(current)
|
||||
return report_error(GdAssertMessages.error_is_instanceof(result_current, result_expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_not_instanceof(type: Variant) -> GdUnitObjectAssert:
|
||||
var current: Variant = current_value()
|
||||
if is_instance_of(current, type):
|
||||
var result := GdObjects.extract_class_name(type)
|
||||
if result.is_success():
|
||||
return report_error("Expected not be a instance of <%s>" % str(result.value()))
|
||||
|
||||
push_error("Internal ERROR: %s" % result.error_message())
|
||||
return self
|
||||
return report_success()
|
||||
|
||||
|
||||
## Checks whether the current object inherits from the specified type.
|
||||
func is_inheriting(type: Variant) -> GdUnitObjectAssert:
|
||||
var current: Variant = current_value()
|
||||
if not is_instance_of(current, TYPE_OBJECT):
|
||||
return report_error("Expected '%s' to inherit from at least Object." % str(current))
|
||||
var result := _inherits(current, type)
|
||||
if result.is_success():
|
||||
return report_success()
|
||||
return report_error(result.error_message())
|
||||
|
||||
|
||||
## Checks whether the current object does NOT inherit from the specified type.
|
||||
func is_not_inheriting(type: Variant) -> GdUnitObjectAssert:
|
||||
var current: Variant = current_value()
|
||||
if not is_instance_of(current, TYPE_OBJECT):
|
||||
return report_error("Expected '%s' to inherit from at least Object." % str(current))
|
||||
var result := _inherits(current, type)
|
||||
if result.is_success():
|
||||
return report_error("Expected type to not inherit from <%s>" % _extract_class_type(type))
|
||||
return report_success()
|
||||
|
||||
|
||||
func _inherits(current: Variant, type: Variant) -> GdUnitResult:
|
||||
var type_as_string := _extract_class_type(type)
|
||||
if type_as_string == "Object":
|
||||
return GdUnitResult.success("")
|
||||
|
||||
var obj: Object = current
|
||||
for p in obj.get_property_list():
|
||||
var clazz_name :String = p["name"]
|
||||
if p["usage"] == PROPERTY_USAGE_CATEGORY and clazz_name == p["hint_string"] and clazz_name == type_as_string:
|
||||
return GdUnitResult.success("")
|
||||
var script: Script = obj.get_script()
|
||||
if script != null:
|
||||
while script != null:
|
||||
var result := GdObjects.extract_class_name(script)
|
||||
if result.is_success() and result.value() == type_as_string:
|
||||
return GdUnitResult.success("")
|
||||
script = script.get_base_script()
|
||||
return GdUnitResult.error("Expected type to inherit from <%s>" % type_as_string)
|
||||
|
||||
|
||||
func _extract_class_type(type: Variant) -> String:
|
||||
if type is String:
|
||||
return type
|
||||
var result := GdObjects.extract_class_name(type)
|
||||
if result.is_error():
|
||||
return ""
|
||||
return result.value()
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://bm6qm58a0dacq
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
extends GdUnitResultAssert
|
||||
|
||||
var _base: GdUnitAssertImpl
|
||||
|
||||
|
||||
func _init(current :Variant) -> void:
|
||||
_base = GdUnitAssertImpl.new(current)
|
||||
# save the actual assert instance on the current thread context
|
||||
GdUnitThreadManager.get_current_context().set_assert(self)
|
||||
if not validate_value_type(current):
|
||||
@warning_ignore("return_value_discarded")
|
||||
report_error("GdUnitResultAssert inital error, unexpected type <%s>" % GdObjects.typeof_as_string(current))
|
||||
|
||||
|
||||
func _notification(event :int) -> void:
|
||||
if event == NOTIFICATION_PREDELETE:
|
||||
if _base != null:
|
||||
_base.notification(event)
|
||||
_base = null
|
||||
|
||||
|
||||
func validate_value_type(value :Variant) -> bool:
|
||||
return value == null or value is GdUnitResult
|
||||
|
||||
|
||||
func current_value() -> GdUnitResult:
|
||||
return _base.current_value()
|
||||
|
||||
|
||||
func report_success() -> GdUnitResultAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.report_success()
|
||||
return self
|
||||
|
||||
|
||||
func report_error(error :String) -> GdUnitResultAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.report_error(error)
|
||||
return self
|
||||
|
||||
|
||||
func failure_message() -> String:
|
||||
return _base.failure_message()
|
||||
|
||||
|
||||
func override_failure_message(message: String) -> GdUnitResultAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.override_failure_message(message)
|
||||
return self
|
||||
|
||||
|
||||
func append_failure_message(message: String) -> GdUnitResultAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.append_failure_message(message)
|
||||
return self
|
||||
|
||||
|
||||
func is_null() -> GdUnitResultAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_null()
|
||||
return self
|
||||
|
||||
|
||||
func is_not_null() -> GdUnitResultAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_not_null()
|
||||
return self
|
||||
|
||||
|
||||
func is_equal(expected: Variant) -> GdUnitResultAssert:
|
||||
return is_value(expected)
|
||||
|
||||
|
||||
func is_not_equal(expected: Variant) -> GdUnitResultAssert:
|
||||
var result := current_value()
|
||||
var value :Variant = null if result == null else result.value()
|
||||
if GdObjects.equals(value, expected):
|
||||
return report_error(GdAssertMessages.error_not_equal(value, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_empty() -> GdUnitResultAssert:
|
||||
var result := current_value()
|
||||
if result == null or not result.is_empty():
|
||||
return report_error(GdAssertMessages.error_result_is_empty(result))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_success() -> GdUnitResultAssert:
|
||||
var result := current_value()
|
||||
if result == null or not result.is_success():
|
||||
return report_error(GdAssertMessages.error_result_is_success(result))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_warning() -> GdUnitResultAssert:
|
||||
var result := current_value()
|
||||
if result == null or not result.is_warn():
|
||||
return report_error(GdAssertMessages.error_result_is_warning(result))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_error() -> GdUnitResultAssert:
|
||||
var result := current_value()
|
||||
if result == null or not result.is_error():
|
||||
return report_error(GdAssertMessages.error_result_is_error(result))
|
||||
return report_success()
|
||||
|
||||
|
||||
func contains_message(expected :String) -> GdUnitResultAssert:
|
||||
var result := current_value()
|
||||
if result == null:
|
||||
return report_error(GdAssertMessages.error_result_has_message("<null>", expected))
|
||||
if result.is_success():
|
||||
return report_error(GdAssertMessages.error_result_has_message_on_success(expected))
|
||||
if result.is_error() and result.error_message() != expected:
|
||||
return report_error(GdAssertMessages.error_result_has_message(result.error_message(), expected))
|
||||
if result.is_warn() and result.warn_message() != expected:
|
||||
return report_error(GdAssertMessages.error_result_has_message(result.warn_message(), expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_value(expected: Variant) -> GdUnitResultAssert:
|
||||
var result := current_value()
|
||||
var value :Variant = null if result == null else result.value()
|
||||
if not GdObjects.equals(value, expected):
|
||||
return report_error(GdAssertMessages.error_result_is_value(value, expected))
|
||||
return report_success()
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://b0dlq6jyjcvps
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
extends GdUnitSignalAssert
|
||||
|
||||
const DEFAULT_TIMEOUT := 2000
|
||||
|
||||
var _signal_collector :GdUnitSignalCollector
|
||||
var _emitter :Object
|
||||
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
|
||||
|
||||
|
||||
func _init(emitter :Object) -> void:
|
||||
# save the actual assert instance on the current thread context
|
||||
var context := GdUnitThreadManager.get_current_context()
|
||||
context.set_assert(self)
|
||||
_signal_collector = context.get_signal_collector()
|
||||
_line_number = GdUnitAssertions.get_line_number()
|
||||
_emitter = emitter
|
||||
GdAssertReports.reset_last_error_line_number()
|
||||
|
||||
|
||||
func _notification(what :int) -> void:
|
||||
if what == NOTIFICATION_PREDELETE:
|
||||
_interrupted = true
|
||||
if is_instance_valid(_emitter):
|
||||
_signal_collector.unregister_emitter(_emitter)
|
||||
_emitter = null
|
||||
|
||||
|
||||
func report_success() -> GdUnitAssert:
|
||||
GdAssertReports.report_success()
|
||||
return self
|
||||
|
||||
|
||||
func report_warning(message :String) -> GdUnitAssert:
|
||||
GdAssertReports.report_warning(message, GdUnitAssertions.get_line_number())
|
||||
return self
|
||||
|
||||
|
||||
func report_error(failure :String) -> GdUnitAssert:
|
||||
_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) -> GdUnitSignalAssert:
|
||||
_custom_failure_message = message
|
||||
return self
|
||||
|
||||
|
||||
func append_failure_message(message: String) -> GdUnitSignalAssert:
|
||||
_additional_failure_message = message
|
||||
return self
|
||||
|
||||
|
||||
func wait_until(timeout := 2000) -> GdUnitSignalAssert:
|
||||
if timeout <= 0:
|
||||
@warning_ignore("return_value_discarded")
|
||||
report_warning("Invalid timeout parameter, allowed timeouts must be greater than 0, use default timeout instead!")
|
||||
_timeout = DEFAULT_TIMEOUT
|
||||
else:
|
||||
_timeout = timeout
|
||||
return self
|
||||
|
||||
|
||||
func is_null() -> GdUnitSignalAssert:
|
||||
if _emitter != null:
|
||||
return report_error(GdAssertMessages.error_is_null(_emitter))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_not_null() -> GdUnitSignalAssert:
|
||||
if _emitter == null:
|
||||
return report_error(GdAssertMessages.error_is_not_null())
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_equal(_expected: Variant) -> GdUnitSignalAssert:
|
||||
return report_error("Not implemented")
|
||||
|
||||
|
||||
func is_not_equal(_expected: Variant) -> GdUnitSignalAssert:
|
||||
return report_error("Not implemented")
|
||||
|
||||
|
||||
# Verifies the signal exists checked the emitter
|
||||
func is_signal_exists(signal_name :String) -> GdUnitSignalAssert:
|
||||
if not _emitter.has_signal(signal_name):
|
||||
@warning_ignore("return_value_discarded")
|
||||
report_error("The signal '%s' not exists checked object '%s'." % [signal_name, _emitter.get_class()])
|
||||
return self
|
||||
|
||||
|
||||
# Verifies that given signal is emitted until waiting time
|
||||
func is_emitted(name :String, args := []) -> GdUnitSignalAssert:
|
||||
_line_number = GdUnitAssertions.get_line_number()
|
||||
return await _wail_until_signal(name, args, false)
|
||||
|
||||
|
||||
# Verifies that given signal is NOT emitted until waiting time
|
||||
func is_not_emitted(name :String, args := []) -> GdUnitSignalAssert:
|
||||
_line_number = GdUnitAssertions.get_line_number()
|
||||
return await _wail_until_signal(name, args, true)
|
||||
|
||||
|
||||
func _wail_until_signal(signal_name :String, expected_args :Array, expect_not_emitted: bool) -> GdUnitSignalAssert:
|
||||
if _emitter == null:
|
||||
return report_error("Can't wait for signal checked a NULL object.")
|
||||
# first verify the signal is defined
|
||||
if not _emitter.has_signal(signal_name):
|
||||
return report_error("Can't wait for non-existion signal '%s' checked object '%s'." % [signal_name,_emitter.get_class()])
|
||||
_signal_collector.register_emitter(_emitter)
|
||||
var time_scale := Engine.get_time_scale()
|
||||
var timer := Timer.new()
|
||||
(Engine.get_main_loop() as SceneTree).root.add_child(timer)
|
||||
timer.add_to_group("GdUnitTimers")
|
||||
timer.set_one_shot(true)
|
||||
@warning_ignore("return_value_discarded")
|
||||
timer.timeout.connect(func on_timeout() -> void: _interrupted = true)
|
||||
timer.start((_timeout/1000.0)*time_scale)
|
||||
var is_signal_emitted := false
|
||||
while not _interrupted and not is_signal_emitted:
|
||||
await (Engine.get_main_loop() as SceneTree).process_frame
|
||||
if is_instance_valid(_emitter):
|
||||
is_signal_emitted = _signal_collector.match(_emitter, signal_name, expected_args)
|
||||
if is_signal_emitted and expect_not_emitted:
|
||||
@warning_ignore("return_value_discarded")
|
||||
report_error(GdAssertMessages.error_signal_emitted(signal_name, expected_args, LocalTime.elapsed(int(_timeout-timer.time_left*1000))))
|
||||
|
||||
if _interrupted and not expect_not_emitted:
|
||||
@warning_ignore("return_value_discarded")
|
||||
report_error(GdAssertMessages.error_wait_signal(signal_name, expected_args, LocalTime.elapsed(_timeout)))
|
||||
timer.free()
|
||||
if is_instance_valid(_emitter):
|
||||
_signal_collector.reset_received_signals(_emitter, signal_name, expected_args)
|
||||
return self
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://dlh37yc086vr5
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
extends GdUnitStringAssert
|
||||
|
||||
var _base: GdUnitAssertImpl
|
||||
|
||||
|
||||
func _init(current :Variant) -> void:
|
||||
_base = GdUnitAssertImpl.new(current)
|
||||
# save the actual assert instance on the current thread context
|
||||
GdUnitThreadManager.get_current_context().set_assert(self)
|
||||
if current != null and typeof(current) != TYPE_STRING and typeof(current) != TYPE_STRING_NAME:
|
||||
@warning_ignore("return_value_discarded")
|
||||
report_error("GdUnitStringAssert inital error, unexpected type <%s>" % GdObjects.typeof_as_string(current))
|
||||
|
||||
|
||||
func _notification(event :int) -> void:
|
||||
if event == NOTIFICATION_PREDELETE:
|
||||
if _base != null:
|
||||
_base.notification(event)
|
||||
_base = null
|
||||
|
||||
|
||||
func failure_message() -> String:
|
||||
return _base.failure_message()
|
||||
|
||||
|
||||
func current_value() -> Variant:
|
||||
return _base.current_value()
|
||||
|
||||
|
||||
func report_success() -> GdUnitStringAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.report_success()
|
||||
return self
|
||||
|
||||
|
||||
func report_error(error :String) -> GdUnitStringAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.report_error(error)
|
||||
return self
|
||||
|
||||
|
||||
func override_failure_message(message: String) -> GdUnitStringAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.override_failure_message(message)
|
||||
return self
|
||||
|
||||
|
||||
func append_failure_message(message: String) -> GdUnitStringAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.append_failure_message(message)
|
||||
return self
|
||||
|
||||
|
||||
func is_null() -> GdUnitStringAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_null()
|
||||
return self
|
||||
|
||||
|
||||
func is_not_null() -> GdUnitStringAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_not_null()
|
||||
return self
|
||||
|
||||
|
||||
func is_equal(expected: Variant) -> GdUnitStringAssert:
|
||||
return _is_equal(expected, false, GdAssertMessages.error_equal)
|
||||
|
||||
|
||||
func is_equal_ignoring_case(expected: Variant) -> GdUnitStringAssert:
|
||||
return _is_equal(expected, true, GdAssertMessages.error_equal_ignoring_case)
|
||||
|
||||
|
||||
@warning_ignore_start("unsafe_call_argument")
|
||||
func _is_equal(expected: Variant, ignore_case: bool, message_cb: Callable) -> GdUnitStringAssert:
|
||||
var current: Variant = current_value()
|
||||
if current == null:
|
||||
return report_error(message_cb.call(current, expected))
|
||||
var cur_value := str(current)
|
||||
if not GdObjects.equals(cur_value, expected, ignore_case):
|
||||
var exp_value := str(expected)
|
||||
if contains_bbcode(cur_value):
|
||||
# mask user bbcode
|
||||
# https://docs.godotengine.org/en/4.5/tutorials/ui/bbcode_in_richtextlabel.html#handling-user-input-safely
|
||||
return report_error(message_cb.call(cur_value.replace("[", "[lb]"), exp_value.replace("[", "[lb]")))
|
||||
var diffs := GdDiffTool.string_diff(cur_value, exp_value)
|
||||
var formatted_current := GdAssertMessages.colored_array_div(diffs[1])
|
||||
return report_error(message_cb.call(formatted_current, exp_value))
|
||||
return report_success()
|
||||
@warning_ignore_restore("unsafe_call_argument")
|
||||
|
||||
|
||||
func is_not_equal(expected: Variant) -> GdUnitStringAssert:
|
||||
var current: Variant = current_value()
|
||||
if GdObjects.equals(current, expected):
|
||||
return report_error(GdAssertMessages.error_not_equal(current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_not_equal_ignoring_case(expected :Variant) -> GdUnitStringAssert:
|
||||
var current :Variant = current_value()
|
||||
if GdObjects.equals(current, expected, true):
|
||||
return report_error(GdAssertMessages.error_not_equal(current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_empty() -> GdUnitStringAssert:
|
||||
var current :Variant = current_value()
|
||||
@warning_ignore("unsafe_cast")
|
||||
if current == null or not (current as String).is_empty():
|
||||
return report_error(GdAssertMessages.error_is_empty(current))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_not_empty() -> GdUnitStringAssert:
|
||||
var current :Variant = current_value()
|
||||
@warning_ignore("unsafe_cast")
|
||||
if current == null or (current as String).is_empty():
|
||||
return report_error(GdAssertMessages.error_is_not_empty())
|
||||
return report_success()
|
||||
|
||||
|
||||
func contains(expected :String) -> GdUnitStringAssert:
|
||||
var current :Variant = current_value()
|
||||
@warning_ignore("unsafe_cast")
|
||||
if current == null or (current as String).find(expected) == -1:
|
||||
return report_error(GdAssertMessages.error_contains(current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func not_contains(expected :String) -> GdUnitStringAssert:
|
||||
var current :Variant = current_value()
|
||||
@warning_ignore("unsafe_cast")
|
||||
if current != null and (current as String).find(expected) != -1:
|
||||
return report_error(GdAssertMessages.error_not_contains(current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func contains_ignoring_case(expected :String) -> GdUnitStringAssert:
|
||||
var current :Variant = current_value()
|
||||
@warning_ignore("unsafe_cast")
|
||||
if current == null or (current as String).findn(expected) == -1:
|
||||
return report_error(GdAssertMessages.error_contains_ignoring_case(current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func not_contains_ignoring_case(expected :String) -> GdUnitStringAssert:
|
||||
var current :Variant = current_value()
|
||||
@warning_ignore("unsafe_cast")
|
||||
if current != null and (current as String).findn(expected) != -1:
|
||||
return report_error(GdAssertMessages.error_not_contains_ignoring_case(current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func starts_with(expected :String) -> GdUnitStringAssert:
|
||||
var current :Variant = current_value()
|
||||
@warning_ignore("unsafe_cast")
|
||||
if current == null or (current as String).find(expected) != 0:
|
||||
return report_error(GdAssertMessages.error_starts_with(current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func ends_with(expected :String) -> GdUnitStringAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null:
|
||||
return report_error(GdAssertMessages.error_ends_with(current, expected))
|
||||
@warning_ignore("unsafe_cast")
|
||||
var find :int = (current as String).length() - expected.length()
|
||||
@warning_ignore("unsafe_cast")
|
||||
if (current as String).rfind(expected) != find:
|
||||
return report_error(GdAssertMessages.error_ends_with(current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
# gdlint:disable=max-returns
|
||||
func has_length(expected :int, comparator := Comparator.EQUAL) -> GdUnitStringAssert:
|
||||
var current :Variant = current_value()
|
||||
if current == null:
|
||||
return report_error(GdAssertMessages.error_has_length(current, expected, comparator))
|
||||
var str_current: String = current
|
||||
match comparator:
|
||||
Comparator.EQUAL:
|
||||
if str_current.length() != expected:
|
||||
return report_error(GdAssertMessages.error_has_length(str_current, expected, comparator))
|
||||
Comparator.LESS_THAN:
|
||||
if str_current.length() >= expected:
|
||||
return report_error(GdAssertMessages.error_has_length(str_current, expected, comparator))
|
||||
Comparator.LESS_EQUAL:
|
||||
if str_current.length() > expected:
|
||||
return report_error(GdAssertMessages.error_has_length(str_current, expected, comparator))
|
||||
Comparator.GREATER_THAN:
|
||||
if str_current.length() <= expected:
|
||||
return report_error(GdAssertMessages.error_has_length(str_current, expected, comparator))
|
||||
Comparator.GREATER_EQUAL:
|
||||
if str_current.length() < expected:
|
||||
return report_error(GdAssertMessages.error_has_length(str_current, expected, comparator))
|
||||
_:
|
||||
return report_error("Comparator '%d' not implemented!" % comparator)
|
||||
return report_success()
|
||||
|
||||
|
||||
func contains_bbcode(value: String) -> bool:
|
||||
var rtl := RichTextLabel.new()
|
||||
rtl.bbcode_enabled = true
|
||||
rtl.parse_bbcode(value)
|
||||
var has_bbcode := rtl.get_parsed_text() != value
|
||||
rtl.free()
|
||||
return has_bbcode
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://dxqvilchqqeta
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
extends GdUnitVectorAssert
|
||||
|
||||
var _base: GdUnitAssertImpl
|
||||
var _current_type: int
|
||||
var _type_check: bool
|
||||
|
||||
func _init(current: Variant, type_check := true) -> void:
|
||||
_type_check = type_check
|
||||
_base = GdUnitAssertImpl.new(current)
|
||||
# save the actual assert instance on the current thread context
|
||||
GdUnitThreadManager.get_current_context().set_assert(self)
|
||||
if not _validate_value_type(current):
|
||||
@warning_ignore("return_value_discarded")
|
||||
report_error("GdUnitVectorAssert error, the type <%s> is not supported." % GdObjects.typeof_as_string(current))
|
||||
_current_type = typeof(current)
|
||||
|
||||
|
||||
func _notification(event :int) -> void:
|
||||
if event == NOTIFICATION_PREDELETE:
|
||||
if _base != null:
|
||||
_base.notification(event)
|
||||
_base = null
|
||||
|
||||
|
||||
func _validate_value_type(value :Variant) -> bool:
|
||||
return (
|
||||
value == null
|
||||
or typeof(value) in [
|
||||
TYPE_VECTOR2,
|
||||
TYPE_VECTOR2I,
|
||||
TYPE_VECTOR3,
|
||||
TYPE_VECTOR3I,
|
||||
TYPE_VECTOR4,
|
||||
TYPE_VECTOR4I
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
func _validate_is_vector_type(value :Variant) -> bool:
|
||||
var type := typeof(value)
|
||||
if type == _current_type or _current_type == TYPE_NIL:
|
||||
return true
|
||||
@warning_ignore("return_value_discarded")
|
||||
report_error(GdAssertMessages.error_is_wrong_type(_current_type, type))
|
||||
return false
|
||||
|
||||
|
||||
func current_value() -> Variant:
|
||||
return _base.current_value()
|
||||
|
||||
|
||||
func report_success() -> GdUnitVectorAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.report_success()
|
||||
return self
|
||||
|
||||
|
||||
func report_error(error :String) -> GdUnitVectorAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.report_error(error)
|
||||
return self
|
||||
|
||||
|
||||
func failure_message() -> String:
|
||||
return _base.failure_message()
|
||||
|
||||
|
||||
func override_failure_message(message: String) -> GdUnitVectorAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.override_failure_message(message)
|
||||
return self
|
||||
|
||||
|
||||
func append_failure_message(message :String) -> GdUnitVectorAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.append_failure_message(message)
|
||||
return self
|
||||
|
||||
|
||||
func is_null() -> GdUnitVectorAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_null()
|
||||
return self
|
||||
|
||||
|
||||
func is_not_null() -> GdUnitVectorAssert:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_not_null()
|
||||
return self
|
||||
|
||||
|
||||
func is_equal(expected: Variant) -> GdUnitVectorAssert:
|
||||
if _type_check and not _validate_is_vector_type(expected):
|
||||
return self
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_equal(expected)
|
||||
return self
|
||||
|
||||
|
||||
func is_not_equal(expected: Variant) -> GdUnitVectorAssert:
|
||||
if _type_check and not _validate_is_vector_type(expected):
|
||||
return self
|
||||
@warning_ignore("return_value_discarded")
|
||||
_base.is_not_equal(expected)
|
||||
return self
|
||||
|
||||
|
||||
@warning_ignore("shadowed_global_identifier")
|
||||
func is_equal_approx(expected :Variant, approx :Variant) -> GdUnitVectorAssert:
|
||||
if not _validate_is_vector_type(expected) or not _validate_is_vector_type(approx):
|
||||
return self
|
||||
var current :Variant = current_value()
|
||||
var from :Variant = expected - approx
|
||||
var to :Variant = expected + approx
|
||||
if current == null or (not _is_equal_approx(current, from, to)):
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.BETWEEN_EQUAL, current, from, to))
|
||||
return report_success()
|
||||
|
||||
|
||||
func _is_equal_approx(current :Variant, from :Variant, to :Variant) -> bool:
|
||||
match typeof(current):
|
||||
TYPE_VECTOR2, TYPE_VECTOR2I:
|
||||
return ((current.x >= from.x and current.y >= from.y)
|
||||
and (current.x <= to.x and current.y <= to.y))
|
||||
TYPE_VECTOR3, TYPE_VECTOR3I:
|
||||
return ((current.x >= from.x and current.y >= from.y and current.z >= from.z)
|
||||
and (current.x <= to.x and current.y <= to.y and current.z <= to.z))
|
||||
TYPE_VECTOR4, TYPE_VECTOR4I:
|
||||
return ((current.x >= from.x and current.y >= from.y and current.z >= from.z and current.w >= from.w)
|
||||
and (current.x <= to.x and current.y <= to.y and current.z <= to.z and current.w <= to.w))
|
||||
_:
|
||||
push_error("Missing implementation '_is_equal_approx' for vector type %s" % typeof(current))
|
||||
return false
|
||||
|
||||
|
||||
func is_less(expected :Variant) -> GdUnitVectorAssert:
|
||||
if not _validate_is_vector_type(expected):
|
||||
return self
|
||||
var current :Variant = current_value()
|
||||
if current == null or current >= expected:
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.LESS_THAN, current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_less_equal(expected :Variant) -> GdUnitVectorAssert:
|
||||
if not _validate_is_vector_type(expected):
|
||||
return self
|
||||
var current :Variant = current_value()
|
||||
if current == null or current > expected:
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.LESS_EQUAL, current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_greater(expected :Variant) -> GdUnitVectorAssert:
|
||||
if not _validate_is_vector_type(expected):
|
||||
return self
|
||||
var current :Variant = current_value()
|
||||
if current == null or current <= expected:
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.GREATER_THAN, current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_greater_equal(expected :Variant) -> GdUnitVectorAssert:
|
||||
if not _validate_is_vector_type(expected):
|
||||
return self
|
||||
var current :Variant = current_value()
|
||||
if current == null or current < expected:
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.GREATER_EQUAL, current, expected))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_between(from :Variant, to :Variant) -> GdUnitVectorAssert:
|
||||
if not _validate_is_vector_type(from) or not _validate_is_vector_type(to):
|
||||
return self
|
||||
var current :Variant = current_value()
|
||||
if current == null or not (current >= from and current <= to):
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.BETWEEN_EQUAL, current, from, to))
|
||||
return report_success()
|
||||
|
||||
|
||||
func is_not_between(from :Variant, to :Variant) -> GdUnitVectorAssert:
|
||||
if not _validate_is_vector_type(from) or not _validate_is_vector_type(to):
|
||||
return self
|
||||
var current :Variant = current_value()
|
||||
if (current != null and current >= from and current <= to):
|
||||
return report_error(GdAssertMessages.error_is_value(Comparator.NOT_BETWEEN_EQUAL, current, from, to))
|
||||
return report_success()
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://r4avfcakvscw
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# base interface for assert value provider
|
||||
class_name ValueProvider
|
||||
extends RefCounted
|
||||
|
||||
func get_value() -> Variant:
|
||||
return null
|
||||
|
||||
|
||||
func dispose() -> void:
|
||||
pass
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://8y15b6ts3kss
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
class_name CmdArgumentParser
|
||||
extends RefCounted
|
||||
|
||||
var _options :CmdOptions
|
||||
var _tool_name :String
|
||||
var _parsed_commands :Dictionary = Dictionary()
|
||||
|
||||
|
||||
func _init(p_options :CmdOptions, p_tool_name :String) -> void:
|
||||
_options = p_options
|
||||
_tool_name = p_tool_name
|
||||
|
||||
|
||||
func parse(args :Array, ignore_unknown_cmd := false) -> GdUnitResult:
|
||||
_parsed_commands.clear()
|
||||
|
||||
# parse until first program argument
|
||||
while not args.is_empty():
|
||||
var arg :String = args.pop_front()
|
||||
if arg.find(_tool_name) != -1:
|
||||
break
|
||||
|
||||
if args.is_empty():
|
||||
return GdUnitResult.empty()
|
||||
|
||||
# now parse all arguments
|
||||
while not args.is_empty():
|
||||
var cmd :String = args.pop_front()
|
||||
var option := _options.get_option(cmd)
|
||||
|
||||
if option:
|
||||
if _parse_cmd_arguments(option, args) == -1:
|
||||
return GdUnitResult.error("The '%s' command requires an argument!" % option.short_command())
|
||||
elif not ignore_unknown_cmd:
|
||||
return GdUnitResult.error("Unknown '%s' command!" % cmd)
|
||||
return GdUnitResult.success(_parsed_commands.values())
|
||||
|
||||
|
||||
func options() -> CmdOptions:
|
||||
return _options
|
||||
|
||||
|
||||
func _parse_cmd_arguments(option: CmdOption, args: Array) -> int:
|
||||
var command_name := option.short_command()
|
||||
var command: CmdCommand = _parsed_commands.get(command_name, CmdCommand.new(command_name))
|
||||
|
||||
if option.has_argument():
|
||||
if not option.is_argument_optional() and args.is_empty():
|
||||
return -1
|
||||
if _is_next_value_argument(args):
|
||||
var value: String = args.pop_front()
|
||||
command.add_argument(value)
|
||||
elif not option.is_argument_optional():
|
||||
return -1
|
||||
_parsed_commands[command_name] = command
|
||||
return 0
|
||||
|
||||
|
||||
func _is_next_value_argument(args: PackedStringArray) -> bool:
|
||||
if args.is_empty():
|
||||
return false
|
||||
return _options.get_option(args[0]) == null
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://d4hd3vc50jltg
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
class_name CmdCommand
|
||||
extends RefCounted
|
||||
|
||||
var _name: String
|
||||
var _arguments: PackedStringArray
|
||||
|
||||
|
||||
func _init(p_name :String, p_arguments := []) -> void:
|
||||
_name = p_name
|
||||
_arguments = PackedStringArray(p_arguments)
|
||||
|
||||
|
||||
func name() -> String:
|
||||
return _name
|
||||
|
||||
|
||||
func arguments() -> PackedStringArray:
|
||||
return _arguments
|
||||
|
||||
|
||||
func add_argument(arg :String) -> void:
|
||||
@warning_ignore("return_value_discarded")
|
||||
_arguments.append(arg)
|
||||
|
||||
|
||||
func _to_string() -> String:
|
||||
return "%s:%s" % [_name, ", ".join(_arguments)]
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://w4mr1j0k0l
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
class_name CmdCommandHandler
|
||||
extends RefCounted
|
||||
|
||||
const CB_SINGLE_ARG = 0
|
||||
const CB_MULTI_ARGS = 1
|
||||
const NO_CB := Callable()
|
||||
|
||||
var _cmd_options :CmdOptions
|
||||
# holds the command callbacks by key:<cmd_name>:String and value: [<cb single arg>, <cb multible args>]:Array
|
||||
# Dictionary[String, Array[Callback]
|
||||
var _command_cbs :Dictionary
|
||||
|
||||
|
||||
|
||||
func _init(cmd_options: CmdOptions) -> void:
|
||||
_cmd_options = cmd_options
|
||||
|
||||
|
||||
# register a callback function for given command
|
||||
# cmd_name short name of the command
|
||||
# fr_arg a funcref to a function with a single argument
|
||||
func register_cb(cmd_name: String, cb: Callable) -> CmdCommandHandler:
|
||||
var registered_cb: Array = _command_cbs.get(cmd_name, [NO_CB, NO_CB])
|
||||
if registered_cb[CB_SINGLE_ARG]:
|
||||
push_error("A function for command '%s' is already registered!" % cmd_name)
|
||||
return self
|
||||
|
||||
if not _validate_cb_signature(cb, TYPE_STRING):
|
||||
push_error(
|
||||
("The callback '%s:%s' for command '%s' has invalid function signature. "
|
||||
+"The callback signature must be 'func name(value: PackedStringArray)'")
|
||||
% [cb.get_object().get_class(), cb.get_method(), cmd_name])
|
||||
return null
|
||||
|
||||
registered_cb[CB_SINGLE_ARG] = cb
|
||||
_command_cbs[cmd_name] = registered_cb
|
||||
return self
|
||||
|
||||
|
||||
# register a callback function for given command
|
||||
# cb a funcref to a function with a variable number of arguments but expects all parameters to be passed via a single Array.
|
||||
func register_cbv(cmd_name: String, cb: Callable) -> CmdCommandHandler:
|
||||
var registered_cb: Array = _command_cbs.get(cmd_name, [NO_CB, NO_CB])
|
||||
if registered_cb[CB_MULTI_ARGS]:
|
||||
push_error("A function for command '%s' is already registered!" % cmd_name)
|
||||
return self
|
||||
|
||||
if not _validate_cb_signature(cb, TYPE_PACKED_STRING_ARRAY):
|
||||
push_error(
|
||||
("The callback '%s:%s' for command '%s' has invalid function signature. "
|
||||
+"The callback signature must be 'func name(value: PackedStringArray)'")
|
||||
% [cb.get_object().get_class(), cb.get_method(), cmd_name])
|
||||
return null
|
||||
|
||||
registered_cb[CB_MULTI_ARGS] = cb
|
||||
_command_cbs[cmd_name] = registered_cb
|
||||
return self
|
||||
|
||||
|
||||
func _validate() -> GdUnitResult:
|
||||
var errors := PackedStringArray()
|
||||
# Dictionary[StringName, String]
|
||||
var registered_cbs := Dictionary()
|
||||
|
||||
for cmd_name in _command_cbs.keys() as Array[String]:
|
||||
var cb: Callable = (_command_cbs[cmd_name][CB_SINGLE_ARG]
|
||||
if _command_cbs[cmd_name][CB_SINGLE_ARG]
|
||||
else _command_cbs[cmd_name][CB_MULTI_ARGS])
|
||||
if cb != NO_CB and not cb.is_valid():
|
||||
@warning_ignore("return_value_discarded")
|
||||
errors.append("Invalid function reference for command '%s', Check the function reference!" % cmd_name)
|
||||
if _cmd_options.get_option(cmd_name) == null:
|
||||
@warning_ignore("return_value_discarded")
|
||||
errors.append("The command '%s' is unknown, verify your CmdOptions!" % cmd_name)
|
||||
# verify for multiple registered command callbacks
|
||||
if cb != NO_CB:
|
||||
var cb_method := cb.get_method()
|
||||
if registered_cbs.has(cb_method):
|
||||
var already_registered_cmd :String = registered_cbs[cb_method]
|
||||
@warning_ignore("return_value_discarded")
|
||||
errors.append("The function reference '%s' already registerd for command '%s'!" % [cb_method, already_registered_cmd])
|
||||
else:
|
||||
registered_cbs[cb_method] = cmd_name
|
||||
if errors.is_empty():
|
||||
return GdUnitResult.success(true)
|
||||
return GdUnitResult.error("\n".join(errors))
|
||||
|
||||
|
||||
func execute(commands: Array[CmdCommand]) -> GdUnitResult:
|
||||
var result := _validate()
|
||||
if result.is_error():
|
||||
return result
|
||||
for cmd in commands:
|
||||
var cmd_name := cmd.name()
|
||||
if _command_cbs.has(cmd_name):
|
||||
var cb_s: Callable = _command_cbs.get(cmd_name)[CB_SINGLE_ARG]
|
||||
var arguments := cmd.arguments()
|
||||
var cmd_option := _cmd_options.get_option(cmd_name)
|
||||
|
||||
if arguments.is_empty():
|
||||
cb_s.call()
|
||||
elif arguments.size() > 1:
|
||||
var cb_m: Callable = _command_cbs.get(cmd_name)[CB_MULTI_ARGS]
|
||||
cb_m.call(arguments)
|
||||
else:
|
||||
if cmd_option.type() == TYPE_BOOL:
|
||||
cb_s.call(true if arguments[0] == "true" else false)
|
||||
else:
|
||||
cb_s.call(arguments[0])
|
||||
|
||||
return GdUnitResult.success(true)
|
||||
|
||||
|
||||
func _validate_cb_signature(cb: Callable, arg_type: int) -> bool:
|
||||
for m in cb.get_object().get_method_list():
|
||||
if m["name"] == cb.get_method():
|
||||
@warning_ignore("unsafe_cast")
|
||||
return _validate_func_arguments(m["args"] as Array, arg_type)
|
||||
return true
|
||||
|
||||
|
||||
func _validate_func_arguments(arguments: Array, arg_type: int) -> bool:
|
||||
# validate we have a single argument
|
||||
if arguments.size() > 1:
|
||||
return false
|
||||
# a cb with no arguments is also valid
|
||||
if arguments.size() == 0:
|
||||
return true
|
||||
# validate argument type
|
||||
var arg: Dictionary = arguments[0]
|
||||
@warning_ignore("unsafe_cast")
|
||||
if arg["usage"] as int == PROPERTY_USAGE_NIL_IS_VARIANT:
|
||||
return true
|
||||
if arg["type"] != arg_type:
|
||||
return false
|
||||
return true
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://ccm3ivfiaf3i7
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
class_name CmdOption
|
||||
extends RefCounted
|
||||
|
||||
|
||||
var _commands :PackedStringArray
|
||||
var _help :String
|
||||
var _description :String
|
||||
var _type :int
|
||||
var _arg_optional :bool = false
|
||||
|
||||
|
||||
# constructs a command option by given arguments
|
||||
# commands : a string with comma separated list of available commands begining with the short form
|
||||
# help: a help text show howto use
|
||||
# description: a full description of the command
|
||||
# type: the argument type
|
||||
# arg_optional: defines of the argument optional
|
||||
func _init(p_commands :String, p_help :String, p_description :String, p_type :int = TYPE_NIL, p_arg_optional :bool = false) -> void:
|
||||
_commands = p_commands.replace(" ", "").replace("\t", "").split(",")
|
||||
_help = p_help
|
||||
_description = p_description
|
||||
_type = p_type
|
||||
_arg_optional = p_arg_optional
|
||||
|
||||
|
||||
func commands() -> PackedStringArray:
|
||||
return _commands
|
||||
|
||||
|
||||
func short_command() -> String:
|
||||
return _commands[0]
|
||||
|
||||
|
||||
func help() -> String:
|
||||
return _help
|
||||
|
||||
|
||||
func description() -> String:
|
||||
return _description
|
||||
|
||||
|
||||
func type() -> int:
|
||||
return _type
|
||||
|
||||
|
||||
func is_argument_optional() -> bool:
|
||||
return _arg_optional
|
||||
|
||||
|
||||
func has_argument() -> bool:
|
||||
return _type != TYPE_NIL
|
||||
|
||||
|
||||
func describe() -> String:
|
||||
if help().is_empty():
|
||||
return " %-32s %s \n" % [commands(), description()]
|
||||
return " %-32s %s \n %-32s %s\n" % [commands(), description(), "", help()]
|
||||
|
||||
|
||||
func _to_string() -> String:
|
||||
return describe()
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://ccnb2ah35atho
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
class_name CmdOptions
|
||||
extends RefCounted
|
||||
|
||||
|
||||
var _default_options :Array[CmdOption]
|
||||
var _advanced_options :Array[CmdOption]
|
||||
|
||||
|
||||
func _init(p_options :Array[CmdOption] = [], p_advanced_options :Array[CmdOption] = []) -> void:
|
||||
# default help options
|
||||
_default_options = p_options
|
||||
_advanced_options = p_advanced_options
|
||||
|
||||
|
||||
func default_options() -> Array[CmdOption]:
|
||||
return _default_options
|
||||
|
||||
|
||||
func advanced_options() -> Array[CmdOption]:
|
||||
return _advanced_options
|
||||
|
||||
|
||||
func options() -> Array[CmdOption]:
|
||||
return default_options() + advanced_options()
|
||||
|
||||
|
||||
func get_option(cmd :String) -> CmdOption:
|
||||
for option in options():
|
||||
if Array(option.commands()).has(cmd):
|
||||
return option
|
||||
return null
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://0p8udx4tdwol
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
## Small helper tool to work with Godot Arrays
|
||||
class_name GdArrayTools
|
||||
extends RefCounted
|
||||
|
||||
|
||||
const max_elements := 32
|
||||
const ARRAY_TYPES := [
|
||||
TYPE_ARRAY,
|
||||
TYPE_PACKED_BYTE_ARRAY,
|
||||
TYPE_PACKED_INT32_ARRAY,
|
||||
TYPE_PACKED_INT64_ARRAY,
|
||||
TYPE_PACKED_FLOAT32_ARRAY,
|
||||
TYPE_PACKED_FLOAT64_ARRAY,
|
||||
TYPE_PACKED_STRING_ARRAY,
|
||||
TYPE_PACKED_VECTOR2_ARRAY,
|
||||
TYPE_PACKED_VECTOR3_ARRAY,
|
||||
TYPE_PACKED_VECTOR4_ARRAY,
|
||||
TYPE_PACKED_COLOR_ARRAY
|
||||
]
|
||||
|
||||
|
||||
static func is_array_type(value: Variant) -> bool:
|
||||
return is_type_array(typeof(value))
|
||||
|
||||
|
||||
static func is_type_array(type :int) -> bool:
|
||||
return type in ARRAY_TYPES
|
||||
|
||||
|
||||
## Filters an array by given value[br]
|
||||
## If the given value not an array it returns null, will remove all occurence of given value.
|
||||
static func filter_value(array: Variant, value: Variant) -> Variant:
|
||||
if not is_array_type(array):
|
||||
return null
|
||||
|
||||
@warning_ignore("unsafe_method_access")
|
||||
var filtered_array: Variant = array.duplicate()
|
||||
@warning_ignore("unsafe_method_access")
|
||||
var index: int = filtered_array.find(value)
|
||||
while index != -1:
|
||||
@warning_ignore("unsafe_method_access")
|
||||
filtered_array.remove_at(index)
|
||||
@warning_ignore("unsafe_method_access")
|
||||
index = filtered_array.find(value)
|
||||
return filtered_array
|
||||
|
||||
|
||||
## Groups an array by a custom key selector
|
||||
## The function should take an item and return the group key
|
||||
static func group_by(array: Array, key_selector: Callable) -> Dictionary:
|
||||
var result := {}
|
||||
|
||||
for item: Variant in array:
|
||||
var group_key: Variant = key_selector.call(item)
|
||||
var values: Array = result.get_or_add(group_key, [])
|
||||
values.append(item)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
## Erases a value from given array by using equals(l,r) to find the element to erase
|
||||
static func erase_value(array :Array, value :Variant) -> void:
|
||||
for element :Variant in array:
|
||||
if GdObjects.equals(element, value):
|
||||
array.erase(element)
|
||||
|
||||
|
||||
## Scans for the array build in type on a untyped array[br]
|
||||
## Returns the buildin type by scan all values and returns the type if all values has the same type.
|
||||
## If the values has different types TYPE_VARIANT is returend
|
||||
static func scan_typed(array :Array) -> int:
|
||||
if array.is_empty():
|
||||
return TYPE_NIL
|
||||
var actual_type := GdObjects.TYPE_VARIANT
|
||||
for value :Variant in array:
|
||||
var current_type := typeof(value)
|
||||
if not actual_type in [GdObjects.TYPE_VARIANT, current_type]:
|
||||
return GdObjects.TYPE_VARIANT
|
||||
actual_type = current_type
|
||||
return actual_type
|
||||
|
||||
|
||||
## Converts given array into a string presentation.[br]
|
||||
## This function is different to the original Godot str(<array>) implementation.
|
||||
## The string presentaion contains fullquallified typed informations.
|
||||
##[br]
|
||||
## Examples:
|
||||
## [codeblock]
|
||||
## # will result in PackedString(["a", "b"])
|
||||
## GdArrayTools.as_string(PackedStringArray("a", "b"))
|
||||
## # will result in PackedString(["a", "b"])
|
||||
## GdArrayTools.as_string(PackedColorArray(Color.RED, COLOR.GREEN))
|
||||
## [/codeblock]
|
||||
static func as_string(elements: Variant, encode_value := true) -> String:
|
||||
var delemiter := ", "
|
||||
if elements == null:
|
||||
return "<null>"
|
||||
@warning_ignore("unsafe_cast")
|
||||
if (elements as Array).is_empty():
|
||||
return "<empty>"
|
||||
var prefix := _typeof_as_string(elements) if encode_value else ""
|
||||
var formatted := ""
|
||||
var index := 0
|
||||
for element :Variant in elements:
|
||||
if max_elements != -1 and index > max_elements:
|
||||
return prefix + "[" + formatted + delemiter + "...]"
|
||||
if formatted.length() > 0 :
|
||||
formatted += delemiter
|
||||
formatted += GdDefaultValueDecoder.decode(element) if encode_value else str(element)
|
||||
index += 1
|
||||
return prefix + "[" + formatted + "]"
|
||||
|
||||
|
||||
static func has_same_content(current: Array, other: Array) -> bool:
|
||||
if current.size() != other.size(): return false
|
||||
for element: Variant in current:
|
||||
if not other.has(element): return false
|
||||
if current.count(element) != other.count(element): return false
|
||||
return true
|
||||
|
||||
|
||||
static func _typeof_as_string(value :Variant) -> String:
|
||||
var type := typeof(value)
|
||||
# for untyped array we retun empty string
|
||||
if type == TYPE_ARRAY:
|
||||
return ""
|
||||
return GdObjects.typeof_as_string(value)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://bk60ywsj4ekp7
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
# Myers' Diff Algorithm implementation
|
||||
# Based on "An O(ND) Difference Algorithm and Its Variations" by Eugene W. Myers
|
||||
class_name GdDiffTool
|
||||
extends RefCounted
|
||||
|
||||
|
||||
const DIV_ADD :int = 214
|
||||
const DIV_SUB :int = 215
|
||||
|
||||
|
||||
class Edit:
|
||||
enum Type { EQUAL, INSERT, DELETE }
|
||||
var type: Type
|
||||
var character: int
|
||||
|
||||
func _init(t: Type, chr: int) -> void:
|
||||
type = t
|
||||
character = chr
|
||||
|
||||
|
||||
# Main entry point - returns [ldiff, rdiff]
|
||||
static func string_diff(left: Variant, right: Variant) -> Array[PackedInt32Array]:
|
||||
var lb := PackedInt32Array() if left == null else str(left).to_utf32_buffer().to_int32_array()
|
||||
var rb := PackedInt32Array() if right == null else str(right).to_utf32_buffer().to_int32_array()
|
||||
|
||||
# Early exit for identical strings
|
||||
if lb == rb:
|
||||
return [lb.duplicate(), rb.duplicate()]
|
||||
|
||||
var edits := _myers_diff(lb, rb)
|
||||
return _edits_to_diff_format(edits)
|
||||
|
||||
|
||||
# Core Myers' algorithm
|
||||
static func _myers_diff(a: PackedInt32Array, b: PackedInt32Array) -> Array[Edit]:
|
||||
var n := a.size()
|
||||
var m := b.size()
|
||||
var max_d := n + m
|
||||
|
||||
# V array stores the furthest reaching x coordinate for each k-line
|
||||
# We need indices from -max_d to max_d, so we offset by max_d
|
||||
var v := PackedInt32Array()
|
||||
v.resize(2 * max_d + 1)
|
||||
v.fill(-1)
|
||||
v[max_d + 1] = 0 # k=1 starts at x=0
|
||||
|
||||
var trace := [] # Store V arrays for each d to backtrack later
|
||||
|
||||
# Find the edit distance
|
||||
for d in range(0, max_d + 1):
|
||||
# Store current V for backtracking
|
||||
trace.append(v.duplicate())
|
||||
|
||||
for k in range(-d, d + 1, 2):
|
||||
var k_offset := k + max_d
|
||||
|
||||
# Decide whether to move down or right
|
||||
var x: int
|
||||
if k == -d or (k != d and v[k_offset - 1] < v[k_offset + 1]):
|
||||
x = v[k_offset + 1] # Move down (insert from b)
|
||||
else:
|
||||
x = v[k_offset - 1] + 1 # Move right (delete from a)
|
||||
|
||||
var y := x - k
|
||||
|
||||
# Follow diagonal as far as possible (matching characters)
|
||||
while x < n and y < m and a[x] == b[y]:
|
||||
x += 1
|
||||
y += 1
|
||||
|
||||
v[k_offset] = x
|
||||
|
||||
# Check if we've reached the end
|
||||
if x >= n and y >= m:
|
||||
return _backtrack(a, b, trace, d, max_d)
|
||||
|
||||
# Should never reach here for valid inputs
|
||||
return []
|
||||
|
||||
|
||||
# Backtrack through the edit graph to build the edit script
|
||||
static func _backtrack(a: PackedInt32Array, b: PackedInt32Array, trace: Array, d: int, max_d: int) -> Array[Edit]:
|
||||
var edits: Array[Edit] = []
|
||||
var x := a.size()
|
||||
var y := b.size()
|
||||
|
||||
# Walk backwards through each d value
|
||||
for depth in range(d, -1, -1):
|
||||
var v: PackedInt32Array = trace[depth]
|
||||
var k := x - y
|
||||
var k_offset := k + max_d
|
||||
|
||||
# Determine previous k
|
||||
var prev_k: int
|
||||
if k == -depth or (k != depth and v[k_offset - 1] < v[k_offset + 1]):
|
||||
prev_k = k + 1
|
||||
else:
|
||||
prev_k = k - 1
|
||||
|
||||
var prev_k_offset := prev_k + max_d
|
||||
var prev_x := v[prev_k_offset]
|
||||
var prev_y := prev_x - prev_k
|
||||
|
||||
# Extract diagonal (equal) characters
|
||||
while x > prev_x and y > prev_y:
|
||||
x -= 1
|
||||
y -= 1
|
||||
#var char_array := PackedInt32Array([a[x]])
|
||||
edits.insert(0, Edit.new(Edit.Type.EQUAL, a[x]))
|
||||
|
||||
# Record the edit operation
|
||||
if depth > 0:
|
||||
if x == prev_x:
|
||||
# Insert from b
|
||||
y -= 1
|
||||
#var char_array := PackedInt32Array([b[y]])
|
||||
edits.insert(0, Edit.new(Edit.Type.INSERT, b[y]))
|
||||
else:
|
||||
# Delete from a
|
||||
x -= 1
|
||||
#var char_array := PackedInt32Array([a[x]])
|
||||
edits.insert(0, Edit.new(Edit.Type.DELETE, a[x]))
|
||||
|
||||
return edits
|
||||
|
||||
|
||||
# Convert edit script to the DIV_ADD/DIV_SUB format
|
||||
static func _edits_to_diff_format(edits: Array[Edit]) -> Array[PackedInt32Array]:
|
||||
var ldiff := PackedInt32Array()
|
||||
var rdiff := PackedInt32Array()
|
||||
|
||||
for edit in edits:
|
||||
match edit.type:
|
||||
Edit.Type.EQUAL:
|
||||
ldiff.append(edit.character)
|
||||
rdiff.append(edit.character)
|
||||
Edit.Type.INSERT:
|
||||
ldiff.append(DIV_ADD)
|
||||
ldiff.append(edit.character)
|
||||
rdiff.append(DIV_SUB)
|
||||
rdiff.append(edit.character)
|
||||
Edit.Type.DELETE:
|
||||
ldiff.append(DIV_SUB)
|
||||
ldiff.append(edit.character)
|
||||
rdiff.append(DIV_ADD)
|
||||
rdiff.append(edit.character)
|
||||
|
||||
return [ldiff, rdiff]
|
||||
|
||||
|
||||
# prototype
|
||||
static func longestCommonSubsequence(text1 :String, text2 :String) -> PackedStringArray:
|
||||
var text1Words := text1.split(" ")
|
||||
var text2Words := text2.split(" ")
|
||||
var text1WordCount := text1Words.size()
|
||||
var text2WordCount := text2Words.size()
|
||||
var solutionMatrix := Array()
|
||||
for i in text1WordCount+1:
|
||||
var ar := Array()
|
||||
for n in text2WordCount+1:
|
||||
ar.append(0)
|
||||
solutionMatrix.append(ar)
|
||||
|
||||
for i in range(text1WordCount-1, 0, -1):
|
||||
for j in range(text2WordCount-1, 0, -1):
|
||||
if text1Words[i] == text2Words[j]:
|
||||
solutionMatrix[i][j] = solutionMatrix[i + 1][j + 1] + 1;
|
||||
else:
|
||||
solutionMatrix[i][j] = max(solutionMatrix[i + 1][j], solutionMatrix[i][j + 1]);
|
||||
|
||||
var i := 0
|
||||
var j := 0
|
||||
var lcsResultList := PackedStringArray();
|
||||
while (i < text1WordCount && j < text2WordCount):
|
||||
if text1Words[i] == text2Words[j]:
|
||||
@warning_ignore("return_value_discarded")
|
||||
lcsResultList.append(text2Words[j])
|
||||
i += 1
|
||||
j += 1
|
||||
else: if (solutionMatrix[i + 1][j] >= solutionMatrix[i][j + 1]):
|
||||
i += 1
|
||||
else:
|
||||
j += 1
|
||||
return lcsResultList
|
||||
|
||||
|
||||
static func markTextDifferences(text1 :String, text2 :String, lcsList :PackedStringArray, insertColor :Color, deleteColor:Color) -> String:
|
||||
var stringBuffer := ""
|
||||
if text1 == null and lcsList == null:
|
||||
return stringBuffer
|
||||
|
||||
var text1Words := text1.split(" ")
|
||||
var text2Words := text2.split(" ")
|
||||
var i := 0
|
||||
var j := 0
|
||||
var word1LastIndex := 0
|
||||
var word2LastIndex := 0
|
||||
for k in lcsList.size():
|
||||
while i < text1Words.size() and j < text2Words.size():
|
||||
if text1Words[i] == lcsList[k] and text2Words[j] == lcsList[k]:
|
||||
stringBuffer += "<SPAN>" + lcsList[k] + " </SPAN>"
|
||||
word1LastIndex = i + 1
|
||||
word2LastIndex = j + 1
|
||||
i = text1Words.size()
|
||||
j = text2Words.size()
|
||||
|
||||
else: if text1Words[i] != lcsList[k]:
|
||||
while i < text1Words.size() and text1Words[i] != lcsList[k]:
|
||||
stringBuffer += "<SPAN style='BACKGROUND-COLOR:" + deleteColor.to_html() + "'>" + text1Words[i] + " </SPAN>"
|
||||
i += 1
|
||||
else: if text2Words[j] != lcsList[k]:
|
||||
while j < text2Words.size() and text2Words[j] != lcsList[k]:
|
||||
stringBuffer += "<SPAN style='BACKGROUND-COLOR:" + insertColor.to_html() + "'>" + text2Words[j] + " </SPAN>"
|
||||
j += 1
|
||||
i = word1LastIndex
|
||||
j = word2LastIndex
|
||||
|
||||
while word1LastIndex < text1Words.size():
|
||||
stringBuffer += "<SPAN style='BACKGROUND-COLOR:" + deleteColor.to_html() + "'>" + text1Words[word1LastIndex] + " </SPAN>"
|
||||
word1LastIndex += 1
|
||||
while word2LastIndex < text2Words.size():
|
||||
stringBuffer += "<SPAN style='BACKGROUND-COLOR:" + insertColor.to_html() + "'>" + text2Words[word2LastIndex] + " </SPAN>"
|
||||
word2LastIndex += 1
|
||||
return stringBuffer
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://b5sli0lem5xca
|
||||
|
||||
@@ -0,0 +1,726 @@
|
||||
# This is a helper class to compare two objects by equals
|
||||
class_name GdObjects
|
||||
extends Resource
|
||||
|
||||
const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd")
|
||||
|
||||
|
||||
# introduced with Godot 4.3.beta1
|
||||
const TYPE_VOID = 1000
|
||||
const TYPE_VARARG = 1001
|
||||
const TYPE_VARIANT = 1002
|
||||
const TYPE_FUNC = 1003
|
||||
const TYPE_FUZZER = 1004
|
||||
# missing Godot types
|
||||
const TYPE_NODE = 2001
|
||||
const TYPE_CONTROL = 2002
|
||||
const TYPE_CANVAS = 2003
|
||||
const TYPE_ENUM = 2004
|
||||
|
||||
|
||||
const TYPE_AS_STRING_MAPPINGS := {
|
||||
TYPE_NIL: "null",
|
||||
TYPE_BOOL: "bool",
|
||||
TYPE_INT: "int",
|
||||
TYPE_FLOAT: "float",
|
||||
TYPE_STRING: "String",
|
||||
TYPE_VECTOR2: "Vector2",
|
||||
TYPE_VECTOR2I: "Vector2i",
|
||||
TYPE_RECT2: "Rect2",
|
||||
TYPE_RECT2I: "Rect2i",
|
||||
TYPE_VECTOR3: "Vector3",
|
||||
TYPE_VECTOR3I: "Vector3i",
|
||||
TYPE_TRANSFORM2D: "Transform2D",
|
||||
TYPE_VECTOR4: "Vector4",
|
||||
TYPE_VECTOR4I: "Vector4i",
|
||||
TYPE_PLANE: "Plane",
|
||||
TYPE_QUATERNION: "Quaternion",
|
||||
TYPE_AABB: "AABB",
|
||||
TYPE_BASIS: "Basis",
|
||||
TYPE_TRANSFORM3D: "Transform3D",
|
||||
TYPE_PROJECTION: "Projection",
|
||||
TYPE_COLOR: "Color",
|
||||
TYPE_STRING_NAME: "StringName",
|
||||
TYPE_NODE_PATH: "NodePath",
|
||||
TYPE_RID: "RID",
|
||||
TYPE_OBJECT: "Object",
|
||||
TYPE_CALLABLE: "Callable",
|
||||
TYPE_SIGNAL: "Signal",
|
||||
TYPE_DICTIONARY: "Dictionary",
|
||||
TYPE_ARRAY: "Array",
|
||||
TYPE_PACKED_BYTE_ARRAY: "PackedByteArray",
|
||||
TYPE_PACKED_INT32_ARRAY: "PackedInt32Array",
|
||||
TYPE_PACKED_INT64_ARRAY: "PackedInt64Array",
|
||||
TYPE_PACKED_FLOAT32_ARRAY: "PackedFloat32Array",
|
||||
TYPE_PACKED_FLOAT64_ARRAY: "PackedFloat64Array",
|
||||
TYPE_PACKED_STRING_ARRAY: "PackedStringArray",
|
||||
TYPE_PACKED_VECTOR2_ARRAY: "PackedVector2Array",
|
||||
TYPE_PACKED_VECTOR3_ARRAY: "PackedVector3Array",
|
||||
TYPE_PACKED_VECTOR4_ARRAY: "PackedVector4Array",
|
||||
TYPE_PACKED_COLOR_ARRAY: "PackedColorArray",
|
||||
TYPE_VOID: "void",
|
||||
TYPE_VARARG: "VarArg",
|
||||
TYPE_FUNC: "Func",
|
||||
TYPE_FUZZER: "Fuzzer",
|
||||
TYPE_VARIANT: "Variant"
|
||||
}
|
||||
|
||||
|
||||
class EditorNotifications:
|
||||
# NOTE: Hardcoding to avoid runtime errors in exported projects when editor
|
||||
# classes are not available. These values are unlikely to change.
|
||||
# See: EditorSettings.NOTIFICATION_EDITOR_SETTINGS_CHANGED
|
||||
const NOTIFICATION_EDITOR_SETTINGS_CHANGED := 10000
|
||||
|
||||
|
||||
const NOTIFICATION_AS_STRING_MAPPINGS := {
|
||||
TYPE_OBJECT: {
|
||||
Object.NOTIFICATION_POSTINITIALIZE : "POSTINITIALIZE",
|
||||
Object.NOTIFICATION_PREDELETE: "PREDELETE",
|
||||
EditorNotifications.NOTIFICATION_EDITOR_SETTINGS_CHANGED: "EDITOR_SETTINGS_CHANGED",
|
||||
},
|
||||
TYPE_NODE: {
|
||||
Node.NOTIFICATION_ENTER_TREE : "ENTER_TREE",
|
||||
Node.NOTIFICATION_EXIT_TREE: "EXIT_TREE",
|
||||
Node.NOTIFICATION_CHILD_ORDER_CHANGED: "CHILD_ORDER_CHANGED",
|
||||
Node.NOTIFICATION_READY: "READY",
|
||||
Node.NOTIFICATION_PAUSED: "PAUSED",
|
||||
Node.NOTIFICATION_UNPAUSED: "UNPAUSED",
|
||||
Node.NOTIFICATION_PHYSICS_PROCESS: "PHYSICS_PROCESS",
|
||||
Node.NOTIFICATION_PROCESS: "PROCESS",
|
||||
Node.NOTIFICATION_PARENTED: "PARENTED",
|
||||
Node.NOTIFICATION_UNPARENTED: "UNPARENTED",
|
||||
Node.NOTIFICATION_SCENE_INSTANTIATED: "INSTANCED",
|
||||
Node.NOTIFICATION_DRAG_BEGIN: "DRAG_BEGIN",
|
||||
Node.NOTIFICATION_DRAG_END: "DRAG_END",
|
||||
Node.NOTIFICATION_PATH_RENAMED: "PATH_CHANGED",
|
||||
Node.NOTIFICATION_INTERNAL_PROCESS: "INTERNAL_PROCESS",
|
||||
Node.NOTIFICATION_INTERNAL_PHYSICS_PROCESS: "INTERNAL_PHYSICS_PROCESS",
|
||||
Node.NOTIFICATION_POST_ENTER_TREE: "POST_ENTER_TREE",
|
||||
Node.NOTIFICATION_WM_MOUSE_ENTER: "WM_MOUSE_ENTER",
|
||||
Node.NOTIFICATION_WM_MOUSE_EXIT: "WM_MOUSE_EXIT",
|
||||
Node.NOTIFICATION_APPLICATION_FOCUS_IN: "WM_FOCUS_IN",
|
||||
Node.NOTIFICATION_APPLICATION_FOCUS_OUT: "WM_FOCUS_OUT",
|
||||
#Node.NOTIFICATION_WM_QUIT_REQUEST: "WM_QUIT_REQUEST",
|
||||
Node.NOTIFICATION_WM_GO_BACK_REQUEST: "WM_GO_BACK_REQUEST",
|
||||
Node.NOTIFICATION_WM_WINDOW_FOCUS_OUT: "WM_UNFOCUS_REQUEST",
|
||||
Node.NOTIFICATION_OS_MEMORY_WARNING: "OS_MEMORY_WARNING",
|
||||
Node.NOTIFICATION_TRANSLATION_CHANGED: "TRANSLATION_CHANGED",
|
||||
Node.NOTIFICATION_WM_ABOUT: "WM_ABOUT",
|
||||
Node.NOTIFICATION_CRASH: "CRASH",
|
||||
Node.NOTIFICATION_OS_IME_UPDATE: "OS_IME_UPDATE",
|
||||
Node.NOTIFICATION_APPLICATION_RESUMED: "APP_RESUMED",
|
||||
Node.NOTIFICATION_APPLICATION_PAUSED: "APP_PAUSED",
|
||||
Node3D.NOTIFICATION_TRANSFORM_CHANGED: "TRANSFORM_CHANGED",
|
||||
Node3D.NOTIFICATION_ENTER_WORLD: "ENTER_WORLD",
|
||||
Node3D.NOTIFICATION_EXIT_WORLD: "EXIT_WORLD",
|
||||
Node3D.NOTIFICATION_VISIBILITY_CHANGED: "VISIBILITY_CHANGED",
|
||||
Skeleton3D.NOTIFICATION_UPDATE_SKELETON: "UPDATE_SKELETON",
|
||||
CanvasItem.NOTIFICATION_DRAW: "DRAW",
|
||||
CanvasItem.NOTIFICATION_VISIBILITY_CHANGED: "VISIBILITY_CHANGED",
|
||||
CanvasItem.NOTIFICATION_ENTER_CANVAS: "ENTER_CANVAS",
|
||||
CanvasItem.NOTIFICATION_EXIT_CANVAS: "EXIT_CANVAS",
|
||||
#Popup.NOTIFICATION_POST_POPUP: "POST_POPUP",
|
||||
#Popup.NOTIFICATION_POPUP_HIDE: "POPUP_HIDE",
|
||||
},
|
||||
TYPE_CONTROL : {
|
||||
Object.NOTIFICATION_PREDELETE: "PREDELETE",
|
||||
Container.NOTIFICATION_SORT_CHILDREN: "SORT_CHILDREN",
|
||||
Control.NOTIFICATION_RESIZED: "RESIZED",
|
||||
Control.NOTIFICATION_MOUSE_ENTER: "MOUSE_ENTER",
|
||||
Control.NOTIFICATION_MOUSE_EXIT: "MOUSE_EXIT",
|
||||
Control.NOTIFICATION_FOCUS_ENTER: "FOCUS_ENTER",
|
||||
Control.NOTIFICATION_FOCUS_EXIT: "FOCUS_EXIT",
|
||||
Control.NOTIFICATION_THEME_CHANGED: "THEME_CHANGED",
|
||||
#Control.NOTIFICATION_MODAL_CLOSE: "MODAL_CLOSE",
|
||||
Control.NOTIFICATION_SCROLL_BEGIN: "SCROLL_BEGIN",
|
||||
Control.NOTIFICATION_SCROLL_END: "SCROLL_END",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum COMPARE_MODE {
|
||||
OBJECT_REFERENCE,
|
||||
PARAMETER_DEEP_TEST
|
||||
}
|
||||
|
||||
|
||||
# prototype of better object to dictionary
|
||||
static func obj2dict(obj: Object, hashed_objects := Dictionary()) -> Dictionary:
|
||||
if obj == null:
|
||||
return {}
|
||||
var clazz_name := obj.get_class()
|
||||
var dict := Dictionary()
|
||||
var clazz_path := ""
|
||||
|
||||
if is_instance_valid(obj) and obj.get_script() != null:
|
||||
var script: Script = obj.get_script()
|
||||
# handle build-in scripts
|
||||
if script.resource_path != null and script.resource_path.contains(".tscn"):
|
||||
var path_elements := script.resource_path.split(".tscn")
|
||||
clazz_name = path_elements[0].get_file()
|
||||
clazz_path = script.resource_path
|
||||
else:
|
||||
var d := inst_to_dict(obj)
|
||||
clazz_path = d["@path"]
|
||||
if d["@subpath"] != NodePath(""):
|
||||
clazz_name = d["@subpath"]
|
||||
dict["@inner_class"] = true
|
||||
else:
|
||||
clazz_name = clazz_path.get_file().replace(".gd", "")
|
||||
dict["@path"] = clazz_path
|
||||
|
||||
for property in obj.get_property_list():
|
||||
var property_name :String = property["name"]
|
||||
var property_type :int = property["type"]
|
||||
var property_value :Variant = obj.get(property_name)
|
||||
if property_value is GDScript or property_value is Callable or property_value is RegEx:
|
||||
continue
|
||||
if (property["usage"] & PROPERTY_USAGE_SCRIPT_VARIABLE|PROPERTY_USAGE_DEFAULT
|
||||
and not property["usage"] & PROPERTY_USAGE_CATEGORY
|
||||
and not property["usage"] == 0):
|
||||
if property_type == TYPE_OBJECT:
|
||||
# prevent recursion
|
||||
if hashed_objects.has(obj):
|
||||
dict[property_name] = str(property_value)
|
||||
continue
|
||||
hashed_objects[obj] = true
|
||||
@warning_ignore("unsafe_cast")
|
||||
dict[property_name] = obj2dict(property_value as Object, hashed_objects)
|
||||
else:
|
||||
dict[property_name] = property_value
|
||||
if obj is Node:
|
||||
var childrens :Array = (obj as Node).get_children()
|
||||
dict["childrens"] = childrens.map(func (child :Object) -> Dictionary: return obj2dict(child, hashed_objects))
|
||||
if obj is TreeItem:
|
||||
var childrens :Array = (obj as TreeItem).get_children()
|
||||
dict["childrens"] = childrens.map(func (child :Object) -> Dictionary: return obj2dict(child, hashed_objects))
|
||||
|
||||
return {"%s" % clazz_name : dict}
|
||||
|
||||
|
||||
static func equals(obj_a :Variant, obj_b :Variant, case_sensitive :bool = false, compare_mode :COMPARE_MODE = COMPARE_MODE.PARAMETER_DEEP_TEST) -> bool:
|
||||
return _equals(obj_a, obj_b, case_sensitive, compare_mode, [], 0)
|
||||
|
||||
|
||||
static func equals_sorted(obj_a: Array[Variant], obj_b: Array[Variant], case_sensitive: bool = false, compare_mode: COMPARE_MODE = COMPARE_MODE.PARAMETER_DEEP_TEST) -> bool:
|
||||
var a: Array[Variant] = obj_a.duplicate()
|
||||
var b: Array[Variant] = obj_b.duplicate()
|
||||
a.sort()
|
||||
b.sort()
|
||||
return equals(a, b, case_sensitive, compare_mode)
|
||||
|
||||
|
||||
static func _equals(obj_a :Variant, obj_b :Variant, case_sensitive :bool, compare_mode :COMPARE_MODE, deep_stack :Array, stack_depth :int ) -> bool:
|
||||
var type_a := typeof(obj_a)
|
||||
var type_b := typeof(obj_b)
|
||||
if stack_depth > 32:
|
||||
prints("stack_depth", stack_depth, deep_stack)
|
||||
push_error("GdUnit equals has max stack deep reached!")
|
||||
return false
|
||||
|
||||
# use argument matcher if requested
|
||||
if is_instance_valid(obj_a) and obj_a is GdUnitArgumentMatcher:
|
||||
@warning_ignore("unsafe_cast")
|
||||
return (obj_a as GdUnitArgumentMatcher).is_match(obj_b)
|
||||
if is_instance_valid(obj_b) and obj_b is GdUnitArgumentMatcher:
|
||||
@warning_ignore("unsafe_cast")
|
||||
return (obj_b as GdUnitArgumentMatcher).is_match(obj_a)
|
||||
|
||||
stack_depth += 1
|
||||
# fast fail is different types
|
||||
if not _is_type_equivalent(type_a, type_b):
|
||||
return false
|
||||
# is same instance
|
||||
if obj_a == obj_b:
|
||||
return true
|
||||
# handle null values
|
||||
if obj_a == null and obj_b != null:
|
||||
return false
|
||||
if obj_b == null and obj_a != null:
|
||||
return false
|
||||
|
||||
match type_a:
|
||||
TYPE_OBJECT:
|
||||
if deep_stack.has(obj_a) or deep_stack.has(obj_b):
|
||||
return true
|
||||
deep_stack.append(obj_a)
|
||||
deep_stack.append(obj_b)
|
||||
if compare_mode == COMPARE_MODE.PARAMETER_DEEP_TEST:
|
||||
# fail fast
|
||||
if not is_instance_valid(obj_a) or not is_instance_valid(obj_b):
|
||||
return false
|
||||
@warning_ignore("unsafe_method_access")
|
||||
if obj_a.get_class() != obj_b.get_class():
|
||||
return false
|
||||
@warning_ignore("unsafe_cast")
|
||||
var a := obj2dict(obj_a as Object)
|
||||
@warning_ignore("unsafe_cast")
|
||||
var b := obj2dict(obj_b as Object)
|
||||
return _equals(a, b, case_sensitive, compare_mode, deep_stack, stack_depth)
|
||||
return obj_a == obj_b
|
||||
|
||||
TYPE_ARRAY:
|
||||
@warning_ignore("unsafe_method_access")
|
||||
if obj_a.size() != obj_b.size():
|
||||
return false
|
||||
@warning_ignore("unsafe_method_access")
|
||||
for index :int in obj_a.size():
|
||||
if not _equals(obj_a[index], obj_b[index], case_sensitive, compare_mode, deep_stack, stack_depth):
|
||||
return false
|
||||
return true
|
||||
|
||||
TYPE_DICTIONARY:
|
||||
@warning_ignore("unsafe_method_access")
|
||||
if obj_a.size() != obj_b.size():
|
||||
return false
|
||||
@warning_ignore("unsafe_method_access")
|
||||
for key :Variant in obj_a.keys():
|
||||
@warning_ignore("unsafe_method_access")
|
||||
var value_a :Variant = obj_a[key] if obj_a.has(key) else null
|
||||
@warning_ignore("unsafe_method_access")
|
||||
var value_b :Variant = obj_b[key] if obj_b.has(key) else null
|
||||
if not _equals(value_a, value_b, case_sensitive, compare_mode, deep_stack, stack_depth):
|
||||
return false
|
||||
return true
|
||||
|
||||
TYPE_STRING:
|
||||
if case_sensitive:
|
||||
@warning_ignore("unsafe_method_access")
|
||||
return obj_a.to_lower() == obj_b.to_lower()
|
||||
else:
|
||||
return obj_a == obj_b
|
||||
return obj_a == obj_b
|
||||
|
||||
|
||||
@warning_ignore("shadowed_variable_base_class")
|
||||
static func notification_as_string(instance :Variant, notification :int) -> String:
|
||||
var error := "Unknown notification: '%s' at instance: %s" % [notification, instance]
|
||||
if instance is Node and NOTIFICATION_AS_STRING_MAPPINGS[TYPE_NODE].has(notification):
|
||||
return NOTIFICATION_AS_STRING_MAPPINGS[TYPE_NODE].get(notification, error)
|
||||
if instance is Control and NOTIFICATION_AS_STRING_MAPPINGS[TYPE_CONTROL].has(notification):
|
||||
return NOTIFICATION_AS_STRING_MAPPINGS[TYPE_CONTROL].get(notification, error)
|
||||
return NOTIFICATION_AS_STRING_MAPPINGS[TYPE_OBJECT].get(notification, error)
|
||||
|
||||
|
||||
static func string_to_type(value :String) -> int:
|
||||
for type :int in TYPE_AS_STRING_MAPPINGS.keys():
|
||||
if TYPE_AS_STRING_MAPPINGS.get(type) == value:
|
||||
return type
|
||||
return TYPE_NIL
|
||||
|
||||
|
||||
static func to_camel_case(value :String) -> String:
|
||||
var p := to_pascal_case(value)
|
||||
if not p.is_empty():
|
||||
p[0] = p[0].to_lower()
|
||||
return p
|
||||
|
||||
|
||||
static func to_pascal_case(value :String) -> String:
|
||||
return value.capitalize().replace(" ", "")
|
||||
|
||||
|
||||
@warning_ignore("return_value_discarded")
|
||||
static func to_snake_case(value :String) -> String:
|
||||
var result := PackedStringArray()
|
||||
for ch in value:
|
||||
var lower_ch := ch.to_lower()
|
||||
if ch != lower_ch and result.size() > 1:
|
||||
result.append('_')
|
||||
result.append(lower_ch)
|
||||
return ''.join(result)
|
||||
|
||||
|
||||
static func is_snake_case(value :String) -> bool:
|
||||
for ch in value:
|
||||
if ch == '_':
|
||||
continue
|
||||
if ch == ch.to_upper():
|
||||
return false
|
||||
return true
|
||||
|
||||
|
||||
static func type_as_string(type :int) -> String:
|
||||
if type < TYPE_MAX:
|
||||
return type_string(type)
|
||||
return TYPE_AS_STRING_MAPPINGS.get(type, "Variant")
|
||||
|
||||
|
||||
static func typeof_as_string(value :Variant) -> String:
|
||||
return TYPE_AS_STRING_MAPPINGS.get(typeof(value), "Unknown type")
|
||||
|
||||
|
||||
static func all_types() -> PackedInt32Array:
|
||||
return PackedInt32Array(TYPE_AS_STRING_MAPPINGS.keys())
|
||||
|
||||
|
||||
static func string_as_typeof(type_name :String) -> int:
|
||||
var type :Variant = TYPE_AS_STRING_MAPPINGS.find_key(type_name)
|
||||
return type if type != null else TYPE_VARIANT
|
||||
|
||||
|
||||
static func is_primitive_type(value :Variant) -> bool:
|
||||
return typeof(value) in [TYPE_BOOL, TYPE_STRING, TYPE_STRING_NAME, TYPE_INT, TYPE_FLOAT]
|
||||
|
||||
|
||||
static func _is_type_equivalent(type_a :int, type_b :int) -> bool:
|
||||
# don't test for TYPE_STRING_NAME equivalenz
|
||||
if type_a == TYPE_STRING_NAME or type_b == TYPE_STRING_NAME:
|
||||
return true
|
||||
if GdUnitSettings.is_strict_number_type_compare():
|
||||
return type_a == type_b
|
||||
return (
|
||||
(type_a == TYPE_FLOAT and type_b == TYPE_INT)
|
||||
or (type_a == TYPE_INT and type_b == TYPE_FLOAT)
|
||||
or type_a == type_b)
|
||||
|
||||
|
||||
static func is_engine_type(value :Variant) -> bool:
|
||||
if value is GDScript or value is ScriptExtension:
|
||||
return false
|
||||
var obj: Object = value
|
||||
if is_instance_valid(obj) and obj.has_method("is_class"):
|
||||
return obj.is_class("GDScriptNativeClass")
|
||||
return false
|
||||
|
||||
|
||||
static func is_type(value :Variant) -> bool:
|
||||
# is an build-in type
|
||||
if typeof(value) != TYPE_OBJECT:
|
||||
return false
|
||||
# is a engine class type
|
||||
if is_engine_type(value):
|
||||
return true
|
||||
# is a custom class type
|
||||
@warning_ignore("unsafe_cast")
|
||||
if value is GDScript and (value as GDScript).can_instantiate():
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
static func _is_same(left :Variant, right :Variant) -> bool:
|
||||
var left_type := -1 if left == null else typeof(left)
|
||||
var right_type := -1 if right == null else typeof(right)
|
||||
|
||||
# if typ different can't be the same
|
||||
if left_type != right_type:
|
||||
return false
|
||||
if left_type == TYPE_OBJECT and right_type == TYPE_OBJECT:
|
||||
@warning_ignore("unsafe_cast")
|
||||
return (left as Object).get_instance_id() == (right as Object).get_instance_id()
|
||||
return equals(left, right)
|
||||
|
||||
|
||||
static func is_object(value :Variant) -> bool:
|
||||
return typeof(value) == TYPE_OBJECT
|
||||
|
||||
|
||||
static func is_script(value :Variant) -> bool:
|
||||
return is_object(value) and value is Script
|
||||
|
||||
|
||||
static func is_native_class(value :Variant) -> bool:
|
||||
return is_object(value) and is_engine_type(value)
|
||||
|
||||
|
||||
static func is_scene(value :Variant) -> bool:
|
||||
return is_object(value) and value is PackedScene
|
||||
|
||||
|
||||
static func is_scene_resource_path(value :Variant) -> bool:
|
||||
@warning_ignore("unsafe_cast")
|
||||
return value is String and (value as String).ends_with(".tscn")
|
||||
|
||||
|
||||
static func is_singleton(value: Variant) -> bool:
|
||||
if not is_instance_valid(value) or is_native_class(value):
|
||||
return false
|
||||
for name in Engine.get_singleton_list():
|
||||
@warning_ignore("unsafe_cast")
|
||||
if (value as Object).is_class(name):
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
static func is_instance(value :Variant) -> bool:
|
||||
if not is_instance_valid(value) or is_native_class(value):
|
||||
return false
|
||||
@warning_ignore("unsafe_cast")
|
||||
if is_script(value) and (value as Script).get_instance_base_type() == "":
|
||||
return true
|
||||
if is_scene(value):
|
||||
return true
|
||||
@warning_ignore("unsafe_cast")
|
||||
return not (value as Object).has_method('new') and not (value as Object).has_method('instance')
|
||||
|
||||
|
||||
# only object form type Node and attached filename
|
||||
static func is_instance_scene(instance :Variant) -> bool:
|
||||
if instance is Node:
|
||||
var node: Node = instance
|
||||
return node.get_scene_file_path() != null and not node.get_scene_file_path().is_empty()
|
||||
return false
|
||||
|
||||
|
||||
static func can_be_instantiate(obj :Variant) -> bool:
|
||||
if not obj or is_engine_type(obj):
|
||||
return false
|
||||
@warning_ignore("unsafe_cast")
|
||||
return (obj as Object).has_method("new")
|
||||
|
||||
|
||||
static func create_instance(clazz :Variant) -> GdUnitResult:
|
||||
match typeof(clazz):
|
||||
TYPE_OBJECT:
|
||||
# test is given clazz already an instance
|
||||
if is_instance(clazz):
|
||||
return GdUnitResult.success(clazz)
|
||||
@warning_ignore("unsafe_method_access")
|
||||
return GdUnitResult.success(clazz.new())
|
||||
TYPE_STRING:
|
||||
var clazz_name: String = clazz
|
||||
if ClassDB.class_exists(clazz_name):
|
||||
if Engine.has_singleton(clazz_name):
|
||||
return GdUnitResult.error("Not allowed to create a instance for singelton '%s'." % clazz_name)
|
||||
if not ClassDB.can_instantiate(clazz_name):
|
||||
return GdUnitResult.error("Can't instance Engine class '%s'." % clazz_name)
|
||||
return GdUnitResult.success(ClassDB.instantiate(clazz_name))
|
||||
else:
|
||||
var clazz_path :String = extract_class_path(clazz_name)[0]
|
||||
if not FileAccess.file_exists(clazz_path):
|
||||
return GdUnitResult.error("Class '%s' not found." % clazz_name)
|
||||
var script: GDScript = load(clazz_path)
|
||||
if script != null:
|
||||
return GdUnitResult.success(script.new())
|
||||
else:
|
||||
return GdUnitResult.error("Can't create instance for '%s'." % clazz_name)
|
||||
return GdUnitResult.error("Can't create instance for class '%s'." % str(clazz))
|
||||
|
||||
|
||||
## We do dispose 'GDScriptFunctionState' in a kacky style because the class is not visible anymore
|
||||
static func dispose_function_state(func_state: Variant) -> void:
|
||||
if func_state != null and str(func_state).contains("GDScriptFunctionState"):
|
||||
@warning_ignore("unsafe_method_access")
|
||||
func_state.completed.emit()
|
||||
|
||||
|
||||
@warning_ignore("return_value_discarded")
|
||||
static func extract_class_path(clazz :Variant) -> PackedStringArray:
|
||||
var clazz_path := PackedStringArray()
|
||||
if clazz is String:
|
||||
@warning_ignore("unsafe_cast")
|
||||
clazz_path.append(clazz as String)
|
||||
return clazz_path
|
||||
if is_instance(clazz):
|
||||
# is instance a script instance?
|
||||
var script: GDScript = clazz.script
|
||||
if script != null:
|
||||
return extract_class_path(script)
|
||||
return clazz_path
|
||||
|
||||
if clazz is GDScript:
|
||||
var script: GDScript = clazz
|
||||
if not script.resource_path.is_empty():
|
||||
clazz_path.append(script.resource_path)
|
||||
return clazz_path
|
||||
# if not found we go the expensive way and extract the path form the script by creating an instance
|
||||
var arg_list := build_function_default_arguments(script, "_init")
|
||||
var instance: Object = script.callv("new", arg_list)
|
||||
var clazz_info := inst_to_dict(instance)
|
||||
GdUnitTools.free_instance(instance)
|
||||
@warning_ignore("unsafe_cast")
|
||||
clazz_path.append(clazz_info["@path"] as String)
|
||||
if clazz_info.has("@subpath"):
|
||||
var sub_path :String = clazz_info["@subpath"]
|
||||
if not sub_path.is_empty():
|
||||
var sub_paths := sub_path.split("/")
|
||||
clazz_path += sub_paths
|
||||
return clazz_path
|
||||
return clazz_path
|
||||
|
||||
|
||||
static func extract_class_name_from_class_path(clazz_path :PackedStringArray) -> String:
|
||||
var base_clazz := clazz_path[0]
|
||||
# return original class name if engine class
|
||||
if ClassDB.class_exists(base_clazz):
|
||||
return base_clazz
|
||||
var clazz_name := to_pascal_case(base_clazz.get_basename().get_file())
|
||||
for path_index in range(1, clazz_path.size()):
|
||||
clazz_name += "." + clazz_path[path_index]
|
||||
return clazz_name
|
||||
|
||||
|
||||
static func extract_class_name(clazz :Variant) -> GdUnitResult:
|
||||
if clazz == null:
|
||||
return GdUnitResult.error("Can't extract class name form a null value.")
|
||||
|
||||
if is_instance(clazz):
|
||||
# is instance a script instance?
|
||||
var script: GDScript = clazz.script
|
||||
if script != null:
|
||||
return extract_class_name(script)
|
||||
@warning_ignore("unsafe_cast")
|
||||
return GdUnitResult.success((clazz as Object).get_class())
|
||||
|
||||
# extract name form full qualified class path
|
||||
if clazz is String:
|
||||
var clazz_name: String = clazz
|
||||
if ClassDB.class_exists(clazz_name):
|
||||
return GdUnitResult.success(clazz_name)
|
||||
var source_script :GDScript = load(clazz_name)
|
||||
clazz_name = GdScriptParser.new().get_class_name(source_script)
|
||||
return GdUnitResult.success(to_pascal_case(clazz_name))
|
||||
|
||||
if is_primitive_type(clazz):
|
||||
return GdUnitResult.error("Can't extract class name for an primitive '%s'" % type_as_string(typeof(clazz)))
|
||||
|
||||
if is_script(clazz):
|
||||
@warning_ignore("unsafe_cast")
|
||||
if (clazz as Script).resource_path.is_empty():
|
||||
var class_path := extract_class_name_from_class_path(extract_class_path(clazz))
|
||||
return GdUnitResult.success(class_path);
|
||||
return extract_class_name(clazz.resource_path)
|
||||
|
||||
# need to create an instance for a class typ the extract the class name
|
||||
@warning_ignore("unsafe_method_access")
|
||||
var instance :Variant = clazz.new()
|
||||
if instance == null:
|
||||
return GdUnitResult.error("Can't create a instance for class '%s'" % str(clazz))
|
||||
var result := extract_class_name(instance)
|
||||
@warning_ignore("return_value_discarded")
|
||||
GdUnitTools.free_instance(instance)
|
||||
return result
|
||||
|
||||
|
||||
static func extract_inner_clazz_names(clazz_name :String, script_path :PackedStringArray) -> PackedStringArray:
|
||||
var inner_classes := PackedStringArray()
|
||||
|
||||
if ClassDB.class_exists(clazz_name):
|
||||
return inner_classes
|
||||
var script :GDScript = load(script_path[0])
|
||||
var map := script.get_script_constant_map()
|
||||
for key :String in map.keys():
|
||||
var value :Variant = map.get(key)
|
||||
if value is GDScript:
|
||||
var class_path := extract_class_path(value)
|
||||
@warning_ignore("return_value_discarded")
|
||||
inner_classes.append(class_path[1])
|
||||
return inner_classes
|
||||
|
||||
|
||||
static func extract_class_functions(clazz_name :String, script_path :PackedStringArray) -> Array:
|
||||
if ClassDB.class_get_method_list(clazz_name):
|
||||
return ClassDB.class_get_method_list(clazz_name)
|
||||
|
||||
if not FileAccess.file_exists(script_path[0]):
|
||||
return Array()
|
||||
var script :GDScript = load(script_path[0])
|
||||
if script is GDScript:
|
||||
# if inner class on class path we have to load the script from the script_constant_map
|
||||
if script_path.size() == 2 and script_path[1] != "":
|
||||
var inner_classes := script_path[1]
|
||||
var map := script.get_script_constant_map()
|
||||
script = map[inner_classes]
|
||||
var clazz_functions :Array = script.get_method_list()
|
||||
var base_clazz :String = script.get_instance_base_type()
|
||||
if base_clazz:
|
||||
return extract_class_functions(base_clazz, script_path)
|
||||
return clazz_functions
|
||||
return Array()
|
||||
|
||||
|
||||
# scans all registert script classes for given <clazz_name>
|
||||
# if the class is public in the global space than return true otherwise false
|
||||
# public class means the script class is defined by 'class_name <name>'
|
||||
static func is_public_script_class(clazz_name :String) -> bool:
|
||||
var script_classes:Array[Dictionary] = ProjectSettings.get_global_class_list()
|
||||
for class_info in script_classes:
|
||||
if class_info.has("class"):
|
||||
if class_info["class"] == clazz_name:
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
static func build_function_default_arguments(script :GDScript, func_name :String) -> Array:
|
||||
var arg_list := Array()
|
||||
for func_sig in script.get_script_method_list():
|
||||
if func_sig["name"] == func_name:
|
||||
var args :Array[Dictionary] = func_sig["args"]
|
||||
for arg in args:
|
||||
var value_type :int = arg["type"]
|
||||
var default_value :Variant = default_value_by_type(value_type)
|
||||
arg_list.append(default_value)
|
||||
return arg_list
|
||||
return arg_list
|
||||
|
||||
|
||||
static func default_value_by_type(type :int) -> Variant:
|
||||
assert(type < TYPE_MAX)
|
||||
assert(type >= 0)
|
||||
|
||||
match type:
|
||||
TYPE_NIL: return null
|
||||
TYPE_BOOL: return false
|
||||
TYPE_INT: return 0
|
||||
TYPE_FLOAT: return 0.0
|
||||
TYPE_STRING: return ""
|
||||
TYPE_VECTOR2: return Vector2.ZERO
|
||||
TYPE_VECTOR2I: return Vector2i.ZERO
|
||||
TYPE_VECTOR3: return Vector3.ZERO
|
||||
TYPE_VECTOR3I: return Vector3i.ZERO
|
||||
TYPE_VECTOR4: return Vector4.ZERO
|
||||
TYPE_VECTOR4I: return Vector4i.ZERO
|
||||
TYPE_RECT2: return Rect2()
|
||||
TYPE_RECT2I: return Rect2i()
|
||||
TYPE_TRANSFORM2D: return Transform2D()
|
||||
TYPE_PLANE: return Plane()
|
||||
TYPE_QUATERNION: return Quaternion()
|
||||
TYPE_AABB: return AABB()
|
||||
TYPE_BASIS: return Basis()
|
||||
TYPE_TRANSFORM3D: return Transform3D()
|
||||
TYPE_COLOR: return Color()
|
||||
TYPE_NODE_PATH: return NodePath()
|
||||
TYPE_RID: return RID()
|
||||
TYPE_OBJECT: return null
|
||||
TYPE_CALLABLE: return Callable()
|
||||
TYPE_ARRAY: return []
|
||||
TYPE_DICTIONARY: return {}
|
||||
TYPE_PACKED_BYTE_ARRAY: return PackedByteArray()
|
||||
TYPE_PACKED_COLOR_ARRAY: return PackedColorArray()
|
||||
TYPE_PACKED_INT32_ARRAY: return PackedInt32Array()
|
||||
TYPE_PACKED_INT64_ARRAY: return PackedInt64Array()
|
||||
TYPE_PACKED_FLOAT32_ARRAY: return PackedFloat32Array()
|
||||
TYPE_PACKED_FLOAT64_ARRAY: return PackedFloat64Array()
|
||||
TYPE_PACKED_STRING_ARRAY: return PackedStringArray()
|
||||
TYPE_PACKED_VECTOR2_ARRAY: return PackedVector2Array()
|
||||
TYPE_PACKED_VECTOR3_ARRAY: return PackedVector3Array()
|
||||
|
||||
push_error("Can't determine a default value for type: '%s', Please create a Bug issue and attach the stacktrace please." % type)
|
||||
return null
|
||||
|
||||
|
||||
static func find_nodes_by_class(root: Node, cls: String, recursive: bool = false) -> Array[Node]:
|
||||
if not recursive:
|
||||
return _find_nodes_by_class_no_rec(root, cls)
|
||||
return _find_nodes_by_class(root, cls)
|
||||
|
||||
|
||||
static func _find_nodes_by_class_no_rec(parent: Node, cls: String) -> Array[Node]:
|
||||
var result :Array[Node] = []
|
||||
for ch in parent.get_children():
|
||||
if ch.get_class() == cls:
|
||||
result.append(ch)
|
||||
return result
|
||||
|
||||
|
||||
static func _find_nodes_by_class(root: Node, cls: String) -> Array[Node]:
|
||||
var result :Array[Node] = []
|
||||
var stack :Array[Node] = [root]
|
||||
while stack:
|
||||
var node :Node = stack.pop_back()
|
||||
if node.get_class() == cls:
|
||||
result.append(node)
|
||||
for ch in node.get_children():
|
||||
stack.push_back(ch)
|
||||
return result
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://b7ldhc4ryfh1v
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user