Clean 3.x branch (#65)

This commit is contained in:
Rafał Mikrut 2022-01-05 19:35:38 +01:00 committed by GitHub
parent e59d9cb011
commit 1aff26a273
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 228 additions and 713 deletions

View File

@ -27,6 +27,7 @@ jobs:
libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev yasm \
xvfb wget2 unzip python scons git
# Allows to test project with precompiled binaries
# - name: Download Godot
# run: |
# wget2 https://downloads.tuxfamily.org/godotengine/3.2.4/beta1/Godot_v3.2.4-beta1_x11.64.zip
@ -63,11 +64,11 @@ jobs:
- name: Test project
run: |
DRI_PRIME=0 xvfb-run ./godot.x11.tools.64s 60 --audio-driver Dummy --video-driver GLES3 --path $(pwd) 2>&1 | tee sanitizers_log.txt || true
DRI_PRIME=0 xvfb-run ./godot.x11.tools.64s 180 --audio-driver Dummy --video-driver GLES3 --path $(pwd) 2>&1 | tee sanitizers_log.txt || true
misc/check_ci_log.py sanitizers_log.txt
- uses: actions/upload-artifact@v2
with:
name: ${{ github.job }}
path: godot.x11.tools.64s
retention-days: 14
# - uses: actions/upload-artifact@v2
# with:
# name: ${{ github.job }}
# path: godot.x11.tools.64s
# retention-days: 14

View File

@ -20,21 +20,22 @@ const alone_steps: Array = [
"res://Nodes/Nodes.tscn",
"res://Physics/2D/Physics2D.tscn",
"res://Physics/3D/Physics3D.tscn",
"res://ReparentingDeleting/ReparentingDeleting.tscn",
"res://AutomaticBugs/FunctionExecutor.tscn", # Only runs
# "res://ReparentingDeleting/ReparentingDeleting.tscn", Not always reproducible
"res://AutomaticBugs/FunctionExecutor.tscn", # Only need to run once
]
var time_object : Object
var time_object: Object
func _init():
# Workaround for Time/OS breaking change - https://github.com/godotengine/godot/pull/54056
if ClassDB.class_exists("_Time"):
time_object = ClassDB.instance("_Time")
elif ClassDB.class_exists("Time"):
time_object = ClassDB.instance("Time")
else:
time_object = ClassDB.instance("_OS")
start_time = time_object.get_ticks_msec()
# In case when user doesn't provide time
@ -45,13 +46,13 @@ func _init():
time_to_show = int(argument.to_float() * 1000)
time_for_each_step = time_to_show / (alone_steps.size())
print("Time set to: " + str(time_to_show / 1000.0) + " seconds with " + str(alone_steps.size()) + " steps, each step will take " + str(time_for_each_step / 1000.0) + " seconds.")
break # We only need to take first argument
break # We only need to take first numeric argument
func _process(delta: float) -> void:
var current_run_time: int = time_object.get_ticks_msec() - start_time
# While loop instead if, will allow to properly flush results under heavy operations(e.g. Thread sanitizer)
# While loop instead simple if, because will allow to properly flush results under heavy operations(e.g. Thread sanitizer)
while current_run_time > time_to_print_next_time:
print("Test is running now " + str(int(time_to_print_next_time / 1000)) + " seconds")
time_to_print_next_time += PRINT_TIME_EVERY_MILISECONDS
@ -59,6 +60,7 @@ func _process(delta: float) -> void:
if current_run_time > time_to_show && can_be_closed:
print("######################## Ending test ########################")
get_tree().quit()
func _exit_tree() -> void:
time_object.free()

View File

@ -1,71 +1,61 @@
extends Node
var regression_test_project : bool = true # Set it to true in RegressionTestProject
### Contains info about disabled classes and allows to take info about allowed methods
# Globablly disabled functions for all classes
var function_exceptions : Array = [
"get_packet", # TODO
"_gui_input", # TODO probably missing cherrypick #GH 47636
"_input",
"_unhandled_input",
"_unhandled_key_input",
"connect_to_signal", # Should be chrrypicked
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
#"connect_to_signal", # GH 47572
"_editor_settings_changed",# GH 45979
"_submenu_timeout", # GH 45981
"_thread_done", #GH 46000
"generate", #GH 46001
"_proximity_group_broadcast", #GH 46002
"_direct_state_changed", #GH 46003
"create_from", #GH 46004
"create_from_blend_shape", #GH 46004
"append_from", #GH 46004
"_set_tile_data", #GH 46015
"get", #GH 46019
"instance_has", #GH 46020
"get_var", #GH 46096
"set_script", #GH 46120
"getvar", #GH 46019
"get_available_chars", #GH 46118
"open_midi_inputs", #GH 46183
"set_icon", #GH 46189
"get_latin_keyboard_variant", #GH TODO Memory Leak
"set_editor_hint", #GH 46252
"get_item_at_position", #TODO hard to find
"set_probe_data", #GH 46570
"_range_click_timeout", #GH 46648
"get_indexed", #GH 46019
"add_vertex", #GH 47066
"create_client", # TODO, strange memory leak
"create_shape_owner", #47135
"shape_owner_get_owner", #47135
"get_bind_bone", #GH 47358
"get_bind_name", #GH 47358
"get_bind_pose", #GH 47358
# TODO Check this later
"get_packet", # TODO
"_gui_input", # TODO probably missing cherrypick #GH 47636
"_input",
"_unhandled_input",
"_unhandled_key_input",
"connect_to_signal", # Should be chrrypicked
"_editor_settings_changed", # GH 45979
"_submenu_timeout", # GH 45981
"_thread_done", #GH 46000
"generate", #GH 46001
"_proximity_group_broadcast", #GH 46002
"_direct_state_changed", #GH 46003
"create_from", #GH 46004
"create_from_blend_shape", #GH 46004
"append_from", #GH 46004
"_set_tile_data", #GH 46015
"get", #GH 46019
"instance_has", #GH 46020
"get_var", #GH 46096
"set_script", #GH 46120
"getvar", #GH 46019
"get_available_chars", #GH 46118
"open_midi_inputs", #GH 46183
"set_icon", #GH 46189
"get_latin_keyboard_variant", #GH TODO Memory Leak
"set_editor_hint", #GH 46252
"get_item_at_position", #TODO hard to find
"set_probe_data", #GH 46570
"_range_click_timeout", #GH 46648
"get_indexed", #GH 46019
"add_vertex", #GH 47066
"create_client", # TODO, strange memory leak
"create_shape_owner", #47135
"shape_owner_get_owner", #47135
"get_bind_bone", #GH 47358
"get_bind_name", #GH 47358
"get_bind_pose", #GH 47358
# Not worth using
"propagate_notification",
"notification",
# TODO Adds big spam when i>100 - look for possiblity to
# TODO Adds big spam when i>100 - look for possiblity to
"add_sphere",
"_update_inputs", # Cause big spam with add_input
# Spam when i~1000 - change to specific
"_update_inputs", # Cause big spam with add_input
# Spam when i~1000 - change to specific
"update_bitmask_region",
"set_enabled_inputs",
# 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",
@ -84,19 +74,16 @@ var function_exceptions : Array = [
"open_encrypted",
"open_encrypted_with_pass",
"open_compressed",
# Do not warp mouse
"warp_mouse",
"warp_mouse_position",
# OS
"kill",
"shell_open",
"execute",
"delay_usec",
"delay_msec",
"alert", # Stupid alert window opens
"alert", # Stupid alert window opens
# Godot Freeze
"wait_to_finish",
"accept_stream",
@ -105,12 +92,8 @@ var function_exceptions : Array = [
"wait",
"debug_bake",
"bake",
"_create", # TODO Check
"set_gizmo", # Stupid function, needs as parameter an object which can't be instanced # TODO, create issue to hide it
"_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",
@ -118,7 +101,6 @@ var function_exceptions : Array = [
"print_all_textures_by_size",
"print_all_resources",
"print_resources_in_use",
# Do not call other functions
"_call_function",
"call",
@ -126,7 +108,6 @@ var function_exceptions : Array = [
"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",
@ -149,13 +130,12 @@ var function_exceptions : Array = [
"add_sibling",
]
# 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
"_OS", # This may sometimes crash compositor, but it should be tested manually sometimes
"GDScript", # Broke script
# Globally disabled classes which causes bugs or are very hard to use properly
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
"_OS", # This may sometimes crash compositor, but it should be tested manually sometimes
"GDScript", # Broke scripts
# This classes have problems with static/non static methods
"PhysicsDirectSpaceState",
"Physics2DDirectSpaceState",
@ -170,54 +150,79 @@ var disabled_classes : Array = [
"NavigationAgent2D",
"NavigationAgent",
# Only one class - JavaClass returns Null when using JavaClass.new().get_class
# Only one class - JavaClass returns Null when using JavaClass.new().get_class()
"JavaClass",
# Just don't use these because they are not normal things
# Just don't use these because they are not normal things
"_Thread",
"_Semaphore",
"_Mutex",
]
# Checks if function can be executed
# Looks at its arguments an
func check_if_is_allowed(method_data : Dictionary) -> bool:
# Looks at its arguments and checks if are recognized and supported
func check_if_is_allowed(method_data: Dictionary) -> bool:
# 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
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"]
var name_of_class: String = arg["class_name"]
if name_of_class.empty():
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"):
if !ClassDB.class_exists(name_of_class):
return false
# Editor stuff usually aren't good choice for arhuments
if !ClassDB.is_parent_class(name_of_class, "Node") && !ClassDB.is_parent_class(name_of_class, "Reference"):
return false
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
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
return true
func remove_disabled_methods(method_list : Array, exceptions : Array) -> void:
# Removes disabled methods from classes
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()):
@ -227,35 +232,30 @@ func remove_disabled_methods(method_list : Array, exceptions : Array) -> void:
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 = []
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
for name_of_class in full_class_list:
# rr += 1
if name_of_class in disabled_classes:
continue
# if rr < 550:
# continue
#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:
if !ClassDB.is_parent_class(name_of_class, "Node") && !ClassDB.is_parent_class(name_of_class, "Reference"):
continue
if !ClassDB.is_parent_class(name_of_class, "Node") && !ClassDB.is_parent_class(name_of_class, "Reference"):
continue
# Don't test Servers objects like TranslationServer
if name_of_class.find("Server") != -1:
continue
# Don't test Editor nodes
if name_of_class.find("Editor") != -1:
continue
if name_of_class.find("Server") != -1 && !ClassDB.is_parent_class(name_of_class,"Reference"):
continue
if name_of_class.find("Editor") != -1 && regression_test_project:
continue
if !must_be_instantable || ClassDB.can_instance(name_of_class):
classes.push_back(name_of_class)
c+= 1
c += 1
print(str(c) + " choosen classes from all " + str(full_class_list.size()) + " classes.")
return classes

View File

@ -6,6 +6,7 @@ extends Node
### - 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
### - removes all objects/nodes to prevent memory leak
var debug_print: bool = true
var add_to_tree: bool = false # Adds nodes to tree, freeze godot when removing a lot of nodes
@ -15,23 +16,9 @@ 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()
if exiting:
get_tree().quit()
tests_all_functions()
# Test all functions
@ -39,7 +26,7 @@ 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:
@ -50,50 +37,49 @@ func tests_all_functions() -> void:
# Removes excluded methods
BasicData.remove_disabled_methods(method_list, BasicData.function_exceptions)
for _i in range(1):
for method_data in method_list:
if !BasicData.check_if_is_allowed(method_data):
continue
for method_data in method_list:
if !BasicData.check_if_is_allowed(method_data):
continue
var arguments: Array = ParseArgumentType.parse_and_return_objects(method_data, name_of_class, debug_print)
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"] + "("
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)
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)
object.callv(method_data["name"], arguments)
object.callv(method_data["name"], arguments)
for argument in arguments:
if argument is Node:
argument.queue_free()
elif argument is Object && !(argument is Reference):
argument.free()
for argument in arguments:
if argument is Node:
argument.queue_free()
elif argument is Object && !(argument is Reference):
argument.free()
if use_always_new_object:
if use_always_new_object:
if object is Node:
object.queue_free()
elif object is Object && !(object is Reference):
object.free()
object = ClassDB.instance(name_of_class)
if add_to_tree:
if object is Node:
object.queue_free()
elif object is Object && !(object is Reference):
object.free()
object = ClassDB.instance(name_of_class)
if add_to_tree:
if object is Node:
add_child(object)
add_child(object)
if object is Node:
object.queue_free()

View File

@ -1,124 +1,5 @@
extends Node
### 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
var value: String # np. randi() % 100 or
var is_object: bool = false # Check if this is object e.g. Node not Vector2
var is_only_object: bool = false # Only needs to freed with .free()
var is_only_reference: bool = false # Don't needs to be removed manually
var is_only_node: bool = false # Needs to be removed with .queue_free()
func create_gdscript_arguments(arguments: Array) -> Array:
var argument_array: Array = []
var counter = 0
for argument in arguments:
counter += 1
var sa: SingleArgument = SingleArgument.new()
sa.name = "variable" + str(counter)
match argument["type"]:
TYPE_NIL: # Looks that this means VARIANT not null
sa.type = "Variant"
sa.value = "false"
TYPE_AABB:
sa.type = "AABB"
sa.value = ValueCreator.get_aabb_string()
TYPE_ARRAY:
sa.type = "Array"
sa.value = "[]"
TYPE_BASIS:
sa.type = "Basis"
sa.value = ValueCreator.get_basis_string()
TYPE_BOOL:
sa.type = "bool"
sa.value = ValueCreator.get_bool_string().to_lower()
TYPE_COLOR:
sa.type = "Color"
sa.value = ValueCreator.get_color_string()
TYPE_COLOR_ARRAY:
sa.type = "PoolColorArray"
sa.value = "PoolColorArray([])"
TYPE_DICTIONARY:
sa.type = "Dictionary"
sa.value = "{}" # TODO Why not all use ValueCreator?
TYPE_INT:
sa.type = "int"
sa.value = ValueCreator.get_int_string()
TYPE_INT_ARRAY:
sa.type = "PoolIntArray"
sa.value = "PoolIntArray([])"
TYPE_NODE_PATH:
sa.type = "NodePath"
sa.value = "NodePath(\".\")"
TYPE_OBJECT:
sa.type = ValueCreator.get_object_string(argument["class_name"])
sa.value = sa.type + ".new()"
sa.is_object = true
if ClassDB.is_parent_class(sa.type, "Node"):
sa.is_only_node = true
elif ClassDB.is_parent_class(sa.type, "Reference"):
sa.is_only_reference = true
else:
sa.is_only_object = true
TYPE_PLANE:
sa.type = "Plane"
sa.value = ValueCreator.get_plane_string()
TYPE_QUAT:
sa.type = "Quat"
sa.value = ValueCreator.get_quat_string()
TYPE_RAW_ARRAY:
sa.type = "PoolByteArray"
sa.value = "PoolByteArray([])"
TYPE_REAL:
sa.type = "float"
sa.value = ValueCreator.get_float_string()
TYPE_REAL_ARRAY:
sa.type = "PoolRealArray"
sa.value = "PoolRealArray([])"
TYPE_RECT2:
sa.type = "Rect2"
sa.value = ValueCreator.get_rect2_string()
TYPE_RID:
sa.type = "RID"
sa.value = "RID()"
TYPE_STRING:
sa.type = "String"
sa.value = ValueCreator.get_string_string()
TYPE_STRING_ARRAY:
sa.type = "PoolStringArray"
sa.value = "PoolStringArray([])"
TYPE_TRANSFORM:
sa.type = "Transform"
sa.value = ValueCreator.get_transform_string()
TYPE_TRANSFORM2D:
sa.type = "Transform2D"
sa.value = ValueCreator.get_transform2D_string()
TYPE_VECTOR2:
sa.type = "Vector2"
sa.value = ValueCreator.get_vector2_string()
TYPE_VECTOR2_ARRAY:
sa.type = "PoolVector2Array"
sa.value = "PoolVector2Array([])"
TYPE_VECTOR3:
sa.type = "Vector3"
sa.value = ValueCreator.get_vector3_string()
TYPE_VECTOR3_ARRAY:
sa.type = "PoolVector3Array"
sa.value = "PoolVector3Array([])"
_:
assert(false, "Missing type, needs to be added to project")
argument_array.append(sa)
return argument_array
func parse_and_return_objects(method_data: Dictionary, name_of_class: String, debug_print: bool = false) -> Array:
var arguments_array: Array = []
@ -126,21 +7,7 @@ func parse_and_return_objects(method_data: Dictionary, name_of_class: String, de
for argument in method_data["args"]:
match argument.type:
TYPE_NIL: # Looks that this means VARIANT not null
if ValueCreator.random == false:
arguments_array.push_back(false)
else:
if randi() % 3:
arguments_array.push_back(ValueCreator.get_array())
elif randi() % 3:
arguments_array.push_back(ValueCreator.get_object("Object"))
elif randi() % 3:
arguments_array.push_back(ValueCreator.get_dictionary())
elif randi() % 3:
arguments_array.push_back(ValueCreator.get_string())
elif randi() % 3:
arguments_array.push_back(ValueCreator.get_int())
else:
arguments_array.push_back(ValueCreator.get_basis())
arguments_array.push_back(false)
TYPE_AABB:
arguments_array.push_back(ValueCreator.get_aabb())
TYPE_ARRAY:
@ -162,13 +29,9 @@ func parse_and_return_objects(method_data: Dictionary, name_of_class: String, de
TYPE_NODE_PATH:
arguments_array.push_back(ValueCreator.get_nodepath())
TYPE_OBJECT:
if ValueCreator.random && randi() % 2:
arguments_array.push_back(null)
else:
var obj: Object = ValueCreator.get_object(argument["class_name"])
arguments_array.push_back(obj)
assert(obj != null, "Failed to create an object of type " + argument["class_name"])
var obj: Object = ValueCreator.get_object(argument["class_name"])
arguments_array.push_back(obj)
assert(obj != null, "Failed to create an object of type " + argument["class_name"])
TYPE_PLANE:
arguments_array.push_back(ValueCreator.get_plane())
TYPE_QUAT:
@ -292,7 +155,7 @@ func return_gdscript_code_which_run_this_object(data) -> String:
&& !ClassDB.is_parent_class(name_of_class, "Reference")
&& !ClassDB.class_has_method(name_of_class, "new")
):
return_string += "ClassDB.instance(\"" + name_of_class + "\")"
return_string += 'ClassDB.instance("' + name_of_class + '")'
else:
return_string = name_of_class.trim_prefix("_")
return_string += ".new()"
@ -342,7 +205,7 @@ func return_gdscript_code_which_run_this_object(data) -> String:
TYPE_RID:
return_string = "RID()"
TYPE_STRING:
return_string = "\"" + data + "\""
return_string = '"' + data + '"'
TYPE_STRING_ARRAY:
return_string = "PoolStringArray(["
for i in data.size():

View File

@ -3,9 +3,6 @@ extends Node
# Creates random or not objects, variables etc.
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
@ -14,246 +11,87 @@ func _ready() -> void:
func get_int() -> int:
if random:
if int(number) == 0:
return 0
return (randi() % int(number)) - int(number / 2.0)
else:
return int(number)
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))
else:
return str(int(number))
return str(int(number))
func get_float() -> float:
if random:
return (randf() * number) - (number / 2.0)
else:
return number
return number
func get_float_string() -> String:
if random:
return "(randf() * number) - (number / 2.0)".replace("number", str(number))
else:
return str(number)
return str(number)
func get_bool() -> bool:
if random:
if number < 2:
return bool()
return bool(randi() % 2)
else:
return bool()
return bool()
func get_bool_string() -> String:
if random:
if number < 2:
return str(bool())
return "bool(randi() % 2)"
else:
return str(bool())
return str(bool())
func get_vector2() -> Vector2:
if random:
if randi() % 2:
return Vector2(get_float(), get_float()).normalized()
return Vector2(get_float(), get_float())
func get_vector2_string() -> String:
if random:
if randi() % 2:
return "Vector2(" + get_float_string() + ", " + get_float_string() + ").normalized()"
return "Vector2(" + get_float_string() + ", " + get_float_string() + ")"
func get_vector2_string_csharp() -> String:
if random:
if randi() % 2:
return "new Vector2(" + get_float_string() + ", " + get_float_string() + ").Normalized()"
return "new Vector2(" + get_float_string() + ", " + get_float_string() + ")"
func get_vector3() -> Vector3:
if random:
if randi() % 2:
return Vector3(get_float(), get_float(), get_float()).normalized()
return Vector3(get_float(), get_float(), get_float())
func get_vector3_string() -> String:
if random:
if randi() % 2:
return "Vector3(" + get_float_string() + ", " + get_float_string() + ", " + get_float_string() + ").normalized()"
return "Vector3(" + get_float_string() + ", " + get_float_string() + ", " + get_float_string() + ")"
func get_vector3_string_csharp() -> String:
if random:
if randi() % 2:
return "new Vector3(" + get_float_string() + ", " + get_float_string() + ", " + get_float_string() + ").Normalized()"
return "new Vector3(" + get_float_string() + ", " + get_float_string() + ", " + get_float_string() + ")"
func get_aabb() -> AABB:
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())
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())
func get_transform2D_string() -> 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())
func get_plane_string() -> 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() + ")"
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())
func get_color_string() -> 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:
if random:
if randi() % 2 == 0:
return String(".")
else:
return str(randi())
return String()
func get_string_string() -> String:
if random:
if randi() % 3 == 0:
return "\".\""
elif randi() % 3 == 0:
return "\"\""
else:
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))):
if random && randi() % 2:
array.append(randi() % 100)
else:
array.append([])
return Array([])
func get_dictionary() -> Dictionary:
if random:
if randi() % 2:
return Dictionary({"roman": 22, 22: 25, BoxShape.new(): BoxShape.new()})
return Dictionary({})
func get_pool_string_array() -> PoolStringArray:
var array: Array = []
if random && randi() % 2:
return PoolStringArray(array)
for _i in range(int(min(max_array_size, number))):
array.append(get_string())
return PoolStringArray(array)
@ -261,8 +99,6 @@ func get_pool_string_array() -> PoolStringArray:
func get_pool_int_array() -> PoolIntArray:
var array: Array = []
if random && randi() % 2:
return PoolIntArray(array)
for _i in range(int(min(max_array_size, number))):
array.append(get_int())
return PoolIntArray(array)
@ -270,8 +106,6 @@ func get_pool_int_array() -> PoolIntArray:
func get_pool_byte_array() -> PoolByteArray:
var array: Array = []
if random && randi() % 2:
return PoolByteArray(array)
for _i in range(int(min(max_array_size, number))):
array.append(get_int())
return PoolByteArray(array)
@ -279,8 +113,6 @@ func get_pool_byte_array() -> PoolByteArray:
func get_pool_real_array() -> PoolRealArray:
var array: Array = []
if random && randi() % 2:
return PoolRealArray(array)
for _i in range(int(min(max_array_size, number))):
array.append(get_float())
return PoolRealArray(array)
@ -288,8 +120,6 @@ func get_pool_real_array() -> PoolRealArray:
func get_pool_vector2_array() -> PoolVector2Array:
var array: Array = []
if random && randi() % 2:
return PoolVector2Array(array)
for _i in range(int(min(max_array_size, number))):
array.append(get_vector2())
return PoolVector2Array(array)
@ -297,8 +127,6 @@ func get_pool_vector2_array() -> PoolVector2Array:
func get_pool_vector3_array() -> PoolVector3Array:
var array: Array = []
if random && randi() % 2:
return PoolVector3Array(array)
for _i in range(int(min(max_array_size, number))):
array.append(get_vector3())
return PoolVector3Array(array)
@ -306,8 +134,6 @@ func get_pool_vector3_array() -> PoolVector3Array:
func get_pool_color_array() -> PoolColorArray:
var array: Array = []
if random && randi() % 2:
return PoolColorArray(array)
for _i in range(int(min(max_array_size, number))):
array.append(get_color())
return PoolColorArray(array)
@ -315,144 +141,18 @@ func get_pool_color_array() -> PoolColorArray:
func get_object(object_name: String) -> Object:
assert(ClassDB.class_exists(object_name), "Class " + object_name + " doesn't exists.")
if object_name == "PhysicsDirectSpaceState" || object_name == "Physics2DDirectSpaceState":
return BoxShape.new()
# if object_name == "PhysicsDirectSpaceState" || object_name == "Physics2DDirectSpaceState":
# return BoxShape.new()
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"))
&& !(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, "Cannot find proper instantable child for " + object_name)
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, "Cannot find proper instantable child for " + object_name)
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, "Cannot find proper instantable child for " + object_name)
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)
# Non Node/Resource object
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, "Cannot find proper instantable child for " + object_name)
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, "Cannot find proper instantable child for " + object_name)
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)
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:
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: # Found child of non instantable object
var list_of_class = ClassDB.get_inheriters_from_class(object_name)
assert(list_of_class.size() > 0, "Cannot find proper instantable child for " + object_name) # 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, "Cannot find proper instantable child for " + object_name)
# Checking for children of non instantable object
var list_of_class = ClassDB.get_inheriters_from_class(object_name)
assert(list_of_class.size() > 0, "Cannot find proper instantable child for " + object_name) # 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, "Cannot find proper instantable child for " + object_name)
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, "Cannot find proper instantable child for " + object_name)
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, "Cannot find proper instantable child for " + object_name)
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, "Cannot find proper instantable child for " + object_name)
var choosen_class: String = classes[randi() % classes.size()]
if !ClassDB.is_parent_class(choosen_class, object_name):
return choosen_class
# Non Node/Resource object
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, "Cannot find proper instantable child for " + object_name)
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, "Cannot find proper instantable child for " + object_name)
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 choosen_class
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, "Cannot find proper instantable child for " + object_name) # 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, "Cannot find proper instantable child for " + object_name)
assert(false, "Cannot find proper instantable child for " + object_name)
return "BoxMesh"

