diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/core/input/test_input_event_key.h | 2 | ||||
-rw-r--r-- | tests/core/math/test_aabb.h | 21 | ||||
-rw-r--r-- | tests/core/math/test_basis.h | 34 | ||||
-rw-r--r-- | tests/core/math/test_plane.h | 23 | ||||
-rw-r--r-- | tests/core/math/test_quaternion.h | 59 | ||||
-rw-r--r-- | tests/core/math/test_rect2.h | 21 | ||||
-rw-r--r-- | tests/core/math/test_transform_2d.h | 34 | ||||
-rw-r--r-- | tests/core/math/test_transform_3d.h | 23 | ||||
-rw-r--r-- | tests/core/math/test_vector2.h | 109 | ||||
-rw-r--r-- | tests/core/math/test_vector2i.h | 16 | ||||
-rw-r--r-- | tests/core/math/test_vector3.h | 126 | ||||
-rw-r--r-- | tests/core/math/test_vector3i.h | 16 | ||||
-rw-r--r-- | tests/core/math/test_vector4.h | 94 | ||||
-rw-r--r-- | tests/core/math/test_vector4i.h | 16 | ||||
-rw-r--r-- | tests/core/object/test_class_db.h | 4 | ||||
-rw-r--r-- | tests/core/string/test_string.h | 38 | ||||
-rw-r--r-- | tests/core/templates/test_command_queue.h | 4 | ||||
-rw-r--r-- | tests/scene/test_audio_stream_wav.h | 2 | ||||
-rw-r--r-- | tests/scene/test_bit_map.h | 14 | ||||
-rw-r--r-- | tests/scene/test_text_edit.h | 1101 |
20 files changed, 1483 insertions, 274 deletions
diff --git a/tests/core/input/test_input_event_key.h b/tests/core/input/test_input_event_key.h index 4c9cd2002c..ef0a656b18 100644 --- a/tests/core/input/test_input_event_key.h +++ b/tests/core/input/test_input_event_key.h @@ -118,7 +118,7 @@ TEST_CASE("[InputEventKey] Key correctly converts itself to text") { InputEventKey none_key2; - // Key is None without modifers with a physical key. + // Key is None without modifiers with a physical key. none_key2.set_keycode(Key::NONE); none_key2.set_physical_keycode(Key::ENTER); diff --git a/tests/core/math/test_aabb.h b/tests/core/math/test_aabb.h index d5f54a139e..ebaf441abf 100644 --- a/tests/core/math/test_aabb.h +++ b/tests/core/math/test_aabb.h @@ -389,6 +389,27 @@ TEST_CASE("[AABB] Expanding") { aabb.expand(Vector3(-20, 0, 0)).is_equal_approx(AABB(Vector3(-20, 0, -2.5), Vector3(22.5, 7, 6))), "expand() with non-contained point should return the expected AABB."); } + +TEST_CASE("[AABB] Finite number checks") { + const Vector3 x(0, 1, 2); + const Vector3 infinite(NAN, NAN, NAN); + + CHECK_MESSAGE( + AABB(x, x).is_finite(), + "AABB with all components finite should be finite"); + + CHECK_FALSE_MESSAGE( + AABB(infinite, x).is_finite(), + "AABB with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + AABB(x, infinite).is_finite(), + "AABB with one component infinite should not be finite."); + + CHECK_FALSE_MESSAGE( + AABB(infinite, infinite).is_finite(), + "AABB with two components infinite should not be finite."); +} + } // namespace TestAABB #endif // TEST_AABB_H diff --git a/tests/core/math/test_basis.h b/tests/core/math/test_basis.h index b6493c5726..a65020597a 100644 --- a/tests/core/math/test_basis.h +++ b/tests/core/math/test_basis.h @@ -334,6 +334,40 @@ TEST_CASE("[Basis] Set axis angle") { bugNan.get_axis_angle(axis, angle); CHECK(!Math::is_nan(angle)); } + +TEST_CASE("[Basis] Finite number checks") { + const Vector3 x(0, 1, 2); + const Vector3 infinite(NAN, NAN, NAN); + + CHECK_MESSAGE( + Basis(x, x, x).is_finite(), + "Basis with all components finite should be finite"); + + CHECK_FALSE_MESSAGE( + Basis(infinite, x, x).is_finite(), + "Basis with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Basis(x, infinite, x).is_finite(), + "Basis with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Basis(x, x, infinite).is_finite(), + "Basis with one component infinite should not be finite."); + + CHECK_FALSE_MESSAGE( + Basis(infinite, infinite, x).is_finite(), + "Basis with two components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Basis(infinite, x, infinite).is_finite(), + "Basis with two components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Basis(x, infinite, infinite).is_finite(), + "Basis with two components infinite should not be finite."); + + CHECK_FALSE_MESSAGE( + Basis(infinite, infinite, infinite).is_finite(), + "Basis with three components infinite should not be finite."); +} + } // namespace TestBasis #endif // TEST_BASIS_H diff --git a/tests/core/math/test_plane.h b/tests/core/math/test_plane.h index d81a5af1ce..84d9a0ff7d 100644 --- a/tests/core/math/test_plane.h +++ b/tests/core/math/test_plane.h @@ -167,6 +167,29 @@ TEST_CASE("[Plane] Intersection") { vec_out.is_equal_approx(Vector3(1, 1, 1)), "intersects_segment() should modify vec_out to the expected result."); } + +TEST_CASE("[Plane] Finite number checks") { + const Vector3 x(0, 1, 2); + const Vector3 infinite_vec(NAN, NAN, NAN); + const real_t y = 0; + const real_t infinite_y = NAN; + + CHECK_MESSAGE( + Plane(x, y).is_finite(), + "Plane with all components finite should be finite"); + + CHECK_FALSE_MESSAGE( + Plane(x, infinite_y).is_finite(), + "Plane with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Plane(infinite_vec, y).is_finite(), + "Plane with one component infinite should not be finite."); + + CHECK_FALSE_MESSAGE( + Plane(infinite_vec, infinite_y).is_finite(), + "Plane with two components infinite should not be finite."); +} + } // namespace TestPlane #endif // TEST_PLANE_H diff --git a/tests/core/math/test_quaternion.h b/tests/core/math/test_quaternion.h index 1b80ffba0b..d1912cbf42 100644 --- a/tests/core/math/test_quaternion.h +++ b/tests/core/math/test_quaternion.h @@ -160,7 +160,7 @@ TEST_CASE("[Quaternion] Construct Euler YXZ dynamic axes") { double pitch = Math::deg_to_rad(30.0); double roll = Math::deg_to_rad(10.0); - // Generate YXZ comparision data (Z-then-X-then-Y) using single-axis Euler + // 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); @@ -384,6 +384,63 @@ TEST_CASE("[Stress][Quaternion] Many vector xforms") { } } +TEST_CASE("[Quaternion] Finite number checks") { + const real_t x = NAN; + + CHECK_MESSAGE( + Quaternion(0, 1, 2, 3).is_finite(), + "Quaternion with all components finite should be finite"); + + CHECK_FALSE_MESSAGE( + Quaternion(x, 1, 2, 3).is_finite(), + "Quaternion with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Quaternion(0, x, 2, 3).is_finite(), + "Quaternion with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Quaternion(0, 1, x, 3).is_finite(), + "Quaternion with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Quaternion(0, 1, 2, x).is_finite(), + "Quaternion with one component infinite should not be finite."); + + CHECK_FALSE_MESSAGE( + Quaternion(x, x, 2, 3).is_finite(), + "Quaternion with two components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Quaternion(x, 1, x, 3).is_finite(), + "Quaternion with two components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Quaternion(x, 1, 2, x).is_finite(), + "Quaternion with two components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Quaternion(0, x, x, 3).is_finite(), + "Quaternion with two components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Quaternion(0, x, 2, x).is_finite(), + "Quaternion with two components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Quaternion(0, 1, x, x).is_finite(), + "Quaternion with two components infinite should not be finite."); + + CHECK_FALSE_MESSAGE( + Quaternion(0, x, x, x).is_finite(), + "Quaternion with three components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Quaternion(x, 1, x, x).is_finite(), + "Quaternion with three components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Quaternion(x, x, 2, x).is_finite(), + "Quaternion with three components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Quaternion(x, x, x, 3).is_finite(), + "Quaternion with three components infinite should not be finite."); + + CHECK_FALSE_MESSAGE( + Quaternion(x, x, x, x).is_finite(), + "Quaternion with four components infinite should not be finite."); +} + } // namespace TestQuaternion #endif // TEST_QUATERNION_H diff --git a/tests/core/math/test_rect2.h b/tests/core/math/test_rect2.h index 6323b214db..d784875c1c 100644 --- a/tests/core/math/test_rect2.h +++ b/tests/core/math/test_rect2.h @@ -300,6 +300,27 @@ TEST_CASE("[Rect2] Merging") { Rect2(0, 100, 1280, 720).merge(Rect2(-4000, -4000, 100, 100)).is_equal_approx(Rect2(-4000, -4000, 5280, 4820)), "merge() with non-enclosed Rect2 should return the expected result."); } + +TEST_CASE("[Rect2] Finite number checks") { + const Vector2 x(0, 1); + const Vector2 infinite(NAN, NAN); + + CHECK_MESSAGE( + Rect2(x, x).is_finite(), + "Rect2 with all components finite should be finite"); + + CHECK_FALSE_MESSAGE( + Rect2(infinite, x).is_finite(), + "Rect2 with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Rect2(x, infinite).is_finite(), + "Rect2 with one component infinite should not be finite."); + + CHECK_FALSE_MESSAGE( + Rect2(infinite, infinite).is_finite(), + "Rect2 with two components infinite should not be finite."); +} + } // namespace TestRect2 #endif // TEST_RECT2_H diff --git a/tests/core/math/test_transform_2d.h b/tests/core/math/test_transform_2d.h index 697bf63fc5..ab51bcd7da 100644 --- a/tests/core/math/test_transform_2d.h +++ b/tests/core/math/test_transform_2d.h @@ -83,6 +83,40 @@ TEST_CASE("[Transform2D] rotation") { CHECK(orig.rotated(phi) == R * orig); CHECK(orig.rotated_local(phi) == orig * R); } + +TEST_CASE("[Transform2D] Finite number checks") { + const Vector2 x(0, 1); + const Vector2 infinite(NAN, NAN); + + CHECK_MESSAGE( + Transform2D(x, x, x).is_finite(), + "Transform2D with all components finite should be finite"); + + CHECK_FALSE_MESSAGE( + Transform2D(infinite, x, x).is_finite(), + "Transform2D with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Transform2D(x, infinite, x).is_finite(), + "Transform2D with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Transform2D(x, x, infinite).is_finite(), + "Transform2D with one component infinite should not be finite."); + + CHECK_FALSE_MESSAGE( + Transform2D(infinite, infinite, x).is_finite(), + "Transform2D with two components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Transform2D(infinite, x, infinite).is_finite(), + "Transform2D with two components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Transform2D(x, infinite, infinite).is_finite(), + "Transform2D with two components infinite should not be finite."); + + CHECK_FALSE_MESSAGE( + Transform2D(infinite, infinite, infinite).is_finite(), + "Transform2D with three components infinite should not be finite."); +} + } // namespace TestTransform2D #endif // TEST_TRANSFORM_2D_H diff --git a/tests/core/math/test_transform_3d.h b/tests/core/math/test_transform_3d.h index da166b43f7..d2730f3577 100644 --- a/tests/core/math/test_transform_3d.h +++ b/tests/core/math/test_transform_3d.h @@ -84,6 +84,29 @@ TEST_CASE("[Transform3D] rotation") { CHECK(orig.rotated(axis, phi) == R * orig); CHECK(orig.rotated_local(axis, phi) == orig * R); } + +TEST_CASE("[Transform3D] Finite number checks") { + const Vector3 y(0, 1, 2); + const Vector3 infinite_vec(NAN, NAN, NAN); + const Basis x(y, y, y); + const Basis infinite_basis(infinite_vec, infinite_vec, infinite_vec); + + CHECK_MESSAGE( + Transform3D(x, y).is_finite(), + "Transform3D with all components finite should be finite"); + + CHECK_FALSE_MESSAGE( + Transform3D(x, infinite_vec).is_finite(), + "Transform3D with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Transform3D(infinite_basis, y).is_finite(), + "Transform3D with one component infinite should not be finite."); + + CHECK_FALSE_MESSAGE( + Transform3D(infinite_basis, infinite_vec).is_finite(), + "Transform3D with two components infinite should not be finite."); +} + } // namespace TestTransform3D #endif // TEST_TRANSFORM_3D_H diff --git a/tests/core/math/test_vector2.h b/tests/core/math/test_vector2.h index 9b7800164a..a87b9ffc02 100644 --- a/tests/core/math/test_vector2.h +++ b/tests/core/math/test_vector2.h @@ -37,6 +37,14 @@ namespace TestVector2 { +TEST_CASE("[Vector2] Constructor methods") { + const Vector2 vector_empty = Vector2(); + const Vector2 vector_zero = Vector2(0.0, 0.0); + CHECK_MESSAGE( + vector_empty == vector_zero, + "Vector2 Constructor with no inputs should return a zero Vector2."); +} + TEST_CASE("[Vector2] Angle methods") { const Vector2 vector_x = Vector2(1, 0); const Vector2 vector_y = Vector2(0, 1); @@ -102,6 +110,9 @@ TEST_CASE("[Vector2] Interpolation methods") { Vector2(1, 1).slerp(Vector2(), 0.5) == Vector2(0.5, 0.5), "Vector2 slerp with one input as zero should behave like a regular lerp."); CHECK_MESSAGE( + 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), "Vector2 slerp with different length input should return a vector with an interpolated length."); CHECK_MESSAGE( @@ -171,6 +182,15 @@ TEST_CASE("[Vector2] Normalization methods") { CHECK_MESSAGE( Vector2(1, 1).normalized().is_equal_approx(Vector2(Math_SQRT12, Math_SQRT12)), "Vector2 normalized should work as expected."); + + Vector2 vector = Vector2(3.2, -5.4); + vector.normalize(); + CHECK_MESSAGE( + vector == Vector2(3.2, -5.4).normalized(), + "Vector2 normalize should convert same way as Vector2 normalized."); + CHECK_MESSAGE( + vector.is_equal_approx(Vector2(0.509802390301732898898, -0.860291533634174266891)), + "Vector2 normalize should work as expected."); } TEST_CASE("[Vector2] Operators") { @@ -276,12 +296,14 @@ TEST_CASE("[Vector2] Other methods") { CHECK_MESSAGE( Math::is_equal_approx(vector.aspect(), (real_t)1.2 / (real_t)3.4), "Vector2 aspect should work as expected."); + CHECK_MESSAGE( vector.direction_to(Vector2()).is_equal_approx(-vector.normalized()), "Vector2 direction_to should work as expected."); CHECK_MESSAGE( Vector2(1, 1).direction_to(Vector2(2, 2)).is_equal_approx(Vector2(Math_SQRT12, Math_SQRT12)), "Vector2 direction_to should work as expected."); + CHECK_MESSAGE( vector.posmod(2).is_equal_approx(Vector2(1.2, 1.4)), "Vector2 posmod should work as expected."); @@ -294,10 +316,21 @@ TEST_CASE("[Vector2] Other methods") { CHECK_MESSAGE( (-vector).posmodv(Vector2(2, 3)).is_equal_approx(Vector2(0.8, 2.6)), "Vector2 posmodv should work as expected."); + + CHECK_MESSAGE( + vector.rotated(Math_TAU).is_equal_approx(Vector2(1.2, 3.4)), + "Vector2 rotated should work as expected."); CHECK_MESSAGE( vector.rotated(Math_TAU / 4).is_equal_approx(Vector2(-3.4, 1.2)), "Vector2 rotated should work as expected."); CHECK_MESSAGE( + vector.rotated(Math_TAU / 3).is_equal_approx(Vector2(-3.544486372867091398996, -0.660769515458673623883)), + "Vector2 rotated should work as expected."); + CHECK_MESSAGE( + vector.rotated(Math_TAU / 2).is_equal_approx(vector.rotated(Math_TAU / -2)), + "Vector2 rotated should work as expected."); + + CHECK_MESSAGE( vector.snapped(Vector2(1, 1)) == Vector2(1, 3), "Vector2 snapped to integers should be the same as rounding."); CHECK_MESSAGE( @@ -306,23 +339,57 @@ TEST_CASE("[Vector2] Other methods") { CHECK_MESSAGE( vector.snapped(Vector2(0.25, 0.25)) == Vector2(1.25, 3.5), "Vector2 snapped to 0.25 should give exact results."); + + CHECK_MESSAGE( + Vector2(1.2, 2.5).is_equal_approx(vector.min(Vector2(3.0, 2.5))), + "Vector2 min should return expected value."); + + CHECK_MESSAGE( + Vector2(5.3, 3.4).is_equal_approx(vector.max(Vector2(5.3, 2.0))), + "Vector2 max should return expected value."); } TEST_CASE("[Vector2] Plane methods") { const Vector2 vector = Vector2(1.2, 3.4); const Vector2 vector_y = Vector2(0, 1); + const Vector2 vector_normal = Vector2(0.95879811270838721622267, 0.2840883296913739899919); + const Vector2 vector_non_normal = Vector2(5.4, 1.6); CHECK_MESSAGE( vector.bounce(vector_y) == Vector2(1.2, -3.4), "Vector2 bounce on a plane with normal of the Y axis should."); CHECK_MESSAGE( + vector.bounce(vector_normal).is_equal_approx(Vector2(-2.85851197982345523329, 2.197477931904161412358)), + "Vector2 bounce with normal should return expected value."); + CHECK_MESSAGE( vector.reflect(vector_y) == Vector2(-1.2, 3.4), "Vector2 reflect on a plane with normal of the Y axis should."); CHECK_MESSAGE( + vector.reflect(vector_normal).is_equal_approx(Vector2(2.85851197982345523329, -2.197477931904161412358)), + "Vector2 reflect with normal should return expected value."); + CHECK_MESSAGE( vector.project(vector_y) == Vector2(0, 3.4), - "Vector2 projected on the X axis should only give the Y component."); + "Vector2 projected on the Y axis should only give the Y component."); + CHECK_MESSAGE( + vector.project(vector_normal).is_equal_approx(Vector2(2.0292559899117276166, 0.60126103404791929382)), + "Vector2 projected on a normal should return expected value."); CHECK_MESSAGE( vector.slide(vector_y) == Vector2(1.2, 0), "Vector2 slide on a plane with normal of the Y axis should set the Y to zero."); + CHECK_MESSAGE( + vector.slide(vector_normal).is_equal_approx(Vector2(-0.8292559899117276166456, 2.798738965952080706179)), + "Vector2 slide with normal should return expected value."); + // There's probably a better way to test these ones? + ERR_PRINT_OFF; + CHECK_MESSAGE( + vector.bounce(vector_non_normal).is_equal_approx(Vector2()), + "Vector2 bounce should return empty Vector2 with non-normalised input."); + CHECK_MESSAGE( + vector.reflect(vector_non_normal).is_equal_approx(Vector2()), + "Vector2 reflect should return empty Vector2 with non-normalised input."); + CHECK_MESSAGE( + vector.slide(vector_non_normal).is_equal_approx(Vector2()), + "Vector2 slide should return empty Vector2 with non-normalised input."); + ERR_PRINT_ON; } TEST_CASE("[Vector2] Rounding methods") { @@ -367,12 +434,20 @@ TEST_CASE("[Vector2] Rounding methods") { TEST_CASE("[Vector2] Linear algebra methods") { const Vector2 vector_x = Vector2(1, 0); const Vector2 vector_y = Vector2(0, 1); + const Vector2 a = Vector2(3.5, 8.5); + const Vector2 b = Vector2(5.2, 4.6); CHECK_MESSAGE( vector_x.cross(vector_y) == 1, "Vector2 cross product of X and Y should give 1."); CHECK_MESSAGE( 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), + "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 cross should return expected value."); CHECK_MESSAGE( vector_x.dot(vector_y) == 0.0, @@ -383,7 +458,39 @@ TEST_CASE("[Vector2] Linear algebra methods") { CHECK_MESSAGE( (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), + "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 dot should return expected value."); +} + +TEST_CASE("[Vector2] Finite number checks") { + const double infinite[] = { NAN, INFINITY, -INFINITY }; + + CHECK_MESSAGE( + Vector2(0, 1).is_finite(), + "Vector2(0, 1) should be finite"); + + for (double x : infinite) { + CHECK_FALSE_MESSAGE( + Vector2(x, 1).is_finite(), + "Vector2 with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Vector2(0, x).is_finite(), + "Vector2 with one component infinite should not be finite."); + } + + for (double x : infinite) { + for (double y : infinite) { + CHECK_FALSE_MESSAGE( + Vector2(x, y).is_finite(), + "Vector2 with two components infinite should not be finite."); + } + } } + } // namespace TestVector2 #endif // TEST_VECTOR2_H diff --git a/tests/core/math/test_vector2i.h b/tests/core/math/test_vector2i.h index 841bb793a4..49b0632e3c 100644 --- a/tests/core/math/test_vector2i.h +++ b/tests/core/math/test_vector2i.h @@ -37,6 +37,14 @@ namespace TestVector2i { +TEST_CASE("[Vector2i] Constructor methods") { + const Vector2i vector_empty = Vector2i(); + const Vector2i vector_zero = Vector2i(0, 0); + CHECK_MESSAGE( + vector_empty == vector_zero, + "Vector2i Constructor with no inputs should return a zero Vector2i."); +} + TEST_CASE("[Vector2i] Axis methods") { Vector2i vector = Vector2i(2, 3); CHECK_MESSAGE( @@ -121,6 +129,14 @@ TEST_CASE("[Vector2i] Other methods") { CHECK_MESSAGE( Math::is_equal_approx(vector.aspect(), (real_t)1.0 / (real_t)3.0), "Vector2i aspect should work as expected."); + + CHECK_MESSAGE( + Vector2i(1, 2) == vector.min(Vector2i(3, 2)), + "Vector2i min should return expected value."); + + CHECK_MESSAGE( + Vector2i(5, 3) == vector.max(Vector2i(5, 2)), + "Vector2i max should return expected value."); } TEST_CASE("[Vector2i] Abs and sign methods") { diff --git a/tests/core/math/test_vector3.h b/tests/core/math/test_vector3.h index 6f99fada2b..4932cd04db 100644 --- a/tests/core/math/test_vector3.h +++ b/tests/core/math/test_vector3.h @@ -39,6 +39,14 @@ namespace TestVector3 { +TEST_CASE("[Vector3] Constructor methods") { + const Vector3 vector_empty = Vector3(); + const Vector3 vector_zero = Vector3(0.0, 0.0, 0.0); + CHECK_MESSAGE( + vector_empty == vector_zero, + "Vector3 Constructor with no inputs should return a zero Vector3."); +} + TEST_CASE("[Vector3] Angle methods") { const Vector3 vector_x = Vector3(1, 0, 0); const Vector3 vector_y = Vector3(0, 1, 0); @@ -76,16 +84,12 @@ TEST_CASE("[Vector3] Axis methods") { vector.min_axis_index() == Vector3::Axis::AXIS_X, "Vector3 min_axis_index should work as expected."); CHECK_MESSAGE( - vector.get_axis(vector.max_axis_index()) == (real_t)5.6, - "Vector3 get_axis should work as expected."); + vector[vector.max_axis_index()] == (real_t)5.6, + "Vector3 array operator should work as expected."); CHECK_MESSAGE( vector[vector.min_axis_index()] == (real_t)1.2, "Vector3 array operator should work as expected."); - vector.set_axis(Vector3::Axis::AXIS_Y, 4.7); - CHECK_MESSAGE( - vector.get_axis(Vector3::Axis::AXIS_Y) == (real_t)4.7, - "Vector3 set_axis should work as expected."); vector[Vector3::Axis::AXIS_Y] = 3.7; CHECK_MESSAGE( vector[Vector3::Axis::AXIS_Y] == (real_t)3.7, @@ -123,6 +127,9 @@ TEST_CASE("[Vector3] Interpolation methods") { Vector3(1, 1, 1).slerp(Vector3(), 0.5) == Vector3(0.5, 0.5, 0.5), "Vector3 slerp with one input as zero should behave like a regular lerp."); CHECK_MESSAGE( + 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), "Vector3 slerp with different length input should return a vector with an interpolated length."); CHECK_MESSAGE( @@ -195,6 +202,15 @@ TEST_CASE("[Vector3] Normalization methods") { CHECK_MESSAGE( Vector3(1, 1, 1).normalized().is_equal_approx(Vector3(Math_SQRT13, Math_SQRT13, Math_SQRT13)), "Vector3 normalized should work as expected."); + + Vector3 vector = Vector3(3.2, -5.4, 6); + vector.normalize(); + CHECK_MESSAGE( + vector == Vector3(3.2, -5.4, 6).normalized(), + "Vector3 normalize should convert same way as Vector3 normalized."); + CHECK_MESSAGE( + vector.is_equal_approx(Vector3(0.368522751763902980457, -0.621882143601586279522, 0.6909801595573180883585)), + "Vector3 normalize should work as expected."); } TEST_CASE("[Vector3] Operators") { @@ -318,10 +334,21 @@ TEST_CASE("[Vector3] Other methods") { CHECK_MESSAGE( (-vector).posmodv(Vector3(2, 3, 4)).is_equal_approx(Vector3(0.8, 2.6, 2.4)), "Vector3 posmodv should work as expected."); + + CHECK_MESSAGE( + vector.rotated(Vector3(0, 1, 0), Math_TAU).is_equal_approx(vector), + "Vector3 rotated should work as expected."); CHECK_MESSAGE( vector.rotated(Vector3(0, 1, 0), Math_TAU / 4).is_equal_approx(Vector3(5.6, 3.4, -1.2)), "Vector3 rotated should work as expected."); CHECK_MESSAGE( + vector.rotated(Vector3(1, 0, 0), Math_TAU / 3).is_equal_approx(Vector3(1.2, -6.54974226119285642, 0.1444863728670914)), + "Vector3 rotated should work as expected."); + CHECK_MESSAGE( + vector.rotated(Vector3(0, 0, 1), Math_TAU / 2).is_equal_approx(vector.rotated(Vector3(0, 0, 1), Math_TAU / -2)), + "Vector3 rotated should work as expected."); + + CHECK_MESSAGE( vector.snapped(Vector3(1, 1, 1)) == Vector3(1, 3, 6), "Vector3 snapped to integers should be the same as rounding."); CHECK_MESSAGE( @@ -332,18 +359,44 @@ TEST_CASE("[Vector3] Other methods") { TEST_CASE("[Vector3] Plane methods") { const Vector3 vector = Vector3(1.2, 3.4, 5.6); const Vector3 vector_y = Vector3(0, 1, 0); + const Vector3 vector_normal = Vector3(0.88763458893247992491, 0.26300284116517923701, 0.37806658417494515320); + const Vector3 vector_non_normal = Vector3(5.4, 1.6, 2.3); CHECK_MESSAGE( vector.bounce(vector_y) == Vector3(1.2, -3.4, 5.6), "Vector3 bounce on a plane with normal of the Y axis should."); CHECK_MESSAGE( + vector.bounce(vector_normal).is_equal_approx(Vector3(-6.0369629829775736287, 1.25571467171034855444, 2.517589840583626047)), + "Vector3 bounce with normal should return expected value."); + CHECK_MESSAGE( vector.reflect(vector_y) == Vector3(-1.2, 3.4, -5.6), "Vector3 reflect on a plane with normal of the Y axis should."); CHECK_MESSAGE( + vector.reflect(vector_normal).is_equal_approx(Vector3(6.0369629829775736287, -1.25571467171034855444, -2.517589840583626047)), + "Vector3 reflect with normal should return expected value."); + CHECK_MESSAGE( vector.project(vector_y) == Vector3(0, 3.4, 0), - "Vector3 projected on the X axis should only give the Y component."); + "Vector3 projected on the Y axis should only give the Y component."); + CHECK_MESSAGE( + vector.project(vector_normal).is_equal_approx(Vector3(3.61848149148878681437, 1.0721426641448257227776, 1.54120507970818697649)), + "Vector3 projected on a normal should return expected value."); CHECK_MESSAGE( vector.slide(vector_y) == Vector3(1.2, 0, 5.6), "Vector3 slide on a plane with normal of the Y axis should set the Y to zero."); + CHECK_MESSAGE( + vector.slide(vector_normal).is_equal_approx(Vector3(-2.41848149148878681437, 2.32785733585517427722237, 4.0587949202918130235)), + "Vector3 slide with normal should return expected value."); + // There's probably a better way to test these ones? + ERR_PRINT_OFF; + CHECK_MESSAGE( + vector.bounce(vector_non_normal).is_equal_approx(Vector3()), + "Vector3 bounce should return empty Vector3 with non-normalised input."); + CHECK_MESSAGE( + vector.reflect(vector_non_normal).is_equal_approx(Vector3()), + "Vector3 reflect should return empty Vector3 with non-normalised input."); + CHECK_MESSAGE( + vector.slide(vector_non_normal).is_equal_approx(Vector3()), + "Vector3 slide should return empty Vector3 with non-normalised input."); + ERR_PRINT_ON; } TEST_CASE("[Vector3] Rounding methods") { @@ -389,6 +442,8 @@ TEST_CASE("[Vector3] Linear algebra methods") { const Vector3 vector_x = Vector3(1, 0, 0); const Vector3 vector_y = Vector3(0, 1, 0); const Vector3 vector_z = Vector3(0, 0, 1); + const Vector3 a = Vector3(3.5, 8.5, 2.3); + const Vector3 b = Vector3(5.2, 4.6, 7.8); CHECK_MESSAGE( vector_x.cross(vector_y) == vector_z, "Vector3 cross product of X and Y should give Z."); @@ -401,6 +456,12 @@ TEST_CASE("[Vector3] Linear algebra methods") { CHECK_MESSAGE( vector_z.cross(vector_x) == vector_y, "Vector3 cross product of Z and X should give Y."); + CHECK_MESSAGE( + a.cross(b).is_equal_approx(Vector3(55.72, -15.34, -28.1)), + "Vector3 cross should return expected value."); + CHECK_MESSAGE( + Vector3(-a.x, a.y, -a.z).cross(Vector3(b.x, -b.y, b.z)).is_equal_approx(Vector3(55.72, 15.34, -28.1)), + "Vector2 cross should return expected value."); CHECK_MESSAGE( vector_x.dot(vector_y) == 0.0, @@ -411,7 +472,58 @@ TEST_CASE("[Vector3] Linear algebra methods") { CHECK_MESSAGE( (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), + "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 dot should return expected value."); +} + +TEST_CASE("[Vector3] Finite number checks") { + const double infinite[] = { NAN, INFINITY, -INFINITY }; + + CHECK_MESSAGE( + Vector3(0, 1, 2).is_finite(), + "Vector3(0, 1, 2) should be finite"); + + for (double x : infinite) { + CHECK_FALSE_MESSAGE( + Vector3(x, 1, 2).is_finite(), + "Vector3 with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Vector3(0, x, 2).is_finite(), + "Vector3 with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Vector3(0, 1, x).is_finite(), + "Vector3 with one component infinite should not be finite."); + } + + for (double x : infinite) { + for (double y : infinite) { + CHECK_FALSE_MESSAGE( + Vector3(x, y, 2).is_finite(), + "Vector3 with two components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Vector3(x, 1, y).is_finite(), + "Vector3 with two components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Vector3(0, x, y).is_finite(), + "Vector3 with two components infinite should not be finite."); + } + } + + for (double x : infinite) { + for (double y : infinite) { + for (double z : infinite) { + CHECK_FALSE_MESSAGE( + Vector3(x, y, z).is_finite(), + "Vector3 with three components infinite should not be finite."); + } + } + } } + } // namespace TestVector3 #endif // TEST_VECTOR3_H diff --git a/tests/core/math/test_vector3i.h b/tests/core/math/test_vector3i.h index b1c6944eba..2050b222d0 100644 --- a/tests/core/math/test_vector3i.h +++ b/tests/core/math/test_vector3i.h @@ -36,6 +36,14 @@ namespace TestVector3i { +TEST_CASE("[Vector3i] Constructor methods") { + const Vector3i vector_empty = Vector3i(); + const Vector3i vector_zero = Vector3i(0, 0, 0); + CHECK_MESSAGE( + vector_empty == vector_zero, + "Vector3i Constructor with no inputs should return a zero Vector3i."); +} + TEST_CASE("[Vector3i] Axis methods") { Vector3i vector = Vector3i(1, 2, 3); CHECK_MESSAGE( @@ -45,16 +53,12 @@ TEST_CASE("[Vector3i] Axis methods") { vector.min_axis_index() == Vector3i::Axis::AXIS_X, "Vector3i min_axis_index should work as expected."); CHECK_MESSAGE( - vector.get_axis(vector.max_axis_index()) == 3, - "Vector3i get_axis should work as expected."); + vector[vector.max_axis_index()] == 3, + "Vector3i array operator should work as expected."); CHECK_MESSAGE( vector[vector.min_axis_index()] == 1, "Vector3i array operator should work as expected."); - vector.set_axis(Vector3i::Axis::AXIS_Y, 4); - CHECK_MESSAGE( - vector.get_axis(Vector3i::Axis::AXIS_Y) == 4, - "Vector3i set_axis should work as expected."); vector[Vector3i::Axis::AXIS_Y] = 5; CHECK_MESSAGE( vector[Vector3i::Axis::AXIS_Y] == 5, diff --git a/tests/core/math/test_vector4.h b/tests/core/math/test_vector4.h index ccf991401b..b31db56f67 100644 --- a/tests/core/math/test_vector4.h +++ b/tests/core/math/test_vector4.h @@ -38,6 +38,14 @@ namespace TestVector4 { +TEST_CASE("[Vector4] Constructor methods") { + const Vector4 vector_empty = Vector4(); + const Vector4 vector_zero = Vector4(0.0, 0.0, 0.0, 0.0); + CHECK_MESSAGE( + vector_empty == vector_zero, + "Vector4 Constructor with no inputs should return a zero Vector4."); +} + TEST_CASE("[Vector4] Axis methods") { Vector4 vector = Vector4(1.2, 3.4, 5.6, -0.9); CHECK_MESSAGE( @@ -47,16 +55,12 @@ TEST_CASE("[Vector4] Axis methods") { vector.min_axis_index() == Vector4::Axis::AXIS_W, "Vector4 min_axis_index should work as expected."); CHECK_MESSAGE( - vector.get_axis(vector.max_axis_index()) == (real_t)5.6, - "Vector4 get_axis should work as expected."); + vector[vector.max_axis_index()] == (real_t)5.6, + "Vector4 array operator should work as expected."); CHECK_MESSAGE( vector[vector.min_axis_index()] == (real_t)-0.9, "Vector4 array operator should work as expected."); - vector.set_axis(Vector4::Axis::AXIS_Y, 4.7); - CHECK_MESSAGE( - vector.get_axis(Vector4::Axis::AXIS_Y) == (real_t)4.7, - "Vector4 set_axis should work as expected."); vector[Vector4::Axis::AXIS_Y] = 3.7; CHECK_MESSAGE( vector[Vector4::Axis::AXIS_Y] == (real_t)3.7, @@ -310,6 +314,84 @@ TEST_CASE("[Vector4] Linear algebra methods") { Math::is_equal_approx((vector1 * 2).dot(vector2 * 4), (real_t)-25.9 * 8), "Vector4 dot product should work as expected."); } + +TEST_CASE("[Vector4] Finite number checks") { + const double infinite[] = { NAN, INFINITY, -INFINITY }; + + CHECK_MESSAGE( + Vector4(0, 1, 2, 3).is_finite(), + "Vector4(0, 1, 2, 3) should be finite"); + + for (double x : infinite) { + CHECK_FALSE_MESSAGE( + Vector4(x, 1, 2, 3).is_finite(), + "Vector4 with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Vector4(0, x, 2, 3).is_finite(), + "Vector4 with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Vector4(0, 1, x, 3).is_finite(), + "Vector4 with one component infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Vector4(0, 1, 2, x).is_finite(), + "Vector4 with one component infinite should not be finite."); + } + + for (double x : infinite) { + for (double y : infinite) { + CHECK_FALSE_MESSAGE( + Vector4(x, y, 2, 3).is_finite(), + "Vector4 with two components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Vector4(x, 1, y, 3).is_finite(), + "Vector4 with two components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Vector4(x, 1, 2, y).is_finite(), + "Vector4 with two components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Vector4(0, x, y, 3).is_finite(), + "Vector4 with two components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Vector4(0, x, 2, y).is_finite(), + "Vector4 with two components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Vector4(0, 1, x, y).is_finite(), + "Vector4 with two components infinite should not be finite."); + } + } + + for (double x : infinite) { + for (double y : infinite) { + for (double z : infinite) { + CHECK_FALSE_MESSAGE( + Vector4(0, x, y, z).is_finite(), + "Vector4 with three components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Vector4(x, 1, y, z).is_finite(), + "Vector4 with three components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Vector4(x, y, 2, z).is_finite(), + "Vector4 with three components infinite should not be finite."); + CHECK_FALSE_MESSAGE( + Vector4(x, y, z, 3).is_finite(), + "Vector4 with three components infinite should not be finite."); + } + } + } + + for (double x : infinite) { + for (double y : infinite) { + for (double z : infinite) { + for (double w : infinite) { + CHECK_FALSE_MESSAGE( + Vector4(x, y, z, w).is_finite(), + "Vector4 with four components infinite should not be finite."); + } + } + } + } +} + } // namespace TestVector4 #endif // TEST_VECTOR4_H diff --git a/tests/core/math/test_vector4i.h b/tests/core/math/test_vector4i.h index ac63001b24..309162c3f7 100644 --- a/tests/core/math/test_vector4i.h +++ b/tests/core/math/test_vector4i.h @@ -36,6 +36,14 @@ namespace TestVector4i { +TEST_CASE("[Vector4i] Constructor methods") { + const Vector4i vector_empty = Vector4i(); + const Vector4i vector_zero = Vector4i(0, 0, 0, 0); + CHECK_MESSAGE( + vector_empty == vector_zero, + "Vector4i Constructor with no inputs should return a zero Vector4i."); +} + TEST_CASE("[Vector4i] Axis methods") { Vector4i vector = Vector4i(1, 2, 3, 4); CHECK_MESSAGE( @@ -45,16 +53,12 @@ TEST_CASE("[Vector4i] Axis methods") { vector.min_axis_index() == Vector4i::Axis::AXIS_X, "Vector4i min_axis_index should work as expected."); CHECK_MESSAGE( - vector.get_axis(vector.max_axis_index()) == 4, - "Vector4i get_axis should work as expected."); + vector[vector.max_axis_index()] == 4, + "Vector4i array operator should work as expected."); CHECK_MESSAGE( vector[vector.min_axis_index()] == 1, "Vector4i array operator should work as expected."); - vector.set_axis(Vector4i::Axis::AXIS_Y, 5); - CHECK_MESSAGE( - vector.get_axis(Vector4i::Axis::AXIS_Y) == 5, - "Vector4i set_axis should work as expected."); vector[Vector4i::Axis::AXIS_Y] = 5; CHECK_MESSAGE( vector[Vector4i::Axis::AXIS_Y] == 5, diff --git a/tests/core/object/test_class_db.h b/tests/core/object/test_class_db.h index 208923edb9..b0375c63b9 100644 --- a/tests/core/object/test_class_db.h +++ b/tests/core/object/test_class_db.h @@ -666,6 +666,10 @@ void add_exposed_classes(Context &r_context) { } else { exposed_class.methods.push_back(method); } + + if (method.is_virtual) { + TEST_COND(String(method.name)[0] != '_', "Virtual method ", String(method.name), " does not start with underscore."); + } } // Add signals diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h index d97da05c04..cd1b421ce8 100644 --- a/tests/core/string/test_string.h +++ b/tests/core/string/test_string.h @@ -411,9 +411,13 @@ TEST_CASE("[String] Number to string") { CHECK(String::num_real(3.141593) == "3.141593"); CHECK(String::num_real(3.141) == "3.141"); // No trailing zeros. #ifdef REAL_T_IS_DOUBLE + CHECK_MESSAGE(String::num_real(123.456789) == "123.456789", "Prints the appropriate amount of digits for real_t = double."); + CHECK_MESSAGE(String::num_real(-123.456789) == "-123.456789", "Prints the appropriate amount of digits for real_t = double."); CHECK_MESSAGE(String::num_real(Math_PI) == "3.14159265358979", "Prints the appropriate amount of digits for real_t = double."); CHECK_MESSAGE(String::num_real(3.1415f) == "3.1414999961853", "Prints more digits of 32-bit float when real_t = double (ones that would be reliable for double) and no trailing zero."); #else + CHECK_MESSAGE(String::num_real(123.456789) == "123.4568", "Prints the appropriate amount of digits for real_t = float."); + CHECK_MESSAGE(String::num_real(-123.456789) == "-123.4568", "Prints the appropriate amount of digits for real_t = float."); CHECK_MESSAGE(String::num_real(Math_PI) == "3.141593", "Prints the appropriate amount of digits for real_t = float."); CHECK_MESSAGE(String::num_real(3.1415f) == "3.1415", "Prints only reliable digits of 32-bit float when real_t = float."); #endif // REAL_T_IS_DOUBLE @@ -740,6 +744,14 @@ TEST_CASE("[String] sprintf") { REQUIRE(error == false); CHECK(output == String("fish 99.990000 frog")); + // Real (infinity) left-padded + format = "fish %11f frog"; + args.clear(); + args.push_back(INFINITY); + output = format.sprintf(args, &error); + REQUIRE(error == false); + CHECK(output == String("fish inf frog")); + // Real right-padded. format = "fish %-11f frog"; args.clear(); @@ -840,6 +852,14 @@ TEST_CASE("[String] sprintf") { REQUIRE(error == false); CHECK(output == String("fish ( 19.990000, 1.000000, -2.050000) frog")); + // Vector left-padded with inf/nan + format = "fish %11v frog"; + args.clear(); + args.push_back(Variant(Vector2(INFINITY, NAN))); + output = format.sprintf(args, &error); + REQUIRE(error == false); + CHECK(output == String("fish ( inf, nan) frog")); + // Vector right-padded. format = "fish %-11v frog"; args.clear(); @@ -1408,20 +1428,22 @@ TEST_CASE("[String] dedent") { } TEST_CASE("[String] Path functions") { - static const char *path[7] = { "C:\\Godot\\project\\test.tscn", "/Godot/project/test.xscn", "../Godot/project/test.scn", "Godot\\test.doc", "C:\\test.", "res://test", "/.test" }; - static const char *base_dir[7] = { "C:\\Godot\\project", "/Godot/project", "../Godot/project", "Godot", "C:\\", "res://", "/" }; - static const char *base_name[7] = { "C:\\Godot\\project\\test", "/Godot/project/test", "../Godot/project/test", "Godot\\test", "C:\\test", "res://test", "/" }; - static const char *ext[7] = { "tscn", "xscn", "scn", "doc", "", "", "test" }; - static const char *file[7] = { "test.tscn", "test.xscn", "test.scn", "test.doc", "test.", "test", ".test" }; - static const bool abs[7] = { true, true, false, false, true, true, true }; - - for (int i = 0; i < 7; i++) { + static const char *path[8] = { "C:\\Godot\\project\\test.tscn", "/Godot/project/test.xscn", "../Godot/project/test.scn", "Godot\\test.doc", "C:\\test.", "res://test", "user://test", "/.test" }; + static const char *base_dir[8] = { "C:\\Godot\\project", "/Godot/project", "../Godot/project", "Godot", "C:\\", "res://", "user://", "/" }; + static const char *base_name[8] = { "C:\\Godot\\project\\test", "/Godot/project/test", "../Godot/project/test", "Godot\\test", "C:\\test", "res://test", "user://test", "/" }; + static const char *ext[8] = { "tscn", "xscn", "scn", "doc", "", "", "", "test" }; + static const char *file[8] = { "test.tscn", "test.xscn", "test.scn", "test.doc", "test.", "test", "test", ".test" }; + static const char *simplified[8] = { "C:/Godot/project/test.tscn", "/Godot/project/test.xscn", "Godot/project/test.scn", "Godot/test.doc", "C:/test.", "res://test", "user://test", "/.test" }; + static const bool abs[8] = { true, true, false, false, true, true, true, true }; + + for (int i = 0; i < 8; i++) { CHECK(String(path[i]).get_base_dir() == base_dir[i]); CHECK(String(path[i]).get_basename() == base_name[i]); 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_relative_path() != abs[i]); + CHECK(String(path[i]).simplify_path() == String(simplified[i])); CHECK(String(path[i]).simplify_path().get_base_dir().path_join(file[i]) == String(path[i]).simplify_path()); } diff --git a/tests/core/templates/test_command_queue.h b/tests/core/templates/test_command_queue.h index 0d016f5d06..db1e436ed9 100644 --- a/tests/core/templates/test_command_queue.h +++ b/tests/core/templates/test_command_queue.h @@ -38,8 +38,6 @@ #include "core/templates/command_queue_mt.h" #include "tests/test_macros.h" -#if !defined(NO_THREADS) - namespace TestCommandQueue { class ThreadWork { @@ -426,6 +424,4 @@ TEST_CASE("[Stress][CommandQueue] Stress test command queue") { } } // namespace TestCommandQueue -#endif // !defined(NO_THREADS) - #endif // TEST_COMMAND_QUEUE_H diff --git a/tests/scene/test_audio_stream_wav.h b/tests/scene/test_audio_stream_wav.h index cf369c115b..4ba431dfc2 100644 --- a/tests/scene/test_audio_stream_wav.h +++ b/tests/scene/test_audio_stream_wav.h @@ -138,7 +138,7 @@ void run_test(String file_name, AudioStreamWAV::Format data_format, bool stereo, CHECK(stream->get_data() == test_data); SUBCASE("Stream length is computed properly") { - CHECK(Math::is_equal_approx(stream->get_length(), wav_count / wav_rate)); + CHECK(Math::is_equal_approx(stream->get_length(), double(wav_count / wav_rate))); } SUBCASE("Stream can be saved as .wav") { diff --git a/tests/scene/test_bit_map.h b/tests/scene/test_bit_map.h index 53afdc38f7..a102f40725 100644 --- a/tests/scene/test_bit_map.h +++ b/tests/scene/test_bit_map.h @@ -76,15 +76,11 @@ TEST_CASE("[BitMap] Create bit map from image alpha") { bit_map.create_from_image_alpha(empty_img); CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 256), "Bitmap should have its old values because bitmap creation from an empty image should fail."); - Ref<Image> wrong_format_img; - wrong_format_img.instantiate(); - wrong_format_img->create(3, 3, false, Image::Format::FORMAT_DXT1); + Ref<Image> wrong_format_img = Image::create_empty(3, 3, false, Image::Format::FORMAT_DXT1); bit_map.create_from_image_alpha(wrong_format_img); CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 256), "Bitmap should have its old values because converting from a compressed image should fail."); - Ref<Image> img; - img.instantiate(); - img->create(3, 3, false, Image::Format::FORMAT_RGBA8); + Ref<Image> img = Image::create_empty(3, 3, false, Image::Format::FORMAT_RGBA8); img->set_pixel(0, 0, Color(0, 0, 0, 0)); img->set_pixel(0, 1, Color(0, 0, 0, 0.09f)); img->set_pixel(0, 2, Color(0, 0, 0, 0.25f)); @@ -183,7 +179,7 @@ TEST_CASE("[BitMap] Get true bit count") { CHECK(bit_map.get_true_bit_count() == 0); bit_map.create(dim); - CHECK_MESSAGE(bit_map.get_true_bit_count() == 0, "Unitialized bit map should have no true bits"); + CHECK_MESSAGE(bit_map.get_true_bit_count() == 0, "Uninitialized bit map should have no true bits"); bit_map.set_bit_rect(Rect2i{ 0, 0, 256, 256 }, true); CHECK(bit_map.get_true_bit_count() == 65536); bit_map.set_bitv(Point2i{ 0, 0 }, false); @@ -196,7 +192,7 @@ TEST_CASE("[BitMap] Get size") { const Size2i dim{ 256, 256 }; BitMap bit_map{}; - CHECK_MESSAGE(bit_map.get_size() == Size2i(0, 0), "Unitialized bit map should have a size of 0x0"); + CHECK_MESSAGE(bit_map.get_size() == Size2i(0, 0), "Uninitialized bit map should have a size of 0x0"); bit_map.create(dim); CHECK(bit_map.get_size() == Size2i(256, 256)); @@ -390,7 +386,7 @@ TEST_CASE("[BitMap] Convert to image") { bit_map.create(dim); img = bit_map.convert_to_image(); CHECK_MESSAGE(img->get_size() == dim, "Image should have the same dimensions as the BitMap"); - CHECK_MESSAGE(img->get_pixel(0, 0).is_equal_approx(Color(0, 0, 0)), "BitMap is intialized to all 0's, so Image should be all black"); + CHECK_MESSAGE(img->get_pixel(0, 0).is_equal_approx(Color(0, 0, 0)), "BitMap is initialized to all 0's, so Image should be all black"); reset_bit_map(bit_map); bit_map.set_bit_rect(Rect2i(0, 0, 128, 128), true); diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h index 225316b293..2ef0a3345f 100644 --- a/tests/scene/test_text_edit.h +++ b/tests/scene/test_text_edit.h @@ -93,10 +93,10 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->undo(); MessageQueue::get_singleton()->flush(); CHECK(text_edit->get_text() == "test text"); - CHECK(text_edit->get_caret_column() == 9); + CHECK(text_edit->get_caret_column() == 0); SIGNAL_CHECK("lines_edited_from", lines_edited_args); - SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); + SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_set"); text_edit->redo(); @@ -104,18 +104,18 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK(text_edit->get_text() == ""); CHECK(text_edit->get_caret_column() == 0); SIGNAL_CHECK("lines_edited_from", lines_edited_args); - SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); + SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_set"); // Cannot undo when not-editable but should still clear. text_edit->undo(); MessageQueue::get_singleton()->flush(); CHECK(text_edit->get_text() == "test text"); - CHECK(text_edit->get_caret_column() == 9); + CHECK(text_edit->get_caret_column() == 0); SIGNAL_CHECK("lines_edited_from", lines_edited_args); - SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); + SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_set"); // Clear. @@ -131,8 +131,8 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK(text_edit->get_text() == ""); CHECK(text_edit->get_caret_column() == 0); SIGNAL_CHECK("text_set", empty_signal_args); - SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_clear_args); + SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_changed"); text_edit->set_editable(true); @@ -252,6 +252,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK(text_edit->get_line(0) == "te"); CHECK(text_edit->has_selection()); CHECK(text_edit->get_selected_text() == "te"); + CHECK(text_edit->get_caret_column() == 2); SIGNAL_CHECK("lines_edited_from", lines_edited_args); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); @@ -263,6 +264,8 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { MessageQueue::get_singleton()->flush(); CHECK(text_edit->get_line(0) == "test text"); CHECK(text_edit->has_selection()); + CHECK(text_edit->get_selected_text() == "test"); + CHECK(text_edit->get_caret_column() == 4); SIGNAL_CHECK("lines_edited_from", lines_edited_args); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); @@ -271,7 +274,8 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->redo(); MessageQueue::get_singleton()->flush(); CHECK(text_edit->get_line(0) == "te"); - CHECK_FALSE(text_edit->has_selection()); // Currently not handled. + CHECK(text_edit->has_selection()); + CHECK(text_edit->get_caret_column() == 2); SIGNAL_CHECK("lines_edited_from", lines_edited_args); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); @@ -425,7 +429,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->undo(); MessageQueue::get_singleton()->flush(); CHECK(text_edit->get_text() == "testing\nswap"); - CHECK_FALSE(text_edit->has_selection()); // Not currently handled. + CHECK(text_edit->has_selection()); SIGNAL_CHECK("lines_edited_from", lines_edited_args); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); @@ -436,7 +440,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->redo(); MessageQueue::get_singleton()->flush(); CHECK(text_edit->get_text() == "new\ntesting\nswap"); - CHECK_FALSE(text_edit->has_selection()); // Not currently handled. + CHECK(text_edit->has_selection()); SIGNAL_CHECK("lines_edited_from", lines_edited_args); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); @@ -448,7 +452,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK(text_edit->has_selection()); CHECK(text_edit->get_selection_from_line() == 0); CHECK(text_edit->get_selection_to_line() == 2); - SIGNAL_CHECK("caret_changed", empty_signal_args); + SIGNAL_CHECK_FALSE("caret_changed"); ((Array)lines_edited_args[0])[0] = 2; ((Array)lines_edited_args[0])[1] = 3; @@ -533,7 +537,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { MessageQueue::get_singleton()->flush(); CHECK(text_edit->get_text() == "temidsting\nswap"); CHECK(text_edit->get_caret_line() == 0); - CHECK(text_edit->get_caret_column() == 10); + CHECK(text_edit->get_caret_column() == 5); CHECK(text_edit->has_selection()); SIGNAL_CHECK("lines_edited_from", lines_edited_args); SIGNAL_CHECK("text_changed", empty_signal_args); @@ -633,17 +637,42 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { } SUBCASE("[TextEdit] select word under caret") { - text_edit->set_text("test test"); + text_edit->set_text("\ntest test\ntest test"); + text_edit->set_caret_column(0); + text_edit->set_caret_line(1); + + text_edit->add_caret(2, 0); + text_edit->add_caret(2, 2); + CHECK(text_edit->get_caret_count() == 3); + + MessageQueue::get_singleton()->flush(); + + SIGNAL_DISCARD("text_set"); + SIGNAL_DISCARD("text_changed"); + SIGNAL_DISCARD("lines_edited_from"); + SIGNAL_DISCARD("caret_changed"); + text_edit->select_word_under_caret(); - CHECK(text_edit->get_selected_text() == "test"); - CHECK(text_edit->has_selection()); - CHECK(text_edit->get_selection_from_line() == 0); - CHECK(text_edit->get_selection_from_column() == 0); - CHECK(text_edit->get_selection_to_line() == 0); - CHECK(text_edit->get_selection_to_column() == 4); - CHECK(text_edit->get_caret_line() == 0); - CHECK(text_edit->get_caret_column() == 4); + CHECK(text_edit->has_selection(0)); + CHECK(text_edit->get_selected_text(0) == "test"); + CHECK(text_edit->get_selection_from_line(0) == 1); + CHECK(text_edit->get_selection_from_column(0) == 0); + CHECK(text_edit->get_selection_to_line(0) == 1); + CHECK(text_edit->get_selection_to_column(0) == 4); + CHECK(text_edit->get_caret_line(0) == 1); + CHECK(text_edit->get_caret_column(0) == 4); + + CHECK(text_edit->has_selection(1)); + CHECK(text_edit->get_selected_text(1) == "test"); + CHECK(text_edit->get_selection_from_line(1) == 2); + CHECK(text_edit->get_selection_from_column(1) == 0); + CHECK(text_edit->get_selection_to_line(1) == 2); + CHECK(text_edit->get_selection_to_column(1) == 4); + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 4); + + CHECK(text_edit->get_caret_count() == 2); text_edit->select_word_under_caret(); CHECK_FALSE(text_edit->has_selection()); @@ -652,27 +681,44 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SEND_GUI_ACTION(text_edit, "ui_text_select_word_under_caret"); CHECK(text_edit->get_viewport()->is_input_handled()); MessageQueue::get_singleton()->flush(); - CHECK(text_edit->has_selection()); - CHECK(text_edit->get_selected_text() == "test"); - CHECK(text_edit->get_selection_from_line() == 0); - CHECK(text_edit->get_selection_from_column() == 0); - CHECK(text_edit->get_selection_to_line() == 0); - CHECK(text_edit->get_selection_to_column() == 4); - CHECK(text_edit->get_caret_line() == 0); - CHECK(text_edit->get_caret_column() == 4); + CHECK(text_edit->has_selection(0)); + CHECK(text_edit->get_selected_text(0) == "test"); + CHECK(text_edit->get_selection_from_line(0) == 1); + CHECK(text_edit->get_selection_from_column(0) == 0); + CHECK(text_edit->get_selection_to_line(0) == 1); + CHECK(text_edit->get_selection_to_column(0) == 4); + CHECK(text_edit->get_caret_line(0) == 1); + CHECK(text_edit->get_caret_column(0) == 4); + + CHECK(text_edit->has_selection(1)); + CHECK(text_edit->get_selected_text(1) == "test"); + CHECK(text_edit->get_selection_from_line(1) == 2); + CHECK(text_edit->get_selection_from_column(1) == 0); + CHECK(text_edit->get_selection_to_line(1) == 2); + CHECK(text_edit->get_selection_to_column(1) == 4); + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 4); + + CHECK(text_edit->get_selected_text() == "test\ntest"); SIGNAL_CHECK("caret_changed", empty_signal_args); text_edit->set_selecting_enabled(false); text_edit->select_word_under_caret(); CHECK_FALSE(text_edit->has_selection()); CHECK(text_edit->get_selected_text() == ""); - CHECK(text_edit->get_caret_line() == 0); - CHECK(text_edit->get_caret_column() == 4); + CHECK(text_edit->get_caret_line(0) == 1); + CHECK(text_edit->get_caret_column(0) == 4); + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 4); SIGNAL_CHECK_FALSE("caret_changed"); text_edit->set_selecting_enabled(true); - text_edit->set_caret_line(0); - text_edit->set_caret_column(5); + text_edit->set_caret_line(1, false, true, 0, 0); + text_edit->set_caret_column(5, false, 0); + + text_edit->set_caret_line(2, false, true, 0, 1); + text_edit->set_caret_column(5, false, 1); + text_edit->select_word_under_caret(); CHECK_FALSE(text_edit->has_selection()); CHECK(text_edit->get_selected_text() == ""); @@ -680,8 +726,10 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->select_word_under_caret(); CHECK_FALSE(text_edit->has_selection()); CHECK(text_edit->get_selected_text() == ""); - CHECK(text_edit->get_caret_line() == 0); - CHECK(text_edit->get_caret_column() == 5); + CHECK(text_edit->get_caret_line(0) == 1); + CHECK(text_edit->get_caret_column(0) == 5); + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 5); SIGNAL_CHECK_FALSE("caret_changed"); } @@ -950,11 +998,15 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->delete_selection(); CHECK(text_edit->get_text() == "this is some text\nfor selection"); + CHECK(text_edit->get_caret_line() == 0); + CHECK(text_edit->get_caret_column() == 8); text_edit->select(0, 8, 0, 4); CHECK(text_edit->has_selection()); SEND_GUI_ACTION(text_edit, "ui_text_backspace"); CHECK(text_edit->get_text() == "thissome text\nfor selection"); + CHECK(text_edit->get_caret_line() == 0); + CHECK(text_edit->get_caret_column() == 4); text_edit->undo(); CHECK(text_edit->has_selection()); @@ -966,7 +1018,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK_FALSE(text_edit->has_selection()); CHECK(text_edit->get_text() == "thissome text\nfor selection"); CHECK(text_edit->get_caret_line() == 0); - CHECK(text_edit->get_caret_column() == 8); + CHECK(text_edit->get_caret_column() == 4); text_edit->undo(); CHECK(text_edit->has_selection()); @@ -991,7 +1043,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK_FALSE(text_edit->has_selection()); CHECK(text_edit->get_text() == "thissome text\nfor selection"); CHECK(text_edit->get_caret_line() == 0); - CHECK(text_edit->get_caret_column() == 8); + CHECK(text_edit->get_caret_column() == 4); text_edit->undo(); CHECK(text_edit->has_selection()); @@ -1176,8 +1228,8 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->undo(); MessageQueue::get_singleton()->flush(); CHECK(text_edit->get_text() == "this is\nsome\n"); - CHECK(text_edit->get_caret_line() == 1); - CHECK(text_edit->get_caret_column() == 0); + CHECK(text_edit->get_caret_line() == 0); + CHECK(text_edit->get_caret_column() == 6); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); @@ -1187,9 +1239,9 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->redo(); MessageQueue::get_singleton()->flush(); CHECK(text_edit->get_text() == "some\n"); - CHECK(text_edit->get_caret_line() == 1); - CHECK(text_edit->get_caret_column() == 0); - SIGNAL_CHECK_FALSE("caret_changed"); + CHECK(text_edit->get_caret_line() == 0); + CHECK(text_edit->get_caret_column() == 4); + SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); @@ -1259,9 +1311,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { lines_edited_args.push_back(args1); SUBCASE("[TextEdit] ui_text_newline_above") { - text_edit->set_text("this is some test text."); + text_edit->set_text("this is some test text.\nthis is some test text."); text_edit->select(0, 0, 0, 4); text_edit->set_caret_column(4); + + text_edit->add_caret(1, 4); + text_edit->select(1, 0, 1, 4, 1); + CHECK(text_edit->get_caret_count() == 2); + MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1269,50 +1326,78 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); - ((Array)lines_edited_args[0])[1] = 1; + // For the second caret. + Array args2; + args2.push_back(0); + args2.push_back(1); + lines_edited_args.push_front(args2); + + ((Array)lines_edited_args[1])[1] = 1; SEND_GUI_ACTION(text_edit, "ui_text_newline_above"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\nthis is some test text."); + CHECK(text_edit->get_text() == "\nthis is some test text.\n\nthis is some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); text_edit->set_caret_line(1); text_edit->set_caret_column(4); - text_edit->select(0, 0, 0, 4); + + text_edit->set_caret_line(3, false, true, 0, 1); + text_edit->set_caret_column(4, false, 1); MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("caret_changed"); text_edit->set_editable(false); SEND_GUI_ACTION(text_edit, "ui_text_newline_above"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\nthis is some test text."); + CHECK(text_edit->get_text() == "\nthis is some test text.\n\nthis is some test text."); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 4); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 3); + CHECK(text_edit->get_caret_column(1) == 4); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); text_edit->set_editable(true); + ((Array)lines_edited_args[0])[0] = 2; + ((Array)lines_edited_args[0])[1] = 3; + SEND_GUI_ACTION(text_edit, "ui_text_newline_above"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\n\nthis is some test text."); + CHECK(text_edit->get_text() == "\n\nthis is some test text.\n\n\nthis is some test text."); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 4); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); } SUBCASE("[TextEdit] ui_text_newline_blank") { - text_edit->set_text("this is some test text."); + text_edit->set_text("this is some test text.\nthis is some test text."); text_edit->select(0, 0, 0, 4); text_edit->set_caret_column(4); + + text_edit->add_caret(1, 4); + text_edit->select(1, 0, 1, 4, 1); + CHECK(text_edit->get_caret_count() == 2); + MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1320,13 +1405,23 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); - ((Array)lines_edited_args[0])[1] = 1; + // For the second caret. + Array args2; + args2.push_back(1); + args2.push_back(2); + lines_edited_args.push_front(args2); + + ((Array)lines_edited_args[1])[1] = 1; SEND_GUI_ACTION(text_edit, "ui_text_newline_blank"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "this is some test text.\n"); + CHECK(text_edit->get_text() == "this is some test text.\n\nthis is some test text.\n"); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 3); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); @@ -1334,10 +1429,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_editable(false); SEND_GUI_ACTION(text_edit, "ui_text_newline_blank"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "this is some test text.\n"); + CHECK(text_edit->get_text() == "this is some test text.\n\nthis is some test text.\n"); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 3); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); @@ -1345,9 +1444,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { } SUBCASE("[TextEdit] ui_text_newline") { - text_edit->set_text("this is some test text."); + text_edit->set_text("this is some test text.\nthis is some test text."); text_edit->select(0, 0, 0, 4); text_edit->set_caret_column(4); + + text_edit->add_caret(1, 4); + text_edit->select(1, 0, 1, 4, 1); + CHECK(text_edit->get_caret_count() == 2); + MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1355,14 +1459,27 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); - lines_edited_args.push_back(lines_edited_args[0].duplicate()); - ((Array)lines_edited_args[1])[1] = 1; + // For the second caret. + Array args2; + args2.push_back(1); + args2.push_back(1); + lines_edited_args.push_front(args2); + lines_edited_args.push_front(args2.duplicate()); + ((Array)lines_edited_args[1])[1] = 2; + + lines_edited_args.push_back(lines_edited_args[2].duplicate()); + ((Array)lines_edited_args[3])[1] = 1; + SEND_GUI_ACTION(text_edit, "ui_text_newline"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\n is some test text."); + CHECK(text_edit->get_text() == "\n is some test text.\n\n is some test text."); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 3); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); @@ -1370,10 +1487,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_editable(false); SEND_GUI_ACTION(text_edit, "ui_text_newline"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\n is some test text."); + CHECK(text_edit->get_text() == "\n is some test text.\n\n is some test text."); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 3); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); @@ -1381,10 +1502,15 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { } SUBCASE("[TextEdit] ui_text_backspace_all_to_left") { - text_edit->set_text("\nthis is some test text."); + text_edit->set_text("\nthis is some test text.\n\nthis is some test text."); text_edit->select(1, 0, 1, 4); text_edit->set_caret_line(1); text_edit->set_caret_column(4); + + text_edit->add_caret(3, 4); + text_edit->select(3, 0, 3, 4, 1); + CHECK(text_edit->get_caret_count() == 2); + MessageQueue::get_singleton()->flush(); Ref<InputEvent> tmpevent = InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::ALT | KeyModifierMask::CMD_OR_CTRL); @@ -1395,34 +1521,50 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); + // For the second caret. + Array args2; + args2.push_back(3); + args2.push_back(3); + lines_edited_args.push_front(args2); + // With selection should be a normal backspace. - ((Array)lines_edited_args[0])[0] = 1; - ((Array)lines_edited_args[0])[1] = 1; + ((Array)lines_edited_args[1])[0] = 1; + ((Array)lines_edited_args[1])[1] = 1; SEND_GUI_ACTION(text_edit, "ui_text_backspace_all_to_left"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\n is some test text."); + CHECK(text_edit->get_text() == "\n is some test text.\n\n is some test text."); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 3); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); - ((Array)lines_edited_args[0])[1] = 0; + ((Array)lines_edited_args[0])[1] = 2; + ((Array)lines_edited_args[1])[1] = 0; // Start of line should also be a normal backspace. SEND_GUI_ACTION(text_edit, "ui_text_backspace_all_to_left"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " is some test text."); + CHECK(text_edit->get_text() == " is some test text.\n is some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); text_edit->set_caret_column(text_edit->get_line(0).length()); + text_edit->set_caret_column(text_edit->get_line(1).length(), false, 1); MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1433,23 +1575,33 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_editable(false); SEND_GUI_ACTION(text_edit, "ui_text_backspace_all_to_left"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " is some test text."); + CHECK(text_edit->get_text() == " is some test text.\n is some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length()); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == text_edit->get_line(1).length()); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); text_edit->set_editable(true); - ((Array)lines_edited_args[0])[0] = 0; + ((Array)lines_edited_args[0])[0] = 1; + ((Array)lines_edited_args[0])[1] = 1; + ((Array)lines_edited_args[1])[0] = 0; SEND_GUI_ACTION(text_edit, "ui_text_backspace_all_to_left"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == ""); + CHECK(text_edit->get_text() == "\n"); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); @@ -1458,10 +1610,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { } SUBCASE("[TextEdit] ui_text_backspace_word") { - text_edit->set_text("\nthis is some test text."); + text_edit->set_text("\nthis is some test text.\n\nthis is some test text."); text_edit->select(1, 0, 1, 4); text_edit->set_caret_line(1); text_edit->set_caret_column(4); + + text_edit->add_caret(3, 4); + text_edit->select(3, 0, 3, 4, 1); + CHECK(text_edit->get_caret_count() == 2); MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1469,30 +1625,45 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); + // For the second caret. + Array args2; + args2.push_back(3); + args2.push_back(3); + lines_edited_args.push_front(args2); + // With selection should be a normal backspace. - ((Array)lines_edited_args[0])[0] = 1; - ((Array)lines_edited_args[0])[1] = 1; + ((Array)lines_edited_args[1])[0] = 1; + ((Array)lines_edited_args[1])[1] = 1; SEND_GUI_ACTION(text_edit, "ui_text_backspace_word"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\n is some test text."); + CHECK(text_edit->get_text() == "\n is some test text.\n\n is some test text."); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 3); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); text_edit->end_complex_operation(); - ((Array)lines_edited_args[0])[1] = 0; + ((Array)lines_edited_args[0])[1] = 2; + ((Array)lines_edited_args[1])[1] = 0; // Start of line should also be a normal backspace. SEND_GUI_ACTION(text_edit, "ui_text_backspace_word"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " is some test text."); + CHECK(text_edit->get_text() == " is some test text.\n is some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); @@ -1500,16 +1671,21 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_editable(false); SEND_GUI_ACTION(text_edit, "ui_text_backspace_word"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " is some test text."); + CHECK(text_edit->get_text() == " is some test text.\n is some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); text_edit->set_editable(true); text_edit->set_caret_column(text_edit->get_line(0).length()); + text_edit->set_caret_column(text_edit->get_line(1).length(), false, 1); MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1517,24 +1693,35 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); - ((Array)lines_edited_args[0])[0] = 0; + ((Array)lines_edited_args[0])[0] = 1; + ((Array)lines_edited_args[0])[1] = 1; + ((Array)lines_edited_args[1])[0] = 0; SEND_GUI_ACTION(text_edit, "ui_text_backspace_word"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " is some test "); + CHECK(text_edit->get_text() == " is some test \n is some test "); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 14); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 14); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); } SUBCASE("[TextEdit] ui_text_backspace") { - text_edit->set_text("\nthis is some test text."); + text_edit->set_text("\nthis is some test text.\n\nthis is some test text."); text_edit->select(1, 0, 1, 4); text_edit->set_caret_line(1); text_edit->set_caret_column(4); + + text_edit->add_caret(3, 4); + text_edit->select(3, 0, 3, 4, 1); + CHECK(text_edit->get_caret_count() == 2); + MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1542,34 +1729,50 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); + // For the second caret. + Array args2; + args2.push_back(3); + args2.push_back(3); + lines_edited_args.push_front(args2); + // With selection should be a normal backspace. - ((Array)lines_edited_args[0])[0] = 1; - ((Array)lines_edited_args[0])[1] = 1; + ((Array)lines_edited_args[1])[0] = 1; + ((Array)lines_edited_args[1])[1] = 1; SEND_GUI_ACTION(text_edit, "ui_text_backspace"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\n is some test text."); + CHECK(text_edit->get_text() == "\n is some test text.\n\n is some test text."); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 3); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); - ((Array)lines_edited_args[0])[1] = 0; + ((Array)lines_edited_args[0])[1] = 2; + ((Array)lines_edited_args[1])[1] = 0; // Start of line should also be a normal backspace. SEND_GUI_ACTION(text_edit, "ui_text_backspace"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " is some test text."); + CHECK(text_edit->get_text() == " is some test text.\n is some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); text_edit->set_caret_column(text_edit->get_line(0).length()); + text_edit->set_caret_column(text_edit->get_line(1).length(), false, 1); MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1580,23 +1783,33 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_editable(false); SEND_GUI_ACTION(text_edit, "ui_text_backspace"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " is some test text."); + CHECK(text_edit->get_text() == " is some test text.\n is some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length()); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == text_edit->get_line(1).length()); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); text_edit->set_editable(true); - ((Array)lines_edited_args[0])[0] = 0; + ((Array)lines_edited_args[0])[0] = 1; + ((Array)lines_edited_args[0])[1] = 1; + ((Array)lines_edited_args[1])[0] = 0; SEND_GUI_ACTION(text_edit, "ui_text_backspace"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " is some test text"); + CHECK(text_edit->get_text() == " is some test text\n is some test text"); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 18); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 18); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); @@ -1605,6 +1818,10 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->select(0, 18, 0, 0); text_edit->set_caret_line(0); text_edit->set_caret_column(0); + + text_edit->select(1, 18, 1, 0, 1); + text_edit->set_caret_line(1, false, true, 0, 1); + text_edit->set_caret_column(0, false, 1); MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1612,12 +1829,12 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); - ((Array)lines_edited_args[0])[0] = 0; - SEND_GUI_ACTION(text_edit, "ui_text_backspace"); - CHECK(text_edit->get_text() == ""); + CHECK(text_edit->get_text() == "\n"); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 0); SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); @@ -1627,10 +1844,15 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { Ref<InputEvent> tmpevent = InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::ALT | KeyModifierMask::CMD_OR_CTRL); InputMap::get_singleton()->action_add_event("ui_text_delete_all_to_right", tmpevent); - text_edit->set_text("this is some test text.\n"); + text_edit->set_text("this is some test text.\nthis is some test text.\n"); text_edit->select(0, 0, 0, 4); text_edit->set_caret_line(0); text_edit->set_caret_column(4); + + text_edit->add_caret(1, 4); + text_edit->select(1, 0, 1, 4, 1); + CHECK(text_edit->get_caret_count() == 2); + MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1638,19 +1860,30 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); + // For the second caret. + Array args2; + args2.push_back(1); + args2.push_back(1); + lines_edited_args.push_front(args2); + // With selection should be a normal delete. SEND_GUI_ACTION(text_edit, "ui_text_delete_all_to_right"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " is some test text.\n"); + CHECK(text_edit->get_text() == " is some test text.\n is some test text.\n"); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); // End of line should not do anything. text_edit->set_caret_column(text_edit->get_line(0).length()); + text_edit->set_caret_column(text_edit->get_line(1).length(), false, 1); MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1660,15 +1893,20 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SEND_GUI_ACTION(text_edit, "ui_text_delete_all_to_right"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " is some test text.\n"); + CHECK(text_edit->get_text() == " is some test text.\n is some test text.\n"); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length()); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == text_edit->get_line(1).length()); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); text_edit->set_caret_column(0); + text_edit->set_caret_column(0, false, 1); MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1679,10 +1917,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_editable(false); SEND_GUI_ACTION(text_edit, "ui_text_delete_all_to_right"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " is some test text.\n"); + CHECK(text_edit->get_text() == " is some test text.\n is some test text.\n"); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); @@ -1690,10 +1932,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SEND_GUI_ACTION(text_edit, "ui_text_delete_all_to_right"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\n"); + CHECK(text_edit->get_text() == "\n\n"); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); @@ -1705,10 +1951,15 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_caret_mid_grapheme_enabled(true); CHECK(text_edit->is_caret_mid_grapheme_enabled()); - text_edit->set_text("this ffi some test text.\n"); + text_edit->set_text("this ffi some test text.\n\nthis ffi some test text.\n"); text_edit->select(0, 0, 0, 4); text_edit->set_caret_line(0); text_edit->set_caret_column(4); + + text_edit->add_caret(2, 4); + text_edit->select(2, 0, 2, 4, 1); + CHECK(text_edit->get_caret_count() == 2); + MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1716,20 +1967,32 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); + // For the second caret. + Array args2; + args2.push_back(2); + args2.push_back(2); + lines_edited_args.push_front(args2); + // With selection should be a normal delete. SEND_GUI_ACTION(text_edit, "ui_text_delete_word"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " ffi some test text.\n"); + CHECK(text_edit->get_text() == " ffi some test text.\n\n ffi some test text.\n"); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); // With selection should be a normal delete. - ((Array)lines_edited_args[0])[0] = 1; + ((Array)lines_edited_args[0])[0] = 3; + ((Array)lines_edited_args[1])[0] = 1; text_edit->set_caret_column(text_edit->get_line(0).length()); + text_edit->set_caret_column(text_edit->get_line(2).length(), false, 1); MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1739,16 +2002,23 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SEND_GUI_ACTION(text_edit, "ui_text_delete_word"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " ffi some test text."); + CHECK(text_edit->get_text() == " ffi some test text.\n ffi some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length()); CHECK_FALSE(text_edit->has_selection()); - SIGNAL_CHECK_FALSE("caret_changed"); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == text_edit->get_line(1).length()); + CHECK_FALSE(text_edit->has_selection(0)); + SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); - ((Array)lines_edited_args[0])[0] = 0; + ((Array)lines_edited_args[1])[0] = 0; + ((Array)lines_edited_args[0])[0] = 1; + ((Array)lines_edited_args[0])[1] = 1; text_edit->set_caret_column(0); + text_edit->set_caret_column(0, false, 1); MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1759,10 +2029,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_editable(false); SEND_GUI_ACTION(text_edit, "ui_text_delete_word"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " ffi some test text."); + CHECK(text_edit->get_text() == " ffi some test text.\n ffi some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); @@ -1770,10 +2044,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SEND_GUI_ACTION(text_edit, "ui_text_delete_word"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " some test text."); + CHECK(text_edit->get_text() == " some test text.\n some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); @@ -1783,10 +2061,15 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_caret_mid_grapheme_enabled(true); CHECK(text_edit->is_caret_mid_grapheme_enabled()); - text_edit->set_text("this ffi some test text.\n"); + text_edit->set_text("this ffi some test text.\nthis ffi some test text."); text_edit->select(0, 0, 0, 4); text_edit->set_caret_line(0); text_edit->set_caret_column(4); + + text_edit->add_caret(1, 4); + text_edit->select(1, 0, 1, 4, 1); + CHECK(text_edit->get_caret_count() == 2); + MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1794,19 +2077,31 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); + // For the second caret. + Array args2; + args2.push_back(1); + args2.push_back(1); + lines_edited_args.push_front(args2); + // With selection should be a normal delete. SEND_GUI_ACTION(text_edit, "ui_text_delete"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " ffi some test text.\n"); + CHECK(text_edit->get_text() == " ffi some test text.\n ffi some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); // With selection should be a normal delete. + lines_edited_args.remove_at(0); ((Array)lines_edited_args[0])[0] = 1; + text_edit->set_caret_column(text_edit->get_line(1).length(), false, 1); text_edit->set_caret_column(text_edit->get_line(0).length()); MessageQueue::get_singleton()->flush(); @@ -1817,16 +2112,25 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SEND_GUI_ACTION(text_edit, "ui_text_delete"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " ffi some test text."); + CHECK(text_edit->get_text() == " ffi some test text. ffi some test text."); CHECK(text_edit->get_caret_line() == 0); - CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length()); - CHECK_FALSE(text_edit->has_selection()); - SIGNAL_CHECK_FALSE("caret_changed"); + CHECK(text_edit->get_caret_column() == 20); + CHECK_FALSE(text_edit->has_selection(0)); + SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); - ((Array)lines_edited_args[0])[0] = 0; + // Caret should be removed due to column preservation. + CHECK(text_edit->get_caret_count() == 1); + + // Lets add it back. text_edit->set_caret_column(0); + text_edit->add_caret(0, 20); + + ((Array)lines_edited_args[0])[0] = 0; + lines_edited_args.push_back(args2); + ((Array)lines_edited_args[1])[0] = 0; + ((Array)lines_edited_args[1])[1] = 0; MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1837,43 +2141,59 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_editable(false); SEND_GUI_ACTION(text_edit, "ui_text_delete"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " ffi some test text."); + CHECK(text_edit->get_text() == " ffi some test text. ffi some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 0); + CHECK(text_edit->get_caret_column(1) == 20); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); text_edit->set_editable(true); + text_edit->start_action(TextEdit::EditAction::ACTION_NONE); + SEND_GUI_ACTION(text_edit, "ui_text_delete"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "ffi some test text."); + CHECK(text_edit->get_text() == "ffi some test text.ffi some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); - SIGNAL_CHECK_FALSE("caret_changed"); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 0); + CHECK(text_edit->get_caret_column(1) == 19); + CHECK_FALSE(text_edit->has_selection(0)); + SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); + text_edit->start_action(TextEdit::EditAction::ACTION_NONE); + SEND_GUI_ACTION(text_edit, "ui_text_delete"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "fi some test text."); + CHECK(text_edit->get_text() == "fi some test text.fi some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); - SIGNAL_CHECK_FALSE("caret_changed"); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 0); + CHECK(text_edit->get_caret_column(1) == 18); + CHECK_FALSE(text_edit->has_selection(1)); + SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); text_edit->set_caret_mid_grapheme_enabled(false); CHECK_FALSE(text_edit->is_caret_mid_grapheme_enabled()); + text_edit->start_action(TextEdit::EditAction::ACTION_NONE); + text_edit->undo(); - text_edit->set_caret_line(0); - text_edit->set_caret_column(0); MessageQueue::get_singleton()->flush(); - CHECK(text_edit->get_text() == "ffi some test text."); + CHECK(text_edit->get_text() == "ffi some test text.ffi some test text."); SIGNAL_DISCARD("text_set"); SIGNAL_DISCARD("text_changed"); @@ -1882,19 +2202,26 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SEND_GUI_ACTION(text_edit, "ui_text_delete"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == " some test text."); + CHECK(text_edit->get_text() == " some test text. some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); - SIGNAL_CHECK_FALSE("caret_changed"); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 0); + CHECK(text_edit->get_caret_column(1) == 16); + CHECK_FALSE(text_edit->has_selection(1)); + SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); } SUBCASE("[TextEdit] ui_text_caret_word_left") { - text_edit->set_text("\nthis is some test text."); + text_edit->set_text("\nthis is some test text.\nthis is some test text."); text_edit->set_caret_line(1); text_edit->set_caret_column(7); + + text_edit->add_caret(2, 7); + CHECK(text_edit->get_caret_count() == 2); MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1902,47 +2229,67 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); + // Shift should select. #ifdef MACOS_ENABLED SEND_GUI_KEY_EVENT(text_edit, Key::LEFT | KeyModifierMask::ALT | KeyModifierMask::SHIFT); #else SEND_GUI_KEY_EVENT(text_edit, Key::LEFT | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT); #endif CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\nthis is some test text."); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 5); - CHECK(text_edit->get_selected_text() == "is"); - CHECK(text_edit->has_selection()); + CHECK(text_edit->get_selected_text(0) == "is"); + CHECK(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 5); + CHECK(text_edit->get_selected_text(1) == "is"); + CHECK(text_edit->has_selection(1)); + SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + // Should still move caret with selection. SEND_GUI_ACTION(text_edit, "ui_text_caret_word_left"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\nthis is some test text."); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); + SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + // Normal word left. SEND_GUI_ACTION(text_edit, "ui_text_caret_word_left"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\nthis is some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 23); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); } SUBCASE("[TextEdit] ui_text_caret_left") { - text_edit->set_text("\nthis is some test text."); + text_edit->set_text("\nthis is some test text.\nthis is some test text."); text_edit->set_caret_line(1); text_edit->set_caret_column(7); text_edit->select(1, 2, 1, 7); + + text_edit->add_caret(2, 7); + text_edit->select(2, 2, 2, 7, 1); + CHECK(text_edit->get_caret_count() == 2); + MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -1950,62 +2297,91 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); + // Normal left shoud deselect and place at selection start. SEND_GUI_ACTION(text_edit, "ui_text_caret_left"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\nthis is some test text."); + CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 2); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 2); + CHECK_FALSE(text_edit->has_selection(1)); + SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + // With shift should select. SEND_GUI_KEY_EVENT(text_edit, Key::LEFT | KeyModifierMask::SHIFT); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\nthis is some test text."); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 1); - CHECK(text_edit->get_selected_text() == "h"); - CHECK(text_edit->has_selection()); + CHECK(text_edit->get_selected_text(0) == "h"); + CHECK(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 1); + CHECK(text_edit->get_selected_text(1) == "h"); + CHECK(text_edit->has_selection(1)); + SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + // All ready at select left, should only deselect. SEND_GUI_ACTION(text_edit, "ui_text_caret_left"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\nthis is some test text."); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 1); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 1); + CHECK_FALSE(text_edit->has_selection(1)); + SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + // Normal left. SEND_GUI_ACTION(text_edit, "ui_text_caret_left"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\nthis is some test text."); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 0); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 0); CHECK_FALSE(text_edit->has_selection()); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + // Left at col 0 should go up a line. SEND_GUI_ACTION(text_edit, "ui_text_caret_left"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "\nthis is some test text."); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 23); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); } SUBCASE("[TextEdit] ui_text_caret_word_right") { - text_edit->set_text("this is some test text\n"); + text_edit->set_text("this is some test text\n\nthis is some test text\n"); text_edit->set_caret_line(0); text_edit->set_caret_column(13); + + text_edit->add_caret(2, 13); + CHECK(text_edit->get_caret_count() == 2); + MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -2013,47 +2389,67 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); + // Shift should select. #ifdef MACOS_ENABLED SEND_GUI_KEY_EVENT(text_edit, Key::RIGHT | KeyModifierMask::ALT | KeyModifierMask::SHIFT); #else SEND_GUI_KEY_EVENT(text_edit, Key::RIGHT | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT); #endif CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "this is some test text\n"); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 17); - CHECK(text_edit->get_selected_text() == "test"); - CHECK(text_edit->has_selection()); + CHECK(text_edit->get_selected_text(0) == "test"); + CHECK(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 17); + CHECK(text_edit->get_selected_text(1) == "test"); + CHECK(text_edit->has_selection(1)); + SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + // Should still move caret with selection. SEND_GUI_ACTION(text_edit, "ui_text_caret_word_right"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "this is some test text\n"); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 22); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 22); + CHECK_FALSE(text_edit->has_selection(1)); + SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + // Normal word right. SEND_GUI_ACTION(text_edit, "ui_text_caret_word_right"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "this is some test text\n"); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 3); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); } SUBCASE("[TextEdit] ui_text_caret_right") { - text_edit->set_text("this is some test text\n"); + text_edit->set_text("this is some test text\n\nthis is some test text\n"); text_edit->set_caret_line(0); text_edit->set_caret_column(16); text_edit->select(0, 16, 0, 20); + + text_edit->add_caret(2, 16); + text_edit->select(2, 16, 2, 20, 1); + CHECK(text_edit->get_caret_count() == 2); + MessageQueue::get_singleton()->flush(); SIGNAL_DISCARD("text_set"); @@ -2061,53 +2457,76 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); + // Normal right shoud deselect and place at selection start. SEND_GUI_ACTION(text_edit, "ui_text_caret_right"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "this is some test text\n"); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 20); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 20); + CHECK_FALSE(text_edit->has_selection(1)); + SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + // With shift should select. SEND_GUI_KEY_EVENT(text_edit, Key::RIGHT | KeyModifierMask::SHIFT); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "this is some test text\n"); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 21); - CHECK(text_edit->get_selected_text() == "x"); - CHECK(text_edit->has_selection()); + CHECK(text_edit->get_selected_text(0) == "x"); + CHECK(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 21); + CHECK(text_edit->get_selected_text(1) == "x"); + CHECK(text_edit->has_selection(1)); + SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + // All ready at select right, should only deselect. SEND_GUI_ACTION(text_edit, "ui_text_caret_right"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "this is some test text\n"); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 21); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 21); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + // Normal right. SEND_GUI_ACTION(text_edit, "ui_text_caret_right"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "this is some test text\n"); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 22); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 22); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + // Right at end col should go down a line. SEND_GUI_ACTION(text_edit, "ui_text_caret_right"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "this is some test text\n"); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 3); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); @@ -2117,9 +2536,13 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY); text_edit->set_size(Size2(110, 100)); - text_edit->set_text("this is some\nother test\nlines\ngo here"); - text_edit->set_caret_line(4); + text_edit->set_text("this is some\nother test\nlines\ngo here\nthis is some\nother test\nlines\ngo here"); + text_edit->set_caret_line(3); text_edit->set_caret_column(7); + + text_edit->add_caret(7, 7); + CHECK(text_edit->get_caret_count() == 2); + MessageQueue::get_singleton()->flush(); CHECK(text_edit->is_line_wrapped(0)); @@ -2128,44 +2551,61 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); + // Select + up should select everything to the left on that line. SEND_GUI_KEY_EVENT(text_edit, Key::UP | KeyModifierMask::SHIFT); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "this is some\nother test\nlines\ngo here"); CHECK(text_edit->get_caret_line() == 2); CHECK(text_edit->get_caret_column() == 5); - CHECK(text_edit->get_selected_text() == "\ngo here"); - CHECK(text_edit->has_selection()); + CHECK(text_edit->get_selected_text(0) == "\ngo here"); + CHECK(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 6); + CHECK(text_edit->get_caret_column(1) == 5); + CHECK(text_edit->get_selected_text(1) == "\ngo here"); + CHECK(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + // Should deselect and move up. SEND_GUI_ACTION(text_edit, "ui_text_caret_up"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "this is some\nother test\nlines\ngo here"); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 8); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 5); + CHECK(text_edit->get_caret_column(1) == 8); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + // Normal up over wrapped line. SEND_GUI_ACTION(text_edit, "ui_text_caret_up"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "this is some\nother test\nlines\ngo here"); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 12); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 4); + CHECK(text_edit->get_caret_column(1) == 12); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); text_edit->set_caret_column(12, false); + // Normal up over wrapped line to line 0. SEND_GUI_ACTION(text_edit, "ui_text_caret_up"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "this is some\nother test\nlines\ngo here"); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 7); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 4); + CHECK(text_edit->get_caret_column(1) == 7); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); @@ -2175,9 +2615,13 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY); text_edit->set_size(Size2(110, 100)); - text_edit->set_text("go here\nlines\nother test\nthis is some"); + text_edit->set_text("go here\nlines\nother test\nthis is some\ngo here\nlines\nother test\nthis is some"); text_edit->set_caret_line(0); text_edit->set_caret_column(7); + + text_edit->add_caret(4, 7); + CHECK(text_edit->get_caret_count() == 2); + MessageQueue::get_singleton()->flush(); CHECK(text_edit->is_line_wrapped(3)); @@ -2186,44 +2630,61 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); + // Select + down should select everything to the right on that line. SEND_GUI_KEY_EVENT(text_edit, Key::DOWN | KeyModifierMask::SHIFT); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "go here\nlines\nother test\nthis is some"); CHECK(text_edit->get_caret_line() == 1); CHECK(text_edit->get_caret_column() == 5); - CHECK(text_edit->get_selected_text() == "\nlines"); - CHECK(text_edit->has_selection()); + CHECK(text_edit->get_selected_text(0) == "\nlines"); + CHECK(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 5); + CHECK(text_edit->get_caret_column(1) == 5); + CHECK(text_edit->get_selected_text(1) == "\nlines"); + CHECK(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + // Should deselect and move down. SEND_GUI_ACTION(text_edit, "ui_text_caret_down"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "go here\nlines\nother test\nthis is some"); CHECK(text_edit->get_caret_line() == 2); CHECK(text_edit->get_caret_column() == 8); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 6); + CHECK(text_edit->get_caret_column(1) == 8); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + // Normal down over wrapped line. SEND_GUI_ACTION(text_edit, "ui_text_caret_down"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "go here\nlines\nother test\nthis is some"); CHECK(text_edit->get_caret_line() == 3); CHECK(text_edit->get_caret_column() == 7); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 7); + CHECK(text_edit->get_caret_column(1) == 7); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); text_edit->set_caret_column(7, false); + // Normal down over wrapped line to last wrapped line. SEND_GUI_ACTION(text_edit, "ui_text_caret_down"); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "go here\nlines\nother test\nthis is some"); CHECK(text_edit->get_caret_line() == 3); CHECK(text_edit->get_caret_column() == 12); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 7); + CHECK(text_edit->get_caret_column(1) == 12); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); @@ -2236,6 +2697,10 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_text("this is some\nother test\nlines\ngo here"); text_edit->set_caret_line(4); text_edit->set_caret_column(7); + + text_edit->add_caret(3, 2); + CHECK(text_edit->get_caret_count() == 2); + MessageQueue::get_singleton()->flush(); CHECK(text_edit->is_line_wrapped(0)); @@ -2258,6 +2723,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + CHECK(text_edit->get_caret_count() == 1); SEND_GUI_ACTION(text_edit, "ui_text_caret_document_start"); CHECK(text_edit->get_viewport()->is_input_handled()); @@ -2277,6 +2743,9 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_text("go here\nlines\nother test\nthis is some"); text_edit->set_caret_line(0); text_edit->set_caret_column(0); + + text_edit->add_caret(1, 0); + CHECK(text_edit->get_caret_count() == 2); MessageQueue::get_singleton()->flush(); CHECK(text_edit->is_line_wrapped(3)); @@ -2299,6 +2768,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + CHECK(text_edit->get_caret_count() == 1); SEND_GUI_ACTION(text_edit, "ui_text_caret_document_end"); CHECK(text_edit->get_viewport()->is_input_handled()); @@ -2315,9 +2785,12 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY); text_edit->set_size(Size2(110, 100)); - text_edit->set_text(" this is some"); + text_edit->set_text(" this is some\n this is some"); text_edit->set_caret_line(0); text_edit->set_caret_column(text_edit->get_line(0).length()); + + text_edit->add_caret(1, text_edit->get_line(1).length()); + CHECK(text_edit->get_caret_count() == 2); MessageQueue::get_singleton()->flush(); CHECK(text_edit->is_line_wrapped(0)); @@ -2334,8 +2807,13 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK(text_edit->get_viewport()->is_input_handled()); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 10); - CHECK(text_edit->has_selection()); - CHECK(text_edit->get_selected_text() == "some"); + CHECK(text_edit->has_selection(0)); + CHECK(text_edit->get_selected_text(0) == "some"); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 10); + CHECK(text_edit->has_selection(1)); + CHECK(text_edit->get_selected_text(1) == "some"); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); @@ -2344,7 +2822,11 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK(text_edit->get_viewport()->is_input_handled()); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 2); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 2); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); @@ -2353,7 +2835,11 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK(text_edit->get_viewport()->is_input_handled()); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 0); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 0); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); @@ -2362,7 +2848,11 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK(text_edit->get_viewport()->is_input_handled()); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 2); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 2); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); @@ -2372,9 +2862,12 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY); text_edit->set_size(Size2(110, 100)); - text_edit->set_text(" this is some"); + text_edit->set_text(" this is some\n this is some"); text_edit->set_caret_line(0); text_edit->set_caret_column(0); + + text_edit->add_caret(1, 0); + CHECK(text_edit->get_caret_count() == 2); MessageQueue::get_singleton()->flush(); CHECK(text_edit->is_line_wrapped(0)); @@ -2391,8 +2884,13 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK(text_edit->get_viewport()->is_input_handled()); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == 9); - CHECK(text_edit->has_selection()); - CHECK(text_edit->get_selected_text() == " this is"); + CHECK(text_edit->has_selection(0)); + CHECK(text_edit->get_selected_text(0) == " this is"); + + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 9); + CHECK(text_edit->has_selection(1)); + CHECK(text_edit->get_selected_text(1) == " this is"); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); @@ -2401,13 +2899,24 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK(text_edit->get_viewport()->is_input_handled()); CHECK(text_edit->get_caret_line() == 0); CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length()); - CHECK_FALSE(text_edit->has_selection()); + CHECK_FALSE(text_edit->has_selection(0)); + + CHECK(text_edit->get_viewport()->is_input_handled()); + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == text_edit->get_line(1).length()); + CHECK_FALSE(text_edit->has_selection(1)); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); } SUBCASE("[TextEdit] unicode") { + text_edit->set_text("\n"); + text_edit->set_caret_line(0); + text_edit->set_caret_column(0); + + text_edit->add_caret(1, 0); + CHECK(text_edit->get_caret_count() == 2); text_edit->insert_text_at_caret("a"); MessageQueue::get_singleton()->flush(); @@ -2416,10 +2925,17 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_DISCARD("lines_edited_from"); SIGNAL_DISCARD("caret_changed"); + // For the second caret. + Array args2; + args2.push_back(1); + args2.push_back(1); + lines_edited_args.push_front(args2); + SEND_GUI_KEY_EVENT(text_edit, Key::A); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "aA"); + CHECK(text_edit->get_text() == "aA\naA"); CHECK(text_edit->get_caret_column() == 2); + CHECK(text_edit->get_caret_column(1) == 2); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); @@ -2427,20 +2943,24 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { text_edit->set_editable(false); SEND_GUI_KEY_EVENT(text_edit, Key::A); CHECK_FALSE(text_edit->get_viewport()->is_input_handled()); // Should this be handled? - CHECK(text_edit->get_text() == "aA"); + CHECK(text_edit->get_text() == "aA\naA"); CHECK(text_edit->get_caret_column() == 2); + CHECK(text_edit->get_caret_column(1) == 2); SIGNAL_CHECK_FALSE("caret_changed"); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); text_edit->set_editable(true); - lines_edited_args.push_back(lines_edited_args[0].duplicate()); + lines_edited_args.push_back(lines_edited_args[1].duplicate()); + lines_edited_args.push_front(args2.duplicate()); text_edit->select(0, 0, 0, 1); + text_edit->select(1, 0, 1, 1, 1); SEND_GUI_KEY_EVENT(text_edit, Key::B); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "BA"); + CHECK(text_edit->get_text() == "BA\nBA"); CHECK(text_edit->get_caret_column() == 1); + CHECK(text_edit->get_caret_column(1) == 1); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); @@ -2450,22 +2970,36 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SEND_GUI_KEY_EVENT(text_edit, Key::B); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "BB"); + CHECK(text_edit->get_text() == "BB\nBB"); CHECK(text_edit->get_caret_column() == 2); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); text_edit->select(0, 0, 0, 1); + text_edit->select(1, 0, 1, 1, 1); SEND_GUI_KEY_EVENT(text_edit, Key::A); CHECK(text_edit->get_viewport()->is_input_handled()); - CHECK(text_edit->get_text() == "AB"); + CHECK(text_edit->get_text() == "AB\nAB"); CHECK(text_edit->get_caret_column() == 1); + CHECK(text_edit->get_caret_column(1) == 1); SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK("text_changed", empty_signal_args); SIGNAL_CHECK("lines_edited_from", lines_edited_args); text_edit->set_overtype_mode_enabled(false); CHECK_FALSE(text_edit->is_overtype_mode_enabled()); + + lines_edited_args.remove_at(0); + lines_edited_args.remove_at(1); + + SEND_GUI_KEY_EVENT(text_edit, Key::TAB); + CHECK(text_edit->get_viewport()->is_input_handled()); + CHECK(text_edit->get_text() == "A\tB\nA\tB"); + CHECK(text_edit->get_caret_column() == 2); + CHECK(text_edit->get_caret_column(1) == 2); + SIGNAL_CHECK("caret_changed", empty_signal_args); + SIGNAL_CHECK("text_changed", empty_signal_args); + SIGNAL_CHECK("lines_edited_from", lines_edited_args); } SIGNAL_UNWATCH(text_edit, "text_set"); @@ -2558,7 +3092,7 @@ TEST_CASE("[SceneTree][TextEdit] versioning") { CHECK(text_edit->has_redo()); text_edit->redo(); - CHECK(text_edit->get_line(0) == "test nested ops"); + CHECK(text_edit->get_line(0) == "test ops nested"); CHECK(text_edit->get_version() == 3); CHECK(text_edit->get_saved_version() == 3); CHECK(text_edit->has_undo()); @@ -2779,6 +3313,99 @@ TEST_CASE("[SceneTree][TextEdit] caret") { memdelete(text_edit); } +TEST_CASE("[SceneTree][TextEdit] muiticaret") { + TextEdit *text_edit = memnew(TextEdit); + SceneTree::get_singleton()->get_root()->add_child(text_edit); + text_edit->set_multiple_carets_enabled(true); + + Array empty_signal_args; + empty_signal_args.push_back(Array()); + + SIGNAL_WATCH(text_edit, "caret_changed"); + + text_edit->set_text("this is\nsome test\ntext"); + text_edit->set_caret_line(0); + text_edit->set_caret_column(0); + MessageQueue::get_singleton()->flush(); + SIGNAL_DISCARD("caret_changed"); + + SUBCASE("[TextEdit] add remove caret") { + // Overlapping + CHECK(text_edit->add_caret(0, 0) == -1); + MessageQueue::get_singleton()->flush(); + SIGNAL_CHECK_FALSE("caret_changed"); + + // Selection + text_edit->select(0, 0, 2, 4); + CHECK(text_edit->add_caret(0, 0) == -1); + CHECK(text_edit->add_caret(2, 4) == -1); + CHECK(text_edit->add_caret(1, 2) == -1); + + // Out of bounds + CHECK(text_edit->add_caret(-1, 0) == -1); + CHECK(text_edit->add_caret(5, 0) == -1); + CHECK(text_edit->add_caret(0, 100) == -1); + + MessageQueue::get_singleton()->flush(); + SIGNAL_CHECK_FALSE("caret_changed"); + + CHECK(text_edit->get_caret_count() == 1); + + text_edit->deselect(); + SIGNAL_CHECK_FALSE("caret_changed"); + + CHECK(text_edit->add_caret(0, 1) == 1); + MessageQueue::get_singleton()->flush(); + SIGNAL_CHECK("caret_changed", empty_signal_args); + CHECK(text_edit->get_caret_count() == 2); + + CHECK(text_edit->get_caret_line(0) == 0); + CHECK(text_edit->get_caret_column(0) == 0); + + CHECK(text_edit->get_caret_line(1) == 0); + CHECK(text_edit->get_caret_column(1) == 1); + + ERR_PRINT_OFF; + text_edit->remove_caret(-1); + text_edit->remove_caret(5); + ERR_PRINT_ON; + CHECK(text_edit->get_caret_count() == 2); + SIGNAL_CHECK_FALSE("caret_changed"); + + text_edit->remove_caret(0); + SIGNAL_CHECK_FALSE("caret_changed"); + CHECK(text_edit->get_caret_count() == 1); + CHECK(text_edit->get_caret_line(0) == 0); + CHECK(text_edit->get_caret_column(0) == 1); + + ERR_PRINT_OFF; + text_edit->remove_caret(0); + CHECK(text_edit->get_caret_count() == 1); + ERR_PRINT_ON; + } + + SUBCASE("[TextEdit] caret index edit order") { + Vector<int> caret_index_get_order; + caret_index_get_order.push_back(1); + caret_index_get_order.push_back(0); + + CHECK(text_edit->add_caret(1, 0)); + CHECK(text_edit->get_caret_count() == 2); + CHECK(text_edit->get_caret_index_edit_order() == caret_index_get_order); + + text_edit->remove_secondary_carets(); + text_edit->set_caret_line(1); + CHECK(text_edit->add_caret(0, 0)); + CHECK(text_edit->get_caret_count() == 2); + + caret_index_get_order.write[0] = 0; + caret_index_get_order.write[1] = 1; + CHECK(text_edit->get_caret_index_edit_order() == caret_index_get_order); + } + + memdelete(text_edit); +} + TEST_CASE("[SceneTree][TextEdit] line wrapping") { TextEdit *text_edit = memnew(TextEdit); SceneTree::get_singleton()->get_root()->add_child(text_edit); @@ -3291,6 +3918,32 @@ TEST_CASE("[SceneTree][TextEdit] viewport") { CHECK(text_edit->get_last_full_visible_line_wrap_index() == 0); CHECK(text_edit->get_caret_wrap_index() == 0); + // Typing and undo / redo should adjust viewport + text_edit->set_caret_line(0); + text_edit->set_caret_column(0); + text_edit->set_line_as_first_visible(5); + MessageQueue::get_singleton()->flush(); + CHECK(text_edit->get_first_visible_line() == 5); + + SEND_GUI_KEY_EVENT(text_edit, Key::A); + CHECK(text_edit->get_first_visible_line() == 0); + + text_edit->set_line_as_first_visible(5); + MessageQueue::get_singleton()->flush(); + CHECK(text_edit->get_first_visible_line() == 5); + + text_edit->undo(); + MessageQueue::get_singleton()->flush(); + CHECK(text_edit->get_first_visible_line() == 0); + + text_edit->set_line_as_first_visible(5); + MessageQueue::get_singleton()->flush(); + CHECK(text_edit->get_first_visible_line() == 5); + + text_edit->redo(); + MessageQueue::get_singleton()->flush(); + CHECK(text_edit->get_first_visible_line() == 0); + memdelete(text_edit); } |