################################################################################ #(G)odot (U)nit (T)est class # ################################################################################ #The MIT License (MIT) #===================== # #Copyright (c) 2019 Tom "Butch" Wesley # #Permission is hereby granted, free of charge, to any person obtaining a copy #of this software and associated documentation files (the "Software"), to deal #in the Software without restriction, including without limitation the rights #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #copies of the Software, and to permit persons to whom the Software is #furnished to do so, subject to the following conditions: # #The above copyright notice and this permission notice shall be included in #all copies or substantial portions of the Software. # #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN #THE SOFTWARE. # ################################################################################ # Description # ----------- # Command line interface for the GUT unit testing tool. Allows you to run tests # from the command line instead of running a scene. Place this script along with # gut.gd into your scripts directory at the root of your project. Once there you # can run this script (from the root of your project) using the following command: # godot -s -d test/gut/gut_cmdln.gd # # See the readme for a list of options and examples. You can also use the -gh # option to get more information about how to use the command line interface. # # Version 6.8.1 ################################################################################ #------------------------------------------------------------------------------- # Parses the command line arguments supplied into an array that can then be # examined and parsed based on how the gut options work. #------------------------------------------------------------------------------- class CmdLineParser: var _used_options = [] # an array of arrays. Each element in this array will contain an option # name and if that option contains a value then it will have a sedond # element. For example: # [[-gselect, test.gd], [-gexit]] var _opts = [] func _init(): for i in range(OS.get_cmdline_args().size()): var opt_val = OS.get_cmdline_args()[i].split('=') _opts.append(opt_val) # Parse out multiple comma delimited values from a command line # option. Values are separated from option name with "=" and # additional values are comma separated. func _parse_array_value(full_option): var value = _parse_option_value(full_option) var split = value.split(',') return split # Parse out the value of an option. Values are separated from # the option name with "=" func _parse_option_value(full_option): if(full_option.size() > 1): return full_option[1] else: return null # Search _opts for an element that starts with the option name # specified. func find_option(name): var found = false var idx = 0 while(idx < _opts.size() and !found): if(_opts[idx][0] == name): found = true else: idx += 1 if(found): return idx else: return -1 func get_array_value(option): _used_options.append(option) var to_return = [] var opt_loc = find_option(option) if(opt_loc != -1): to_return = _parse_array_value(_opts[opt_loc]) _opts.remove(opt_loc) return to_return # returns the value of an option if it was specified, null otherwise. This # used to return the default but that became problemnatic when trying to # punch through the different places where values could be specified. func get_value(option): _used_options.append(option) var to_return = null var opt_loc = find_option(option) if(opt_loc != -1): to_return = _parse_option_value(_opts[opt_loc]) _opts.remove(opt_loc) return to_return # returns true if it finds the option, false if not. func was_specified(option): _used_options.append(option) return find_option(option) != -1 # Returns any unused command line options. I found that only the -s and # script name come through from godot, all other options that godot uses # are not sent through OS.get_cmdline_args(). # # This is a onetime thing b/c i kill all items in _used_options func get_unused_options(): var to_return = [] for i in range(_opts.size()): to_return.append(_opts[i][0]) var script_option = to_return.find('-s') if script_option != -1: to_return.remove(script_option + 1) to_return.remove(script_option) while(_used_options.size() > 0): var index = to_return.find(_used_options[0].split("=")[0]) if(index != -1): to_return.remove(index) _used_options.remove(0) return to_return #------------------------------------------------------------------------------- # Simple class to hold a command line option #------------------------------------------------------------------------------- class Option: var value = null var option_name = '' var default = null var description = '' func _init(name, default_value, desc=''): option_name = name default = default_value description = desc value = null#default_value func pad(value, size, pad_with=' '): var to_return = value for i in range(value.length(), size): to_return += pad_with return to_return func to_s(min_space=0): var subbed_desc = description if(subbed_desc.find('[default]') != -1): subbed_desc = subbed_desc.replace('[default]', str(default)) return pad(option_name, min_space) + subbed_desc #------------------------------------------------------------------------------- # The high level interface between this script and the command line options # supplied. Uses Option class and CmdLineParser to extract information from # the command line and make it easily accessible. #------------------------------------------------------------------------------- var options = [] var _opts = [] var _banner = '' func add(name, default, desc): options.append(Option.new(name, default, desc)) func get_value(name): var found = false var idx = 0 while(idx < options.size() and !found): if(options[idx].option_name == name): found = true else: idx += 1 if(found): return options[idx].value else: print("COULD NOT FIND OPTION " + name) return null func set_banner(banner): _banner = banner func print_help(): var longest = 0 for i in range(options.size()): if(options[i].option_name.length() > longest): longest = options[i].option_name.length() print('---------------------------------------------------------') print(_banner) print("\nOptions\n-------") for i in range(options.size()): print(' ' + options[i].to_s(longest + 2)) print('---------------------------------------------------------') func print_options(): for i in range(options.size()): print(options[i].option_name + '=' + str(options[i].value)) func parse(): var parser = CmdLineParser.new() for i in range(options.size()): var t = typeof(options[i].default) # only set values that were specified at the command line so that # we can punch through default and config values correctly later. # Without this check, you can't tell the difference between the # defaults and what was specified, so you can't punch through # higher level options. if(parser.was_specified(options[i].option_name)): if(t == TYPE_INT): options[i].value = int(parser.get_value(options[i].option_name)) elif(t == TYPE_STRING): options[i].value = parser.get_value(options[i].option_name) elif(t == TYPE_ARRAY): options[i].value = parser.get_array_value(options[i].option_name) elif(t == TYPE_BOOL): options[i].value = parser.was_specified(options[i].option_name) elif(t == TYPE_NIL): print(options[i].option_name + ' cannot be processed, it has a nil datatype') else: print(options[i].option_name + ' cannot be processed, it has unknown datatype:' + str(t)) var unused = parser.get_unused_options() if(unused.size() > 0): print("Unrecognized options: ", unused) return false return true