View File

@ -1,30 +1,32 @@
extends Node2D
var available_classes : Array = []
var exeptions : Array = ["SceneTree", "EditorSettings", "ProjectSettings"]
var available_classes: Array = []
var exeptions: Array = ["SceneTree", "EditorSettings", "ProjectSettings"]
func _ready():
var cl : Array = Array(ClassDB.get_class_list())
var cl: Array = Array(ClassDB.get_class_list())
cl.sort()
for name_of_class in cl:
if !ClassDB.can_instance(name_of_class):
continue
if name_of_class in exeptions:
continue
if name_of_class.to_lower().find("server") != -1:
continue
print("########### " + name_of_class)
print("GDSCRIPT CODE: var thing = ClassDB.instance(\"" + name_of_class + "\")")
print("GDSCRIPT CODE: str(" + name_of_class + ")")
var thing = ClassDB.instance(name_of_class)
str(thing)
if thing is Node:
print("GDSCRIPT CODE: thing.queue_free()")
thing.queue_free()
elif thing is Object && !(thing is Reference):
print("GDSCRIPT CODE: thing.free()")
thing.free()
# Repeat 3 times, to be sure that code don't crash in unreleated function
for _i in range(3):
if !ClassDB.can_instance(name_of_class):
continue
if name_of_class in exeptions:
continue
if name_of_class.to_lower().find("server") != -1:
continue
print("########### " + name_of_class)
print('GDSCRIPT CODE: var thing = ClassDB.instance("' + name_of_class + '")')
print("GDSCRIPT CODE: str(" + name_of_class + ")")
var thing = ClassDB.instance(name_of_class)
str(thing)
if thing is Node:
print("GDSCRIPT CODE: thing.queue_free()")
thing.queue_free()
elif thing is Object && !(thing is Reference):
print("GDSCRIPT CODE: thing.free()")
thing.free()

