mirror of
https://github.com/Relintai/regression-test-project.git
synced 2024-11-12 10:25:30 +01:00
Better prints messages (#46)
This commit is contained in:
parent
4d82f9f873
commit
4a4a1543d9
@ -2,28 +2,21 @@ extends Node
|
||||
|
||||
var regression_test_project : bool = true # Set it to true in RegressionTestProject
|
||||
|
||||
# Contains info about disabled classes
|
||||
# Also allows to get list of available classes
|
||||
### Contains info about disabled classes and allows to take info about allowed methods
|
||||
|
||||
var properties_exceptions : Array = [
|
||||
"user_data",
|
||||
"config_file",
|
||||
"",
|
||||
"",
|
||||
]
|
||||
# Globablly disabled functions for all classes
|
||||
var function_exceptions : Array = [
|
||||
"_set_user_data",
|
||||
"get_packet", # TODO
|
||||
"create_from_mesh",
|
||||
"_gui_input", # TODO probably missing cherrypick #GH 47636
|
||||
"_input",
|
||||
"_unhandled_input",
|
||||
"_unhandled_key_input",
|
||||
"connect_to_signal", # Should be chrrypicked
|
||||
|
||||
# They exists without assigment like Class.method, because they may be a parent of other objects and children also should have disabled child.method, its children also etc. which is too much to do
|
||||
"connect_to_signal", # GH 47572
|
||||
"set_config_file", # GH 45997
|
||||
"class_get_property", # GH 47573
|
||||
"class_set_property", # GH 47573
|
||||
#"connect_to_signal", # GH 47572
|
||||
"_editor_settings_changed",# GH 45979
|
||||
"_submenu_timeout", # GH 45981
|
||||
"_gui_input", # GH 45998
|
||||
"_unhandled_key_input", # GH 45998
|
||||
"_thread_done", #GH 46000
|
||||
"generate", #GH 46001
|
||||
"_proximity_group_broadcast", #GH 46002
|
||||
@ -31,13 +24,10 @@ var function_exceptions : Array = [
|
||||
"create_from", #GH 46004
|
||||
"create_from_blend_shape", #GH 46004
|
||||
"append_from", #GH 46004
|
||||
"_unhandled_input", # TODO
|
||||
"_input", # TODO
|
||||
"_set_tile_data", #GH 46015
|
||||
"get", #GH 46019
|
||||
"instance_has", #GH 46020
|
||||
"get_var", #GH 46096
|
||||
"force_drag", #GH 46114
|
||||
"set_script", #GH 46120
|
||||
"getvar", #GH 46019
|
||||
"get_available_chars", #GH 46118
|
||||
@ -47,22 +37,16 @@ var function_exceptions : Array = [
|
||||
"set_editor_hint", #GH 46252
|
||||
"get_item_at_position", #TODO hard to find
|
||||
"set_probe_data", #GH 46570
|
||||
"_range_click_timeout",
|
||||
"draw", #GH 46648
|
||||
"_range_click_timeout", #GH 46648
|
||||
"get_indexed", #GH 46019
|
||||
"_vp_input", # TODO
|
||||
"_vp_unhandled_input", # TODO
|
||||
"remove_joy_mapping", #GH 46754
|
||||
"add_joy_mapping", #GH 46754
|
||||
"add_vertex", #GH 47066
|
||||
"create_client", # TODO, strange memory leak
|
||||
"create_shape_owner", #47135
|
||||
"shape_owner_get_owner", #47135
|
||||
|
||||
"collide", #GH 46137
|
||||
"collide_and_get_contacts", #GH 46137
|
||||
"collide_with_motion", #GH 46137
|
||||
"collide_with_motion_and_get_contacts", #GH 46137
|
||||
"get_bind_bone", #GH 47358
|
||||
"get_bind_name", #GH 47358
|
||||
"get_bind_pose", #GH 47358
|
||||
|
||||
# TODO Check this later
|
||||
"propagate_notification",
|
||||
@ -162,67 +146,10 @@ var function_exceptions : Array = [
|
||||
"raise",
|
||||
"add_child",
|
||||
"add_child_below_node",
|
||||
]
|
||||
var exported : Array = [
|
||||
"get_bind_bone",
|
||||
"get_bind_name",
|
||||
"get_bind_pose",
|
||||
"add_sibling",
|
||||
]
|
||||
|
||||
# List of slow functions, which may frooze project(not simple executing each function alone)
|
||||
var slow_functions : Array = [
|
||||
"interpolate_baked",
|
||||
"get_baked_length",
|
||||
"get_baked_points",
|
||||
"get_closest_offset",
|
||||
"get_closest_point", # Only Curve, but looks that a lot of other classes uses this
|
||||
"get_baked_up_vectors",
|
||||
"interpolate_baked_up_vector",
|
||||
"tessellate",
|
||||
"get_baked_tilts",
|
||||
"set_enabled_inputs",
|
||||
"grow_mask",
|
||||
"force_update_transform",
|
||||
|
||||
|
||||
# In 3d view some options are really slow, needs to be limited
|
||||
"set_rings",
|
||||
"set_amount", # Particles
|
||||
|
||||
|
||||
# Just a little slow functions
|
||||
"is_enabler_enabled",
|
||||
"set_enabler",
|
||||
"get_aabb",
|
||||
"set_aabb",
|
||||
"is_on_screen"
|
||||
]
|
||||
# Specific classes which are initialized in specific way e.g. var undo_redo = get_undo_redo() instead var undo_redo = UndoRedo.new()
|
||||
var only_instance : Array = [
|
||||
"UndoRedo",
|
||||
"Object",
|
||||
"JSONRPC",
|
||||
"MainLoop",
|
||||
"SceneTree",
|
||||
"ARVRPositionalTracker",
|
||||
]
|
||||
var invalid_signals : Array = [
|
||||
"multi_selected",
|
||||
"item_collapsed",
|
||||
"button_pressed",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
|
||||
|
||||
# Probably Vararg
|
||||
"tween_step",
|
||||
"tween_completed",
|
||||
"tween_started",
|
||||
"data_channel_received",
|
||||
"",
|
||||
]
|
||||
# Used only in ValueCreator
|
||||
# Globally disabled classes which causes bugs or are very hard to us
|
||||
var disabled_classes : Array = [
|
||||
"ProjectSettings", # Don't mess with project settings, because they can broke entire your workflow
|
||||
"EditorSettings", # Also don't mess with editor settings
|
||||
@ -239,6 +166,8 @@ var disabled_classes : Array = [
|
||||
"IP_Unix",
|
||||
"JNISingleton",
|
||||
|
||||
# Only one class - JavaClass returns Null when using JavaClass.new().get_class
|
||||
"JavaClass",
|
||||
|
||||
# Just don't use these because they are not normal things
|
||||
"_Thread",
|
||||
@ -246,53 +175,63 @@ var disabled_classes : Array = [
|
||||
"_Mutex",
|
||||
]
|
||||
|
||||
# GH 47358
|
||||
func _init():
|
||||
function_exceptions.append_array(exported)
|
||||
|
||||
# Checks if function can be executed
|
||||
# Looks at its arguments an
|
||||
func check_if_is_allowed(method_data : Dictionary) -> bool:
|
||||
# Function is virtual, so we just skip it
|
||||
# Function is virtual or vararg, so we just skip it
|
||||
if method_data["flags"] == method_data["flags"] | METHOD_FLAG_VIRTUAL:
|
||||
return false
|
||||
if method_data["flags"] == method_data["flags"] | 128: # VARARG TODO, Godot issue, add missing flag binding
|
||||
return false
|
||||
|
||||
for arg in method_data["args"]:
|
||||
var name_of_class : String = arg["class_name"]
|
||||
if name_of_class.empty():
|
||||
continue
|
||||
if !ClassDB.class_exists(name_of_class): # This is enum not object, but we allow it
|
||||
continue
|
||||
if name_of_class in disabled_classes:
|
||||
return false
|
||||
if name_of_class.find("Server") != -1 && ClassDB.class_exists(name_of_class) && !ClassDB.is_parent_class(name_of_class,"Reference"):
|
||||
return false
|
||||
if name_of_class.find("Editor") != -1: # TODO not sure about it
|
||||
# Editor stuff usually aren't good choice for arhuments
|
||||
if name_of_class.find("Editor") != -1 || name_of_class.find("SkinReference") != -1:
|
||||
return false
|
||||
|
||||
# In case of adding new type, this prevents from crashing due not recognizing this type
|
||||
# In case of removing/rename type, just comment e.g. TYPE_ARRAY and all occurencies on e.g. switch statement with it
|
||||
var t : int = arg["type"]
|
||||
if !(t == TYPE_NIL || t == TYPE_AABB || t == TYPE_ARRAY || t == TYPE_BASIS || t == TYPE_BOOL || t == TYPE_COLOR || t == TYPE_COLOR_ARRAY || t == TYPE_DICTIONARY || t == TYPE_INT || t == TYPE_INT_ARRAY || t == TYPE_NODE_PATH || t == TYPE_OBJECT || t == TYPE_PLANE || t == TYPE_QUAT || t == TYPE_RAW_ARRAY || t == TYPE_REAL || t == TYPE_REAL_ARRAY || t == TYPE_RECT2 || t == TYPE_RID || t == TYPE_STRING || t == TYPE_TRANSFORM || t == TYPE_TRANSFORM2D || t == TYPE_VECTOR2 || t == TYPE_VECTOR2_ARRAY || t == TYPE_VECTOR3 || t == TYPE_VECTOR3_ARRAY):
|
||||
print("----------------------------------------------------------- TODO - MISSING TYPE, ADD SUPPORT IT") # Add assert here to get info which type is missing
|
||||
return false
|
||||
|
||||
#This is only for RegressionTestProject, because it needs for now clear visual info what is going on screen, but some nodes broke view
|
||||
if regression_test_project:
|
||||
# That means that this is constant, not class
|
||||
if !ClassDB.class_exists(name_of_class):
|
||||
continue
|
||||
if !ClassDB.is_parent_class(name_of_class, "Node") && !ClassDB.is_parent_class(name_of_class, "Reference"):
|
||||
return false
|
||||
|
||||
# In case of adding new type, this prevents from crashing due not recognizing this type
|
||||
var t : int = arg["type"]
|
||||
if !(t == TYPE_NIL || t == TYPE_AABB || t == TYPE_ARRAY || t == TYPE_BASIS || t == TYPE_BOOL || t == TYPE_COLOR || t == TYPE_COLOR_ARRAY || t == TYPE_DICTIONARY || t == TYPE_INT || t == TYPE_INT_ARRAY || t == TYPE_NODE_PATH || t == TYPE_OBJECT || t == TYPE_PLANE || t == TYPE_QUAT || t == TYPE_RAW_ARRAY || t == TYPE_REAL || t == TYPE_REAL_ARRAY || t == TYPE_RECT2 || t == TYPE_RID || t == TYPE_STRING || t == TYPE_TRANSFORM || t == TYPE_TRANSFORM2D || t == TYPE_VECTOR2 || t == TYPE_VECTOR2_ARRAY || t == TYPE_VECTOR3 || t == TYPE_VECTOR3_ARRAY):
|
||||
print("----------------------------------------------------------- TODO - MISSING TYPE, ADD SUPPORT IT")
|
||||
return false
|
||||
|
||||
|
||||
return true
|
||||
|
||||
# Return all available classes to instance and test
|
||||
func remove_disabled_methods(method_list : Array, exceptions : Array) -> void:
|
||||
for exception in exceptions:
|
||||
var index: int = -1
|
||||
for method_index in range(method_list.size()):
|
||||
if method_list[method_index]["name"] == exception:
|
||||
index = method_index
|
||||
break
|
||||
if index != -1:
|
||||
method_list.remove(index)
|
||||
|
||||
# Return all available classes which can be used
|
||||
func get_list_of_available_classes(must_be_instantable : bool = true) -> Array:
|
||||
var full_class_list : Array = Array(ClassDB.get_class_list())
|
||||
var classes : Array = []
|
||||
full_class_list.sort()
|
||||
var c = 0
|
||||
var rr = 0
|
||||
# var rr = 0
|
||||
for name_of_class in full_class_list:
|
||||
rr += 1
|
||||
# rr += 1
|
||||
if name_of_class in disabled_classes:
|
||||
continue
|
||||
|
||||
@ -306,7 +245,7 @@ func get_list_of_available_classes(must_be_instantable : bool = true) -> Array:
|
||||
|
||||
if name_of_class.find("Server") != -1 && !ClassDB.is_parent_class(name_of_class,"Reference"):
|
||||
continue
|
||||
if name_of_class.find("Editor") != -1: # TODO not sure about it
|
||||
if name_of_class.find("Editor") != -1 && regression_test_project:
|
||||
continue
|
||||
|
||||
|
||||
|
@ -1,18 +1,32 @@
|
||||
extends Node
|
||||
|
||||
# Execute every object function
|
||||
### Script:
|
||||
### - takes all available classes
|
||||
### - checks if method is allowed
|
||||
### - checks each argument if is allowed(in case e.g. adding new, to prevent crashes due not recognizing types)
|
||||
### - print info if needed to console
|
||||
### - execute function with parameters
|
||||
|
||||
var debug_print: bool = true
|
||||
var add_to_tree: bool = false # Adds nodes to tree, freeze godot when removing a lot of nodes
|
||||
var use_parent_methods: bool = false # Allows Node2D use Node methods etc. - it is a little slow option which rarely shows
|
||||
var use_always_new_object: bool = true # Don't allow to "remeber" other function effects
|
||||
var exiting: bool = true
|
||||
var exiting: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
if BasicData.regression_test_project:
|
||||
ValueCreator.random = false # Results in RegressionTestProject must be always reproducible
|
||||
else:
|
||||
ValueCreator.random = true
|
||||
|
||||
ValueCreator.number = 100
|
||||
ValueCreator.should_be_always_valid = false
|
||||
|
||||
if BasicData.regression_test_project:
|
||||
tests_all_functions()
|
||||
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if !BasicData.regression_test_project:
|
||||
tests_all_functions()
|
||||
@ -23,44 +37,54 @@ func _process(_delta: float) -> void:
|
||||
# Test all functions
|
||||
func tests_all_functions() -> void:
|
||||
for name_of_class in BasicData.get_list_of_available_classes():
|
||||
if debug_print:
|
||||
print("\n#################### " + name_of_class + " ####################")
|
||||
|
||||
var object: Object = ClassDB.instance(name_of_class)
|
||||
assert(object != null, "Object must be instantable")
|
||||
if add_to_tree:
|
||||
if object is Node:
|
||||
add_child(object)
|
||||
var method_list: Array = ClassDB.class_get_method_list(name_of_class, !use_parent_methods)
|
||||
|
||||
## Exception
|
||||
for exception in BasicData.function_exceptions:
|
||||
var index: int = -1
|
||||
for method_index in range(method_list.size()):
|
||||
if method_list[method_index]["name"] == exception:
|
||||
index = method_index
|
||||
break
|
||||
if index != -1:
|
||||
method_list.remove(index)
|
||||
# Removes excluded methods
|
||||
BasicData.remove_disabled_methods(method_list, BasicData.function_exceptions)
|
||||
|
||||
if debug_print:
|
||||
print("#################### " + name_of_class +" ####################")
|
||||
for _i in range(1):
|
||||
for method_data in method_list:
|
||||
if !BasicData.check_if_is_allowed(method_data):
|
||||
continue
|
||||
|
||||
if debug_print:
|
||||
print(name_of_class + "." + method_data["name"])
|
||||
var arguments: Array = ParseArgumentType.parse_and_return_objects(method_data, name_of_class, debug_print)
|
||||
|
||||
if debug_print:
|
||||
var to_print: String = "GDSCRIPT CODE: "
|
||||
if (
|
||||
ClassDB.is_parent_class(name_of_class, "Object")
|
||||
&& !ClassDB.is_parent_class(name_of_class, "Node")
|
||||
&& !ClassDB.is_parent_class(name_of_class, "Reference")
|
||||
&& !ClassDB.class_has_method(name_of_class, "new")
|
||||
):
|
||||
to_print += "ClassDB.instance(\"" + name_of_class + "\")." + method_data["name"] + "("
|
||||
else:
|
||||
to_print += name_of_class.trim_prefix("_") + ".new()." + method_data["name"] + "("
|
||||
|
||||
for i in arguments.size():
|
||||
to_print += ParseArgumentType.return_gdscript_code_which_run_this_object(arguments[i])
|
||||
if i != arguments.size() - 1:
|
||||
to_print += ", "
|
||||
to_print += ")"
|
||||
print(to_print)
|
||||
|
||||
var arguments: Array = ParseArgumentType.parse_and_return_objects(method_data, debug_print)
|
||||
object.callv(method_data["name"], arguments)
|
||||
|
||||
for argument in arguments:
|
||||
if argument != null:
|
||||
if argument is Node:
|
||||
argument.queue_free()
|
||||
elif argument is Object && !(argument is Reference):
|
||||
argument.free()
|
||||
if argument is Node:
|
||||
argument.queue_free()
|
||||
elif argument is Object && !(argument is Reference):
|
||||
argument.free()
|
||||
|
||||
if use_always_new_object:
|
||||
assert(object != null, "Object must be instantable")
|
||||
if object is Node:
|
||||
object.queue_free()
|
||||
elif object is Object && !(object is Reference):
|
||||
|
@ -1,7 +1,9 @@
|
||||
extends Node
|
||||
|
||||
# Parse arguments and return needed info/objects etc.
|
||||
### Scripts to arguments and return needed info about them.
|
||||
|
||||
|
||||
### Class which contains informations about used
|
||||
class SingleArgument:
|
||||
var name: String # E.G. var roman, can be empty, so temp variable isn't created(nodes and objects must be created with temp_variable due to memory leaks)
|
||||
var type: String # np. Vector2 or Object
|
||||
@ -15,10 +17,6 @@ class SingleArgument:
|
||||
func create_gdscript_arguments(arguments: Array) -> Array:
|
||||
var argument_array: Array = []
|
||||
|
||||
ValueCreator.number = 10
|
||||
ValueCreator.random = true
|
||||
ValueCreator.should_be_always_valid = true # DO NOT CHANGE, BECAUSE NON VALID VALUES WILL SHOW GDSCRIPT ERRORS!
|
||||
|
||||
var counter = 0
|
||||
for argument in arguments:
|
||||
counter += 1
|
||||
@ -122,17 +120,9 @@ func create_gdscript_arguments(arguments: Array) -> Array:
|
||||
return argument_array
|
||||
|
||||
|
||||
func parse_and_return_objects(method_data: Dictionary, debug_print: bool = false) -> Array:
|
||||
func parse_and_return_objects(method_data: Dictionary, name_of_class: String, debug_print: bool = false) -> Array:
|
||||
var arguments_array: Array = []
|
||||
|
||||
if BasicData.regression_test_project:
|
||||
ValueCreator.number = 100
|
||||
ValueCreator.random = false # Results in RegressionTestProject must be always reproducible
|
||||
else:
|
||||
ValueCreator.number = 1000
|
||||
ValueCreator.random = true
|
||||
ValueCreator.should_be_always_valid = false
|
||||
|
||||
for argument in method_data["args"]:
|
||||
match argument.type:
|
||||
TYPE_NIL: # Looks that this means VARIANT not null
|
||||
@ -213,5 +203,196 @@ func parse_and_return_objects(method_data: Dictionary, debug_print: bool = false
|
||||
assert(false, "Missing type, needs to be added to project")
|
||||
|
||||
if debug_print:
|
||||
print("Parameters " + str(arguments_array))
|
||||
print("\n" + name_of_class + "." + method_data["name"] + " --- executing with " + str(arguments_array.size()) + " parameters " + str(arguments_array))
|
||||
return arguments_array
|
||||
|
||||
|
||||
func return_gdscript_code_which_run_this_object(data) -> String:
|
||||
if data == null:
|
||||
return "null"
|
||||
|
||||
var return_string: String = ""
|
||||
|
||||
match typeof(data):
|
||||
TYPE_NIL: # Looks that this means VARIANT not null
|
||||
assert("false", "This is even possible?")
|
||||
TYPE_AABB:
|
||||
return_string = "AABB("
|
||||
return_string += return_gdscript_code_which_run_this_object(data.position)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.size)
|
||||
return_string += ")"
|
||||
TYPE_ARRAY:
|
||||
return_string = "Array(["
|
||||
for i in data.size():
|
||||
return_string += return_gdscript_code_which_run_this_object(data[i])
|
||||
if i != data.size() - 1:
|
||||
return_string += ", "
|
||||
return_string += "])"
|
||||
TYPE_BASIS:
|
||||
return_string = "Basis("
|
||||
return_string += return_gdscript_code_which_run_this_object(data.x)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.y)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.z)
|
||||
return_string += ")"
|
||||
TYPE_BOOL:
|
||||
if data == true:
|
||||
return_string = "true"
|
||||
else:
|
||||
return_string = "false"
|
||||
TYPE_COLOR:
|
||||
return_string = "Color("
|
||||
return_string += return_gdscript_code_which_run_this_object(data.r)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.g)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.b)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.a)
|
||||
return_string += ")"
|
||||
TYPE_COLOR_ARRAY:
|
||||
return_string = "PoolColorArray(["
|
||||
for i in data.size():
|
||||
return_string += return_gdscript_code_which_run_this_object(data[i])
|
||||
if i != data.size() - 1:
|
||||
return_string += ", "
|
||||
return_string += "])"
|
||||
TYPE_DICTIONARY:
|
||||
return_string = "{"
|
||||
for i in data.size():
|
||||
return_string += return_gdscript_code_which_run_this_object(data.keys()[i])
|
||||
return_string += " : "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.values()[i])
|
||||
if i != data.size() - 1:
|
||||
return_string += ", "
|
||||
return_string += "}"
|
||||
TYPE_INT:
|
||||
return_string = str(data)
|
||||
TYPE_INT_ARRAY:
|
||||
return_string = "PoolIntArray(["
|
||||
for i in data.size():
|
||||
return_string += return_gdscript_code_which_run_this_object(data[i])
|
||||
if i != data.size() - 1:
|
||||
return_string += ", "
|
||||
return_string += "])"
|
||||
TYPE_NODE_PATH:
|
||||
return_string = "NodePath("
|
||||
return_string += return_gdscript_code_which_run_this_object(str(data))
|
||||
return_string += ")"
|
||||
TYPE_OBJECT:
|
||||
if data == null:
|
||||
return_string = "null"
|
||||
else:
|
||||
var name_of_class: String = data.get_class()
|
||||
if (
|
||||
ClassDB.is_parent_class(name_of_class, "Object")
|
||||
&& !ClassDB.is_parent_class(name_of_class, "Node")
|
||||
&& !ClassDB.is_parent_class(name_of_class, "Reference")
|
||||
&& !ClassDB.class_has_method(name_of_class, "new")
|
||||
):
|
||||
return_string += "ClassDB.instance(\"" + name_of_class + "\")"
|
||||
else:
|
||||
return_string = name_of_class.trim_prefix("_")
|
||||
return_string += ".new()"
|
||||
|
||||
TYPE_PLANE:
|
||||
return_string = "Plane("
|
||||
return_string += return_gdscript_code_which_run_this_object(data.x)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.y)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.z)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.d)
|
||||
return_string += ")"
|
||||
TYPE_QUAT:
|
||||
return_string = "Quat("
|
||||
return_string += return_gdscript_code_which_run_this_object(data.x)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.y)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.z)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.w)
|
||||
return_string += ")"
|
||||
TYPE_RAW_ARRAY:
|
||||
return_string = "PoolByteArray(["
|
||||
for i in data.size():
|
||||
return_string += return_gdscript_code_which_run_this_object(data[i])
|
||||
if i != data.size() - 1:
|
||||
return_string += ", "
|
||||
return_string += "])"
|
||||
TYPE_REAL:
|
||||
return_string = str(data)
|
||||
TYPE_REAL_ARRAY:
|
||||
return_string = "PoolRealArray(["
|
||||
for i in data.size():
|
||||
return_string += return_gdscript_code_which_run_this_object(data[i])
|
||||
if i != data.size() - 1:
|
||||
return_string += ", "
|
||||
return_string += "])"
|
||||
TYPE_RECT2:
|
||||
return_string = "Rect2("
|
||||
return_string += return_gdscript_code_which_run_this_object(data.position)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.size)
|
||||
return_string += ")"
|
||||
TYPE_RID:
|
||||
return_string = "RID()"
|
||||
TYPE_STRING:
|
||||
return_string = "\"" + data + "\""
|
||||
TYPE_STRING_ARRAY:
|
||||
return_string = "PoolStringArray(["
|
||||
for i in data.size():
|
||||
return_string += return_gdscript_code_which_run_this_object(data[i])
|
||||
if i != data.size() - 1:
|
||||
return_string += ", "
|
||||
return_string += "])"
|
||||
TYPE_TRANSFORM:
|
||||
return_string = "Transform("
|
||||
return_string += return_gdscript_code_which_run_this_object(data.basis)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.origin)
|
||||
return_string += ")"
|
||||
TYPE_TRANSFORM2D:
|
||||
return_string = "Transform2D("
|
||||
return_string += return_gdscript_code_which_run_this_object(data.x)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.y)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.origin)
|
||||
return_string += ")"
|
||||
TYPE_VECTOR2:
|
||||
return_string = "Vector2("
|
||||
return_string += return_gdscript_code_which_run_this_object(data.x)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.y)
|
||||
return_string += ")"
|
||||
TYPE_VECTOR2_ARRAY:
|
||||
return_string = "PoolVector2Array(["
|
||||
for i in data.size():
|
||||
return_string += return_gdscript_code_which_run_this_object(data[i])
|
||||
if i != data.size() - 1:
|
||||
return_string += ", "
|
||||
return_string += "])"
|
||||
TYPE_VECTOR3:
|
||||
return_string = "Vector3("
|
||||
return_string += return_gdscript_code_which_run_this_object(data.x)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.y)
|
||||
return_string += ", "
|
||||
return_string += return_gdscript_code_which_run_this_object(data.z)
|
||||
return_string += ")"
|
||||
TYPE_VECTOR3_ARRAY:
|
||||
return_string = "PoolVector3Array(["
|
||||
for i in data.size():
|
||||
return_string += return_gdscript_code_which_run_this_object(data[i])
|
||||
if i != data.size() - 1:
|
||||
return_string += ", "
|
||||
return_string += "])"
|
||||
_:
|
||||
assert(false, "Missing type, needs to be added to project")
|
||||
|
||||
return return_string
|
||||
|
54
README.md
54
README.md
@ -50,18 +50,19 @@ A scene that will probably give people a hard time quite often is `FunctionExecu
|
||||
This is a fuzzer, but with removed ability to use random argument values (the arguments are identical every time it is run).
|
||||
When the engine crashes, in logs usually will be something like this:
|
||||
```
|
||||
#################### SkeletonModification2DPhysicalBones ####################
|
||||
SkeletonModification2DPhysicalBones.set_physical_bone_node
|
||||
Parameters [100, ]
|
||||
ERROR: Joint index out of range!
|
||||
at: set_physical_bone_node (scene/resources/skeleton_modification_2d_physicalbones.cpp:259)
|
||||
SkeletonModification2DPhysicalBones.get_physical_bone_node
|
||||
Parameters [100]
|
||||
ERROR: Joint index out of range!
|
||||
at: get_physical_bone_node (scene/resources/skeleton_modification_2d_physicalbones.cpp:265)
|
||||
SkeletonModification2DPhysicalBones.fetch_physical_bones
|
||||
Parameters []
|
||||
scene/resources/skeleton_modification_2d_physicalbones.cpp:186:2: runtime error: member access within null pointer of type 'struct SkeletonModificationStack2D'
|
||||
#################### LineEdit ####################
|
||||
|
||||
LineEdit._text_changed --- executing with 0 parameters []
|
||||
GDSCRIPT CODE: LineEdit.new()._text_changed()
|
||||
|
||||
LineEdit._toggle_draw_caret --- executing with 0 parameters []
|
||||
GDSCRIPT CODE: LineEdit.new()._toggle_draw_caret()
|
||||
|
||||
LineEdit.set_align --- executing with 1 parameters [100]
|
||||
GDSCRIPT CODE: LineEdit.new().set_align(100)
|
||||
ERROR: set_align: Index (int)p_align = 100 is out of bounds (4 = 4).
|
||||
At: scene/gui/line_edit.cpp:592.
|
||||
scene/resources/line_edit.cpp:186:2: runtime error: member access within null pointer of type 'struct LineEdit'
|
||||
handle_crash: Program crashed with signal 11
|
||||
Dumping the backtrace. Please include this when reporting the bug on godotengine/godot/issues
|
||||
[1] bin/godot.linuxbsd.tools.64s() [0x1e697d8] (/home/runner/work/godot/godot/platform/linuxbsd/crash_handler_linuxbsd.cpp:54)
|
||||
@ -70,24 +71,24 @@ Dumping the backtrace. Please include this when reporting the bug on godotengine
|
||||
There are some interesting things to discuss here.
|
||||
This line shows what class we are testing now
|
||||
```
|
||||
#################### SkeletonModification2DPhysicalBones ####################
|
||||
#################### LineEdit ####################
|
||||
```
|
||||
which method
|
||||
```
|
||||
SkeletonModification2DPhysicalBones.set_physical_bone_node
|
||||
LineEdit.set_align
|
||||
```
|
||||
and which parameters (here are two arguments - `100`, \` \`(empty string))
|
||||
and which parameters
|
||||
```
|
||||
Parameters [100, ]
|
||||
--- executing with 1 parameters [100]
|
||||
```
|
||||
To make testing easier, each object is created from scratch and by looking at the class definition in Godot - `set_physical_bone_node(int, String)` we can create an expression that is executed on this line:
|
||||
Next you can see GDScript command which is executed and you can copy it and test manually in Godot
|
||||
```
|
||||
SkeletonModification2DPhysicalBones.new().set_physical_bone_node(100,"")
|
||||
GDSCRIPT CODE: LineEdit.new()._toggle_draw_caret()
|
||||
```
|
||||
Then you can see errors caused by invalid arguments, which you can ignore if they don't cause other crashes/leaks etc.
|
||||
```
|
||||
ERROR: Joint index out of range!
|
||||
at: get_physical_bone_node (scene/resources/skeleton_modification_2d_physicalbones.cpp:265)
|
||||
ERROR: set_align: Index (int)p_align = 100 is out of bounds (4 = 4).
|
||||
At: scene/gui/line_edit.cpp:592.
|
||||
```
|
||||
At the end we can see Godot's crash log with additional information that tried to use null pointer incorrectly:
|
||||
```
|
||||
@ -97,14 +98,14 @@ Dumping the backtrace. Please include this when reporting the bug on godotengine
|
||||
[1] bin/godot.linuxbsd.tools.64s() [0x1e697d8] (/home/runner/work/godot/godot/platform/linuxbsd/crash_handler_linuxbsd.cpp:54)
|
||||
[2] /lib/x86_64-linux-gnu/libc.so.6(+0x46210) [0x7fd1ca5b0210] (??:0)
|
||||
```
|
||||
we can assume that this is caused by calling the function immediately before the crash:
|
||||
In most situations, the latest executed function/created object is responsible for crash
|
||||
```
|
||||
SkeletonModification2DPhysicalBones.fetch_physical_bones
|
||||
Parameters []
|
||||
LineEdit.set_align --- executing with 1 parameters [100]
|
||||
GDSCRIPT CODE: LineEdit.new().set_align(100)
|
||||
```
|
||||
We can test this by running a function in Godot that looks like this(just add `.new()` after class name and fill function arguments from `Parameters`):
|
||||
So we can just take GDScript code from above, copy it into Godot and test project, which should crash engine
|
||||
```
|
||||
SkeletonModification2DPhysicalBones.new().fetch_physical_bones()
|
||||
LineEdit.new().set_align(100)
|
||||
```
|
||||
|
||||
## Nodes
|
||||
@ -125,7 +126,8 @@ Scenes like `Physics2D.tscn` or `Lights3D.tscn` are normal scenes with specific
|
||||
|
||||
## 4.0 version limitations
|
||||
ReparentingDeleting is in 4.0 only Reparenting - bug https://github.com/godotengine/godot/issues/45471
|
||||
Some scenes available in 3.x branch, but due freezes and long loading times are disabled.
|
||||
Some scenes available in 3.x branch, but due freezes and long loading times are disabled(mostly Vulkan fault).
|
||||
Some patches are applied to e.g. handle rename `OS` -> `Platform` or `Transform` -> `Transform3D`
|
||||
|
||||
## Epilepsy Warning
|
||||
Due using by project a lot of functions from each type of Node, screen may flicker, images and objects may change randomly color and size which may lead some users to health problems.
|
||||
|
Loading…
Reference in New Issue
Block a user