summaryrefslogtreecommitdiff
path: root/main/tests
diff options
context:
space:
mode:
Diffstat (limited to 'main/tests')
-rw-r--r--main/tests/test_astar.cpp91
-rw-r--r--main/tests/test_class_db.cpp882
-rw-r--r--main/tests/test_class_db.h42
-rw-r--r--main/tests/test_gdscript.cpp221
-rw-r--r--main/tests/test_gui.cpp5
-rw-r--r--main/tests/test_main.cpp32
-rw-r--r--main/tests/test_math.cpp119
-rw-r--r--main/tests/test_oa_hash_map.cpp152
-rw-r--r--main/tests/test_ordered_hash_map.cpp14
-rw-r--r--main/tests/test_physics_2d.cpp35
-rw-r--r--main/tests/test_physics_3d.cpp28
-rw-r--r--main/tests/test_render.cpp12
-rw-r--r--main/tests/test_shader_lang.cpp110
-rw-r--r--main/tests/test_string.cpp138
14 files changed, 1442 insertions, 439 deletions
diff --git a/main/tests/test_astar.cpp b/main/tests/test_astar.cpp
index e82d885af2..fe335589b0 100644
--- a/main/tests/test_astar.cpp
+++ b/main/tests/test_astar.cpp
@@ -173,7 +173,9 @@ bool test_add_remove() {
for (int i = 0; i < 20000; i++) {
int u = Math::rand() % 5;
int v = Math::rand() % 4;
- if (u == v) v = 4;
+ if (u == v) {
+ v = 4;
+ }
if (Math::rand() % 2 == 1) {
// Add a (possibly existing) directed edge and confirm connectivity
a.connect_points(u, v, false);
@@ -188,18 +190,22 @@ bool test_add_remove() {
// Random tests for point removal
for (int i = 0; i < 20000; i++) {
a.clear();
- for (int j = 0; j < 5; j++)
+ for (int j = 0; j < 5; j++) {
a.add_point(j, Vector3(0, 0, 0));
+ }
// Add or remove random edges
for (int j = 0; j < 10; j++) {
int u = Math::rand() % 5;
int v = Math::rand() % 4;
- if (u == v) v = 4;
- if (Math::rand() % 2 == 1)
+ if (u == v) {
+ v = 4;
+ }
+ if (Math::rand() % 2 == 1) {
a.connect_points(u, v, false);
- else
+ } else {
a.disconnect_points(u, v, false);
+ }
}
// Remove point 0
@@ -239,7 +245,9 @@ bool test_solutions() {
int u, v;
u = Math::rand() % N;
v = Math::rand() % (N - 1);
- if (u == v) v = N - 1;
+ if (u == v) {
+ v = N - 1;
+ }
// Pick a random operation
int op = Math::rand();
@@ -253,14 +261,18 @@ bool test_solutions() {
// Add edge (u, v); possibly bidirectional
a.connect_points(u, v, op % 2);
adj[u][v] = true;
- if (op % 2) adj[v][u] = true;
+ if (op % 2) {
+ adj[v][u] = true;
+ }
break;
case 6:
case 7:
// Remove edge (u, v); possibly bidirectional
a.disconnect_points(u, v, op % 2);
adj[u][v] = false;
- if (op % 2) adj[v][u] = false;
+ if (op % 2) {
+ adj[v][u] = false;
+ }
break;
case 8:
// Remove point u and add it back; clears adjacent edges and changes coordinates
@@ -269,40 +281,55 @@ bool test_solutions() {
p[u].y = Math::rand() % 100;
p[u].z = Math::rand() % 100;
a.add_point(u, p[u]);
- for (v = 0; v < N; v++)
+ for (v = 0; v < N; v++) {
adj[u][v] = adj[v][u] = false;
+ }
break;
}
}
// Floyd-Warshall
float d[N][N];
- for (int u = 0; u < N; u++)
- for (int v = 0; v < N; v++)
+ for (int u = 0; u < N; u++) {
+ for (int v = 0; v < N; v++) {
d[u][v] = (u == v || adj[u][v]) ? p[u].distance_to(p[v]) : INFINITY;
+ }
+ }
- for (int w = 0; w < N; w++)
- for (int u = 0; u < N; u++)
- for (int v = 0; v < N; v++)
- if (d[u][v] > d[u][w] + d[w][v])
+ for (int w = 0; w < N; w++) {
+ for (int u = 0; u < N; u++) {
+ for (int v = 0; v < N; v++) {
+ if (d[u][v] > d[u][w] + d[w][v]) {
d[u][v] = d[u][w] + d[w][v];
+ }
+ }
+ }
+ }
// Display statistics
int count = 0;
- for (int u = 0; u < N; u++)
- for (int v = 0; v < N; v++)
- if (adj[u][v]) count++;
+ for (int u = 0; u < N; u++) {
+ for (int v = 0; v < N; v++) {
+ if (adj[u][v]) {
+ count++;
+ }
+ }
+ }
printf("Test #%4d: %3d edges, ", test + 1, count);
count = 0;
- for (int u = 0; u < N; u++)
- for (int v = 0; v < N; v++)
- if (!Math::is_inf(d[u][v])) count++;
+ for (int u = 0; u < N; u++) {
+ for (int v = 0; v < N; v++) {
+ if (!Math::is_inf(d[u][v])) {
+ count++;
+ }
+ }
+ }
printf("%3d/%d pairs of reachable points\n", count - N, N * (N - 1));
// Check A*'s output
bool match = true;
- for (int u = 0; u < N; u++)
- for (int v = 0; v < N; v++)
+ for (int u = 0; u < N; u++) {
+ for (int v = 0; v < N; v++) {
if (u != v) {
Vector<int> route = a.get_id_path(u, v);
if (!Math::is_inf(d[u][v])) {
@@ -337,21 +364,25 @@ bool test_solutions() {
}
}
}
+ }
+ }
exit:
- if (!match) return false;
+ if (!match) {
+ return false;
+ }
}
return true;
}
-typedef bool (*TestFunc)(void);
+typedef bool (*TestFunc)();
TestFunc test_funcs[] = {
test_abc,
test_abcx,
test_add_remove,
test_solutions,
- NULL
+ nullptr
};
MainLoop *test() {
@@ -359,18 +390,20 @@ MainLoop *test() {
int passed = 0;
while (true) {
- if (!test_funcs[count])
+ if (!test_funcs[count]) {
break;
+ }
bool pass = test_funcs[count]();
- if (pass)
+ if (pass) {
passed++;
+ }
OS::get_singleton()->print("\t%s\n", pass ? "PASS" : "FAILED");
count++;
}
OS::get_singleton()->print("\n");
OS::get_singleton()->print("Passed %i of %i tests\n", passed, count);
- return NULL;
+ return nullptr;
}
} // namespace TestAStar
diff --git a/main/tests/test_class_db.cpp b/main/tests/test_class_db.cpp
new file mode 100644
index 0000000000..3171091402
--- /dev/null
+++ b/main/tests/test_class_db.cpp
@@ -0,0 +1,882 @@
+/*************************************************************************/
+/* test_class_db.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "test_class_db.h"
+
+#include "core/global_constants.h"
+#include "core/ordered_hash_map.h"
+#include "core/os/os.h"
+#include "core/string_name.h"
+#include "core/ustring.h"
+#include "core/variant.h"
+
+namespace TestClassDB {
+
+enum class [[nodiscard]] TestResult{
+ FAILED,
+ PASS
+};
+
+#define TEST_FAIL_COND(m_cond, m_msg) \
+ if (unlikely(m_cond)) { \
+ ERR_PRINT(m_msg); \
+ return TestResult::FAILED; \
+ } else \
+ ((void)0)
+
+#define TEST_COND(m_cond, m_msg) \
+ if (unlikely(m_cond)) { \
+ ERR_PRINT(m_msg); \
+ __test_result__ = TestResult::FAILED; \
+ } else \
+ ((void)0)
+
+#define TEST_FAIL_CHECK(m_test_expr) \
+ if (unlikely((m_test_expr) == TestResult::FAILED)) { \
+ return TestResult::FAILED; \
+ } else \
+ ((void)0)
+
+#define TEST_CHECK(m_test_expr) \
+ if (unlikely((m_test_expr) == TestResult::FAILED)) { \
+ __test_result__ = TestResult::FAILED; \
+ } else \
+ ((void)0)
+
+#define TEST_START() \
+ TestResult __test_result__ = TestResult::PASS; \
+ ((void)0)
+
+#define TEST_END() return __test_result__;
+
+struct TypeReference {
+ StringName name;
+ bool is_enum = false;
+};
+
+struct ConstantData {
+ String name;
+ int value = 0;
+};
+
+struct EnumData {
+ StringName name;
+ List<ConstantData> constants;
+
+ _FORCE_INLINE_ bool operator==(const EnumData &p_enum) const {
+ return p_enum.name == name;
+ }
+};
+
+struct PropertyData {
+ StringName name;
+ int index = 0;
+
+ StringName getter;
+ StringName setter;
+};
+
+struct ArgumentData {
+ TypeReference type;
+ String name;
+ bool has_defval = false;
+ Variant defval;
+};
+
+struct MethodData {
+ StringName name;
+ TypeReference return_type;
+ List<ArgumentData> arguments;
+ bool is_virtual = false;
+ bool is_vararg = false;
+};
+
+struct SignalData {
+ StringName name;
+ List<ArgumentData> arguments;
+};
+
+struct ExposedClass {
+ StringName name;
+ StringName base;
+
+ bool is_singleton = false;
+ bool is_instantiable = false;
+ bool is_reference = false;
+
+ ClassDB::APIType api_type;
+
+ List<ConstantData> constants;
+ List<EnumData> enums;
+ List<PropertyData> properties;
+ List<MethodData> methods;
+ List<SignalData> signals_;
+
+ const PropertyData *find_property_by_name(const StringName &p_name) const {
+ for (const List<PropertyData>::Element *E = properties.front(); E; E = E->next()) {
+ if (E->get().name == p_name) {
+ return &E->get();
+ }
+ }
+
+ return nullptr;
+ }
+
+ const MethodData *find_method_by_name(const StringName &p_name) const {
+ for (const List<MethodData>::Element *E = methods.front(); E; E = E->next()) {
+ if (E->get().name == p_name) {
+ return &E->get();
+ }
+ }
+
+ return nullptr;
+ }
+};
+
+struct NamesCache {
+ StringName variant_type = StaticCString::create("Variant");
+ StringName object_class = StaticCString::create("Object");
+ StringName reference_class = StaticCString::create("Reference");
+ StringName string_type = StaticCString::create("String");
+ StringName string_name_type = StaticCString::create("StringName");
+ StringName node_path_type = StaticCString::create("NodePath");
+ StringName bool_type = StaticCString::create("bool");
+ StringName int_type = StaticCString::create("int");
+ StringName float_type = StaticCString::create("float");
+ StringName void_type = StaticCString::create("void");
+ StringName vararg_stub_type = StaticCString::create("@VarArg@");
+ StringName vector2_type = StaticCString::create("Vector2");
+ StringName rect2_type = StaticCString::create("Rect2");
+ StringName vector3_type = StaticCString::create("Vector3");
+
+ // Object not included as it must be checked for all derived classes
+ static constexpr int nullable_types_count = 17;
+ StringName nullable_types[nullable_types_count] = {
+ string_type,
+ string_name_type,
+ node_path_type,
+
+ StaticCString::create(_STR(Array)),
+ StaticCString::create(_STR(Dictionary)),
+ StaticCString::create(_STR(Callable)),
+ StaticCString::create(_STR(Signal)),
+
+ StaticCString::create(_STR(PackedByteArray)),
+ StaticCString::create(_STR(PackedInt32Array)),
+ StaticCString::create(_STR(PackedInt64rray)),
+ StaticCString::create(_STR(PackedFloat32Array)),
+ StaticCString::create(_STR(PackedFloat64Array)),
+ StaticCString::create(_STR(PackedStringArray)),
+ StaticCString::create(_STR(PackedVector2Array)),
+ StaticCString::create(_STR(PackedVector3Array)),
+ StaticCString::create(_STR(PackedColorArray)),
+ };
+
+ bool is_nullable_type(const StringName &p_type) const {
+ for (int i = 0; i < nullable_types_count; i++) {
+ if (p_type == nullable_types[i]) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+};
+
+typedef OrderedHashMap<StringName, ExposedClass> ExposedClasses;
+
+struct Context {
+ Vector<StringName> enum_types;
+ Vector<StringName> builtin_types;
+ ExposedClasses exposed_classes;
+ List<EnumData> global_enums;
+ NamesCache names_cache;
+
+ const ExposedClass *find_exposed_class(const StringName &p_name) const {
+ ExposedClasses::ConstElement elem = exposed_classes.find(p_name);
+ return elem ? &elem.value() : nullptr;
+ }
+
+ const ExposedClass *find_exposed_class(const TypeReference &p_type_ref) const {
+ ExposedClasses::ConstElement elem = exposed_classes.find(p_type_ref.name);
+ return elem ? &elem.value() : nullptr;
+ }
+
+ bool has_type(const TypeReference &p_type_ref) const {
+ if (builtin_types.find(p_type_ref.name) >= 0) {
+ return true;
+ }
+
+ if (p_type_ref.is_enum) {
+ if (enum_types.find(p_type_ref.name) >= 0) {
+ return true;
+ }
+
+ // Enum not found. Most likely because none of its constants were bound, so it's empty. That's fine. Use int instead.
+ return builtin_types.find(names_cache.int_type);
+ }
+
+ return false;
+ }
+};
+
+bool arg_default_value_is_assignable_to_type(const Context &p_context, const Variant &p_val, const TypeReference &p_arg_type) {
+ if (p_arg_type.name == p_context.names_cache.variant_type) {
+ // Variant can take anything
+ return true;
+ }
+
+ switch (p_val.get_type()) {
+ case Variant::NIL:
+ return p_context.find_exposed_class(p_arg_type) ||
+ p_context.names_cache.is_nullable_type(p_arg_type.name);
+ case Variant::BOOL:
+ return p_arg_type.name == p_context.names_cache.bool_type;
+ case Variant::INT:
+ return p_arg_type.name == p_context.names_cache.int_type ||
+ p_arg_type.name == p_context.names_cache.float_type ||
+ p_arg_type.is_enum;
+ case Variant::FLOAT:
+ return p_arg_type.name == p_context.names_cache.float_type;
+ case Variant::STRING:
+ case Variant::STRING_NAME:
+ return p_arg_type.name == p_context.names_cache.string_type ||
+ p_arg_type.name == p_context.names_cache.string_name_type ||
+ p_arg_type.name == p_context.names_cache.node_path_type;
+ case Variant::NODE_PATH:
+ return p_arg_type.name == p_context.names_cache.node_path_type;
+ case Variant::TRANSFORM:
+ case Variant::TRANSFORM2D:
+ case Variant::BASIS:
+ case Variant::QUAT:
+ case Variant::PLANE:
+ case Variant::AABB:
+ case Variant::COLOR:
+ case Variant::VECTOR2:
+ case Variant::RECT2:
+ case Variant::VECTOR3:
+ case Variant::_RID:
+ case Variant::ARRAY:
+ case Variant::DICTIONARY:
+ case Variant::PACKED_BYTE_ARRAY:
+ case Variant::PACKED_INT32_ARRAY:
+ case Variant::PACKED_INT64_ARRAY:
+ case Variant::PACKED_FLOAT32_ARRAY:
+ case Variant::PACKED_FLOAT64_ARRAY:
+ case Variant::PACKED_STRING_ARRAY:
+ case Variant::PACKED_VECTOR2_ARRAY:
+ case Variant::PACKED_VECTOR3_ARRAY:
+ case Variant::PACKED_COLOR_ARRAY:
+ case Variant::CALLABLE:
+ case Variant::SIGNAL:
+ return p_arg_type.name == Variant::get_type_name(p_val.get_type());
+ case Variant::OBJECT:
+ return p_context.find_exposed_class(p_arg_type);
+ case Variant::VECTOR2I:
+ return p_arg_type.name == p_context.names_cache.vector2_type ||
+ p_arg_type.name == Variant::get_type_name(p_val.get_type());
+ case Variant::RECT2I:
+ return p_arg_type.name == p_context.names_cache.rect2_type ||
+ p_arg_type.name == Variant::get_type_name(p_val.get_type());
+ case Variant::VECTOR3I:
+ return p_arg_type.name == p_context.names_cache.vector3_type ||
+ p_arg_type.name == Variant::get_type_name(p_val.get_type());
+ default:
+ ERR_PRINT("Unexpected Variant type: " + itos(p_val.get_type()));
+ break;
+ }
+
+ return false;
+}
+
+TestResult validate_property(const Context &p_context, const ExposedClass &p_class, const PropertyData &p_prop) {
+ TEST_START();
+
+ const MethodData *setter = p_class.find_method_by_name(p_prop.setter);
+
+ // Search it in base classes too
+ const ExposedClass *top = &p_class;
+ while (!setter && top->base != StringName()) {
+ top = p_context.find_exposed_class(top->base);
+ TEST_FAIL_COND(!top, "Class not found '" + top->base + "'. Inherited by '" + top->name + "'.");
+ setter = top->find_method_by_name(p_prop.setter);
+ }
+
+ const MethodData *getter = p_class.find_method_by_name(p_prop.getter);
+
+ // Search it in base classes too
+ top = &p_class;
+ while (!getter && top->base != StringName()) {
+ top = p_context.find_exposed_class(top->base);
+ TEST_FAIL_COND(!top, "Class not found '" + top->base + "'. Inherited by '" + top->name + "'.");
+ getter = top->find_method_by_name(p_prop.getter);
+ }
+
+ TEST_FAIL_COND(!setter && !getter,
+ "Couldn't find neither the setter nor the getter for property: '" + p_class.name + "." + String(p_prop.name) + "'.");
+
+ if (setter) {
+ int setter_argc = p_prop.index != -1 ? 2 : 1;
+ TEST_FAIL_COND(setter->arguments.size() != setter_argc,
+ "Invalid property setter argument count: '" + p_class.name + "." + String(p_prop.name) + "'.");
+ }
+
+ if (getter) {
+ int getter_argc = p_prop.index != -1 ? 1 : 0;
+ TEST_FAIL_COND(getter->arguments.size() != getter_argc,
+ "Invalid property setter argument count: '" + p_class.name + "." + String(p_prop.name) + "'.");
+ }
+
+ if (getter && setter) {
+ const ArgumentData &setter_first_arg = setter->arguments.back()->get();
+ if (getter->return_type.name != setter_first_arg.type.name) {
+ // Special case for Node::set_name
+ bool whitelisted = getter->return_type.name == p_context.names_cache.string_name_type &&
+ setter_first_arg.type.name == p_context.names_cache.string_type;
+
+ TEST_FAIL_COND(!whitelisted,
+ "Return type from getter doesn't match first argument of setter, for property: '" + p_class.name + "." + String(p_prop.name) + "'.");
+ }
+ }
+
+ const TypeReference &prop_type_ref = getter ? getter->return_type : setter->arguments.back()->get().type;
+
+ const ExposedClass *prop_class = p_context.find_exposed_class(prop_type_ref);
+ if (prop_class) {
+ TEST_COND(prop_class->is_singleton,
+ "Property type is a singleton: '" + p_class.name + "." + String(p_prop.name) + "'.");
+ } else {
+ TEST_FAIL_COND(!p_context.has_type(prop_type_ref),
+ "Property type '" + prop_type_ref.name + "' not found: '" + p_class.name + "." + String(p_prop.name) + "'.");
+ }
+
+ if (getter) {
+ if (p_prop.index != -1) {
+ const ArgumentData &idx_arg = getter->arguments.front()->get();
+ if (idx_arg.type.name != p_context.names_cache.int_type) {
+ // If not an int, it can be an enum
+ TEST_COND(p_context.enum_types.find(idx_arg.type.name) < 0,
+ "Invalid type '" + idx_arg.type.name + "' for index argument of property getter: '" + p_class.name + "." + String(p_prop.name) + "'.");
+ }
+ }
+ }
+
+ if (setter) {
+ if (p_prop.index != -1) {
+ const ArgumentData &idx_arg = setter->arguments.front()->get();
+ if (idx_arg.type.name != p_context.names_cache.int_type) {
+ // Assume the index parameter is an enum
+ // If not an int, it can be an enum
+ TEST_COND(p_context.enum_types.find(idx_arg.type.name) < 0,
+ "Invalid type '" + idx_arg.type.name + "' for index argument of property setter: '" + p_class.name + "." + String(p_prop.name) + "'.");
+ }
+ }
+ }
+
+ TEST_END();
+}
+
+TestResult validate_method(const Context &p_context, const ExposedClass &p_class, const MethodData &p_method) {
+ TEST_START();
+
+ const ExposedClass *return_class = p_context.find_exposed_class(p_method.return_type);
+ if (return_class) {
+ TEST_COND(return_class->is_singleton,
+ "Method return type is a singleton: '" + p_class.name + "." + p_method.name + "'.");
+ }
+
+ for (const List<ArgumentData>::Element *F = p_method.arguments.front(); F; F = F->next()) {
+ const ArgumentData &arg = F->get();
+
+ const ExposedClass *arg_class = p_context.find_exposed_class(arg.type);
+ if (arg_class) {
+ TEST_COND(arg_class->is_singleton,
+ "Argument type is a singleton: '" + arg.name + "' of method '" + p_class.name + "." + p_method.name + "'.");
+ } else {
+ TEST_FAIL_COND(!p_context.has_type(arg.type),
+ "Argument type '" + arg.type.name + "' not found: '" + arg.name + "' of method" + p_class.name + "." + p_method.name + "'.");
+ }
+
+ if (arg.has_defval) {
+ TEST_COND(!arg_default_value_is_assignable_to_type(p_context, arg.defval, arg.type),
+ "Invalid default value for parameter '" + arg.name + "' of method '" + p_class.name + "." + p_method.name + "'.");
+ }
+ }
+
+ TEST_END();
+}
+
+TestResult validate_signal(const Context &p_context, const ExposedClass &p_class, const SignalData &p_signal) {
+ TEST_START();
+
+ for (const List<ArgumentData>::Element *F = p_signal.arguments.front(); F; F = F->next()) {
+ const ArgumentData &arg = F->get();
+
+ const ExposedClass *arg_class = p_context.find_exposed_class(arg.type);
+ if (arg_class) {
+ TEST_COND(arg_class->is_singleton,
+ "Argument class is a singleton: '" + arg.name + "' of signal" + p_class.name + "." + p_signal.name + "'.");
+ } else {
+ TEST_FAIL_COND(!p_context.has_type(arg.type),
+ "Argument type '" + arg.type.name + "' not found: '" + arg.name + "' of signal" + p_class.name + "." + p_signal.name + "'.");
+ }
+ }
+
+ TEST_END();
+}
+
+TestResult validate_class(const Context &p_context, const ExposedClass &p_exposed_class) {
+ TEST_START();
+
+ bool is_derived_type = p_exposed_class.base != StringName();
+
+ if (!is_derived_type) {
+ // Asserts about the base Object class
+ TEST_FAIL_COND(p_exposed_class.name != p_context.names_cache.object_class,
+ "Class '" + p_exposed_class.name + "' has no base class.");
+ TEST_FAIL_COND(!p_exposed_class.is_instantiable,
+ "Object class is not instantiable.");
+ TEST_FAIL_COND(p_exposed_class.api_type != ClassDB::API_CORE,
+ "Object class is API is not API_CORE.");
+ TEST_FAIL_COND(p_exposed_class.is_singleton,
+ "Object class is registered as a singleton.");
+ }
+
+ TEST_FAIL_COND(p_exposed_class.is_singleton && p_exposed_class.base != p_context.names_cache.object_class,
+ "Singleton base class '" + String(p_exposed_class.base) + "' is not Object, for class '" + p_exposed_class.name + "'.");
+
+ TEST_FAIL_COND(is_derived_type && !p_context.exposed_classes.has(p_exposed_class.base),
+ "Base type '" + p_exposed_class.base.operator String() + "' does not exist, for class '" + p_exposed_class.name + "'.");
+
+ for (const List<PropertyData>::Element *F = p_exposed_class.properties.front(); F; F = F->next()) {
+ TEST_CHECK(validate_property(p_context, p_exposed_class, F->get()));
+ }
+
+ for (const List<MethodData>::Element *F = p_exposed_class.methods.front(); F; F = F->next()) {
+ TEST_CHECK(validate_method(p_context, p_exposed_class, F->get()));
+ }
+
+ for (const List<SignalData>::Element *F = p_exposed_class.signals_.front(); F; F = F->next()) {
+ TEST_CHECK(validate_signal(p_context, p_exposed_class, F->get()));
+ }
+
+ TEST_END();
+}
+
+TestResult add_exposed_classes(Context &r_context) {
+ TEST_START();
+
+ List<StringName> class_list;
+ ClassDB::get_class_list(&class_list);
+ class_list.sort_custom<StringName::AlphCompare>();
+
+ while (class_list.size()) {
+ StringName class_name = class_list.front()->get();
+
+ ClassDB::APIType api_type = ClassDB::get_api_type(class_name);
+
+ if (api_type == ClassDB::API_NONE) {
+ class_list.pop_front();
+ continue;
+ }
+
+ if (!ClassDB::is_class_exposed(class_name)) {
+ OS::get_singleton()->print("Ignoring class '%s' because it's not exposed\n", String(class_name).utf8().get_data());
+ class_list.pop_front();
+ continue;
+ }
+
+ if (!ClassDB::is_class_enabled(class_name)) {
+ OS::get_singleton()->print("Ignoring class '%s' because it's not enabled\n", String(class_name).utf8().get_data());
+ class_list.pop_front();
+ continue;
+ }
+
+ ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(class_name);
+
+ ExposedClass exposed_class;
+ exposed_class.name = class_name;
+ exposed_class.api_type = api_type;
+ exposed_class.is_singleton = Engine::get_singleton()->has_singleton(class_name);
+ exposed_class.is_instantiable = class_info->creation_func && !exposed_class.is_singleton;
+ exposed_class.is_reference = ClassDB::is_parent_class(class_name, "Reference");
+ exposed_class.base = ClassDB::get_parent_class(class_name);
+
+ // Add properties
+
+ List<PropertyInfo> property_list;
+ ClassDB::get_property_list(class_name, &property_list, true);
+
+ Map<StringName, StringName> accessor_methods;
+
+ for (const List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
+ const PropertyInfo &property = E->get();
+
+ if (property.usage & PROPERTY_USAGE_GROUP || property.usage & PROPERTY_USAGE_SUBGROUP || property.usage & PROPERTY_USAGE_CATEGORY) {
+ continue;
+ }
+
+ PropertyData prop;
+ prop.name = property.name;
+ prop.setter = ClassDB::get_property_setter(class_name, prop.name);
+ prop.getter = ClassDB::get_property_getter(class_name, prop.name);
+
+ if (prop.setter != StringName()) {
+ accessor_methods[prop.setter] = prop.name;
+ }
+ if (prop.getter != StringName()) {
+ accessor_methods[prop.getter] = prop.name;
+ }
+
+ bool valid = false;
+ prop.index = ClassDB::get_property_index(class_name, prop.name, &valid);
+ TEST_FAIL_COND(!valid, "Invalid property: '" + exposed_class.name + "." + String(prop.name) + "'.");
+
+ exposed_class.properties.push_back(prop);
+ }
+
+ // Add methods
+
+ List<MethodInfo> virtual_method_list;
+ ClassDB::get_virtual_methods(class_name, &virtual_method_list, true);
+
+ List<MethodInfo> method_list;
+ ClassDB::get_method_list(class_name, &method_list, true);
+ method_list.sort();
+
+ for (List<MethodInfo>::Element *E = method_list.front(); E; E = E->next()) {
+ const MethodInfo &method_info = E->get();
+
+ int argc = method_info.arguments.size();
+
+ if (method_info.name.empty()) {
+ continue;
+ }
+
+ MethodData method;
+ method.name = method_info.name;
+
+ if (method_info.flags & METHOD_FLAG_VIRTUAL) {
+ method.is_virtual = true;
+ }
+
+ PropertyInfo return_info = method_info.return_val;
+
+ MethodBind *m = method.is_virtual ? nullptr : ClassDB::get_method(class_name, method_info.name);
+
+ method.is_vararg = m && m->is_vararg();
+
+ if (!m && !method.is_virtual) {
+ TEST_FAIL_COND(!virtual_method_list.find(method_info),
+ "Missing MethodBind for non-virtual method: '" + exposed_class.name + "." + method.name + "'.");
+
+ // A virtual method without the virtual flag. This is a special case.
+
+ // The method Object.free is registered as a virtual method, but without the virtual flag.
+ // This is because this method is not supposed to be overridden, but called.
+ // We assume the return type is void.
+ method.return_type.name = r_context.names_cache.void_type;
+
+ // Actually, more methods like this may be added in the future, which could return
+ // something different. Let's put this check to notify us if that ever happens.
+ if (exposed_class.name != r_context.names_cache.object_class || String(method.name) != "free") {
+ WARN_PRINT("Notification: New unexpected virtual non-overridable method found."
+ " We only expected Object.free, but found '" +
+ exposed_class.name + "." + method.name + "'.");
+ }
+ } else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
+ method.return_type.name = return_info.class_name;
+ method.return_type.is_enum = true;
+ } else if (return_info.class_name != StringName()) {
+ method.return_type.name = return_info.class_name;
+
+ bool bad_reference_hint = !method.is_virtual && return_info.hint != PROPERTY_HINT_RESOURCE_TYPE &&
+ ClassDB::is_parent_class(return_info.class_name, r_context.names_cache.reference_class);
+ TEST_COND(bad_reference_hint, String() + "Return type is reference but hint is not '" _STR(PROPERTY_HINT_RESOURCE_TYPE) "'." +
+ " Are you returning a reference type by pointer? Method: '" +
+ exposed_class.name + "." + method.name + "'.");
+ } else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) {
+ method.return_type.name = return_info.hint_string;
+ } else if (return_info.type == Variant::NIL && return_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
+ method.return_type.name = r_context.names_cache.variant_type;
+ } else if (return_info.type == Variant::NIL) {
+ method.return_type.name = r_context.names_cache.void_type;
+ } else {
+ // NOTE: We don't care about the size and sign of int and float in these tests
+ method.return_type.name = Variant::get_type_name(return_info.type);
+ }
+
+ for (int i = 0; i < argc; i++) {
+ PropertyInfo arg_info = method_info.arguments[i];
+
+ String orig_arg_name = arg_info.name;
+
+ ArgumentData arg;
+ arg.name = orig_arg_name;
+
+ if (arg_info.type == Variant::INT && arg_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
+ arg.type.name = arg_info.class_name;
+ arg.type.is_enum = true;
+ } else if (arg_info.class_name != StringName()) {
+ arg.type.name = arg_info.class_name;
+ } else if (arg_info.hint == PROPERTY_HINT_RESOURCE_TYPE) {
+ arg.type.name = arg_info.hint_string;
+ } else if (arg_info.type == Variant::NIL) {
+ arg.type.name = r_context.names_cache.variant_type;
+ } else {
+ // NOTE: We don't care about the size and sign of int and float in these tests
+ arg.type.name = Variant::get_type_name(arg_info.type);
+ }
+
+ if (m && m->has_default_argument(i)) {
+ arg.has_defval = true;
+ arg.defval = m->get_default_argument(i);
+ }
+
+ method.arguments.push_back(arg);
+ }
+
+ if (method.is_vararg) {
+ ArgumentData vararg;
+ vararg.type.name = r_context.names_cache.vararg_stub_type;
+ vararg.name = "@varargs@";
+ method.arguments.push_back(vararg);
+ }
+
+ TEST_COND(exposed_class.find_property_by_name(method.name),
+ "Method name conflicts with property: '" + String(class_name) + "." + String(method.name) + "'.");
+
+ // Classes starting with an underscore are ignored unless they're used as a property setter or getter
+ if (!method.is_virtual && String(method.name)[0] == '_') {
+ for (const List<PropertyData>::Element *F = exposed_class.properties.front(); F; F = F->next()) {
+ const PropertyData &prop = F->get();
+
+ if (prop.setter == method.name || prop.getter == method.name) {
+ exposed_class.methods.push_back(method);
+ break;
+ }
+ }
+ } else {
+ exposed_class.methods.push_back(method);
+ }
+ }
+
+ // Add signals
+
+ const HashMap<StringName, MethodInfo> &signal_map = class_info->signal_map;
+ const StringName *k = nullptr;
+
+ while ((k = signal_map.next(k))) {
+ SignalData signal;
+
+ const MethodInfo &method_info = signal_map.get(*k);
+
+ signal.name = method_info.name;
+
+ int argc = method_info.arguments.size();
+
+ for (int i = 0; i < argc; i++) {
+ PropertyInfo arg_info = method_info.arguments[i];
+
+ String orig_arg_name = arg_info.name;
+
+ ArgumentData arg;
+ arg.name = orig_arg_name;
+
+ if (arg_info.type == Variant::INT && arg_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
+ arg.type.name = arg_info.class_name;
+ arg.type.is_enum = true;
+ } else if (arg_info.class_name != StringName()) {
+ arg.type.name = arg_info.class_name;
+ } else if (arg_info.hint == PROPERTY_HINT_RESOURCE_TYPE) {
+ arg.type.name = arg_info.hint_string;
+ } else if (arg_info.type == Variant::NIL) {
+ arg.type.name = r_context.names_cache.variant_type;
+ } else {
+ // NOTE: We don't care about the size and sign of int and float in these tests
+ arg.type.name = Variant::get_type_name(arg_info.type);
+ }
+
+ signal.arguments.push_back(arg);
+ }
+
+ bool method_conflict = exposed_class.find_property_by_name(signal.name);
+
+ if (method_conflict || exposed_class.find_method_by_name(signal.name)) {
+ // TODO:
+ // ClassDB allows signal names that conflict with method or property names.
+ // However registering a signal with a conflicting name is still considered wrong.
+ // Unfortunately there are some existing cases that are yet to be fixed.
+ // Until those are fixed we will print a warning instead of failing the test.
+ WARN_PRINT("Signal name conflicts with " + String(method_conflict ? "method" : "property") +
+ ": '" + String(class_name) + "." + String(signal.name) + "'.");
+ }
+
+ exposed_class.signals_.push_back(signal);
+ }
+
+ // Add enums and constants
+
+ List<String> constants;
+ ClassDB::get_integer_constant_list(class_name, &constants, true);
+
+ const HashMap<StringName, List<StringName>> &enum_map = class_info->enum_map;
+ k = nullptr;
+
+ while ((k = enum_map.next(k))) {
+ EnumData enum_;
+ enum_.name = *k;
+
+ const List<StringName> &enum_constants = enum_map.get(*k);
+ for (const List<StringName>::Element *E = enum_constants.front(); E; E = E->next()) {
+ const StringName &constant_name = E->get();
+ int *value = class_info->constant_map.getptr(constant_name);
+ TEST_FAIL_COND(!value, "Missing enum constant value: '" +
+ String(class_name) + "." + String(enum_.name) + "." + String(constant_name) + "'.");
+ constants.erase(constant_name);
+
+ ConstantData constant;
+ constant.name = constant_name;
+ constant.value = *value;
+
+ enum_.constants.push_back(constant);
+ }
+
+ exposed_class.enums.push_back(enum_);
+
+ r_context.enum_types.push_back(String(class_name) + "." + String(*k));
+ }
+
+ for (const List<String>::Element *E = constants.front(); E; E = E->next()) {
+ const String &constant_name = E->get();
+ int *value = class_info->constant_map.getptr(StringName(E->get()));
+ TEST_FAIL_COND(!value, "Missing enum constant value: '" + String(class_name) + "." + String(constant_name) + "'.");
+
+ ConstantData constant;
+ constant.name = constant_name;
+ constant.value = *value;
+
+ exposed_class.constants.push_back(constant);
+ }
+
+ r_context.exposed_classes.insert(class_name, exposed_class);
+ class_list.pop_front();
+ }
+
+ TEST_END();
+}
+
+void add_builtin_types(Context &r_context) {
+ // NOTE: We don't care about the size and sign of int and float in these tests
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ r_context.builtin_types.push_back(Variant::get_type_name(Variant::Type(i)));
+ }
+
+ r_context.builtin_types.push_back(_STR(Variant));
+ r_context.builtin_types.push_back(r_context.names_cache.vararg_stub_type);
+ r_context.builtin_types.push_back("void");
+}
+
+void add_global_enums(Context &r_context) {
+ int global_constants_count = GlobalConstants::get_global_constant_count();
+
+ if (global_constants_count > 0) {
+ for (int i = 0; i < global_constants_count; i++) {
+ StringName enum_name = GlobalConstants::get_global_constant_enum(i);
+
+ if (enum_name != StringName()) {
+ ConstantData constant;
+ constant.name = GlobalConstants::get_global_constant_name(i);
+ constant.value = GlobalConstants::get_global_constant_value(i);
+
+ EnumData enum_;
+ enum_.name = enum_name;
+ List<EnumData>::Element *enum_match = r_context.global_enums.find(enum_);
+ if (enum_match) {
+ enum_match->get().constants.push_back(constant);
+ } else {
+ enum_.constants.push_back(constant);
+ r_context.global_enums.push_back(enum_);
+ }
+ }
+ }
+
+ for (List<EnumData>::Element *E = r_context.global_enums.front(); E; E = E->next()) {
+ r_context.enum_types.push_back(E->get().name);
+ }
+ }
+
+ // HARDCODED
+ List<StringName> hardcoded_enums;
+ hardcoded_enums.push_back("Vector2.Axis");
+ hardcoded_enums.push_back("Vector2i.Axis");
+ hardcoded_enums.push_back("Vector3.Axis");
+ hardcoded_enums.push_back("Vector3i.Axis");
+ for (List<StringName>::Element *E = hardcoded_enums.front(); E; E = E->next()) {
+ // These enums are not generated and must be written manually (e.g.: Vector3.Axis)
+ // Here, we assume core types do not begin with underscore
+ r_context.enum_types.push_back(E->get());
+ }
+}
+
+TestResult run_class_db_tests() {
+ TEST_START();
+
+ Context context;
+
+ TEST_FAIL_CHECK(add_exposed_classes(context));
+ add_builtin_types(context);
+ add_global_enums(context);
+
+ const ExposedClass *object_class = context.find_exposed_class(context.names_cache.object_class);
+ TEST_FAIL_COND(!object_class, "Object class not found.");
+ TEST_FAIL_COND(object_class->base != StringName(),
+ "Object class derives from another class: '" + object_class->base + "'.");
+
+ for (ExposedClasses::Element E = context.exposed_classes.front(); E; E = E.next()) {
+ TEST_CHECK(validate_class(context, E.value()));
+ }
+
+ TEST_END();
+}
+
+MainLoop *test() {
+ TestResult pass = run_class_db_tests();
+
+ OS::get_singleton()->print("ClassDB tests: %s\n", pass == TestResult::PASS ? "PASS" : "FAILED");
+
+ if (pass == TestResult::FAILED) {
+ OS::get_singleton()->set_exit_code(pass == TestResult::PASS ? 0 : 1);
+ }
+
+ return nullptr;
+}
+
+} // namespace TestClassDB
diff --git a/main/tests/test_class_db.h b/main/tests/test_class_db.h
new file mode 100644
index 0000000000..1a31cfb01b
--- /dev/null
+++ b/main/tests/test_class_db.h
@@ -0,0 +1,42 @@
+/*************************************************************************/
+/* test_class_db.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GODOT_TEST_CLASS_DB_H
+#define GODOT_TEST_CLASS_DB_H
+
+#include "core/os/main_loop.h"
+
+namespace TestClassDB {
+
+MainLoop *test();
+
+}
+
+#endif //GODOT_TEST_CLASS_DB_H
diff --git a/main/tests/test_gdscript.cpp b/main/tests/test_gdscript.cpp
index 0e7c45f603..10586c6495 100644
--- a/main/tests/test_gdscript.cpp
+++ b/main/tests/test_gdscript.cpp
@@ -45,7 +45,6 @@
namespace TestGDScript {
static void _print_indent(int p_ident, const String &p_text) {
-
String txt;
for (int i = 0; i < p_ident; i++) {
txt += '\t';
@@ -55,18 +54,18 @@ static void _print_indent(int p_ident, const String &p_text) {
}
static String _parser_extends(const GDScriptParser::ClassNode *p_class) {
-
String txt = "extends ";
if (String(p_class->extends_file) != "") {
txt += "\"" + p_class->extends_file + "\"";
- if (p_class->extends_class.size())
+ if (p_class->extends_class.size()) {
txt += ".";
+ }
}
for (int i = 0; i < p_class->extends_class.size(); i++) {
-
- if (i != 0)
+ if (i != 0) {
txt += ".";
+ }
txt += p_class->extends_class[i];
}
@@ -75,21 +74,19 @@ static String _parser_extends(const GDScriptParser::ClassNode *p_class) {
}
static String _parser_expr(const GDScriptParser::Node *p_expr) {
-
String txt;
switch (p_expr->type) {
-
case GDScriptParser::Node::TYPE_IDENTIFIER: {
-
const GDScriptParser::IdentifierNode *id_node = static_cast<const GDScriptParser::IdentifierNode *>(p_expr);
txt = id_node->name;
} break;
case GDScriptParser::Node::TYPE_CONSTANT: {
const GDScriptParser::ConstantNode *c_node = static_cast<const GDScriptParser::ConstantNode *>(p_expr);
- if (c_node->value.get_type() == Variant::STRING)
+ if (c_node->value.get_type() == Variant::STRING) {
txt = "\"" + String(c_node->value) + "\"";
- else
+ } else {
txt = c_node->value;
+ }
} break;
case GDScriptParser::Node::TYPE_SELF: {
@@ -99,9 +96,9 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) {
const GDScriptParser::ArrayNode *arr_node = static_cast<const GDScriptParser::ArrayNode *>(p_expr);
txt += "[";
for (int i = 0; i < arr_node->elements.size(); i++) {
-
- if (i > 0)
+ if (i > 0) {
txt += ", ";
+ }
txt += _parser_expr(arr_node->elements[i]);
}
txt += "]";
@@ -110,9 +107,9 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) {
const GDScriptParser::DictionaryNode *dict_node = static_cast<const GDScriptParser::DictionaryNode *>(p_expr);
txt += "{";
for (int i = 0; i < dict_node->elements.size(); i++) {
-
- if (i > 0)
+ if (i > 0) {
txt += ", ";
+ }
const GDScriptParser::DictionaryNode::Pair &p = dict_node->elements[i];
txt += _parser_expr(p.key);
@@ -122,37 +119,32 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) {
txt += "}";
} break;
case GDScriptParser::Node::TYPE_OPERATOR: {
-
const GDScriptParser::OperatorNode *c_node = static_cast<const GDScriptParser::OperatorNode *>(p_expr);
switch (c_node->op) {
-
case GDScriptParser::OperatorNode::OP_PARENT_CALL:
txt += ".";
[[fallthrough]];
case GDScriptParser::OperatorNode::OP_CALL: {
-
ERR_FAIL_COND_V(c_node->arguments.size() < 1, "");
String func_name;
const GDScriptParser::Node *nfunc = c_node->arguments[0];
int arg_ofs = 0;
if (nfunc->type == GDScriptParser::Node::TYPE_BUILT_IN_FUNCTION) {
-
const GDScriptParser::BuiltInFunctionNode *bif_node = static_cast<const GDScriptParser::BuiltInFunctionNode *>(nfunc);
func_name = GDScriptFunctions::get_func_name(bif_node->function);
arg_ofs = 1;
} else if (nfunc->type == GDScriptParser::Node::TYPE_TYPE) {
-
const GDScriptParser::TypeNode *t_node = static_cast<const GDScriptParser::TypeNode *>(nfunc);
func_name = Variant::get_type_name(t_node->vtype);
arg_ofs = 1;
} else {
-
ERR_FAIL_COND_V(c_node->arguments.size() < 2, "");
nfunc = c_node->arguments[1];
ERR_FAIL_COND_V(nfunc->type != GDScriptParser::Node::TYPE_IDENTIFIER, "");
- if (c_node->arguments[0]->type != GDScriptParser::Node::TYPE_SELF)
+ if (c_node->arguments[0]->type != GDScriptParser::Node::TYPE_SELF) {
func_name = _parser_expr(c_node->arguments[0]) + ".";
+ }
func_name += _parser_expr(nfunc);
arg_ofs = 2;
@@ -161,10 +153,10 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) {
txt += func_name + "(";
for (int i = arg_ofs; i < c_node->arguments.size(); i++) {
-
const GDScriptParser::Node *arg = c_node->arguments[i];
- if (i > arg_ofs)
+ if (i > arg_ofs) {
txt += ", ";
+ }
txt += _parser_expr(arg);
}
@@ -172,7 +164,6 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) {
} break;
case GDScriptParser::OperatorNode::OP_INDEX: {
-
ERR_FAIL_COND_V(c_node->arguments.size() != 2, "");
//index with []
@@ -180,7 +171,6 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) {
} break;
case GDScriptParser::OperatorNode::OP_INDEX_NAMED: {
-
ERR_FAIL_COND_V(c_node->arguments.size() != 2, "");
txt = _parser_expr(c_node->arguments[0]) + "." + _parser_expr(c_node->arguments[1]);
@@ -296,11 +286,9 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) {
} break;
case GDScriptParser::Node::TYPE_NEWLINE: {
-
//skippie
} break;
default: {
-
ERR_FAIL_V_MSG("", "Parser bug at " + itos(p_expr->line) + ", invalid expression type: " + itos(p_expr->type));
}
}
@@ -309,20 +297,14 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) {
}
static void _parser_show_block(const GDScriptParser::BlockNode *p_block, int p_indent) {
-
for (int i = 0; i < p_block->statements.size(); i++) {
-
const GDScriptParser::Node *statement = p_block->statements[i];
switch (statement->type) {
-
case GDScriptParser::Node::TYPE_CONTROL_FLOW: {
-
const GDScriptParser::ControlFlowNode *cf_node = static_cast<const GDScriptParser::ControlFlowNode *>(statement);
switch (cf_node->cf_type) {
-
case GDScriptParser::ControlFlowNode::CF_IF: {
-
ERR_FAIL_COND(cf_node->arguments.size() != 1);
String txt;
txt += "if ";
@@ -351,7 +333,6 @@ static void _parser_show_block(const GDScriptParser::BlockNode *p_block, int p_i
} break;
case GDScriptParser::ControlFlowNode::CF_WHILE: {
-
ERR_FAIL_COND(cf_node->arguments.size() != 1);
String txt;
txt += "while ";
@@ -366,25 +347,22 @@ static void _parser_show_block(const GDScriptParser::BlockNode *p_block, int p_i
// FIXME: Implement
} break;
case GDScriptParser::ControlFlowNode::CF_CONTINUE: {
-
_print_indent(p_indent, "continue");
} break;
case GDScriptParser::ControlFlowNode::CF_BREAK: {
-
_print_indent(p_indent, "break");
} break;
case GDScriptParser::ControlFlowNode::CF_RETURN: {
-
- if (cf_node->arguments.size())
+ if (cf_node->arguments.size()) {
_print_indent(p_indent, "return " + _parser_expr(cf_node->arguments[0]));
- else
+ } else {
_print_indent(p_indent, "return ");
+ }
} break;
}
} break;
case GDScriptParser::Node::TYPE_LOCAL_VAR: {
-
const GDScriptParser::LocalVarNode *lv_node = static_cast<const GDScriptParser::LocalVarNode *>(statement);
_print_indent(p_indent, "var " + String(lv_node->name));
} break;
@@ -396,22 +374,23 @@ static void _parser_show_block(const GDScriptParser::BlockNode *p_block, int p_i
}
}
-static void _parser_show_function(const GDScriptParser::FunctionNode *p_func, int p_indent, GDScriptParser::BlockNode *p_initializer = NULL) {
-
+static void _parser_show_function(const GDScriptParser::FunctionNode *p_func, int p_indent, GDScriptParser::BlockNode *p_initializer = nullptr) {
String txt;
- if (p_func->_static)
+ if (p_func->_static) {
txt = "static ";
+ }
txt += "func ";
- if (p_func->name == "") // initializer
+ if (p_func->name == "") { // initializer
txt += "[built-in-initializer]";
- else
+ } else {
txt += String(p_func->name);
+ }
txt += "(";
for (int i = 0; i < p_func->arguments.size(); i++) {
-
- if (i != 0)
+ if (i != 0) {
txt += ", ";
+ }
txt += "var " + String(p_func->arguments[i]);
if (i >= (p_func->arguments.size() - p_func->default_values.size())) {
int defarg = i - (p_func->arguments.size() - p_func->default_values.size());
@@ -427,25 +406,24 @@ static void _parser_show_function(const GDScriptParser::FunctionNode *p_func, in
txt += ":";
_print_indent(p_indent, txt);
- if (p_initializer)
+ if (p_initializer) {
_parser_show_block(p_initializer, p_indent + 1);
+ }
_parser_show_block(p_func->body, p_indent + 1);
}
static void _parser_show_class(const GDScriptParser::ClassNode *p_class, int p_indent, const Vector<String> &p_code) {
-
if (p_indent == 0 && (String(p_class->extends_file) != "" || p_class->extends_class.size())) {
-
_print_indent(p_indent, _parser_extends(p_class));
print_line("\n");
}
for (int i = 0; i < p_class->subclasses.size(); i++) {
-
const GDScriptParser::ClassNode *subclass = p_class->subclasses[i];
String line = "class " + subclass->name;
- if (String(subclass->extends_file) != "" || subclass->extends_class.size())
+ if (String(subclass->extends_file) != "" || subclass->extends_class.size()) {
line += " " + _parser_extends(subclass);
+ }
line += ":";
_print_indent(p_indent, line);
_parser_show_class(subclass, p_indent + 1, p_code);
@@ -458,7 +436,6 @@ static void _parser_show_class(const GDScriptParser::ClassNode *p_class, int p_i
}
for (int i = 0; i < p_class->variables.size(); i++) {
-
const GDScriptParser::ClassNode::Member &m = p_class->variables[i];
_print_indent(p_indent, "var " + String(m.identifier));
@@ -467,17 +444,16 @@ static void _parser_show_class(const GDScriptParser::ClassNode *p_class, int p_i
print_line("\n");
for (int i = 0; i < p_class->static_functions.size(); i++) {
-
_parser_show_function(p_class->static_functions[i], p_indent);
print_line("\n");
}
for (int i = 0; i < p_class->functions.size(); i++) {
-
if (String(p_class->functions[i]->name) == "_init") {
_parser_show_function(p_class->functions[i], p_indent, p_class->initializer);
- } else
+ } else {
_parser_show_function(p_class->functions[i], p_indent);
+ }
print_line("\n");
}
//_parser_show_function(p_class->initializer,p_indent);
@@ -485,11 +461,9 @@ static void _parser_show_class(const GDScriptParser::ClassNode *p_class, int p_i
}
static String _disassemble_addr(const Ref<GDScript> &p_script, const GDScriptFunction &func, int p_addr) {
-
int addr = p_addr & GDScriptFunction::ADDR_MASK;
switch (p_addr >> GDScriptFunction::ADDR_BITS) {
-
case GDScriptFunction::ADDR_TYPE_SELF: {
return "self";
} break;
@@ -497,33 +471,28 @@ static String _disassemble_addr(const Ref<GDScript> &p_script, const GDScriptFun
return "class";
} break;
case GDScriptFunction::ADDR_TYPE_MEMBER: {
-
return "member(" + p_script->debug_get_member_by_index(addr) + ")";
} break;
case GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT: {
-
return "class_const(" + func.get_global_name(addr) + ")";
} break;
case GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT: {
-
Variant v = func.get_constant(addr);
String txt;
- if (v.get_type() == Variant::STRING || v.get_type() == Variant::NODE_PATH)
+ if (v.get_type() == Variant::STRING || v.get_type() == Variant::NODE_PATH) {
txt = "\"" + String(v) + "\"";
- else
+ } else {
txt = v;
+ }
return "const(" + txt + ")";
} break;
case GDScriptFunction::ADDR_TYPE_STACK: {
-
return "stack(" + itos(addr) + ")";
} break;
case GDScriptFunction::ADDR_TYPE_STACK_VARIABLE: {
-
return "var_stack(" + itos(addr) + ")";
} break;
case GDScriptFunction::ADDR_TYPE_GLOBAL: {
-
return "global(" + func.get_global_name(addr) + ")";
} break;
case GDScriptFunction::ADDR_TYPE_NIL: {
@@ -535,11 +504,9 @@ static String _disassemble_addr(const Ref<GDScript> &p_script, const GDScriptFun
}
static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String> &p_code) {
-
const Map<StringName, GDScriptFunction *> &mf = p_class->debug_get_member_functions();
for (const Map<StringName, GDScriptFunction *>::Element *E = mf.front(); E; E = E->next()) {
-
const GDScriptFunction &func = *E->get();
const int *code = func.get_code();
int codelen = func.get_code_size();
@@ -547,9 +514,9 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
if (func.get_default_argument_count()) {
defargs = "defarg at: ";
for (int i = 0; i < func.get_default_argument_count(); i++) {
-
- if (i > 0)
+ if (i > 0) {
defargs += ",";
+ }
defargs += itos(func.get_default_argument_addr(i));
}
defargs += " ";
@@ -559,14 +526,11 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
#define DADDR(m_ip) (_disassemble_addr(p_class, func, code[ip + m_ip]))
for (int ip = 0; ip < codelen;) {
-
int incr = 0;
String txt = itos(ip) + " ";
switch (code[ip]) {
-
case GDScriptFunction::OPCODE_OPERATOR: {
-
int op = code[ip + 1];
txt += " op ";
@@ -581,7 +545,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_SET: {
-
txt += "set ";
txt += DADDR(1);
txt += "[";
@@ -592,7 +555,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_GET: {
-
txt += " get ";
txt += DADDR(3);
txt += "=";
@@ -604,7 +566,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_SET_NAMED: {
-
txt += " set_named ";
txt += DADDR(1);
txt += "[\"";
@@ -615,7 +576,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_GET_NAMED: {
-
txt += " get_named ";
txt += DADDR(3);
txt += "=";
@@ -627,7 +587,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_SET_MEMBER: {
-
txt += " set_member ";
txt += "[\"";
txt += func.get_global_name(code[ip + 1]);
@@ -637,7 +596,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_GET_MEMBER: {
-
txt += " get_member ";
txt += DADDR(2);
txt += "=";
@@ -648,7 +606,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_ASSIGN: {
-
txt += " assign ";
txt += DADDR(1);
txt += "=";
@@ -657,7 +614,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_ASSIGN_TRUE: {
-
txt += " assign ";
txt += DADDR(1);
txt += "= true";
@@ -665,7 +621,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_ASSIGN_FALSE: {
-
txt += " assign ";
txt += DADDR(1);
txt += "= false";
@@ -673,7 +628,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN: {
-
txt += " assign typed builtin (";
txt += Variant::get_type_name((Variant::Type)code[ip + 1]);
txt += ") ";
@@ -697,7 +651,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_CAST_TO_SCRIPT: {
-
txt += " cast ";
txt += DADDR(3);
txt += "=";
@@ -708,7 +661,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_CONSTRUCT: {
-
Variant::Type t = Variant::Type(code[ip + 1]);
int argc = code[ip + 2];
@@ -718,9 +670,9 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
txt += Variant::get_type_name(t) + "(";
for (int i = 0; i < argc; i++) {
-
- if (i > 0)
+ if (i > 0) {
txt += ", ";
+ }
txt += DADDR(i + 3);
}
txt += ")";
@@ -729,15 +681,15 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_CONSTRUCT_ARRAY: {
-
int argc = code[ip + 1];
txt += " make_array ";
txt += DADDR(2 + argc);
txt += " = [ ";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
txt += ", ";
+ }
txt += DADDR(2 + i);
}
@@ -747,15 +699,15 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_CONSTRUCT_DICTIONARY: {
-
int argc = code[ip + 1];
txt += " make_dict ";
txt += DADDR(2 + argc * 2);
txt += " = { ";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
txt += ", ";
+ }
txt += DADDR(2 + i * 2 + 0);
txt += ":";
txt += DADDR(2 + i * 2 + 1);
@@ -769,13 +721,13 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
case GDScriptFunction::OPCODE_CALL:
case GDScriptFunction::OPCODE_CALL_RETURN: {
-
bool ret = code[ip] == GDScriptFunction::OPCODE_CALL_RETURN;
- if (ret)
+ if (ret) {
txt += " call-ret ";
- else
+ } else {
txt += " call ";
+ }
int argc = code[ip + 1];
if (ret) {
@@ -787,8 +739,9 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
txt += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
txt += ", ";
+ }
txt += DADDR(4 + i);
}
txt += ")";
@@ -797,7 +750,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_CALL_BUILT_IN: {
-
txt += " call-built-in ";
int argc = code[ip + 2];
@@ -807,8 +759,9 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
txt += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
txt += ", ";
+ }
txt += DADDR(3 + i);
}
txt += ")";
@@ -817,7 +770,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_CALL_SELF_BASE: {
-
txt += " call-self-base ";
int argc = code[ip + 2];
@@ -827,8 +779,9 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
txt += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
txt += ", ";
+ }
txt += DADDR(3 + i);
}
txt += ")";
@@ -837,13 +790,11 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_YIELD: {
-
txt += " yield ";
incr = 1;
} break;
case GDScriptFunction::OPCODE_YIELD_SIGNAL: {
-
txt += " yield_signal ";
txt += DADDR(1);
txt += ",";
@@ -851,13 +802,11 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
incr = 3;
} break;
case GDScriptFunction::OPCODE_YIELD_RESUME: {
-
txt += " yield resume: ";
txt += DADDR(1);
incr = 2;
} break;
case GDScriptFunction::OPCODE_JUMP: {
-
txt += " jump ";
txt += itos(code[ip + 1]);
@@ -865,7 +814,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_JUMP_IF: {
-
txt += " jump-if ";
txt += DADDR(1);
txt += " to ";
@@ -874,7 +822,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
incr = 3;
} break;
case GDScriptFunction::OPCODE_JUMP_IF_NOT: {
-
txt += " jump-if-not ";
txt += DADDR(1);
txt += " to ";
@@ -883,12 +830,10 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
incr = 3;
} break;
case GDScriptFunction::OPCODE_JUMP_TO_DEF_ARGUMENT: {
-
txt += " jump-to-default-argument ";
incr = 1;
} break;
case GDScriptFunction::OPCODE_RETURN: {
-
txt += " return ";
txt += DADDR(1);
@@ -896,33 +841,29 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
} break;
case GDScriptFunction::OPCODE_ITERATE_BEGIN: {
-
txt += " for-init " + DADDR(4) + " in " + DADDR(2) + " counter " + DADDR(1) + " end " + itos(code[ip + 3]);
incr += 5;
} break;
case GDScriptFunction::OPCODE_ITERATE: {
-
txt += " for-loop " + DADDR(4) + " in " + DADDR(2) + " counter " + DADDR(1) + " end " + itos(code[ip + 3]);
incr += 5;
} break;
case GDScriptFunction::OPCODE_LINE: {
-
int line = code[ip + 1] - 1;
- if (line >= 0 && line < p_code.size())
+ if (line >= 0 && line < p_code.size()) {
txt = "\n" + itos(line + 1) + ": " + p_code[line] + "\n";
- else
+ } else {
txt = "";
+ }
incr += 2;
} break;
case GDScriptFunction::OPCODE_END: {
-
txt += " end";
incr += 1;
} break;
case GDScriptFunction::OPCODE_ASSERT: {
-
txt += " assert ";
txt += DADDR(1);
incr += 2;
@@ -931,33 +872,32 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String
}
if (incr == 0) {
-
ERR_BREAK_MSG(true, "Unhandled opcode: " + itos(code[ip]));
}
ip += incr;
- if (txt != "")
+ if (txt != "") {
print_line(txt);
+ }
}
}
}
MainLoop *test(TestType p_type) {
-
List<String> cmdlargs = OS::get_singleton()->get_cmdline_args();
if (cmdlargs.empty()) {
- return NULL;
+ return nullptr;
}
String test = cmdlargs.back()->get();
if (!test.ends_with(".gd") && !test.ends_with(".gdc")) {
print_line("This test expects a path to a GDScript file as its last parameter. Got: " + test);
- return NULL;
+ return nullptr;
}
FileAccess *fa = FileAccess::open(test, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(!fa, NULL, "Could not open file: " + test);
+ ERR_FAIL_COND_V_MSG(!fa, nullptr, "Could not open file: " + test);
Vector<uint8_t> buf;
int flen = fa->get_len();
@@ -972,40 +912,38 @@ MainLoop *test(TestType p_type) {
int last = 0;
for (int i = 0; i <= code.length(); i++) {
-
if (code[i] == '\n' || code[i] == 0) {
-
lines.push_back(code.substr(last, i - last));
last = i + 1;
}
}
if (p_type == TEST_TOKENIZER) {
-
GDScriptTokenizerText tk;
tk.set_code(code);
int line = -1;
while (tk.get_token() != GDScriptTokenizer::TK_EOF) {
-
String text;
- if (tk.get_token() == GDScriptTokenizer::TK_IDENTIFIER)
+ if (tk.get_token() == GDScriptTokenizer::TK_IDENTIFIER) {
text = "'" + tk.get_token_identifier() + "' (identifier)";
- else if (tk.get_token() == GDScriptTokenizer::TK_CONSTANT) {
+ } else if (tk.get_token() == GDScriptTokenizer::TK_CONSTANT) {
const Variant &c = tk.get_token_constant();
- if (c.get_type() == Variant::STRING)
+ if (c.get_type() == Variant::STRING) {
text = "\"" + String(c) + "\"";
- else
+ } else {
text = c;
+ }
text = text + " (" + Variant::get_type_name(c.get_type()) + " constant)";
- } else if (tk.get_token() == GDScriptTokenizer::TK_ERROR)
+ } else if (tk.get_token() == GDScriptTokenizer::TK_ERROR) {
text = "ERROR: " + tk.get_token_error();
- else if (tk.get_token() == GDScriptTokenizer::TK_NEWLINE)
+ } else if (tk.get_token() == GDScriptTokenizer::TK_NEWLINE) {
text = "newline (" + itos(tk.get_token_line()) + ") + indent: " + itos(tk.get_token_line_indent());
- else if (tk.get_token() == GDScriptTokenizer::TK_BUILT_IN_FUNC)
+ } else if (tk.get_token() == GDScriptTokenizer::TK_BUILT_IN_FUNC) {
text = "'" + String(GDScriptFunctions::get_func_name(tk.get_token_built_in_func())) + "' (built-in function)";
- else
+ } else {
text = tk.get_token_name(tk.get_token());
+ }
if (tk.get_token_line() != line) {
int from = line + 1;
@@ -1024,31 +962,29 @@ MainLoop *test(TestType p_type) {
}
if (p_type == TEST_PARSER) {
-
GDScriptParser parser;
Error err = parser.parse(code);
if (err) {
print_line("Parse Error:\n" + itos(parser.get_error_line()) + ":" + itos(parser.get_error_column()) + ":" + parser.get_error());
memdelete(fa);
- return NULL;
+ return nullptr;
}
const GDScriptParser::Node *root = parser.get_parse_tree();
- ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, NULL);
+ ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, nullptr);
const GDScriptParser::ClassNode *cnode = static_cast<const GDScriptParser::ClassNode *>(root);
_parser_show_class(cnode, 0, lines);
}
if (p_type == TEST_COMPILER) {
-
GDScriptParser parser;
Error err = parser.parse(code);
if (err) {
print_line("Parse Error:\n" + itos(parser.get_error_line()) + ":" + itos(parser.get_error_column()) + ":" + parser.get_error());
memdelete(fa);
- return NULL;
+ return nullptr;
}
Ref<GDScript> gds;
@@ -1057,15 +993,13 @@ MainLoop *test(TestType p_type) {
GDScriptCompiler gdc;
err = gdc.compile(&parser, gds.ptr());
if (err) {
-
print_line("Compile Error:\n" + itos(gdc.get_error_line()) + ":" + itos(gdc.get_error_column()) + ":" + gdc.get_error());
- return NULL;
+ return nullptr;
}
Ref<GDScript> current = gds;
while (current.is_valid()) {
-
print_line("** CLASS **");
_disassemble_class(current, lines);
@@ -1073,7 +1007,6 @@ MainLoop *test(TestType p_type) {
}
} else if (p_type == TEST_BYTECODE) {
-
Vector<uint8_t> buf2 = GDScriptTokenizerBuffer::parse_code_string(code);
String dst = test.get_basename() + ".gdc";
FileAccess *fw = FileAccess::open(dst, FileAccess::WRITE);
@@ -1083,8 +1016,9 @@ MainLoop *test(TestType p_type) {
memdelete(fa);
- return NULL;
+ return nullptr;
}
+
} // namespace TestGDScript
#else
@@ -1093,8 +1027,9 @@ namespace TestGDScript {
MainLoop *test(TestType p_type) {
ERR_PRINT("The GDScript module is disabled, therefore GDScript tests cannot be used.");
- return NULL;
+ return nullptr;
}
+
} // namespace TestGDScript
#endif
diff --git a/main/tests/test_gui.cpp b/main/tests/test_gui.cpp
index c5c8917a51..d46a13d2c0 100644
--- a/main/tests/test_gui.cpp
+++ b/main/tests/test_gui.cpp
@@ -59,14 +59,11 @@
namespace TestGUI {
class TestMainLoop : public SceneTree {
-
public:
virtual void request_quit() {
-
quit();
}
virtual void init() {
-
SceneTree::init();
Panel *frame = memnew(Panel);
@@ -266,9 +263,9 @@ public:
};
MainLoop *test() {
-
return memnew(TestMainLoop);
}
+
} // namespace TestGUI
#endif
diff --git a/main/tests/test_main.cpp b/main/tests/test_main.cpp
index a9a671e2f1..0bb8367240 100644
--- a/main/tests/test_main.cpp
+++ b/main/tests/test_main.cpp
@@ -35,6 +35,7 @@
#ifdef DEBUG_ENABLED
#include "test_astar.h"
+#include "test_class_db.h"
#include "test_gdscript.h"
#include "test_gui.h"
#include "test_math.h"
@@ -47,7 +48,6 @@
#include "test_string.h"
const char **tests_get_names() {
-
static const char *test_names[] = {
"string",
"math",
@@ -55,6 +55,7 @@ const char **tests_get_names() {
"physics_3d",
"render",
"oa_hash_map",
+ "class_db",
"gui",
"shaderlang",
"gd_tokenizer",
@@ -63,104 +64,91 @@ const char **tests_get_names() {
"gd_bytecode",
"ordered_hash_map",
"astar",
- NULL
+ nullptr
};
return test_names;
}
MainLoop *test_main(String p_test, const List<String> &p_args) {
-
if (p_test == "string") {
-
return TestString::test();
}
if (p_test == "math") {
-
return TestMath::test();
}
if (p_test == "physics_2d") {
-
return TestPhysics2D::test();
}
if (p_test == "physics_3d") {
-
return TestPhysics3D::test();
}
if (p_test == "render") {
-
return TestRender::test();
}
if (p_test == "oa_hash_map") {
-
return TestOAHashMap::test();
}
+ if (p_test == "class_db") {
+ return TestClassDB::test();
+ }
+
#ifndef _3D_DISABLED
if (p_test == "gui") {
-
return TestGUI::test();
}
#endif
if (p_test == "shaderlang") {
-
return TestShaderLang::test();
}
if (p_test == "gd_tokenizer") {
-
return TestGDScript::test(TestGDScript::TEST_TOKENIZER);
}
if (p_test == "gd_parser") {
-
return TestGDScript::test(TestGDScript::TEST_PARSER);
}
if (p_test == "gd_compiler") {
-
return TestGDScript::test(TestGDScript::TEST_COMPILER);
}
if (p_test == "gd_bytecode") {
-
return TestGDScript::test(TestGDScript::TEST_BYTECODE);
}
if (p_test == "ordered_hash_map") {
-
return TestOrderedHashMap::test();
}
if (p_test == "astar") {
-
return TestAStar::test();
}
print_line("Unknown test: " + p_test);
- return NULL;
+ return nullptr;
}
#else
const char **tests_get_names() {
-
static const char *test_names[] = {
- NULL
+ nullptr
};
return test_names;
}
MainLoop *test_main(String p_test, const List<String> &p_args) {
-
- return NULL;
+ return nullptr;
}
#endif
diff --git a/main/tests/test_math.cpp b/main/tests/test_math.cpp
index 29fa5e73a7..9e159798bb 100644
--- a/main/tests/test_math.cpp
+++ b/main/tests/test_math.cpp
@@ -32,8 +32,10 @@
#include "core/math/basis.h"
#include "core/math/camera_matrix.h"
+#include "core/math/delaunay_3d.h"
#include "core/math/math_funcs.h"
#include "core/math/transform.h"
+#include "core/method_ptrcall.h"
#include "core/os/file_access.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
@@ -45,12 +47,9 @@
#include "scene/resources/texture.h"
#include "servers/rendering/shader_language.h"
-#include "core/method_ptrcall.h"
-
namespace TestMath {
class GetClassAndNamespace {
-
String code;
int idx;
int line;
@@ -77,12 +76,9 @@ class GetClassAndNamespace {
};
Token get_token() {
-
while (true) {
switch (code[idx]) {
-
case '\n': {
-
line++;
idx++;
break;
@@ -92,37 +88,30 @@ class GetClassAndNamespace {
} break;
case '{': {
-
idx++;
return TK_CURLY_BRACKET_OPEN;
};
case '}': {
-
idx++;
return TK_CURLY_BRACKET_CLOSE;
};
case '[': {
-
idx++;
return TK_BRACKET_OPEN;
};
case ']': {
-
idx++;
return TK_BRACKET_CLOSE;
};
case ':': {
-
idx++;
return TK_COLON;
};
case ',': {
-
idx++;
return TK_COMMA;
};
case '.': {
-
idx++;
return TK_PERIOD;
};
@@ -134,7 +123,6 @@ class GetClassAndNamespace {
continue;
} break;
case '/': {
-
switch (code[idx + 1]) {
case '*': { // block comment
@@ -145,7 +133,6 @@ class GetClassAndNamespace {
error = true;
return TK_ERROR;
} else if (code[idx] == '*' && code[idx + 1] == '/') {
-
idx += 2;
break;
} else if (code[idx] == '\n') {
@@ -174,7 +161,6 @@ class GetClassAndNamespace {
} break;
case '\'':
case '"': {
-
CharType begin_str = code[idx];
idx++;
String tk_string = String();
@@ -198,15 +184,24 @@ class GetClassAndNamespace {
CharType res = 0;
switch (next) {
-
- case 'b': res = 8; break;
- case 't': res = 9; break;
- case 'n': res = 10; break;
- case 'f': res = 12; break;
+ case 'b':
+ res = 8;
+ break;
+ case 't':
+ res = 9;
+ break;
+ case 'n':
+ res = 10;
+ break;
+ case 'f':
+ res = 12;
+ break;
case 'r':
res = 13;
break;
- case '\"': res = '\"'; break;
+ case '\"':
+ res = '\"';
+ break;
case '\\':
res = '\\';
break;
@@ -218,8 +213,9 @@ class GetClassAndNamespace {
tk_string += res;
} else {
- if (code[idx] == '\n')
+ if (code[idx] == '\n') {
line++;
+ }
tk_string += code[idx];
}
idx++;
@@ -231,7 +227,6 @@ class GetClassAndNamespace {
} break;
default: {
-
if (code[idx] <= 32) {
idx++;
break;
@@ -252,11 +247,9 @@ class GetClassAndNamespace {
return TK_NUMBER;
} else if ((code[idx] >= 'A' && code[idx] <= 'Z') || (code[idx] >= 'a' && code[idx] <= 'z') || code[idx] > 127) {
-
String id;
while ((code[idx] >= 'A' && code[idx] <= 'Z') || (code[idx] >= 'a' && code[idx] <= 'z') || code[idx] > 127) {
-
id += code[idx];
idx++;
}
@@ -275,7 +268,6 @@ class GetClassAndNamespace {
public:
Error parse(const String &p_code, const String &p_known_class_name = String()) {
-
code = p_code;
idx = 0;
line = 0;
@@ -291,7 +283,6 @@ public:
int curly_stack = 0;
while (!error || tk != TK_EOF) {
-
if (tk == TK_BRACKET_OPEN) {
tk = get_token();
if (tk == TK_IDENTIFIER && String(value) == "ScriptClass") {
@@ -348,8 +339,9 @@ public:
tk = get_token();
}
- if (error)
+ if (error) {
return ERR_PARSE_ERROR;
+ }
return OK;
}
@@ -364,7 +356,6 @@ public:
};
void test_vec(Plane p_vec) {
-
CameraMatrix cm;
cm.set_perspective(45, 1, 0, 100);
Plane v0 = cm.xform4(p_vec);
@@ -403,6 +394,54 @@ uint32_t ihash3(uint32_t a) {
}
MainLoop *test() {
+ {
+ Vector<Vector3> points;
+ points.push_back(Vector3(0, 0, 0));
+ points.push_back(Vector3(0, 0, 1));
+ points.push_back(Vector3(0, 1, 0));
+ points.push_back(Vector3(0, 1, 1));
+ points.push_back(Vector3(1, 1, 0));
+ points.push_back(Vector3(1, 0, 0));
+ points.push_back(Vector3(1, 0, 1));
+ points.push_back(Vector3(1, 1, 1));
+
+ for (int i = 0; i < 800; i++) {
+ points.push_back(Vector3(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0) * Vector3(25, 30, 33));
+ }
+
+ Vector<Delaunay3D::OutputSimplex> os = Delaunay3D::tetrahedralize(points);
+ print_line("simplices in the end: " + itos(os.size()));
+ for (int i = 0; i < os.size(); i++) {
+ print_line("Simplex " + itos(i) + ": ");
+ print_line(points[os[i].points[0]]);
+ print_line(points[os[i].points[1]]);
+ print_line(points[os[i].points[2]]);
+ print_line(points[os[i].points[3]]);
+ }
+
+ {
+ FileAccessRef f = FileAccess::open("res://bsp.obj", FileAccess::WRITE);
+ for (int i = 0; i < os.size(); i++) {
+ f->store_line("o Simplex" + itos(i));
+ for (int j = 0; j < 4; j++) {
+ f->store_line(vformat("v %f %f %f", points[os[i].points[j]].x, points[os[i].points[j]].y, points[os[i].points[j]].z));
+ }
+ static const int face_order[4][3] = {
+ { 1, 2, 3 },
+ { 1, 3, 4 },
+ { 1, 2, 4 },
+ { 2, 3, 4 }
+ };
+
+ for (int j = 0; j < 4; j++) {
+ f->store_line(vformat("f %d %d %d", 4 * i + face_order[j][0], 4 * i + face_order[j][1], 4 * i + face_order[j][2]));
+ }
+ }
+ f->close();
+ }
+
+ return nullptr;
+ }
{
float r = 1;
@@ -443,7 +482,7 @@ MainLoop *test() {
float gb = (rgbe >> 9) & 0x1ff;
float bb = (rgbe >> 18) & 0x1ff;
float eb = (rgbe >> 27);
- float mb = Math::pow(2, eb - 15.0 - 9.0);
+ float mb = Math::pow(2.0, eb - 15.0 - 9.0);
float rd = rb * mb;
float gd = gb * mb;
float bd = bb * mb;
@@ -475,18 +514,18 @@ MainLoop *test() {
if (cmdlargs.empty()) {
//try editor!
- return NULL;
+ return nullptr;
}
String test = cmdlargs.back()->get();
if (test == "math") {
// Not a file name but the test name, abort.
// FIXME: This test is ugly as heck, needs fixing :)
- return NULL;
+ return nullptr;
}
FileAccess *fa = FileAccess::open(test, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(!fa, NULL, "Could not open file: " + test);
+ ERR_FAIL_COND_V_MSG(!fa, nullptr, "Could not open file: " + test);
Vector<uint8_t> buf;
int flen = fa->get_len();
@@ -505,26 +544,22 @@ MainLoop *test() {
}
{
-
Vector<int> hashes;
List<StringName> tl;
ClassDB::get_class_list(&tl);
for (List<StringName>::Element *E = tl.front(); E; E = E->next()) {
-
Vector<uint8_t> m5b = E->get().operator String().md5_buffer();
hashes.push_back(hashes.size());
}
for (int i = nearest_shift(hashes.size()); i < 20; i++) {
-
bool success = true;
for (int s = 0; s < 10000; s++) {
Set<uint32_t> existing;
success = true;
for (int j = 0; j < hashes.size(); j++) {
-
uint32_t eh = ihash2(ihash3(hashes[j] + ihash(s) + s)) & ((1 << i) - 1);
if (existing.has(eh)) {
success = false;
@@ -538,8 +573,9 @@ MainLoop *test() {
break;
}
}
- if (success)
+ if (success) {
break;
+ }
}
print_line("DONE");
@@ -580,7 +616,7 @@ MainLoop *test() {
List<String> args;
args.push_back("-l");
- Error err = OS::get_singleton()->execute("/bin/ls", args, true, NULL, &ret);
+ Error err = OS::get_singleton()->execute("/bin/ls", args, true, nullptr, &ret);
print_line("error: " + itos(err));
print_line(ret);
@@ -660,6 +696,7 @@ MainLoop *test() {
print_line("scalar /=: " + v);
}
- return NULL;
+ return nullptr;
}
+
} // namespace TestMath
diff --git a/main/tests/test_oa_hash_map.cpp b/main/tests/test_oa_hash_map.cpp
index ac53f124d2..9182f66b61 100644
--- a/main/tests/test_oa_hash_map.cpp
+++ b/main/tests/test_oa_hash_map.cpp
@@ -35,8 +35,38 @@
namespace TestOAHashMap {
-MainLoop *test() {
+struct CountedItem {
+ static int count;
+
+ int id = -1;
+ bool destroyed = false;
+
+ CountedItem() {
+ count++;
+ }
+
+ CountedItem(int p_id) :
+ id(p_id) {
+ count++;
+ }
+
+ CountedItem(const CountedItem &p_other) :
+ id(p_other.id) {
+ count++;
+ }
+
+ CountedItem &operator=(const CountedItem &p_other) = default;
+
+ ~CountedItem() {
+ CRASH_COND(destroyed);
+ count--;
+ destroyed = true;
+ }
+};
+
+int CountedItem::count;
+MainLoop *test() {
OS::get_singleton()->print("\n\n\nHello from test\n");
// test element tracking.
@@ -71,8 +101,9 @@ MainLoop *test() {
uint32_t num_elems = 0;
for (int i = 0; i < 500; i++) {
int tmp;
- if (map.lookup(i, tmp) && tmp == i * 2)
+ if (map.lookup(i, tmp) && tmp == i * 2) {
num_elems++;
+ }
}
OS::get_singleton()->print("elements %d == %d.\n", map.get_num_elements(), num_elems);
@@ -105,8 +136,9 @@ MainLoop *test() {
keys[i] = Math::rand();
map.set(keys[i], dummy);
- if (!map.lookup(keys[i], dummy))
+ if (!map.lookup(keys[i], dummy)) {
OS::get_singleton()->print("could not find 0x%X despite it was just inserted!\n", unsigned(keys[i]));
+ }
}
// check whether the keys are still present
@@ -122,7 +154,6 @@ MainLoop *test() {
// regression test / test for issue related to #31402
{
-
OS::get_singleton()->print("test for issue #31402 started...\n");
const int num_test_values = 12;
@@ -152,6 +183,117 @@ MainLoop *test() {
map.set(5, 1);
}
- return NULL;
+ // test memory management of items, should not crash or leak items
+ {
+ // Exercise different patterns of removal
+ for (int i = 0; i < 4; ++i) {
+ {
+ OAHashMap<String, CountedItem> map;
+ int id = 0;
+ for (int j = 0; j < 100; ++j) {
+ map.insert(itos(j), CountedItem(id));
+ }
+ if (i <= 1) {
+ for (int j = 0; j < 100; ++j) {
+ map.remove(itos(j));
+ }
+ }
+ if (i % 2 == 0) {
+ map.clear();
+ }
+ }
+
+ if (CountedItem::count != 0) {
+ OS::get_singleton()->print("%d != 0 (not performing the other test sub-cases, breaking...)\n", CountedItem::count);
+ break;
+ }
+ }
+ }
+
+ // Test map with 0 capacity.
+ {
+ OAHashMap<int, String> original_map(0);
+ original_map.set(1, "1");
+ OS::get_singleton()->print("OAHashMap 0 capacity initialization passed.\n");
+ }
+
+ // Test copy constructor.
+ {
+ OAHashMap<int, String> original_map;
+ original_map.set(1, "1");
+ original_map.set(2, "2");
+ original_map.set(3, "3");
+ original_map.set(4, "4");
+ original_map.set(5, "5");
+
+ OAHashMap<int, String> map_copy(original_map);
+
+ bool pass = true;
+ for (
+ OAHashMap<int, String>::Iterator it = original_map.iter();
+ it.valid;
+ it = original_map.next_iter(it)) {
+ if (map_copy.lookup_ptr(*it.key) == nullptr) {
+ pass = false;
+ }
+ if (*it.value != *map_copy.lookup_ptr(*it.key)) {
+ pass = false;
+ }
+ }
+ if (pass) {
+ OS::get_singleton()->print("OAHashMap copy constructor test passed.\n");
+ } else {
+ OS::get_singleton()->print("OAHashMap copy constructor test FAILED.\n");
+ }
+
+ map_copy.set(1, "Random String");
+ if (*map_copy.lookup_ptr(1) == *original_map.lookup_ptr(1)) {
+ OS::get_singleton()->print("OAHashMap copy constructor, atomic copy test FAILED.\n");
+ } else {
+ OS::get_singleton()->print("OAHashMap copy constructor, atomic copy test passed.\n");
+ }
+ }
+
+ // Test assign operator.
+ {
+ OAHashMap<int, String> original_map;
+ original_map.set(1, "1");
+ original_map.set(2, "2");
+ original_map.set(3, "3");
+ original_map.set(4, "4");
+ original_map.set(5, "5");
+
+ OAHashMap<int, String> map_copy(100000);
+ map_copy.set(1, "Just a string.");
+ map_copy = original_map;
+
+ bool pass = true;
+ for (
+ OAHashMap<int, String>::Iterator it = map_copy.iter();
+ it.valid;
+ it = map_copy.next_iter(it)) {
+ if (original_map.lookup_ptr(*it.key) == nullptr) {
+ pass = false;
+ }
+ if (*it.value != *original_map.lookup_ptr(*it.key)) {
+ pass = false;
+ }
+ }
+ if (pass) {
+ OS::get_singleton()->print("OAHashMap assign operation test passed.\n");
+ } else {
+ OS::get_singleton()->print("OAHashMap assign operation test FAILED.\n");
+ }
+
+ map_copy.set(1, "Random String");
+ if (*map_copy.lookup_ptr(1) == *original_map.lookup_ptr(1)) {
+ OS::get_singleton()->print("OAHashMap assign operation atomic copy test FAILED.\n");
+ } else {
+ OS::get_singleton()->print("OAHashMap assign operation atomic copy test passed.\n");
+ }
+ }
+
+ return nullptr;
}
+
} // namespace TestOAHashMap
diff --git a/main/tests/test_ordered_hash_map.cpp b/main/tests/test_ordered_hash_map.cpp
index a5553217e2..d18a3784be 100644
--- a/main/tests/test_ordered_hash_map.cpp
+++ b/main/tests/test_ordered_hash_map.cpp
@@ -130,7 +130,7 @@ bool test_const_iteration() {
return test_const_iteration(map);
}
-typedef bool (*TestFunc)(void);
+typedef bool (*TestFunc)();
TestFunc test_funcs[] = {
@@ -141,21 +141,22 @@ TestFunc test_funcs[] = {
test_size,
test_iteration,
test_const_iteration,
- 0
+ nullptr
};
MainLoop *test() {
-
int count = 0;
int passed = 0;
while (true) {
- if (!test_funcs[count])
+ if (!test_funcs[count]) {
break;
+ }
bool pass = test_funcs[count]();
- if (pass)
+ if (pass) {
passed++;
+ }
OS::get_singleton()->print("\t%s\n", pass ? "PASS" : "FAILED");
count++;
@@ -168,6 +169,7 @@ MainLoop *test() {
OS::get_singleton()->print("Passed %i of %i tests\n", passed, count);
- return NULL;
+ return nullptr;
}
+
} // namespace TestOrderedHashMap
diff --git a/main/tests/test_physics_2d.cpp b/main/tests/test_physics_2d.cpp
index 6feff3b0a9..6cb9bf7b60 100644
--- a/main/tests/test_physics_2d.cpp
+++ b/main/tests/test_physics_2d.cpp
@@ -44,7 +44,6 @@ static const unsigned char convex_png[] = {
};
class TestPhysics2DMainLoop : public MainLoop {
-
GDCLASS(TestPhysics2DMainLoop, MainLoop);
RID circle_img;
@@ -58,7 +57,6 @@ class TestPhysics2DMainLoop : public MainLoop {
Vector2 ray_from, ray_to;
struct BodyShapeData {
-
RID image;
RID shape;
};
@@ -72,13 +70,10 @@ class TestPhysics2DMainLoop : public MainLoop {
// SEGMENT
{
-
Vector<uint8_t> pixels;
pixels.resize(32 * 2 * 2);
for (int i = 0; i < 2; i++) {
-
for (int j = 0; j < 32; j++) {
-
pixels.set(i * 32 * 2 + j * 2 + 0, (j == 0) ? 255 : 0);
pixels.set(i * 32 * 2 + j * 2 + 1, 255);
}
@@ -97,13 +92,10 @@ class TestPhysics2DMainLoop : public MainLoop {
// CIRCLE
{
-
Vector<uint8_t> pixels;
pixels.resize(32 * 32 * 2);
for (int i = 0; i < 32; i++) {
-
for (int j = 0; j < 32; j++) {
-
bool black = Vector2(i - 16, j - 16).length_squared() < 16 * 16;
pixels.set(i * 32 * 2 + j * 2 + 0, (i == 16 || j == 16) ? 255 : 0);
@@ -124,13 +116,10 @@ class TestPhysics2DMainLoop : public MainLoop {
// BOX
{
-
Vector<uint8_t> pixels;
pixels.resize(32 * 32 * 2);
for (int i = 0; i < 32; i++) {
-
for (int j = 0; j < 32; j++) {
-
bool black = i > 0 && i < 31 && j > 0 && j < 31;
pixels.set(i * 32 * 2 + j * 2 + 0, black ? 0 : 255);
@@ -151,13 +140,10 @@ class TestPhysics2DMainLoop : public MainLoop {
// CAPSULE
{
-
Vector<uint8_t> pixels;
pixels.resize(32 * 64 * 2);
for (int i = 0; i < 64; i++) {
-
for (int j = 0; j < 32; j++) {
-
int si = i > 48 ? i - 32 : (i < 16 ? i : 16);
bool black = Vector2(si - 16, j - 16).length_squared() < 16 * 16;
@@ -179,7 +165,6 @@ class TestPhysics2DMainLoop : public MainLoop {
// CONVEX
{
-
Ref<Image> image = memnew(Image(convex_png));
body_shape_data[PhysicsServer2D::SHAPE_CONVEX_POLYGON].image = vs->texture_2d_create(image);
@@ -202,7 +187,6 @@ class TestPhysics2DMainLoop : public MainLoop {
}
void _do_ray_query() {
-
/*
PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
ps->query_intersection_segment(ray_query,ray_from,ray_to);
@@ -211,13 +195,10 @@ class TestPhysics2DMainLoop : public MainLoop {
protected:
void input_event(const Ref<InputEvent> &p_event) {
-
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
-
if (mb->is_pressed()) {
-
Point2 p(mb->get_position().x, mb->get_position().y);
if (mb->get_button_index() == 1) {
@@ -233,7 +214,6 @@ protected:
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
-
Point2 p = mm->get_position();
if (mm->get_button_mask() & BUTTON_MASK_LEFT) {
@@ -247,7 +227,6 @@ protected:
}
RID _add_body(PhysicsServer2D::ShapeType p_shape, const Transform2D &p_xform) {
-
RenderingServer *vs = RenderingServer::get_singleton();
PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
@@ -272,7 +251,6 @@ protected:
}
void _add_plane(const Vector2 &p_normal, real_t p_d) {
-
PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
Array arr;
@@ -289,7 +267,6 @@ protected:
}
void _add_concave(const Vector<Vector2> &p_points, const Transform2D &p_xform = Transform2D()) {
-
PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
RenderingServer *vs = RenderingServer::get_singleton();
@@ -315,7 +292,6 @@ protected:
}
void _ray_query_callback(const RID &p_rid, ObjectID p_id, int p_shape, const Vector2 &p_point, const Vector2 &p_normal) {
-
Vector2 ray_end;
if (p_rid.is_valid()) {
@@ -328,19 +304,18 @@ protected:
vs->canvas_item_clear(ray);
vs->canvas_item_add_line(ray, ray_from, ray_end, p_rid.is_valid() ? Color(0, 1, 0.4) : Color(1, 0.4, 0), 2);
- if (p_rid.is_valid())
+ if (p_rid.is_valid()) {
vs->canvas_item_add_line(ray, ray_end, ray_end + p_normal * 20, p_rid.is_valid() ? Color(0, 1, 0.4) : Color(1, 0.4, 0), 2);
+ }
}
static void _bind_methods() {
-
ClassDB::bind_method(D_METHOD("_body_moved"), &TestPhysics2DMainLoop::_body_moved);
ClassDB::bind_method(D_METHOD("_ray_query_callback"), &TestPhysics2DMainLoop::_ray_query_callback);
}
public:
virtual void init() {
-
RenderingServer *vs = RenderingServer::get_singleton();
PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
@@ -351,7 +326,6 @@ public:
ps->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, 98);
{
-
RID vp = vs->viewport_create();
canvas = vs->canvas_create();
@@ -377,7 +351,6 @@ public:
_create_body_shape_data();
for (int i = 0; i < 32; i++) {
-
PhysicsServer2D::ShapeType types[4] = {
PhysicsServer2D::SHAPE_CIRCLE,
PhysicsServer2D::SHAPE_CAPSULE,
@@ -402,7 +375,6 @@ public:
Vector<Point2> parr;
for (int i = 0; i < 30; i++) {
-
Point2 p(i * 60, Math::randf() * 70 + 340);
if (i > 0) {
parr.push_back(prev);
@@ -418,7 +390,6 @@ public:
}
virtual bool idle(float p_time) {
-
return false;
}
virtual void finish() {
@@ -430,7 +401,7 @@ public:
namespace TestPhysics2D {
MainLoop *test() {
-
return memnew(TestPhysics2DMainLoop);
}
+
} // namespace TestPhysics2D
diff --git a/main/tests/test_physics_3d.cpp b/main/tests/test_physics_3d.cpp
index 2d208ee317..fe54ece98e 100644
--- a/main/tests/test_physics_3d.cpp
+++ b/main/tests/test_physics_3d.cpp
@@ -41,7 +41,6 @@
#include "servers/rendering_server.h"
class TestPhysics3DMainLoop : public MainLoop {
-
GDCLASS(TestPhysics3DMainLoop, MainLoop);
enum {
@@ -69,7 +68,6 @@ class TestPhysics3DMainLoop : public MainLoop {
Map<PhysicsServer3D::ShapeType, RID> type_mesh_map;
void body_changed_transform(Object *p_state, RID p_visual_instance) {
-
PhysicsDirectBodyState3D *state = (PhysicsDirectBodyState3D *)p_state;
RenderingServer *vs = RenderingServer::get_singleton();
Transform t = state->get_transform();
@@ -80,12 +78,10 @@ class TestPhysics3DMainLoop : public MainLoop {
protected:
static void _bind_methods() {
-
ClassDB::bind_method("body_changed_transform", &TestPhysics3DMainLoop::body_changed_transform);
}
RID create_body(PhysicsServer3D::ShapeType p_shape, PhysicsServer3D::BodyMode p_body, const Transform p_location, bool p_active_default = true, const Transform &p_shape_xform = Transform()) {
-
RenderingServer *vs = RenderingServer::get_singleton();
PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
@@ -101,14 +97,12 @@ protected:
bodies.push_back(body);
if (p_body == PhysicsServer3D::BODY_MODE_STATIC) {
-
vs->instance_set_transform(mesh_instance, p_location);
}
return body;
}
RID create_static_plane(const Plane &p_plane) {
-
PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
RID world_margin_shape = ps->shape_create(PhysicsServer3D::SHAPE_PLANE);
@@ -122,7 +116,6 @@ protected:
}
void configure_body(RID p_body, float p_mass, float p_friction, float p_bounce) {
-
PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
ps->body_set_param(p_body, PhysicsServer3D::BODY_PARAM_MASS, p_mass);
ps->body_set_param(p_body, PhysicsServer3D::BODY_PARAM_FRICTION, p_friction);
@@ -130,7 +123,6 @@ protected:
}
void init_shapes() {
-
RenderingServer *vs = RenderingServer::get_singleton();
PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
@@ -188,7 +180,6 @@ protected:
}
void make_trimesh(Vector<Vector3> p_faces, const Transform &p_xform = Transform()) {
-
RenderingServer *vs = RenderingServer::get_singleton();
PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
RID trimesh_shape = ps->shape_create(PhysicsServer3D::SHAPE_CONCAVE_POLYGON);
@@ -196,7 +187,6 @@ protected:
p_faces = ps->shape_get_data(trimesh_shape); // optimized one
Vector<Vector3> normals; // for drawing
for (int i = 0; i < p_faces.size() / 3; i++) {
-
Plane p(p_faces[i * 3 + 0], p_faces[i * 3 + 1], p_faces[i * 3 + 2]);
normals.push_back(p.normal);
normals.push_back(p.normal);
@@ -222,17 +212,14 @@ protected:
}
void make_grid(int p_width, int p_height, float p_cellsize, float p_cellheight, const Transform &p_xform = Transform()) {
-
Vector<Vector<float>> grid;
grid.resize(p_width);
for (int i = 0; i < p_width; i++) {
-
grid.write[i].resize(p_height);
for (int j = 0; j < p_height; j++) {
-
grid.write[i].write[j] = 1.0 + Math::random(-p_cellheight, p_cellheight);
}
}
@@ -240,9 +227,7 @@ protected:
Vector<Vector3> faces;
for (int i = 1; i < p_width; i++) {
-
for (int j = 1; j < p_height; j++) {
-
#define MAKE_VERTEX(m_x, m_z) \
faces.push_back(Vector3((m_x - p_width / 2) * p_cellsize, grid[m_x][m_z], (m_z - p_height / 2) * p_cellsize))
@@ -261,21 +246,17 @@ protected:
public:
virtual void input_event(const Ref<InputEvent> &p_event) {
-
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid() && mm->get_button_mask() & 4) {
-
ofs_y -= mm->get_relative().y / 200.0;
ofs_x += mm->get_relative().x / 200.0;
}
if (mm.is_valid() && mm->get_button_mask() & 1) {
-
float y = -mm->get_relative().y / 20.0;
float x = mm->get_relative().x / 20.0;
if (mover.is_valid()) {
-
PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
Transform t = ps->body_get_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM);
t.origin += Vector3(x, y, 0);
@@ -286,11 +267,9 @@ public:
}
virtual void request_quit() {
-
quit = true;
}
virtual void init() {
-
ofs_x = ofs_y = 0;
init_shapes();
@@ -332,7 +311,6 @@ public:
quit = false;
}
virtual bool iteration(float p_time) {
-
if (mover.is_valid()) {
static float joy_speed = 10;
PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
@@ -360,7 +338,6 @@ public:
}
void test_character() {
-
RenderingServer *vs = RenderingServer::get_singleton();
PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
@@ -393,9 +370,7 @@ public:
}
void test_fall() {
-
for (int i = 0; i < 35; i++) {
-
static const PhysicsServer3D::ShapeType shape_idx[] = {
PhysicsServer3D::SHAPE_CAPSULE,
PhysicsServer3D::SHAPE_BOX,
@@ -417,7 +392,6 @@ public:
}
void test_activate() {
-
create_body(PhysicsServer3D::SHAPE_BOX, PhysicsServer3D::BODY_MODE_RIGID, Transform(Basis(), Vector3(0, 2, 0)), true);
create_static_plane(Plane(Vector3(0, 1, 0), -1));
}
@@ -433,7 +407,7 @@ public:
namespace TestPhysics3D {
MainLoop *test() {
-
return memnew(TestPhysics3DMainLoop);
}
+
} // namespace TestPhysics3D
diff --git a/main/tests/test_render.cpp b/main/tests/test_render.cpp
index bcfcf61e25..afc09374b9 100644
--- a/main/tests/test_render.cpp
+++ b/main/tests/test_render.cpp
@@ -44,7 +44,6 @@
namespace TestRender {
class TestMainLoop : public MainLoop {
-
RID test_cube;
RID instance;
RID camera;
@@ -53,7 +52,6 @@ class TestMainLoop : public MainLoop {
RID scenario;
struct InstanceInfo {
-
RID instance;
Transform base;
Vector3 rot_axis;
@@ -67,13 +65,12 @@ class TestMainLoop : public MainLoop {
protected:
public:
virtual void input_event(const Ref<InputEvent> &p_event) {
-
- if (p_event->is_pressed())
+ if (p_event->is_pressed()) {
quit = true;
+ }
}
virtual void init() {
-
print_line("INITIALIZING TEST RENDER");
RenderingServer *vs = RenderingServer::get_singleton();
test_cube = vs->get_test_cube();
@@ -144,7 +141,6 @@ public:
};
for (int i = 0; i < object_count; i++) {
-
InstanceInfo ii;
ii.instance = vs->instance_create2(test_cube, scenario);
@@ -205,7 +201,6 @@ public:
quit = false;
}
virtual bool iteration(float p_time) {
-
RenderingServer *vs = RenderingServer::get_singleton();
//Transform t;
//t.rotate(Vector3(0, 1, 0), ofs);
@@ -217,7 +212,6 @@ public:
//return quit;
for (List<InstanceInfo>::Element *E = instances.front(); E; E = E->next()) {
-
Transform pre(Basis(E->get().rot_axis, ofs), Vector3());
vs->instance_set_transform(E->get().instance, pre * E->get().base);
/*
@@ -240,7 +234,7 @@ public:
};
MainLoop *test() {
-
return memnew(TestMainLoop);
}
+
} // namespace TestRender
diff --git a/main/tests/test_shader_lang.cpp b/main/tests/test_shader_lang.cpp
index dd525d7653..34ee3e3210 100644
--- a/main/tests/test_shader_lang.cpp
+++ b/main/tests/test_shader_lang.cpp
@@ -44,7 +44,6 @@ typedef ShaderLanguage SL;
namespace TestShaderLang {
static String _mktab(int p_level) {
-
String tb;
for (int i = 0; i < p_level; i++) {
tb += "\t";
@@ -54,61 +53,74 @@ static String _mktab(int p_level) {
}
static String _typestr(SL::DataType p_type) {
-
return ShaderLanguage::get_datatype_name(p_type);
}
static String _prestr(SL::DataPrecision p_pres) {
-
switch (p_pres) {
- case SL::PRECISION_LOWP: return "lowp ";
- case SL::PRECISION_MEDIUMP: return "mediump ";
- case SL::PRECISION_HIGHP: return "highp ";
- case SL::PRECISION_DEFAULT: return "";
+ case SL::PRECISION_LOWP:
+ return "lowp ";
+ case SL::PRECISION_MEDIUMP:
+ return "mediump ";
+ case SL::PRECISION_HIGHP:
+ return "highp ";
+ case SL::PRECISION_DEFAULT:
+ return "";
}
return "";
}
static String _opstr(SL::Operator p_op) {
-
return ShaderLanguage::get_operator_text(p_op);
}
static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value> &p_values) {
-
switch (p_type) {
- case SL::TYPE_BOOL: return p_values[0].boolean ? "true" : "false";
- case SL::TYPE_BVEC2: return String() + "bvec2(" + (p_values[0].boolean ? "true" : "false") + (p_values[1].boolean ? "true" : "false") + ")";
- case SL::TYPE_BVEC3: return String() + "bvec3(" + (p_values[0].boolean ? "true" : "false") + "," + (p_values[1].boolean ? "true" : "false") + "," + (p_values[2].boolean ? "true" : "false") + ")";
- case SL::TYPE_BVEC4: return String() + "bvec4(" + (p_values[0].boolean ? "true" : "false") + "," + (p_values[1].boolean ? "true" : "false") + "," + (p_values[2].boolean ? "true" : "false") + "," + (p_values[3].boolean ? "true" : "false") + ")";
- case SL::TYPE_INT: return rtos(p_values[0].sint);
- case SL::TYPE_IVEC2: return String() + "ivec2(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + ")";
- case SL::TYPE_IVEC3: return String() + "ivec3(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + "," + rtos(p_values[2].sint) + ")";
- case SL::TYPE_IVEC4: return String() + "ivec4(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + "," + rtos(p_values[2].sint) + "," + rtos(p_values[3].sint) + ")";
- case SL::TYPE_UINT: return rtos(p_values[0].real);
- case SL::TYPE_UVEC2: return String() + "uvec2(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + ")";
- case SL::TYPE_UVEC3: return String() + "uvec3(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + ")";
- case SL::TYPE_UVEC4: return String() + "uvec4(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + "," + rtos(p_values[3].real) + ")";
- case SL::TYPE_FLOAT: return rtos(p_values[0].real);
- case SL::TYPE_VEC2: return String() + "vec2(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + ")";
- case SL::TYPE_VEC3: return String() + "vec3(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + ")";
- case SL::TYPE_VEC4: return String() + "vec4(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + "," + rtos(p_values[3].real) + ")";
- default: ERR_FAIL_V(String());
+ case SL::TYPE_BOOL:
+ return p_values[0].boolean ? "true" : "false";
+ case SL::TYPE_BVEC2:
+ return String() + "bvec2(" + (p_values[0].boolean ? "true" : "false") + (p_values[1].boolean ? "true" : "false") + ")";
+ case SL::TYPE_BVEC3:
+ return String() + "bvec3(" + (p_values[0].boolean ? "true" : "false") + "," + (p_values[1].boolean ? "true" : "false") + "," + (p_values[2].boolean ? "true" : "false") + ")";
+ case SL::TYPE_BVEC4:
+ return String() + "bvec4(" + (p_values[0].boolean ? "true" : "false") + "," + (p_values[1].boolean ? "true" : "false") + "," + (p_values[2].boolean ? "true" : "false") + "," + (p_values[3].boolean ? "true" : "false") + ")";
+ case SL::TYPE_INT:
+ return rtos(p_values[0].sint);
+ case SL::TYPE_IVEC2:
+ return String() + "ivec2(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + ")";
+ case SL::TYPE_IVEC3:
+ return String() + "ivec3(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + "," + rtos(p_values[2].sint) + ")";
+ case SL::TYPE_IVEC4:
+ return String() + "ivec4(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + "," + rtos(p_values[2].sint) + "," + rtos(p_values[3].sint) + ")";
+ case SL::TYPE_UINT:
+ return rtos(p_values[0].real);
+ case SL::TYPE_UVEC2:
+ return String() + "uvec2(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + ")";
+ case SL::TYPE_UVEC3:
+ return String() + "uvec3(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + ")";
+ case SL::TYPE_UVEC4:
+ return String() + "uvec4(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + "," + rtos(p_values[3].real) + ")";
+ case SL::TYPE_FLOAT:
+ return rtos(p_values[0].real);
+ case SL::TYPE_VEC2:
+ return String() + "vec2(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + ")";
+ case SL::TYPE_VEC3:
+ return String() + "vec3(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + ")";
+ case SL::TYPE_VEC4:
+ return String() + "vec4(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + "," + rtos(p_values[3].real) + ")";
+ default:
+ ERR_FAIL_V(String());
}
}
static String dump_node_code(SL::Node *p_node, int p_level) {
-
String code;
switch (p_node->type) {
-
case SL::Node::TYPE_SHADER: {
-
SL::ShaderNode *pnode = (SL::ShaderNode *)p_node;
for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) {
-
String ucode = "uniform ";
ucode += _prestr(E->get().precision);
ucode += _typestr(E->get().type);
@@ -128,14 +140,14 @@ static String dump_node_code(SL::Node *p_node, int p_level) {
"white"
};
- if (E->get().hint)
+ if (E->get().hint) {
ucode += " : " + String(hint_name[E->get().hint]);
+ }
code += ucode + "\n";
}
for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) {
-
String vcode = "varying ";
vcode += _prestr(E->get().precision);
vcode += _typestr(E->get().type);
@@ -144,15 +156,14 @@ static String dump_node_code(SL::Node *p_node, int p_level) {
code += vcode + "\n";
}
for (int i = 0; i < pnode->functions.size(); i++) {
-
SL::FunctionNode *fnode = pnode->functions[i].function;
String header;
header = _typestr(fnode->return_type) + " " + fnode->name + "(";
for (int j = 0; j < fnode->arguments.size(); j++) {
-
- if (j > 0)
+ if (j > 0) {
header += ", ";
+ }
header += _prestr(fnode->arguments[j].precision) + _typestr(fnode->arguments[j].type) + " " + fnode->arguments[j].name;
}
@@ -164,10 +175,8 @@ static String dump_node_code(SL::Node *p_node, int p_level) {
//code+=dump_node_code(pnode->body,p_level);
} break;
case SL::Node::TYPE_STRUCT: {
-
} break;
case SL::Node::TYPE_FUNCTION: {
-
} break;
case SL::Node::TYPE_BLOCK: {
SL::BlockNode *bnode = (SL::BlockNode *)p_node;
@@ -175,12 +184,10 @@ static String dump_node_code(SL::Node *p_node, int p_level) {
//variables
code += _mktab(p_level - 1) + "{\n";
for (Map<StringName, SL::BlockNode::Variable>::Element *E = bnode->variables.front(); E; E = E->next()) {
-
code += _mktab(p_level) + _prestr(E->get().precision) + _typestr(E->get().type) + " " + E->key() + ";\n";
}
for (int i = 0; i < bnode->statements.size(); i++) {
-
String scode = dump_node_code(bnode->statements[i], p_level);
if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW) {
@@ -219,7 +226,6 @@ static String dump_node_code(SL::Node *p_node, int p_level) {
SL::OperatorNode *onode = (SL::OperatorNode *)p_node;
switch (onode->op) {
-
case SL::OP_ASSIGN:
case SL::OP_ASSIGN_ADD:
case SL::OP_ASSIGN_SUB:
@@ -248,14 +254,14 @@ static String dump_node_code(SL::Node *p_node, int p_level) {
case SL::OP_CONSTRUCT:
code = dump_node_code(onode->arguments[0], p_level) + "(";
for (int i = 1; i < onode->arguments.size(); i++) {
- if (i > 1)
+ if (i > 1) {
code += ", ";
+ }
code += dump_node_code(onode->arguments[i], p_level);
}
code += ")";
break;
default: {
-
code = "(" + dump_node_code(onode->arguments[0], p_level) + _opstr(onode->op) + dump_node_code(onode->arguments[1], p_level) + ")";
break;
}
@@ -265,17 +271,14 @@ static String dump_node_code(SL::Node *p_node, int p_level) {
case SL::Node::TYPE_CONTROL_FLOW: {
SL::ControlFlowNode *cfnode = (SL::ControlFlowNode *)p_node;
if (cfnode->flow_op == SL::FLOW_OP_IF) {
-
code += _mktab(p_level) + "if (" + dump_node_code(cfnode->expressions[0], p_level) + ")\n";
code += dump_node_code(cfnode->blocks[0], p_level + 1);
if (cfnode->blocks.size() == 2) {
-
code += _mktab(p_level) + "else\n";
code += dump_node_code(cfnode->blocks[1], p_level + 1);
}
} else if (cfnode->flow_op == SL::FLOW_OP_RETURN) {
-
if (cfnode->blocks.size()) {
code = "return " + dump_node_code(cfnode->blocks[0], p_level);
} else {
@@ -295,7 +298,6 @@ static String dump_node_code(SL::Node *p_node, int p_level) {
}
static Error recreate_code(void *p_str, SL::ShaderNode *p_program) {
-
String *str = (String *)p_str;
*str = dump_node_code(p_program, 0);
@@ -304,13 +306,12 @@ static Error recreate_code(void *p_str, SL::ShaderNode *p_program) {
}
MainLoop *test() {
-
List<String> cmdlargs = OS::get_singleton()->get_cmdline_args();
if (cmdlargs.empty()) {
//try editor!
print_line("usage: godot -test shader_lang <shader>");
- return NULL;
+ return nullptr;
}
String test = cmdlargs.back()->get();
@@ -318,15 +319,16 @@ MainLoop *test() {
FileAccess *fa = FileAccess::open(test, FileAccess::READ);
if (!fa) {
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
String code;
while (true) {
CharType c = fa->get_8();
- if (fa->eof_reached())
+ if (fa->eof_reached()) {
break;
+ }
code += c;
}
@@ -342,18 +344,18 @@ MainLoop *test() {
Set<String> types;
types.insert("spatial");
- Error err = sl.compile(code, dt, rm, types);
+ Error err = sl.compile(code, dt, rm, types, nullptr);
if (err) {
-
print_line("Error at line: " + rtos(sl.get_error_line()) + ": " + sl.get_error_text());
- return NULL;
+ return nullptr;
} else {
String code2;
recreate_code(&code2, sl.get_shader());
print_line("code:\n\n" + code2);
}
- return NULL;
+ return nullptr;
}
+
} // namespace TestShaderLang
diff --git a/main/tests/test_string.cpp b/main/tests/test_string.cpp
index 84731746fa..775c039282 100644
--- a/main/tests/test_string.cpp
+++ b/main/tests/test_string.cpp
@@ -45,7 +45,6 @@
namespace TestString {
bool test_1() {
-
OS::get_singleton()->print("\n\nTest 1: Assign from cstr\n");
String s = "Hello";
@@ -57,7 +56,6 @@ bool test_1() {
}
bool test_2() {
-
OS::get_singleton()->print("\n\nTest 2: Assign from string (operator=)\n");
String s = "Dolly";
@@ -70,7 +68,6 @@ bool test_2() {
}
bool test_3() {
-
OS::get_singleton()->print("\n\nTest 3: Assign from c-string (copycon)\n");
String s("Sheep");
@@ -83,7 +80,6 @@ bool test_3() {
}
bool test_4() {
-
OS::get_singleton()->print("\n\nTest 4: Assign from c-widechar (operator=)\n");
String s(L"Give me");
@@ -95,7 +91,6 @@ bool test_4() {
}
bool test_5() {
-
OS::get_singleton()->print("\n\nTest 5: Assign from c-widechar (copycon)\n");
String s(L"Wool");
@@ -107,67 +102,72 @@ bool test_5() {
}
bool test_6() {
-
OS::get_singleton()->print("\n\nTest 6: comparisons (equal)\n");
String s = "Test Compare";
OS::get_singleton()->print("\tComparing to \"Test Compare\"\n");
- if (!(s == "Test Compare"))
+ if (!(s == "Test Compare")) {
return false;
+ }
- if (!(s == L"Test Compare"))
+ if (!(s == L"Test Compare")) {
return false;
+ }
- if (!(s == String("Test Compare")))
+ if (!(s == String("Test Compare"))) {
return false;
+ }
return true;
}
bool test_7() {
-
OS::get_singleton()->print("\n\nTest 7: comparisons (unequal)\n");
String s = "Test Compare";
OS::get_singleton()->print("\tComparing to \"Test Compare\"\n");
- if (!(s != "Peanut"))
+ if (!(s != "Peanut")) {
return false;
+ }
- if (!(s != L"Coconut"))
+ if (!(s != L"Coconut")) {
return false;
+ }
- if (!(s != String("Butter")))
+ if (!(s != String("Butter"))) {
return false;
+ }
return true;
}
bool test_8() {
-
OS::get_singleton()->print("\n\nTest 8: comparisons (operator<)\n");
String s = "Bees";
OS::get_singleton()->print("\tComparing to \"Bees\"\n");
- if (!(s < "Elephant"))
+ if (!(s < "Elephant")) {
return false;
+ }
- if (s < L"Amber")
+ if (s < L"Amber") {
return false;
+ }
- if (s < String("Beatrix"))
+ if (s < String("Beatrix")) {
return false;
+ }
return true;
}
bool test_9() {
-
OS::get_singleton()->print("\n\nTest 9: Concatenation\n");
String s;
@@ -186,23 +186,24 @@ bool test_9() {
}
bool test_10() {
-
OS::get_singleton()->print("\n\nTest 10: Misc funcs (size/length/empty/etc)\n");
- if (!String("").empty())
+ if (!String("").empty()) {
return false;
+ }
- if (String("Mellon").size() != 7)
+ if (String("Mellon").size() != 7) {
return false;
+ }
- if (String("Oranges").length() != 7)
+ if (String("Oranges").length() != 7) {
return false;
+ }
return true;
}
bool test_11() {
-
OS::get_singleton()->print("\n\nTest 11: Operator[]\n");
String a = "Kugar Sane";
@@ -210,32 +211,34 @@ bool test_11() {
a[0] = 'S';
a[6] = 'C';
- if (a != "Sugar Cane")
+ if (a != "Sugar Cane") {
return false;
+ }
- if (a[1] != 'u')
+ if (a[1] != 'u') {
return false;
+ }
return true;
}
bool test_12() {
-
OS::get_singleton()->print("\n\nTest 12: case functions\n");
String a = "MoMoNgA";
- if (a.to_upper() != "MOMONGA")
+ if (a.to_upper() != "MOMONGA") {
return false;
+ }
- if (a.nocasecmp_to("momonga") != 0)
+ if (a.nocasecmp_to("momonga") != 0) {
return false;
+ }
return true;
}
bool test_13() {
-
OS::get_singleton()->print("\n\nTest 13: UTF8\n");
/* how can i embed UTF in here? */
@@ -252,7 +255,6 @@ bool test_13() {
}
bool test_14() {
-
OS::get_singleton()->print("\n\nTest 14: ASCII\n");
String s = L"Primero Leche";
@@ -263,7 +265,6 @@ bool test_14() {
}
bool test_15() {
-
OS::get_singleton()->print("\n\nTest 15: substr\n");
String s = "Killer Baby";
@@ -273,7 +274,6 @@ bool test_15() {
}
bool test_16() {
-
OS::get_singleton()->print("\n\nTest 16: find\n");
String s = "Pretty Woman";
@@ -281,17 +281,18 @@ bool test_16() {
OS::get_singleton()->print("\t\"tty\" is at %i pos.\n", s.find("tty"));
OS::get_singleton()->print("\t\"Revenge of the Monster Truck\" is at %i pos.\n", s.find("Revenge of the Monster Truck"));
- if (s.find("tty") != 3)
+ if (s.find("tty") != 3) {
return false;
+ }
- if (s.find("Revenge of the Monster Truck") != -1)
+ if (s.find("Revenge of the Monster Truck") != -1) {
return false;
+ }
return true;
}
bool test_17() {
-
OS::get_singleton()->print("\n\nTest 17: find no case\n");
String s = "Pretty Whale";
@@ -299,17 +300,18 @@ bool test_17() {
OS::get_singleton()->print("\t\"WHA\" is at %i pos.\n", s.findn("WHA"));
OS::get_singleton()->print("\t\"Revenge of the Monster SawFish\" is at %i pos.\n", s.findn("Revenge of the Monster Truck"));
- if (s.findn("WHA") != 7)
+ if (s.findn("WHA") != 7) {
return false;
+ }
- if (s.findn("Revenge of the Monster SawFish") != -1)
+ if (s.findn("Revenge of the Monster SawFish") != -1) {
return false;
+ }
return true;
}
bool test_18() {
-
OS::get_singleton()->print("\n\nTest 18: find no case\n");
String s = "Pretty Whale";
@@ -317,17 +319,18 @@ bool test_18() {
OS::get_singleton()->print("\t\"WHA\" is at %i pos.\n", s.findn("WHA"));
OS::get_singleton()->print("\t\"Revenge of the Monster SawFish\" is at %i pos.\n", s.findn("Revenge of the Monster Truck"));
- if (s.findn("WHA") != 7)
+ if (s.findn("WHA") != 7) {
return false;
+ }
- if (s.findn("Revenge of the Monster SawFish") != -1)
+ if (s.findn("Revenge of the Monster SawFish") != -1) {
return false;
+ }
return true;
}
bool test_19() {
-
OS::get_singleton()->print("\n\nTest 19: Search & replace\n");
String s = "Happy Birthday, Anna!";
@@ -340,7 +343,6 @@ bool test_19() {
}
bool test_20() {
-
OS::get_singleton()->print("\n\nTest 20: Insertion\n");
String s = "Who is Frederic?";
@@ -353,7 +355,6 @@ bool test_20() {
}
bool test_21() {
-
OS::get_singleton()->print("\n\nTest 21: Number -> String\n");
OS::get_singleton()->print("\tPi is %f\n", 33.141593);
@@ -363,7 +364,6 @@ bool test_21() {
}
bool test_22() {
-
OS::get_singleton()->print("\n\nTest 22: String -> Int\n");
static const char *nums[4] = { "1237461283", "- 22", "0", " - 1123412" };
@@ -372,15 +372,15 @@ bool test_22() {
for (int i = 0; i < 4; i++) {
OS::get_singleton()->print("\tString: \"%s\" as Int is %i\n", nums[i], String(nums[i]).to_int());
- if (String(nums[i]).to_int() != num[i])
+ if (String(nums[i]).to_int() != num[i]) {
return false;
+ }
}
return true;
}
bool test_23() {
-
OS::get_singleton()->print("\n\nTest 23: String -> Float\n");
static const char *nums[4] = { "-12348298412.2", "0.05", "2.0002", " -0.0001" };
@@ -389,15 +389,15 @@ bool test_23() {
for (int i = 0; i < 4; i++) {
OS::get_singleton()->print("\tString: \"%s\" as Float is %f\n", nums[i], String(nums[i]).to_double());
- if (ABS(String(nums[i]).to_double() - num[i]) > 0.00001)
+ if (ABS(String(nums[i]).to_double() - num[i]) > 0.00001) {
return false;
+ }
}
return true;
}
bool test_24() {
-
OS::get_singleton()->print("\n\nTest 24: Slicing\n");
String s = "Mars,Jupiter,Saturn,Uranus";
@@ -407,18 +407,17 @@ bool test_24() {
OS::get_singleton()->print("\tSlicing \"%ls\" by \"%s\"..\n", s.c_str(), ",");
for (int i = 0; i < s.get_slice_count(","); i++) {
-
OS::get_singleton()->print("\t\t%i- %ls\n", i + 1, s.get_slice(",", i).c_str());
- if (s.get_slice(",", i) != slices[i])
+ if (s.get_slice(",", i) != slices[i]) {
return false;
+ }
}
return true;
}
bool test_25() {
-
OS::get_singleton()->print("\n\nTest 25: Erasing\n");
String s = "Josephine is such a cute girl!";
@@ -433,7 +432,6 @@ bool test_25() {
}
bool test_26() {
-
OS::get_singleton()->print("\n\nTest 26: RegEx substitution\n");
#ifndef MODULE_REGEX_ENABLED
@@ -461,7 +459,6 @@ struct test_27_data {
};
bool test_27() {
-
OS::get_singleton()->print("\n\nTest 27: begins_with\n");
test_27_data tc[] = {
{ "res://foobar", "res://", true },
@@ -486,7 +483,6 @@ bool test_27() {
};
bool test_28() {
-
OS::get_singleton()->print("\n\nTest 28: sprintf\n");
bool success, state = true;
@@ -822,7 +818,6 @@ bool test_28() {
}
bool test_29() {
-
bool state = true;
IP_Address ip0("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
@@ -972,28 +967,35 @@ bool test_31() {
String a = "";
success = a[0] == 0;
OS::get_singleton()->print("Is 0 String[0]:, %s\n", success ? "OK" : "FAIL");
- if (!success) state = false;
+ if (!success) {
+ state = false;
+ }
String b = "Godot";
success = b[b.size()] == 0;
OS::get_singleton()->print("Is 0 String[size()]:, %s\n", success ? "OK" : "FAIL");
- if (!success) state = false;
+ if (!success) {
+ state = false;
+ }
const String c = "";
success = c[0] == 0;
OS::get_singleton()->print("Is 0 const String[0]:, %s\n", success ? "OK" : "FAIL");
- if (!success) state = false;
+ if (!success) {
+ state = false;
+ }
const String d = "Godot";
success = d[d.size()] == 0;
OS::get_singleton()->print("Is 0 const String[size()]:, %s\n", success ? "OK" : "FAIL");
- if (!success) state = false;
+ if (!success) {
+ state = false;
+ }
return state;
};
bool test_32() {
-
#define STRIP_TEST(x) \
{ \
bool success = x; \
@@ -1071,7 +1073,7 @@ bool test_33() {
OS::get_singleton()->print("\n\nTest 33: parse_utf8(null, -1)\n");
String empty;
- return empty.parse_utf8(NULL, -1);
+ return empty.parse_utf8(nullptr, -1);
}
bool test_34() {
@@ -1125,7 +1127,7 @@ bool test_35() {
return state;
}
-typedef bool (*TestFunc)(void);
+typedef bool (*TestFunc)();
TestFunc test_funcs[] = {
@@ -1164,12 +1166,11 @@ TestFunc test_funcs[] = {
test_33,
test_34,
test_35,
- 0
+ nullptr
};
MainLoop *test() {
-
/** A character length != wchar_t may be forced, so the tests won't work */
static_assert(sizeof(CharType) == sizeof(wchar_t));
@@ -1178,11 +1179,13 @@ MainLoop *test() {
int passed = 0;
while (true) {
- if (!test_funcs[count])
+ if (!test_funcs[count]) {
break;
+ }
bool pass = test_funcs[count]();
- if (pass)
+ if (pass) {
passed++;
+ }
OS::get_singleton()->print("\t%s\n", pass ? "PASS" : "FAILED");
count++;
@@ -1195,6 +1198,7 @@ MainLoop *test() {
OS::get_singleton()->print("Passed %i of %i tests\n", passed, count);
- return NULL;
+ return nullptr;
}
+
} // namespace TestString