View File

@ -1,34 +0,0 @@
#!/bin/bash
grep -rl "onready" . --exclude-dir=.git,Godot4Update.sh | xargs sed -i 's/@onready /@onready /'
grep -rl "extends RigidBody3D" . --exclude-dir=.git | xargs sed -i 's/extends RigidBody/extends RigidBody3D/'
grep -rl "extends RigidBody3D3D2D" . --exclude-dir=.git | xargs sed -i 's/extends RigidBody2D/extends RigidBody2D/'
grep -rl "PointLight2D" . --exclude-dir=.git | xargs sed -i 's/Light2D/PointLight2D/'
grep -rl "Camera3D" . --exclude-dir=.git | xargs sed -i 's/Camera/Camera3D/'
grep -rl "Camera3D3D2D" . --exclude-dir=.git | xargs sed -i 's/Camera2D/Camera2D/'
grep -rl "if i.get_name() != \"Camera3D3D\":" . --exclude-dir=.git | xargs sed -i 's/if i.get_name() != "Camera":/if i.get_name() != "Camera":/'
grep -rl "DirectionalLight3D" . --exclude-dir=.git | xargs sed -i 's/DirectionalLight/DirectionalLight3D/'
grep -rl "DirectionalLight3D3D2D" . --exclude-dir=.git | xargs sed -i 's/DirectionalLight2D/DirectionalPointLight2D/'
grep -rl "SpotLight3D" . --exclude-dir=.git | xargs sed -i 's/SpotLight/SpotLight3D/'
grep -rl "SpotLight3D3D2D" . --exclude-dir=.git | xargs sed -i 's/SpotLight2D/SpotPointLight2D/'
grep -rl "OmniLight3D" . --exclude-dir=.git | xargs sed -i 's/OmniLight/OmniLight3D/'
grep -rl "OmniLight3D3D2D" . --exclude-dir=.git | xargs sed -i 's/OmniLight2D/OmniPointLight2D/'
grep -rl "Node3D" . --exclude-dir=.git | xargs sed -i 's/Spatial/Node3D/'

