Added automatic test (#27)

This commit is contained in:
Rafał Mikrut 2021-02-16 08:21:20 +01:00 committed by GitHub
parent 2e73f681a8
commit b52b5368a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 472 additions and 1 deletions

View File

@ -207,7 +207,6 @@ shape = SubResource( 4 )
[node name="DampedSpringJoint2D" type="DampedSpringJoint2D" parent="."]
position = Vector2( 606, 195 )
node_a = NodePath("RigidBody2D")
node_b = NodePath("RigidBody2D2")
[node name="RigidBody2D" type="RigidBody2D" parent="DampedSpringJoint2D"]

View File

@ -30,6 +30,7 @@ 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",
]

123
AutomaticBugs/BasicData.gd Normal file
View File

@ -0,0 +1,123 @@
extends Node
var function_exceptions = [
# 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
"debug_bake",# GH 45978
"bake", # GH 45978
"_editor_settings_changed",# GH 45979
"_mesh_changed",# GH 45980
"_submenu_timeout", # GH 45981
"set_data", # GH 45995 - probably this will cause a lot of different errors in other classes
"_set_user_data", # GH 45996
"set_config_file", # GH 45997
"_gui_input", # GH 45998
"_unhandled_key_input", # GH 45998
"navpoly_add", #GH 43288
"create_from_mesh", #GH 45999
"_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
"get_column_width", #GH 46005
"_unhandled_input", # TODO
"_input", # TODO
"lightmap_unwrap", #GH 46007 - memory leak
"_input_type_changed", #GH 46011
"add_node", #GH 46012
"play", #GH 46013
"connect_nodes_forced", #GH 46014
"_set_tile_data", #GH 46015
"add_image", #GH 46016
"_edit_set_state", #GH 46017
"_edit_set_position", #GH 46018
"_edit_set_rect", #GH 46018
"get", #GH 46019
"instance_has", #GH
"", #GH
"", #GH
"", #GH
"", #GH
"", #GH
"", #GH
# TODO is workaround for removing memory leak in Thread::start, should be fixed by GH 45618
"start",
# TODO Adds big spam when i>100
"add_sphere",
# Do not save files and create files and folders
"save",
"save_png",
"save_to_wav",
"save_to_file",
"make_dir",
"make_dir_recursive",
# Do not warp mouse
"warp_mouse",
"warp_mouse_position",
# Looks like a bug in FuncRef, probably but not needed
"call_func",
# Godot Freeze
"discover",
"wait",
"register_text_enter",
# Do not call other functions
"_call_function",
"call",
"call_deferred",
# Too dangerous, because add, mix and remove randomly nodes and objects
"init_ref",
"reference",
"unreference",
"new",
"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",
]
# 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
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
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) )
print(str(c) + " choosen classes from all " + str(full_class_list.size()) + " classes.")
return classes

View File

@ -0,0 +1,141 @@
extends Node
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
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
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)
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)
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 = []
ValueCreator.number = 10
ValueCreator.random = 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_AABB:
arguments_array.push_back(ValueCreator.get_aabb())
TYPE_ARRAY:
arguments_array.push_back(ValueCreator.get_array())
TYPE_BASIS:
arguments_array.push_back(ValueCreator.get_basis())
TYPE_BOOL:
arguments_array.push_back(ValueCreator.get_bool())
TYPE_COLOR:
arguments_array.push_back(ValueCreator.get_color())
TYPE_COLOR_ARRAY:
arguments_array.push_back(ValueCreator.get_pool_color_array())
TYPE_DICTIONARY:
arguments_array.push_back(ValueCreator.get_dictionary())
TYPE_INT:
arguments_array.push_back(ValueCreator.get_int())
TYPE_INT_ARRAY:
arguments_array.push_back(ValueCreator.get_pool_int_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
TYPE_PLANE:
arguments_array.push_back(ValueCreator.get_plane())
TYPE_QUAT:
arguments_array.push_back(ValueCreator.get_quat())
TYPE_RAW_ARRAY:
arguments_array.push_back(ValueCreator.get_pool_byte_array())
TYPE_REAL:
arguments_array.push_back(ValueCreator.get_float())
TYPE_REAL_ARRAY:
arguments_array.push_back(ValueCreator.get_pool_real_array())
TYPE_RECT2:
arguments_array.push_back(ValueCreator.get_rect2())
TYPE_RID:
arguments_array.push_back(RID())
TYPE_STRING:
arguments_array.push_back(ValueCreator.get_string())
TYPE_STRING_ARRAY:
arguments_array.push_back(ValueCreator.get_pool_string_array())
TYPE_TRANSFORM:
arguments_array.push_back(ValueCreator.get_transform())
TYPE_TRANSFORM2D:
arguments_array.push_back(ValueCreator.get_transform2D())
TYPE_VECTOR2:
arguments_array.push_back(ValueCreator.get_vector2())
TYPE_VECTOR2_ARRAY:
arguments_array.push_back(ValueCreator.get_pool_vector2_array())
TYPE_VECTOR3:
arguments_array.push_back(ValueCreator.get_vector3())
TYPE_VECTOR3_ARRAY:
arguments_array.push_back(ValueCreator.get_pool_vector3_array())
_:
assert(false) # Missed some types, add it
# print("Parameters " + str(arguments_array))
return arguments_array

View File

@ -0,0 +1,6 @@
[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 )

View File

@ -0,0 +1,199 @@
extends Node
var number : float = 0.0
var random : bool = false
var max_array_size : int = 15
func get_int() -> int:
if random:
if int(number) == 0:
return 0
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))
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:
return bool()
return bool(randi() % 2)
else:
return bool()
func get_bool_string() -> String:
if random:
if number < 2:
return str(bool())
return "bool(randi() % 2)"
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_vector3() -> Vector3:
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_aabb() -> AABB:
return AABB(get_vector3(),get_vector3())
func get_aabb_string() -> String:
return "AABB(" + get_vector3_string() + ", " + get_vector3_string() + ")"
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_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_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_quat() -> Quat:
return Quat(get_vector3())
func get_quat_string() -> String:
return "Quat(" + get_vector3_string() + ")"
func get_basis() -> Basis:
return Basis(get_vector3())
func get_basis_string() -> String:
return "Basis(" + get_vector3_string() + ")"
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_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() + ")"
# 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() % 2 == 0:
return "\".\""
else:
return "\"randi())\""
return "\"\""
# TODO
func get_nodepath() -> NodePath:
return NodePath(get_string())
# TODO
func get_array() -> Array:
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))):
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))):
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))):
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))):
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))):
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))):
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))):
array.append(get_color())
return PoolColorArray(array)
func get_object(object_name : String) -> Object:
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)
else:
if ClassDB.is_class(object_name) && ClassDB.can_instance(object_name):
return ClassDB.instance(object_name)
else:
return BoxShape.new()
return BoxShape.new()

View File

@ -26,6 +26,8 @@ config/icon="res://icon.png"
[autoload]
Autoload="*res://Autoload/Autoload.gd"
ValueCreator="*res://AutomaticBugs/ValueCreator.gd"
BasicData="*res://AutomaticBugs/BasicData.gd"
[debug]