diff options
Diffstat (limited to 'tests')
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(); |