View File

@ -41,7 +41,7 @@ func collect() -> void:
var to_print: String = "DEBUG: List of classes used in Nodes scene:\n"
to_print += "DEBUG: ["
for index in range(classes.size()):
to_print += "\"" + classes[index] + "\""
to_print += '"' + classes[index] + '"'
if index != classes.size() - 1:
to_print += ", "
print(to_print)

View File

@ -1,5 +1,6 @@
extends RigidBody
func _physics_process(delta: float) -> void:
add_force(Vector3(0,4 * delta ,0),Vector3(0,0,0))
add_force(Vector3(0, 4 * delta, 0), Vector3(0, 0, 0))
pass

View File

@ -1,7 +1,7 @@
# Godot regression test project
This repository contains project which is used to find regressions in Godot.
It aims to check as much as possible functions and states, be easy in maintain and provide reproducible results.
It aims to check as much as possible functions and states, be easy in maintain and provide quite reproducible results.
## Basic Informations
This project contains a few different scenes and `Start.tscn`(default one) which opens every other scene.
@ -116,25 +116,18 @@ It is used to catch early very obvious and easy to reproduce bugs.
This is more advanced variation of Nodes scene.
In random order adds, remove and move in scene tree nodes. It may not sound spectacular, but it sometimes allows you to find bugs that are hard to detect.
## CreatingAllThings
This scene creates, prints and removes object.
Can be used to quicly check if classes don't crash when executing simple commands on them.
## Others
Scenes like `Physics2D.tscn` or `Lights3D.tscn` are normal scenes with specific types of nodes. They are only used to manually check visual differences between different Godot versions.
![Physics](https://user-images.githubusercontent.com/41945903/115050994-9da8a100-9edc-11eb-99f6-9375ef917be1.png)
## TODO
- Add physics test - currently blocked by several crashes - https://github.com/godotengine/godot/issues/47440
## 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(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.
## Problems with project
The project should not cause too many problems in CI when adding and removing features in Godot, since it don't uses too much functions but for example removing a base type e.g. `TYPE_INT` or changes in GDScript(e.g. changing `instance` to `instantiate`) can mess it up.
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.

View File

@ -2,6 +2,7 @@ extends Node
# Script first adds nodes to scene, then choose some random nodes and reparents
# them or delete and replace with new ones
# This is not really reproducible, but crashes find by this tool should be quite easy to recreate
## Algorithm
# - Add multiple nodes to scene
@ -45,7 +46,7 @@ func collect() -> void:
var to_print: String = "DEBUG: List of classes used in ReparentingDeleting scene:\n"
to_print += "DEBUG: ["
for index in range(classes.size()):
to_print += "\"" + classes[index] + "\""
to_print += '"' + classes[index] + '"'
if index != classes.size() - 1:
to_print += ", "
print(to_print)