diff options
Diffstat (limited to 'tests/core')
-rw-r--r-- | tests/core/input/test_input_event_key.h | 2 | ||||
-rw-r--r-- | tests/core/io/test_image.h | 6 | ||||
-rw-r--r-- | tests/core/io/test_json.h | 2 | ||||
-rw-r--r-- | tests/core/math/test_aabb.h | 8 | ||||
-rw-r--r-- | tests/core/math/test_basis.h | 144 | ||||
-rw-r--r-- | tests/core/math/test_color.h | 6 | ||||
-rw-r--r-- | tests/core/math/test_expression.h | 20 | ||||
-rw-r--r-- | tests/core/math/test_geometry_2d.h | 26 | ||||
-rw-r--r-- | tests/core/math/test_math_funcs.h | 556 | ||||
-rw-r--r-- | tests/core/math/test_quaternion.h | 65 | ||||
-rw-r--r-- | tests/core/math/test_rect2.h | 8 | ||||
-rw-r--r-- | tests/core/math/test_vector2.h | 34 | ||||
-rw-r--r-- | tests/core/math/test_vector2i.h | 6 | ||||
-rw-r--r-- | tests/core/math/test_vector3.h | 34 | ||||
-rw-r--r-- | tests/core/math/test_vector3i.h | 4 | ||||
-rw-r--r-- | tests/core/math/test_vector4.h | 10 | ||||
-rw-r--r-- | tests/core/math/test_vector4i.h | 4 | ||||
-rw-r--r-- | tests/core/string/test_string.h | 8 |
18 files changed, 726 insertions, 217 deletions
diff --git a/tests/core/input/test_input_event_key.h b/tests/core/input/test_input_event_key.h index ef0a656b18..b852f3ccb9 100644 --- a/tests/core/input/test_input_event_key.h +++ b/tests/core/input/test_input_event_key.h @@ -102,7 +102,7 @@ TEST_CASE("[InputEventKey] Key correctly converts itself to text") { // as text. These cases are a bit weird, since None has no textual representation // (find_keycode_name(Key::NONE) results in a nullptr). Thus, these tests look weird // with only (Physical) or a lonely modifier with (Physical) but (as far as I - // understand the code, that is intended behaviour. + // understand the code, that is intended behavior. // Key is None without a physical key. none_key.set_keycode(Key::NONE); diff --git a/tests/core/io/test_image.h b/tests/core/io/test_image.h index 38b616cda0..1559c59b5c 100644 --- a/tests/core/io/test_image.h +++ b/tests/core/io/test_image.h @@ -124,7 +124,7 @@ TEST_CASE("[Image] Saving and loading") { image_jpg->load_jpg_from_buffer(data_jpg) == OK, "The JPG image should load successfully."); - // Load WEBP + // Load WebP Ref<Image> image_webp = memnew(Image()); Ref<FileAccess> f_webp = FileAccess::open(TestUtils::get_data_path("images/icon.webp"), FileAccess::READ, &err); PackedByteArray data_webp; @@ -132,7 +132,7 @@ TEST_CASE("[Image] Saving and loading") { f_webp->get_buffer(data_webp.ptrw(), f_webp->get_length()); CHECK_MESSAGE( image_webp->load_webp_from_buffer(data_webp) == OK, - "The WEBP image should load successfully."); + "The WebP image should load successfully."); // Load PNG Ref<Image> image_png = memnew(Image()); @@ -162,7 +162,7 @@ TEST_CASE("[Image] Basic getters") { CHECK(image->get_size() == Vector2(8, 4)); CHECK(image->get_format() == Image::FORMAT_LA8); CHECK(image->get_used_rect() == Rect2i(0, 0, 0, 0)); - Ref<Image> image_get_rect = image->get_rect(Rect2i(0, 0, 2, 1)); + Ref<Image> image_get_rect = image->get_region(Rect2i(0, 0, 2, 1)); CHECK(image_get_rect->get_size() == Vector2(2, 1)); } diff --git a/tests/core/io/test_json.h b/tests/core/io/test_json.h index 478cf1766e..af450da3b8 100644 --- a/tests/core/io/test_json.h +++ b/tests/core/io/test_json.h @@ -83,7 +83,7 @@ TEST_CASE("[JSON] Parsing single data types") { json.get_error_line() == 0, "Parsing a floating-point number as JSON should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(json.get_data()), 0.123456), + double(json.get_data()) == doctest::Approx(0.123456), "Parsing a floating-point number as JSON should return the expected value."); json.parse("\"hello\""); diff --git a/tests/core/math/test_aabb.h b/tests/core/math/test_aabb.h index ebaf441abf..23969556be 100644 --- a/tests/core/math/test_aabb.h +++ b/tests/core/math/test_aabb.h @@ -91,7 +91,7 @@ TEST_CASE("[AABB] Basic setters") { TEST_CASE("[AABB] Volume getters") { AABB aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6)); CHECK_MESSAGE( - Math::is_equal_approx(aabb.get_volume(), 120), + aabb.get_volume() == doctest::Approx(120), "get_volume() should return the expected value with positive size."); CHECK_MESSAGE( aabb.has_volume(), @@ -99,17 +99,17 @@ TEST_CASE("[AABB] Volume getters") { aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(-4, 5, 6)); CHECK_MESSAGE( - Math::is_equal_approx(aabb.get_volume(), -120), + aabb.get_volume() == doctest::Approx(-120), "get_volume() should return the expected value with negative size (1 component)."); aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(-4, -5, 6)); CHECK_MESSAGE( - Math::is_equal_approx(aabb.get_volume(), 120), + aabb.get_volume() == doctest::Approx(120), "get_volume() should return the expected value with negative size (2 components)."); aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(-4, -5, -6)); CHECK_MESSAGE( - Math::is_equal_approx(aabb.get_volume(), -120), + aabb.get_volume() == doctest::Approx(-120), "get_volume() should return the expected value with negative size (3 components)."); aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 0, 6)); diff --git a/tests/core/math/test_basis.h b/tests/core/math/test_basis.h index a65020597a..dce9d5cec3 100644 --- a/tests/core/math/test_basis.h +++ b/tests/core/math/test_basis.h @@ -38,15 +38,6 @@ namespace TestBasis { -enum RotOrder { - EulerXYZ, - EulerXZY, - EulerYZX, - EulerYXZ, - EulerZXY, - EulerZYX -}; - Vector3 deg_to_rad(const Vector3 &p_rotation) { return p_rotation / 180.0 * Math_PI; } @@ -55,88 +46,26 @@ Vector3 rad2deg(const Vector3 &p_rotation) { return p_rotation / Math_PI * 180.0; } -Basis EulerToBasis(RotOrder mode, const Vector3 &p_rotation) { - Basis ret; - switch (mode) { - case EulerXYZ: - ret.set_euler(p_rotation, Basis::EULER_ORDER_XYZ); - break; - - case EulerXZY: - ret.set_euler(p_rotation, Basis::EULER_ORDER_XZY); - break; - - case EulerYZX: - ret.set_euler(p_rotation, Basis::EULER_ORDER_YZX); - break; - - case EulerYXZ: - ret.set_euler(p_rotation, Basis::EULER_ORDER_YXZ); - break; - - case EulerZXY: - ret.set_euler(p_rotation, Basis::EULER_ORDER_ZXY); - break; - - case EulerZYX: - ret.set_euler(p_rotation, Basis::EULER_ORDER_ZYX); - break; - - default: - // If you land here, Please integrate all rotation orders. - FAIL("This is not unreachable."); - } - - return ret; -} - -Vector3 BasisToEuler(RotOrder mode, const Basis &p_rotation) { - switch (mode) { - case EulerXYZ: - return p_rotation.get_euler(Basis::EULER_ORDER_XYZ); - - case EulerXZY: - return p_rotation.get_euler(Basis::EULER_ORDER_XZY); - - case EulerYZX: - return p_rotation.get_euler(Basis::EULER_ORDER_YZX); - - case EulerYXZ: - return p_rotation.get_euler(Basis::EULER_ORDER_YXZ); - - case EulerZXY: - return p_rotation.get_euler(Basis::EULER_ORDER_ZXY); - - case EulerZYX: - return p_rotation.get_euler(Basis::EULER_ORDER_ZYX); - - default: - // If you land here, Please integrate all rotation orders. - FAIL("This is not unreachable."); - return Vector3(); - } -} - -String get_rot_order_name(RotOrder ro) { +String get_rot_order_name(EulerOrder ro) { switch (ro) { - case EulerXYZ: + case EulerOrder::XYZ: return "XYZ"; - case EulerXZY: + case EulerOrder::XZY: return "XZY"; - case EulerYZX: + case EulerOrder::YZX: return "YZX"; - case EulerYXZ: + case EulerOrder::YXZ: return "YXZ"; - case EulerZXY: + case EulerOrder::ZXY: return "ZXY"; - case EulerZYX: + case EulerOrder::ZYX: return "ZYX"; default: return "[Not supported]"; } } -void test_rotation(Vector3 deg_original_euler, RotOrder rot_order) { +void test_rotation(Vector3 deg_original_euler, EulerOrder rot_order) { // This test: // 1. Converts the rotation vector from deg to rad. // 2. Converts euler to basis. @@ -156,11 +85,11 @@ void test_rotation(Vector3 deg_original_euler, RotOrder rot_order) { // Euler to rotation const Vector3 original_euler = deg_to_rad(deg_original_euler); - const Basis to_rotation = EulerToBasis(rot_order, original_euler); + const Basis to_rotation = Basis::from_euler(original_euler, rot_order); // Euler from rotation - const Vector3 euler_from_rotation = BasisToEuler(rot_order, to_rotation); - const Basis rotation_from_computed_euler = EulerToBasis(rot_order, euler_from_rotation); + const Vector3 euler_from_rotation = to_rotation.get_euler(rot_order); + const Basis rotation_from_computed_euler = Basis::from_euler(euler_from_rotation, rot_order); Basis res = to_rotation.inverse() * rotation_from_computed_euler; @@ -169,9 +98,8 @@ void test_rotation(Vector3 deg_original_euler, RotOrder rot_order) { CHECK_MESSAGE((res.get_column(2) - Vector3(0.0, 0.0, 1.0)).length() <= 0.1, vformat("Fail due to Z %s\n", String(res.get_column(2))).utf8().ptr()); // Double check `to_rotation` decomposing with XYZ rotation order. - const Vector3 euler_xyz_from_rotation = to_rotation.get_euler(Basis::EULER_ORDER_XYZ); - Basis rotation_from_xyz_computed_euler; - rotation_from_xyz_computed_euler.set_euler(euler_xyz_from_rotation, Basis::EULER_ORDER_XYZ); + const Vector3 euler_xyz_from_rotation = to_rotation.get_euler(EulerOrder::XYZ); + Basis rotation_from_xyz_computed_euler = Basis::from_euler(euler_xyz_from_rotation, EulerOrder::XYZ); res = to_rotation.inverse() * rotation_from_xyz_computed_euler; @@ -185,13 +113,13 @@ void test_rotation(Vector3 deg_original_euler, RotOrder rot_order) { } TEST_CASE("[Basis] Euler conversions") { - Vector<RotOrder> rotorder_to_test; - rotorder_to_test.push_back(EulerXYZ); - rotorder_to_test.push_back(EulerXZY); - rotorder_to_test.push_back(EulerYZX); - rotorder_to_test.push_back(EulerYXZ); - rotorder_to_test.push_back(EulerZXY); - rotorder_to_test.push_back(EulerZYX); + Vector<EulerOrder> euler_order_to_test; + euler_order_to_test.push_back(EulerOrder::XYZ); + euler_order_to_test.push_back(EulerOrder::XZY); + euler_order_to_test.push_back(EulerOrder::YZX); + euler_order_to_test.push_back(EulerOrder::YXZ); + euler_order_to_test.push_back(EulerOrder::ZXY); + euler_order_to_test.push_back(EulerOrder::ZYX); Vector<Vector3> vectors_to_test; @@ -249,21 +177,21 @@ TEST_CASE("[Basis] Euler conversions") { vectors_to_test.push_back(Vector3(120.0, 150.0, -130.0)); vectors_to_test.push_back(Vector3(120.0, 150.0, 130.0)); - for (int h = 0; h < rotorder_to_test.size(); h += 1) { + for (int h = 0; h < euler_order_to_test.size(); h += 1) { for (int i = 0; i < vectors_to_test.size(); i += 1) { - test_rotation(vectors_to_test[i], rotorder_to_test[h]); + test_rotation(vectors_to_test[i], euler_order_to_test[h]); } } } TEST_CASE("[Stress][Basis] Euler conversions") { - Vector<RotOrder> rotorder_to_test; - rotorder_to_test.push_back(EulerXYZ); - rotorder_to_test.push_back(EulerXZY); - rotorder_to_test.push_back(EulerYZX); - rotorder_to_test.push_back(EulerYXZ); - rotorder_to_test.push_back(EulerZXY); - rotorder_to_test.push_back(EulerZYX); + Vector<EulerOrder> euler_order_to_test; + euler_order_to_test.push_back(EulerOrder::XYZ); + euler_order_to_test.push_back(EulerOrder::XZY); + euler_order_to_test.push_back(EulerOrder::YZX); + euler_order_to_test.push_back(EulerOrder::YXZ); + euler_order_to_test.push_back(EulerOrder::ZXY); + euler_order_to_test.push_back(EulerOrder::ZYX); Vector<Vector3> vectors_to_test; // Add 1000 random vectors with weirds numbers. @@ -275,9 +203,9 @@ TEST_CASE("[Stress][Basis] Euler conversions") { rng.randf_range(-1800, 1800))); } - for (int h = 0; h < rotorder_to_test.size(); h += 1) { + for (int h = 0; h < euler_order_to_test.size(); h += 1) { for (int i = 0; i < vectors_to_test.size(); i += 1) { - test_rotation(vectors_to_test[i], rotorder_to_test[h]); + test_rotation(vectors_to_test[i], euler_order_to_test[h]); } } } @@ -295,7 +223,7 @@ TEST_CASE("[Basis] Set axis angle") { // Testing the singularity when the angle is 180°. Basis singularityPi(-1, 0, 0, 0, 1, 0, 0, 0, -1); singularityPi.get_axis_angle(axis, angle); - CHECK(Math::is_equal_approx(angle, pi)); + CHECK(angle == doctest::Approx(pi)); // Testing reversing the an axis (of an 30° angle). float cos30deg = Math::cos(Math::deg_to_rad((real_t)30.0)); @@ -303,17 +231,17 @@ TEST_CASE("[Basis] Set axis angle") { Basis z_negative(cos30deg, 0.5, 0, -0.5, cos30deg, 0, 0, 0, 1); z_positive.get_axis_angle(axis, angle); - CHECK(Math::is_equal_approx(angle, Math::deg_to_rad((real_t)30.0))); + CHECK(angle == doctest::Approx(Math::deg_to_rad((real_t)30.0))); CHECK(axis == Vector3(0, 0, 1)); z_negative.get_axis_angle(axis, angle); - CHECK(Math::is_equal_approx(angle, Math::deg_to_rad((real_t)30.0))); + CHECK(angle == doctest::Approx(Math::deg_to_rad((real_t)30.0))); CHECK(axis == Vector3(0, 0, -1)); // Testing a rotation of 90° on x-y-z. Basis x90deg(1, 0, 0, 0, 0, -1, 0, 1, 0); x90deg.get_axis_angle(axis, angle); - CHECK(Math::is_equal_approx(angle, pi / (real_t)2)); + CHECK(angle == doctest::Approx(pi / (real_t)2)); CHECK(axis == Vector3(1, 0, 0)); Basis y90deg(0, 0, 1, 0, 1, 0, -1, 0, 0); @@ -327,7 +255,7 @@ TEST_CASE("[Basis] Set axis angle") { // Regression test: checks that the method returns a small angle (not 0). Basis tiny(1, 0, 0, 0, 0.9999995, -0.001, 0, 001, 0.9999995); // The min angle possible with float is 0.001rad. tiny.get_axis_angle(axis, angle); - CHECK(Math::is_equal_approx(angle, (real_t)0.001, (real_t)0.0001)); + CHECK(angle == doctest::Approx(0.001).epsilon(0.0001)); // Regression test: checks that the method returns an angle which is a number (not NaN) Basis bugNan(1.00000024, 0, 0.000100001693, 0, 1, 0, -0.000100009143, 0, 1.00000024); diff --git a/tests/core/math/test_color.h b/tests/core/math/test_color.h index 51c3bc8bdc..c6550778e8 100644 --- a/tests/core/math/test_color.h +++ b/tests/core/math/test_color.h @@ -101,13 +101,13 @@ TEST_CASE("[Color] Reading methods") { const Color dark_blue = Color(0, 0, 0.5, 0.4); CHECK_MESSAGE( - Math::is_equal_approx(dark_blue.get_h(), 240.0f / 360.0f), + dark_blue.get_h() == doctest::Approx(240.0f / 360.0f), "The returned HSV hue should match the expected value."); CHECK_MESSAGE( - Math::is_equal_approx(dark_blue.get_s(), 1.0f), + dark_blue.get_s() == doctest::Approx(1.0f), "The returned HSV saturation should match the expected value."); CHECK_MESSAGE( - Math::is_equal_approx(dark_blue.get_v(), 0.5f), + dark_blue.get_v() == doctest::Approx(0.5f), "The returned HSV value should match the expected value."); } diff --git a/tests/core/math/test_expression.h b/tests/core/math/test_expression.h index 6e3be541b0..9734fd9f36 100644 --- a/tests/core/math/test_expression.h +++ b/tests/core/math/test_expression.h @@ -83,42 +83,42 @@ TEST_CASE("[Expression] Floating-point arithmetic") { expression.parse("-123.456") == OK, "Float identity should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), -123.456), + double(expression.execute()) == doctest::Approx(-123.456), "Float identity should return the expected result."); CHECK_MESSAGE( expression.parse("2.0 + 3.0") == OK, "Float addition should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 5), + double(expression.execute()) == doctest::Approx(5), "Float addition should return the expected result."); CHECK_MESSAGE( expression.parse("3.0 / 10") == OK, "Float / integer division should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 0.3), + double(expression.execute()) == doctest::Approx(0.3), "Float / integer division should return the expected result."); CHECK_MESSAGE( expression.parse("3 / 10.0") == OK, "Basic integer / float division should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 0.3), + double(expression.execute()) == doctest::Approx(0.3), "Basic integer / float division should return the expected result."); CHECK_MESSAGE( expression.parse("3.0 / 10.0") == OK, "Float / float division should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 0.3), + double(expression.execute()) == doctest::Approx(0.3), "Float / float division should return the expected result."); CHECK_MESSAGE( expression.parse("2.5 * (6.0 + 14.25) / 2.0 - 5.12345") == OK, "Float multiplication-addition-subtraction-division should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 20.18905), + double(expression.execute()) == doctest::Approx(20.18905), "Float multiplication-addition-subtraction-division should return the expected result."); } @@ -129,7 +129,7 @@ TEST_CASE("[Expression] Scientific notation") { expression.parse("2.e5") == OK, "The expression should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 200'000), + double(expression.execute()) == doctest::Approx(200'000), "The expression should return the expected result."); // The middle "e" is ignored here. @@ -137,14 +137,14 @@ TEST_CASE("[Expression] Scientific notation") { expression.parse("2e5") == OK, "The expression should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 2e5), + double(expression.execute()) == doctest::Approx(2e5), "The expression should return the expected result."); CHECK_MESSAGE( expression.parse("2e.5") == OK, "The expression should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 2), + double(expression.execute()) == doctest::Approx(2), "The expression should return the expected result."); } @@ -176,7 +176,7 @@ TEST_CASE("[Expression] Built-in functions") { expression.parse("snapped(sin(0.5), 0.01)") == OK, "The expression should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 0.48), + double(expression.execute()) == doctest::Approx(0.48), "`snapped(sin(0.5), 0.01)` should return the expected result."); CHECK_MESSAGE( diff --git a/tests/core/math/test_geometry_2d.h b/tests/core/math/test_geometry_2d.h index db4e6e2177..27c9e7f58b 100644 --- a/tests/core/math/test_geometry_2d.h +++ b/tests/core/math/test_geometry_2d.h @@ -64,7 +64,7 @@ TEST_CASE("[Geometry2D] Point in triangle") { // This tests points on the edge of the triangle. They are treated as being outside the triangle. // 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). + // the behavior 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))); } @@ -171,43 +171,43 @@ TEST_CASE("[Geometry2D] Segment intersection with circle") { real_t one = 1.0; CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(0, 0), Vector2(4, 0), Vector2(0, 0), 1.0), one_quarter), + Geometry2D::segment_intersects_circle(Vector2(0, 0), Vector2(4, 0), Vector2(0, 0), 1.0) == doctest::Approx(one_quarter), "Segment from inside to outside of circle should intersect it."); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(4, 0), Vector2(0, 0), Vector2(0, 0), 1.0), three_quarters), + Geometry2D::segment_intersects_circle(Vector2(4, 0), Vector2(0, 0), Vector2(0, 0), 1.0) == doctest::Approx(three_quarters), "Segment from outside to inside of circle should intersect it."); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(-2, 0), Vector2(2, 0), Vector2(0, 0), 1.0), one_quarter), + Geometry2D::segment_intersects_circle(Vector2(-2, 0), Vector2(2, 0), Vector2(0, 0), 1.0) == doctest::Approx(one_quarter), "Segment running through circle should intersect it."); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(-2, 0), Vector2(0, 0), 1.0), one_quarter), + Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(-2, 0), Vector2(0, 0), 1.0) == doctest::Approx(one_quarter), "Segment running through circle should intersect it."); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(0, 0), Vector2(1, 0), Vector2(0, 0), 1.0), one), + Geometry2D::segment_intersects_circle(Vector2(0, 0), Vector2(1, 0), Vector2(0, 0), 1.0) == doctest::Approx(one), "Segment starting inside the circle and ending on the circle should intersect it"); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(0, 0), Vector2(0, 0), 1.0), zero), + Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(0, 0), Vector2(0, 0), 1.0) == doctest::Approx(zero), "Segment starting on the circle and going inwards should intersect it"); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(2, 0), Vector2(0, 0), 1.0), zero), + Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(2, 0), Vector2(0, 0), 1.0) == doctest::Approx(zero), "Segment starting on the circle and going outwards should intersect it"); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(1, 0), Vector2(0, 0), 1.0), one), + Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(1, 0), Vector2(0, 0), 1.0) == doctest::Approx(one), "Segment starting outside the circle and ending on the circle intersect it"); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(-1, 0), Vector2(1, 0), Vector2(0, 0), 2.0), minus_one), + Geometry2D::segment_intersects_circle(Vector2(-1, 0), Vector2(1, 0), Vector2(0, 0), 2.0) == doctest::Approx(minus_one), "Segment completely within the circle should not intersect it"); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(-1, 0), Vector2(0, 0), 2.0), minus_one), + Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(-1, 0), Vector2(0, 0), 2.0) == doctest::Approx(minus_one), "Segment completely within the circle should not intersect it"); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(3, 0), Vector2(0, 0), 1.0), minus_one), + Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(3, 0), Vector2(0, 0), 1.0) == doctest::Approx(minus_one), "Segment completely outside the circle should not intersect it"); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(3, 0), Vector2(2, 0), Vector2(0, 0), 1.0), minus_one), + Geometry2D::segment_intersects_circle(Vector2(3, 0), Vector2(2, 0), Vector2(0, 0), 1.0) == doctest::Approx(minus_one), "Segment completely outside the circle should not intersect it"); } diff --git a/tests/core/math/test_math_funcs.h b/tests/core/math/test_math_funcs.h new file mode 100644 index 0000000000..c468e73b74 --- /dev/null +++ b/tests/core/math/test_math_funcs.h @@ -0,0 +1,556 @@ +/*************************************************************************/ +/* test_math_funcs.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 TEST_MATH_FUNCS_H +#define TEST_MATH_FUNCS_H + +#include "tests/test_macros.h" + +namespace TestMath { + +TEST_CASE("[Math] C++ macros") { + CHECK(MIN(-2, 2) == -2); + CHECK(MIN(600, 2) == 2); + + CHECK(MAX(-2, 2) == 2); + CHECK(MAX(600, 2) == 600); + + CHECK(CLAMP(600, -2, 2) == 2); + CHECK(CLAMP(620, 600, 650) == 620); + // `max` is lower than `min`. + CHECK(CLAMP(620, 600, 50) == 50); + + CHECK(ABS(-5) == 5); + CHECK(ABS(0) == 0); + CHECK(ABS(5) == 5); + + CHECK(SIGN(-5) == -1.0); + CHECK(SIGN(0) == 0.0); + CHECK(SIGN(5) == 1.0); +} + +TEST_CASE("[Math] Power of two functions") { + CHECK(next_power_of_2(0) == 0); + CHECK(next_power_of_2(1) == 1); + CHECK(next_power_of_2(16) == 16); + CHECK(next_power_of_2(17) == 32); + CHECK(next_power_of_2(65535) == 65536); + + CHECK(previous_power_of_2(0) == 0); + CHECK(previous_power_of_2(1) == 1); + CHECK(previous_power_of_2(16) == 16); + CHECK(previous_power_of_2(17) == 16); + CHECK(previous_power_of_2(65535) == 32768); + + CHECK(closest_power_of_2(0) == 0); + CHECK(closest_power_of_2(1) == 1); + CHECK(closest_power_of_2(16) == 16); + CHECK(closest_power_of_2(17) == 16); + CHECK(closest_power_of_2(65535) == 65536); + + CHECK(get_shift_from_power_of_2(0) == -1); + CHECK(get_shift_from_power_of_2(1) == 0); + CHECK(get_shift_from_power_of_2(16) == 4); + CHECK(get_shift_from_power_of_2(17) == -1); + CHECK(get_shift_from_power_of_2(65535) == -1); + + CHECK(nearest_shift(0) == 0); + CHECK(nearest_shift(1) == 1); + CHECK(nearest_shift(16) == 5); + CHECK(nearest_shift(17) == 5); + CHECK(nearest_shift(65535) == 16); +} + +TEST_CASE("[Math] abs") { + // int + CHECK(Math::abs(-1) == 1); + CHECK(Math::abs(0) == 0); + CHECK(Math::abs(1) == 1); + + // double + CHECK(Math::abs(-0.1) == 0.1); + CHECK(Math::abs(0.0) == 0.0); + CHECK(Math::abs(0.1) == 0.1); + + // float + CHECK(Math::abs(-0.1f) == 0.1f); + CHECK(Math::abs(0.0f) == 0.0f); + CHECK(Math::abs(0.1f) == 0.1f); +} + +TEST_CASE("[Math] round/floor/ceil") { + CHECK(Math::round(1.5) == 2.0); + CHECK(Math::round(1.6) == 2.0); + CHECK(Math::round(-1.5) == -2.0); + CHECK(Math::round(-1.1) == -1.0); + + CHECK(Math::floor(1.5) == 1.0); + CHECK(Math::floor(-1.5) == -2.0); + + CHECK(Math::ceil(1.5) == 2.0); + CHECK(Math::ceil(-1.9) == -1.0); +} + +TEST_CASE("[Math] sin/cos/tan") { + CHECK(Math::sin(-0.1) == doctest::Approx(-0.0998334166)); + CHECK(Math::sin(0.1) == doctest::Approx(0.0998334166)); + CHECK(Math::sin(0.5) == doctest::Approx(0.4794255386)); + CHECK(Math::sin(1.0) == doctest::Approx(0.8414709848)); + CHECK(Math::sin(1.5) == doctest::Approx(0.9974949866)); + CHECK(Math::sin(450.0) == doctest::Approx(-0.683283725)); + + CHECK(Math::cos(-0.1) == doctest::Approx(0.99500416530)); + CHECK(Math::cos(0.1) == doctest::Approx(0.9950041653)); + CHECK(Math::cos(0.5) == doctest::Approx(0.8775825619)); + CHECK(Math::cos(1.0) == doctest::Approx(0.5403023059)); + CHECK(Math::cos(1.5) == doctest::Approx(0.0707372017)); + CHECK(Math::cos(450.0) == doctest::Approx(-0.7301529642)); + + CHECK(Math::tan(-0.1) == doctest::Approx(-0.1003346721)); + CHECK(Math::tan(0.1) == doctest::Approx(0.1003346721)); + CHECK(Math::tan(0.5) == doctest::Approx(0.5463024898)); + CHECK(Math::tan(1.0) == doctest::Approx(1.5574077247)); + CHECK(Math::tan(1.5) == doctest::Approx(14.1014199472)); + CHECK(Math::tan(450.0) == doctest::Approx(0.9358090134)); +} + +TEST_CASE("[Math] sinh/cosh/tanh") { + CHECK(Math::sinh(-0.1) == doctest::Approx(-0.10016675)); + CHECK(Math::sinh(0.1) == doctest::Approx(0.10016675)); + CHECK(Math::sinh(0.5) == doctest::Approx(0.5210953055)); + CHECK(Math::sinh(1.0) == doctest::Approx(1.1752011936)); + CHECK(Math::sinh(1.5) == doctest::Approx(2.1292794551)); + + CHECK(Math::cosh(-0.1) == doctest::Approx(1.0050041681)); + CHECK(Math::cosh(0.1) == doctest::Approx(1.0050041681)); + CHECK(Math::cosh(0.5) == doctest::Approx(1.1276259652)); + CHECK(Math::cosh(1.0) == doctest::Approx(1.5430806348)); + CHECK(Math::cosh(1.5) == doctest::Approx(2.3524096152)); + + CHECK(Math::tanh(-0.1) == doctest::Approx(-0.0996679946)); + CHECK(Math::tanh(0.1) == doctest::Approx(0.0996679946)); + CHECK(Math::tanh(0.5) == doctest::Approx(0.4621171573)); + CHECK(Math::tanh(1.0) == doctest::Approx(0.761594156)); + CHECK(Math::tanh(1.5) == doctest::Approx(0.9051482536)); + CHECK(Math::tanh(450.0) == doctest::Approx(1.0)); +} + +TEST_CASE("[Math] asin/acos/atan") { + CHECK(Math::asin(-0.1) == doctest::Approx(-0.1001674212)); + CHECK(Math::asin(0.1) == doctest::Approx(0.1001674212)); + CHECK(Math::asin(0.5) == doctest::Approx(0.5235987756)); + CHECK(Math::asin(1.0) == doctest::Approx(1.5707963268)); + CHECK(Math::is_nan(Math::asin(1.5))); + CHECK(Math::is_nan(Math::asin(450.0))); + + CHECK(Math::acos(-0.1) == doctest::Approx(1.670963748)); + CHECK(Math::acos(0.1) == doctest::Approx(1.4706289056)); + CHECK(Math::acos(0.5) == doctest::Approx(1.0471975512)); + CHECK(Math::acos(1.0) == doctest::Approx(0.0)); + CHECK(Math::is_nan(Math::acos(1.5))); + CHECK(Math::is_nan(Math::acos(450.0))); + + CHECK(Math::atan(-0.1) == doctest::Approx(-0.0996686525)); + CHECK(Math::atan(0.1) == doctest::Approx(0.0996686525)); + CHECK(Math::atan(0.5) == doctest::Approx(0.463647609)); + CHECK(Math::atan(1.0) == doctest::Approx(0.7853981634)); + CHECK(Math::atan(1.5) == doctest::Approx(0.9827937232)); + CHECK(Math::atan(450.0) == doctest::Approx(1.5685741082)); +} + +TEST_CASE("[Math] sinc/sincn/atan2") { + CHECK(Math::sinc(-0.1) == doctest::Approx(0.9983341665)); + CHECK(Math::sinc(0.1) == doctest::Approx(0.9983341665)); + CHECK(Math::sinc(0.5) == doctest::Approx(0.9588510772)); + CHECK(Math::sinc(1.0) == doctest::Approx(0.8414709848)); + CHECK(Math::sinc(1.5) == doctest::Approx(0.6649966577)); + CHECK(Math::sinc(450.0) == doctest::Approx(-0.0015184083)); + + CHECK(Math::sincn(-0.1) == doctest::Approx(0.9836316431)); + CHECK(Math::sincn(0.1) == doctest::Approx(0.9836316431)); + CHECK(Math::sincn(0.5) == doctest::Approx(0.6366197724)); + CHECK(Math::sincn(1.0) == doctest::Approx(0.0)); + CHECK(Math::sincn(1.5) == doctest::Approx(-0.2122065908)); + CHECK(Math::sincn(450.0) == doctest::Approx(0.0)); + + CHECK(Math::atan2(-0.1, 0.5) == doctest::Approx(-0.1973955598)); + CHECK(Math::atan2(0.1, -0.5) == doctest::Approx(2.9441970937)); + CHECK(Math::atan2(0.5, 1.5) == doctest::Approx(0.3217505544)); + CHECK(Math::atan2(1.0, 2.5) == doctest::Approx(0.3805063771)); + CHECK(Math::atan2(1.5, 1.0) == doctest::Approx(0.9827937232)); + CHECK(Math::atan2(450.0, 1.0) == doctest::Approx(1.5685741082)); +} + +TEST_CASE("[Math] pow/log/log2/exp/sqrt") { + CHECK(Math::pow(-0.1, 2.0) == doctest::Approx(0.01)); + CHECK(Math::pow(0.1, 2.5) == doctest::Approx(0.0031622777)); + CHECK(Math::pow(0.5, 0.5) == doctest::Approx(0.7071067812)); + CHECK(Math::pow(1.0, 1.0) == doctest::Approx(1.0)); + CHECK(Math::pow(1.5, -1.0) == doctest::Approx(0.6666666667)); + CHECK(Math::pow(450.0, -2.0) == doctest::Approx(0.0000049383)); + CHECK(Math::pow(450.0, 0.0) == doctest::Approx(1.0)); + + CHECK(Math::is_nan(Math::log(-0.1))); + CHECK(Math::log(0.1) == doctest::Approx(-2.302585093)); + CHECK(Math::log(0.5) == doctest::Approx(-0.6931471806)); + CHECK(Math::log(1.0) == doctest::Approx(0.0)); + CHECK(Math::log(1.5) == doctest::Approx(0.4054651081)); + CHECK(Math::log(450.0) == doctest::Approx(6.1092475828)); + + CHECK(Math::is_nan(Math::log2(-0.1))); + CHECK(Math::log2(0.1) == doctest::Approx(-3.3219280949)); + CHECK(Math::log2(0.5) == doctest::Approx(-1.0)); + CHECK(Math::log2(1.0) == doctest::Approx(0.0)); + CHECK(Math::log2(1.5) == doctest::Approx(0.5849625007)); + CHECK(Math::log2(450.0) == doctest::Approx(8.8137811912)); + + CHECK(Math::exp(-0.1) == doctest::Approx(0.904837418)); + CHECK(Math::exp(0.1) == doctest::Approx(1.1051709181)); + CHECK(Math::exp(0.5) == doctest::Approx(1.6487212707)); + CHECK(Math::exp(1.0) == doctest::Approx(2.7182818285)); + CHECK(Math::exp(1.5) == doctest::Approx(4.4816890703)); + + CHECK(Math::is_nan(Math::sqrt(-0.1))); + CHECK(Math::sqrt(0.1) == doctest::Approx(0.316228)); + CHECK(Math::sqrt(0.5) == doctest::Approx(0.707107)); + CHECK(Math::sqrt(1.0) == doctest::Approx(1.0)); + CHECK(Math::sqrt(1.5) == doctest::Approx(1.224745)); +} + +TEST_CASE("[Math] is_nan/is_inf") { + CHECK(!Math::is_nan(0.0)); + CHECK(Math::is_nan(NAN)); + + CHECK(!Math::is_inf(0.0)); + CHECK(Math::is_inf(INFINITY)); +} + +TEST_CASE("[Math] linear_to_db") { + CHECK(Math::linear_to_db(1.0) == doctest::Approx(0.0)); + CHECK(Math::linear_to_db(20.0) == doctest::Approx(26.0206)); + CHECK(Math::is_inf(Math::linear_to_db(0.0))); + CHECK(Math::is_nan(Math::linear_to_db(-20.0))); +} + +TEST_CASE("[Math] db_to_linear") { + CHECK(Math::db_to_linear(0.0) == doctest::Approx(1.0)); + CHECK(Math::db_to_linear(1.0) == doctest::Approx(1.122018)); + CHECK(Math::db_to_linear(20.0) == doctest::Approx(10.0)); + CHECK(Math::db_to_linear(-20.0) == doctest::Approx(0.1)); +} + +TEST_CASE("[Math] step_decimals") { + CHECK(Math::step_decimals(-0.5) == 1); + CHECK(Math::step_decimals(0) == 0); + CHECK(Math::step_decimals(1) == 0); + CHECK(Math::step_decimals(0.1) == 1); + CHECK(Math::step_decimals(0.01) == 2); + CHECK(Math::step_decimals(0.001) == 3); + CHECK(Math::step_decimals(0.0001) == 4); + CHECK(Math::step_decimals(0.00001) == 5); + CHECK(Math::step_decimals(0.000001) == 6); + CHECK(Math::step_decimals(0.0000001) == 7); + CHECK(Math::step_decimals(0.00000001) == 8); + CHECK(Math::step_decimals(0.000000001) == 9); + // Too many decimals to handle. + CHECK(Math::step_decimals(0.0000000001) == 0); +} + +TEST_CASE("[Math] range_step_decimals") { + CHECK(Math::range_step_decimals(0.000000001) == 9); + // Too many decimals to handle. + CHECK(Math::range_step_decimals(0.0000000001) == 0); + // Should be treated as a step of 0 for use by the editor. + CHECK(Math::range_step_decimals(0.0) == 16); + CHECK(Math::range_step_decimals(-0.5) == 16); +} + +TEST_CASE("[Math] lerp") { + CHECK(Math::lerp(2.0, 5.0, -0.1) == doctest::Approx(1.7)); + CHECK(Math::lerp(2.0, 5.0, 0.0) == doctest::Approx(2.0)); + CHECK(Math::lerp(2.0, 5.0, 0.1) == doctest::Approx(2.3)); + CHECK(Math::lerp(2.0, 5.0, 1.0) == doctest::Approx(5.0)); + CHECK(Math::lerp(2.0, 5.0, 2.0) == doctest::Approx(8.0)); + + CHECK(Math::lerp(-2.0, -5.0, -0.1) == doctest::Approx(-1.7)); + CHECK(Math::lerp(-2.0, -5.0, 0.0) == doctest::Approx(-2.0)); + CHECK(Math::lerp(-2.0, -5.0, 0.1) == doctest::Approx(-2.3)); + CHECK(Math::lerp(-2.0, -5.0, 1.0) == doctest::Approx(-5.0)); + CHECK(Math::lerp(-2.0, -5.0, 2.0) == doctest::Approx(-8.0)); +} + +TEST_CASE("[Math] inverse_lerp") { + CHECK(Math::inverse_lerp(2.0, 5.0, 1.7) == doctest::Approx(-0.1)); + CHECK(Math::inverse_lerp(2.0, 5.0, 2.0) == doctest::Approx(0.0)); + CHECK(Math::inverse_lerp(2.0, 5.0, 2.3) == doctest::Approx(0.1)); + CHECK(Math::inverse_lerp(2.0, 5.0, 5.0) == doctest::Approx(1.0)); + CHECK(Math::inverse_lerp(2.0, 5.0, 8.0) == doctest::Approx(2.0)); + + CHECK(Math::inverse_lerp(-2.0, -5.0, -1.7) == doctest::Approx(-0.1)); + CHECK(Math::inverse_lerp(-2.0, -5.0, -2.0) == doctest::Approx(0.0)); + CHECK(Math::inverse_lerp(-2.0, -5.0, -2.3) == doctest::Approx(0.1)); + CHECK(Math::inverse_lerp(-2.0, -5.0, -5.0) == doctest::Approx(1.0)); + CHECK(Math::inverse_lerp(-2.0, -5.0, -8.0) == doctest::Approx(2.0)); +} + +TEST_CASE("[Math] remap") { + CHECK(Math::remap(50.0, 100.0, 200.0, 0.0, 1000.0) == doctest::Approx(-500.0)); + CHECK(Math::remap(100.0, 100.0, 200.0, 0.0, 1000.0) == doctest::Approx(0.0)); + CHECK(Math::remap(200.0, 100.0, 200.0, 0.0, 1000.0) == doctest::Approx(1000.0)); + CHECK(Math::remap(250.0, 100.0, 200.0, 0.0, 1000.0) == doctest::Approx(1500.0)); + + CHECK(Math::remap(-50.0, -100.0, -200.0, 0.0, 1000.0) == doctest::Approx(-500.0)); + CHECK(Math::remap(-100.0, -100.0, -200.0, 0.0, 1000.0) == doctest::Approx(0.0)); + CHECK(Math::remap(-200.0, -100.0, -200.0, 0.0, 1000.0) == doctest::Approx(1000.0)); + CHECK(Math::remap(-250.0, -100.0, -200.0, 0.0, 1000.0) == doctest::Approx(1500.0)); + + CHECK(Math::remap(-50.0, -100.0, -200.0, 0.0, -1000.0) == doctest::Approx(500.0)); + CHECK(Math::remap(-100.0, -100.0, -200.0, 0.0, -1000.0) == doctest::Approx(0.0)); + CHECK(Math::remap(-200.0, -100.0, -200.0, 0.0, -1000.0) == doctest::Approx(-1000.0)); + CHECK(Math::remap(-250.0, -100.0, -200.0, 0.0, -1000.0) == doctest::Approx(-1500.0)); +} + +TEST_CASE("[Math] lerp_angle") { + // Counter-clockwise rotation. + CHECK(Math::lerp_angle(0.24 * Math_TAU, 0.75 * Math_TAU, 0.5) == doctest::Approx(-0.005 * Math_TAU)); + // Counter-clockwise rotation. + CHECK(Math::lerp_angle(0.25 * Math_TAU, 0.75 * Math_TAU, 0.5) == doctest::Approx(0.0)); + // Clockwise rotation. + CHECK(Math::lerp_angle(0.26 * Math_TAU, 0.75 * Math_TAU, 0.5) == doctest::Approx(0.505 * Math_TAU)); + + CHECK(Math::lerp_angle(-0.25 * Math_TAU, 1.25 * Math_TAU, 0.5) == doctest::Approx(-0.5 * Math_TAU)); + CHECK(Math::lerp_angle(0.72 * Math_TAU, 1.44 * Math_TAU, 0.96) == doctest::Approx(0.4512 * Math_TAU)); + CHECK(Math::lerp_angle(0.72 * Math_TAU, 1.44 * Math_TAU, 1.04) == doctest::Approx(0.4288 * Math_TAU)); + + // Initial and final angles are effectively identical, so the value returned + // should always be the same regardless of the `weight` parameter. + CHECK(Math::lerp_angle(-4 * Math_TAU, 4 * Math_TAU, -1.0) == doctest::Approx(-4.0 * Math_TAU)); + CHECK(Math::lerp_angle(-4 * Math_TAU, 4 * Math_TAU, 0.0) == doctest::Approx(-4.0 * Math_TAU)); + CHECK(Math::lerp_angle(-4 * Math_TAU, 4 * Math_TAU, 0.5) == doctest::Approx(-4.0 * Math_TAU)); + CHECK(Math::lerp_angle(-4 * Math_TAU, 4 * Math_TAU, 1.0) == doctest::Approx(-4.0 * Math_TAU)); + CHECK(Math::lerp_angle(-4 * Math_TAU, 4 * Math_TAU, 500.0) == doctest::Approx(-4.0 * Math_TAU)); +} + +TEST_CASE("[Math] move_toward") { + CHECK(Math::move_toward(2.0, 5.0, -1.0) == doctest::Approx(1.0)); + CHECK(Math::move_toward(2.0, 5.0, 2.5) == doctest::Approx(4.5)); + CHECK(Math::move_toward(2.0, 5.0, 4.0) == doctest::Approx(5.0)); + CHECK(Math::move_toward(-2.0, -5.0, -1.0) == doctest::Approx(-1.0)); + CHECK(Math::move_toward(-2.0, -5.0, 2.5) == doctest::Approx(-4.5)); + CHECK(Math::move_toward(-2.0, -5.0, 4.0) == doctest::Approx(-5.0)); +} + +TEST_CASE("[Math] smoothstep") { + CHECK(Math::smoothstep(0.0, 2.0, -5.0) == doctest::Approx(0.0)); + CHECK(Math::smoothstep(0.0, 2.0, 0.5) == doctest::Approx(0.15625)); + CHECK(Math::smoothstep(0.0, 2.0, 1.0) == doctest::Approx(0.5)); + CHECK(Math::smoothstep(0.0, 2.0, 2.0) == doctest::Approx(1.0)); +} + +TEST_CASE("[Math] ease") { + CHECK(Math::ease(0.1, 1.0) == doctest::Approx(0.1)); + CHECK(Math::ease(0.1, 2.0) == doctest::Approx(0.01)); + CHECK(Math::ease(0.1, 0.5) == doctest::Approx(0.19)); + CHECK(Math::ease(0.1, 0.0) == doctest::Approx(0)); + CHECK(Math::ease(0.1, -0.5) == doctest::Approx(0.2236067977)); + CHECK(Math::ease(0.1, -1.0) == doctest::Approx(0.1)); + CHECK(Math::ease(0.1, -2.0) == doctest::Approx(0.02)); + + CHECK(Math::ease(-1.0, 1.0) == doctest::Approx(0)); + CHECK(Math::ease(-1.0, 2.0) == doctest::Approx(0)); + CHECK(Math::ease(-1.0, 0.5) == doctest::Approx(0)); + CHECK(Math::ease(-1.0, 0.0) == doctest::Approx(0)); + CHECK(Math::ease(-1.0, -0.5) == doctest::Approx(0)); + CHECK(Math::ease(-1.0, -1.0) == doctest::Approx(0)); + CHECK(Math::ease(-1.0, -2.0) == doctest::Approx(0)); +} + +TEST_CASE("[Math] snapped") { + CHECK(Math::snapped(0.5, 0.04) == doctest::Approx(0.52)); + CHECK(Math::snapped(-0.5, 0.04) == doctest::Approx(-0.48)); + CHECK(Math::snapped(0.0, 0.04) == doctest::Approx(0)); + CHECK(Math::snapped(128'000.025, 0.04) == doctest::Approx(128'000.04)); + + CHECK(Math::snapped(0.5, 400) == doctest::Approx(0)); + CHECK(Math::snapped(-0.5, 400) == doctest::Approx(0)); + CHECK(Math::snapped(0.0, 400) == doctest::Approx(0)); + CHECK(Math::snapped(128'000.025, 400) == doctest::Approx(128'000.0)); + + CHECK(Math::snapped(0.5, 0.0) == doctest::Approx(0.5)); + CHECK(Math::snapped(-0.5, 0.0) == doctest::Approx(-0.5)); + CHECK(Math::snapped(0.0, 0.0) == doctest::Approx(0.0)); + CHECK(Math::snapped(128'000.025, 0.0) == doctest::Approx(128'000.0)); + + CHECK(Math::snapped(0.5, -1.0) == doctest::Approx(0)); + CHECK(Math::snapped(-0.5, -1.0) == doctest::Approx(-1.0)); + CHECK(Math::snapped(0.0, -1.0) == doctest::Approx(0)); + CHECK(Math::snapped(128'000.025, -1.0) == doctest::Approx(128'000.0)); +} + +TEST_CASE("[Math] larger_prime") { + CHECK(Math::larger_prime(0) == 5); + CHECK(Math::larger_prime(1) == 5); + CHECK(Math::larger_prime(2) == 5); + CHECK(Math::larger_prime(5) == 13); + CHECK(Math::larger_prime(500) == 769); + CHECK(Math::larger_prime(1'000'000) == 1'572'869); + CHECK(Math::larger_prime(1'000'000'000) == 1'610'612'741); + + // The next prime is larger than `INT32_MAX` and is not present in the built-in prime table. + ERR_PRINT_OFF; + CHECK(Math::larger_prime(2'000'000'000) == 0); + ERR_PRINT_ON; +} + +TEST_CASE("[Math] fmod") { + CHECK(Math::fmod(-2.0, 0.3) == doctest::Approx(-0.2)); + CHECK(Math::fmod(0.0, 0.3) == doctest::Approx(0.0)); + CHECK(Math::fmod(2.0, 0.3) == doctest::Approx(0.2)); + + CHECK(Math::fmod(-2.0, -0.3) == doctest::Approx(-0.2)); + CHECK(Math::fmod(0.0, -0.3) == doctest::Approx(0.0)); + CHECK(Math::fmod(2.0, -0.3) == doctest::Approx(0.2)); +} + +TEST_CASE("[Math] fposmod") { + CHECK(Math::fposmod(-2.0, 0.3) == doctest::Approx(0.1)); + CHECK(Math::fposmod(0.0, 0.3) == doctest::Approx(0.0)); + CHECK(Math::fposmod(2.0, 0.3) == doctest::Approx(0.2)); + + CHECK(Math::fposmod(-2.0, -0.3) == doctest::Approx(-0.2)); + CHECK(Math::fposmod(0.0, -0.3) == doctest::Approx(0.0)); + CHECK(Math::fposmod(2.0, -0.3) == doctest::Approx(-0.1)); +} + +TEST_CASE("[Math] fposmodp") { + CHECK(Math::fposmodp(-2.0, 0.3) == doctest::Approx(0.1)); + CHECK(Math::fposmodp(0.0, 0.3) == doctest::Approx(0.0)); + CHECK(Math::fposmodp(2.0, 0.3) == doctest::Approx(0.2)); + + CHECK(Math::fposmodp(-2.0, -0.3) == doctest::Approx(-0.5)); + CHECK(Math::fposmodp(0.0, -0.3) == doctest::Approx(0.0)); + CHECK(Math::fposmodp(2.0, -0.3) == doctest::Approx(0.2)); +} + +TEST_CASE("[Math] posmod") { + CHECK(Math::posmod(-20, 3) == 1); + CHECK(Math::posmod(0, 3) == 0); + CHECK(Math::posmod(20, 3) == 2); + CHECK(Math::posmod(-20, -3) == -2); + CHECK(Math::posmod(0, -3) == 0); + CHECK(Math::posmod(20, -3) == -1); +} + +TEST_CASE("[Math] wrapi") { + CHECK(Math::wrapi(-30, -20, 160) == 150); + CHECK(Math::wrapi(30, -20, 160) == 30); + CHECK(Math::wrapi(300, -20, 160) == 120); + CHECK(Math::wrapi(300'000'000'000, -20, 160) == 120); +} + +TEST_CASE("[Math] wrapf") { + CHECK(Math::wrapf(-30.0, -20.0, 160.0) == doctest::Approx(150.0)); + CHECK(Math::wrapf(30.0, -2.0, 160.0) == doctest::Approx(30.0)); + CHECK(Math::wrapf(300.0, -20.0, 160.0) == doctest::Approx(120.0)); + CHECK(Math::wrapf(300'000'000'000.0, -20.0, 160.0) == doctest::Approx(120.0)); +} + +TEST_CASE("[Math] fract") { + CHECK(Math::fract(1.0) == doctest::Approx(0.0)); + CHECK(Math::fract(77.8) == doctest::Approx(0.8)); + CHECK(Math::fract(-10.1) == doctest::Approx(0.9)); +} + +TEST_CASE("[Math] pingpong") { + CHECK(Math::pingpong(0.0, 0.0) == doctest::Approx(0.0)); + CHECK(Math::pingpong(1.0, 1.0) == doctest::Approx(1.0)); + CHECK(Math::pingpong(0.5, 2.0) == doctest::Approx(0.5)); + CHECK(Math::pingpong(3.5, 2.0) == doctest::Approx(0.5)); + CHECK(Math::pingpong(11.5, 2.0) == doctest::Approx(0.5)); + CHECK(Math::pingpong(-2.5, 2.0) == doctest::Approx(1.5)); +} + +TEST_CASE("[Math] deg_to_rad/rad_to_deg") { + CHECK(Math::deg_to_rad(180.0) == doctest::Approx(Math_PI)); + CHECK(Math::deg_to_rad(-27.0) == doctest::Approx(-0.471239)); + + CHECK(Math::rad_to_deg(Math_PI) == doctest::Approx(180.0)); + CHECK(Math::rad_to_deg(-1.5) == doctest::Approx(-85.94366927)); +} + +TEST_CASE("[Math] cubic_interpolate") { + CHECK(Math::cubic_interpolate(0.2, 0.8, 0.0, 1.0, 0.0) == doctest::Approx(0.2)); + CHECK(Math::cubic_interpolate(0.2, 0.8, 0.0, 1.0, 0.25) == doctest::Approx(0.33125)); + CHECK(Math::cubic_interpolate(0.2, 0.8, 0.0, 1.0, 0.5) == doctest::Approx(0.5)); + CHECK(Math::cubic_interpolate(0.2, 0.8, 0.0, 1.0, 0.75) == doctest::Approx(0.66875)); + CHECK(Math::cubic_interpolate(0.2, 0.8, 0.0, 1.0, 1.0) == doctest::Approx(0.8)); + + CHECK(Math::cubic_interpolate(20.2, 30.1, -100.0, 32.0, -50.0) == doctest::Approx(-6662732.3)); + CHECK(Math::cubic_interpolate(20.2, 30.1, -100.0, 32.0, -5.0) == doctest::Approx(-9356.3)); + CHECK(Math::cubic_interpolate(20.2, 30.1, -100.0, 32.0, 0.0) == doctest::Approx(20.2)); + CHECK(Math::cubic_interpolate(20.2, 30.1, -100.0, 32.0, 1.0) == doctest::Approx(30.1)); + CHECK(Math::cubic_interpolate(20.2, 30.1, -100.0, 32.0, 4.0) == doctest::Approx(1853.2)); +} + +TEST_CASE("[Math] cubic_interpolate_angle") { + CHECK(Math::cubic_interpolate_angle(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 0.0) == doctest::Approx(Math_PI * (1.0 / 6.0))); + CHECK(Math::cubic_interpolate_angle(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 0.25) == doctest::Approx(0.973566)); + CHECK(Math::cubic_interpolate_angle(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 0.5) == doctest::Approx(Math_PI / 2.0)); + CHECK(Math::cubic_interpolate_angle(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 0.75) == doctest::Approx(2.16803)); + CHECK(Math::cubic_interpolate_angle(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 1.0) == doctest::Approx(Math_PI * (5.0 / 6.0))); +} + +TEST_CASE("[Math] cubic_interpolate_in_time") { + CHECK(Math::cubic_interpolate_in_time(0.2, 0.8, 0.0, 1.0, 0.0, 0.5, 0.0, 1.0) == doctest::Approx(0.0)); + CHECK(Math::cubic_interpolate_in_time(0.2, 0.8, 0.0, 1.0, 0.25, 0.5, 0.0, 1.0) == doctest::Approx(0.1625)); + CHECK(Math::cubic_interpolate_in_time(0.2, 0.8, 0.0, 1.0, 0.5, 0.5, 0.0, 1.0) == doctest::Approx(0.4)); + CHECK(Math::cubic_interpolate_in_time(0.2, 0.8, 0.0, 1.0, 0.75, 0.5, 0.0, 1.0) == doctest::Approx(0.6375)); + CHECK(Math::cubic_interpolate_in_time(0.2, 0.8, 0.0, 1.0, 1.0, 0.5, 0.0, 1.0) == doctest::Approx(0.8)); +} + +TEST_CASE("[Math] cubic_interpolate_angle_in_time") { + CHECK(Math::cubic_interpolate_angle_in_time(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 0.0, 0.5, 0.0, 1.0) == doctest::Approx(0.0)); + CHECK(Math::cubic_interpolate_angle_in_time(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 0.25, 0.5, 0.0, 1.0) == doctest::Approx(0.494964)); + CHECK(Math::cubic_interpolate_angle_in_time(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 0.5, 0.5, 0.0, 1.0) == doctest::Approx(1.27627)); + CHECK(Math::cubic_interpolate_angle_in_time(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 0.75, 0.5, 0.0, 1.0) == doctest::Approx(2.07394)); + CHECK(Math::cubic_interpolate_angle_in_time(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 1.0, 0.5, 0.0, 1.0) == doctest::Approx(Math_PI * (5.0 / 6.0))); +} + +TEST_CASE("[Math] bezier_interpolate") { + CHECK(Math::bezier_interpolate(0.0, 0.2, 0.8, 1.0, 0.0) == doctest::Approx(0.0)); + CHECK(Math::bezier_interpolate(0.0, 0.2, 0.8, 1.0, 0.25) == doctest::Approx(0.2125)); + CHECK(Math::bezier_interpolate(0.0, 0.2, 0.8, 1.0, 0.5) == doctest::Approx(0.5)); + CHECK(Math::bezier_interpolate(0.0, 0.2, 0.8, 1.0, 0.75) == doctest::Approx(0.7875)); + CHECK(Math::bezier_interpolate(0.0, 0.2, 0.8, 1.0, 1.0) == doctest::Approx(1.0)); +} + +} // namespace TestMath + +#endif // TEST_MATH_FUNCS_H diff --git a/tests/core/math/test_quaternion.h b/tests/core/math/test_quaternion.h index d1912cbf42..c3ae322991 100644 --- a/tests/core/math/test_quaternion.h +++ b/tests/core/math/test_quaternion.h @@ -47,9 +47,9 @@ Quaternion quat_euler_yxz_deg(Vector3 angle) { // Generate YXZ (Z-then-X-then-Y) Quaternion using single-axis Euler // constructor and quaternion product, both tested separately. - Quaternion q_y(Vector3(0.0, yaw, 0.0)); - Quaternion q_p(Vector3(pitch, 0.0, 0.0)); - Quaternion q_r(Vector3(0.0, 0.0, roll)); + Quaternion q_y = Quaternion::from_euler(Vector3(0.0, yaw, 0.0)); + Quaternion q_p = Quaternion::from_euler(Vector3(pitch, 0.0, 0.0)); + Quaternion q_r = Quaternion::from_euler(Vector3(0.0, 0.0, roll)); // Roll-Z is followed by Pitch-X, then Yaw-Y. Quaternion q_yxz = q_y * q_p * q_r; @@ -134,21 +134,21 @@ TEST_CASE("[Quaternion] Construct Euler SingleAxis") { double roll = Math::deg_to_rad(10.0); Vector3 euler_y(0.0, yaw, 0.0); - Quaternion q_y(euler_y); + Quaternion q_y = Quaternion::from_euler(euler_y); CHECK(q_y[0] == doctest::Approx(0.0)); CHECK(q_y[1] == doctest::Approx(0.382684)); CHECK(q_y[2] == doctest::Approx(0.0)); CHECK(q_y[3] == doctest::Approx(0.923879)); Vector3 euler_p(pitch, 0.0, 0.0); - Quaternion q_p(euler_p); + Quaternion q_p = Quaternion::from_euler(euler_p); CHECK(q_p[0] == doctest::Approx(0.258819)); CHECK(q_p[1] == doctest::Approx(0.0)); CHECK(q_p[2] == doctest::Approx(0.0)); CHECK(q_p[3] == doctest::Approx(0.965926)); Vector3 euler_r(0.0, 0.0, roll); - Quaternion q_r(euler_r); + Quaternion q_r = Quaternion::from_euler(euler_r); CHECK(q_r[0] == doctest::Approx(0.0)); CHECK(q_r[1] == doctest::Approx(0.0)); CHECK(q_r[2] == doctest::Approx(0.0871558)); @@ -163,27 +163,27 @@ TEST_CASE("[Quaternion] Construct Euler YXZ dynamic axes") { // Generate YXZ comparison data (Z-then-X-then-Y) using single-axis Euler // constructor and quaternion product, both tested separately. Vector3 euler_y(0.0, yaw, 0.0); - Quaternion q_y(euler_y); + Quaternion q_y = Quaternion::from_euler(euler_y); Vector3 euler_p(pitch, 0.0, 0.0); - Quaternion q_p(euler_p); + Quaternion q_p = Quaternion::from_euler(euler_p); Vector3 euler_r(0.0, 0.0, roll); - Quaternion q_r(euler_r); + Quaternion q_r = Quaternion::from_euler(euler_r); - // Roll-Z is followed by Pitch-X. - Quaternion check_xz = q_p * q_r; - // Then Yaw-Y follows both. - Quaternion check_yxz = q_y * check_xz; + // Instrinsically, Yaw-Y then Pitch-X then Roll-Z. + // Extrinsically, Roll-Z is followed by Pitch-X, then Yaw-Y. + Quaternion check_yxz = q_y * q_p * q_r; // Test construction from YXZ Euler angles. Vector3 euler_yxz(pitch, yaw, roll); - Quaternion q(euler_yxz); + Quaternion q = Quaternion::from_euler(euler_yxz); CHECK(q[0] == doctest::Approx(check_yxz[0])); CHECK(q[1] == doctest::Approx(check_yxz[1])); CHECK(q[2] == doctest::Approx(check_yxz[2])); CHECK(q[3] == doctest::Approx(check_yxz[3])); - // Sneak in a test of is_equal_approx. CHECK(q.is_equal_approx(check_yxz)); + CHECK(q.get_euler().is_equal_approx(euler_yxz)); + CHECK(check_yxz.get_euler().is_equal_approx(euler_yxz)); } TEST_CASE("[Quaternion] Construct Basis Euler") { @@ -191,8 +191,8 @@ TEST_CASE("[Quaternion] Construct Basis Euler") { double pitch = Math::deg_to_rad(30.0); double roll = Math::deg_to_rad(10.0); Vector3 euler_yxz(pitch, yaw, roll); - Quaternion q_yxz(euler_yxz); - Basis basis_axes(euler_yxz); + Quaternion q_yxz = Quaternion::from_euler(euler_yxz); + Basis basis_axes = Basis::from_euler(euler_yxz); Quaternion q(basis_axes); CHECK(q.is_equal_approx(q_yxz)); } @@ -209,7 +209,7 @@ TEST_CASE("[Quaternion] Construct Basis Axes") { // Quaternion from local calculation. Quaternion q_local = quat_euler_yxz_deg(Vector3(31.41, -49.16, 12.34)); // Quaternion from Euler angles constructor. - Quaternion q_euler(euler_yxz); + Quaternion q_euler = Quaternion::from_euler(euler_yxz); CHECK(q_calc.is_equal_approx(q_local)); CHECK(q_local.is_equal_approx(q_euler)); @@ -218,7 +218,7 @@ TEST_CASE("[Quaternion] Construct Basis Axes") { // This is by design, but may be subject to change. // Workaround by constructing Basis from Euler angles. // basis_axes = Basis(i_unit, j_unit, k_unit); - Basis basis_axes(euler_yxz); + Basis basis_axes = Basis::from_euler(euler_yxz); Quaternion q(basis_axes); CHECK(basis_axes.get_column(0).is_equal_approx(i_unit)); @@ -235,6 +235,23 @@ TEST_CASE("[Quaternion] Construct Basis Axes") { CHECK(q[3] == doctest::Approx(0.8582598)); } +TEST_CASE("[Quaternion] Get Euler Orders") { + double x = Math::deg_to_rad(30.0); + double y = Math::deg_to_rad(45.0); + double z = Math::deg_to_rad(10.0); + Vector3 euler(x, y, z); + for (int i = 0; i < 6; i++) { + EulerOrder order = (EulerOrder)i; + Basis basis = Basis::from_euler(euler, order); + Quaternion q = Quaternion(basis); + Vector3 check = q.get_euler(order); + CHECK_MESSAGE(check.is_equal_approx(euler), + "Quaternion get_euler method should return the original angles."); + CHECK_MESSAGE(check.is_equal_approx(basis.get_euler(order)), + "Quaternion get_euler method should behave the same as Basis get_euler."); + } +} + TEST_CASE("[Quaternion] Product (book)") { // Example from "Quaternions and Rotation Sequences" by Jack Kuipers, p. 108. Quaternion p(1.0, -2.0, 1.0, 3.0); @@ -253,21 +270,21 @@ TEST_CASE("[Quaternion] Product") { double roll = Math::deg_to_rad(10.0); Vector3 euler_y(0.0, yaw, 0.0); - Quaternion q_y(euler_y); + Quaternion q_y = Quaternion::from_euler(euler_y); CHECK(q_y[0] == doctest::Approx(0.0)); CHECK(q_y[1] == doctest::Approx(0.382684)); CHECK(q_y[2] == doctest::Approx(0.0)); CHECK(q_y[3] == doctest::Approx(0.923879)); Vector3 euler_p(pitch, 0.0, 0.0); - Quaternion q_p(euler_p); + Quaternion q_p = Quaternion::from_euler(euler_p); CHECK(q_p[0] == doctest::Approx(0.258819)); CHECK(q_p[1] == doctest::Approx(0.0)); CHECK(q_p[2] == doctest::Approx(0.0)); CHECK(q_p[3] == doctest::Approx(0.965926)); Vector3 euler_r(0.0, 0.0, roll); - Quaternion q_r(euler_r); + Quaternion q_r = Quaternion::from_euler(euler_r); CHECK(q_r[0] == doctest::Approx(0.0)); CHECK(q_r[1] == doctest::Approx(0.0)); CHECK(q_r[2] == doctest::Approx(0.0871558)); @@ -334,7 +351,7 @@ TEST_CASE("[Quaternion] xform unit vectors") { TEST_CASE("[Quaternion] xform vector") { // Arbitrary quaternion rotates an arbitrary vector. Vector3 euler_yzx(Math::deg_to_rad(31.41), Math::deg_to_rad(-49.16), Math::deg_to_rad(12.34)); - Basis basis_axes(euler_yzx); + Basis basis_axes = Basis::from_euler(euler_yzx); Quaternion q(basis_axes); Vector3 v_arb(3.0, 4.0, 5.0); @@ -347,7 +364,7 @@ TEST_CASE("[Quaternion] xform vector") { // Test vector xform for a single combination of Quaternion and Vector. void test_quat_vec_rotate(Vector3 euler_yzx, Vector3 v_in) { - Basis basis_axes(euler_yzx); + Basis basis_axes = Basis::from_euler(euler_yzx); Quaternion q(basis_axes); Vector3 v_rot = q.xform(v_in); diff --git a/tests/core/math/test_rect2.h b/tests/core/math/test_rect2.h index d784875c1c..9984823331 100644 --- a/tests/core/math/test_rect2.h +++ b/tests/core/math/test_rect2.h @@ -102,16 +102,16 @@ TEST_CASE("[Rect2] Basic setters") { TEST_CASE("[Rect2] Area getters") { CHECK_MESSAGE( - Math::is_equal_approx(Rect2(0, 100, 1280, 720).get_area(), 921'600), + Rect2(0, 100, 1280, 720).get_area() == doctest::Approx(921'600), "get_area() should return the expected value."); CHECK_MESSAGE( - Math::is_equal_approx(Rect2(0, 100, -1280, -720).get_area(), 921'600), + Rect2(0, 100, -1280, -720).get_area() == doctest::Approx(921'600), "get_area() should return the expected value."); CHECK_MESSAGE( - Math::is_equal_approx(Rect2(0, 100, 1280, -720).get_area(), -921'600), + Rect2(0, 100, 1280, -720).get_area() == doctest::Approx(-921'600), "get_area() should return the expected value."); CHECK_MESSAGE( - Math::is_equal_approx(Rect2(0, 100, -1280, 720).get_area(), -921'600), + Rect2(0, 100, -1280, 720).get_area() == doctest::Approx(-921'600), "get_area() should return the expected value."); CHECK_MESSAGE( Math::is_zero_approx(Rect2(0, 100, 0, 720).get_area()), diff --git a/tests/core/math/test_vector2.h b/tests/core/math/test_vector2.h index a87b9ffc02..8f8fccd717 100644 --- a/tests/core/math/test_vector2.h +++ b/tests/core/math/test_vector2.h @@ -49,16 +49,16 @@ TEST_CASE("[Vector2] Angle methods") { const Vector2 vector_x = Vector2(1, 0); const Vector2 vector_y = Vector2(0, 1); CHECK_MESSAGE( - Math::is_equal_approx(vector_x.angle_to(vector_y), (real_t)Math_TAU / 4), + vector_x.angle_to(vector_y) == doctest::Approx((real_t)Math_TAU / 4), "Vector2 angle_to should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector_y.angle_to(vector_x), (real_t)-Math_TAU / 4), + vector_y.angle_to(vector_x) == doctest::Approx((real_t)-Math_TAU / 4), "Vector2 angle_to should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector_x.angle_to_point(vector_y), (real_t)Math_TAU * 3 / 8), + vector_x.angle_to_point(vector_y) == doctest::Approx((real_t)Math_TAU * 3 / 8), "Vector2 angle_to_point should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector_y.angle_to_point(vector_x), (real_t)-Math_TAU / 8), + vector_y.angle_to_point(vector_x) == doctest::Approx((real_t)-Math_TAU / 8), "Vector2 angle_to_point should work as expected."); } @@ -113,10 +113,10 @@ TEST_CASE("[Vector2] Interpolation methods") { Vector2(4, 6).slerp(Vector2(8, 10), 0.5).is_equal_approx(Vector2(5.9076470794008017626, 8.07918879020090480697)), "Vector2 slerp should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.slerp(vector2, 0.5).length(), (real_t)4.31959610746631919), + vector1.slerp(vector2, 0.5).length() == doctest::Approx((real_t)4.31959610746631919), "Vector2 slerp with different length input should return a vector with an interpolated length."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.angle_to(vector1.slerp(vector2, 0.5)) * 2, vector1.angle_to(vector2)), + vector1.angle_to(vector1.slerp(vector2, 0.5)) * 2 == doctest::Approx(vector1.angle_to(vector2)), "Vector2 slerp with different length input should return a vector with an interpolated angle."); CHECK_MESSAGE( vector1.cubic_interpolate(vector2, Vector2(), Vector2(7, 7), 0.5) == Vector2(2.375, 3.5), @@ -136,19 +136,19 @@ TEST_CASE("[Vector2] Length methods") { vector1.length_squared() == 200, "Vector2 length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.length(), 10 * (real_t)Math_SQRT2), + vector1.length() == doctest::Approx(10 * (real_t)Math_SQRT2), "Vector2 length should work as expected."); CHECK_MESSAGE( vector2.length_squared() == 1300, "Vector2 length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector2.length(), (real_t)36.05551275463989293119), + vector2.length() == doctest::Approx((real_t)36.05551275463989293119), "Vector2 length should work as expected."); CHECK_MESSAGE( vector1.distance_squared_to(vector2) == 500, "Vector2 distance_squared_to should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.distance_to(vector2), (real_t)22.36067977499789696409), + vector1.distance_to(vector2) == doctest::Approx((real_t)22.36067977499789696409), "Vector2 distance_to should work as expected."); } @@ -294,7 +294,7 @@ TEST_CASE("[Vector2] Operators") { TEST_CASE("[Vector2] Other methods") { const Vector2 vector = Vector2(1.2, 3.4); CHECK_MESSAGE( - Math::is_equal_approx(vector.aspect(), (real_t)1.2 / (real_t)3.4), + vector.aspect() == doctest::Approx((real_t)1.2 / (real_t)3.4), "Vector2 aspect should work as expected."); CHECK_MESSAGE( @@ -382,13 +382,13 @@ TEST_CASE("[Vector2] Plane methods") { ERR_PRINT_OFF; CHECK_MESSAGE( vector.bounce(vector_non_normal).is_equal_approx(Vector2()), - "Vector2 bounce should return empty Vector2 with non-normalised input."); + "Vector2 bounce should return empty Vector2 with non-normalized input."); CHECK_MESSAGE( vector.reflect(vector_non_normal).is_equal_approx(Vector2()), - "Vector2 reflect should return empty Vector2 with non-normalised input."); + "Vector2 reflect should return empty Vector2 with non-normalized input."); CHECK_MESSAGE( vector.slide(vector_non_normal).is_equal_approx(Vector2()), - "Vector2 slide should return empty Vector2 with non-normalised input."); + "Vector2 slide should return empty Vector2 with non-normalized input."); ERR_PRINT_ON; } @@ -443,10 +443,10 @@ TEST_CASE("[Vector2] Linear algebra methods") { vector_y.cross(vector_x) == -1, "Vector2 cross product of Y and X should give negative 1."); CHECK_MESSAGE( - Math::is_equal_approx(a.cross(b), (real_t)-28.1), + a.cross(b) == doctest::Approx((real_t)-28.1), "Vector2 cross should return expected value."); CHECK_MESSAGE( - Math::is_equal_approx(Vector2(-a.x, a.y).cross(Vector2(b.x, -b.y)), (real_t)-28.1), + Vector2(-a.x, a.y).cross(Vector2(b.x, -b.y)) == doctest::Approx((real_t)-28.1), "Vector2 cross should return expected value."); CHECK_MESSAGE( @@ -459,10 +459,10 @@ TEST_CASE("[Vector2] Linear algebra methods") { (vector_x * 10).dot(vector_x * 10) == 100.0, "Vector2 dot product of same direction vectors should behave as expected."); CHECK_MESSAGE( - Math::is_equal_approx(a.dot(b), (real_t)57.3), + a.dot(b) == doctest::Approx((real_t)57.3), "Vector2 dot should return expected value."); CHECK_MESSAGE( - Math::is_equal_approx(Vector2(-a.x, a.y).dot(Vector2(b.x, -b.y)), (real_t)-57.3), + Vector2(-a.x, a.y).dot(Vector2(b.x, -b.y)) == doctest::Approx((real_t)-57.3), "Vector2 dot should return expected value."); } diff --git a/tests/core/math/test_vector2i.h b/tests/core/math/test_vector2i.h index 49b0632e3c..c7a0dccdcc 100644 --- a/tests/core/math/test_vector2i.h +++ b/tests/core/math/test_vector2i.h @@ -79,13 +79,13 @@ TEST_CASE("[Vector2i] Length methods") { vector1.length_squared() == 200, "Vector2i length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.length(), 10 * Math_SQRT2), + vector1.length() == doctest::Approx(10 * Math_SQRT2), "Vector2i length should work as expected."); CHECK_MESSAGE( vector2.length_squared() == 1300, "Vector2i length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector2.length(), 36.05551275463989293119), + vector2.length() == doctest::Approx(36.05551275463989293119), "Vector2i length should work as expected."); } @@ -127,7 +127,7 @@ TEST_CASE("[Vector2i] Operators") { TEST_CASE("[Vector2i] Other methods") { const Vector2i vector = Vector2i(1, 3); CHECK_MESSAGE( - Math::is_equal_approx(vector.aspect(), (real_t)1.0 / (real_t)3.0), + vector.aspect() == doctest::Approx((real_t)1.0 / (real_t)3.0), "Vector2i aspect should work as expected."); CHECK_MESSAGE( diff --git a/tests/core/math/test_vector3.h b/tests/core/math/test_vector3.h index 4932cd04db..89d73ee6de 100644 --- a/tests/core/math/test_vector3.h +++ b/tests/core/math/test_vector3.h @@ -52,26 +52,26 @@ TEST_CASE("[Vector3] Angle methods") { const Vector3 vector_y = Vector3(0, 1, 0); const Vector3 vector_yz = Vector3(0, 1, 1); CHECK_MESSAGE( - Math::is_equal_approx(vector_x.angle_to(vector_y), (real_t)Math_TAU / 4), + vector_x.angle_to(vector_y) == doctest::Approx((real_t)Math_TAU / 4), "Vector3 angle_to should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector_x.angle_to(vector_yz), (real_t)Math_TAU / 4), + vector_x.angle_to(vector_yz) == doctest::Approx((real_t)Math_TAU / 4), "Vector3 angle_to should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector_yz.angle_to(vector_x), (real_t)Math_TAU / 4), + vector_yz.angle_to(vector_x) == doctest::Approx((real_t)Math_TAU / 4), "Vector3 angle_to should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector_y.angle_to(vector_yz), (real_t)Math_TAU / 8), + vector_y.angle_to(vector_yz) == doctest::Approx((real_t)Math_TAU / 8), "Vector3 angle_to should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector_x.signed_angle_to(vector_y, vector_y), (real_t)Math_TAU / 4), + vector_x.signed_angle_to(vector_y, vector_y) == doctest::Approx((real_t)Math_TAU / 4), "Vector3 signed_angle_to edge case should be positive."); CHECK_MESSAGE( - Math::is_equal_approx(vector_x.signed_angle_to(vector_yz, vector_y), (real_t)Math_TAU / -4), + vector_x.signed_angle_to(vector_yz, vector_y) == doctest::Approx((real_t)Math_TAU / -4), "Vector3 signed_angle_to should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector_yz.signed_angle_to(vector_x, vector_y), (real_t)Math_TAU / 4), + vector_yz.signed_angle_to(vector_x, vector_y) == doctest::Approx((real_t)Math_TAU / 4), "Vector3 signed_angle_to should work as expected."); } @@ -130,10 +130,10 @@ TEST_CASE("[Vector3] Interpolation methods") { Vector3(4, 6, 2).slerp(Vector3(8, 10, 3), 0.5).is_equal_approx(Vector3(5.90194219811429941053, 8.06758688849378394534, 2.558307894718317120038)), "Vector3 slerp should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.slerp(vector2, 0.5).length(), (real_t)6.25831088708303172), + vector1.slerp(vector2, 0.5).length() == doctest::Approx((real_t)6.25831088708303172), "Vector3 slerp with different length input should return a vector with an interpolated length."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.angle_to(vector1.slerp(vector2, 0.5)) * 2, vector1.angle_to(vector2)), + vector1.angle_to(vector1.slerp(vector2, 0.5)) * 2 == doctest::Approx(vector1.angle_to(vector2)), "Vector3 slerp with different length input should return a vector with an interpolated angle."); CHECK_MESSAGE( vector1.cubic_interpolate(vector2, Vector3(), Vector3(7, 7, 7), 0.5) == Vector3(2.375, 3.5, 4.625), @@ -153,19 +153,19 @@ TEST_CASE("[Vector3] Length methods") { vector1.length_squared() == 300, "Vector3 length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.length(), 10 * (real_t)Math_SQRT3), + vector1.length() == doctest::Approx(10 * (real_t)Math_SQRT3), "Vector3 length should work as expected."); CHECK_MESSAGE( vector2.length_squared() == 2900, "Vector3 length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector2.length(), (real_t)53.8516480713450403125), + vector2.length() == doctest::Approx((real_t)53.8516480713450403125), "Vector3 length should work as expected."); CHECK_MESSAGE( vector1.distance_squared_to(vector2) == 1400, "Vector3 distance_squared_to should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.distance_to(vector2), (real_t)37.41657386773941385584), + vector1.distance_to(vector2) == doctest::Approx((real_t)37.41657386773941385584), "Vector3 distance_to should work as expected."); } @@ -389,13 +389,13 @@ TEST_CASE("[Vector3] Plane methods") { ERR_PRINT_OFF; CHECK_MESSAGE( vector.bounce(vector_non_normal).is_equal_approx(Vector3()), - "Vector3 bounce should return empty Vector3 with non-normalised input."); + "Vector3 bounce should return empty Vector3 with non-normalized input."); CHECK_MESSAGE( vector.reflect(vector_non_normal).is_equal_approx(Vector3()), - "Vector3 reflect should return empty Vector3 with non-normalised input."); + "Vector3 reflect should return empty Vector3 with non-normalized input."); CHECK_MESSAGE( vector.slide(vector_non_normal).is_equal_approx(Vector3()), - "Vector3 slide should return empty Vector3 with non-normalised input."); + "Vector3 slide should return empty Vector3 with non-normalized input."); ERR_PRINT_ON; } @@ -473,10 +473,10 @@ TEST_CASE("[Vector3] Linear algebra methods") { (vector_x * 10).dot(vector_x * 10) == 100.0, "Vector3 dot product of same direction vectors should behave as expected."); CHECK_MESSAGE( - Math::is_equal_approx(a.dot(b), (real_t)75.24), + a.dot(b) == doctest::Approx((real_t)75.24), "Vector3 dot should return expected value."); CHECK_MESSAGE( - Math::is_equal_approx(Vector3(-a.x, a.y, -a.z).dot(Vector3(b.x, -b.y, b.z)), (real_t)-75.24), + Vector3(-a.x, a.y, -a.z).dot(Vector3(b.x, -b.y, b.z)) == doctest::Approx((real_t)-75.24), "Vector3 dot should return expected value."); } diff --git a/tests/core/math/test_vector3i.h b/tests/core/math/test_vector3i.h index 2050b222d0..56578f99eb 100644 --- a/tests/core/math/test_vector3i.h +++ b/tests/core/math/test_vector3i.h @@ -82,13 +82,13 @@ TEST_CASE("[Vector3i] Length methods") { vector1.length_squared() == 300, "Vector3i length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.length(), 10 * Math_SQRT3), + vector1.length() == doctest::Approx(10 * Math_SQRT3), "Vector3i length should work as expected."); CHECK_MESSAGE( vector2.length_squared() == 2900, "Vector3i length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector2.length(), 53.8516480713450403125), + vector2.length() == doctest::Approx(53.8516480713450403125), "Vector3i length should work as expected."); } diff --git a/tests/core/math/test_vector4.h b/tests/core/math/test_vector4.h index b31db56f67..6ed85661cb 100644 --- a/tests/core/math/test_vector4.h +++ b/tests/core/math/test_vector4.h @@ -91,19 +91,19 @@ TEST_CASE("[Vector4] Length methods") { vector1.length_squared() == 400, "Vector4 length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.length(), 20), + vector1.length() == doctest::Approx(20), "Vector4 length should work as expected."); CHECK_MESSAGE( vector2.length_squared() == 5400, "Vector4 length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector2.length(), (real_t)73.484692283495), + vector2.length() == doctest::Approx((real_t)73.484692283495), "Vector4 length should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.distance_to(vector2), (real_t)54.772255750517), + vector1.distance_to(vector2) == doctest::Approx((real_t)54.772255750517), "Vector4 distance_to should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.distance_squared_to(vector2), 3000), + vector1.distance_squared_to(vector2) == doctest::Approx(3000), "Vector4 distance_squared_to should work as expected."); } @@ -311,7 +311,7 @@ TEST_CASE("[Vector4] Linear algebra methods") { (vector_x * 10).dot(vector_x * 10) == 100.0, "Vector4 dot product of same direction vectors should behave as expected."); CHECK_MESSAGE( - Math::is_equal_approx((vector1 * 2).dot(vector2 * 4), (real_t)-25.9 * 8), + (vector1 * 2).dot(vector2 * 4) == doctest::Approx((real_t)-25.9 * 8), "Vector4 dot product should work as expected."); } diff --git a/tests/core/math/test_vector4i.h b/tests/core/math/test_vector4i.h index 309162c3f7..30d38607dd 100644 --- a/tests/core/math/test_vector4i.h +++ b/tests/core/math/test_vector4i.h @@ -82,13 +82,13 @@ TEST_CASE("[Vector4i] Length methods") { vector1.length_squared() == 400, "Vector4i length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.length(), 20), + vector1.length() == doctest::Approx(20), "Vector4i length should work as expected."); CHECK_MESSAGE( vector2.length_squared() == 5400, "Vector4i length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector2.length(), 73.4846922835), + vector2.length() == doctest::Approx(73.4846922835), "Vector4i length should work as expected."); } diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h index cd1b421ce8..7e4e3aa9f0 100644 --- a/tests/core/string/test_string.h +++ b/tests/core/string/test_string.h @@ -485,6 +485,7 @@ TEST_CASE("[String] Splitting") { const char *slices_l[3] = { "Mars", "Jupiter", "Saturn,Uranus" }; const char *slices_r[3] = { "Mars,Jupiter", "Saturn", "Uranus" }; + const char *slices_3[4] = { "t", "e", "s", "t" }; l = s.split(",", true, 2); CHECK(l.size() == 3); @@ -498,6 +499,13 @@ TEST_CASE("[String] Splitting") { CHECK(l[i] == slices_r[i]); } + s = "test"; + l = s.split(); + CHECK(l.size() == 4); + for (int i = 0; i < l.size(); i++) { + CHECK(l[i] == slices_3[i]); + } + s = "Mars Jupiter Saturn Uranus"; const char *slices_s[4] = { "Mars", "Jupiter", "Saturn", "Uranus" }; l = s.split_spaces(); |