2022-06-02 04:13:43 +02:00
|
|
|
# ##############################################################################
|
|
|
|
#(G)odot (U)nit (T)est class
|
|
|
|
#
|
|
|
|
# ##############################################################################
|
|
|
|
# The MIT License (MIT)
|
|
|
|
# =====================
|
|
|
|
#
|
|
|
|
# Copyright (c) 2020 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
|
|
|
|
# -----------
|
|
|
|
# ##############################################################################
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# A stroke of genius if I do say so. This allows for doubling a scene without
|
2023-01-07 20:26:17 +01:00
|
|
|
# having to write any files. By overloading the "instantiate" method we can
|
2022-06-02 04:13:43 +02:00
|
|
|
# make whatever we want.
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
class PackedSceneDouble:
|
|
|
|
extends PackedScene
|
2023-01-07 20:26:17 +01:00
|
|
|
var _script = null
|
2022-06-02 04:13:43 +02:00
|
|
|
var _scene = null
|
|
|
|
|
|
|
|
func set_script_obj(obj):
|
|
|
|
_script = obj
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func instantiate(edit_state=0):
|
2022-11-09 21:57:46 +01:00
|
|
|
var inst = _scene.instantiate(edit_state)
|
2023-01-07 20:26:17 +01:00
|
|
|
if(_script != null):
|
2022-06-02 04:13:43 +02:00
|
|
|
inst.set_script(_script)
|
|
|
|
return inst
|
|
|
|
|
|
|
|
func load_scene(path):
|
|
|
|
_scene = load(path)
|
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
|
2022-06-02 04:13:43 +02:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# START Doubler
|
|
|
|
# ------------------------------------------------------------------------------
|
2023-01-07 20:26:17 +01:00
|
|
|
var _utils = load('res://addons/gut/utils.gd').get_instance()
|
|
|
|
var _base_script_text = _utils.get_file_as_text('res://addons/gut/double_templates/script_template.txt')
|
|
|
|
var _script_collector = _utils.ScriptCollector.new()
|
|
|
|
# used by tests for debugging purposes.
|
|
|
|
var print_source = false
|
|
|
|
var inner_class_registry = _utils.InnerClassRegistry.new()
|
2022-06-02 04:13:43 +02:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
# ###############
|
|
|
|
# Properties
|
|
|
|
# ###############
|
2022-06-02 04:13:43 +02:00
|
|
|
var _stubber = _utils.Stubber.new()
|
2023-01-07 20:26:17 +01:00
|
|
|
func get_stubber():
|
|
|
|
return _stubber
|
|
|
|
func set_stubber(stubber):
|
|
|
|
_stubber = stubber
|
|
|
|
|
2022-06-02 04:13:43 +02:00
|
|
|
var _lgr = _utils.get_logger()
|
2023-01-07 20:26:17 +01:00
|
|
|
func get_logger():
|
|
|
|
return _lgr
|
|
|
|
func set_logger(logger):
|
|
|
|
_lgr = logger
|
|
|
|
_method_maker.set_logger(logger)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
|
|
|
var _spy = null
|
2023-01-07 20:26:17 +01:00
|
|
|
func get_spy():
|
|
|
|
return _spy
|
|
|
|
func set_spy(spy):
|
|
|
|
_spy = spy
|
|
|
|
|
2022-06-02 04:13:43 +02:00
|
|
|
var _gut = null
|
2023-01-07 20:26:17 +01:00
|
|
|
func get_gut():
|
|
|
|
return _gut
|
|
|
|
func set_gut(gut):
|
|
|
|
_gut = gut
|
|
|
|
|
2022-06-02 04:13:43 +02:00
|
|
|
var _strategy = null
|
2023-01-07 20:26:17 +01:00
|
|
|
func get_strategy():
|
|
|
|
return _strategy
|
|
|
|
func set_strategy(strategy):
|
|
|
|
_strategy = strategy
|
2022-06-02 04:13:43 +02:00
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
var _method_maker = _utils.MethodMaker.new()
|
|
|
|
func get_method_maker():
|
|
|
|
return _method_maker
|
2022-06-02 04:13:43 +02:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
var _ignored_methods = _utils.OneToMany.new()
|
|
|
|
func get_ignored_methods():
|
|
|
|
return _ignored_methods
|
2022-06-02 04:13:43 +02:00
|
|
|
|
|
|
|
# ###############
|
|
|
|
# Private
|
|
|
|
# ###############
|
2023-01-07 20:26:17 +01:00
|
|
|
func _init(strategy=_utils.DOUBLE_STRATEGY.SCRIPT_ONLY):
|
|
|
|
set_logger(_utils.get_logger())
|
|
|
|
_strategy = strategy
|
|
|
|
|
|
|
|
|
2022-06-02 04:13:43 +02:00
|
|
|
func _get_indented_line(indents, text):
|
2023-01-07 20:26:17 +01:00
|
|
|
var to_return = ''
|
2022-06-02 04:13:43 +02:00
|
|
|
for _i in range(indents):
|
|
|
|
to_return += "\t"
|
|
|
|
return str(to_return, text, "\n")
|
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func _stub_to_call_super(parsed, method_name):
|
|
|
|
if(_utils.non_super_methods.has(method_name)):
|
2022-06-02 04:13:43 +02:00
|
|
|
return
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
var params = _utils.StubParams.new(parsed.script_path, method_name, parsed.subpath)
|
2022-06-02 04:13:43 +02:00
|
|
|
params.to_call_super()
|
|
|
|
_stubber.add_stub(params)
|
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func _get_base_script_text(parsed, override_path, partial):
|
|
|
|
var path = parsed.script_path
|
|
|
|
if(override_path != null):
|
2022-06-02 04:13:43 +02:00
|
|
|
path = override_path
|
|
|
|
|
|
|
|
var stubber_id = -1
|
2023-01-07 20:26:17 +01:00
|
|
|
if(_stubber != null):
|
2022-06-02 04:13:43 +02:00
|
|
|
stubber_id = _stubber.get_instance_id()
|
|
|
|
|
|
|
|
var spy_id = -1
|
2023-01-07 20:26:17 +01:00
|
|
|
if(_spy != null):
|
2022-06-02 04:13:43 +02:00
|
|
|
spy_id = _spy.get_instance_id()
|
|
|
|
|
|
|
|
var gut_id = -1
|
2023-01-07 20:26:17 +01:00
|
|
|
if(_gut != null):
|
2022-06-02 04:13:43 +02:00
|
|
|
gut_id = _gut.get_instance_id()
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
var extends_text = parsed.get_extends_text()
|
|
|
|
|
2022-06-02 04:13:43 +02:00
|
|
|
var values = {
|
|
|
|
# Top sections
|
2023-01-07 20:26:17 +01:00
|
|
|
"extends":extends_text,
|
|
|
|
"constants":'',#obj_info.get_constants_text(),
|
|
|
|
"properties":'',#obj_info.get_properties_text(),
|
|
|
|
|
2022-06-02 04:13:43 +02:00
|
|
|
# metadata values
|
2023-01-07 20:26:17 +01:00
|
|
|
"path":path,
|
|
|
|
"subpath":_utils.nvl(parsed.subpath, ''),
|
|
|
|
"stubber_id":stubber_id,
|
|
|
|
"spy_id":spy_id,
|
|
|
|
"gut_id":gut_id,
|
|
|
|
"singleton_name":'',#_utils.nvl(obj_info.get_singleton_name(), ''),
|
|
|
|
"is_partial":partial,
|
2022-06-02 04:13:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return _base_script_text.format(values)
|
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
func _create_double(parsed, strategy, override_path, partial):
|
|
|
|
var base_script = _get_base_script_text(parsed, override_path, partial)
|
2022-06-02 04:13:43 +02:00
|
|
|
var super_name = ""
|
|
|
|
var path = ""
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
path = parsed.script_path
|
|
|
|
var dbl_src = ""
|
|
|
|
dbl_src += base_script
|
2022-06-02 04:13:43 +02:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
for method in parsed.get_local_methods():
|
|
|
|
if(!method.is_black_listed() && !_ignored_methods.has(parsed.resource, method.meta.name)):
|
|
|
|
var mthd = parsed.get_local_method(method.meta.name)
|
|
|
|
dbl_src += _get_func_text(method.meta, path, super_name)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
if(strategy == _utils.DOUBLE_STRATEGY.INCLUDE_SUPER):
|
|
|
|
for method in parsed.get_super_methods():
|
|
|
|
if(!method.is_black_listed() && !_ignored_methods.has(parsed.resource, method.meta.name)):
|
|
|
|
_stub_to_call_super(parsed, method.meta.name)
|
|
|
|
dbl_src += _get_func_text(method.meta, path, super_name)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
if(print_source):
|
|
|
|
print(_utils.add_line_numbers(dbl_src))
|
2022-06-02 04:13:43 +02:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
var DblClass = _utils.create_script_from_source(dbl_src)
|
|
|
|
if(_stubber != null):
|
|
|
|
_stub_method_default_values(DblClass, parsed, strategy)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
return DblClass
|
2022-06-02 04:13:43 +02:00
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func _stub_method_default_values(which, parsed, strategy):
|
|
|
|
for method in parsed.get_local_methods():
|
|
|
|
if(!method.is_black_listed() && !_ignored_methods.has(parsed.resource, method.meta.name)):
|
|
|
|
_stubber.stub_defaults_from_meta(parsed.script_path, method.meta)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func _double_scene_and_script(scene, strategy, partial):
|
|
|
|
var to_return = PackedSceneDouble.new()
|
|
|
|
to_return.load_scene(scene.get_path())
|
2022-06-02 04:13:43 +02:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
var script_obj = _utils.get_scene_script_object(scene)
|
|
|
|
if(script_obj != null):
|
|
|
|
var script_dbl = null
|
|
|
|
if(partial):
|
|
|
|
script_dbl = _partial_double(script_obj, strategy, scene.get_path())
|
|
|
|
else:
|
|
|
|
script_dbl = _double(script_obj, strategy, scene.get_path())
|
|
|
|
to_return.set_script_obj(script_dbl)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
return to_return
|
2022-06-02 04:13:43 +02:00
|
|
|
|
|
|
|
|
|
|
|
func _get_inst_id_ref_str(inst):
|
2023-01-07 20:26:17 +01:00
|
|
|
var ref_str = 'null'
|
|
|
|
if(inst):
|
|
|
|
ref_str = str('instance_from_id(', inst.get_instance_id(),')')
|
2022-06-02 04:13:43 +02:00
|
|
|
return ref_str
|
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func _get_func_text(method_hash, path, super_=""):
|
|
|
|
var override_count = null;
|
|
|
|
if(_stubber != null):
|
2022-06-02 04:13:43 +02:00
|
|
|
override_count = _stubber.get_parameter_count(path, method_hash.name)
|
2023-01-07 20:26:17 +01:00
|
|
|
if(override_count != null):
|
|
|
|
print(method_hash.name, ' override: ', override_count)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
var text = _method_maker.get_function_text(method_hash, path, override_count, super_) + "\n"
|
2022-06-02 04:13:43 +02:00
|
|
|
|
|
|
|
return text
|
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func _parse_script(obj):
|
|
|
|
var parsed = null
|
2022-06-02 04:13:43 +02:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
if(_utils.is_inner_class(obj)):
|
|
|
|
if(inner_class_registry.has(obj)):
|
|
|
|
parsed = _script_collector.parse(inner_class_registry.get_base_resource(obj), obj)
|
|
|
|
else:
|
|
|
|
_lgr.error('Doubling Inner Classes requires you register them first. Call register_inner_classes passing the script that contains the inner class.')
|
2022-06-02 04:13:43 +02:00
|
|
|
else:
|
2023-01-07 20:26:17 +01:00
|
|
|
parsed = _script_collector.parse(obj)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
return parsed
|
2022-06-02 04:13:43 +02:00
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
# Override path is used with scenes.
|
|
|
|
func _double(obj, strategy, override_path=null):
|
|
|
|
var parsed = _parse_script(obj)
|
|
|
|
if(parsed != null):
|
|
|
|
return _create_double(parsed, strategy, override_path, false)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func _partial_double(obj, strategy, override_path=null):
|
|
|
|
var parsed = _parse_script(obj)
|
|
|
|
if(parsed != null):
|
|
|
|
return _create_double(parsed, strategy, override_path, true)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
# -------------------------
|
2022-06-02 04:13:43 +02:00
|
|
|
# Public
|
2023-01-07 20:26:17 +01:00
|
|
|
# -------------------------
|
2022-06-02 04:13:43 +02:00
|
|
|
|
|
|
|
# double a script/object
|
2023-01-07 20:26:17 +01:00
|
|
|
func double(obj, strategy=_strategy):
|
|
|
|
return _double(obj, strategy)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func partial_double(obj, strategy=_strategy):
|
|
|
|
return _partial_double(obj, strategy)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
# double a scene
|
|
|
|
func double_scene(scene, strategy=_strategy):
|
|
|
|
return _double_scene_and_script(scene, strategy, false)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func partial_double_scene(scene, strategy=_strategy):
|
|
|
|
return _double_scene_and_script(scene, strategy, true)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func double_gdnative(which):
|
|
|
|
return _double(which, _utils.DOUBLE_STRATEGY.INCLUDE_SUPER)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func partial_double_gdnative(which):
|
|
|
|
return _partial_double(which, _utils.DOUBLE_STRATEGY.INCLUDE_SUPER)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func double_inner(parent, inner, strategy=_strategy):
|
|
|
|
var parsed = _script_collector.parse(parent, inner)
|
|
|
|
return _create_double(parsed, strategy, null, false)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func partial_double_inner(parent, inner, strategy=_strategy):
|
|
|
|
var parsed = _script_collector.parse(parent, inner)
|
|
|
|
return _create_double(parsed, strategy, null, true)
|
2022-06-02 04:13:43 +02:00
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func add_ignored_method(obj, method_name):
|
|
|
|
_ignored_methods.add(obj, method_name)
|