summaryrefslogtreecommitdiff
path: root/addons/gdUnit4/src/cmd/CmdCommandHandler.gd
diff options
context:
space:
mode:
Diffstat (limited to 'addons/gdUnit4/src/cmd/CmdCommandHandler.gd')
-rw-r--r--addons/gdUnit4/src/cmd/CmdCommandHandler.gd136
1 files changed, 136 insertions, 0 deletions
diff --git a/addons/gdUnit4/src/cmd/CmdCommandHandler.gd b/addons/gdUnit4/src/cmd/CmdCommandHandler.gd
new file mode 100644
index 0000000..2a7ed55
--- /dev/null
+++ b/addons/gdUnit4/src/cmd/CmdCommandHandler.gd
@@ -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