# ------------- # returns{} and parameters {} have the followin structure # ------------- # { # inst_id_or_path1:{ # method_name1: [StubParams, StubParams], # method_name2: [StubParams, StubParams] # }, # inst_id_or_path2:{ # method_name1: [StubParams, StubParams], # method_name2: [StubParams, StubParams] # } # } var returns = {} var _utils = load("res://addons/gut/utils.gd").get_instance() var _lgr = _utils.get_logger() var _strutils = _utils.Strutils.new() func _make_key_from_metadata(doubled): var to_return = doubled.__gut_metadata_.path if doubled.__gut_metadata_.from_singleton != "": to_return = str(doubled.__gut_metadata_.from_singleton) elif doubled.__gut_metadata_.subpath != "": to_return += str("-", doubled.__gut_metadata_.subpath) return to_return # Creates they key for the returns hash based on the type of object passed in # obj could be a string of a path to a script with an optional subpath or # it could be an instance of a doubled object. func _make_key_from_variant(obj, subpath = null): var to_return = null match typeof(obj): TYPE_STRING: # this has to match what is done in _make_key_from_metadata to_return = obj if subpath != null and subpath != "": to_return += str("-", subpath) TYPE_OBJECT: if _utils.is_instance(obj): to_return = _make_key_from_metadata(obj) elif _utils.is_native_class(obj): to_return = _utils.get_native_class_name(obj) else: to_return = obj.resource_path return to_return func _add_obj_method(obj, method, subpath = null): var key = _make_key_from_variant(obj, subpath) if _utils.is_instance(obj): key = obj if !returns.has(key): returns[key] = {} if !returns[key].has(method): returns[key][method] = [] return key # ############## # Public # ############## # Searches returns for an entry that matches the instance or the class that # passed in obj is. # # obj can be an instance, class, or a path. func _find_stub(obj, method, parameters = null, find_overloads = false): var key = _make_key_from_variant(obj) var to_return = null if _utils.is_instance(obj): if returns.has(obj) and returns[obj].has(method): key = obj elif obj.get("__gut_metadata_"): key = _make_key_from_metadata(obj) if returns.has(key) and returns[key].has(method): var param_match = null var null_match = null var overload_match = null for i in range(returns[key][method].size()): if returns[key][method][i].parameters == parameters: param_match = returns[key][method][i] if returns[key][method][i].parameters == null: null_match = returns[key][method][i] if returns[key][method][i].has_param_override(): overload_match = returns[key][method][i] if find_overloads and overload_match != null: to_return = overload_match # We have matching parameter values so return the stub value for that elif param_match != null: to_return = param_match # We found a case where the parameters were not specified so return # parameters for that. Only do this if the null match is not *just* # a paramerter override stub. elif null_match != null and !null_match.is_param_override_only(): to_return = null_match else: _lgr.warn( str( "Call to [", method, "] was not stubbed for the supplied parameters ", parameters, ". Null was returned." ) ) return to_return func add_stub(stub_params): if stub_params.stub_method == "_init": _lgr.error("You cannot stub _init. Super's _init is ALWAYS called.") else: var key = _add_obj_method( stub_params.stub_target, stub_params.stub_method, stub_params.target_subpath ) returns[key][stub_params.stub_method].append(stub_params) # Gets a stubbed return value for the object and method passed in. If the # instance was stubbed it will use that, otherwise it will use the path and # subpath of the object to try to find a value. # # It will also use the optional list of parameter values to find a value. If # the object was stubbed with no parameters than any parameters will match. # If it was stubbed with specific parameter values then it will try to match. # If the parameters do not match BUT there was also an empty parameter list stub # then it will return those. # If it cannot find anything that matches then null is returned.for # # Parameters # obj: this should be an instance of a doubled object. # method: the method called # parameters: optional array of parameter vales to find a return value for. func get_return(obj, method, parameters = null): var stub_info = _find_stub(obj, method, parameters) if stub_info != null: return stub_info.return_val else: return null func should_call_super(obj, method, parameters = null): if _utils.non_super_methods.has(method): return false var stub_info = _find_stub(obj, method, parameters) var is_partial = false if typeof(obj) != TYPE_STRING: # some stubber tests test with strings is_partial = obj.__gut_metadata_.is_partial var should = is_partial if stub_info != null: should = stub_info.call_super elif !is_partial: # this log message is here because of how the generated doubled scripts # are structured. With this log msg here, you will only see one # "unstubbed" info instead of multiple. _lgr.info("Unstubbed call to " + method + "::" + _strutils.type2str(obj)) should = false return should func get_parameter_count(obj, method): var to_return = null var stub_info = _find_stub(obj, method, null, true) if stub_info != null and stub_info.has_param_override(): to_return = stub_info.parameter_count return to_return func get_default_value(obj, method, p_index): var to_return = null var stub_info = _find_stub(obj, method, null, true) if ( stub_info != null and stub_info.parameter_defaults != null and stub_info.parameter_defaults.size() > p_index ): to_return = stub_info.parameter_defaults[p_index] return to_return func clear(): returns.clear() func get_logger(): return _lgr func set_logger(logger): _lgr = logger func to_s(): var text = "" for thing in returns: text += str("-- ", thing, " --\n") for method in returns[thing]: text += str("\t", method, "\n") for i in range(returns[thing][method].size()): text += "\t\t" + returns[thing][method][i].to_s() + "\n" if text == "": text = "Stubber is empty" return text