summaryrefslogtreecommitdiff
path: root/tests/scene
diff options
context:
space:
mode:
Diffstat (limited to 'tests/scene')
-rw-r--r--tests/scene/test_animation.h148
-rw-r--r--tests/scene/test_arraymesh.h325
-rw-r--r--tests/scene/test_audio_stream_wav.h60
-rw-r--r--tests/scene/test_bit_map.h148
-rw-r--r--tests/scene/test_code_edit.h152
-rw-r--r--tests/scene/test_curve.h120
-rw-r--r--tests/scene/test_gradient.h68
-rw-r--r--tests/scene/test_node.h415
-rw-r--r--tests/scene/test_path_2d.h109
-rw-r--r--tests/scene/test_path_3d.h58
-rw-r--r--tests/scene/test_path_follow_2d.h58
-rw-r--r--tests/scene/test_path_follow_3d.h58
-rw-r--r--tests/scene/test_primitives.h850
-rw-r--r--tests/scene/test_sprite_frames.h66
-rw-r--r--tests/scene/test_text_edit.h1362
-rw-r--r--tests/scene/test_theme.h58
-rw-r--r--tests/scene/test_visual_shader.h151
17 files changed, 3480 insertions, 726 deletions
diff --git a/tests/scene/test_animation.h b/tests/scene/test_animation.h
index 9199713fd9..0e16fc104c 100644
--- a/tests/scene/test_animation.h
+++ b/tests/scene/test_animation.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* test_animation.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* test_animation.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef TEST_ANIMATION_H
#define TEST_ANIMATION_H
@@ -40,8 +40,8 @@ namespace TestAnimation {
TEST_CASE("[Animation] Empty animation getters") {
const Ref<Animation> animation = memnew(Animation);
- CHECK(Math::is_equal_approx(animation->get_length(), real_t(1.0)));
- CHECK(Math::is_equal_approx(animation->get_step(), real_t(0.1)));
+ CHECK(animation->get_length() == doctest::Approx(real_t(1.0)));
+ CHECK(animation->get_step() == doctest::Approx(real_t(0.1)));
}
TEST_CASE("[Animation] Create value track") {
@@ -59,33 +59,33 @@ TEST_CASE("[Animation] Create value track") {
CHECK(int(animation->track_get_key_value(0, 0)) == 0);
CHECK(int(animation->track_get_key_value(0, 1)) == 100);
- CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, -0.2), 0.0));
- CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, 0.0), 0.0));
- CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, 0.2), 40.0));
- CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, 0.4), 80.0));
- CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, 0.5), 100.0));
- CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, 0.6), 100.0));
+ CHECK(animation->value_track_interpolate(0, -0.2) == doctest::Approx(0.0));
+ CHECK(animation->value_track_interpolate(0, 0.0) == doctest::Approx(0.0));
+ CHECK(animation->value_track_interpolate(0, 0.2) == doctest::Approx(40.0));
+ CHECK(animation->value_track_interpolate(0, 0.4) == doctest::Approx(80.0));
+ CHECK(animation->value_track_interpolate(0, 0.5) == doctest::Approx(100.0));
+ CHECK(animation->value_track_interpolate(0, 0.6) == doctest::Approx(100.0));
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 0), real_t(1.0)));
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 1), real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 0) == doctest::Approx(real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 1) == doctest::Approx(real_t(1.0)));
ERR_PRINT_OFF;
// Nonexistent keys.
CHECK(animation->track_get_key_value(0, 2).is_null());
CHECK(animation->track_get_key_value(0, -1).is_null());
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 2), real_t(-1.0)));
+ CHECK(animation->track_get_key_transition(0, 2) == doctest::Approx(real_t(-1.0)));
// Nonexistent track (and keys).
CHECK(animation->track_get_key_value(1, 0).is_null());
CHECK(animation->track_get_key_value(1, 1).is_null());
CHECK(animation->track_get_key_value(1, 2).is_null());
CHECK(animation->track_get_key_value(1, -1).is_null());
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(1, 0), real_t(-1.0)));
+ CHECK(animation->track_get_key_transition(1, 0) == doctest::Approx(real_t(-1.0)));
// This is a value track, so the methods below should return errors.
CHECK(animation->position_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
CHECK(animation->rotation_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
CHECK(animation->scale_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
- CHECK(Math::is_zero_approx(animation->bezier_track_interpolate(0, 0.0)));
+ CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(0.0));
CHECK(animation->blend_shape_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
ERR_PRINT_ON;
}
@@ -123,15 +123,15 @@ TEST_CASE("[Animation] Create 3D position track") {
CHECK(r_interpolation.is_equal_approx(Vector3(3.5, 4, 5)));
// 3D position tracks always use linear interpolation for performance reasons.
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 0), real_t(1.0)));
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 1), real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 0) == doctest::Approx(real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 1) == doctest::Approx(real_t(1.0)));
// This is a 3D position track, so the methods below should return errors.
ERR_PRINT_OFF;
CHECK(animation->value_track_interpolate(0, 0.0).is_null());
CHECK(animation->rotation_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
CHECK(animation->scale_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
- CHECK(Math::is_zero_approx(animation->bezier_track_interpolate(0, 0.0)));
+ CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(0.0));
CHECK(animation->blend_shape_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
ERR_PRINT_ON;
}
@@ -140,13 +140,13 @@ TEST_CASE("[Animation] Create 3D rotation track") {
Ref<Animation> animation = memnew(Animation);
const int track_index = animation->add_track(Animation::TYPE_ROTATION_3D);
animation->track_set_path(track_index, NodePath("Enemy:rotation"));
- animation->rotation_track_insert_key(track_index, 0.0, Quaternion(Vector3(0, 1, 2)));
- animation->rotation_track_insert_key(track_index, 0.5, Quaternion(Vector3(3.5, 4, 5)));
+ animation->rotation_track_insert_key(track_index, 0.0, Quaternion::from_euler(Vector3(0, 1, 2)));
+ animation->rotation_track_insert_key(track_index, 0.5, Quaternion::from_euler(Vector3(3.5, 4, 5)));
CHECK(animation->get_track_count() == 1);
CHECK(!animation->track_is_compressed(0));
- CHECK(Quaternion(animation->track_get_key_value(0, 0)).is_equal_approx(Quaternion(Vector3(0, 1, 2))));
- CHECK(Quaternion(animation->track_get_key_value(0, 1)).is_equal_approx(Quaternion(Vector3(3.5, 4, 5))));
+ CHECK(Quaternion(animation->track_get_key_value(0, 0)).is_equal_approx(Quaternion::from_euler(Vector3(0, 1, 2))));
+ CHECK(Quaternion(animation->track_get_key_value(0, 1)).is_equal_approx(Quaternion::from_euler(Vector3(3.5, 4, 5))));
Quaternion r_interpolation;
@@ -169,15 +169,15 @@ TEST_CASE("[Animation] Create 3D rotation track") {
CHECK(r_interpolation.is_equal_approx(Quaternion(0.231055, 0.374912, 0.761204, 0.476048)));
// 3D rotation tracks always use linear interpolation for performance reasons.
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 0), real_t(1.0)));
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 1), real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 0) == doctest::Approx(real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 1) == doctest::Approx(real_t(1.0)));
// This is a 3D rotation track, so the methods below should return errors.
ERR_PRINT_OFF;
CHECK(animation->value_track_interpolate(0, 0.0).is_null());
CHECK(animation->position_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
CHECK(animation->scale_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
- CHECK(Math::is_zero_approx(animation->bezier_track_interpolate(0, 0.0)));
+ CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(real_t(0.0)));
CHECK(animation->blend_shape_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
ERR_PRINT_ON;
}
@@ -215,15 +215,15 @@ TEST_CASE("[Animation] Create 3D scale track") {
CHECK(r_interpolation.is_equal_approx(Vector3(3.5, 4, 5)));
// 3D scale tracks always use linear interpolation for performance reasons.
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 0), real_t(1.0)));
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 1), real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 0) == doctest::Approx(1.0));
+ CHECK(animation->track_get_key_transition(0, 1) == doctest::Approx(1.0));
// This is a 3D scale track, so the methods below should return errors.
ERR_PRINT_OFF;
CHECK(animation->value_track_interpolate(0, 0.0).is_null());
CHECK(animation->position_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
CHECK(animation->rotation_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
- CHECK(Math::is_zero_approx(animation->bezier_track_interpolate(0, 0.0)));
+ CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(0.0));
CHECK(animation->blend_shape_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
ERR_PRINT_ON;
}
@@ -242,32 +242,32 @@ TEST_CASE("[Animation] Create blend shape track") {
float r_blend = 0.0f;
CHECK(animation->blend_shape_track_get_key(0, 0, &r_blend) == OK);
- CHECK(Math::is_equal_approx(r_blend, -1.0f));
+ CHECK(r_blend == doctest::Approx(-1.0f));
CHECK(animation->blend_shape_track_get_key(0, 1, &r_blend) == OK);
- CHECK(Math::is_equal_approx(r_blend, 1.0f));
+ CHECK(r_blend == doctest::Approx(1.0f));
CHECK(animation->blend_shape_track_interpolate(0, -0.2, &r_blend) == OK);
- CHECK(Math::is_equal_approx(r_blend, -1.0f));
+ CHECK(r_blend == doctest::Approx(-1.0f));
CHECK(animation->blend_shape_track_interpolate(0, 0.0, &r_blend) == OK);
- CHECK(Math::is_equal_approx(r_blend, -1.0f));
+ CHECK(r_blend == doctest::Approx(-1.0f));
CHECK(animation->blend_shape_track_interpolate(0, 0.2, &r_blend) == OK);
- CHECK(Math::is_equal_approx(r_blend, -0.2f));
+ CHECK(r_blend == doctest::Approx(-0.2f));
CHECK(animation->blend_shape_track_interpolate(0, 0.4, &r_blend) == OK);
- CHECK(Math::is_equal_approx(r_blend, 0.6f));
+ CHECK(r_blend == doctest::Approx(0.6f));
CHECK(animation->blend_shape_track_interpolate(0, 0.5, &r_blend) == OK);
- CHECK(Math::is_equal_approx(r_blend, 1.0f));
+ CHECK(r_blend == doctest::Approx(1.0f));
CHECK(animation->blend_shape_track_interpolate(0, 0.6, &r_blend) == OK);
- CHECK(Math::is_equal_approx(r_blend, 1.0f));
+ CHECK(r_blend == doctest::Approx(1.0f));
// Blend shape tracks always use linear interpolation for performance reasons.
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 0), real_t(1.0)));
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 1), real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 0) == doctest::Approx(real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 1) == doctest::Approx(real_t(1.0)));
// This is a blend shape track, so the methods below should return errors.
ERR_PRINT_OFF;
@@ -275,7 +275,7 @@ TEST_CASE("[Animation] Create blend shape track") {
CHECK(animation->position_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
CHECK(animation->rotation_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
CHECK(animation->scale_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
- CHECK(Math::is_zero_approx(animation->bezier_track_interpolate(0, 0.0)));
+ CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(0.0));
ERR_PRINT_ON;
}
@@ -289,15 +289,15 @@ TEST_CASE("[Animation] Create Bezier track") {
CHECK(animation->get_track_count() == 1);
CHECK(!animation->track_is_compressed(0));
- CHECK(Math::is_equal_approx(animation->bezier_track_get_key_value(0, 0), real_t(-1.0)));
- CHECK(Math::is_equal_approx(animation->bezier_track_get_key_value(0, 1), real_t(1.0)));
+ CHECK(animation->bezier_track_get_key_value(0, 0) == doctest::Approx(real_t(-1.0)));
+ CHECK(animation->bezier_track_get_key_value(0, 1) == doctest::Approx(real_t(1.0)));
- CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, -0.2), real_t(-1.0)));
- CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, 0.0), real_t(-1.0)));
- CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, 0.2), real_t(-0.76057207584381)));
- CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, 0.4), real_t(-0.39975279569626)));
- CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, 0.5), real_t(1.0)));
- CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, 0.6), real_t(1.0)));
+ CHECK(animation->bezier_track_interpolate(0, -0.2) == doctest::Approx(real_t(-1.0)));
+ CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(real_t(-1.0)));
+ CHECK(animation->bezier_track_interpolate(0, 0.2) == doctest::Approx(real_t(-0.76057207584381)));
+ CHECK(animation->bezier_track_interpolate(0, 0.4) == doctest::Approx(real_t(-0.39975279569626)));
+ CHECK(animation->bezier_track_interpolate(0, 0.5) == doctest::Approx(real_t(1.0)));
+ CHECK(animation->bezier_track_interpolate(0, 0.6) == doctest::Approx(real_t(1.0)));
// This is a bezier track, so the methods below should return errors.
ERR_PRINT_OFF;
diff --git a/tests/scene/test_arraymesh.h b/tests/scene/test_arraymesh.h
new file mode 100644
index 0000000000..4d9feeb4fa
--- /dev/null
+++ b/tests/scene/test_arraymesh.h
@@ -0,0 +1,325 @@
+/**************************************************************************/
+/* test_arraymesh.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef TEST_ARRAYMESH_H
+#define TEST_ARRAYMESH_H
+
+#include "scene/resources/mesh.h"
+#include "scene/resources/primitive_meshes.h"
+
+#include "tests/test_macros.h"
+
+namespace TestArrayMesh {
+
+TEST_CASE("[SceneTree][ArrayMesh] Adding and modifying blendshapes.") {
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+ StringName name_a{ "ShapeA" };
+ StringName name_b{ "ShapeB" };
+
+ SUBCASE("Adding a blend shape to the mesh before a surface is added.") {
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_b);
+
+ CHECK(mesh->get_blend_shape_name(0) == name_a);
+ CHECK(mesh->get_blend_shape_name(1) == name_b);
+ }
+
+ SUBCASE("Add same blend shape multiple times appends name with number.") {
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_a);
+
+ CHECK(mesh->get_blend_shape_name(0) == "ShapeA");
+ bool all_different = (static_cast<String>(mesh->get_blend_shape_name(0)) != static_cast<String>(mesh->get_blend_shape_name(1))) &&
+ (static_cast<String>(mesh->get_blend_shape_name(1)) != static_cast<String>(mesh->get_blend_shape_name(2))) &&
+ (static_cast<String>(mesh->get_blend_shape_name(0)) != static_cast<String>(mesh->get_blend_shape_name(2)));
+ bool all_have_name = static_cast<String>(mesh->get_blend_shape_name(1)).contains("ShapeA") &&
+ static_cast<String>(mesh->get_blend_shape_name(2)).contains("ShapeA");
+ CHECK((all_different && all_have_name));
+ }
+
+ SUBCASE("ArrayMesh keeps correct count of number of blend shapes") {
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_b);
+ mesh->add_blend_shape(name_b);
+ mesh->add_blend_shape(name_b);
+
+ REQUIRE(mesh->get_blend_shape_count() == 5);
+ }
+
+ SUBCASE("Adding blend shape after surface is added causes error") {
+ Ref<CylinderMesh> cylinder = memnew(CylinderMesh);
+ Array cylinder_array{};
+ cylinder_array.resize(Mesh::ARRAY_MAX);
+ cylinder->create_mesh_array(cylinder_array, 3.f, 3.f, 5.f);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
+
+ ERR_PRINT_OFF
+ mesh->add_blend_shape(name_a);
+ ERR_PRINT_ON
+ CHECK(mesh->get_blend_shape_count() == 0);
+ }
+
+ SUBCASE("Change blend shape name after adding.") {
+ mesh->add_blend_shape(name_a);
+ mesh->set_blend_shape_name(0, name_b);
+
+ CHECK(mesh->get_blend_shape_name(0) == name_b);
+ }
+
+ SUBCASE("Change blend shape name to the name of one already there, should append number to end") {
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_b);
+ mesh->set_blend_shape_name(0, name_b);
+
+ String name_string = mesh->get_blend_shape_name(0);
+ CHECK(name_string.contains("ShapeB"));
+ CHECK(name_string.length() > static_cast<String>(name_b).size());
+ }
+
+ SUBCASE("Clear all blend shapes before surface has been added.") {
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_b);
+ CHECK(mesh->get_blend_shape_count() == 2);
+
+ mesh->clear_blend_shapes();
+ CHECK(mesh->get_blend_shape_count() == 0);
+ }
+
+ SUBCASE("Can't clear blend shapes after surface had been added.") {
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_b);
+ Ref<CylinderMesh> cylinder = memnew(CylinderMesh);
+ Array cylinder_array{};
+ cylinder_array.resize(Mesh::ARRAY_MAX);
+ cylinder->create_mesh_array(cylinder_array, 3.f, 3.f, 5.f);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
+
+ ERR_PRINT_OFF
+ mesh->clear_blend_shapes();
+ ERR_PRINT_ON
+ CHECK(mesh->get_blend_shape_count() == 2);
+ }
+
+ SUBCASE("Set the blend shape mode of ArrayMesh and underlying mesh RID.") {
+ mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_RELATIVE);
+ CHECK(mesh->get_blend_shape_mode() == Mesh::BLEND_SHAPE_MODE_RELATIVE);
+ }
+}
+
+TEST_CASE("[SceneTree][ArrayMesh] Surface meta data tests.") {
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+ Ref<CylinderMesh> cylinder = memnew(CylinderMesh);
+ Array cylinder_array{};
+ cylinder_array.resize(Mesh::ARRAY_MAX);
+ cylinder->create_mesh_array(cylinder_array, 3.f, 3.f, 5.f);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
+
+ Ref<BoxMesh> box = memnew(BoxMesh);
+ Array box_array{};
+ box_array.resize(Mesh::ARRAY_MAX);
+ box->create_mesh_array(box_array, Vector3(2.f, 1.2f, 1.6f));
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, box_array);
+
+ SUBCASE("Add 2 surfaces and count the number of surfaces in the mesh.") {
+ REQUIRE(mesh->get_surface_count() == 2);
+ }
+
+ SUBCASE("Get the surface array from mesh.") {
+ REQUIRE(mesh->surface_get_arrays(0)[0] == cylinder_array[0]);
+ REQUIRE(mesh->surface_get_arrays(1)[0] == box_array[0]);
+ }
+
+ SUBCASE("Get the array length of a particular surface.") {
+ CHECK(mesh->surface_get_array_len(0) == static_cast<Vector<Vector3>>(cylinder_array[RenderingServer::ARRAY_VERTEX]).size());
+ CHECK(mesh->surface_get_array_len(1) == static_cast<Vector<Vector3>>(box_array[RenderingServer::ARRAY_VERTEX]).size());
+ }
+
+ SUBCASE("Get the index array length of a particular surface.") {
+ CHECK(mesh->surface_get_array_index_len(0) == static_cast<Vector<Vector3>>(cylinder_array[RenderingServer::ARRAY_INDEX]).size());
+ CHECK(mesh->surface_get_array_index_len(1) == static_cast<Vector<Vector3>>(box_array[RenderingServer::ARRAY_INDEX]).size());
+ }
+
+ SUBCASE("Get correct primitive type") {
+ CHECK(mesh->surface_get_primitive_type(0) == Mesh::PRIMITIVE_TRIANGLES);
+ CHECK(mesh->surface_get_primitive_type(1) == Mesh::PRIMITIVE_TRIANGLES);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLE_STRIP, box_array);
+ CHECK(mesh->surface_get_primitive_type(2) == Mesh::PRIMITIVE_TRIANGLE_STRIP);
+ }
+
+ SUBCASE("Returns correct format for the mesh") {
+ auto format = RS::ARRAY_FORMAT_BLEND_SHAPE_MASK | RS::ARRAY_FORMAT_TEX_UV | RS::ARRAY_FORMAT_INDEX;
+ CHECK((mesh->surface_get_format(0) & format) != 0);
+ CHECK((mesh->surface_get_format(1) & format) != 0);
+ }
+
+ SUBCASE("Set a surface name and retrieve it by name.") {
+ mesh->surface_set_name(0, "surf1");
+ CHECK(mesh->surface_find_by_name("surf1") == 0);
+ CHECK(mesh->surface_get_name(0) == "surf1");
+ }
+
+ SUBCASE("Set material to two different surfaces.") {
+ Ref<Material> mat = memnew(Material);
+ mesh->surface_set_material(0, mat);
+ CHECK(mesh->surface_get_material(0) == mat);
+ mesh->surface_set_material(1, mat);
+ CHECK(mesh->surface_get_material(1) == mat);
+ }
+
+ SUBCASE("Set same material multiple times doesn't change material of surface.") {
+ Ref<Material> mat = memnew(Material);
+ mesh->surface_set_material(0, mat);
+ mesh->surface_set_material(0, mat);
+ mesh->surface_set_material(0, mat);
+ CHECK(mesh->surface_get_material(0) == mat);
+ }
+
+ SUBCASE("Set material of surface then change to different material.") {
+ Ref<Material> mat1 = memnew(Material);
+ Ref<Material> mat2 = memnew(Material);
+ mesh->surface_set_material(1, mat1);
+ CHECK(mesh->surface_get_material(1) == mat1);
+ mesh->surface_set_material(1, mat2);
+ CHECK(mesh->surface_get_material(1) == mat2);
+ }
+
+ SUBCASE("Get the LOD of the mesh.") {
+ Dictionary lod{};
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array, TypedArray<Array>{}, lod);
+ CHECK(mesh->surface_get_lods(2) == lod);
+ }
+
+ SUBCASE("Get the blend shape arrays from the mesh.") {
+ TypedArray<Array> blend{};
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array, blend);
+ CHECK(mesh->surface_get_blend_shape_arrays(2) == blend);
+ }
+}
+
+TEST_CASE("[SceneTree][ArrayMesh] Get/Set mesh metadata and actions") {
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+ Ref<CylinderMesh> cylinder = memnew(CylinderMesh);
+ Array cylinder_array{};
+ cylinder_array.resize(Mesh::ARRAY_MAX);
+ cylinder->create_mesh_array(cylinder_array, 3.f, 3.f, 5.f);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
+
+ Ref<BoxMesh> box = memnew(BoxMesh);
+ Array box_array{};
+ box_array.resize(Mesh::ARRAY_MAX);
+ box->create_mesh_array(box_array, Vector3(2.f, 1.2f, 1.6f));
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, box_array);
+
+ SUBCASE("Set the shadow mesh.") {
+ Ref<ArrayMesh> shadow = memnew(ArrayMesh);
+ mesh->set_shadow_mesh(shadow);
+ CHECK(mesh->get_shadow_mesh() == shadow);
+ }
+
+ SUBCASE("Set the shadow mesh multiple times.") {
+ Ref<ArrayMesh> shadow = memnew(ArrayMesh);
+ mesh->set_shadow_mesh(shadow);
+ mesh->set_shadow_mesh(shadow);
+ mesh->set_shadow_mesh(shadow);
+ mesh->set_shadow_mesh(shadow);
+ CHECK(mesh->get_shadow_mesh() == shadow);
+ }
+
+ SUBCASE("Set the same shadow mesh on multiple meshes.") {
+ Ref<ArrayMesh> shadow = memnew(ArrayMesh);
+ Ref<ArrayMesh> mesh2 = memnew(ArrayMesh);
+ mesh->set_shadow_mesh(shadow);
+ mesh2->set_shadow_mesh(shadow);
+
+ CHECK(mesh->get_shadow_mesh() == shadow);
+ CHECK(mesh2->get_shadow_mesh() == shadow);
+ }
+
+ SUBCASE("Set the shadow mesh and then change it.") {
+ Ref<ArrayMesh> shadow = memnew(ArrayMesh);
+ mesh->set_shadow_mesh(shadow);
+ CHECK(mesh->get_shadow_mesh() == shadow);
+ Ref<ArrayMesh> shadow2 = memnew(ArrayMesh);
+ mesh->set_shadow_mesh(shadow2);
+ CHECK(mesh->get_shadow_mesh() == shadow2);
+ }
+
+ SUBCASE("Set custom AABB.") {
+ AABB bound{};
+ mesh->set_custom_aabb(bound);
+ CHECK(mesh->get_custom_aabb() == bound);
+ }
+
+ SUBCASE("Set custom AABB multiple times.") {
+ AABB bound{};
+ mesh->set_custom_aabb(bound);
+ mesh->set_custom_aabb(bound);
+ mesh->set_custom_aabb(bound);
+ mesh->set_custom_aabb(bound);
+ CHECK(mesh->get_custom_aabb() == bound);
+ }
+
+ SUBCASE("Set custom AABB then change to another AABB.") {
+ AABB bound{};
+ AABB bound2{};
+ mesh->set_custom_aabb(bound);
+ CHECK(mesh->get_custom_aabb() == bound);
+ mesh->set_custom_aabb(bound2);
+ CHECK(mesh->get_custom_aabb() == bound2);
+ }
+
+ SUBCASE("Clear all surfaces should leave zero count.") {
+ mesh->clear_surfaces();
+ CHECK(mesh->get_surface_count() == 0);
+ }
+
+ SUBCASE("Able to get correct mesh RID.") {
+ RID rid = mesh->get_rid();
+ CHECK(RS::get_singleton()->mesh_get_surface_count(rid) == 2);
+ }
+
+ SUBCASE("Create surface from raw SurfaceData data.") {
+ RID mesh_rid = mesh->get_rid();
+ RS::SurfaceData surface_data = RS::get_singleton()->mesh_get_surface(mesh_rid, 0);
+ Ref<ArrayMesh> mesh2 = memnew(ArrayMesh);
+ mesh2->add_surface(surface_data.format, Mesh::PRIMITIVE_TRIANGLES, surface_data.vertex_data, surface_data.attribute_data,
+ surface_data.skin_data, surface_data.vertex_count, surface_data.index_data, surface_data.index_count, surface_data.aabb);
+ CHECK(mesh2->get_surface_count() == 1);
+ CHECK(mesh2->surface_get_primitive_type(0) == Mesh::PRIMITIVE_TRIANGLES);
+ CHECK((mesh2->surface_get_format(0) & surface_data.format) != 0);
+ CHECK(mesh2->get_aabb().is_equal_approx(surface_data.aabb));
+ }
+}
+
+} // namespace TestArrayMesh
+
+#endif // TEST_ARRAYMESH_H
diff --git a/tests/scene/test_audio_stream_wav.h b/tests/scene/test_audio_stream_wav.h
index cf369c115b..e36f049136 100644
--- a/tests/scene/test_audio_stream_wav.h
+++ b/tests/scene/test_audio_stream_wav.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* test_audio_stream_wav.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* test_audio_stream_wav.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef TEST_AUDIO_STREAM_WAV_H
#define 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(stream->get_length() == doctest::Approx(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..3c372b2ac3 100644
--- a/tests/scene/test_bit_map.h
+++ b/tests/scene/test_bit_map.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* test_bit_map.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* test_bit_map.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef TEST_BIT_MAP_H
#define TEST_BIT_MAP_H
@@ -49,6 +49,8 @@ TEST_CASE("[BitMap] Create bit map") {
CHECK(bit_map.get_size() == Size2i(256, 512));
CHECK_MESSAGE(bit_map.get_true_bit_count() == 0, "This will go through the entire bitmask inside of bitmap, thus hopefully checking if the bitmask was correctly set up.");
+ ERR_PRINT_OFF
+
dim = Size2i(0, 256);
bit_map.create(dim);
CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 512), "We should still have the same dimensions as before, because the new dimension is invalid.");
@@ -60,6 +62,8 @@ TEST_CASE("[BitMap] Create bit map") {
dim = Size2i(46341, 46341);
bit_map.create(dim);
CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 512), "We should still have the same dimensions as before, because the new dimension is too large (46341*46341=2147488281).");
+
+ ERR_PRINT_ON
}
TEST_CASE("[BitMap] Create bit map from image alpha") {
@@ -67,6 +71,8 @@ TEST_CASE("[BitMap] Create bit map from image alpha") {
BitMap bit_map{};
bit_map.create(dim);
+ ERR_PRINT_OFF
+
const Ref<Image> null_img = nullptr;
bit_map.create_from_image_alpha(null_img);
CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 256), "Bitmap should have its old values because bitmap creation from a nullptr should fail.");
@@ -76,15 +82,13 @@ 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);
+ ERR_PRINT_ON
+
+ 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));
@@ -109,6 +113,8 @@ TEST_CASE("[BitMap] Set bit") {
BitMap bit_map{};
// Setting a point before a bit map is created should not crash, because there are checks to see if we are out of bounds.
+ ERR_PRINT_OFF
+
bit_map.set_bitv(Point2i(128, 128), true);
bit_map.create(dim);
@@ -124,12 +130,16 @@ TEST_CASE("[BitMap] Set bit") {
bit_map.create(dim);
bit_map.set_bitv(Point2i(512, 512), true);
CHECK_MESSAGE(bit_map.get_true_bit_count() == 0, "Nothing should change as we were trying to edit a bit outside of the correct range.");
+
+ ERR_PRINT_ON
}
TEST_CASE("[BitMap] Get bit") {
const Size2i dim{ 256, 256 };
BitMap bit_map{};
+ ERR_PRINT_OFF
+
CHECK_MESSAGE(bit_map.get_bitv(Point2i(128, 128)) == false, "Trying to access a bit outside of the BitMap's range should always return false");
bit_map.create(dim);
@@ -144,6 +154,8 @@ TEST_CASE("[BitMap] Get bit") {
CHECK(bit_map.get_bitv(Point2i(255, 255)) == true);
CHECK(bit_map.get_bitv(Point2i(256, 256)) == false);
CHECK(bit_map.get_bitv(Point2i(257, 257)) == false);
+
+ ERR_PRINT_ON
}
TEST_CASE("[BitMap] Set bit rect") {
@@ -162,6 +174,9 @@ TEST_CASE("[BitMap] Set bit rect") {
reset_bit_map(bit_map);
// Checking out of bounds handling.
+
+ ERR_PRINT_OFF
+
bit_map.set_bit_rect(Rect2i{ 128, 128, 256, 256 }, true);
CHECK(bit_map.get_true_bit_count() == 16384);
@@ -174,6 +189,8 @@ TEST_CASE("[BitMap] Set bit rect") {
bit_map.set_bit_rect(Rect2i{ -128, -128, 512, 512 }, true);
CHECK(bit_map.get_true_bit_count() == 65536);
+
+ ERR_PRINT_ON
}
TEST_CASE("[BitMap] Get true bit count") {
@@ -183,7 +200,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,12 +213,14 @@ 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));
+ ERR_PRINT_OFF
bit_map.create(Size2i(-1, 0));
+ ERR_PRINT_ON
CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 256), "Invalid size should not be accepted by create");
bit_map.create(Size2i(256, 128));
@@ -223,7 +242,9 @@ TEST_CASE("[BitMap] Resize") {
CHECK_MESSAGE(bit_map.get_true_bit_count() == 50, "There should be 25 bits in the top left corner, and 25 bits in the bottom right corner");
bit_map.create(dim);
+ ERR_PRINT_OFF
bit_map.resize(Size2i(-1, 128));
+ ERR_PRINT_ON
CHECK_MESSAGE(bit_map.get_size() == Size2i(128, 128), "When an invalid size is given the bit map will keep its size");
bit_map.create(dim);
@@ -238,7 +259,9 @@ TEST_CASE("[BitMap] Resize") {
TEST_CASE("[BitMap] Grow and shrink mask") {
const Size2i dim{ 256, 256 };
BitMap bit_map{};
- bit_map.grow_mask(100, Rect2i(0, 0, 128, 128)); // Check if method does not crash when working with an uninitialised bit map.
+ ERR_PRINT_OFF
+ bit_map.grow_mask(100, Rect2i(0, 0, 128, 128)); // Check if method does not crash when working with an uninitialized bit map.
+ ERR_PRINT_ON
CHECK_MESSAGE(bit_map.get_size() == Size2i(0, 0), "Size should still be equal to 0x0");
bit_map.create(dim);
@@ -335,25 +358,27 @@ TEST_CASE("[BitMap] Blit") {
Ref<BitMap> blit_bit_map{};
// Testing null reference to blit bit map.
+ ERR_PRINT_OFF
bit_map.blit(blit_pos, blit_bit_map);
+ ERR_PRINT_ON
blit_bit_map.instantiate();
- // Testing if uninitialised blit bit map and uninitialised bit map does not crash
+ // Testing if uninitialized blit bit map and uninitialized bit map does not crash
bit_map.blit(blit_pos, blit_bit_map);
- // Testing if uninitialised bit map does not crash
+ // Testing if uninitialized bit map does not crash
blit_bit_map->create(blit_size);
bit_map.blit(blit_pos, blit_bit_map);
- // Testing if uninitialised bit map does not crash
+ // Testing if uninitialized bit map does not crash
blit_bit_map.unref();
blit_bit_map.instantiate();
CHECK_MESSAGE(blit_bit_map->get_size() == Point2i(0, 0), "Size should be cleared by unref and instance calls.");
bit_map.create(bit_map_size);
bit_map.blit(Point2i(128, 128), blit_bit_map);
- // Testing if both initialised does not crash.
+ // Testing if both initialized does not crash.
blit_bit_map->create(blit_size);
bit_map.blit(blit_pos, blit_bit_map);
@@ -382,7 +407,9 @@ TEST_CASE("[BitMap] Convert to image") {
BitMap bit_map{};
Ref<Image> img;
+ ERR_PRINT_OFF
img = bit_map.convert_to_image();
+ ERR_PRINT_ON
CHECK_MESSAGE(img.is_valid(), "We should receive a valid Image Object even if BitMap is not created yet");
CHECK_MESSAGE(img->get_format() == Image::FORMAT_L8, "We should receive a valid Image Object even if BitMap is not created yet");
CHECK_MESSAGE(img->get_size() == (Size2i(0, 0)), "Image should have no width or height, because BitMap has not yet been created");
@@ -390,13 +417,13 @@ 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);
img = bit_map.convert_to_image();
CHECK_MESSAGE(img->get_pixel(0, 0).is_equal_approx(Color(1, 1, 1)), "BitMap's top-left quadrant is all 1's, so Image should be white");
- CHECK_MESSAGE(img->get_pixel(256, 256).is_equal_approx(Color(0, 0, 0)), "All other quadrants were 0's, so these should be black");
+ CHECK_MESSAGE(img->get_pixel(255, 255).is_equal_approx(Color(0, 0, 0)), "All other quadrants were 0's, so these should be black");
}
TEST_CASE("[BitMap] Clip to polygon") {
@@ -404,7 +431,9 @@ TEST_CASE("[BitMap] Clip to polygon") {
BitMap bit_map{};
Vector<Vector<Vector2>> polygons;
+ ERR_PRINT_OFF
polygons = bit_map.clip_opaque_to_polygons(Rect2i(0, 0, 128, 128));
+ ERR_PRINT_ON
CHECK_MESSAGE(polygons.size() == 0, "We should have no polygons, because the BitMap was not initialized");
bit_map.create(dim);
@@ -438,6 +467,37 @@ TEST_CASE("[BitMap] Clip to polygon") {
polygons = bit_map.clip_opaque_to_polygons(Rect2i(0, 0, 128, 128));
CHECK_MESSAGE(polygons.size() == 1, "We should have exactly 1 polygon");
CHECK_MESSAGE(polygons[0].size() == 6, "The polygon should have exactly 6 points");
+
+ reset_bit_map(bit_map);
+ bit_map.set_bit_rect(Rect2i(0, 0, 64, 64), true);
+ bit_map.set_bit_rect(Rect2i(64, 64, 64, 64), true);
+ bit_map.set_bit_rect(Rect2i(192, 128, 64, 64), true);
+ bit_map.set_bit_rect(Rect2i(128, 192, 64, 64), true);
+ polygons = bit_map.clip_opaque_to_polygons(Rect2i(0, 0, 256, 256));
+ CHECK_MESSAGE(polygons.size() == 4, "We should have exactly 4 polygons");
+ CHECK_MESSAGE(polygons[0].size() == 4, "The polygon should have exactly 4 points");
+ CHECK_MESSAGE(polygons[1].size() == 4, "The polygon should have exactly 4 points");
+ CHECK_MESSAGE(polygons[2].size() == 4, "The polygon should have exactly 4 points");
+ CHECK_MESSAGE(polygons[3].size() == 4, "The polygon should have exactly 4 points");
+
+ reset_bit_map(bit_map);
+ bit_map.set_bit(0, 0, true);
+ bit_map.set_bit(2, 0, true);
+ bit_map.set_bit_rect(Rect2i(1, 1, 1, 2), true);
+ polygons = bit_map.clip_opaque_to_polygons(Rect2i(0, 0, 3, 3));
+ CHECK_MESSAGE(polygons.size() == 3, "We should have exactly 3 polygons");
+ CHECK_MESSAGE(polygons[0].size() == 4, "The polygon should have exactly 4 points");
+ CHECK_MESSAGE(polygons[1].size() == 4, "The polygon should have exactly 4 points");
+ CHECK_MESSAGE(polygons[2].size() == 4, "The polygon should have exactly 4 points");
+
+ reset_bit_map(bit_map);
+ bit_map.set_bit_rect(Rect2i(0, 0, 2, 1), true);
+ bit_map.set_bit_rect(Rect2i(0, 2, 3, 1), true);
+ bit_map.set_bit(0, 1, true);
+ bit_map.set_bit(2, 1, true);
+ polygons = bit_map.clip_opaque_to_polygons(Rect2i(0, 0, 4, 4));
+ CHECK_MESSAGE(polygons.size() == 1, "We should have exactly 1 polygon");
+ CHECK_MESSAGE(polygons[0].size() == 6, "The polygon should have exactly 6 points");
}
} // namespace TestBitmap
diff --git a/tests/scene/test_code_edit.h b/tests/scene/test_code_edit.h
index 3940bdb37a..c68560000c 100644
--- a/tests/scene/test_code_edit.h
+++ b/tests/scene/test_code_edit.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* test_code_edit.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* test_code_edit.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef TEST_CODE_EDIT_H
#define TEST_CODE_EDIT_H
@@ -2871,6 +2871,89 @@ TEST_CASE("[SceneTree][CodeEdit] completion") {
CHECK(code_edit->get_text() == "\'\'\'");
}
+ SUBCASE("[CodeEdit] autocomplete with brace completion") {
+ code_edit->set_auto_brace_completion_enabled(true);
+ CHECK(code_edit->is_auto_brace_completion_enabled());
+
+ code_edit->insert_text_at_caret("(te)");
+ code_edit->set_caret_column(3);
+
+ // Full completion.
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_FUNCTION, "test()", "test()");
+ code_edit->update_code_completion_options();
+ code_edit->confirm_code_completion();
+ CHECK(code_edit->get_line(0) == "(test())");
+ CHECK(code_edit->get_caret_column() == 7);
+ code_edit->undo();
+
+ // With "arg".
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_FUNCTION, "test(", "test(");
+ code_edit->update_code_completion_options();
+ code_edit->confirm_code_completion();
+ CHECK(code_edit->get_line(0) == "(test())");
+ CHECK(code_edit->get_caret_column() == 6);
+ code_edit->undo();
+
+ // brace completion disabled
+ code_edit->set_auto_brace_completion_enabled(false);
+
+ // Full completion.
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_FUNCTION, "test()", "test()");
+ code_edit->update_code_completion_options();
+ code_edit->confirm_code_completion();
+ CHECK(code_edit->get_line(0) == "(test())");
+ CHECK(code_edit->get_caret_column() == 7);
+ code_edit->undo();
+
+ // With "arg".
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_FUNCTION, "test(", "test(");
+ code_edit->update_code_completion_options();
+ code_edit->confirm_code_completion();
+ CHECK(code_edit->get_line(0) == "(test()");
+ CHECK(code_edit->get_caret_column() == 6);
+
+ // String
+ code_edit->set_auto_brace_completion_enabled(true);
+ code_edit->clear();
+ code_edit->insert_text_at_caret("\"\"");
+ code_edit->set_caret_column(1);
+
+ // Full completion.
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_NODE_PATH, "\"test\"", "\"test\"");
+ code_edit->update_code_completion_options();
+ code_edit->confirm_code_completion();
+ CHECK(code_edit->get_line(0) == "\"test\"");
+ CHECK(code_edit->get_caret_column() == 6);
+ code_edit->undo();
+
+ // With "arg".
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_NODE_PATH, "\"test", "\"test");
+ code_edit->update_code_completion_options();
+ code_edit->confirm_code_completion();
+ CHECK(code_edit->get_line(0) == "\"\"test\"\"");
+ CHECK(code_edit->get_caret_column() == 7);
+ code_edit->undo();
+
+ // brace completion disabled
+ code_edit->set_auto_brace_completion_enabled(false);
+
+ // Full completion.
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_NODE_PATH, "\"test\"", "\"test\"");
+ code_edit->update_code_completion_options();
+ code_edit->confirm_code_completion();
+ CHECK(code_edit->get_line(0) == "\"test\"");
+ CHECK(code_edit->get_caret_column() == 6);
+ code_edit->undo();
+
+ // With "arg".
+ code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_NODE_PATH, "\"test", "\"test");
+ code_edit->update_code_completion_options();
+ code_edit->confirm_code_completion();
+ CHECK(code_edit->get_line(0) == "\"\"test\"");
+ CHECK(code_edit->get_caret_column() == 7);
+ code_edit->undo();
+ }
+
SUBCASE("[CodeEdit] autocomplete") {
code_edit->set_code_completion_enabled(true);
CHECK(code_edit->is_code_completion_enabled());
@@ -3027,15 +3110,16 @@ TEST_CASE("[SceneTree][CodeEdit] completion") {
CHECK(code_edit->get_code_completion_selected_index() == 0);
Point2 caret_pos = code_edit->get_caret_draw_pos();
- caret_pos.y -= code_edit->get_line_height();
- SEND_GUI_MOUSE_BUTTON_EVENT(code_edit, caret_pos, MouseButton::WHEEL_DOWN, MouseButton::NONE, Key::NONE);
+ caret_pos.y += code_edit->get_line_height();
+ SEND_GUI_MOUSE_BUTTON_EVENT(code_edit, caret_pos, MouseButton::WHEEL_DOWN, 0, Key::NONE);
CHECK(code_edit->get_code_completion_selected_index() == 1);
- SEND_GUI_MOUSE_BUTTON_EVENT(code_edit, caret_pos, MouseButton::WHEEL_UP, MouseButton::NONE, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(code_edit, caret_pos, MouseButton::WHEEL_UP, 0, Key::NONE);
CHECK(code_edit->get_code_completion_selected_index() == 0);
/* Single click selects. */
- SEND_GUI_MOUSE_BUTTON_EVENT(code_edit, caret_pos, MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE);
+ caret_pos.y += code_edit->get_line_height() * 2;
+ SEND_GUI_MOUSE_BUTTON_EVENT(code_edit, caret_pos, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK(code_edit->get_code_completion_selected_index() == 2);
/* Double click inserts. */
@@ -3246,7 +3330,7 @@ TEST_CASE("[SceneTree][CodeEdit] symbol lookup") {
Point2 caret_pos = code_edit->get_caret_draw_pos();
caret_pos.x += 60;
- SEND_GUI_MOUSE_BUTTON_EVENT(code_edit, caret_pos, MouseButton::NONE, MouseButton::NONE, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(code_edit, caret_pos, MouseButton::NONE, 0, Key::NONE);
CHECK(code_edit->get_text_for_symbol_lookup() == "this is s" + String::chr(0xFFFF) + "ome text");
SIGNAL_WATCH(code_edit, "symbol_validate");
diff --git a/tests/scene/test_curve.h b/tests/scene/test_curve.h
index ad7625ddc5..bfa37e8f69 100644
--- a/tests/scene/test_curve.h
+++ b/tests/scene/test_curve.h
@@ -1,36 +1,37 @@
-/*************************************************************************/
-/* test_curve.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* test_curve.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef TEST_CURVE_H
#define TEST_CURVE_H
+#include "core/math/math_funcs.h"
#include "scene/resources/curve.h"
#include "tests/test_macros.h"
@@ -83,54 +84,54 @@ TEST_CASE("[Curve] Custom curve with free tangents") {
Math::is_zero_approx(curve->sample(-0.1)),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.1), (real_t)0.352),
+ curve->sample(0.1) == doctest::Approx((real_t)0.352),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.4), (real_t)0.352),
+ curve->sample(0.4) == doctest::Approx((real_t)0.352),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.7), (real_t)0.896),
+ curve->sample(0.7) == doctest::Approx((real_t)0.896),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(1), 1),
+ curve->sample(1) == doctest::Approx(1),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(2), 1),
+ curve->sample(2) == doctest::Approx(1),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
Math::is_zero_approx(curve->sample_baked(-0.1)),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.1), (real_t)0.352),
+ curve->sample_baked(0.1) == doctest::Approx((real_t)0.352),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.4), (real_t)0.352),
+ curve->sample_baked(0.4) == doctest::Approx((real_t)0.352),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.7), (real_t)0.896),
+ curve->sample_baked(0.7) == doctest::Approx((real_t)0.896),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(1), 1),
+ curve->sample_baked(1) == doctest::Approx(1),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(2), 1),
+ curve->sample_baked(2) == doctest::Approx(1),
"Custom free curve should return the expected baked value at offset 0.1.");
curve->remove_point(1);
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.1), 0),
+ curve->sample(0.1) == doctest::Approx(0),
"Custom free curve should return the expected value at offset 0.1 after removing point at index 1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.1), 0),
+ curve->sample_baked(0.1) == doctest::Approx(0),
"Custom free curve should return the expected baked value at offset 0.1 after removing point at index 1.");
curve->clear_points();
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.6), 0),
+ curve->sample(0.6) == doctest::Approx(0),
"Custom free curve should return the expected value at offset 0.6 after clearing all points.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.6), 0),
+ curve->sample_baked(0.6) == doctest::Approx(0),
"Custom free curve should return the expected baked value at offset 0.6 after clearing all points.");
}
@@ -143,7 +144,7 @@ TEST_CASE("[Curve] Custom curve with linear tangents") {
curve->add_point(Vector2(0.75, 1), 0, 0, Curve::TangentMode::TANGENT_LINEAR, Curve::TangentMode::TANGENT_LINEAR);
CHECK_MESSAGE(
- Math::is_equal_approx(curve->get_point_left_tangent(3), 4),
+ curve->get_point_left_tangent(3) == doctest::Approx(4),
"get_point_left_tangent() should return the expected value for point index 3.");
CHECK_MESSAGE(
Math::is_zero_approx(curve->get_point_right_tangent(3)),
@@ -172,48 +173,48 @@ TEST_CASE("[Curve] Custom curve with linear tangents") {
Math::is_zero_approx(curve->sample(-0.1)),
"Custom linear curve should return the expected value at offset -0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.1), (real_t)0.4),
+ curve->sample(0.1) == doctest::Approx((real_t)0.4),
"Custom linear curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.4), (real_t)0.4),
+ curve->sample(0.4) == doctest::Approx((real_t)0.4),
"Custom linear curve should return the expected value at offset 0.4.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.7), (real_t)0.8),
+ curve->sample(0.7) == doctest::Approx((real_t)0.8),
"Custom linear curve should return the expected value at offset 0.7.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(1), 1),
+ curve->sample(1) == doctest::Approx(1),
"Custom linear curve should return the expected value at offset 1.0.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(2), 1),
+ curve->sample(2) == doctest::Approx(1),
"Custom linear curve should return the expected value at offset 2.0.");
CHECK_MESSAGE(
Math::is_zero_approx(curve->sample_baked(-0.1)),
"Custom linear curve should return the expected baked value at offset -0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.1), (real_t)0.4),
+ curve->sample_baked(0.1) == doctest::Approx((real_t)0.4),
"Custom linear curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.4), (real_t)0.4),
+ curve->sample_baked(0.4) == doctest::Approx((real_t)0.4),
"Custom linear curve should return the expected baked value at offset 0.4.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.7), (real_t)0.8),
+ curve->sample_baked(0.7) == doctest::Approx((real_t)0.8),
"Custom linear curve should return the expected baked value at offset 0.7.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(1), 1),
+ curve->sample_baked(1) == doctest::Approx(1),
"Custom linear curve should return the expected baked value at offset 1.0.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(2), 1),
+ curve->sample_baked(2) == doctest::Approx(1),
"Custom linear curve should return the expected baked value at offset 2.0.");
ERR_PRINT_OFF;
curve->remove_point(10);
ERR_PRINT_ON;
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.7), (real_t)0.8),
+ curve->sample(0.7) == doctest::Approx((real_t)0.8),
"Custom free curve should return the expected value at offset 0.7 after removing point at invalid index 10.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.7), (real_t)0.8),
+ curve->sample_baked(0.7) == doctest::Approx((real_t)0.8),
"Custom free curve should return the expected baked value at offset 0.7 after removing point at invalid index 10.");
}
@@ -229,7 +230,7 @@ TEST_CASE("[Curve2D] Linear sampling should return exact value") {
for (int i = 0; i < len; i++) {
Vector2 pos = curve->sample_baked(i);
- CHECK_MESSAGE(pos.x == i, "sample_baked should return exact value");
+ CHECK_MESSAGE(Math::is_equal_approx(pos.x, i), "sample_baked should return exact value");
}
}
@@ -239,13 +240,14 @@ TEST_CASE("[Curve3D] Linear sampling should return exact value") {
curve->add_point(Vector3(0, 0, 0));
curve->add_point(Vector3(len, 0, 0));
-
+ ERR_PRINT_OFF
real_t baked_length = curve->get_baked_length();
+ ERR_PRINT_ON
CHECK(len == baked_length);
for (int i = 0; i < len; i++) {
Vector3 pos = curve->sample_baked(i);
- CHECK_MESSAGE(pos.x == i, "sample_baked should return exact value");
+ CHECK_MESSAGE(Math::is_equal_approx(pos.x, i), "sample_baked should return exact value");
}
}
diff --git a/tests/scene/test_gradient.h b/tests/scene/test_gradient.h
index b0e6128932..4fbdaa8125 100644
--- a/tests/scene/test_gradient.h
+++ b/tests/scene/test_gradient.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* test_gradient.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* test_gradient.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef TEST_GRADIENT_H
#define TEST_GRADIENT_H
@@ -42,7 +42,7 @@ TEST_CASE("[Gradient] Default gradient") {
Ref<Gradient> gradient = memnew(Gradient);
CHECK_MESSAGE(
- gradient->get_points_count() == 2,
+ gradient->get_point_count() == 2,
"Default gradient should contain the expected number of points.");
CHECK_MESSAGE(
@@ -77,7 +77,7 @@ TEST_CASE("[Gradient] Custom gradient (points specified in order)") {
gradient->set_points(points);
CHECK_MESSAGE(
- gradient->get_points_count() == 3,
+ gradient->get_point_count() == 3,
"Custom gradient should contain the expected number of points.");
CHECK_MESSAGE(
@@ -98,7 +98,7 @@ TEST_CASE("[Gradient] Custom gradient (points specified in order)") {
gradient->remove_point(1);
CHECK_MESSAGE(
- gradient->get_points_count() == 2,
+ gradient->get_point_count() == 2,
"Custom gradient should contain the expected number of points after removing one point.");
CHECK_MESSAGE(
gradient->get_color_at_offset(0.5).is_equal_approx(Color(0.5, 1, 0)),
@@ -119,7 +119,7 @@ TEST_CASE("[Gradient] Custom gradient (points specified out-of-order)") {
gradient->set_points(points);
CHECK_MESSAGE(
- gradient->get_points_count() == 6,
+ gradient->get_point_count() == 6,
"Custom out-of-order gradient should contain the expected number of points.");
CHECK_MESSAGE(
@@ -137,7 +137,7 @@ TEST_CASE("[Gradient] Custom gradient (points specified out-of-order)") {
gradient->remove_point(0);
CHECK_MESSAGE(
- gradient->get_points_count() == 5,
+ gradient->get_point_count() == 5,
"Custom out-of-order gradient should contain the expected number of points after removing one point.");
// The color will be clamped to the nearest point (which is at offset 0.2).
CHECK_MESSAGE(
diff --git a/tests/scene/test_node.h b/tests/scene/test_node.h
new file mode 100644
index 0000000000..20c42d9fc2
--- /dev/null
+++ b/tests/scene/test_node.h
@@ -0,0 +1,415 @@
+/**************************************************************************/
+/* test_node.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef TEST_NODE_H
+#define TEST_NODE_H
+
+#include "scene/main/node.h"
+
+#include "tests/test_macros.h"
+
+namespace TestNode {
+
+TEST_CASE("[SceneTree][Node] Simple Add/Remove/Move/Find") {
+ Node *node = memnew(Node);
+
+ // Check initial scene tree setup.
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 0);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 1);
+
+ // Check initial node setup.
+ CHECK(node->get_name() == StringName());
+ CHECK_FALSE(node->is_inside_tree());
+ CHECK_EQ(node->get_parent(), nullptr);
+ ERR_PRINT_OFF;
+ CHECK(node->get_path().is_empty());
+ ERR_PRINT_ON;
+ CHECK_EQ(node->get_child_count(), 0);
+
+ SceneTree::get_singleton()->get_root()->add_child(node);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 1);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 2);
+
+ CHECK(node->get_name() != StringName());
+ CHECK(node->is_inside_tree());
+ CHECK_EQ(SceneTree::get_singleton()->get_root(), node->get_parent());
+ CHECK_FALSE(node->get_path().is_empty());
+ CHECK_EQ(node->get_child_count(), 0);
+
+ SUBCASE("Node should be accessible as first child") {
+ Node *child = SceneTree::get_singleton()->get_root()->get_child(0);
+ CHECK_EQ(child, node);
+ }
+
+ SUBCASE("Node should be accessible via the node path") {
+ Node *child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node->get_path());
+ CHECK_EQ(child_by_path, node);
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("Node"));
+ CHECK_EQ(child_by_path, nullptr);
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("/root/Node"));
+ CHECK_EQ(child_by_path, nullptr);
+
+ node->set_name("Node");
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node->get_path());
+ CHECK_EQ(child_by_path, node);
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("Node"));
+ CHECK_EQ(child_by_path, node);
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("/root/Node"));
+ CHECK_EQ(child_by_path, node);
+ }
+
+ SUBCASE("Node should be accessible via group") {
+ List<Node *> nodes;
+ SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes);
+ CHECK(nodes.is_empty());
+
+ node->add_to_group("nodes");
+
+ SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes);
+ CHECK_EQ(nodes.size(), 1);
+ List<Node *>::Element *E = nodes.front();
+ CHECK_EQ(E->get(), node);
+ }
+
+ SUBCASE("Node should be possible to find") {
+ Node *child = SceneTree::get_singleton()->get_root()->find_child("Node", true, false);
+ CHECK_EQ(child, nullptr);
+
+ node->set_name("Node");
+
+ child = SceneTree::get_singleton()->get_root()->find_child("Node", true, false);
+ CHECK_EQ(child, node);
+ }
+
+ SUBCASE("Node should be possible to remove") {
+ SceneTree::get_singleton()->get_root()->remove_child(node);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 0);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 1);
+
+ CHECK_FALSE(node->is_inside_tree());
+ CHECK_EQ(node->get_parent(), nullptr);
+ ERR_PRINT_OFF;
+ CHECK(node->get_path().is_empty());
+ ERR_PRINT_ON;
+ }
+
+ SUBCASE("Node should be possible to move") {
+ SceneTree::get_singleton()->get_root()->move_child(node, 0);
+
+ Node *child = SceneTree::get_singleton()->get_root()->get_child(0);
+ CHECK_EQ(child, node);
+ CHECK(node->is_inside_tree());
+ }
+
+ memdelete(node);
+}
+
+TEST_CASE("[SceneTree][Node] Nested Add/Remove/Move/Find") {
+ Node *node1 = memnew(Node);
+ Node *node2 = memnew(Node);
+ Node *node1_1 = memnew(Node);
+
+ SceneTree::get_singleton()->get_root()->add_child(node1);
+ SceneTree::get_singleton()->get_root()->add_child(node2);
+
+ node1->add_child(node1_1);
+
+ CHECK(node1_1->is_inside_tree());
+ CHECK_EQ(node1_1->get_parent(), node1);
+ CHECK_EQ(node1->get_child_count(), 1);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 2);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4);
+
+ SUBCASE("Nodes should be accessible via get_child(..)") {
+ Node *child1 = SceneTree::get_singleton()->get_root()->get_child(0);
+ CHECK_EQ(child1, node1);
+
+ Node *child2 = SceneTree::get_singleton()->get_root()->get_child(1);
+ CHECK_EQ(child2, node2);
+
+ Node *child1_1 = node1->get_child(0);
+ CHECK_EQ(child1_1, node1_1);
+ }
+
+ SUBCASE("Removed nodes should also remove their children from the scene tree") {
+ // Should also remove node1_1 from the scene tree.
+ SceneTree::get_singleton()->get_root()->remove_child(node1);
+
+ CHECK_EQ(node1->get_child_count(), 1);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 1);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 2);
+
+ // First child should now be the second node.
+ Node *child1 = SceneTree::get_singleton()->get_root()->get_child(0);
+ CHECK_EQ(child1, node2);
+ }
+
+ SUBCASE("Removed children nodes should not affect their parent in the scene tree") {
+ node1->remove_child(node1_1);
+
+ CHECK_EQ(node1_1->get_parent(), nullptr);
+ CHECK_EQ(node1->get_child_count(), 0);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 3);
+ }
+
+ SUBCASE("Nodes should be in the expected order when a node is moved to the back") {
+ SceneTree::get_singleton()->get_root()->move_child(node1, 1);
+
+ Node *child1 = SceneTree::get_singleton()->get_root()->get_child(0);
+ CHECK_EQ(child1, node2);
+
+ Node *child2 = SceneTree::get_singleton()->get_root()->get_child(1);
+ CHECK_EQ(child2, node1);
+ }
+
+ SUBCASE("Nodes should be in the expected order when a node is moved to the front") {
+ SceneTree::get_singleton()->get_root()->move_child(node2, 0);
+
+ Node *child1 = SceneTree::get_singleton()->get_root()->get_child(0);
+ CHECK_EQ(child1, node2);
+
+ Node *child2 = SceneTree::get_singleton()->get_root()->get_child(1);
+ CHECK_EQ(child2, node1);
+ }
+
+ SUBCASE("Nodes should be in the expected order when reparented") {
+ CHECK_EQ(node2->get_child_count(), 0);
+
+ node1->remove_child(node1_1);
+ CHECK_EQ(node1->get_child_count(), 0);
+ CHECK_EQ(node1_1->get_parent(), nullptr);
+
+ node2->add_child(node1_1);
+ CHECK_EQ(node2->get_child_count(), 1);
+ CHECK_EQ(node1_1->get_parent(), node2);
+
+ Node *child = node2->get_child(0);
+ CHECK_EQ(child, node1_1);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 2);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4);
+ }
+
+ SUBCASE("Nodes should be possible to find") {
+ Node *child = SceneTree::get_singleton()->get_root()->find_child("NestedNode", true, false);
+ CHECK_EQ(child, nullptr);
+
+ node1->set_name("Node1");
+ node2->set_name("Node2");
+ node1_1->set_name("NestedNode");
+
+ child = SceneTree::get_singleton()->get_root()->find_child("NestedNode", true, false);
+ CHECK_EQ(child, node1_1);
+
+ // First node that matches with the name is node1.
+ child = SceneTree::get_singleton()->get_root()->find_child("Node?", true, false);
+ CHECK_EQ(child, node1);
+
+ SceneTree::get_singleton()->get_root()->move_child(node2, 0);
+
+ // It should be node2, as it is now the first one in the tree.
+ child = SceneTree::get_singleton()->get_root()->find_child("Node?", true, false);
+ CHECK_EQ(child, node2);
+ }
+
+ SUBCASE("Nodes should be accessible via their node path") {
+ Node *child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node1->get_path());
+ CHECK_EQ(child_by_path, node1);
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node2->get_path());
+ CHECK_EQ(child_by_path, node2);
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node1_1->get_path());
+ CHECK_EQ(child_by_path, node1_1);
+
+ node1->set_name("Node1");
+ node1_1->set_name("NestedNode");
+
+ child_by_path = node1->get_node_or_null(NodePath("NestedNode"));
+ CHECK_EQ(child_by_path, node1_1);
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("/root/Node1/NestedNode"));
+ CHECK_EQ(child_by_path, node1_1);
+
+ child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("Node1/NestedNode"));
+ CHECK_EQ(child_by_path, node1_1);
+ }
+
+ SUBCASE("Nodes should be accessible via their groups") {
+ List<Node *> nodes;
+ SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes);
+ CHECK(nodes.is_empty());
+
+ SceneTree::get_singleton()->get_nodes_in_group("other_nodes", &nodes);
+ CHECK(nodes.is_empty());
+
+ node1->add_to_group("nodes");
+ node2->add_to_group("other_nodes");
+ node1_1->add_to_group("nodes");
+ node1_1->add_to_group("other_nodes");
+
+ SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes);
+ CHECK_EQ(nodes.size(), 2);
+
+ List<Node *>::Element *E = nodes.front();
+ CHECK_EQ(E->get(), node1);
+ E = E->next();
+ CHECK_EQ(E->get(), node1_1);
+
+ // Clear and try again with the other group.
+ nodes.clear();
+
+ SceneTree::get_singleton()->get_nodes_in_group("other_nodes", &nodes);
+ CHECK_EQ(nodes.size(), 2);
+
+ E = nodes.front();
+ CHECK_EQ(E->get(), node1_1);
+ E = E->next();
+ CHECK_EQ(E->get(), node2);
+
+ // Clear and try again with the other group and one node removed.
+ nodes.clear();
+
+ node1->remove_from_group("nodes");
+ SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes);
+ CHECK_EQ(nodes.size(), 1);
+
+ E = nodes.front();
+ CHECK_EQ(E->get(), node1_1);
+ }
+
+ memdelete(node1_1);
+ memdelete(node1);
+ memdelete(node2);
+}
+
+TEST_CASE("[Node] Processing") {
+ Node *node = memnew(Node);
+
+ SUBCASE("Processing") {
+ CHECK_FALSE(node->is_processing());
+
+ node->set_process(true);
+
+ CHECK(node->is_processing());
+
+ node->set_process(false);
+
+ CHECK_FALSE(node->is_processing());
+ }
+
+ SUBCASE("Physics processing") {
+ CHECK_FALSE(node->is_physics_processing());
+
+ node->set_physics_process(true);
+
+ CHECK(node->is_physics_processing());
+
+ node->set_physics_process(false);
+
+ CHECK_FALSE(node->is_physics_processing());
+ }
+
+ SUBCASE("Unhandled input processing") {
+ CHECK_FALSE(node->is_processing_unhandled_input());
+
+ node->set_process_unhandled_input(true);
+
+ CHECK(node->is_processing_unhandled_input());
+
+ node->set_process_unhandled_input(false);
+
+ CHECK_FALSE(node->is_processing_unhandled_input());
+ }
+
+ SUBCASE("Input processing") {
+ CHECK_FALSE(node->is_processing_input());
+
+ node->set_process_input(true);
+
+ CHECK(node->is_processing_input());
+
+ node->set_process_input(false);
+
+ CHECK_FALSE(node->is_processing_input());
+ }
+
+ SUBCASE("Unhandled key input processing") {
+ CHECK_FALSE(node->is_processing_unhandled_key_input());
+
+ node->set_process_unhandled_key_input(true);
+
+ CHECK(node->is_processing_unhandled_key_input());
+
+ node->set_process_unhandled_key_input(false);
+
+ CHECK_FALSE(node->is_processing_unhandled_key_input());
+ }
+
+ SUBCASE("Shortcut input processing") {
+ CHECK_FALSE(node->is_processing_shortcut_input());
+
+ node->set_process_shortcut_input(true);
+
+ CHECK(node->is_processing_shortcut_input());
+
+ node->set_process_shortcut_input(false);
+
+ CHECK_FALSE(node->is_processing_shortcut_input());
+ }
+
+ SUBCASE("Internal processing") {
+ CHECK_FALSE(node->is_processing_internal());
+
+ node->set_process_internal(true);
+
+ CHECK(node->is_processing_internal());
+
+ node->set_process_internal(false);
+
+ CHECK_FALSE(node->is_processing_internal());
+ }
+
+ memdelete(node);
+}
+
+} // namespace TestNode
+
+#endif // TEST_NODE_H
diff --git a/tests/scene/test_path_2d.h b/tests/scene/test_path_2d.h
new file mode 100644
index 0000000000..7b6cec96db
--- /dev/null
+++ b/tests/scene/test_path_2d.h
@@ -0,0 +1,109 @@
+/**************************************************************************/
+/* test_path_2d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef TEST_PATH_2D_H
+#define TEST_PATH_2D_H
+
+#include "scene/2d/path_2d.h"
+
+#include "tests/test_macros.h"
+
+namespace TestPath2D {
+
+TEST_CASE("[SceneTree][Path2D] Initialization") {
+ SUBCASE("Path should be empty right after initialization") {
+ Path2D *test_path = memnew(Path2D);
+ CHECK(test_path->get_curve() == nullptr);
+ memdelete(test_path);
+ }
+}
+
+TEST_CASE("[SceneTree][Path2D] Curve setter and getter") {
+ Path2D *test_path = memnew(Path2D);
+ const Ref<Curve2D> &curve = memnew(Curve2D);
+
+ SUBCASE("Curve passed to the class should remain the same") {
+ test_path->set_curve(curve);
+ CHECK(test_path->get_curve() == curve);
+ }
+ SUBCASE("Curve passed many times to the class should remain the same") {
+ test_path->set_curve(curve);
+ test_path->set_curve(curve);
+ test_path->set_curve(curve);
+ CHECK(test_path->get_curve() == curve);
+ }
+ SUBCASE("Curve rewrite testing") {
+ const Ref<Curve2D> &curve1 = memnew(Curve2D);
+ const Ref<Curve2D> &curve2 = memnew(Curve2D);
+
+ test_path->set_curve(curve1);
+ test_path->set_curve(curve2);
+ CHECK_MESSAGE(test_path->get_curve() != curve1,
+ "After rewrite, second curve should be in class");
+ CHECK_MESSAGE(test_path->get_curve() == curve2,
+ "After rewrite, second curve should be in class");
+ }
+
+ SUBCASE("Assign same curve to two paths") {
+ Path2D *path2 = memnew(Path2D);
+
+ test_path->set_curve(curve);
+ path2->set_curve(curve);
+ CHECK_MESSAGE(test_path->get_curve() == path2->get_curve(),
+ "Both paths have the same curve.");
+ memdelete(path2);
+ }
+
+ SUBCASE("Swapping curves between two paths") {
+ Path2D *path2 = memnew(Path2D);
+ const Ref<Curve2D> &curve1 = memnew(Curve2D);
+ const Ref<Curve2D> &curve2 = memnew(Curve2D);
+
+ test_path->set_curve(curve1);
+ path2->set_curve(curve2);
+ CHECK(test_path->get_curve() == curve1);
+ CHECK(path2->get_curve() == curve2);
+
+ // Do the swap
+ Ref<Curve2D> temp = test_path->get_curve();
+ test_path->set_curve(path2->get_curve());
+ path2->set_curve(temp);
+
+ CHECK(test_path->get_curve() == curve2);
+ CHECK(path2->get_curve() == curve1);
+ memdelete(path2);
+ }
+
+ memdelete(test_path);
+}
+
+} // namespace TestPath2D
+
+#endif // TEST_PATH_2D_H
diff --git a/tests/scene/test_path_3d.h b/tests/scene/test_path_3d.h
index 8ac3d7b5b4..f779f514a4 100644
--- a/tests/scene/test_path_3d.h
+++ b/tests/scene/test_path_3d.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* test_path_3d.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* test_path_3d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef TEST_PATH_3D_H
#define TEST_PATH_3D_H
diff --git a/tests/scene/test_path_follow_2d.h b/tests/scene/test_path_follow_2d.h
index 57261116a2..1958befa18 100644
--- a/tests/scene/test_path_follow_2d.h
+++ b/tests/scene/test_path_follow_2d.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* test_path_follow_2d.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* test_path_follow_2d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef TEST_PATH_FOLLOW_2D_H
#define TEST_PATH_FOLLOW_2D_H
diff --git a/tests/scene/test_path_follow_3d.h b/tests/scene/test_path_follow_3d.h
index 6334fa56de..7595fddd2f 100644
--- a/tests/scene/test_path_follow_3d.h
+++ b/tests/scene/test_path_follow_3d.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* test_path_follow_3d.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* test_path_follow_3d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef TEST_PATH_FOLLOW_3D_H
#define TEST_PATH_FOLLOW_3D_H
diff --git a/tests/scene/test_primitives.h b/tests/scene/test_primitives.h
new file mode 100644
index 0000000000..6cdb5fb0a5
--- /dev/null
+++ b/tests/scene/test_primitives.h
@@ -0,0 +1,850 @@
+/**************************************************************************/
+/* test_primitives.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef TEST_PRIMITIVES_H
+#define TEST_PRIMITIVES_H
+
+#include "scene/resources/primitive_meshes.h"
+
+#include "tests/test_macros.h"
+
+namespace TestPrimitives {
+
+TEST_CASE("[SceneTree][Primitive][Capsule] Capsule Primitive") {
+ Ref<CapsuleMesh> capsule = memnew(CapsuleMesh);
+
+ SUBCASE("[SceneTree][Primitive][Capsule] Default values should be valid") {
+ CHECK_MESSAGE(capsule->get_radius() > 0,
+ "Radius of default capsule positive.");
+ CHECK_MESSAGE(capsule->get_height() > 0,
+ "Height of default capsule positive.");
+ CHECK_MESSAGE(capsule->get_radial_segments() >= 0,
+ "Radius Segments of default capsule positive.");
+ CHECK_MESSAGE(capsule->get_rings() >= 0,
+ "Number of rings of default capsule positive.");
+ }
+
+ SUBCASE("[SceneTree][Primitive][Capsule] Set properties of the capsule and get them with accessor methods") {
+ capsule->set_height(7.1f);
+ capsule->set_radius(1.3f);
+ capsule->set_radial_segments(16);
+ capsule->set_rings(32);
+
+ CHECK_MESSAGE(capsule->get_radius() == doctest::Approx(1.3f),
+ "Get/Set radius work with one set.");
+ CHECK_MESSAGE(capsule->get_height() == doctest::Approx(7.1f),
+ "Get/Set radius work with one set.");
+ CHECK_MESSAGE(capsule->get_radial_segments() == 16,
+ "Get/Set radius work with one set.");
+ CHECK_MESSAGE(capsule->get_rings() == 32,
+ "Get/Set radius work with one set.");
+ }
+
+ SUBCASE("[SceneTree][Primitive][Capsule] If set segments negative, default to at least 0") {
+ capsule->set_radial_segments(-5);
+ capsule->set_rings(-17);
+
+ CHECK_MESSAGE(capsule->get_radial_segments() >= 0,
+ "Ensure number of radial segments is >= 0.");
+ CHECK_MESSAGE(capsule->get_rings() >= 0,
+ "Ensure number of rings is >= 0.");
+ }
+
+ SUBCASE("[SceneTree][Primitive][Capsule] If set height < 2*radius, adjust radius and height to radius=height*0.5") {
+ capsule->set_radius(1.f);
+ capsule->set_height(0.5f);
+
+ CHECK_MESSAGE(capsule->get_radius() >= capsule->get_height() * 0.5,
+ "Ensure radius >= height * 0.5 (needed for capsule to exist).");
+ }
+
+ SUBCASE("[Primitive][Capsule] Check mesh is correct") {
+ Array data{};
+ data.resize(RS::ARRAY_MAX);
+ float radius{ 0.5f };
+ float height{ 4.f };
+ int num_radial_segments{ 4 };
+ int num_rings{ 8 };
+ CapsuleMesh::create_mesh_array(data, radius, height, num_radial_segments, num_rings);
+ Vector<Vector3> points = data[RS::ARRAY_VERTEX];
+
+ SUBCASE("[Primitive][Capsule] Ensure all vertices positions are within bounding radius and height") {
+ // Get mesh data
+
+ // Check all points within radius of capsule
+ float dist_to_yaxis = 0.f;
+ for (Vector3 point : points) {
+ float new_dist_to_y = point.x * point.x + point.z * point.z;
+ if (new_dist_to_y > dist_to_yaxis)
+ dist_to_yaxis = new_dist_to_y;
+ }
+
+ CHECK(dist_to_yaxis <= radius * radius);
+
+ // Check highest point and lowest point are within height of each other
+ float max_y{ 0.f };
+ float min_y{ 0.f };
+ for (Vector3 point : points) {
+ if (point.y > max_y)
+ max_y = point.y;
+ if (point.y < min_y)
+ min_y = point.y;
+ }
+
+ CHECK(max_y - min_y <= height);
+ }
+
+ SUBCASE("[Primitive][Capsule] If normal.y == 0, then mesh makes a cylinder.") {
+ Vector<Vector3> normals = data[RS::ARRAY_NORMAL];
+ for (int ii = 0; ii < points.size(); ++ii) {
+ float point_dist_from_yaxis = Math::sqrt(points[ii].x * points[ii].x + points[ii].z * points[ii].z);
+ Vector3 yaxis_to_point{ points[ii].x / point_dist_from_yaxis, 0.f, points[ii].z / point_dist_from_yaxis };
+ if (normals[ii].y == 0.f) {
+ float mag_of_normal = Math::sqrt(normals[ii].x * normals[ii].x + normals[ii].z * normals[ii].z);
+ Vector3 normalized_normal = normals[ii] / mag_of_normal;
+ CHECK_MESSAGE(point_dist_from_yaxis == doctest::Approx(radius),
+ "Points on the tube of the capsule are radius away from y-axis.");
+ CHECK_MESSAGE(normalized_normal.is_equal_approx(yaxis_to_point),
+ "Normal points orthogonal from mid cylinder.");
+ }
+ }
+ }
+ }
+} // End capsule tests
+
+TEST_CASE("[SceneTree][Primitive][Box] Box Primitive") {
+ Ref<BoxMesh> box = memnew(BoxMesh);
+
+ SUBCASE("[SceneTree][Primitive][Box] Default values should be valid") {
+ CHECK(box->get_size().x > 0);
+ CHECK(box->get_size().y > 0);
+ CHECK(box->get_size().z > 0);
+ CHECK(box->get_subdivide_width() >= 0);
+ CHECK(box->get_subdivide_height() >= 0);
+ CHECK(box->get_subdivide_depth() >= 0);
+ }
+
+ SUBCASE("[SceneTree][Primitive][Box] Set properties and get them with accessor methods") {
+ Vector3 size{ 2.1, 3.3, 1.7 };
+ box->set_size(size);
+ box->set_subdivide_width(3);
+ box->set_subdivide_height(2);
+ box->set_subdivide_depth(4);
+
+ CHECK(box->get_size().is_equal_approx(size));
+ CHECK(box->get_subdivide_width() == 3);
+ CHECK(box->get_subdivide_height() == 2);
+ CHECK(box->get_subdivide_depth() == 4);
+ }
+
+ SUBCASE("[SceneTree][Primitive][Box] Set subdivides to negative and ensure they are >= 0") {
+ box->set_subdivide_width(-2);
+ box->set_subdivide_height(-2);
+ box->set_subdivide_depth(-2);
+
+ CHECK(box->get_subdivide_width() >= 0);
+ CHECK(box->get_subdivide_height() >= 0);
+ CHECK(box->get_subdivide_depth() >= 0);
+ }
+
+ SUBCASE("[Primitive][Box] Check mesh is correct.") {
+ Array data{};
+ data.resize(RS::ARRAY_MAX);
+ Vector3 size{ 0.5f, 1.2f, .9f };
+ int subdivide_width{ 3 };
+ int subdivide_height{ 2 };
+ int subdivide_depth{ 8 };
+ BoxMesh::create_mesh_array(data, size, subdivide_width, subdivide_height, subdivide_depth);
+ Vector<Vector3> points = data[RS::ARRAY_VERTEX];
+ Vector<Vector3> normals = data[RS::ARRAY_NORMAL];
+
+ SUBCASE("Only 6 distinct normals.") {
+ Vector<Vector3> distinct_normals{};
+ distinct_normals.push_back(normals[0]);
+
+ for (const Vector3 &normal : normals) {
+ bool add_normal{ true };
+ for (const Vector3 &vec : distinct_normals) {
+ if (vec.is_equal_approx(normal))
+ add_normal = false;
+ }
+
+ if (add_normal)
+ distinct_normals.push_back(normal);
+ }
+
+ CHECK_MESSAGE(distinct_normals.size() == 6,
+ "There are exactly 6 distinct normals in the mesh data.");
+
+ // All normals are orthogonal, or pointing in same direction.
+ bool normal_correct_direction{ true };
+ for (int rowIndex = 0; rowIndex < distinct_normals.size(); ++rowIndex) {
+ for (int colIndex = rowIndex + 1; colIndex < distinct_normals.size(); ++colIndex) {
+ if (!Math::is_equal_approx(distinct_normals[rowIndex].normalized().dot(distinct_normals[colIndex].normalized()), 0) &&
+ !Math::is_equal_approx(distinct_normals[rowIndex].normalized().dot(distinct_normals[colIndex].normalized()), 1) &&
+ !Math::is_equal_approx(distinct_normals[rowIndex].normalized().dot(distinct_normals[colIndex].normalized()), -1)) {
+ normal_correct_direction = false;
+ break;
+ }
+ }
+ if (!normal_correct_direction)
+ break;
+ }
+
+ CHECK_MESSAGE(normal_correct_direction,
+ "All normals are either orthogonal or colinear.");
+ }
+ }
+} // End box tests
+
+TEST_CASE("[SceneTree][Primitive][Cylinder] Cylinder Primitive") {
+ Ref<CylinderMesh> cylinder = memnew(CylinderMesh);
+
+ SUBCASE("[SceneTree][Primitive][Cylinder] Default values should be valid") {
+ CHECK(cylinder->get_top_radius() > 0);
+ CHECK(cylinder->get_bottom_radius() > 0);
+ CHECK(cylinder->get_height() > 0);
+ CHECK(cylinder->get_radial_segments() > 0);
+ CHECK(cylinder->get_rings() > 0);
+ }
+
+ SUBCASE("[SceneTree][Primitive][Cylinder] Set properties and get them") {
+ cylinder->set_top_radius(4.3f);
+ cylinder->set_bottom_radius(1.2f);
+ cylinder->set_height(9.77f);
+ cylinder->set_radial_segments(12);
+ cylinder->set_rings(16);
+ cylinder->set_cap_top(false);
+ cylinder->set_cap_bottom(false);
+
+ CHECK(cylinder->get_top_radius() == doctest::Approx(4.3f));
+ CHECK(cylinder->get_bottom_radius() == doctest::Approx(1.2f));
+ CHECK(cylinder->get_height() == doctest::Approx(9.77f));
+ CHECK(cylinder->get_radial_segments() == 12);
+ CHECK(cylinder->get_rings() == 16);
+ CHECK(!cylinder->is_cap_top());
+ CHECK(!cylinder->is_cap_bottom());
+ }
+
+ SUBCASE("[SceneTree][Primitive][Cylinder] Ensure num segments is >= 0") {
+ cylinder->set_radial_segments(-12);
+ cylinder->set_rings(-16);
+
+ CHECK(cylinder->get_radial_segments() >= 0);
+ CHECK(cylinder->get_rings() >= 0);
+ }
+
+ SUBCASE("[Primitive][Cylinder] Actual cylinder mesh tests (top and bottom radius the same).") {
+ Array data{};
+ data.resize(RS::ARRAY_MAX);
+ real_t radius = .9f;
+ real_t height = 3.2f;
+ int radial_segments = 8;
+ int rings = 5;
+ bool top_cap = true;
+ bool bottom_cap = true;
+ CylinderMesh::create_mesh_array(data, radius, radius, height, radial_segments, rings, top_cap, bottom_cap);
+ Vector<Vector3> points = data[RS::ARRAY_VERTEX];
+ Vector<Vector3> normals = data[RS::ARRAY_NORMAL];
+
+ SUBCASE("[Primitive][Cylinder] Side points are radius away from y-axis.") {
+ bool is_radius_correct{ true };
+ for (int index = 0; index < normals.size(); ++index) {
+ if (Math::is_equal_approx(normals[index].y, 0)) {
+ if (!Math::is_equal_approx((points[index] - Vector3(0, points[index].y, 0)).length_squared(), radius * radius)) {
+ is_radius_correct = false;
+ break;
+ }
+ }
+ }
+
+ CHECK(is_radius_correct);
+ }
+
+ SUBCASE("[Primitive][Cylinder] Only possible normals point in direction of point or in positive/negative y direction.") {
+ bool is_correct_normals{ true };
+ for (int index = 0; index < normals.size(); ++index) {
+ Vector3 yaxis_to_point = points[index] - Vector3(0.f, points[index].y, 0.f);
+ Vector3 point_to_normal = normals[index].normalized() - yaxis_to_point.normalized();
+ // std::cout << "<" << point_to_normal.x << ", " << point_to_normal.y << ", " << point_to_normal.z << ">\n";
+ if (!(point_to_normal.is_equal_approx(Vector3(0, 0, 0))) &&
+ (!Math::is_equal_approx(Math::abs(normals[index].normalized().y), 1))) {
+ is_correct_normals = false;
+ break;
+ }
+ }
+
+ CHECK(is_correct_normals);
+ }
+
+ SUBCASE("[Primitive][Cylinder] Points on top and bottom are height/2 away from origin.") {
+ bool is_height_correct{ true };
+ real_t half_height = 0.5 * height;
+ for (int index = 0; index < normals.size(); ++index) {
+ if (Math::is_equal_approx(normals[index].x, 0) &&
+ Math::is_equal_approx(normals[index].z, 0) &&
+ normals[index].y > 0) {
+ if (!Math::is_equal_approx(points[index].y, half_height)) {
+ is_height_correct = false;
+ break;
+ }
+ }
+ if (Math::is_equal_approx(normals[index].x, 0) &&
+ Math::is_equal_approx(normals[index].z, 0) &&
+ normals[index].y < 0) {
+ if (!Math::is_equal_approx(points[index].y, -half_height)) {
+ is_height_correct = false;
+ break;
+ }
+ }
+ }
+
+ CHECK(is_height_correct);
+ }
+
+ SUBCASE("[Primitive][Cylinder] Does mesh obey cap parameters?") {
+ CylinderMesh::create_mesh_array(data, radius, radius, height, radial_segments, rings, top_cap, false);
+ points = data[RS::ARRAY_VERTEX];
+ normals = data[RS::ARRAY_NORMAL];
+ bool no_bottom_cap{ true };
+
+ for (int index = 0; index < normals.size(); ++index) {
+ if (Math::is_equal_approx(normals[index].x, 0) &&
+ Math::is_equal_approx(normals[index].z, 0) &&
+ normals[index].y < 0) {
+ no_bottom_cap = false;
+ break;
+ }
+ }
+
+ CHECK_MESSAGE(no_bottom_cap,
+ "Check there is no bottom cap.");
+
+ CylinderMesh::create_mesh_array(data, radius, radius, height, radial_segments, rings, false, bottom_cap);
+ points = data[RS::ARRAY_VERTEX];
+ normals = data[RS::ARRAY_NORMAL];
+ bool no_top_cap{ true };
+
+ for (int index = 0; index < normals.size(); ++index) {
+ if (Math::is_equal_approx(normals[index].x, 0) &&
+ Math::is_equal_approx(normals[index].z, 0) &&
+ normals[index].y > 0) {
+ no_top_cap = false;
+ break;
+ }
+ }
+
+ CHECK_MESSAGE(no_top_cap,
+ "Check there is no top cap.");
+ }
+ }
+
+ SUBCASE("[Primitive][Cylinder] Slanted cylinder mesh (top and bottom radius different).") {
+ Array data{};
+ data.resize(RS::ARRAY_MAX);
+ real_t top_radius = 2.f;
+ real_t bottom_radius = 1.f;
+ real_t height = 1.f;
+ int radial_segments = 8;
+ int rings = 5;
+ CylinderMesh::create_mesh_array(data, top_radius, bottom_radius, height, radial_segments, rings, false, false);
+ Vector<Vector3> points = data[RS::ARRAY_VERTEX];
+ Vector<Vector3> normals = data[RS::ARRAY_NORMAL];
+
+ SUBCASE("[Primitive][Cylinder] Side points lie correct distance from y-axis") {
+ bool is_radius_correct{ true };
+ for (int index = 0; index < points.size(); ++index) {
+ real_t radius = ((top_radius - bottom_radius) / height) * (points[index].y - 0.5 * height) + top_radius;
+ Vector3 distance_to_yaxis = points[index] - Vector3(0.f, points[index].y, 0.f);
+ if (!Math::is_equal_approx(distance_to_yaxis.length_squared(), radius * radius)) {
+ is_radius_correct = false;
+ break;
+ }
+ }
+
+ CHECK(is_radius_correct);
+ }
+
+ SUBCASE("[Primitive][Cylinder] Normal on side is orthogonal to side tangent vector") {
+ bool is_normal_correct{ true };
+ for (int index = 0; index < points.size(); ++index) {
+ Vector3 yaxis_to_point = points[index] - Vector3(0.f, points[index].y, 0.f);
+ Vector3 yaxis_to_rb = yaxis_to_point.normalized() * bottom_radius;
+ Vector3 rb_to_point = yaxis_to_point - yaxis_to_rb;
+ Vector3 y_to_bottom = -Vector3(0.f, points[index].y + 0.5 * height, 0.f);
+ Vector3 side_tangent = rb_to_point - y_to_bottom;
+
+ if (!Math::is_equal_approx(normals[index].dot(side_tangent), 0)) {
+ is_normal_correct = false;
+ break;
+ }
+ }
+
+ CHECK(is_normal_correct);
+ }
+ }
+
+} // End cylinder tests
+
+TEST_CASE("[SceneTree][Primitive][Plane] Plane Primitive") {
+ Ref<PlaneMesh> plane = memnew(PlaneMesh);
+
+ SUBCASE("[SceneTree][Primitive][Plane] Default values should be valid") {
+ CHECK(plane->get_size().x > 0);
+ CHECK(plane->get_size().y > 0);
+ CHECK(plane->get_subdivide_width() >= 0);
+ CHECK(plane->get_subdivide_depth() >= 0);
+ CHECK((plane->get_orientation() == PlaneMesh::FACE_X || plane->get_orientation() == PlaneMesh::FACE_Y || plane->get_orientation() == PlaneMesh::FACE_Z));
+ }
+
+ SUBCASE("[SceneTree][Primitive][Plane] Set properties and get them.") {
+ Size2 size{ 3.2, 1.8 };
+ Vector3 offset{ -7.3, 0.4, -1.7 };
+ plane->set_size(size);
+ plane->set_subdivide_width(15);
+ plane->set_subdivide_depth(29);
+ plane->set_center_offset(offset);
+ plane->set_orientation(PlaneMesh::FACE_X);
+
+ CHECK(plane->get_size().is_equal_approx(size));
+ CHECK(plane->get_subdivide_width() == 15);
+ CHECK(plane->get_subdivide_depth() == 29);
+ CHECK(plane->get_center_offset().is_equal_approx(offset));
+ CHECK(plane->get_orientation() == PlaneMesh::FACE_X);
+ }
+
+ SUBCASE("[SceneTree][Primitive][Plane] Ensure number of segments is >= 0.") {
+ plane->set_subdivide_width(-15);
+ plane->set_subdivide_depth(-29);
+
+ CHECK(plane->get_subdivide_width() >= 0);
+ CHECK(plane->get_subdivide_depth() >= 0);
+ }
+}
+
+TEST_CASE("[SceneTree][Primitive][Quad] QuadMesh Primitive") {
+ Ref<QuadMesh> quad = memnew(QuadMesh);
+
+ SUBCASE("[Primitive][Quad] Orientation on initialization is in z direction") {
+ CHECK(quad->get_orientation() == PlaneMesh::FACE_Z);
+ }
+}
+
+TEST_CASE("[SceneTree][Primitive][Prism] Prism Primitive") {
+ Ref<PrismMesh> prism = memnew(PrismMesh);
+
+ SUBCASE("[Primitive][Prism] There are valid values of properties on initialization.") {
+ CHECK(prism->get_left_to_right() >= 0);
+ CHECK(prism->get_size().x >= 0);
+ CHECK(prism->get_size().y >= 0);
+ CHECK(prism->get_size().z >= 0);
+ CHECK(prism->get_subdivide_width() >= 0);
+ CHECK(prism->get_subdivide_height() >= 0);
+ CHECK(prism->get_subdivide_depth() >= 0);
+ }
+
+ SUBCASE("[Primitive][Prism] Are able to change prism properties.") {
+ Vector3 size{ 4.3, 9.1, 0.43 };
+ prism->set_left_to_right(3.4f);
+ prism->set_size(size);
+ prism->set_subdivide_width(36);
+ prism->set_subdivide_height(5);
+ prism->set_subdivide_depth(64);
+
+ CHECK(prism->get_left_to_right() == doctest::Approx(3.4f));
+ CHECK(prism->get_size().is_equal_approx(size));
+ CHECK(prism->get_subdivide_width() == 36);
+ CHECK(prism->get_subdivide_height() == 5);
+ CHECK(prism->get_subdivide_depth() == 64);
+ }
+
+ SUBCASE("[Primitive][Prism] Ensure number of segments always >= 0") {
+ prism->set_subdivide_width(-36);
+ prism->set_subdivide_height(-5);
+ prism->set_subdivide_depth(-64);
+
+ CHECK(prism->get_subdivide_width() >= 0);
+ CHECK(prism->get_subdivide_height() >= 0);
+ CHECK(prism->get_subdivide_depth() >= 0);
+ }
+}
+
+TEST_CASE("[SceneTree][Primitive][Sphere] Sphere Primitive") {
+ Ref<SphereMesh> sphere = memnew(SphereMesh);
+
+ SUBCASE("[Primitive][Sphere] There are valid values of properties on initialization.") {
+ CHECK(sphere->get_radius() >= 0);
+ CHECK(sphere->get_height() >= 0);
+ CHECK(sphere->get_radial_segments() >= 0);
+ CHECK(sphere->get_rings() >= 0);
+ }
+
+ SUBCASE("[Primitive][Sphere] Are able to change prism properties.") {
+ sphere->set_radius(3.4f);
+ sphere->set_height(2.2f);
+ sphere->set_radial_segments(36);
+ sphere->set_rings(5);
+ sphere->set_is_hemisphere(true);
+
+ CHECK(sphere->get_radius() == doctest::Approx(3.4f));
+ CHECK(sphere->get_height() == doctest::Approx(2.2f));
+ CHECK(sphere->get_radial_segments() == 36);
+ CHECK(sphere->get_rings() == 5);
+ CHECK(sphere->get_is_hemisphere());
+ }
+
+ SUBCASE("[Primitive][Sphere] Ensure number of segments always >= 0") {
+ sphere->set_radial_segments(-36);
+ sphere->set_rings(-5);
+
+ CHECK(sphere->get_radial_segments() >= 0);
+ CHECK(sphere->get_rings() >= 0);
+ }
+
+ SUBCASE("[Primitive][Sphere] Sphere mesh tests.") {
+ Array data{};
+ data.resize(RS::ARRAY_MAX);
+ real_t radius = 1.1f;
+ int radial_segments = 8;
+ int rings = 5;
+ SphereMesh::create_mesh_array(data, radius, 2 * radius, radial_segments, rings);
+ Vector<Vector3> points = data[RS::ARRAY_VERTEX];
+ Vector<Vector3> normals = data[RS::ARRAY_NORMAL];
+
+ SUBCASE("[Primitive][Sphere] All points lie radius away from origin.") {
+ bool is_radius_correct = true;
+ for (Vector3 point : points) {
+ if (!Math::is_equal_approx(point.length_squared(), radius * radius)) {
+ is_radius_correct = false;
+ break;
+ }
+ }
+
+ CHECK(is_radius_correct);
+ }
+
+ SUBCASE("[Primitive][Sphere] All normals lie in direction of corresponding point.") {
+ bool is_normals_correct = true;
+ for (int index = 0; index < points.size(); ++index) {
+ if (!Math::is_equal_approx(normals[index].normalized().dot(points[index].normalized()), 1)) {
+ is_normals_correct = false;
+ break;
+ }
+ }
+
+ CHECK(is_normals_correct);
+ }
+ }
+}
+
+TEST_CASE("[SceneTree][Primitive][Torus] Torus Primitive") {
+ Ref<TorusMesh> torus = memnew(TorusMesh);
+ Ref<PrimitiveMesh> prim = memnew(PrimitiveMesh);
+
+ SUBCASE("[Primitive][Torus] There are valid values of properties on initialization.") {
+ CHECK(torus->get_inner_radius() > 0);
+ CHECK(torus->get_outer_radius() > 0);
+ CHECK(torus->get_rings() >= 0);
+ CHECK(torus->get_ring_segments() >= 0);
+ }
+
+ SUBCASE("[Primitive][Torus] Are able to change properties.") {
+ torus->set_inner_radius(3.2f);
+ torus->set_outer_radius(9.5f);
+ torus->set_rings(19);
+ torus->set_ring_segments(43);
+
+ CHECK(torus->get_inner_radius() == doctest::Approx(3.2f));
+ CHECK(torus->get_outer_radius() == doctest::Approx(9.5f));
+ CHECK(torus->get_rings() == 19);
+ CHECK(torus->get_ring_segments() == 43);
+ }
+}
+
+TEST_CASE("[SceneTree][Primitive][TubeTrail] TubeTrail Primitive") {
+ Ref<TubeTrailMesh> tube = memnew(TubeTrailMesh);
+
+ SUBCASE("[Primitive][TubeTrail] There are valid values of properties on initialization.") {
+ CHECK(tube->get_radius() > 0);
+ CHECK(tube->get_radial_steps() >= 0);
+ CHECK(tube->get_sections() >= 0);
+ CHECK(tube->get_section_length() > 0);
+ CHECK(tube->get_section_rings() >= 0);
+ CHECK(tube->get_curve() == nullptr);
+ CHECK(tube->get_builtin_bind_pose_count() >= 0);
+ }
+
+ SUBCASE("[Primitive][TubeTrail] Are able to change properties.") {
+ tube->set_radius(7.2f);
+ tube->set_radial_steps(9);
+ tube->set_sections(33);
+ tube->set_section_length(5.5f);
+ tube->set_section_rings(12);
+ Ref<Curve> curve = memnew(Curve);
+ tube->set_curve(curve);
+
+ CHECK(tube->get_radius() == doctest::Approx(7.2f));
+ CHECK(tube->get_section_length() == doctest::Approx(5.5f));
+ CHECK(tube->get_radial_steps() == 9);
+ CHECK(tube->get_sections() == 33);
+ CHECK(tube->get_section_rings() == 12);
+ CHECK(tube->get_curve() == curve);
+ }
+
+ SUBCASE("[Primitive][TubeTrail] Setting same curve more than once, it remains the same.") {
+ Ref<Curve> curve = memnew(Curve);
+ tube->set_curve(curve);
+ tube->set_curve(curve);
+ tube->set_curve(curve);
+
+ CHECK(tube->get_curve() == curve);
+ }
+
+ SUBCASE("[Primitive][TubeTrail] Setting curve, then changing to different curve.") {
+ Ref<Curve> curve1 = memnew(Curve);
+ Ref<Curve> curve2 = memnew(Curve);
+ tube->set_curve(curve1);
+ CHECK(tube->get_curve() == curve1);
+
+ tube->set_curve(curve2);
+ CHECK(tube->get_curve() == curve2);
+ }
+
+ SUBCASE("[Primitive][TubeTrail] Assign same curve to two different tube trails") {
+ Ref<TubeTrailMesh> tube2 = memnew(TubeTrailMesh);
+ Ref<Curve> curve = memnew(Curve);
+ tube->set_curve(curve);
+ tube2->set_curve(curve);
+
+ CHECK(tube->get_curve() == curve);
+ CHECK(tube2->get_curve() == curve);
+ }
+}
+
+TEST_CASE("[SceneTree][Primitive][RibbonTrail] RibbonTrail Primitive") {
+ Ref<RibbonTrailMesh> ribbon = memnew(RibbonTrailMesh);
+
+ SUBCASE("[Primitive][RibbonTrail] There are valid values of properties on initialization.") {
+ CHECK(ribbon->get_size() > 0);
+ CHECK(ribbon->get_sections() >= 0);
+ CHECK(ribbon->get_section_length() > 0);
+ CHECK(ribbon->get_section_segments() >= 0);
+ CHECK(ribbon->get_builtin_bind_pose_count() >= 0);
+ CHECK(ribbon->get_curve() == nullptr);
+ CHECK((ribbon->get_shape() == RibbonTrailMesh::SHAPE_CROSS ||
+ ribbon->get_shape() == RibbonTrailMesh::SHAPE_FLAT));
+ }
+
+ SUBCASE("[Primitive][RibbonTrail] Able to change properties.") {
+ Ref<Curve> curve = memnew(Curve);
+ ribbon->set_size(4.3f);
+ ribbon->set_sections(16);
+ ribbon->set_section_length(1.3f);
+ ribbon->set_section_segments(9);
+ ribbon->set_curve(curve);
+
+ CHECK(ribbon->get_size() == doctest::Approx(4.3f));
+ CHECK(ribbon->get_section_length() == doctest::Approx(1.3f));
+ CHECK(ribbon->get_sections() == 16);
+ CHECK(ribbon->get_section_segments() == 9);
+ CHECK(ribbon->get_curve() == curve);
+ }
+
+ SUBCASE("[Primitive][RibbonTrail] Setting same curve more than once, it remains the same.") {
+ Ref<Curve> curve = memnew(Curve);
+ ribbon->set_curve(curve);
+ ribbon->set_curve(curve);
+ ribbon->set_curve(curve);
+
+ CHECK(ribbon->get_curve() == curve);
+ }
+
+ SUBCASE("[Primitive][RibbonTrail] Setting curve, then changing to different curve.") {
+ Ref<Curve> curve1 = memnew(Curve);
+ Ref<Curve> curve2 = memnew(Curve);
+ ribbon->set_curve(curve1);
+ CHECK(ribbon->get_curve() == curve1);
+
+ ribbon->set_curve(curve2);
+ CHECK(ribbon->get_curve() == curve2);
+ }
+
+ SUBCASE("[Primitive][RibbonTrail] Assign same curve to two different ribbon trails") {
+ Ref<RibbonTrailMesh> ribbon2 = memnew(RibbonTrailMesh);
+ Ref<Curve> curve = memnew(Curve);
+ ribbon->set_curve(curve);
+ ribbon2->set_curve(curve);
+
+ CHECK(ribbon->get_curve() == curve);
+ CHECK(ribbon2->get_curve() == curve);
+ }
+}
+
+TEST_CASE("[SceneTree][Primitive][Text] Text Primitive") {
+ Ref<TextMesh> text = memnew(TextMesh);
+
+ SUBCASE("[Primitive][Text] There are valid values of properties on initialization.") {
+ CHECK((text->get_horizontal_alignment() == HORIZONTAL_ALIGNMENT_CENTER ||
+ text->get_horizontal_alignment() == HORIZONTAL_ALIGNMENT_LEFT ||
+ text->get_horizontal_alignment() == HORIZONTAL_ALIGNMENT_RIGHT ||
+ text->get_horizontal_alignment() == HORIZONTAL_ALIGNMENT_FILL));
+ CHECK((text->get_vertical_alignment() == VERTICAL_ALIGNMENT_BOTTOM ||
+ text->get_vertical_alignment() == VERTICAL_ALIGNMENT_TOP ||
+ text->get_vertical_alignment() == VERTICAL_ALIGNMENT_CENTER ||
+ text->get_vertical_alignment() == VERTICAL_ALIGNMENT_FILL));
+ CHECK(text->get_font() == nullptr);
+ CHECK(text->get_font_size() > 0);
+ CHECK(text->get_line_spacing() >= 0);
+ CHECK((text->get_autowrap_mode() == TextServer::AUTOWRAP_OFF ||
+ text->get_autowrap_mode() == TextServer::AUTOWRAP_ARBITRARY ||
+ text->get_autowrap_mode() == TextServer::AUTOWRAP_WORD ||
+ text->get_autowrap_mode() == TextServer::AUTOWRAP_WORD_SMART));
+ CHECK((text->get_text_direction() == TextServer::DIRECTION_AUTO ||
+ text->get_text_direction() == TextServer::DIRECTION_LTR ||
+ text->get_text_direction() == TextServer::DIRECTION_RTL));
+ CHECK((text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_DEFAULT ||
+ text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_URI ||
+ text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_FILE ||
+ text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_EMAIL ||
+ text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_LIST ||
+ text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_NONE ||
+ text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_CUSTOM));
+ CHECK(text->get_structured_text_bidi_override_options().size() >= 0);
+ CHECK(text->get_width() > 0);
+ CHECK(text->get_depth() > 0);
+ CHECK(text->get_curve_step() > 0);
+ CHECK(text->get_pixel_size() > 0);
+ }
+
+ SUBCASE("[Primitive][Text] Change the properties of the mesh.") {
+ Ref<Font> font = memnew(Font);
+ Array options{};
+ Point2 offset{ 30.8, 104.23 };
+ text->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
+ text->set_vertical_alignment(VERTICAL_ALIGNMENT_BOTTOM);
+ text->set_text("Hello");
+ text->set_font(font);
+ text->set_font_size(12);
+ text->set_line_spacing(1.7f);
+ text->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
+ text->set_text_direction(TextServer::DIRECTION_RTL);
+ text->set_language("French");
+ text->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_EMAIL);
+ text->set_structured_text_bidi_override_options(options);
+ text->set_uppercase(true);
+ real_t width{ 0.6 };
+ real_t depth{ 1.7 };
+ real_t pixel_size{ 2.8 };
+ real_t curve_step{ 4.8 };
+ text->set_width(width);
+ text->set_depth(depth);
+ text->set_curve_step(curve_step);
+ text->set_pixel_size(pixel_size);
+ text->set_offset(offset);
+
+ CHECK(text->get_horizontal_alignment() == HORIZONTAL_ALIGNMENT_RIGHT);
+ CHECK(text->get_vertical_alignment() == VERTICAL_ALIGNMENT_BOTTOM);
+ CHECK(text->get_text_direction() == TextServer::DIRECTION_RTL);
+ CHECK(text->get_text() == "Hello");
+ CHECK(text->get_font() == font);
+ CHECK(text->get_font_size() == 12);
+ CHECK(text->get_autowrap_mode() == TextServer::AUTOWRAP_WORD_SMART);
+ CHECK(text->get_language() == "French");
+ CHECK(text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_EMAIL);
+ CHECK(text->get_structured_text_bidi_override_options() == options);
+ CHECK(text->is_uppercase() == true);
+ CHECK(text->get_offset() == offset);
+ CHECK(text->get_line_spacing() == doctest::Approx(1.7f));
+ CHECK(text->get_width() == doctest::Approx(width));
+ CHECK(text->get_depth() == doctest::Approx(depth));
+ CHECK(text->get_curve_step() == doctest::Approx(curve_step));
+ CHECK(text->get_pixel_size() == doctest::Approx(pixel_size));
+ }
+
+ SUBCASE("[Primitive][Text] Set objects multiple times.") {
+ Ref<Font> font = memnew(Font);
+ Array options{};
+ Point2 offset{ 30.8, 104.23 };
+
+ text->set_font(font);
+ text->set_font(font);
+ text->set_font(font);
+ text->set_structured_text_bidi_override_options(options);
+ text->set_structured_text_bidi_override_options(options);
+ text->set_structured_text_bidi_override_options(options);
+ text->set_offset(offset);
+ text->set_offset(offset);
+ text->set_offset(offset);
+
+ CHECK(text->get_font() == font);
+ CHECK(text->get_structured_text_bidi_override_options() == options);
+ CHECK(text->get_offset() == offset);
+ }
+
+ SUBCASE("[Primitive][Text] Set then change objects.") {
+ Ref<Font> font1 = memnew(Font);
+ Ref<Font> font2 = memnew(Font);
+ Array options1{};
+ Array options2{};
+ Point2 offset1{ 30.8, 104.23 };
+ Point2 offset2{ -30.8, -104.23 };
+
+ text->set_font(font1);
+ text->set_structured_text_bidi_override_options(options1);
+ text->set_offset(offset1);
+
+ CHECK(text->get_font() == font1);
+ CHECK(text->get_structured_text_bidi_override_options() == options1);
+ CHECK(text->get_offset() == offset1);
+
+ text->set_font(font2);
+ text->set_structured_text_bidi_override_options(options2);
+ text->set_offset(offset2);
+
+ CHECK(text->get_font() == font2);
+ CHECK(text->get_structured_text_bidi_override_options() == options2);
+ CHECK(text->get_offset() == offset2);
+ }
+
+ SUBCASE("[Primitive][Text] Assign same font to two Textmeshes.") {
+ Ref<TextMesh> text2 = memnew(TextMesh);
+ Ref<Font> font = memnew(Font);
+
+ text->set_font(font);
+ text2->set_font(font);
+
+ CHECK(text->get_font() == font);
+ CHECK(text2->get_font() == font);
+ }
+}
+
+} // namespace TestPrimitives
+
+#endif // TEST_PRIMITIVES_H
diff --git a/tests/scene/test_sprite_frames.h b/tests/scene/test_sprite_frames.h
index 61bbd16493..bf127cd42c 100644
--- a/tests/scene/test_sprite_frames.h
+++ b/tests/scene/test_sprite_frames.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* test_sprite_frames.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* test_sprite_frames.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef TEST_SPRITE_FRAMES_H
#define TEST_SPRITE_FRAMES_H
@@ -210,9 +210,9 @@ TEST_CASE("[SpriteFrames] Frame addition, removal, and retrieval") {
frames.get_frame_count(test_animation_name) == 0,
"Animation has a default frame count of 0");
- frames.add_frame(test_animation_name, dummy_frame1, 0);
- frames.add_frame(test_animation_name, dummy_frame1, 1);
- frames.add_frame(test_animation_name, dummy_frame1, 2);
+ frames.add_frame(test_animation_name, dummy_frame1, 1.0, 0);
+ frames.add_frame(test_animation_name, dummy_frame1, 1.0, 1);
+ frames.add_frame(test_animation_name, dummy_frame1, 1.0, 2);
CHECK_MESSAGE(
frames.get_frame_count(test_animation_name) == 3,
@@ -227,7 +227,7 @@ TEST_CASE("[SpriteFrames] Frame addition, removal, and retrieval") {
// These error handling cases should not crash.
ERR_PRINT_OFF;
- frames.add_frame("does not exist", dummy_frame1, 0);
+ frames.add_frame("does not exist", dummy_frame1, 1.0, 0);
frames.remove_frame(test_animation_name, -99);
frames.remove_frame("does not exist", 0);
ERR_PRINT_ON;
diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h
index 7550c12a0f..944f9cb9f6 100644
--- a/tests/scene/test_text_edit.h
+++ b/tests/scene/test_text_edit.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* test_text_edit.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* test_text_edit.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef TEST_TEXT_EDIT_H
#define 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,11 +726,81 @@ 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");
}
+ SUBCASE("[TextEdit] add selection for next occurrence") {
+ text_edit->set_text("\ntest other_test\nrandom test\nword test word nonrandom");
+ text_edit->set_caret_column(0);
+ text_edit->set_caret_line(1);
+
+ // First selection made by the implicit select_word_under_caret call
+ text_edit->add_selection_for_next_occurrence();
+ CHECK(text_edit->get_caret_count() == 1);
+ 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);
+
+ text_edit->add_selection_for_next_occurrence();
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->get_selected_text(1) == "test");
+ CHECK(text_edit->get_selection_from_line(1) == 1);
+ CHECK(text_edit->get_selection_from_column(1) == 13);
+ CHECK(text_edit->get_selection_to_line(1) == 1);
+ CHECK(text_edit->get_selection_to_column(1) == 17);
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 17);
+
+ text_edit->add_selection_for_next_occurrence();
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->get_selected_text(2) == "test");
+ CHECK(text_edit->get_selection_from_line(2) == 2);
+ CHECK(text_edit->get_selection_from_column(2) == 9);
+ CHECK(text_edit->get_selection_to_line(2) == 2);
+ CHECK(text_edit->get_selection_to_column(2) == 13);
+ CHECK(text_edit->get_caret_line(2) == 2);
+ CHECK(text_edit->get_caret_column(2) == 13);
+
+ text_edit->add_selection_for_next_occurrence();
+ CHECK(text_edit->get_caret_count() == 4);
+ CHECK(text_edit->get_selected_text(3) == "test");
+ CHECK(text_edit->get_selection_from_line(3) == 3);
+ CHECK(text_edit->get_selection_from_column(3) == 5);
+ CHECK(text_edit->get_selection_to_line(3) == 3);
+ CHECK(text_edit->get_selection_to_column(3) == 9);
+ CHECK(text_edit->get_caret_line(3) == 3);
+ CHECK(text_edit->get_caret_column(3) == 9);
+
+ // A different word with a new manually added caret
+ text_edit->add_caret(2, 1);
+ text_edit->select(2, 0, 2, 4, 4);
+ CHECK(text_edit->get_selected_text(4) == "rand");
+
+ text_edit->add_selection_for_next_occurrence();
+ CHECK(text_edit->get_caret_count() == 6);
+ CHECK(text_edit->get_selected_text(5) == "rand");
+ CHECK(text_edit->get_selection_from_line(5) == 3);
+ CHECK(text_edit->get_selection_from_column(5) == 18);
+ CHECK(text_edit->get_selection_to_line(5) == 3);
+ CHECK(text_edit->get_selection_to_column(5) == 22);
+ CHECK(text_edit->get_caret_line(5) == 3);
+ CHECK(text_edit->get_caret_column(5) == 22);
+
+ // Make sure the previous selections are still active
+ CHECK(text_edit->get_selected_text(0) == "test");
+ CHECK(text_edit->get_selected_text(1) == "test");
+ CHECK(text_edit->get_selected_text(2) == "test");
+ CHECK(text_edit->get_selected_text(3) == "test");
+ }
+
SUBCASE("[TextEdit] deselect on focus loss") {
text_edit->set_text("test");
@@ -727,7 +843,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
#ifdef MACOS_ENABLED
SEND_GUI_KEY_EVENT(text_edit, Key::RIGHT | KeyModifierMask::SHIFT | KeyModifierMask::ALT)
#else
- SEND_GUI_KEY_EVENT(text_edit, Key::RIGHT | KeyModifierMask::SHIFT | KeyModifierMask::CMD)
+ SEND_GUI_KEY_EVENT(text_edit, Key::RIGHT | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL)
#endif
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "test");
@@ -739,7 +855,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
#ifdef MACOS_ENABLED
SEND_GUI_KEY_EVENT(text_edit, Key::LEFT | KeyModifierMask::SHIFT | KeyModifierMask::ALT)
#else
- SEND_GUI_KEY_EVENT(text_edit, Key::LEFT | KeyModifierMask::SHIFT | KeyModifierMask::CMD)
+ SEND_GUI_KEY_EVENT(text_edit, Key::LEFT | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL)
#endif
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "");
@@ -775,8 +891,8 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->grab_focus();
MessageQueue::get_singleton()->flush();
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 1), MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE);
- SEND_GUI_MOUSE_MOTION_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 7), MouseButton::MASK_LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 1), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 7), MouseButtonMask::LEFT, Key::NONE);
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "for s");
CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_POINTER);
@@ -787,12 +903,12 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 5);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 9), MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 9), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(text_edit->has_selection());
text_edit->set_selecting_enabled(false);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 1), MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE);
- SEND_GUI_MOUSE_MOTION_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 7), MouseButton::MASK_LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 1), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 7), MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 5);
@@ -819,7 +935,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_caret_column() == 3);
SIGNAL_CHECK("caret_changed", empty_signal_args);
- SEND_GUI_MOUSE_MOTION_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 7), MouseButton::MASK_LEFT, Key::NONE);
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 7), MouseButtonMask::LEFT, Key::NONE);
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "for selection");
CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_WORD);
@@ -833,7 +949,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
Point2i line_0 = text_edit->get_pos_at_line_column(0, 0);
line_0.y /= 2;
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, line_0, MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, line_0, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(text_edit->has_selection());
text_edit->set_selecting_enabled(false);
@@ -852,7 +968,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
MessageQueue::get_singleton()->flush();
SEND_GUI_DOUBLE_CLICK(text_edit, text_edit->get_pos_at_line_column(0, 2), Key::NONE);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 2), MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 2), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "for selection");
CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_LINE);
@@ -865,12 +981,12 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
Point2i line_0 = text_edit->get_pos_at_line_column(0, 0);
line_0.y /= 2;
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, line_0, MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, line_0, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(text_edit->has_selection());
text_edit->set_selecting_enabled(false);
SEND_GUI_DOUBLE_CLICK(text_edit, text_edit->get_pos_at_line_column(0, 2), Key::NONE);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 2), MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 2), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
@@ -884,8 +1000,8 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_text("this is some text\nfor selection");
MessageQueue::get_singleton()->flush();
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 0), MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 7), MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE | KeyModifierMask::SHIFT);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 7), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::SHIFT);
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "for s");
CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_POINTER);
@@ -896,12 +1012,12 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 5);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 9), MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 9), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(text_edit->has_selection());
text_edit->set_selecting_enabled(false);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 0), MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 7), MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE | KeyModifierMask::SHIFT);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 7), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::SHIFT);
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 5);
@@ -950,11 +1066,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 +1086,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 +1111,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());
@@ -1029,19 +1149,19 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
Point2i line_0 = text_edit->get_pos_at_line_column(0, 0);
line_0.y /= 2;
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, line_0, MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, line_0, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK(text_edit->is_mouse_over_selection());
- SEND_GUI_MOUSE_MOTION_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 7), MouseButton::MASK_LEFT, Key::NONE);
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit, text_edit->get_pos_at_line_column(0, 7), MouseButtonMask::LEFT, Key::NONE);
CHECK(text_edit->get_viewport()->gui_is_dragging());
CHECK(text_edit->get_viewport()->gui_get_drag_data() == "drag me");
line_0 = target_text_edit->get_pos_at_line_column(0, 0);
line_0.y /= 2;
line_0.x += 401; // As empty add one.
- SEND_GUI_MOUSE_MOTION_EVENT(target_text_edit, line_0, MouseButton::MASK_LEFT, Key::NONE);
+ SEND_GUI_MOUSE_MOTION_EVENT(target_text_edit, line_0, MouseButtonMask::LEFT, Key::NONE);
CHECK(text_edit->get_viewport()->gui_is_dragging());
- SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(target_text_edit, line_0, MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(target_text_edit, line_0, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
CHECK(text_edit->get_text() == "");
@@ -1176,8 +1296,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 +1307,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 +1379,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 +1394,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 +1473,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 +1497,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 +1512,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 +1527,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 +1555,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,13 +1570,18 @@ 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);
+ Ref<InputEvent> tmpevent = InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::ALT | KeyModifierMask::CMD_OR_CTRL);
InputMap::get_singleton()->action_add_event("ui_text_backspace_all_to_left", tmpevent);
SIGNAL_DISCARD("text_set");
@@ -1395,34 +1589,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 +1643,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 +1678,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 +1693,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 +1739,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 +1761,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 +1797,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 +1851,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 +1886,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,25 +1897,30 @@ 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);
}
SUBCASE("[TextEdit] ui_text_delete_all_to_right") {
- Ref<InputEvent> tmpevent = InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::ALT | KeyModifierMask::CMD);
+ 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 +1928,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 +1961,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 +1985,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 +2000,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 +2019,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 +2035,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 +2070,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 +2097,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 +2112,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 +2129,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 +2145,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 +2180,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 +2209,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 +2270,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 +2297,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 | KeyModifierMask::SHIFT);
+ 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 +2365,91 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // Normal left should 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 +2457,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 | KeyModifierMask::SHIFT);
+ 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 +2525,76 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // Normal right should 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 +2604,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 +2619,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 +2683,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 +2698,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 +2765,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));
@@ -2245,9 +2778,9 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("caret_changed");
#ifdef MACOS_ENABLED
- SEND_GUI_KEY_EVENT(text_edit, Key::UP | KeyModifierMask::CMD | KeyModifierMask::SHIFT);
+ SEND_GUI_KEY_EVENT(text_edit, Key::UP | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT);
#else
- SEND_GUI_KEY_EVENT(text_edit, Key::HOME | KeyModifierMask::CMD | KeyModifierMask::SHIFT);
+ SEND_GUI_KEY_EVENT(text_edit, Key::HOME | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT);
#endif
CHECK(text_edit->get_viewport()->is_input_handled());
CHECK(text_edit->get_text() == "this is some\nother test\nlines\ngo here");
@@ -2258,6 +2791,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 +2811,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));
@@ -2286,9 +2823,9 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("caret_changed");
#ifdef MACOS_ENABLED
- SEND_GUI_KEY_EVENT(text_edit, Key::DOWN | KeyModifierMask::CMD | KeyModifierMask::SHIFT);
+ SEND_GUI_KEY_EVENT(text_edit, Key::DOWN | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT);
#else
- SEND_GUI_KEY_EVENT(text_edit, Key::END | KeyModifierMask::CMD | KeyModifierMask::SHIFT);
+ SEND_GUI_KEY_EVENT(text_edit, Key::END | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT);
#endif
CHECK(text_edit->get_viewport()->is_input_handled());
CHECK(text_edit->get_text() == "go here\nlines\nother test\nthis is some");
@@ -2299,6 +2836,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 +2853,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));
@@ -2327,15 +2868,20 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("caret_changed");
#ifdef MACOS_ENABLED
- SEND_GUI_KEY_EVENT(text_edit, Key::LEFT | KeyModifierMask::CMD | KeyModifierMask::SHIFT);
+ SEND_GUI_KEY_EVENT(text_edit, Key::LEFT | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT);
#else
SEND_GUI_KEY_EVENT(text_edit, Key::HOME | KeyModifierMask::SHIFT);
#endif
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 +2890,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 +2903,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 +2916,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 +2930,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));
@@ -2384,15 +2945,20 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("caret_changed");
#ifdef MACOS_ENABLED
- SEND_GUI_KEY_EVENT(text_edit, Key::RIGHT | KeyModifierMask::CMD | KeyModifierMask::SHIFT);
+ SEND_GUI_KEY_EVENT(text_edit, Key::RIGHT | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT);
#else
SEND_GUI_KEY_EVENT(text_edit, Key::END | KeyModifierMask::SHIFT);
#endif
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 +2967,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 +2993,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 +3011,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 +3038,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");
@@ -2491,14 +3093,14 @@ TEST_CASE("[SceneTree][TextEdit] context menu") {
CHECK_FALSE(text_edit->is_context_menu_enabled());
CHECK_FALSE(text_edit->is_menu_visible());
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(600, 10), MouseButton::RIGHT, MouseButton::MASK_RIGHT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(600, 10), MouseButton::RIGHT, MouseButtonMask::RIGHT, Key::NONE);
CHECK_FALSE(text_edit->is_menu_visible());
text_edit->set_context_menu_enabled(true);
CHECK(text_edit->is_context_menu_enabled());
CHECK_FALSE(text_edit->is_menu_visible());
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(700, 10), MouseButton::RIGHT, MouseButton::MASK_RIGHT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(700, 10), MouseButton::RIGHT, MouseButtonMask::RIGHT, Key::NONE);
CHECK(text_edit->is_menu_visible());
memdelete(text_edit);
@@ -2558,7 +3160,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());
@@ -2659,8 +3261,8 @@ TEST_CASE("[SceneTree][TextEdit] mouse") {
CHECK(text_edit->get_line_column_at_pos(Point2i(end_pos.x - 100, end_pos.y - 100), false) == Point2i(90, 0));
CHECK(text_edit->get_line_column_at_pos(Point2i(end_pos.x - 100, end_pos.y)) == Point2i(90, 0));
- CHECK(text_edit->get_line_column_at_pos(Point2i(end_pos.x, end_pos.y + 100)) == Point2i(141, 0));
- CHECK(text_edit->get_line_column_at_pos(Point2i(end_pos.x - 100, end_pos.y + 100)) == Point2i(141, 0));
+ CHECK(text_edit->get_line_column_at_pos(Point2i(end_pos.x, end_pos.y + 100)) == Point2i(140, 0));
+ CHECK(text_edit->get_line_column_at_pos(Point2i(end_pos.x - 100, end_pos.y + 100)) == Point2i(140, 0));
CHECK(text_edit->get_line_column_at_pos(Point2i(end_pos.x, end_pos.y - 100)) == Point2i(104, 0));
CHECK(text_edit->get_line_column_at_pos(Point2i(end_pos.x - 100, end_pos.y - 100)) == Point2i(90, 0));
@@ -2714,15 +3316,15 @@ TEST_CASE("[SceneTree][TextEdit] caret") {
text_edit->set_caret_blink_enabled(true);
CHECK(text_edit->is_caret_blink_enabled());
- text_edit->set_caret_blink_speed(10);
- CHECK(text_edit->get_caret_blink_speed() == 10);
+ text_edit->set_caret_blink_interval(10);
+ CHECK(text_edit->get_caret_blink_interval() == 10);
ERR_PRINT_OFF;
- text_edit->set_caret_blink_speed(-1);
- CHECK(text_edit->get_caret_blink_speed() == 10);
+ text_edit->set_caret_blink_interval(-1);
+ CHECK(text_edit->get_caret_blink_interval() == 10);
- text_edit->set_caret_blink_speed(0);
- CHECK(text_edit->get_caret_blink_speed() == 10);
+ text_edit->set_caret_blink_interval(0);
+ CHECK(text_edit->get_caret_blink_interval() == 10);
ERR_PRINT_ON;
text_edit->set_caret_type(TextEdit::CaretType::CARET_TYPE_LINE);
@@ -2738,13 +3340,13 @@ TEST_CASE("[SceneTree][TextEdit] caret") {
text_edit->set_move_caret_on_right_click_enabled(false);
CHECK_FALSE(text_edit->is_move_caret_on_right_click_enabled());
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(100, 1), MouseButton::RIGHT, MouseButton::MASK_RIGHT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(100, 1), MouseButton::RIGHT, MouseButtonMask::RIGHT, Key::NONE);
CHECK(text_edit->get_caret_column() == caret_col);
text_edit->set_move_caret_on_right_click_enabled(true);
CHECK(text_edit->is_move_caret_on_right_click_enabled());
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(100, 1), MouseButton::RIGHT, MouseButton::MASK_RIGHT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(100, 1), MouseButton::RIGHT, MouseButtonMask::RIGHT, Key::NONE);
CHECK(text_edit->get_caret_column() != caret_col);
text_edit->set_move_caret_on_right_click_enabled(false);
@@ -2779,6 +3381,136 @@ TEST_CASE("[SceneTree][TextEdit] caret") {
memdelete(text_edit);
}
+TEST_CASE("[SceneTree][TextEdit] multicaret") {
+ 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);
+ }
+
+ SUBCASE("[TextEdit] add caret at carets") {
+ text_edit->remove_secondary_carets();
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(9);
+
+ text_edit->add_caret_at_carets(true);
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 4);
+
+ text_edit->add_caret_at_carets(true);
+ CHECK(text_edit->get_caret_count() == 2);
+
+ text_edit->add_caret_at_carets(false);
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->get_caret_line(2) == 0);
+ CHECK(text_edit->get_caret_column(2) == 7);
+
+ text_edit->remove_secondary_carets();
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(4);
+ text_edit->select(0, 0, 0, 4);
+ text_edit->add_caret_at_carets(true);
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->get_selection_from_line(1) == 1);
+ CHECK(text_edit->get_selection_to_line(1) == 1);
+ CHECK(text_edit->get_selection_from_column(1) == 0);
+ CHECK(text_edit->get_selection_to_column(1) == 3);
+
+ text_edit->add_caret_at_carets(true);
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->get_selection_from_line(2) == 2);
+ CHECK(text_edit->get_selection_to_line(2) == 2);
+ CHECK(text_edit->get_selection_from_column(2) == 0);
+ CHECK(text_edit->get_selection_to_column(2) == 4);
+ }
+
+ memdelete(text_edit);
+}
+
TEST_CASE("[SceneTree][TextEdit] line wrapping") {
TextEdit *text_edit = memnew(TextEdit);
SceneTree::get_singleton()->get_root()->add_child(text_edit);
@@ -3128,28 +3860,28 @@ TEST_CASE("[SceneTree][TextEdit] viewport") {
// Scroll.
int v_scroll = text_edit->get_v_scroll();
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(10, 10), MouseButton::WHEEL_DOWN, MouseButton::WHEEL_DOWN, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(10, 10), MouseButton::WHEEL_DOWN, 0, Key::NONE);
CHECK(text_edit->get_v_scroll() > v_scroll);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(10, 10), MouseButton::WHEEL_UP, MouseButton::WHEEL_UP, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(10, 10), MouseButton::WHEEL_UP, 0, Key::NONE);
CHECK(text_edit->get_v_scroll() == v_scroll);
// smooth scroll speed.
text_edit->set_smooth_scroll_enabled(true);
v_scroll = text_edit->get_v_scroll();
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(10, 10), MouseButton::WHEEL_DOWN, MouseButton::WHEEL_DOWN, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(10, 10), MouseButton::WHEEL_DOWN, 0, Key::NONE);
text_edit->notification(TextEdit::NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
CHECK(text_edit->get_v_scroll() >= v_scroll);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(10, 10), MouseButton::WHEEL_UP, MouseButton::WHEEL_UP, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(10, 10), MouseButton::WHEEL_UP, 0, Key::NONE);
text_edit->notification(TextEdit::NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
CHECK(text_edit->get_v_scroll() == v_scroll);
v_scroll = text_edit->get_v_scroll();
text_edit->set_v_scroll_speed(10000);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(10, 10), MouseButton::WHEEL_DOWN, MouseButton::WHEEL_DOWN, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(10, 10), MouseButton::WHEEL_DOWN, 0, Key::NONE);
text_edit->notification(TextEdit::NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
CHECK(text_edit->get_v_scroll() >= v_scroll);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(10, 10), MouseButton::WHEEL_UP, MouseButton::WHEEL_UP, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit, Point2i(10, 10), MouseButton::WHEEL_UP, 0, Key::NONE);
text_edit->notification(TextEdit::NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
CHECK(text_edit->get_v_scroll() == v_scroll);
@@ -3291,6 +4023,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);
}
diff --git a/tests/scene/test_theme.h b/tests/scene/test_theme.h
index f5b21eec32..69d29e5ca5 100644
--- a/tests/scene/test_theme.h
+++ b/tests/scene/test_theme.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* test_theme.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* test_theme.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef TEST_THEME_H
#define TEST_THEME_H
diff --git a/tests/scene/test_visual_shader.h b/tests/scene/test_visual_shader.h
new file mode 100644
index 0000000000..e54971768c
--- /dev/null
+++ b/tests/scene/test_visual_shader.h
@@ -0,0 +1,151 @@
+/**************************************************************************/
+/* test_visual_shader.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef TEST_VISUAL_SHADER_H
+#define TEST_VISUAL_SHADER_H
+
+#include "scene/resources/visual_shader.h"
+
+#include "tests/test_macros.h"
+
+namespace TestVisualArray {
+
+TEST_CASE("[SceneTree][VisualShader] Object creation and parameter") {
+ Ref<VisualShader> vs = memnew(VisualShader);
+ CHECK(vs.is_valid());
+
+ CHECK(vs->get_mode() == Shader::MODE_SPATIAL);
+
+ for (int i = 1; i < Shader::MODE_MAX; i++) {
+ vs->set_mode((Shader::Mode)i);
+ CHECK(vs->get_mode() == i);
+ }
+}
+
+TEST_CASE("[SceneTree][VisualShader] Testing VisualShaderNodes") {
+ SUBCASE("Testing Node Creation") {
+ Ref<VisualShader> vs = memnew(VisualShader);
+ CHECK(vs.is_valid());
+
+ for (int i = 0; i < VisualShader::TYPE_MAX; i++) {
+ Ref<VisualShaderNode> vsn = memnew(VisualShaderNodeInput);
+ CHECK(vsn.is_valid());
+ vs->add_node(VisualShader::Type(i), vsn, Vector2(1, 10), i + 2);
+ CHECK(vs->get_node(VisualShader::Type(i), i + 2) == vsn);
+ }
+
+ ERR_PRINT_OFF;
+
+ // Testing for Invalid entries.
+ Ref<VisualShaderNode> vsn5 = memnew(VisualShaderNodeInput);
+ Ref<VisualShaderNode> vsn6 = memnew(VisualShaderNodeInput);
+ CHECK(vsn6.is_valid());
+ CHECK(vsn5.is_valid());
+
+ vs->add_node(VisualShader::TYPE_SKY, vsn5, Vector2(1, 10), 0);
+ CHECK_FALSE(vs->get_node(VisualShader::TYPE_SKY, 0) == vsn6);
+ vs->add_node(VisualShader::TYPE_MAX, vsn6, Vector2(1, 10), 7);
+ CHECK_FALSE(vs->get_node(VisualShader::TYPE_SKY, 7) == vsn6);
+
+ ERR_PRINT_ON;
+ }
+
+ SUBCASE("Testing VisualShaderNode position getter and setter") {
+ Ref<VisualShader> vs = memnew(VisualShader);
+ CHECK(vs.is_valid());
+
+ Ref<VisualShaderNode> vsn1 = memnew(VisualShaderNodeInput);
+ CHECK(vsn1.is_valid());
+ vs->add_node(VisualShader::TYPE_COLLIDE, vsn1, Vector2(0, 0), 3);
+ CHECK(vs->get_node_position(VisualShader::TYPE_COLLIDE, 3) == Vector2(0, 0));
+ vs->set_node_position(VisualShader::TYPE_COLLIDE, 3, Vector2(1, 1));
+ CHECK(vs->get_node_position(VisualShader::TYPE_COLLIDE, 3) == Vector2(1, 1));
+
+ Ref<VisualShaderNode> vsn2 = memnew(VisualShaderNodeInput);
+ CHECK(vsn2.is_valid());
+ vs->add_node(VisualShader::TYPE_FOG, vsn2, Vector2(1, 2), 4);
+ CHECK(vs->get_node_position(VisualShader::TYPE_FOG, 4) == Vector2(1, 2));
+ vs->set_node_position(VisualShader::TYPE_FOG, 4, Vector2(2, 2));
+ CHECK(vs->get_node_position(VisualShader::TYPE_FOG, 4) == Vector2(2, 2));
+ }
+
+ SUBCASE("Testing VisualShaderNode ID") {
+ Ref<VisualShader> vs = memnew(VisualShader);
+ CHECK(vs.is_valid());
+
+ for (int i = 0; i < VisualShader::TYPE_MAX; i++) {
+ Ref<VisualShaderNode> vsn = memnew(VisualShaderNodeInput);
+ CHECK(vsn.is_valid());
+ vs->add_node(VisualShader::Type(i), vsn, Vector2(1, 10), i + 2);
+ CHECK(vs->get_valid_node_id(VisualShader::Type(i)) - 1 == i + 2);
+ }
+ }
+
+ SUBCASE("Testing remove and replace VisualShaderNode") {
+ Ref<VisualShader> vs = memnew(VisualShader);
+ CHECK(vs.is_valid());
+
+ ERR_PRINT_OFF;
+
+ for (int i = 0; i < VisualShader::TYPE_MAX; i++) {
+ Ref<VisualShaderNode> vsn = memnew(VisualShaderNodeInput);
+ CHECK(vsn.is_valid());
+ vs->add_node(VisualShader::Type(i), vsn, Vector2(1, 10), i + 2);
+ CHECK(vs->get_node(VisualShader::Type(i), i + 2) == vsn);
+ vs->remove_node(VisualShader::Type(i), i + 2);
+ CHECK_FALSE(vs->get_node(VisualShader::Type(i), i + 2) == vsn);
+ }
+
+ ERR_PRINT_ON;
+ }
+}
+
+TEST_CASE("[SceneTree][VisualShader] Testing Varyings") {
+ Ref<VisualShader> vs = memnew(VisualShader);
+
+ vs->add_varying("Test1", VisualShader::VARYING_MODE_FRAG_TO_LIGHT, VisualShader::VARYING_TYPE_TRANSFORM);
+ CHECK(vs->has_varying("Test1") == true);
+
+ vs->add_varying("Test2", VisualShader::VARYING_MODE_VERTEX_TO_FRAG_LIGHT, VisualShader::VARYING_TYPE_VECTOR_2D);
+ CHECK(vs->has_varying("Test2"));
+
+ CHECK_FALSE(vs->has_varying("Does_not_exits"));
+ ERR_PRINT_OFF;
+ vs->add_varying("Test3", VisualShader::VARYING_MODE_MAX, VisualShader::VARYING_TYPE_INT);
+ CHECK_FALSE(vs->has_varying("Test3"));
+
+ vs->add_varying("Test4", VisualShader::VARYING_MODE_FRAG_TO_LIGHT, VisualShader::VARYING_TYPE_MAX);
+ CHECK_FALSE(vs->has_varying("Test4"));
+ ERR_PRINT_ON;
+}
+
+} //namespace TestVisualArray
+
+#endif // TEST_VISUAL_SHADER_H