diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/data/translations.csv | 5 | ||||
-rw-r--r-- | tests/test_astar.h | 2 | ||||
-rw-r--r-- | tests/test_class_db.h | 64 | ||||
-rw-r--r-- | tests/test_config_file.h | 11 | ||||
-rw-r--r-- | tests/test_curve.h | 35 | ||||
-rw-r--r-- | tests/test_file_access.h | 29 | ||||
-rw-r--r-- | tests/test_geometry_2d.h | 33 | ||||
-rw-r--r-- | tests/test_geometry_3d.h | 29 | ||||
-rw-r--r-- | tests/test_gui.cpp | 2 | ||||
-rw-r--r-- | tests/test_math.cpp | 8 | ||||
-rw-r--r-- | tests/test_object.h | 12 | ||||
-rw-r--r-- | tests/test_physics_2d.cpp | 4 | ||||
-rw-r--r-- | tests/test_physics_3d.cpp | 4 | ||||
-rw-r--r-- | tests/test_render.cpp | 14 | ||||
-rw-r--r-- | tests/test_string.h | 26 | ||||
-rw-r--r-- | tests/test_text_server.h | 40 | ||||
-rw-r--r-- | tests/test_variant.h | 39 |
17 files changed, 250 insertions, 107 deletions
diff --git a/tests/data/translations.csv b/tests/data/translations.csv index 4c9ad4996a..8cb7b800c5 100644 --- a/tests/data/translations.csv +++ b/tests/data/translations.csv @@ -1,3 +1,8 @@ keys,en,de GOOD_MORNING,"Good Morning","Guten Morgen" GOOD_EVENING,"Good Evening","" +Without quotes,"With, comma","With ""inner"" quotes","With ""inner"", quotes"","" and comma","With ""inner +split"" quotes and +line breaks","With \nnewline chars" +Some other~delimiter~should still work, shouldn't it? +What about tab separated lines, good? diff --git a/tests/test_astar.h b/tests/test_astar.h index 12664a5ff1..137c477946 100644 --- a/tests/test_astar.h +++ b/tests/test_astar.h @@ -63,7 +63,7 @@ public: } // Disable heuristic completely. - float _compute_cost(int p_from, int p_to) { + real_t _compute_cost(int p_from, int p_to) { if (p_from == A && p_to == C) { return 1000; } diff --git a/tests/test_class_db.h b/tests/test_class_db.h index 29edf5a4a0..20397bb144 100644 --- a/tests/test_class_db.h +++ b/tests/test_class_db.h @@ -108,9 +108,9 @@ struct ExposedClass { 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(); + for (const PropertyData &E : properties) { + if (E.name == p_name) { + return &E; } } @@ -118,9 +118,9 @@ struct ExposedClass { } 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(); + for (const MethodData &E : methods) { + if (E.name == p_name) { + return &E; } } @@ -395,8 +395,8 @@ void validate_method(const Context &p_context, const ExposedClass &p_class, cons } } - for (const List<ArgumentData>::Element *F = p_method.arguments.front(); F; F = F->next()) { - const ArgumentData &arg = F->get(); + for (const ArgumentData &F : p_method.arguments) { + const ArgumentData &arg = F; const ExposedClass *arg_class = p_context.find_exposed_class(arg.type); if (arg_class) { @@ -427,8 +427,8 @@ void validate_method(const Context &p_context, const ExposedClass &p_class, cons } void validate_signal(const Context &p_context, const ExposedClass &p_class, const SignalData &p_signal) { - for (const List<ArgumentData>::Element *F = p_signal.arguments.front(); F; F = F->next()) { - const ArgumentData &arg = F->get(); + for (const ArgumentData &F : p_signal.arguments) { + const ArgumentData &arg = F; const ExposedClass *arg_class = p_context.find_exposed_class(arg.type); if (arg_class) { @@ -469,16 +469,16 @@ void validate_class(const Context &p_context, const ExposedClass &p_exposed_clas 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()) { - validate_property(p_context, p_exposed_class, F->get()); + for (const PropertyData &F : p_exposed_class.properties) { + validate_property(p_context, p_exposed_class, F); } - for (const List<MethodData>::Element *F = p_exposed_class.methods.front(); F; F = F->next()) { - validate_method(p_context, p_exposed_class, F->get()); + for (const MethodData &F : p_exposed_class.methods) { + validate_method(p_context, p_exposed_class, F); } - for (const List<SignalData>::Element *F = p_exposed_class.signals_.front(); F; F = F->next()) { - validate_signal(p_context, p_exposed_class, F->get()); + for (const SignalData &F : p_exposed_class.signals_) { + validate_signal(p_context, p_exposed_class, F); } } @@ -526,10 +526,8 @@ void add_exposed_classes(Context &r_context) { 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) { + for (const PropertyInfo &property : property_list) { + if (property.usage & PROPERTY_USAGE_GROUP || property.usage & PROPERTY_USAGE_SUBGROUP || property.usage & PROPERTY_USAGE_CATEGORY || (property.type == Variant::NIL && property.usage & PROPERTY_USAGE_ARRAY)) { continue; } @@ -561,8 +559,8 @@ void add_exposed_classes(Context &r_context) { 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(); + for (const MethodInfo &E : method_list) { + const MethodInfo &method_info = E; int argc = method_info.arguments.size(); @@ -667,8 +665,8 @@ void add_exposed_classes(Context &r_context) { // Methods starting with an underscore are ignored unless they're virtual or 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(); + for (const PropertyData &F : exposed_class.properties) { + const PropertyData &prop = F; if (prop.setter == method.name || prop.getter == method.name) { exposed_class.methods.push_back(method); @@ -752,8 +750,8 @@ void add_exposed_classes(Context &r_context) { 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(); + for (const StringName &E : enum_constants) { + const StringName &constant_name = E; TEST_FAIL_COND(String(constant_name).find("::") != -1, "Enum constant contains '::', check bindings to remove the scope: '", String(class_name), ".", String(enum_.name), ".", String(constant_name), "'."); @@ -774,12 +772,12 @@ void add_exposed_classes(Context &r_context) { 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(); + for (const String &E : constants) { + const String &constant_name = E; TEST_FAIL_COND(constant_name.find("::") != -1, "Constant contains '::', check bindings to remove the scope: '", String(class_name), ".", constant_name, "'."); - int *value = class_info->constant_map.getptr(StringName(E->get())); + int *value = class_info->constant_map.getptr(StringName(E)); TEST_FAIL_COND(!value, "Missing constant value: '", String(class_name), ".", String(constant_name), "'."); ConstantData constant; @@ -829,8 +827,8 @@ void add_global_enums(Context &r_context) { } } - for (List<EnumData>::Element *E = r_context.global_enums.front(); E; E = E->next()) { - r_context.enum_types.push_back(E->get().name); + for (const EnumData &E : r_context.global_enums) { + r_context.enum_types.push_back(E.name); } } @@ -840,10 +838,10 @@ void add_global_enums(Context &r_context) { 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()) { + for (const StringName &E : hardcoded_enums) { // 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()); + r_context.enum_types.push_back(E); } } diff --git a/tests/test_config_file.h b/tests/test_config_file.h index 33fd30ffa1..e3f40e16fd 100644 --- a/tests/test_config_file.h +++ b/tests/test_config_file.h @@ -122,6 +122,8 @@ TEST_CASE("[ConfigFile] Saving file") { config_file.set_value("player", "position", Vector2(3, 4)); config_file.set_value("graphics", "antialiasing", true); config_file.set_value("graphics", "antiAliasing", false); + config_file.set_value("quoted", String::utf8("静音"), 42); + config_file.set_value("quoted", "a=b", 7); #ifdef WINDOWS_ENABLED const String config_path = OS::get_singleton()->get_environment("TEMP").plus_file("config.ini"); @@ -132,7 +134,7 @@ TEST_CASE("[ConfigFile] Saving file") { config_file.save(config_path); // Expected contents of the saved ConfigFile. - const String contents = R"([player] + const String contents = String::utf8(R"([player] name="Unnamed Player" tagline="Waiting @@ -145,7 +147,12 @@ position=Vector2(3, 4) antialiasing=true antiAliasing=false -)"; + +[quoted] + +"静音"=42 +"a=b"=7 +)"); FileAccessRef file = FileAccess::open(config_path, FileAccess::READ); CHECK_MESSAGE(file->get_as_utf8_string() == contents, diff --git a/tests/test_curve.h b/tests/test_curve.h index 7eeee86f32..e079905e35 100644 --- a/tests/test_curve.h +++ b/tests/test_curve.h @@ -216,6 +216,41 @@ TEST_CASE("[Curve] Custom curve with linear tangents") { Math::is_equal_approx(curve->interpolate_baked(0.7), (real_t)0.8), "Custom free curve should return the expected baked value at offset 0.7 after removing point at invalid index 10."); } + +TEST_CASE("[Curve2D] Linear sampling should return exact value") { + Ref<Curve2D> curve = memnew(Curve2D); + int len = 2048; + + curve->add_point(Vector2(0, 0)); + curve->add_point(Vector2((float)len, 0)); + + float baked_length = curve->get_baked_length(); + CHECK((float)len == baked_length); + + for (int i = 0; i < len; i++) { + float expected = (float)i; + Vector2 pos = curve->interpolate_baked(expected); + CHECK_MESSAGE(pos.x == expected, "interpolate_baked should return exact value"); + } +} + +TEST_CASE("[Curve3D] Linear sampling should return exact value") { + Ref<Curve3D> curve = memnew(Curve3D); + int len = 2048; + + curve->add_point(Vector3(0, 0, 0)); + curve->add_point(Vector3((float)len, 0, 0)); + + float baked_length = curve->get_baked_length(); + CHECK((float)len == baked_length); + + for (int i = 0; i < len; i++) { + float expected = (float)i; + Vector3 pos = curve->interpolate_baked(expected); + CHECK_MESSAGE(pos.x == expected, "interpolate_baked should return exact value"); + } +} + } // namespace TestCurve #endif // TEST_CURVE_H diff --git a/tests/test_file_access.h b/tests/test_file_access.h index cb74e08a0d..b3da16c1d1 100644 --- a/tests/test_file_access.h +++ b/tests/test_file_access.h @@ -37,12 +37,12 @@ namespace TestFileAccess { TEST_CASE("[FileAccess] CSV read") { - FileAccess *f = FileAccess::open(TestUtils::get_data_path("translations.csv"), FileAccess::READ); + FileAccessRef f = FileAccess::open(TestUtils::get_data_path("translations.csv"), FileAccess::READ); - Vector<String> header = f->get_csv_line(); // Default delimiter: "," + Vector<String> header = f->get_csv_line(); // Default delimiter: ",". REQUIRE(header.size() == 3); - Vector<String> row1 = f->get_csv_line(","); + Vector<String> row1 = f->get_csv_line(","); // Explicit delimiter, should be the same. REQUIRE(row1.size() == 3); CHECK(row1[0] == "GOOD_MORNING"); CHECK(row1[1] == "Good Morning"); @@ -53,12 +53,31 @@ TEST_CASE("[FileAccess] CSV read") { CHECK(row2[0] == "GOOD_EVENING"); CHECK(row2[1] == "Good Evening"); CHECK(row2[2] == ""); // Use case: not yet translated! - // https://github.com/godotengine/godot/issues/44269 CHECK_MESSAGE(row2[2] != "\"", "Should not parse empty string as a single double quote."); + Vector<String> row3 = f->get_csv_line(); + REQUIRE(row3.size() == 6); + CHECK(row3[0] == "Without quotes"); + CHECK(row3[1] == "With, comma"); + CHECK(row3[2] == "With \"inner\" quotes"); + CHECK(row3[3] == "With \"inner\", quotes\",\" and comma"); + CHECK(row3[4] == "With \"inner\nsplit\" quotes and\nline breaks"); + CHECK(row3[5] == "With \\nnewline chars"); // Escaped, not an actual newline. + + Vector<String> row4 = f->get_csv_line("~"); // Custom delimiter, makes inline commas easier. + REQUIRE(row4.size() == 3); + CHECK(row4[0] == "Some other"); + CHECK(row4[1] == "delimiter"); + CHECK(row4[2] == "should still work, shouldn't it?"); + + Vector<String> row5 = f->get_csv_line("\t"); // Tab separated variables. + REQUIRE(row5.size() == 3); + CHECK(row5[0] == "What about"); + CHECK(row5[1] == "tab separated"); + CHECK(row5[2] == "lines, good?"); + f->close(); - memdelete(f); } } // namespace TestFileAccess diff --git a/tests/test_geometry_2d.h b/tests/test_geometry_2d.h index 32d4114a1c..25af8c355e 100644 --- a/tests/test_geometry_2d.h +++ b/tests/test_geometry_2d.h @@ -51,8 +51,6 @@ TEST_CASE("[Geometry2D] Point in circle") { CHECK_FALSE(Geometry2D::is_point_in_circle(Vector2(7, -42), Vector2(4, -40), 3.5)); // This tests points on the edge of the circle. They are treated as being inside the circle. - // In `is_point_in_triangle` and `is_point_in_polygon` they are treated as being outside, so in order the make - // the behaviour consistent this may change in the future (see issue #44717 and PR #44274). CHECK(Geometry2D::is_point_in_circle(Vector2(1.0, 0.0), Vector2(0, 0), 1.0)); CHECK(Geometry2D::is_point_in_circle(Vector2(0.0, -1.0), Vector2(0, 0), 1.0)); } @@ -66,7 +64,7 @@ TEST_CASE("[Geometry2D] Point in triangle") { CHECK_FALSE(Geometry2D::is_point_in_triangle(Vector2(0, 0), Vector2(1, 4), Vector2(3, 2), Vector2(5, 4))); // This tests points on the edge of the triangle. They are treated as being outside the triangle. - // In `is_point_in_circle` they are treated as being inside, so in order the make + // In `is_point_in_circle` and `is_point_in_polygon` they are treated as being inside, so in order the make // the behaviour consistent this may change in the future (see issue #44717 and PR #44274). CHECK_FALSE(Geometry2D::is_point_in_triangle(Vector2(1, 1), Vector2(-1, 1), Vector2(0, -1), Vector2(1, 1))); CHECK_FALSE(Geometry2D::is_point_in_triangle(Vector2(0, 1), Vector2(-1, 1), Vector2(0, -1), Vector2(1, 1))); @@ -95,11 +93,16 @@ TEST_CASE("[Geometry2D] Point in polygon") { CHECK(Geometry2D::is_point_in_polygon(Vector2(370, 55), p)); CHECK(Geometry2D::is_point_in_polygon(Vector2(-160, 190), p)); - // This tests points on the edge of the polygon. They are treated as being outside the polygon. - // In `is_point_in_circle` they are treated as being inside, so in order the make - // the behaviour consistent this may change in the future (see issue #44717 and PR #44274). - CHECK_FALSE(Geometry2D::is_point_in_polygon(Vector2(68, 112), p)); - CHECK_FALSE(Geometry2D::is_point_in_polygon(Vector2(-88, 120), p)); + // This tests points on the edge of the polygon. They are treated as being inside the polygon. + int c = p.size(); + for (int i = 0; i < c; i++) { + const Vector2 &p1 = p[i]; + CHECK(Geometry2D::is_point_in_polygon(p1, p)); + + const Vector2 &p2 = p[(i + 1) % c]; + Vector2 midpoint((p1 + p2) * 0.5); + CHECK(Geometry2D::is_point_in_polygon(midpoint, p)); + } } TEST_CASE("[Geometry2D] Polygon clockwise") { @@ -140,9 +143,21 @@ TEST_CASE("[Geometry2D] Segment intersection.") { CHECK(r.is_equal_approx(Vector2(0, 0))); CHECK_FALSE(Geometry2D::segment_intersects_segment(Vector2(-1, 1), Vector2(1, -1), Vector2(1, 1), Vector2(0.1, 0.1), &r)); + CHECK_FALSE(Geometry2D::segment_intersects_segment(Vector2(-1, 1), Vector2(1, -1), Vector2(0.1, 0.1), Vector2(1, 1), &r)); + CHECK_FALSE_MESSAGE( - Geometry2D::segment_intersects_segment(Vector2(-1, 1), Vector2(1, -1), Vector2(0, 1), Vector2(1, -1), &r), + Geometry2D::segment_intersects_segment(Vector2(-1, 1), Vector2(1, -1), Vector2(0, 1), Vector2(2, -1), &r), "Parallel segments should not intersect."); + + CHECK_MESSAGE( + Geometry2D::segment_intersects_segment(Vector2(0, 0), Vector2(0, 1), Vector2(0, 0), Vector2(1, 0), &r), + "Touching segments should intersect."); + CHECK(r.is_equal_approx(Vector2(0, 0))); + + CHECK_MESSAGE( + Geometry2D::segment_intersects_segment(Vector2(0, 1), Vector2(0, 0), Vector2(0, 0), Vector2(1, 0), &r), + "Touching segments should intersect."); + CHECK(r.is_equal_approx(Vector2(0, 0))); } TEST_CASE("[Geometry2D] Closest point to segment") { diff --git a/tests/test_geometry_3d.h b/tests/test_geometry_3d.h index 2b2a424b2b..40cb8bc07a 100644 --- a/tests/test_geometry_3d.h +++ b/tests/test_geometry_3d.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef TEST_3D_GEOMETRY_H -#define TEST_3D_GEOMETRY_H +#ifndef TEST_GEOMETRY_3D_H +#define TEST_GEOMETRY_3D_H #include "core/math/geometry_3d.h" #include "core/math/plane.h" @@ -38,7 +38,7 @@ #include "tests/test_macros.h" #include "vector" -namespace Test3DGeometry { +namespace TestGeometry3D { TEST_CASE("[Geometry3D] Closest Points Between Segments") { struct Case { Vector3 p_1, p_2, p_3, p_4; @@ -57,6 +57,7 @@ TEST_CASE("[Geometry3D] Closest Points Between Segments") { CHECK(current_case.got_2.is_equal_approx(current_case.want_2)); } } + TEST_CASE("[Geometry3D] Closest Distance Between Segments") { struct Case { Vector3 p_1, p_2, p_3, p_4; @@ -73,6 +74,7 @@ TEST_CASE("[Geometry3D] Closest Distance Between Segments") { CHECK(out == current_case.want); } } + TEST_CASE("[Geometry3D] Build Box Planes") { const Vector3 extents = Vector3(5, 5, 20); Vector<Plane> box = Geometry3D::build_box_planes(extents); @@ -90,6 +92,7 @@ TEST_CASE("[Geometry3D] Build Box Planes") { CHECK(extents.z == box[5].d); CHECK(box[5].normal == Vector3(0, 0, -1)); } + TEST_CASE("[Geometry3D] Build Capsule Planes") { struct Case { real_t radius, height; @@ -109,6 +112,7 @@ TEST_CASE("[Geometry3D] Build Capsule Planes") { CHECK(capsule.size() == current_case.want_size); } } + TEST_CASE("[Geometry3D] Build Cylinder Planes") { struct Case { real_t radius, height; @@ -127,6 +131,7 @@ TEST_CASE("[Geometry3D] Build Cylinder Planes") { CHECK(planes.size() == current_case.want_size); } } + TEST_CASE("[Geometry3D] Build Sphere Planes") { struct Case { real_t radius; @@ -145,6 +150,7 @@ TEST_CASE("[Geometry3D] Build Sphere Planes") { CHECK(planes.size() == 63); } } + TEST_CASE("[Geometry3D] Build Convex Mesh") { struct Case { Vector<Plane> object; @@ -166,6 +172,7 @@ TEST_CASE("[Geometry3D] Build Convex Mesh") { CHECK(mesh.vertices.size() == current_case.want_vertices); } } + TEST_CASE("[Geometry3D] Clip Polygon") { struct Case { Plane clipping_plane; @@ -190,6 +197,7 @@ TEST_CASE("[Geometry3D] Clip Polygon") { } } } + TEST_CASE("[Geometry3D] Compute Convex Mesh Points") { struct Case { Vector<Plane> mesh; @@ -215,6 +223,7 @@ TEST_CASE("[Geometry3D] Compute Convex Mesh Points") { CHECK(vectors == current_case.want); } } + TEST_CASE("[Geometry3D] Get Closest Point To Segment") { struct Case { Vector3 point; @@ -235,6 +244,7 @@ TEST_CASE("[Geometry3D] Get Closest Point To Segment") { CHECK(output.is_equal_approx(current_case.want)); } } + TEST_CASE("[Geometry3D] Plane and Box Overlap") { struct Case { Vector3 normal, max_box; @@ -254,6 +264,7 @@ TEST_CASE("[Geometry3D] Plane and Box Overlap") { CHECK(overlap == current_case.want); } } + TEST_CASE("[Geometry3D] Is Point in Projected Triangle") { struct Case { Vector3 point, v_1, v_2, v_3; @@ -272,6 +283,7 @@ TEST_CASE("[Geometry3D] Is Point in Projected Triangle") { CHECK(output == current_case.want); } } + TEST_CASE("[Geometry3D] Does Ray Intersect Triangle") { struct Case { Vector3 from, direction, v_1, v_2, v_3; @@ -291,6 +303,7 @@ TEST_CASE("[Geometry3D] Does Ray Intersect Triangle") { CHECK(output == current_case.want); } } + TEST_CASE("[Geometry3D] Does Segment Intersect Convex") { struct Case { Vector3 from, to; @@ -311,6 +324,7 @@ TEST_CASE("[Geometry3D] Does Segment Intersect Convex") { CHECK(output == current_case.want); } } + TEST_CASE("[Geometry3D] Segment Intersects Cylinder") { struct Case { Vector3 from, to; @@ -330,6 +344,7 @@ TEST_CASE("[Geometry3D] Segment Intersects Cylinder") { CHECK(output == current_case.want); } } + TEST_CASE("[Geometry3D] Segment Intersects Cylinder") { struct Case { Vector3 from, to, sphere_pos; @@ -350,6 +365,7 @@ TEST_CASE("[Geometry3D] Segment Intersects Cylinder") { CHECK(output == current_case.want); } } + TEST_CASE("[Geometry3D] Segment Intersects Triangle") { struct Case { Vector3 from, to, v_1, v_2, v_3, *result; @@ -368,6 +384,7 @@ TEST_CASE("[Geometry3D] Segment Intersects Triangle") { CHECK(output == current_case.want); } } + TEST_CASE("[Geometry3D] Triangle and Box Overlap") { struct Case { Vector3 box_centre; @@ -389,6 +406,7 @@ TEST_CASE("[Geometry3D] Triangle and Box Overlap") { CHECK(output == current_case.want); } } + TEST_CASE("[Geometry3D] Triangle and Sphere Intersect") { struct Case { Vector<Vector3> triangle; @@ -413,5 +431,6 @@ TEST_CASE("[Geometry3D] Triangle and Sphere Intersect") { CHECK(output == current_case.want); } } -} // namespace Test3DGeometry -#endif +} // namespace TestGeometry3D + +#endif // TEST_GEOMETRY_3D_H diff --git a/tests/test_gui.cpp b/tests/test_gui.cpp index b83bd10af4..0ec8aa78c4 100644 --- a/tests/test_gui.cpp +++ b/tests/test_gui.cpp @@ -217,7 +217,7 @@ public: richtext->add_text("faeries.\n"); richtext->pop(); richtext->add_text("In this new episode, we will attempt to "); - richtext->push_font(richtext->get_theme_font("mono_font", "Fonts")); + richtext->push_font(richtext->get_theme_font(SNAME("mono_font"), SNAME("Fonts"))); richtext->push_color(Color(0.7, 0.5, 1.0)); richtext->add_text("deliver something nice"); richtext->pop(); diff --git a/tests/test_math.cpp b/tests/test_math.cpp index 67d9a52539..a44040dfe2 100644 --- a/tests/test_math.cpp +++ b/tests/test_math.cpp @@ -549,8 +549,8 @@ MainLoop *test() { 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(); + for (const StringName &E : tl) { + Vector<uint8_t> m5b = E.operator String().md5_buffer(); hashes.push_back(hashes.size()); } @@ -589,13 +589,13 @@ MainLoop *test() { { Vector3 v(1, 2, 3); v.normalize(); - float a = 0.3; + real_t a = 0.3; Basis m(v, a); Vector3 v2(7, 3, 1); v2.normalize(); - float a2 = 0.8; + real_t a2 = 0.8; Basis m2(v2, a2); diff --git a/tests/test_object.h b/tests/test_object.h index b7eedc2670..8cb7116a20 100644 --- a/tests/test_object.h +++ b/tests/test_object.h @@ -93,8 +93,8 @@ public: Ref<Script> get_script() const override { return Ref<Script>(); } - const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override { - return Vector<MultiplayerAPI::RPCConfig>(); + const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override { + return Vector<Multiplayer::RPCConfig>(); } ScriptLanguage *get_language() override { return nullptr; @@ -139,7 +139,7 @@ TEST_CASE("[Object] Metadata") { Color(object.get_meta(meta_path)).is_equal_approx(Color(0, 1, 0)), "The returned object metadata after setting should match the expected value."); - List<String> meta_list; + List<StringName> meta_list; object.get_meta_list(&meta_list); CHECK_MESSAGE( meta_list.size() == 1, @@ -154,7 +154,7 @@ TEST_CASE("[Object] Metadata") { "The returned object metadata after removing should match the expected value."); ERR_PRINT_ON; - List<String> meta_list2; + List<StringName> meta_list2; object.get_meta_list(&meta_list2); CHECK_MESSAGE( meta_list2.size() == 0, @@ -206,7 +206,7 @@ TEST_CASE("[Object] Script instance property getter") { } TEST_CASE("[Object] Built-in property setter") { - ClassDB::register_class<_TestDerivedObject>(); + GDREGISTER_CLASS(_TestDerivedObject); _TestDerivedObject derived_object; bool valid = false; @@ -218,7 +218,7 @@ TEST_CASE("[Object] Built-in property setter") { } TEST_CASE("[Object] Built-in property getter") { - ClassDB::register_class<_TestDerivedObject>(); + GDREGISTER_CLASS(_TestDerivedObject); _TestDerivedObject derived_object; derived_object.set_property(100); diff --git a/tests/test_physics_2d.cpp b/tests/test_physics_2d.cpp index a9e2e92b34..61b8951afa 100644 --- a/tests/test_physics_2d.cpp +++ b/tests/test_physics_2d.cpp @@ -255,7 +255,7 @@ protected: arr.push_back(p_normal); arr.push_back(p_d); - RID plane = ps->line_shape_create(); + RID plane = ps->world_margin_shape_create(); ps->shape_set_data(plane, arr); RID plane_body = ps->body_create(); @@ -386,7 +386,7 @@ public: //_add_plane(Vector2(-1,0).normalized(),-600); } - virtual bool process(float p_time) override { + virtual bool process(double p_time) override { return false; } virtual void finalize() override { diff --git a/tests/test_physics_3d.cpp b/tests/test_physics_3d.cpp index 4488e4bf64..ed49b60c71 100644 --- a/tests/test_physics_3d.cpp +++ b/tests/test_physics_3d.cpp @@ -313,7 +313,7 @@ public: test_fall(); quit = false; } - virtual bool physics_process(float p_time) override { + virtual bool physics_process(double p_time) override { if (mover.is_valid()) { static real_t joy_speed = 10; PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); @@ -399,7 +399,7 @@ public: create_static_plane(Plane(Vector3(0, 1, 0), -1)); } - virtual bool process(float p_time) override { + virtual bool process(double p_time) override { return false; } diff --git a/tests/test_render.cpp b/tests/test_render.cpp index fe223ca258..21b4da9b3b 100644 --- a/tests/test_render.cpp +++ b/tests/test_render.cpp @@ -184,7 +184,7 @@ public: light = vs->instance_create2(lightaux, scenario); Transform3D lla; //lla.set_look_at(Vector3(),Vector3(1, -1, 1)); - lla.set_look_at(Vector3(), Vector3(0.0, -0.836026, -0.548690)); + lla.basis = Basis::looking_at(Vector3(0.0, -0.836026, -0.548690)); vs->instance_set_transform(light, lla); @@ -199,7 +199,7 @@ public: ofs = 0; quit = false; } - virtual bool iteration(float p_time) { + virtual bool iteration(double p_time) { RenderingServer *vs = RenderingServer::get_singleton(); //Transform3D t; //t.rotate(Vector3(0, 1, 0), ofs); @@ -210,12 +210,12 @@ public: //return quit; - for (List<InstanceInfo>::Element *E = instances.front(); E; E = E->next()) { - Transform3D pre(Basis(E->get().rot_axis, ofs), Vector3()); - vs->instance_set_transform(E->get().instance, pre * E->get().base); + for (const InstanceInfo &E : instances) { + Transform3D pre(Basis(E.rot_axis, ofs), Vector3()); + vs->instance_set_transform(E.instance, pre * E.base); /* if( !E->next() ) { - vs->free( E->get().instance ); + vs->free( E.instance ); instances.erase(E ); }*/ } @@ -223,7 +223,7 @@ public: return quit; } - virtual bool idle(float p_time) { + virtual bool idle(double p_time) { return quit; } diff --git a/tests/test_string.h b/tests/test_string.h index 1982d8de60..82b23d8a00 100644 --- a/tests/test_string.h +++ b/tests/test_string.h @@ -350,6 +350,9 @@ TEST_CASE("[String] Insertion") { } TEST_CASE("[String] Number to string") { + CHECK(String::num(0) == "0"); + CHECK(String::num(0.0) == "0"); // No trailing zeros. + CHECK(String::num(-0.0) == "-0"); // Includes sign even for zero. CHECK(String::num(3.141593) == "3.141593"); CHECK(String::num(3.141593, 3) == "3.142"); CHECK(String::num_real(3.141593) == "3.141593"); @@ -357,6 +360,27 @@ TEST_CASE("[String] Number to string") { CHECK(String::num_int64(3141593) == "3141593"); CHECK(String::num_int64(0xA141593, 16) == "a141593"); CHECK(String::num_int64(0xA141593, 16, true) == "A141593"); + CHECK(String::num(42.100023, 4) == "42.1"); // No trailing zeros. + + // Checks doubles with many decimal places. + CHECK(String::num(0.0000012345432123454321, -1) == "0.00000123454321"); // -1 uses 14 as sane default. + CHECK(String::num(0.0000012345432123454321) == "0.00000123454321"); // -1 is the default value. + CHECK(String::num(-0.0000012345432123454321) == "-0.00000123454321"); + CHECK(String::num(-10000.0000012345432123454321) == "-10000.0000012345"); + CHECK(String::num(0.0000000000012345432123454321) == "0.00000000000123"); + CHECK(String::num(0.0000000000012345432123454321, 3) == "0"); + + // Note: When relevant (remainder > 0.5), the last digit gets rounded up, + // which can also lead to not include a trailing zero, e.g. "...89" -> "...9". + CHECK(String::num(0.0000056789876567898765) == "0.00000567898766"); // Should round last digit. + CHECK(String::num(10000.000005678999999999) == "10000.000005679"); // We cut at ...789|99 which is rounded to ...79, so only 13 decimals. + CHECK(String::num(42.12999999, 6) == "42.13"); // Also happens with lower decimals count. + + // 32 is MAX_DECIMALS. We can't reliably store that many so we can't compare against a string, + // but we can check that the string length is 34 (32 + 2 for "0."). + CHECK(String::num(0.00000123456789987654321123456789987654321, 32).length() == 34); + CHECK(String::num(0.00000123456789987654321123456789987654321, 42).length() == 34); // Should enforce MAX_DECIMALS. + CHECK(String::num(10000.00000123456789987654321123456789987654321, 42).length() == 38); // 32 decimals + "10000.". } TEST_CASE("[String] String to integer") { @@ -1131,7 +1155,7 @@ TEST_CASE("[String] Path functions") { CHECK(String(path[i]).get_extension() == ext[i]); CHECK(String(path[i]).get_file() == file[i]); CHECK(String(path[i]).is_absolute_path() == abs[i]); - CHECK(String(path[i]).is_rel_path() != abs[i]); + CHECK(String(path[i]).is_relative_path() != abs[i]); CHECK(String(path[i]).simplify_path().get_base_dir().plus_file(file[i]) == String(path[i]).simplify_path()); } diff --git a/tests/test_text_server.h b/tests/test_text_server.h index 3d700f8ec4..b8ed4f89d0 100644 --- a/tests/test_text_server.h +++ b/tests/test_text_server.h @@ -55,7 +55,8 @@ TEST_SUITE("[[TextServer]") { for (int i = 0; i < TextServerManager::get_interface_count(); i++) { TextServer *ts = TextServerManager::initialize(i, err); - RID font = ts->create_font_memory(_font_NotoSansUI_Regular, _font_NotoSansUI_Regular_size, "ttf"); + RID font = ts->create_font(); + ts->font_set_data_ptr(font, _font_NotoSans_Regular, _font_NotoSans_Regular_size); TEST_FAIL_COND(font == RID(), "Loading font failed."); ts->free(font); } @@ -65,9 +66,14 @@ TEST_SUITE("[[TextServer]") { for (int i = 0; i < TextServerManager::get_interface_count(); i++) { TextServer *ts = TextServerManager::initialize(i, err); + RID font1 = ts->create_font(); + ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size); + RID font2 = ts->create_font(); + ts->font_set_data_ptr(font2, _font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size); + Vector<RID> font; - font.push_back(ts->create_font_memory(_font_NotoSansUI_Regular, _font_NotoSansUI_Regular_size, "ttf")); - font.push_back(ts->create_font_memory(_font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size, "ttf")); + font.push_back(font1); + font.push_back(font2); String test = U"คนอ้วน khon uan ראה"; // 6^ 17^ @@ -111,9 +117,14 @@ TEST_SUITE("[[TextServer]") { continue; } + RID font1 = ts->create_font(); + ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size); + RID font2 = ts->create_font(); + ts->font_set_data_ptr(font2, _font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size); + Vector<RID> font; - font.push_back(ts->create_font_memory(_font_NotoSansUI_Regular, _font_NotoSansUI_Regular_size, "ttf")); - font.push_back(ts->create_font_memory(_font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size, "ttf")); + font.push_back(font1); + font.push_back(font2); String test = U"Arabic (اَلْعَرَبِيَّةُ, al-ʿarabiyyah)"; // 7^ 26^ @@ -155,9 +166,14 @@ TEST_SUITE("[[TextServer]") { String test_1 = U"test test test"; // 5^ 10^ + RID font1 = ts->create_font(); + ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size); + RID font2 = ts->create_font(); + ts->font_set_data_ptr(font2, _font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size); + Vector<RID> font; - font.push_back(ts->create_font_memory(_font_NotoSansUI_Regular, _font_NotoSansUI_Regular_size, "ttf")); - font.push_back(ts->create_font_memory(_font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size, "ttf")); + font.push_back(font1); + font.push_back(font2); RID ctx = ts->create_shaped_text(); TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); @@ -185,9 +201,14 @@ TEST_SUITE("[[TextServer]") { for (int i = 0; i < TextServerManager::get_interface_count(); i++) { TextServer *ts = TextServerManager::initialize(i, err); + RID font1 = ts->create_font(); + ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size); + RID font2 = ts->create_font(); + ts->font_set_data_ptr(font2, _font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size); + Vector<RID> font; - font.push_back(ts->create_font_memory(_font_NotoSansUI_Regular, _font_NotoSansUI_Regular_size, "ttf")); - font.push_back(ts->create_font_memory(_font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size, "ttf")); + font.push_back(font1); + font.push_back(font2); String test_1 = U"الحمد"; String test_2 = U"الحمد test"; @@ -242,7 +263,6 @@ TEST_SUITE("[[TextServer]") { font.clear(); } } - memdelete(tsman); } } diff --git a/tests/test_variant.h b/tests/test_variant.h index dfc72b512c..598fe488d7 100644 --- a/tests/test_variant.h +++ b/tests/test_variant.h @@ -39,7 +39,7 @@ namespace TestVariant { TEST_CASE("[Variant] Writer and parser integer") { - int64_t a32 = 2147483648; // 2^31, so out of bounds for 32-bit signed int [-2^31,-2^31-1]. + int64_t a32 = 2147483648; // 2^31, so out of bounds for 32-bit signed int [-2^31, +2^31-1]. String a32_str; VariantWriter::write_to_string(a32, a32_str); @@ -76,34 +76,35 @@ TEST_CASE("[Variant] Writer and parser integer") { CHECK_MESSAGE(b64_int_parsed == 9223372036854775807, "The result should be clamped to max value."); } -TEST_CASE("[Variant] Writer and parser float") { - // Assuming real_t is double. - real_t a64 = 340282346638528859811704183484516925440.0; // std::numeric_limits<real_t>::max() +TEST_CASE("[Variant] Writer and parser Variant::FLOAT") { + // Variant::FLOAT is always 64-bit (C++ double). + // This is the maximum non-infinity double-precision float. + double a64 = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0; String a64_str; VariantWriter::write_to_string(a64, a64_str); - CHECK_MESSAGE(a64_str == "3.40282e+38", "Writes in scientific notation."); + CHECK_MESSAGE(a64_str == "1.79769e+308", "Writes in scientific notation."); CHECK_MESSAGE(a64_str != "inf", "Should not overflow."); CHECK_MESSAGE(a64_str != "nan", "The result should be defined."); - VariantParser::StreamString ss; String errs; int line; - Variant b64_parsed; - real_t b64_float_parsed; - - ss.s = a64_str; - VariantParser::parse(&ss, b64_parsed, errs, line); - b64_float_parsed = b64_parsed; + Variant variant_parsed; + double float_parsed; - CHECK_MESSAGE(b64_float_parsed == 340282001837565597733306976381245063168.0, "Should parse back."); + VariantParser::StreamString bss; + bss.s = a64_str; + VariantParser::parse(&bss, variant_parsed, errs, line); + float_parsed = variant_parsed; // Loses precision, but that's alright. - - ss.s = "1.0e+100"; // Float version of Googol! - VariantParser::parse(&ss, b64_parsed, errs, line); - b64_float_parsed = b64_parsed; - - CHECK_MESSAGE(b64_float_parsed == 340282001837565597733306976381245063168.0, "Should not overflow."); + CHECK_MESSAGE(float_parsed == 1.79769e+308, "Should parse back."); + + // Approximation of Googol with a double-precision float. + VariantParser::StreamString css; + css.s = "1.0e+100"; + VariantParser::parse(&css, variant_parsed, errs, line); + float_parsed = variant_parsed; + CHECK_MESSAGE(float_parsed == 1.0e+100, "Should match the double literal."); } TEST_CASE("[Variant] Assignment To Bool from Int,Float,String,Vec2,Vec2i,Vec3,Vec3i and Color") { |