diff --git a/AIO/AllNodes/2DALL.tscn b/AIO/AllNodes/2DALL.tscn index e55d083..7b53d6f 100644 --- a/AIO/AllNodes/2DALL.tscn +++ b/AIO/AllNodes/2DALL.tscn @@ -4,15 +4,15 @@ [sub_resource type="SpriteFrames" id=1] animations = [ { -"frames": [ ExtResource( 5 ), ExtResource( 5 ), ExtResource( 5 ) ], -"loop": true, -"name": "New Anim", -"speed": 5.0 -}, { "frames": [ ExtResource( 5 ) ], "loop": true, "name": "0", "speed": 5.0 +}, { +"frames": [ ExtResource( 5 ), ExtResource( 5 ), ExtResource( 5 ) ], +"loop": true, +"name": "New Anim", +"speed": 5.0 } ] [sub_resource type="CapsuleShape2D" id=2] diff --git a/Autoload/Autoload.gd b/Autoload/Autoload.gd index 6e85e46..f5a4a97 100644 --- a/Autoload/Autoload.gd +++ b/Autoload/Autoload.gd @@ -8,16 +8,13 @@ var last_time : int const PRINT_TIME_EVERY_MILISECONDS : int = 5000 var time_to_print_next_time : int = PRINT_TIME_EVERY_MILISECONDS -var time_to_show: int = 15 * 1000 # How long test works in miliseconds +var time_to_show: int = 25 * 1000 # How long test works in miliseconds var time_for_each_step : int = -1 # Each scene runs alone const alone_steps : Array = [ - "res://MainScenes/Control.tscn", - "res://MainScenes/Node2D.tscn", - "res://MainScenes/Other.tscn", - "res://MainScenes/Spatial.tscn", + "res://MainScenes/MainScenes.tscn", "res://Physics/2D/Physics2D.tscn", "res://Physics/3D/Physics3D.tscn", "res://Rendering/Lights2D/Lights2D.tscn", @@ -30,8 +27,8 @@ const alone_steps : Array = [ # This should be put regression scripts which needs to run only once const all_in_one : Array = [ "res://AIO/Operators/Operators.tscn", -"res://AutomaticBugs/RealFunctionExecutor.tscn", -#"res://AIO/AllNodes/ALL.tscn", +"res://AutomaticBugs/FunctionExecutor.tscn", +#"res://AIO/AllNodes/ALL.tscn", # Take too much time - opens ~ 20 seconds in CI inside xvfb-run ] func _init(): diff --git a/AutomaticBugs/BasicData.gd b/AutomaticBugs/BasicData.gd index 043f8a2..6f26929 100644 --- a/AutomaticBugs/BasicData.gd +++ b/AutomaticBugs/BasicData.gd @@ -1,6 +1,6 @@ extends Node -var function_exceptions = [ +var function_exceptions : Array = [ # 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 "align",# GH 45976 "_screen_pick_pressed",# GH 45977 @@ -37,47 +37,117 @@ var function_exceptions = [ "_edit_set_position", #GH 46018 "_edit_set_rect", #GH 46018 "get", #GH 46019 -"instance_has", #GH -"", #GH -"", #GH -"", #GH -"", #GH -"", #GH +"instance_has", #GH 46020 +"_update_shader", #GH 46062 +"generate_tangents", #GH 46059 +"get_var", #GH 46096 +"force_drag", #GH 46114 +"set_script", #GH 46120 +"getvar", #GH 46019 +"get_available_chars", #GH 46118 +"set_primary_interface", #GH 46180 +"add_feed", #GH 46181 +"open_midi_inputs", #GH 46183 +"get_unix_time_from_datetime", #GH 46188 +"set_icon", #GH 46189 +"set_window_size", #GH 46187 +"get_screen_size", #GH 46186 +"get_screen_position", #GH 46185 +"set_current_screen", #GH 46184 +"build_capsule_planes", #GH +"build_cylinder_planes", #GH +"get_latin_keyboard_variant", #GH TODO Memory Leak +"add_feed", #GH +"poll", #GH - HTTP CLIENT +"make_atlas", #GH +"set_editor_hint", #GH "", #GH - -# TODO is workaround for removing memory leak in Thread::start, should be fixed by GH 45618 -"start", +"collide", #GH 46137 +"collide_and_get_contacts", #GH 46137 +"collide_with_motion", #GH 46137 +"collide_with_motion_and_get_contacts", #GH 46137 -# TODO Adds big spam when i>100 +# TODO Check this later +"propagate_notification", +"notification", + +# TODO Adds big spam when i>100 - look for possiblity to "add_sphere", +# Spam when i~1000 - change to specific +"update_bitmask_region", + +# Slow Function +"_update_sky", + +# Undo/Redo function which doesn't provide enough information about types of objects, probably due vararg(variable size argument) +"add_do_method", +"add_undo_method", # Do not save files and create files and folders +"pck_start", "save", "save_png", "save_to_wav", "save_to_file", "make_dir", "make_dir_recursive", +"save_encrypted", +"save_encrypted_pass", +"dump_resources_to_file", +"dump_memory_to_file", +# This also allow to save files +"open", +"open_encrypted", +"open_encrypted_with_pass", +"open_compressed", # Do not warp mouse "warp_mouse", "warp_mouse_position", -# Looks like a bug in FuncRef, probably but not needed -"call_func", +# OS +"kill", +"shell_open", +"execute", +"delay_usec", +"delay_msec", +"alert", # Stupid alert window opens # Godot Freeze +"wait_to_finish", +"accept_stream", +"connect_to_stream", "discover", "wait", -"register_text_enter", + +"_create", # TODO Check + + +"set_gizmo", # Stupid function, needs as parameter an object which can't be instanced # TODO, create issue to hide it + +# Spams Output +"print_tree", +"print_stray_nodes", +"print_tree_pretty", +"print_all_textures_by_size", +"print_all_resources", +"print_resources_in_use", # Do not call other functions "_call_function", "call", "call_deferred", +"callv", +# Looks like a bug in FuncRef, probably but not needed, because it call other functions +"call_func", # Too dangerous, because add, mix and remove randomly nodes and objects +"replace_by", +"create_instance", +"set_owner", +"set_root_node", +"instance", "init_ref", "reference", "unreference", @@ -85,39 +155,96 @@ var function_exceptions = [ "duplicate", "queue_free", "free", -"print_tree", -"print_stray_nodes", -"print_tree_pretty", "remove_and_skip", "remove_child", "move_child", "raise", "add_child", "add_child_below_node", + +] + +# List of slow functions, which may frooze project +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", + "", +] + +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 + "SceneTree", # Broke camera visibility ] # Return all available classes to instance and test func get_list_of_available_classes() -> Array: - var debug_print : bool = false var full_class_list : Array = Array(ClassDB.get_class_list()) var classes : Array = [] full_class_list.sort() var c = 0 + var rr = 0 for name_of_class in full_class_list: - if name_of_class == "AudioServer": # Crash GH #45972 - continue - if name_of_class == "NetworkedMultiplayerENet": # TODO - create leaked reference instance, look at it later + rr += 1 + if name_of_class in disabled_classes: continue - if ClassDB.is_parent_class(name_of_class,"Node") or ClassDB.is_parent_class(name_of_class,"Reference"): # Only instance childrens of this - if debug_print: - print(name_of_class) - if ClassDB.can_instance(name_of_class): - classes.push_back(name_of_class) - c+= 1 - else: - if debug_print: - push_error("Failed to instance " + str(name_of_class) ) - + if name_of_class.find("Server") != -1: + continue + + if !ClassDB.is_parent_class(name_of_class, "Node") && !ClassDB.is_parent_class(name_of_class, "Reference"): + continue + + if ClassDB.can_instance(name_of_class): + classes.push_back(name_of_class) + c+= 1 + print(str(c) + " choosen classes from all " + str(full_class_list.size()) + " classes.") return classes diff --git a/AutomaticBugs/RealFunctionExecutor.gd b/AutomaticBugs/FunctionExecutor.gd similarity index 52% rename from AutomaticBugs/RealFunctionExecutor.gd rename to AutomaticBugs/FunctionExecutor.gd index f2bea52..15865fe 100644 --- a/AutomaticBugs/RealFunctionExecutor.gd +++ b/AutomaticBugs/FunctionExecutor.gd @@ -1,86 +1,85 @@ extends Node +var debug_print: bool = true +var add_to_tree: bool = true # Adds nodes to tree +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 + func _ready() -> void: -# NoiseTexture::_thread_done -# var aa = BoxShape.new() -# SurfaceTool.new().create_from(aa,0) -# Tree.new().get_column_width(0) tests_all_functions() - -# TODO - Think about adding 'add_child', to test nodes in scene tree -# Test all functions which takes 0 arguments +# Test all functions func tests_all_functions() -> void: - var debug_print : bool = false - var use_parent_methods : bool = false # Allows Node2D use Node methods etc. - it is a little slow option - var number_of_loops : int = 1 # Can be executed in multiple loops - var use_always_new_object : bool = true # Don't allow to "remeber" other function effects - -# var sss = 0 for name_of_class in BasicData.get_list_of_available_classes(): - if name_of_class.begins_with("_"): # TODO builtin classes like _Dictionary doesn't work properly in GDScript + if name_of_class == "_OS": # Do not change size of window continue -# sss += 1 -# if sss != 220: -# continue + # Instance object to be able to execute on it specific functions and later delete to prevent memory leak if it is a Node - var object : Object = ClassDB.instance(name_of_class) -# if object is Node: -# add_child(object) - assert(object != null) # This should be checked before when collectiong functions - var method_list : Array = ClassDB.class_get_method_list(name_of_class, !use_parent_methods) + var object: Object = ClassDB.instance(name_of_class) + assert(object != null) # This should be checked before when collectiong functions + 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 + 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) - - - for _i in range(number_of_loops): - for method_data in method_list: - # Function is virtual, so we just skip it - if method_data["flags"] == method_data["flags"] | METHOD_FLAG_VIRTUAL: - continue - - if debug_print: - print("##### - " + name_of_class) -# print(method_data) - print(method_data["name"]) -# print(method_data["args"]) - - var arguments : Array = return_for_all(method_data) - object.callv(method_data["name"], arguments) - - for argument in arguments: - if argument is Node: - argument.queue_free() - - if use_always_new_object: - if object is Node: - object.queue_free() - object = ClassDB.instance(name_of_class) - if object is Node: # Just prevent memory leak - object.queue_free() -# TODO add option to generate random data or only basic data e.g. Vector2() instead Vector(2.52,525.2) -func return_for_all(method_data : Dictionary) -> Array: - var arguments_array : Array = [] - + if debug_print: + print("############### CLASS ############### - " + name_of_class) + + for method_data in method_list: + # Function is virtual, so we just skip it + if method_data["flags"] == method_data["flags"] | METHOD_FLAG_VIRTUAL: + continue + + if debug_print: + print(method_data["name"]) + + var arguments: Array = return_for_all(method_data) + object.callv(method_data["name"], arguments) + + for argument in arguments: + assert(argument != null) + if argument is Node: + argument.queue_free() + elif argument is Object && ! (argument is Reference): + argument.free() + + if use_always_new_object: + assert(object != null) + if object is Node: + object.queue_free() + elif object is Object && ! (object is Reference): + object.free() + + object = ClassDB.instance(name_of_class) + + if object is Node: # Just prevent memory leak + object.queue_free() + elif object is Object && ! (object is Reference): + object.free() + + +func return_for_all(method_data: Dictionary) -> Array: + var arguments_array: Array = [] + ValueCreator.number = 10 ValueCreator.random = false - + ValueCreator.should_be_always_valid = false + for argument in method_data["args"]: -# print(argument) match argument.type: - TYPE_NIL: # Looks that this means VARIANT not null - arguments_array.push_back(false) # TODO Add some randomization -# assert(false) - TYPE_MAX: - assert(false) + TYPE_NIL: # Looks that this means VARIANT not null + arguments_array.push_back(false) # TODO randomize this TYPE_AABB: arguments_array.push_back(ValueCreator.get_aabb()) TYPE_ARRAY: @@ -102,7 +101,7 @@ func return_for_all(method_data : Dictionary) -> Array: TYPE_NODE_PATH: arguments_array.push_back(ValueCreator.get_nodepath()) TYPE_OBJECT: - arguments_array.push_back(ValueCreator.get_object("TODO")) # Maybe add a proper type variable if needed + arguments_array.push_back(ValueCreator.get_object(argument["class_name"])) TYPE_PLANE: arguments_array.push_back(ValueCreator.get_plane()) TYPE_QUAT: @@ -134,8 +133,8 @@ func return_for_all(method_data : Dictionary) -> Array: TYPE_VECTOR3_ARRAY: arguments_array.push_back(ValueCreator.get_pool_vector3_array()) _: - assert(false) # Missed some types, add it - -# print("Parameters " + str(arguments_array)) + assert(false) # Missed some types, add it + + if debug_print: + print("Parameters " + str(arguments_array)) return arguments_array - diff --git a/AutomaticBugs/FunctionExecutor.tscn b/AutomaticBugs/FunctionExecutor.tscn new file mode 100644 index 0000000..98ff9eb --- /dev/null +++ b/AutomaticBugs/FunctionExecutor.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://AutomaticBugs/FunctionExecutor.gd" type="Script" id=1] + +[node name="FunctionExecutor" type="Node2D"] +script = ExtResource( 1 ) diff --git a/AutomaticBugs/RealFunctionExecutor.tscn b/AutomaticBugs/RealFunctionExecutor.tscn deleted file mode 100644 index 7e06e8c..0000000 --- a/AutomaticBugs/RealFunctionExecutor.tscn +++ /dev/null @@ -1,6 +0,0 @@ -[gd_scene load_steps=2 format=2] - -[ext_resource path="res://AutomaticBugs/RealFunctionExecutor.gd" type="Script" id=1] - -[node name="RealFunctionExecutor" type="Node2D"] -script = ExtResource( 1 ) diff --git a/AutomaticBugs/ValueCreator.gd b/AutomaticBugs/ValueCreator.gd index 04c0083..3b3e15d 100644 --- a/AutomaticBugs/ValueCreator.gd +++ b/AutomaticBugs/ValueCreator.gd @@ -1,9 +1,15 @@ extends Node -var number : float = 0.0 -var random : bool = false +var number: float = 0.0 +var random: bool = false +var should_be_always_valid: bool = true # Generate only valid values e.g. to Node generate Node2D instead + +var max_array_size: int = 15 + + +func _ready() -> void: + randomize() -var max_array_size : int = 15 func get_int() -> int: if random: @@ -12,27 +18,31 @@ func get_int() -> int: return (randi() % int(number)) - int(number / 2.0) else: return int(number) - + + func get_int_string() -> String: if random: if int(number) == 0: return "0" - return "(randi() % int(number)) - int(number / 2.0)".replace("number",str(number)) + return "(randi() % int(number)) - int(number / 2.0)".replace("number", str(number)) else: return str(int(number)) + func get_float() -> float: if random: return (randf() * number) - (number / 2.0) else: return number - + + func get_float_string() -> String: if random: return "(randf() * number) - (number / 2.0)".replace("number", str(number)) else: return str(number) + func get_bool() -> bool: if random: if number < 2: @@ -40,7 +50,8 @@ func get_bool() -> bool: return bool(randi() % 2) else: return bool() - + + func get_bool_string() -> String: if random: if number < 2: @@ -49,66 +60,126 @@ func get_bool_string() -> String: else: return str(bool()) + func get_vector2() -> Vector2: return Vector2(get_float(), get_float()) - + + func get_vector2_string() -> String: return "Vector2(" + get_float_string() + ", " + get_float_string() + ")" - + + +func get_vector2_string_csharp() -> String: + return "new Vector2(" + get_float_string() + ", " + get_float_string() + ")" + + func get_vector3() -> Vector3: - return Vector3(get_float(),get_float(),get_float()) - + return Vector3(get_float(), get_float(), get_float()) + + func get_vector3_string() -> String: return "Vector3(" + get_float_string() + ", " + get_float_string() + ", " + get_float_string() + ")" - + + +func get_vector3_string_csharp() -> String: + return "new Vector3(" + get_float_string() + ", " + get_float_string() + ", " + get_float_string() + ")" + + func get_aabb() -> AABB: - return AABB(get_vector3(),get_vector3()) - + return AABB(get_vector3(), get_vector3()) + + func get_aabb_string() -> String: return "AABB(" + get_vector3_string() + ", " + get_vector3_string() + ")" - + + +func get_aabb_string_csharp() -> String: + return "new AABB(" + get_vector3_string_csharp() + ", " + get_vector3_string_csharp() + ")" + + func get_transform() -> Transform: - return Transform(get_vector3(),get_vector3(),get_vector3(),get_vector3()) - + return Transform(get_vector3(), get_vector3(), get_vector3(), get_vector3()) + + func get_transform_string() -> String: return "Transform(" + get_vector3_string() + ", " + get_vector3_string() + ", " + get_vector3_string() + ", " + get_vector3_string() + ")" - + + +func get_transform_string_csharp() -> String: + return "new Transform(" + get_vector3_string_csharp() + ", " + get_vector3_string_csharp() + ", " + get_vector3_string_csharp() + ", " + get_vector3_string() + ")" + + func get_transform2D() -> Transform2D: - return Transform2D(get_vector2(),get_vector2(),get_vector2()) - + return Transform2D(get_vector2(), get_vector2(), get_vector2()) + + func get_transform2D_string() -> String: - return "Transform2D(" + get_vector2_string() + ", " + get_vector2_string()+ ", " + get_vector2_string() + ")" - + return "Transform2D(" + get_vector2_string() + ", " + get_vector2_string() + ", " + get_vector2_string() + ")" + + +func get_transform2D_string_csharp() -> String: + return "new Transform2D(" + get_vector2_string_csharp() + ", " + get_vector2_string_csharp() + ", " + get_vector2_string_csharp() + ")" + func get_plane() -> Plane: - return Plane(get_vector3(),get_vector3(),get_vector3()) - + return Plane(get_vector3(), get_vector3(), get_vector3()) + + func get_plane_string() -> String: - return "Plane(" + get_vector3_string() + ", " + get_vector3_string()+ ", " + get_vector3_string() + ")" - + return "Plane(" + get_vector3_string() + ", " + get_vector3_string() + ", " + get_vector3_string() + ")" + + +func get_plane_string_csharp() -> String: + return "new Plane(" + get_vector3_string_csharp() + ", " + get_vector3_string_csharp() + ", " + get_vector3_string_csharp() + ")" + + func get_quat() -> Quat: return Quat(get_vector3()) - + + func get_quat_string() -> String: return "Quat(" + get_vector3_string() + ")" - + + +func get_quat_string_csharp() -> String: + return "new Quat(" + get_vector3_string_csharp() + ")" + + func get_basis() -> Basis: return Basis(get_vector3()) - + + func get_basis_string() -> String: return "Basis(" + get_vector3_string() + ")" - + + +func get_basis_string_csharp() -> String: + return "new Basis(" + get_vector3_string_csharp() + ")" + + func get_rect2() -> Rect2: return Rect2(get_vector2(), get_vector2()) - + + func get_rect2_string() -> String: - return "Rect2(" + get_vector2_string() + ", " + get_vector2_string()+ ")" - + return "Rect2(" + get_vector2_string() + ", " + get_vector2_string() + ")" + + +func get_rect2_string_csharp() -> String: + return "new Rect2(" + get_vector2_string_csharp() + ", " + get_vector2_string_csharp() + ")" + + func get_color() -> Color: - return Color(get_float(), get_float(),get_float()) - + return Color(get_float(), get_float(), get_float()) + + func get_color_string() -> String: - return "Color(" + get_float_string() + ", " + get_float_string()+ ", " + get_float_string() + ")" + return "Color(" + get_float_string() + ", " + get_float_string() + ", " + get_float_string() + ")" + + +func get_color_string_csharp() -> String: + return "new Color(" + get_float_string() + ", " + get_float_string() + ", " + get_float_string() + ")" + # TODO func get_string() -> String: @@ -118,82 +189,200 @@ func get_string() -> String: else: return str(randi()) return String() - + + func get_string_string() -> String: if random: - if randi() % 2 == 0: + if randi() % 3 == 0: return "\".\"" + elif randi() % 3 == 0: + return "\"\"" else: - return "\"randi())\"" + return "str(randi() / 100)" return "\"\"" + + # TODO func get_nodepath() -> NodePath: return NodePath(get_string()) + + +# TODO +func get_nodepath_string_csharp() -> String: + return "new NodePath(\".\")" + + # TODO func get_array() -> Array: - var array : Array = [] - for _i in range(int(min(max_array_size,number))): + var array: Array = [] + for _i in range(int(min(max_array_size, number))): array.append([]) return Array([]) + + # TODO func get_dictionary() -> Dictionary: return Dictionary({}) - - + + func get_pool_string_array() -> PoolStringArray: - var array : Array = [] - for _i in range(int(min(max_array_size,number))): + var array: Array = [] + for _i in range(int(min(max_array_size, number))): array.append(get_string()) return PoolStringArray(array) - + + func get_pool_int_array() -> PoolIntArray: - var array : Array = [] - for _i in range(int(min(max_array_size,number))): + var array: Array = [] + for _i in range(int(min(max_array_size, number))): array.append(get_int()) return PoolIntArray(array) - + + func get_pool_byte_array() -> PoolByteArray: - var array : Array = [] - for _i in range(int(min(max_array_size,number))): + var array: Array = [] + for _i in range(int(min(max_array_size, number))): array.append(get_int()) return PoolByteArray(array) - + + func get_pool_real_array() -> PoolRealArray: - var array : Array = [] - for _i in range(int(min(max_array_size,number))): + var array: Array = [] + for _i in range(int(min(max_array_size, number))): array.append(get_float()) return PoolRealArray(array) - + + func get_pool_vector2_array() -> PoolVector2Array: - var array : Array = [] - for _i in range(int(min(max_array_size,number))): + var array: Array = [] + for _i in range(int(min(max_array_size, number))): array.append(get_vector2()) return PoolVector2Array(array) - + + func get_pool_vector3_array() -> PoolVector3Array: - var array : Array = [] - for _i in range(int(min(max_array_size,number))): + var array: Array = [] + for _i in range(int(min(max_array_size, number))): array.append(get_vector3()) return PoolVector3Array(array) - + + func get_pool_color_array() -> PoolColorArray: - var array : Array = [] - for _i in range(int(min(max_array_size,number))): + var array: Array = [] + for _i in range(int(min(max_array_size, number))): array.append(get_color()) return PoolColorArray(array) - -func get_object(object_name : String) -> Object: + +func get_object(object_name: String) -> Object: + assert(ClassDB.class_exists(object_name)) + + var a = 0 if random: - var classes = ClassDB.get_class_list() - while true: - var choosen_class : String = classes[randi()%classes.size()] - if ClassDB.is_class(choosen_class) && ClassDB.can_instance(choosen_class) && (ClassDB.is_parent_class(choosen_class,"Node")||(ClassDB.is_parent_class(choosen_class,"Reference"))): - return ClassDB.instance(choosen_class) + var classes = ClassDB.get_inheriters_from_class("Node") + ClassDB.get_inheriters_from_class("Reference") + + if object_name == "Object": + while true: + var choosen_class: String = classes[randi() % classes.size()] + if ( + ClassDB.can_instance(choosen_class) + && (ClassDB.is_parent_class(choosen_class, "Node") || ClassDB.is_parent_class(choosen_class, "Reference")) + && ! (choosen_class in BasicData.disabled_classes) + ): + return ClassDB.instance(choosen_class) + + if ClassDB.is_parent_class(object_name, "Node") || ClassDB.is_parent_class(object_name, "Reference"): + if should_be_always_valid: + var to_use_classes = ClassDB.get_inheriters_from_class(object_name) + to_use_classes.append(object_name) + if ! ClassDB.can_instance(object_name) && object_name in BasicData.disabled_classes: + assert(to_use_classes.size() > 0) + + while true: + a += 1 + if a > 50: + # Object doesn't have children which can be instanced + # This shouldn't happens, but sadly happen with e.g. SpatialGizmo + assert(false) + var choosen_class: String = to_use_classes[randi() % to_use_classes.size()] + if ClassDB.can_instance(choosen_class) && ! (choosen_class in BasicData.disabled_classes): + return ClassDB.instance(choosen_class) + else: + while true: + a += 1 + if a > 50: + assert(false) + var choosen_class: String = classes[randi() % classes.size()] + if ClassDB.can_instance(choosen_class) && ! ClassDB.is_parent_class(choosen_class, object_name) && ! (choosen_class in BasicData.disabled_classes): + return ClassDB.instance(choosen_class) + assert(false) # Other argument types are not supported + else: - if ClassDB.is_class(object_name) && ClassDB.can_instance(object_name): + if ClassDB.can_instance(object_name): # E.g. Texture is not instantable or shouldn't be, but LargeTexture is return ClassDB.instance(object_name) - else: - return BoxShape.new() - + else: # Found child of non instantable object + var list_of_class = ClassDB.get_inheriters_from_class(object_name) + assert(list_of_class.size() > 0) # Number of inherited class of non instantable class must be greater than 0, otherwise this function would be useless + for i in list_of_class: + if ClassDB.can_instance(i) && (ClassDB.is_parent_class(i, "Node") || ClassDB.is_parent_class(i, "Reference")): + return ClassDB.instance(i) + assert(false) + + assert(false) return BoxShape.new() + + +# TODO Update this with upper implementation +func get_object_string(object_name: String) -> String: + assert(ClassDB.class_exists(object_name)) + + var a = 0 + if random: + var classes = ClassDB.get_inheriters_from_class("Node") + ClassDB.get_inheriters_from_class("Reference") + + if object_name == "Object": + while true: + var choosen_class: String = classes[randi() % classes.size()] + if ClassDB.can_instance(choosen_class) && (ClassDB.is_parent_class(choosen_class, "Node") || ClassDB.is_parent_class(choosen_class, "Reference")): + return choosen_class + + if ClassDB.is_parent_class(object_name, "Node") || ClassDB.is_parent_class(object_name, "Reference"): + if should_be_always_valid: + var to_use_classes = ClassDB.get_inheriters_from_class(object_name) + to_use_classes.append(object_name) + if ! ClassDB.can_instance(object_name): + assert(to_use_classes.size() > 0) + + while true: + a += 1 + if a > 30: + # Object doesn't have children which can be instanced + # This shouldn't happens, but sadly happen with e.g. SpatialGizmo + assert(false) + var choosen_class: String = to_use_classes[randi() % to_use_classes.size()] + if ClassDB.can_instance(choosen_class): + return choosen_class + else: + while true: + a += 1 + if a > 30: + assert(false) + var choosen_class: String = classes[randi() % classes.size()] + if ! ClassDB.is_parent_class(choosen_class, object_name): + return choosen_class + + assert(false) # Other argument types are not supported + + else: + if ClassDB.can_instance(object_name): # E.g. Texture is not instantable or shouldn't be, but LargeTexture is + return object_name + else: # Found child of non instantable object + var list_of_class = ClassDB.get_inheriters_from_class(object_name) + assert(list_of_class.size() > 0) # Number of inherited class of non instantable class must be greater than 0, otherwise this function would be useless + for i in list_of_class: + if ClassDB.can_instance(i) && (ClassDB.is_parent_class(i, "Node") || ClassDB.is_parent_class(i, "Reference")): + return i + assert(false) + + assert(false) + return "BoxMesh" diff --git a/MainScenes/MainScenes.tscn b/MainScenes/MainScenes.tscn new file mode 100644 index 0000000..81e1bd5 --- /dev/null +++ b/MainScenes/MainScenes.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://MainScenes/Spatial.tscn" type="PackedScene" id=1] +[ext_resource path="res://MainScenes/Other.tscn" type="PackedScene" id=2] +[ext_resource path="res://MainScenes/Control.tscn" type="PackedScene" id=3] +[ext_resource path="res://MainScenes/Node2D.tscn" type="PackedScene" id=4] + +[node name="MainScenes" type="Node"] + +[node name="GridContainer" parent="." instance=ExtResource( 3 )] + +[node name="Node2D" parent="." instance=ExtResource( 4 )] + +[node name="Node" parent="." instance=ExtResource( 2 )] + +[node name="Spatial" parent="." instance=ExtResource( 1 )] diff --git a/README.md b/README.md index 7378f27..ed42efc 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@ It aims to be complex project, which will allow to find crashes, leaks and inval Sadly it can't find automatically any logic errors. ## Reproduce bugs -If CI find bug, you can easily without much effort check which scene cause problems. +If CI find bug, you can easily without much effort check which scene cause problems(stacktrace, address or leak sanitizer log will be available). -Each scene is independent of the other, so it is easy to disable some for testing. +All main scenes are independent of each other(only `Autoload.gd` is required), so it is easy to disable some for testing. To create minimal test scene: - Look at the console output - there is printed info about current used scene @@ -24,7 +24,7 @@ When opening any scene, automatically time to exit is set. If running projet with e.g. this parameters ``` -godot 20 -v +godot 20 ``` Then time is set to 20 seconds so it means that if scenes is 10 (EACH in `alone_steps` array + one for ALL scenes in `all_in_one` array), then each scene will be show for 2 seconds @@ -33,18 +33,32 @@ There are two scenes which opens all scenes: - All.tscn - opens all scenes at once - Start.tscn - opens each scene one by one +### "Safe" Fuzzer +Available inside `AutomaticBugs` directory, check all methods with specific arguments in allowed classes. +During calculations, to output should be written informations about current classes and executed functions with arguments e.g. +``` +############### CLASS ############### - PopupMenu +add_icon_radio_check_shortcut +Parameters [[InputEventMouseMotion:12379], [SoftBody:12380], -109, True] +``` +This fuzzer should in most situations be safe to use, because always use same set of arguments in functions, and objects are cleared before executing next function. + +This tool is developed in external repository - https://github.com/qarmin/Qarminer. + ### AIO -This are scenes which only opens once, because there is no need to open it more times(no scripts or only with `_ready` function). +This are scenes which only opens once, because there is no need to open it more times - used to check loading of specific types of nodes or executing its `_ready` functions. + +### MainScenes +Collections of all nodes, which are after some time simply removed and added to scene. + +### ReparentingDeleting +This scene randomly reparent, add or delete nodes inside it, to check correctness this operations. ### Other Scenes -Each other scenes checks specific types of nodes like lights, rendering, physics, text or reparenting. - -## Contributions -Contributions are welcome. - -For now there is no requirements to format code. - -New functionalities(e.g. physics checks) should be done in different folders(cleaner view to resources) +Each other scenes checks specific types of nodes like lights, rendering, physics, text. ## 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. + +## Problems with project +If you have problem with this project e.g. in CI, just ping me -> @qarmin <- and after that I will try help to fix issues which you have with it or add exception to project. diff --git a/project.godot b/project.godot index 917e1f8..e801eba 100644 --- a/project.godot +++ b/project.godot @@ -34,6 +34,10 @@ BasicData="*res://AutomaticBugs/BasicData.gd" gdscript/warnings/enable=false gdscript/warnings/standalone_expression=false +[logging] + +file_logging/enable_file_logging.pc=false + [memory] limits/message_queue/max_size_kb=131072