summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/core/config/test_project_settings.h3
-rw-r--r--tests/core/input/test_input_event_key.h56
-rw-r--r--tests/core/io/test_image.h8
-rw-r--r--tests/core/math/test_aabb.h9
-rw-r--r--tests/core/object/test_undo_redo.h202
-rw-r--r--tests/core/os/test_os.h24
-rw-r--r--tests/core/string/test_node_path.h75
-rw-r--r--tests/core/string/test_string.h128
-rw-r--r--tests/core/string/test_translation.h2
-rw-r--r--tests/core/test_crypto.h12
-rw-r--r--tests/core/variant/test_array.h2
-rw-r--r--tests/create_test.py4
-rw-r--r--tests/data/crypto/in.key51
-rw-r--r--tests/data/crypto/in.pub14
-rw-r--r--tests/scene/test_arraymesh.h2
-rw-r--r--tests/scene/test_audio_stream_wav.h2
-rw-r--r--tests/scene/test_camera_3d.h12
-rw-r--r--tests/scene/test_image_texture.h111
-rw-r--r--tests/scene/test_navigation_region_3d.h40
-rw-r--r--tests/scene/test_node_2d.h28
-rw-r--r--tests/scene/test_primitives.h14
-rw-r--r--tests/scene/test_viewport.h6
-rw-r--r--tests/servers/test_navigation_server_3d.h67
-rw-r--r--tests/servers/test_text_server.h2
-rw-r--r--tests/test_macros.h10
-rw-r--r--tests/test_main.cpp69
26 files changed, 839 insertions, 114 deletions
diff --git a/tests/core/config/test_project_settings.h b/tests/core/config/test_project_settings.h
index 9bd072f511..8fc2489f8b 100644
--- a/tests/core/config/test_project_settings.h
+++ b/tests/core/config/test_project_settings.h
@@ -45,6 +45,8 @@ public:
namespace TestProjectSettings {
+// TODO: Handle some cases failing on release builds. See: https://github.com/godotengine/godot/pull/88452
+#ifdef TOOLS_ENABLED
TEST_CASE("[ProjectSettings] Get existing setting") {
CHECK(ProjectSettings::get_singleton()->has_setting("application/config/name"));
@@ -64,6 +66,7 @@ TEST_CASE("[ProjectSettings] Default value is ignored if setting exists") {
String name = variant;
CHECK_EQ(name, "GDScript Integration Test Suite");
}
+#endif // TOOLS_ENABLED
TEST_CASE("[ProjectSettings] Non existing setting is null") {
CHECK_FALSE(ProjectSettings::get_singleton()->has_setting("not_existing_setting"));
diff --git a/tests/core/input/test_input_event_key.h b/tests/core/input/test_input_event_key.h
index 3317941fad..80918542ce 100644
--- a/tests/core/input/test_input_event_key.h
+++ b/tests/core/input/test_input_event_key.h
@@ -85,6 +85,16 @@ TEST_CASE("[InputEventKey] Key correctly stores and retrieves unicode") {
CHECK(key.get_unicode() != 'y');
}
+TEST_CASE("[InputEventKey] Key correctly stores and retrieves location") {
+ InputEventKey key;
+
+ CHECK(key.get_location() == KeyLocation::UNSPECIFIED);
+
+ key.set_location(KeyLocation::LEFT);
+ CHECK(key.get_location() == KeyLocation::LEFT);
+ CHECK(key.get_location() != KeyLocation::RIGHT);
+}
+
TEST_CASE("[InputEventKey] Key correctly stores and checks echo") {
InputEventKey key;
@@ -144,32 +154,36 @@ TEST_CASE("[InputEventKey] Key correctly converts itself to text") {
TEST_CASE("[InputEventKey] Key correctly converts its state to a string representation") {
InputEventKey none_key;
- CHECK(none_key.to_string() == "InputEventKey: keycode=(Unset), mods=none, physical=false, pressed=false, echo=false");
+ CHECK(none_key.to_string() == "InputEventKey: keycode=(Unset), mods=none, physical=false, location=unspecified, pressed=false, echo=false");
// Set physical key to Escape.
none_key.set_physical_keycode(Key::ESCAPE);
- CHECK(none_key.to_string() == "InputEventKey: keycode=4194305 (Escape), mods=none, physical=true, pressed=false, echo=false");
+ CHECK(none_key.to_string() == "InputEventKey: keycode=4194305 (Escape), mods=none, physical=true, location=unspecified, pressed=false, echo=false");
InputEventKey key;
// Set physical to None, set keycode to Space.
key.set_keycode(Key::SPACE);
- CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, pressed=false, echo=false");
+ CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, location=unspecified, pressed=false, echo=false");
+
+ // Set location
+ key.set_location(KeyLocation::RIGHT);
+ CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, location=right, pressed=false, echo=false");
// Set pressed to true.
key.set_pressed(true);
- CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, pressed=true, echo=false");
+ CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, location=right, pressed=true, echo=false");
// set echo to true.
key.set_echo(true);
- CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, pressed=true, echo=true");
+ CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, location=right, pressed=true, echo=true");
// Press Ctrl and Alt.
key.set_ctrl_pressed(true);
key.set_alt_pressed(true);
#ifdef MACOS_ENABLED
- CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=Ctrl+Option, physical=false, pressed=true, echo=true");
+ CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=Ctrl+Option, physical=false, location=right, pressed=true, echo=true");
#else
- CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=Ctrl+Alt, physical=false, pressed=true, echo=true");
+ CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=Ctrl+Alt, physical=false, location=right, pressed=true, echo=true");
#endif
}
@@ -291,6 +305,34 @@ TEST_CASE("[IsMatch] Keys are correctly matched") {
CHECK(key2.is_match(match, true) == true);
CHECK(key2.is_match(no_match, true) == false);
+
+ // Physical key with location.
+ InputEventKey key3;
+ key3.set_keycode(Key::NONE);
+ key3.set_physical_keycode(Key::SHIFT);
+
+ Ref<InputEventKey> loc_ref = key.create_reference(Key::NONE);
+
+ loc_ref->set_keycode(Key::SHIFT);
+ loc_ref->set_physical_keycode(Key::SHIFT);
+
+ CHECK(key3.is_match(loc_ref, false) == true);
+ key3.set_location(KeyLocation::UNSPECIFIED);
+ CHECK(key3.is_match(loc_ref, false) == true);
+
+ loc_ref->set_location(KeyLocation::LEFT);
+ CHECK(key3.is_match(loc_ref, false) == true);
+
+ key3.set_location(KeyLocation::LEFT);
+ CHECK(key3.is_match(loc_ref, false) == true);
+
+ key3.set_location(KeyLocation::RIGHT);
+ CHECK(key3.is_match(loc_ref, false) == false);
+
+ // Keycode key with location.
+ key3.set_physical_keycode(Key::NONE);
+ key3.set_keycode(Key::SHIFT);
+ CHECK(key3.is_match(loc_ref, false) == true);
}
} // namespace TestInputEventKey
diff --git a/tests/core/io/test_image.h b/tests/core/io/test_image.h
index 945a7e1ba3..7a0cbb13f9 100644
--- a/tests/core/io/test_image.h
+++ b/tests/core/io/test_image.h
@@ -88,11 +88,14 @@ TEST_CASE("[Image] Saving and loading") {
err == OK,
"The image should be saved successfully as a .png file.");
+ // Only available on editor builds.
+#ifdef TOOLS_ENABLED
// Save EXR
err = image->save_exr(save_path_exr, false);
CHECK_MESSAGE(
err == OK,
"The image should be saved successfully as an .exr file.");
+#endif // TOOLS_ENABLED
// Load using load()
Ref<Image> image_load = memnew(Image());
@@ -417,12 +420,15 @@ TEST_CASE("[Image] Convert image") {
Ref<Image> image = memnew(Image(4, 4, false, Image::FORMAT_RGBA8));
PackedByteArray image_data = image->get_data();
+ ERR_PRINT_OFF;
image->convert((Image::Format)-1);
+ ERR_PRINT_ON;
CHECK_MESSAGE(image->get_data() == image_data, "Image conversion to invalid type (-1) should not alter image.");
-
Ref<Image> image2 = memnew(Image(4, 4, false, Image::FORMAT_RGBA8));
image_data = image2->get_data();
+ ERR_PRINT_OFF;
image2->convert((Image::Format)(Image::FORMAT_MAX + 1));
+ ERR_PRINT_ON;
CHECK_MESSAGE(image2->get_data() == image_data, "Image conversion to invalid type (Image::FORMAT_MAX + 1) should not alter image.");
}
diff --git a/tests/core/math/test_aabb.h b/tests/core/math/test_aabb.h
index d3560ff6b6..b9f84cca24 100644
--- a/tests/core/math/test_aabb.h
+++ b/tests/core/math/test_aabb.h
@@ -228,11 +228,20 @@ TEST_CASE("[AABB] Merging") {
TEST_CASE("[AABB] Encloses") {
const AABB aabb_big = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6));
+ CHECK_MESSAGE(
+ aabb_big.encloses(aabb_big),
+ "encloses() with itself should return the expected result.");
+
AABB aabb_small = AABB(Vector3(-1.5, 2, -2.5), Vector3(1, 1, 1));
CHECK_MESSAGE(
aabb_big.encloses(aabb_small),
"encloses() with fully contained AABB (touching the edge) should return the expected result.");
+ aabb_small = AABB(Vector3(1.5, 6, 2.5), Vector3(1, 1, 1));
+ CHECK_MESSAGE(
+ aabb_big.encloses(aabb_small),
+ "encloses() with fully contained AABB (touching the edge) should return the expected result.");
+
aabb_small = AABB(Vector3(0.5, 1.5, -2), Vector3(1, 1, 1));
CHECK_MESSAGE(
!aabb_big.encloses(aabb_small),
diff --git a/tests/core/object/test_undo_redo.h b/tests/core/object/test_undo_redo.h
new file mode 100644
index 0000000000..ad3554b58c
--- /dev/null
+++ b/tests/core/object/test_undo_redo.h
@@ -0,0 +1,202 @@
+/**************************************************************************/
+/* test_undo_redo.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_UNDO_REDO_H
+#define TEST_UNDO_REDO_H
+
+#include "core/object/undo_redo.h"
+#include "tests/test_macros.h"
+
+// Declared in global namespace because of GDCLASS macro warning (Windows):
+// "Unqualified friend declaration referring to type outside of the nearest enclosing namespace
+// is a Microsoft extension; add a nested name specifier".
+class _TestUndoRedoObject : public Object {
+ GDCLASS(_TestUndoRedoObject, Object);
+ int property_value = 0;
+
+protected:
+ static void _bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_property", "property"), &_TestUndoRedoObject::set_property);
+ ClassDB::bind_method(D_METHOD("get_property"), &_TestUndoRedoObject::get_property);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "property"), "set_property", "get_property");
+ }
+
+public:
+ void set_property(int value) { property_value = value; }
+ int get_property() const { return property_value; }
+ void add_to_property(int value) { property_value += value; }
+ void subtract_from_property(int value) { property_value -= value; }
+};
+
+namespace TestUndoRedo {
+
+void set_property_action(UndoRedo *undo_redo, const String &name, _TestUndoRedoObject *test_object, int value, UndoRedo::MergeMode merge_mode = UndoRedo::MERGE_DISABLE) {
+ undo_redo->create_action(name, merge_mode);
+ undo_redo->add_do_property(test_object, "property", value);
+ undo_redo->add_undo_property(test_object, "property", test_object->get_property());
+ undo_redo->commit_action();
+}
+
+void increment_property_action(UndoRedo *undo_redo, const String &name, _TestUndoRedoObject *test_object, int value, UndoRedo::MergeMode merge_mode = UndoRedo::MERGE_DISABLE) {
+ undo_redo->create_action(name, merge_mode);
+ undo_redo->add_do_method(callable_mp(test_object, &_TestUndoRedoObject::add_to_property).bind(value));
+ undo_redo->add_undo_method(callable_mp(test_object, &_TestUndoRedoObject::subtract_from_property).bind(value));
+ undo_redo->commit_action();
+}
+
+TEST_CASE("[UndoRedo] Simple Property UndoRedo") {
+ GDREGISTER_CLASS(_TestUndoRedoObject);
+ UndoRedo *undo_redo = memnew(UndoRedo());
+
+ _TestUndoRedoObject *test_object = memnew(_TestUndoRedoObject());
+
+ CHECK(test_object->get_property() == 0);
+ CHECK(undo_redo->get_version() == 1);
+ CHECK(undo_redo->get_history_count() == 0);
+
+ set_property_action(undo_redo, "Set Property", test_object, 10);
+
+ CHECK(test_object->get_property() == 10);
+ CHECK(undo_redo->get_version() == 2);
+ CHECK(undo_redo->get_history_count() == 1);
+
+ undo_redo->undo();
+
+ CHECK(test_object->get_property() == 0);
+ CHECK(undo_redo->get_version() == 1);
+ CHECK(undo_redo->get_history_count() == 1);
+
+ undo_redo->redo();
+
+ CHECK(test_object->get_property() == 10);
+ CHECK(undo_redo->get_version() == 2);
+ CHECK(undo_redo->get_history_count() == 1);
+
+ set_property_action(undo_redo, "Set Property", test_object, 100);
+
+ CHECK(test_object->get_property() == 100);
+ CHECK(undo_redo->get_version() == 3);
+ CHECK(undo_redo->get_history_count() == 2);
+
+ set_property_action(undo_redo, "Set Property", test_object, 1000);
+
+ CHECK(test_object->get_property() == 1000);
+ CHECK(undo_redo->get_version() == 4);
+ CHECK(undo_redo->get_history_count() == 3);
+
+ undo_redo->undo();
+
+ CHECK(test_object->get_property() == 100);
+ CHECK(undo_redo->get_version() == 3);
+ CHECK(undo_redo->get_history_count() == 3);
+
+ memdelete(test_object);
+ memdelete(undo_redo);
+}
+
+TEST_CASE("[UndoRedo] Merge Property UndoRedo") {
+ GDREGISTER_CLASS(_TestUndoRedoObject);
+ UndoRedo *undo_redo = memnew(UndoRedo());
+
+ _TestUndoRedoObject *test_object = memnew(_TestUndoRedoObject());
+
+ CHECK(test_object->get_property() == 0);
+ CHECK(undo_redo->get_version() == 1);
+ CHECK(undo_redo->get_history_count() == 0);
+
+ set_property_action(undo_redo, "Merge Action 1", test_object, 10, UndoRedo::MERGE_ALL);
+
+ CHECK(test_object->get_property() == 10);
+ CHECK(undo_redo->get_version() == 2);
+ CHECK(undo_redo->get_history_count() == 1);
+
+ set_property_action(undo_redo, "Merge Action 1", test_object, 100, UndoRedo::MERGE_ALL);
+
+ CHECK(test_object->get_property() == 100);
+ CHECK(undo_redo->get_version() == 2);
+ CHECK(undo_redo->get_history_count() == 1);
+
+ set_property_action(undo_redo, "Merge Action 1", test_object, 1000, UndoRedo::MERGE_ALL);
+
+ CHECK(test_object->get_property() == 1000);
+ CHECK(undo_redo->get_version() == 2);
+ CHECK(undo_redo->get_history_count() == 1);
+
+ memdelete(test_object);
+ memdelete(undo_redo);
+}
+
+TEST_CASE("[UndoRedo] Merge Method UndoRedo") {
+ GDREGISTER_CLASS(_TestUndoRedoObject);
+ UndoRedo *undo_redo = memnew(UndoRedo());
+
+ _TestUndoRedoObject *test_object = memnew(_TestUndoRedoObject());
+
+ CHECK(test_object->get_property() == 0);
+ CHECK(undo_redo->get_version() == 1);
+ CHECK(undo_redo->get_history_count() == 0);
+
+ increment_property_action(undo_redo, "Merge Increment 1", test_object, 10, UndoRedo::MERGE_ALL);
+
+ CHECK(test_object->get_property() == 10);
+ CHECK(undo_redo->get_version() == 2);
+ CHECK(undo_redo->get_history_count() == 1);
+
+ increment_property_action(undo_redo, "Merge Increment 1", test_object, 10, UndoRedo::MERGE_ALL);
+
+ CHECK(test_object->get_property() == 20);
+ CHECK(undo_redo->get_version() == 2);
+ CHECK(undo_redo->get_history_count() == 1);
+
+ increment_property_action(undo_redo, "Merge Increment 1", test_object, 10, UndoRedo::MERGE_ALL);
+
+ CHECK(test_object->get_property() == 30);
+ CHECK(undo_redo->get_version() == 2);
+ CHECK(undo_redo->get_history_count() == 1);
+
+ undo_redo->undo();
+
+ CHECK(test_object->get_property() == 0);
+ CHECK(undo_redo->get_version() == 1);
+ CHECK(undo_redo->get_history_count() == 1);
+
+ undo_redo->redo();
+
+ CHECK(test_object->get_property() == 30);
+ CHECK(undo_redo->get_version() == 2);
+ CHECK(undo_redo->get_history_count() == 1);
+
+ memdelete(test_object);
+ memdelete(undo_redo);
+}
+
+} //namespace TestUndoRedo
+
+#endif // TEST_UNDO_REDO_H
diff --git a/tests/core/os/test_os.h b/tests/core/os/test_os.h
index 3b848bdce8..63f8b18238 100644
--- a/tests/core/os/test_os.h
+++ b/tests/core/os/test_os.h
@@ -115,6 +115,7 @@ TEST_CASE("[OS] Ticks") {
}
TEST_CASE("[OS] Feature tags") {
+#ifdef TOOLS_ENABLED
CHECK_MESSAGE(
OS::get_singleton()->has_feature("editor"),
"The binary has the \"editor\" feature tag.");
@@ -127,6 +128,29 @@ TEST_CASE("[OS] Feature tags") {
CHECK_MESSAGE(
!OS::get_singleton()->has_feature("template_release"),
"The binary does not have the \"template_release\" feature tag.");
+#else
+ CHECK_MESSAGE(
+ !OS::get_singleton()->has_feature("editor"),
+ "The binary does not have the \"editor\" feature tag.");
+ CHECK_MESSAGE(
+ OS::get_singleton()->has_feature("template"),
+ "The binary has the \"template\" feature tag.");
+#ifdef DEBUG_ENABLED
+ CHECK_MESSAGE(
+ OS::get_singleton()->has_feature("template_debug"),
+ "The binary has the \"template_debug\" feature tag.");
+ CHECK_MESSAGE(
+ !OS::get_singleton()->has_feature("template_release"),
+ "The binary does not have the \"template_release\" feature tag.");
+#else
+ CHECK_MESSAGE(
+ !OS::get_singleton()->has_feature("template_debug"),
+ "The binary does not have the \"template_debug\" feature tag.");
+ CHECK_MESSAGE(
+ OS::get_singleton()->has_feature("template_release"),
+ "The binary has the \"template_release\" feature tag.");
+#endif // DEBUG_ENABLED
+#endif // TOOLS_ENABLED
}
TEST_CASE("[OS] Process ID") {
diff --git a/tests/core/string/test_node_path.h b/tests/core/string/test_node_path.h
index b0c810bb54..bdbc578e85 100644
--- a/tests/core/string/test_node_path.h
+++ b/tests/core/string/test_node_path.h
@@ -98,44 +98,44 @@ TEST_CASE("[NodePath] Relative path") {
}
TEST_CASE("[NodePath] Absolute path") {
- const NodePath node_path_aboslute = NodePath("/root/Sprite2D");
+ const NodePath node_path_absolute = NodePath("/root/Sprite2D");
CHECK_MESSAGE(
- node_path_aboslute.get_as_property_path() == NodePath(":root/Sprite2D"),
+ node_path_absolute.get_as_property_path() == NodePath(":root/Sprite2D"),
"The returned property path should match the expected value.");
CHECK_MESSAGE(
- node_path_aboslute.get_concatenated_subnames() == "",
+ node_path_absolute.get_concatenated_subnames() == "",
"The returned concatenated subnames should match the expected value.");
CHECK_MESSAGE(
- node_path_aboslute.get_name(0) == "root",
+ node_path_absolute.get_name(0) == "root",
"The returned name at index 0 should match the expected value.");
CHECK_MESSAGE(
- node_path_aboslute.get_name(1) == "Sprite2D",
+ node_path_absolute.get_name(1) == "Sprite2D",
"The returned name at index 1 should match the expected value.");
ERR_PRINT_OFF;
CHECK_MESSAGE(
- node_path_aboslute.get_name(2) == "",
+ node_path_absolute.get_name(2) == "",
"The returned name at invalid index 2 should match the expected value.");
CHECK_MESSAGE(
- node_path_aboslute.get_name(-1) == "",
+ node_path_absolute.get_name(-1) == "",
"The returned name at invalid index -1 should match the expected value.");
ERR_PRINT_ON;
CHECK_MESSAGE(
- node_path_aboslute.get_name_count() == 2,
+ node_path_absolute.get_name_count() == 2,
"The returned number of names should match the expected value.");
CHECK_MESSAGE(
- node_path_aboslute.get_subname_count() == 0,
+ node_path_absolute.get_subname_count() == 0,
"The returned number of subnames should match the expected value.");
CHECK_MESSAGE(
- node_path_aboslute.is_absolute(),
+ node_path_absolute.is_absolute(),
"The node path should be considered absolute.");
CHECK_MESSAGE(
- !node_path_aboslute.is_empty(),
+ !node_path_absolute.is_empty(),
"The node path shouldn't be considered empty.");
}
@@ -167,6 +167,59 @@ TEST_CASE("[NodePath] Empty path") {
node_path_empty.is_empty(),
"The node path should be considered empty.");
}
+
+TEST_CASE("[NodePath] Slice") {
+ const NodePath node_path_relative = NodePath("Parent/Child:prop");
+ const NodePath node_path_absolute = NodePath("/root/Parent/Child:prop");
+ CHECK_MESSAGE(
+ node_path_relative.slice(0, 2) == NodePath("Parent/Child"),
+ "The slice lower bound should be inclusive and the slice upper bound should be exclusive.");
+ CHECK_MESSAGE(
+ node_path_relative.slice(3) == NodePath(":prop"),
+ "Slicing on the length of the path should return the last entry.");
+ CHECK_MESSAGE(
+ node_path_relative.slice(1, 3) == NodePath("Child:prop"),
+ "Slicing should include names and subnames.");
+ CHECK_MESSAGE(
+ node_path_relative.slice(-1) == NodePath(":prop"),
+ "Slicing on -1 should return the last entry.");
+ CHECK_MESSAGE(
+ node_path_relative.slice(0, -1) == NodePath("Parent/Child"),
+ "Slicing up to -1 should include the second-to-last entry.");
+ CHECK_MESSAGE(
+ node_path_relative.slice(-2, -1) == NodePath("Child"),
+ "Slicing from negative to negative should treat lower bound as inclusive and upper bound as exclusive.");
+ CHECK_MESSAGE(
+ node_path_relative.slice(0, 10) == NodePath("Parent/Child:prop"),
+ "Slicing past the length of the path should work like slicing up to the last entry.");
+ CHECK_MESSAGE(
+ node_path_relative.slice(-10, 2) == NodePath("Parent/Child"),
+ "Slicing negatively past the length of the path should work like slicing from the first entry.");
+ CHECK_MESSAGE(
+ node_path_relative.slice(1, 1) == NodePath(""),
+ "Slicing with a lower bound equal to upper bound should return empty path.");
+
+ CHECK_MESSAGE(
+ node_path_absolute.slice(0, 2) == NodePath("/root/Parent"),
+ "Slice from beginning of an absolute path should be an absolute path.");
+ CHECK_MESSAGE(
+ node_path_absolute.slice(1, 4) == NodePath("Parent/Child:prop"),
+ "Slice of an absolute path that does not start at the beginning should be a relative path.");
+ CHECK_MESSAGE(
+ node_path_absolute.slice(3, 4) == NodePath(":prop"),
+ "Slice of an absolute path that does not start at the beginning should be a relative path.");
+
+ CHECK_MESSAGE(
+ NodePath("").slice(0, 1) == NodePath(""),
+ "Slice of an empty path should be an empty path.");
+ CHECK_MESSAGE(
+ NodePath("").slice(-1, 2) == NodePath(""),
+ "Slice of an empty path should be an empty path.");
+ CHECK_MESSAGE(
+ NodePath("/").slice(-1, 2) == NodePath("/"),
+ "Slice of an empty absolute path should be an empty absolute path.");
+}
+
} // namespace TestNodePath
#endif // TEST_NODE_PATH_H
diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h
index 8a11491bb2..da742d0183 100644
--- a/tests/core/string/test_string.h
+++ b/tests/core/string/test_string.h
@@ -642,48 +642,59 @@ struct test_27_data {
TEST_CASE("[String] Begins with") {
test_27_data tc[] = {
+ // Test cases for true:
{ "res://foobar", "res://", true },
+ { "abc", "abc", true },
+ { "abc", "", true },
+ { "", "", true },
+ // Test cases for false:
{ "res", "res://", false },
- { "abc", "abc", true }
+ { "abcdef", "foo", false },
+ { "abc", "ax", false },
+ { "", "abc", false }
};
size_t count = sizeof(tc) / sizeof(tc[0]);
bool state = true;
- for (size_t i = 0; state && i < count; ++i) {
+ for (size_t i = 0; i < count; ++i) {
String s = tc[i].data;
state = s.begins_with(tc[i].part) == tc[i].expected;
- if (state) {
- String sb = tc[i].part;
- state = s.begins_with(sb) == tc[i].expected;
- }
- CHECK(state);
- if (!state) {
- break;
- }
- };
- CHECK(state);
+ CHECK_MESSAGE(state, "first check failed at: ", i);
+
+ String sb = tc[i].part;
+ state = s.begins_with(sb) == tc[i].expected;
+ CHECK_MESSAGE(state, "second check failed at: ", i);
+ }
+
+ // Test "const char *" version also with nullptr.
+ String s("foo");
+ state = s.begins_with(nullptr) == false;
+ CHECK_MESSAGE(state, "nullptr check failed");
+
+ String empty("");
+ state = empty.begins_with(nullptr) == false;
+ CHECK_MESSAGE(state, "nullptr check with empty string failed");
}
TEST_CASE("[String] Ends with") {
test_27_data tc[] = {
+ // test cases for true:
{ "res://foobar", "foobar", true },
+ { "abc", "abc", true },
+ { "abc", "", true },
+ { "", "", true },
+ // test cases for false:
{ "res", "res://", false },
- { "abc", "abc", true }
+ { "", "abc", false },
+ { "abcdef", "foo", false },
+ { "abc", "xc", false }
};
size_t count = sizeof(tc) / sizeof(tc[0]);
- bool state = true;
- for (size_t i = 0; state && i < count; ++i) {
+ for (size_t i = 0; i < count; ++i) {
String s = tc[i].data;
- state = s.ends_with(tc[i].part) == tc[i].expected;
- if (state) {
- String sb = tc[i].part;
- state = s.ends_with(sb) == tc[i].expected;
- }
- CHECK(state);
- if (!state) {
- break;
- }
- };
- CHECK(state);
+ String sb = tc[i].part;
+ bool state = s.ends_with(sb) == tc[i].expected;
+ CHECK_MESSAGE(state, "check failed at: ", i);
+ }
}
TEST_CASE("[String] format") {
@@ -1300,39 +1311,54 @@ TEST_CASE("[String] Capitalize against many strings") {
input = "snake_case_function( snake_case_arg )";
output = "Snake Case Function( Snake Case Arg )";
CHECK(input.capitalize() == output);
+
+ input = U"словоСлово_слово слово";
+ output = U"Слово Слово Слово Слово";
+ CHECK(input.capitalize() == output);
+
+ input = U"λέξηΛέξη_λέξη λέξη";
+ output = U"Λέξη Λέξη Λέξη Λέξη";
+ CHECK(input.capitalize() == output);
+
+ input = U"բառԲառ_բառ բառ";
+ output = U"Բառ Բառ Բառ Բառ";
+ CHECK(input.capitalize() == output);
}
struct StringCasesTestCase {
- const char *input;
- const char *camel_case;
- const char *pascal_case;
- const char *snake_case;
+ const char32_t *input;
+ const char32_t *camel_case;
+ const char32_t *pascal_case;
+ const char32_t *snake_case;
};
TEST_CASE("[String] Checking case conversion methods") {
StringCasesTestCase test_cases[] = {
/* clang-format off */
- { "2D", "2d", "2d", "2d" },
- { "2d", "2d", "2d", "2d" },
- { "2db", "2Db", "2Db", "2_db" },
- { "Vector3", "vector3", "Vector3", "vector_3" },
- { "sha256", "sha256", "Sha256", "sha_256" },
- { "Node2D", "node2d", "Node2d", "node_2d" },
- { "RichTextLabel", "richTextLabel", "RichTextLabel", "rich_text_label" },
- { "HTML5", "html5", "Html5", "html_5" },
- { "Node2DPosition", "node2dPosition", "Node2dPosition", "node_2d_position" },
- { "Number2Digits", "number2Digits", "Number2Digits", "number_2_digits" },
- { "get_property_list", "getPropertyList", "GetPropertyList", "get_property_list" },
- { "get_camera_2d", "getCamera2d", "GetCamera2d", "get_camera_2d" },
- { "_physics_process", "physicsProcess", "PhysicsProcess", "_physics_process" },
- { "bytes2var", "bytes2Var", "Bytes2Var", "bytes_2_var" },
- { "linear2db", "linear2Db", "Linear2Db", "linear_2_db" },
- { "sha256sum", "sha256Sum", "Sha256Sum", "sha_256_sum" },
- { "camelCase", "camelCase", "CamelCase", "camel_case" },
- { "PascalCase", "pascalCase", "PascalCase", "pascal_case" },
- { "snake_case", "snakeCase", "SnakeCase", "snake_case" },
- { "Test TEST test", "testTestTest", "TestTestTest", "test_test_test" },
- { nullptr, nullptr, nullptr, nullptr },
+ { U"2D", U"2d", U"2d", U"2d" },
+ { U"2d", U"2d", U"2d", U"2d" },
+ { U"2db", U"2Db", U"2Db", U"2_db" },
+ { U"Vector3", U"vector3", U"Vector3", U"vector_3" },
+ { U"sha256", U"sha256", U"Sha256", U"sha_256" },
+ { U"Node2D", U"node2d", U"Node2d", U"node_2d" },
+ { U"RichTextLabel", U"richTextLabel", U"RichTextLabel", U"rich_text_label" },
+ { U"HTML5", U"html5", U"Html5", U"html_5" },
+ { U"Node2DPosition", U"node2dPosition", U"Node2dPosition", U"node_2d_position" },
+ { U"Number2Digits", U"number2Digits", U"Number2Digits", U"number_2_digits" },
+ { U"get_property_list", U"getPropertyList", U"GetPropertyList", U"get_property_list" },
+ { U"get_camera_2d", U"getCamera2d", U"GetCamera2d", U"get_camera_2d" },
+ { U"_physics_process", U"physicsProcess", U"PhysicsProcess", U"_physics_process" },
+ { U"bytes2var", U"bytes2Var", U"Bytes2Var", U"bytes_2_var" },
+ { U"linear2db", U"linear2Db", U"Linear2Db", U"linear_2_db" },
+ { U"sha256sum", U"sha256Sum", U"Sha256Sum", U"sha_256_sum" },
+ { U"camelCase", U"camelCase", U"CamelCase", U"camel_case" },
+ { U"PascalCase", U"pascalCase", U"PascalCase", U"pascal_case" },
+ { U"snake_case", U"snakeCase", U"SnakeCase", U"snake_case" },
+ { U"Test TEST test", U"testTestTest", U"TestTestTest", U"test_test_test" },
+ { U"словоСлово_слово слово", U"словоСловоСловоСлово", U"СловоСловоСловоСлово", U"слово_слово_слово_слово" },
+ { U"λέξηΛέξη_λέξη λέξη", U"λέξηΛέξηΛέξηΛέξη", U"ΛέξηΛέξηΛέξηΛέξη", U"λέξη_λέξη_λέξη_λέξη" },
+ { U"բառԲառ_բառ բառ", U"բառԲառԲառԲառ", U"ԲառԲառԲառԲառ", U"բառ_բառ_բառ_բառ" },
+ { nullptr, nullptr, nullptr, nullptr },
/* clang-format on */
};
diff --git a/tests/core/string/test_translation.h b/tests/core/string/test_translation.h
index bf9674d6b1..acdd851b29 100644
--- a/tests/core/string/test_translation.h
+++ b/tests/core/string/test_translation.h
@@ -129,6 +129,7 @@ TEST_CASE("[TranslationPO] Plural messages") {
CHECK(vformat(translation->get_plural_message("There are %d apples", "", 2), 2) == "Il y a 2 pommes");
}
+#ifdef TOOLS_ENABLED
TEST_CASE("[OptimizedTranslation] Generate from Translation and read messages") {
Ref<Translation> translation = memnew(Translation);
translation->set_locale("fr");
@@ -150,7 +151,6 @@ TEST_CASE("[OptimizedTranslation] Generate from Translation and read messages")
CHECK(messages.size() == 0);
}
-#ifdef TOOLS_ENABLED
TEST_CASE("[TranslationCSV] CSV import") {
Ref<ResourceImporterCSVTranslation> import_csv_translation = memnew(ResourceImporterCSVTranslation);
diff --git a/tests/core/test_crypto.h b/tests/core/test_crypto.h
index 2fd26c3d6b..a7c2fce589 100644
--- a/tests/core/test_crypto.h
+++ b/tests/core/test_crypto.h
@@ -39,13 +39,13 @@ namespace TestCrypto {
class _MockCrypto : public Crypto {
virtual PackedByteArray generate_random_bytes(int p_bytes) { return PackedByteArray(); }
virtual Ref<CryptoKey> generate_rsa(int p_bytes) { return nullptr; }
- virtual Ref<X509Certificate> generate_self_signed_certificate(Ref<CryptoKey> p_key, String p_issuer_name, String p_not_before, String p_not_after) { return nullptr; }
+ virtual Ref<X509Certificate> generate_self_signed_certificate(Ref<CryptoKey> p_key, const String &p_issuer_name, const String &p_not_before, const String &p_not_after) { return nullptr; }
- virtual Vector<uint8_t> sign(HashingContext::HashType p_hash_type, Vector<uint8_t> p_hash, Ref<CryptoKey> p_key) { return Vector<uint8_t>(); }
- virtual bool verify(HashingContext::HashType p_hash_type, Vector<uint8_t> p_hash, Vector<uint8_t> p_signature, Ref<CryptoKey> p_key) { return false; }
- virtual Vector<uint8_t> encrypt(Ref<CryptoKey> p_key, Vector<uint8_t> p_plaintext) { return Vector<uint8_t>(); }
- virtual Vector<uint8_t> decrypt(Ref<CryptoKey> p_key, Vector<uint8_t> p_ciphertext) { return Vector<uint8_t>(); }
- virtual PackedByteArray hmac_digest(HashingContext::HashType p_hash_type, PackedByteArray p_key, PackedByteArray p_msg) { return PackedByteArray(); }
+ virtual Vector<uint8_t> sign(HashingContext::HashType p_hash_type, const Vector<uint8_t> &p_hash, Ref<CryptoKey> p_key) { return Vector<uint8_t>(); }
+ virtual bool verify(HashingContext::HashType p_hash_type, const Vector<uint8_t> &p_hash, const Vector<uint8_t> &p_signature, Ref<CryptoKey> p_key) { return false; }
+ virtual Vector<uint8_t> encrypt(Ref<CryptoKey> p_key, const Vector<uint8_t> &p_plaintext) { return Vector<uint8_t>(); }
+ virtual Vector<uint8_t> decrypt(Ref<CryptoKey> p_key, const Vector<uint8_t> &p_ciphertext) { return Vector<uint8_t>(); }
+ virtual PackedByteArray hmac_digest(HashingContext::HashType p_hash_type, const PackedByteArray &p_key, const PackedByteArray &p_msg) { return PackedByteArray(); }
};
PackedByteArray raw_to_pba(const uint8_t *arr, size_t len) {
diff --git a/tests/core/variant/test_array.h b/tests/core/variant/test_array.h
index 228d77b3b5..ea61ae2a02 100644
--- a/tests/core/variant/test_array.h
+++ b/tests/core/variant/test_array.h
@@ -367,7 +367,7 @@ TEST_CASE("[Array] Duplicate recursive array") {
Array a_shallow = a.duplicate(false);
CHECK_EQ(a, a_shallow);
- // Deep copy of recursive array endup with recursion limit and return
+ // Deep copy of recursive array ends up with recursion limit and return
// an invalid result (multiple nested arrays), the point is we should
// not end up with a segfault and an error log should be printed
ERR_PRINT_OFF;
diff --git a/tests/create_test.py b/tests/create_test.py
index 867a66e446..4d1f1d656e 100644
--- a/tests/create_test.py
+++ b/tests/create_test.py
@@ -38,7 +38,7 @@ def main():
if os.path.isfile(file_path):
print(f'ERROR: The file "{file_path}" already exists.')
sys.exit(1)
- with open(file_path, "w") as file:
+ with open(file_path, "w", encoding="utf-8", newline="\n") as file:
file.write(
"""/**************************************************************************/
/* test_{name_snake_case}.h {padding} */
@@ -108,7 +108,7 @@ TEST_CASE("[{name_pascal_case}] Example test case") {{
if match:
new_string = contents[: match.start()] + f'#include "tests/{file_path}"\n' + contents[match.start() :]
- with open("test_main.cpp", "w") as file:
+ with open("test_main.cpp", "w", encoding="utf-8", newline="\n") as file:
file.write(new_string)
print("Done.")
# Use clang format to sort include directives afster insertion.
diff --git a/tests/data/crypto/in.key b/tests/data/crypto/in.key
new file mode 100644
index 0000000000..c3380c6fe6
--- /dev/null
+++ b/tests/data/crypto/in.key
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----
diff --git a/tests/data/crypto/in.pub b/tests/data/crypto/in.pub
new file mode 100644
index 0000000000..369eebd25c
--- /dev/null
+++ b/tests/data/crypto/in.pub
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp+sWMepqN+dXhmZkS45W
+0FTLX2f0zRb+kUhXngfiEprgA2UuZP5gGv7/EjOBDniYalGZqYPJum08Px++17P6
+Hyopr05aPhZ6Ocnt+LAU/WRAFspN3xXTZglqnmGMsdNcqBl3loVNmC1H/zX53oBe
+P/L/i4lva3DjCRIpHtGjfy3ufSn7fTrlBqKIEHYgQZyzos9dxbk1NJcWVxlNmvFR
+tgPW6DQ/P3g0ahLJeq/hO3ykUFfiKdhHkS+s9dC9qjZwSxCCEF1o6zkEO6ynxk0s
+xjOpPTJFw7fQ+2KeJWJQfdZeJ6u+DpbwK4g9tMUMNxf3QMk1KhAnwwUrKXfZcviS
+3zweD8Tl5zEj45H1ghoUQfuW7Y3wgwHMu8lF8iGA87cf/fhqr0V9piCcwWkfVP/a
+thpMoUfyj9Sa3ag0dvDSo9PAet0urXmdKTyhMg4lQL6f9BmMuuB/KwWzCuG/5VY9
+ONxno3OVX6juHTpng5UglbkiDsD3tivl1gCbvIryoGdt+xI0JmAC5eXfg79Nio/B
+ayDR9Npm1m460p3GeRaawyYysBo/L5/YZ/S3bYBRoJ7lq6GkTA+22lWAb04IgtS8
+wxO4Ma8EOtKD+AoR3C+WLivcp9LNTxbQOMKGL+8imQGBEz3XTR4lrE02QDQy0DIB
+Ky7p7dhlyBdwhTmBX3P2mx0CAwEAAQ==
+-----END PUBLIC KEY-----
diff --git a/tests/scene/test_arraymesh.h b/tests/scene/test_arraymesh.h
index 1623b41300..67aa19c5d3 100644
--- a/tests/scene/test_arraymesh.h
+++ b/tests/scene/test_arraymesh.h
@@ -31,8 +31,8 @@
#ifndef TEST_ARRAYMESH_H
#define TEST_ARRAYMESH_H
+#include "scene/resources/3d/primitive_meshes.h"
#include "scene/resources/mesh.h"
-#include "scene/resources/primitive_meshes.h"
#include "tests/test_macros.h"
diff --git a/tests/scene/test_audio_stream_wav.h b/tests/scene/test_audio_stream_wav.h
index e36f049136..ed1697929e 100644
--- a/tests/scene/test_audio_stream_wav.h
+++ b/tests/scene/test_audio_stream_wav.h
@@ -148,7 +148,7 @@ void run_test(String file_name, AudioStreamWAV::Format data_format, bool stereo,
Ref<FileAccess> wav_file = FileAccess::open(save_path, FileAccess::READ, &error);
REQUIRE(error == OK);
-#if TOOLS_ENABLED
+#ifdef TOOLS_ENABLED
// The WAV importer can be used if enabled to check that the saved file is valid.
Ref<ResourceImporterWAV> wav_importer = memnew(ResourceImporterWAV);
diff --git a/tests/scene/test_camera_3d.h b/tests/scene/test_camera_3d.h
index 169486d108..830c667257 100644
--- a/tests/scene/test_camera_3d.h
+++ b/tests/scene/test_camera_3d.h
@@ -65,17 +65,17 @@ TEST_CASE("[SceneTree][Camera3D] Getters and setters") {
}
SUBCASE("Camera frustum properties") {
- constexpr float near = 0.2f;
- constexpr float far = 995.0f;
+ constexpr float depth_near = 0.2f;
+ constexpr float depth_far = 995.0f;
constexpr float fov = 120.0f;
constexpr float size = 7.0f;
constexpr float h_offset = 1.1f;
constexpr float v_offset = -1.6f;
const Vector2 frustum_offset(5, 7);
- test_camera->set_near(near);
- CHECK(test_camera->get_near() == near);
- test_camera->set_far(far);
- CHECK(test_camera->get_far() == far);
+ test_camera->set_near(depth_near);
+ CHECK(test_camera->get_near() == depth_near);
+ test_camera->set_far(depth_far);
+ CHECK(test_camera->get_far() == depth_far);
test_camera->set_fov(fov);
CHECK(test_camera->get_fov() == fov);
test_camera->set_size(size);
diff --git a/tests/scene/test_image_texture.h b/tests/scene/test_image_texture.h
new file mode 100644
index 0000000000..c9282165a6
--- /dev/null
+++ b/tests/scene/test_image_texture.h
@@ -0,0 +1,111 @@
+/**************************************************************************/
+/* test_image_texture.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_IMAGE_TEXTURE_H
+#define TEST_IMAGE_TEXTURE_H
+
+#include "core/io/image.h"
+#include "scene/resources/image_texture.h"
+
+#include "tests/test_macros.h"
+#include "tests/test_utils.h"
+
+namespace TestImageTexture {
+
+// [SceneTree] in a test case name enables initializing a mock render server,
+// which ImageTexture is dependent on.
+TEST_CASE("[SceneTree][ImageTexture] constructor") {
+ Ref<ImageTexture> image_texture = memnew(ImageTexture);
+ CHECK(image_texture->get_width() == 0);
+ CHECK(image_texture->get_height() == 0);
+ CHECK(image_texture->get_format() == 0);
+ CHECK(image_texture->has_alpha() == false);
+ CHECK(image_texture->get_image() == Ref<Image>());
+}
+
+TEST_CASE("[SceneTree][ImageTexture] create_from_image") {
+ Ref<Image> image = memnew(Image(16, 8, true, Image::FORMAT_RGBA8));
+ Ref<ImageTexture> image_texture = ImageTexture::create_from_image(image);
+ CHECK(image_texture->get_width() == 16);
+ CHECK(image_texture->get_height() == 8);
+ CHECK(image_texture->get_format() == Image::FORMAT_RGBA8);
+ CHECK(image_texture->has_alpha() == true);
+ CHECK(image_texture->get_rid().is_valid() == true);
+}
+
+TEST_CASE("[SceneTree][ImageTexture] set_image") {
+ Ref<ImageTexture> image_texture = memnew(ImageTexture);
+ Ref<Image> image = memnew(Image(8, 4, false, Image::FORMAT_RGB8));
+ image_texture->set_image(image);
+ CHECK(image_texture->get_width() == 8);
+ CHECK(image_texture->get_height() == 4);
+ CHECK(image_texture->get_format() == Image::FORMAT_RGB8);
+ CHECK(image_texture->has_alpha() == false);
+ CHECK(image_texture->get_width() == image_texture->get_image()->get_width());
+ CHECK(image_texture->get_height() == image_texture->get_image()->get_height());
+ CHECK(image_texture->get_format() == image_texture->get_image()->get_format());
+}
+
+TEST_CASE("[SceneTree][ImageTexture] set_size_override") {
+ Ref<Image> image = memnew(Image(16, 8, false, Image::FORMAT_RGB8));
+ Ref<ImageTexture> image_texture = ImageTexture::create_from_image(image);
+ CHECK(image_texture->get_width() == 16);
+ CHECK(image_texture->get_height() == 8);
+ image_texture->set_size_override(Size2i(32, 16));
+ CHECK(image_texture->get_width() == 32);
+ CHECK(image_texture->get_height() == 16);
+}
+
+TEST_CASE("[SceneTree][ImageTexture] is_pixel_opaque") {
+ Ref<Image> image = memnew(Image(8, 8, false, Image::FORMAT_RGBA8));
+ image->set_pixel(0, 0, Color(0.0, 0.0, 0.0, 0.0)); // not opaque
+ image->set_pixel(0, 1, Color(0.0, 0.0, 0.0, 0.1)); // not opaque
+ image->set_pixel(0, 2, Color(0.0, 0.0, 0.0, 0.5)); // opaque
+ image->set_pixel(0, 3, Color(0.0, 0.0, 0.0, 0.9)); // opaque
+ image->set_pixel(0, 4, Color(0.0, 0.0, 0.0, 1.0)); // opaque
+
+ Ref<ImageTexture> image_texture = ImageTexture::create_from_image(image);
+ CHECK(image_texture->is_pixel_opaque(0, 0) == false);
+ CHECK(image_texture->is_pixel_opaque(0, 1) == false);
+ CHECK(image_texture->is_pixel_opaque(0, 2) == true);
+ CHECK(image_texture->is_pixel_opaque(0, 3) == true);
+ CHECK(image_texture->is_pixel_opaque(0, 4) == true);
+}
+
+TEST_CASE("[SceneTree][ImageTexture] set_path") {
+ Ref<ImageTexture> image_texture = memnew(ImageTexture);
+ String path = TestUtils::get_data_path("images/icon.png");
+ image_texture->set_path(path, true);
+ CHECK(image_texture->get_path() == path);
+}
+
+} //namespace TestImageTexture
+
+#endif // TEST_IMAGE_TEXTURE_H
diff --git a/tests/scene/test_navigation_region_3d.h b/tests/scene/test_navigation_region_3d.h
index 4c5ae34615..372f6dc505 100644
--- a/tests/scene/test_navigation_region_3d.h
+++ b/tests/scene/test_navigation_region_3d.h
@@ -31,8 +31,10 @@
#ifndef TEST_NAVIGATION_REGION_3D_H
#define TEST_NAVIGATION_REGION_3D_H
+#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/navigation_region_3d.h"
#include "scene/main/window.h"
+#include "scene/resources/3d/primitive_meshes.h"
#include "tests/test_macros.h"
@@ -44,6 +46,44 @@ TEST_SUITE("[Navigation]") {
CHECK(region_node->get_region_rid().is_valid());
memdelete(region_node);
}
+
+ TEST_CASE("[SceneTree][NavigationRegion3D] Region should bake successfully from valid geometry") {
+ Node3D *node_3d = memnew(Node3D);
+ SceneTree::get_singleton()->get_root()->add_child(node_3d);
+ Ref<NavigationMesh> navigation_mesh = memnew(NavigationMesh);
+ NavigationRegion3D *navigation_region = memnew(NavigationRegion3D);
+ navigation_region->set_navigation_mesh(navigation_mesh);
+ node_3d->add_child(navigation_region);
+ Ref<PlaneMesh> plane_mesh = memnew(PlaneMesh);
+ plane_mesh->set_size(Size2(10.0, 10.0));
+ MeshInstance3D *mesh_instance = memnew(MeshInstance3D);
+ mesh_instance->set_mesh(plane_mesh);
+ navigation_region->add_child(mesh_instance);
+
+ CHECK_FALSE(navigation_region->is_baking());
+ CHECK_EQ(navigation_mesh->get_polygon_count(), 0);
+ CHECK_EQ(navigation_mesh->get_vertices().size(), 0);
+
+ SUBCASE("Synchronous bake should have immediate effects") {
+ navigation_region->bake_navigation_mesh(false);
+ CHECK_FALSE(navigation_region->is_baking());
+ CHECK_NE(navigation_mesh->get_polygon_count(), 0);
+ CHECK_NE(navigation_mesh->get_vertices().size(), 0);
+ }
+
+ // Race condition is present in the below subcase, but baking should take many
+ // orders of magnitude longer than basic checks on the main thread, so it's fine.
+ SUBCASE("Asynchronous bake should not be immediate") {
+ navigation_region->bake_navigation_mesh(true);
+ CHECK(navigation_region->is_baking());
+ CHECK_EQ(navigation_mesh->get_polygon_count(), 0);
+ CHECK_EQ(navigation_mesh->get_vertices().size(), 0);
+ }
+
+ memdelete(mesh_instance);
+ memdelete(navigation_region);
+ memdelete(node_3d);
+ }
}
} //namespace TestNavigationRegion3D
diff --git a/tests/scene/test_node_2d.h b/tests/scene/test_node_2d.h
index 7e93c77e22..8cf6408438 100644
--- a/tests/scene/test_node_2d.h
+++ b/tests/scene/test_node_2d.h
@@ -32,6 +32,7 @@
#define TEST_NODE_2D_H
#include "scene/2d/node_2d.h"
+#include "scene/main/window.h"
#include "tests/test_macros.h"
@@ -56,6 +57,33 @@ TEST_CASE("[SceneTree][Node2D]") {
memdelete(test_child);
memdelete(test_node);
}
+
+ SUBCASE("[Node2D][Global Transform] Global Transform should be correct after inserting node from detached tree into SceneTree.") { // GH-86841
+ Node2D *main = memnew(Node2D);
+ Node2D *outer = memnew(Node2D);
+ Node2D *inner = memnew(Node2D);
+ SceneTree::get_singleton()->get_root()->add_child(main);
+
+ main->set_position(Point2(100, 100));
+ outer->set_position(Point2(10, 0));
+ inner->set_position(Point2(0, 10));
+
+ outer->add_child(inner);
+ // `inner` is still detached.
+ CHECK_EQ(inner->get_global_position(), Point2(10, 10));
+
+ main->add_child(outer);
+ // `inner` is in scene tree.
+ CHECK_EQ(inner->get_global_position(), Point2(110, 110));
+
+ main->remove_child(outer);
+ // `inner` is detached again.
+ CHECK_EQ(inner->get_global_position(), Point2(10, 10));
+
+ memdelete(inner);
+ memdelete(outer);
+ memdelete(main);
+ }
}
} // namespace TestNode2D
diff --git a/tests/scene/test_primitives.h b/tests/scene/test_primitives.h
index 552f722d24..f105e1ac04 100644
--- a/tests/scene/test_primitives.h
+++ b/tests/scene/test_primitives.h
@@ -31,7 +31,7 @@
#ifndef TEST_PRIMITIVES_H
#define TEST_PRIMITIVES_H
-#include "scene/resources/primitive_meshes.h"
+#include "scene/resources/3d/primitive_meshes.h"
#include "tests/test_macros.h"
@@ -68,8 +68,10 @@ TEST_CASE("[SceneTree][Primitive][Capsule] Capsule Primitive") {
}
SUBCASE("[SceneTree][Primitive][Capsule] If set segments negative, default to at least 0") {
+ ERR_PRINT_OFF;
capsule->set_radial_segments(-5);
capsule->set_rings(-17);
+ ERR_PRINT_ON;
CHECK_MESSAGE(capsule->get_radial_segments() >= 0,
"Ensure number of radial segments is >= 0.");
@@ -165,9 +167,11 @@ TEST_CASE("[SceneTree][Primitive][Box] Box Primitive") {
}
SUBCASE("[SceneTree][Primitive][Box] Set subdivides to negative and ensure they are >= 0") {
+ ERR_PRINT_OFF;
box->set_subdivide_width(-2);
box->set_subdivide_height(-2);
box->set_subdivide_depth(-2);
+ ERR_PRINT_ON;
CHECK(box->get_subdivide_width() >= 0);
CHECK(box->get_subdivide_height() >= 0);
@@ -254,8 +258,10 @@ TEST_CASE("[SceneTree][Primitive][Cylinder] Cylinder Primitive") {
}
SUBCASE("[SceneTree][Primitive][Cylinder] Ensure num segments is >= 0") {
+ ERR_PRINT_OFF;
cylinder->set_radial_segments(-12);
cylinder->set_rings(-16);
+ ERR_PRINT_ON;
CHECK(cylinder->get_radial_segments() >= 0);
CHECK(cylinder->get_rings() >= 0);
@@ -441,8 +447,10 @@ TEST_CASE("[SceneTree][Primitive][Plane] Plane Primitive") {
}
SUBCASE("[SceneTree][Primitive][Plane] Ensure number of segments is >= 0.") {
+ ERR_PRINT_OFF;
plane->set_subdivide_width(-15);
plane->set_subdivide_depth(-29);
+ ERR_PRINT_ON;
CHECK(plane->get_subdivide_width() >= 0);
CHECK(plane->get_subdivide_depth() >= 0);
@@ -486,9 +494,11 @@ TEST_CASE("[SceneTree][Primitive][Prism] Prism Primitive") {
}
SUBCASE("[Primitive][Prism] Ensure number of segments always >= 0") {
+ ERR_PRINT_OFF;
prism->set_subdivide_width(-36);
prism->set_subdivide_height(-5);
prism->set_subdivide_depth(-64);
+ ERR_PRINT_ON;
CHECK(prism->get_subdivide_width() >= 0);
CHECK(prism->get_subdivide_height() >= 0);
@@ -521,8 +531,10 @@ TEST_CASE("[SceneTree][Primitive][Sphere] Sphere Primitive") {
}
SUBCASE("[Primitive][Sphere] Ensure number of segments always >= 0") {
+ ERR_PRINT_OFF;
sphere->set_radial_segments(-36);
sphere->set_rings(-5);
+ ERR_PRINT_ON;
CHECK(sphere->get_radial_segments() >= 0);
CHECK(sphere->get_rings() >= 0);
diff --git a/tests/scene/test_viewport.h b/tests/scene/test_viewport.h
index 1afae66ee0..66b0f438cc 100644
--- a/tests/scene/test_viewport.h
+++ b/tests/scene/test_viewport.h
@@ -31,13 +31,13 @@
#ifndef TEST_VIEWPORT_H
#define TEST_VIEWPORT_H
-#include "scene/2d/area_2d.h"
-#include "scene/2d/collision_shape_2d.h"
+#include "scene/2d/physics/area_2d.h"
+#include "scene/2d/physics/collision_shape_2d.h"
#include "scene/gui/control.h"
#include "scene/gui/subviewport_container.h"
#include "scene/main/canvas_layer.h"
#include "scene/main/window.h"
-#include "scene/resources/rectangle_shape_2d.h"
+#include "scene/resources/2d/rectangle_shape_2d.h"
#include "tests/test_macros.h"
diff --git a/tests/servers/test_navigation_server_3d.h b/tests/servers/test_navigation_server_3d.h
index 5ab2975b74..827a1bed17 100644
--- a/tests/servers/test_navigation_server_3d.h
+++ b/tests/servers/test_navigation_server_3d.h
@@ -32,11 +32,9 @@
#define TEST_NAVIGATION_SERVER_3D_H
#include "scene/3d/mesh_instance_3d.h"
-#include "scene/resources/primitive_meshes.h"
+#include "scene/resources/3d/primitive_meshes.h"
#include "servers/navigation_server_3d.h"
-#include "tests/test_macros.h"
-
namespace TestNavigationServer3D {
// TODO: Find a more generic way to create `Callable` mocks.
@@ -580,6 +578,51 @@ TEST_SUITE("[Navigation]") {
}
#endif // DISABLE_DEPRECATED
+ TEST_CASE("[NavigationServer3D][SceneTree] Server should be able to parse geometry") {
+ NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
+
+ // Prepare scene tree with simple mesh to serve as an input geometry.
+ Node3D *node_3d = memnew(Node3D);
+ SceneTree::get_singleton()->get_root()->add_child(node_3d);
+ Ref<PlaneMesh> plane_mesh = memnew(PlaneMesh);
+ plane_mesh->set_size(Size2(10.0, 10.0));
+ MeshInstance3D *mesh_instance = memnew(MeshInstance3D);
+ mesh_instance->set_mesh(plane_mesh);
+ node_3d->add_child(mesh_instance);
+
+ Ref<NavigationMesh> navigation_mesh = memnew(NavigationMesh);
+ Ref<NavigationMeshSourceGeometryData3D> source_geometry = memnew(NavigationMeshSourceGeometryData3D);
+ CHECK_EQ(source_geometry->get_vertices().size(), 0);
+ CHECK_EQ(source_geometry->get_indices().size(), 0);
+
+ navigation_server->parse_source_geometry_data(navigation_mesh, source_geometry, mesh_instance);
+ CHECK_EQ(source_geometry->get_vertices().size(), 12);
+ CHECK_EQ(source_geometry->get_indices().size(), 6);
+
+ SUBCASE("By default, parsing should remove any data that was parsed before") {
+ navigation_server->parse_source_geometry_data(navigation_mesh, source_geometry, mesh_instance);
+ CHECK_EQ(source_geometry->get_vertices().size(), 12);
+ CHECK_EQ(source_geometry->get_indices().size(), 6);
+ }
+
+ SUBCASE("Parsed geometry should be extendible with other geometry") {
+ source_geometry->merge(source_geometry); // Merging with itself.
+ const Vector<float> vertices = source_geometry->get_vertices();
+ const Vector<int> indices = source_geometry->get_indices();
+ REQUIRE_EQ(vertices.size(), 24);
+ REQUIRE_EQ(indices.size(), 12);
+ // Check if first newly added vertex is the same as first vertex.
+ CHECK_EQ(vertices[0], vertices[12]);
+ CHECK_EQ(vertices[1], vertices[13]);
+ CHECK_EQ(vertices[2], vertices[14]);
+ // Check if first newly added index is the same as first index.
+ CHECK_EQ(indices[0] + 4, indices[6]);
+ }
+
+ memdelete(mesh_instance);
+ memdelete(node_3d);
+ }
+
// This test case uses only public APIs on purpose - other test cases use simplified baking.
TEST_CASE("[NavigationServer3D][SceneTree] Server should be able to bake map correctly") {
NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
@@ -720,6 +763,24 @@ TEST_SUITE("[Navigation]") {
navigation_server->free(map);
navigation_server->process(0.0); // Give server some cycles to commit.
}
+
+ TEST_CASE("[NavigationServer3D] Server should be able to bake asynchronously") {
+ NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
+ Ref<NavigationMesh> navigation_mesh = memnew(NavigationMesh);
+ Ref<NavigationMeshSourceGeometryData3D> source_geometry = memnew(NavigationMeshSourceGeometryData3D);
+
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ BoxMesh::create_mesh_array(arr, Vector3(10.0, 0.001, 10.0));
+ source_geometry->add_mesh_array(arr, Transform3D());
+
+ // Race condition is present below, but baking should take many orders of magnitude
+ // longer than basic checks on the main thread, so it's fine.
+ navigation_server->bake_from_source_geometry_data_async(navigation_mesh, source_geometry, Callable());
+ CHECK(navigation_server->is_baking_navigation_mesh(navigation_mesh));
+ CHECK_EQ(navigation_mesh->get_polygon_count(), 0);
+ CHECK_EQ(navigation_mesh->get_vertices().size(), 0);
+ }
}
} //namespace TestNavigationServer3D
diff --git a/tests/servers/test_text_server.h b/tests/servers/test_text_server.h
index 0f23929e1e..334c642d26 100644
--- a/tests/servers/test_text_server.h
+++ b/tests/servers/test_text_server.h
@@ -33,7 +33,7 @@
#ifdef TOOLS_ENABLED
-#include "editor/builtin_fonts.gen.h"
+#include "editor/themes/builtin_fonts.gen.h"
#include "servers/text_server.h"
#include "tests/test_macros.h"
diff --git a/tests/test_macros.h b/tests/test_macros.h
index bc85ec6ddc..a173b37a2d 100644
--- a/tests/test_macros.h
+++ b/tests/test_macros.h
@@ -161,11 +161,11 @@ int register_test_command(String p_command, TestFunc p_function);
MessageQueue::get_singleton()->flush(); \
}
-#define _UPDATE_EVENT_MODIFERS(m_event, m_modifers) \
- m_event->set_shift_pressed(((m_modifers)&KeyModifierMask::SHIFT) != Key::NONE); \
- m_event->set_alt_pressed(((m_modifers)&KeyModifierMask::ALT) != Key::NONE); \
- m_event->set_ctrl_pressed(((m_modifers)&KeyModifierMask::CTRL) != Key::NONE); \
- m_event->set_meta_pressed(((m_modifers)&KeyModifierMask::META) != Key::NONE);
+#define _UPDATE_EVENT_MODIFERS(m_event, m_modifers) \
+ m_event->set_shift_pressed(((m_modifers) & KeyModifierMask::SHIFT) != Key::NONE); \
+ m_event->set_alt_pressed(((m_modifers) & KeyModifierMask::ALT) != Key::NONE); \
+ m_event->set_ctrl_pressed(((m_modifers) & KeyModifierMask::CTRL) != Key::NONE); \
+ m_event->set_meta_pressed(((m_modifers) & KeyModifierMask::META) != Key::NONE);
#define _CREATE_GUI_MOUSE_EVENT(m_screen_pos, m_input, m_mask, m_modifers) \
Ref<InputEventMouseButton> event; \
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 5187ebd00f..423932e2cd 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -30,6 +30,11 @@
#include "test_main.h"
+#ifdef TOOLS_ENABLED
+#include "editor/editor_paths.h"
+#include "editor/editor_settings.h"
+#endif // TOOLS_ENABLED
+
#include "tests/core/config/test_project_settings.h"
#include "tests/core/input/test_input_event.h"
#include "tests/core/input/test_input_event_key.h"
@@ -68,6 +73,7 @@
#include "tests/core/object/test_class_db.h"
#include "tests/core/object/test_method_bind.h"
#include "tests/core/object/test_object.h"
+#include "tests/core/object/test_undo_redo.h"
#include "tests/core/os/test_os.h"
#include "tests/core/string/test_node_path.h"
#include "tests/core/string/test_string.h"
@@ -94,7 +100,6 @@
#include "tests/scene/test_arraymesh.h"
#include "tests/scene/test_audio_stream_wav.h"
#include "tests/scene/test_bit_map.h"
-#include "tests/scene/test_camera_3d.h"
#include "tests/scene/test_code_edit.h"
#include "tests/scene/test_color_picker.h"
#include "tests/scene/test_control.h"
@@ -102,18 +107,11 @@
#include "tests/scene/test_curve_2d.h"
#include "tests/scene/test_curve_3d.h"
#include "tests/scene/test_gradient.h"
-#include "tests/scene/test_navigation_agent_2d.h"
-#include "tests/scene/test_navigation_agent_3d.h"
-#include "tests/scene/test_navigation_obstacle_2d.h"
-#include "tests/scene/test_navigation_obstacle_3d.h"
-#include "tests/scene/test_navigation_region_2d.h"
-#include "tests/scene/test_navigation_region_3d.h"
+#include "tests/scene/test_image_texture.h"
#include "tests/scene/test_node.h"
#include "tests/scene/test_node_2d.h"
#include "tests/scene/test_packed_scene.h"
#include "tests/scene/test_path_2d.h"
-#include "tests/scene/test_path_3d.h"
-#include "tests/scene/test_primitives.h"
#include "tests/scene/test_sprite_frames.h"
#include "tests/scene/test_text_edit.h"
#include "tests/scene/test_theme.h"
@@ -121,21 +119,37 @@
#include "tests/scene/test_visual_shader.h"
#include "tests/scene/test_window.h"
#include "tests/servers/rendering/test_shader_preprocessor.h"
-#include "tests/servers/test_navigation_server_2d.h"
-#include "tests/servers/test_navigation_server_3d.h"
#include "tests/servers/test_text_server.h"
#include "tests/test_validate_testing.h"
+#ifndef _3D_DISABLED
+#include "tests/scene/test_camera_3d.h"
+#include "tests/scene/test_navigation_agent_2d.h"
+#include "tests/scene/test_navigation_agent_3d.h"
+#include "tests/scene/test_navigation_obstacle_2d.h"
+#include "tests/scene/test_navigation_obstacle_3d.h"
+#include "tests/scene/test_navigation_region_2d.h"
+#include "tests/scene/test_navigation_region_3d.h"
+#include "tests/scene/test_path_3d.h"
+#include "tests/scene/test_primitives.h"
+#include "tests/servers/test_navigation_server_2d.h"
+#include "tests/servers/test_navigation_server_3d.h"
+#endif // _3D_DISABLED
+
#include "modules/modules_tests.gen.h"
#include "tests/display_server_mock.h"
#include "tests/test_macros.h"
#include "scene/theme/theme_db.h"
+#ifndef _3D_DISABLED
#include "servers/navigation_server_2d.h"
#include "servers/navigation_server_3d.h"
+#endif // _3D_DISABLED
#include "servers/physics_server_2d.h"
+#ifndef _3D_DISABLED
#include "servers/physics_server_3d.h"
+#endif // _3D_DISABLED
#include "servers/rendering/rendering_server_default.h"
int test_main(int argc, char *argv[]) {
@@ -210,10 +224,12 @@ struct GodotTestCaseListener : public doctest::IReporter {
SignalWatcher *signal_watcher = nullptr;
- PhysicsServer3D *physics_server_3d = nullptr;
PhysicsServer2D *physics_server_2d = nullptr;
+#ifndef _3D_DISABLED
+ PhysicsServer3D *physics_server_3d = nullptr;
NavigationServer3D *navigation_server_3d = nullptr;
NavigationServer2D *navigation_server_2d = nullptr;
+#endif // _3D_DISABLED
void test_case_start(const doctest::TestCaseData &p_in) override {
reinitialize();
@@ -221,7 +237,7 @@ struct GodotTestCaseListener : public doctest::IReporter {
String name = String(p_in.m_name);
String suite_name = String(p_in.m_test_suite);
- if (name.find("[SceneTree]") != -1) {
+ if (name.find("[SceneTree]") != -1 || name.find("[Editor]") != -1) {
memnew(MessageQueue);
memnew(Input);
@@ -245,16 +261,20 @@ struct GodotTestCaseListener : public doctest::IReporter {
ThemeDB::get_singleton()->finalize_theme();
ThemeDB::get_singleton()->initialize_theme_noproject();
+#ifndef _3D_DISABLED
physics_server_3d = PhysicsServer3DManager::get_singleton()->new_default_server();
physics_server_3d->init();
+#endif // _3D_DISABLED
physics_server_2d = PhysicsServer2DManager::get_singleton()->new_default_server();
physics_server_2d->init();
+#ifndef _3D_DISABLED
ERR_PRINT_OFF;
navigation_server_3d = NavigationServer3DManager::new_default_server();
navigation_server_2d = NavigationServer2DManager::new_default_server();
ERR_PRINT_ON;
+#endif // _3D_DISABLED
memnew(InputMap);
InputMap::get_singleton()->load_default();
@@ -264,6 +284,15 @@ struct GodotTestCaseListener : public doctest::IReporter {
if (!DisplayServer::get_singleton()->has_feature(DisplayServer::Feature::FEATURE_SUBWINDOWS)) {
SceneTree::get_singleton()->get_root()->set_embedding_subwindows(true);
}
+
+#ifdef TOOLS_ENABLED
+ if (name.find("[Editor]") != -1) {
+ Engine::get_singleton()->set_editor_hint(true);
+ EditorPaths::create();
+ EditorSettings::create();
+ }
+#endif // TOOLS_ENABLED
+
return;
}
@@ -276,6 +305,7 @@ struct GodotTestCaseListener : public doctest::IReporter {
return;
}
+#ifndef _3D_DISABLED
if (suite_name.find("[Navigation]") != -1 && navigation_server_2d == nullptr && navigation_server_3d == nullptr) {
ERR_PRINT_OFF;
navigation_server_3d = NavigationServer3DManager::new_default_server();
@@ -283,9 +313,18 @@ struct GodotTestCaseListener : public doctest::IReporter {
ERR_PRINT_ON;
return;
}
+#endif // _3D_DISABLED
}
void test_case_end(const doctest::CurrentTestCaseStats &) override {
+#ifdef TOOLS_ENABLED
+ if (EditorSettings::get_singleton()) {
+ EditorSettings::destroy();
+ }
+#endif // TOOLS_ENABLED
+
+ Engine::get_singleton()->set_editor_hint(false);
+
if (SceneTree::get_singleton()) {
SceneTree::get_singleton()->finalize();
}
@@ -298,6 +337,7 @@ struct GodotTestCaseListener : public doctest::IReporter {
memdelete(SceneTree::get_singleton());
}
+#ifndef _3D_DISABLED
if (navigation_server_3d) {
memdelete(navigation_server_3d);
navigation_server_3d = nullptr;
@@ -307,12 +347,15 @@ struct GodotTestCaseListener : public doctest::IReporter {
memdelete(navigation_server_2d);
navigation_server_2d = nullptr;
}
+#endif // _3D_DISABLED
+#ifndef _3D_DISABLED
if (physics_server_3d) {
physics_server_3d->finish();
memdelete(physics_server_3d);
physics_server_3d = nullptr;
}
+#endif // _3D_DISABLED
if (physics_server_2d) {
physics_server_2d->finish();