summaryrefslogtreecommitdiff
path: root/addons/gdUnit4/src/cmd
diff options
context:
space:
mode:
authorradiohotline <radoihotline@disroot.rg>2026-08-25 16:33:56 +0300
committerradiohotline <radoihotline@disroot.rg>2026-08-25 16:33:56 +0300
commita89e744ed0e8c759caf041a580112365bbfe4303 (patch)
treedd61e320904176995727e86a857d00c90d4933ba /addons/gdUnit4/src/cmd
parent6d53d8cac78250dc888aa49d5f9d4175c6652feb (diff)
escoria updateHEADmain
Diffstat (limited to 'addons/gdUnit4/src/cmd')
-rw-r--r--addons/gdUnit4/src/cmd/CmdArgumentParser.gd62
-rw-r--r--addons/gdUnit4/src/cmd/CmdArgumentParser.gd.uid1
-rw-r--r--addons/gdUnit4/src/cmd/CmdCommand.gd27
-rw-r--r--addons/gdUnit4/src/cmd/CmdCommand.gd.uid1
-rw-r--r--addons/gdUnit4/src/cmd/CmdCommandHandler.gd136
-rw-r--r--addons/gdUnit4/src/cmd/CmdCommandHandler.gd.uid1
-rw-r--r--addons/gdUnit4/src/cmd/CmdOption.gd61
-rw-r--r--addons/gdUnit4/src/cmd/CmdOption.gd.uid1
-rw-r--r--addons/gdUnit4/src/cmd/CmdOptions.gd31
-rw-r--r--addons/gdUnit4/src/cmd/CmdOptions.gd.uid1
10 files changed, 322 insertions, 0 deletions
diff --git a/addons/gdUnit4/src/cmd/CmdArgumentParser.gd b/addons/gdUnit4/src/cmd/CmdArgumentParser.gd
new file mode 100644
index 0000000..aa02319
--- /dev/null
+++ b/addons/gdUnit4/src/cmd/CmdArgumentParser.gd
@@ -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
diff --git a/addons/gdUnit4/src/cmd/CmdArgumentParser.gd.uid b/addons/gdUnit4/src/cmd/CmdArgumentParser.gd.uid
new file mode 100644
index 0000000..978c595
--- /dev/null
+++ b/addons/gdUnit4/src/cmd/CmdArgumentParser.gd.uid
@@ -0,0 +1 @@
+uid://v2okve7k32hr
diff --git a/addons/gdUnit4/src/cmd/CmdCommand.gd b/addons/gdUnit4/src/cmd/CmdCommand.gd
new file mode 100644
index 0000000..92e8c1f
--- /dev/null
+++ b/addons/gdUnit4/src/cmd/CmdCommand.gd
@@ -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)]
diff --git a/addons/gdUnit4/src/cmd/CmdCommand.gd.uid b/addons/gdUnit4/src/cmd/CmdCommand.gd.uid
new file mode 100644
index 0000000..28437db
--- /dev/null
+++ b/addons/gdUnit4/src/cmd/CmdCommand.gd.uid
@@ -0,0 +1 @@
+uid://detl386jrd80u
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
diff --git a/addons/gdUnit4/src/cmd/CmdCommandHandler.gd.uid b/addons/gdUnit4/src/cmd/CmdCommandHandler.gd.uid
new file mode 100644
index 0000000..b0fa79a
--- /dev/null
+++ b/addons/gdUnit4/src/cmd/CmdCommandHandler.gd.uid
@@ -0,0 +1 @@
+uid://2q800f4gbor2
diff --git a/addons/gdUnit4/src/cmd/CmdOption.gd b/addons/gdUnit4/src/cmd/CmdOption.gd
new file mode 100644
index 0000000..a4982de
--- /dev/null
+++ b/addons/gdUnit4/src/cmd/CmdOption.gd
@@ -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()
diff --git a/addons/gdUnit4/src/cmd/CmdOption.gd.uid b/addons/gdUnit4/src/cmd/CmdOption.gd.uid
new file mode 100644
index 0000000..e4717b6
--- /dev/null
+++ b/addons/gdUnit4/src/cmd/CmdOption.gd.uid
@@ -0,0 +1 @@
+uid://cjlyjf7drcjtf
diff --git a/addons/gdUnit4/src/cmd/CmdOptions.gd b/addons/gdUnit4/src/cmd/CmdOptions.gd
new file mode 100644
index 0000000..c610529
--- /dev/null
+++ b/addons/gdUnit4/src/cmd/CmdOptions.gd
@@ -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
diff --git a/addons/gdUnit4/src/cmd/CmdOptions.gd.uid b/addons/gdUnit4/src/cmd/CmdOptions.gd.uid
new file mode 100644
index 0000000..6e0c2c7
--- /dev/null
+++ b/addons/gdUnit4/src/cmd/CmdOptions.gd.uid
@@ -0,0 +1 @@
+uid://bcrrg66r74ryx