diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/test_array.h | 186 | ||||
-rw-r--r-- | tests/test_class_db.h | 43 | ||||
-rw-r--r-- | tests/test_main.cpp | 2 | ||||
-rw-r--r-- | tests/test_path_follow_2d.h | 229 | ||||
-rw-r--r-- | tests/test_path_follow_3d.h | 220 | ||||
-rw-r--r-- | tests/test_render.cpp | 4 | ||||
-rw-r--r-- | tests/test_resource.h | 114 |
7 files changed, 791 insertions, 7 deletions
diff --git a/tests/test_array.h b/tests/test_array.h new file mode 100644 index 0000000000..52da256860 --- /dev/null +++ b/tests/test_array.h @@ -0,0 +1,186 @@ +/*************************************************************************/ +/* test_array.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEST_ARRAY_H +#define TEST_ARRAY_H + +#include "core/object/class_db.h" +#include "core/object/script_language.h" +#include "core/templates/hashfuncs.h" +#include "core/templates/vector.h" +#include "core/variant/array.h" +#include "core/variant/container_type_validate.h" +#include "core/variant/variant.h" +#include "tests/test_macros.h" + +namespace TestArray { + +TEST_CASE("[Array] size(), clear(), and is_empty()") { + Array arr; + CHECK(arr.size() == 0); + CHECK(arr.is_empty()); + arr.push_back(1); + CHECK(arr.size() == 1); + arr.clear(); + CHECK(arr.is_empty()); + CHECK(arr.size() == 0); +} + +TEST_CASE("[Array] Assignment and comparison operators") { + Array arr1; + Array arr2; + arr1.push_back(1); + CHECK(arr1 != arr2); + CHECK(arr1 > arr2); + CHECK(arr1 >= arr2); + arr2.push_back(2); + CHECK(arr1 != arr2); + CHECK(arr1 < arr2); + CHECK(arr1 <= arr2); + CHECK(arr2 > arr1); + CHECK(arr2 >= arr1); + Array arr3 = arr2; + CHECK(arr3 == arr2); +} + +TEST_CASE("[Array] append_array()") { + Array arr1; + Array arr2; + arr1.push_back(1); + arr1.append_array(arr2); + CHECK(arr1.size() == 1); + arr2.push_back(2); + arr1.append_array(arr2); + CHECK(arr1.size() == 2); + CHECK(int(arr1[0]) == 1); + CHECK(int(arr1[1]) == 2); +} + +TEST_CASE("[Array] resize(), insert(), and erase()") { + Array arr; + arr.resize(2); + CHECK(arr.size() == 2); + arr.insert(0, 1); + CHECK(int(arr[0]) == 1); + arr.insert(0, 2); + CHECK(int(arr[0]) == 2); + arr.erase(2); + CHECK(int(arr[0]) == 1); +} + +TEST_CASE("[Array] front() and back()") { + Array arr; + arr.push_back(1); + CHECK(int(arr.front()) == 1); + CHECK(int(arr.back()) == 1); + arr.push_back(3); + CHECK(int(arr.front()) == 1); + CHECK(int(arr.back()) == 3); +} + +TEST_CASE("[Array] has() and count()") { + Array arr; + arr.push_back(1); + arr.push_back(1); + CHECK(arr.has(1)); + CHECK(!arr.has(2)); + CHECK(arr.count(1) == 2); + CHECK(arr.count(2) == 0); +} + +TEST_CASE("[Array] remove()") { + Array arr; + arr.push_back(1); + arr.push_back(2); + arr.remove(0); + CHECK(arr.size() == 1); + CHECK(int(arr[0]) == 2); + arr.remove(0); + CHECK(arr.size() == 0); + + // The array is now empty; try to use `remove()` again. + // Normally, this prints an error message so we silence it. + ERR_PRINT_OFF; + arr.remove(0); + ERR_PRINT_ON; + + CHECK(arr.size() == 0); +} + +TEST_CASE("[Array] get()") { + Array arr; + arr.push_back(1); + CHECK(int(arr.get(0)) == 1); +} + +TEST_CASE("[Array] sort()") { + Array arr; + + arr.push_back(3); + arr.push_back(4); + arr.push_back(2); + arr.push_back(1); + arr.sort(); + int val = 1; + for (int i = 0; i < arr.size(); i++) { + CHECK(int(arr[i]) == val); + val++; + } +} + +TEST_CASE("[Array] push_front(), pop_front(), pop_back()") { + Array arr; + arr.push_front(1); + arr.push_front(2); + CHECK(int(arr[0]) == 2); + arr.pop_front(); + CHECK(int(arr[0]) == 1); + CHECK(arr.size() == 1); + arr.push_front(2); + arr.push_front(3); + arr.pop_back(); + CHECK(int(arr[1]) == 2); + CHECK(arr.size() == 2); +} + +TEST_CASE("[Array] max() and min()") { + Array arr; + arr.push_back(3); + arr.push_front(4); + arr.push_back(5); + arr.push_back(2); + int max = int(arr.max()); + int min = int(arr.min()); + CHECK(max == 5); + CHECK(min == 2); +} +} // namespace TestArray + +#endif // TEST_ARRAY_H diff --git a/tests/test_class_db.h b/tests/test_class_db.h index b1440b83ef..9ef4569c14 100644 --- a/tests/test_class_db.h +++ b/tests/test_class_db.h @@ -340,7 +340,14 @@ void validate_property(const Context &p_context, const ExposedClass &p_class, co if (prop_class) { TEST_COND(prop_class->is_singleton, "Property type is a singleton: '", p_class.name, ".", String(p_prop.name), "'."); + + if (p_class.api_type == ClassDB::API_CORE) { + TEST_COND(prop_class->api_type == ClassDB::API_EDITOR, + "Property '", p_class.name, ".", p_prop.name, "' has type '", prop_class->name, + "' from the editor API. Core API cannot have dependencies on the editor API."); + } } else { + // Look for types that don't inherit Object TEST_FAIL_COND(!p_context.has_type(prop_type_ref), "Property type '", prop_type_ref.name, "' not found: '", p_class.name, ".", String(p_prop.name), "'."); } @@ -370,10 +377,22 @@ void validate_property(const Context &p_context, const ExposedClass &p_class, co } void validate_method(const Context &p_context, const ExposedClass &p_class, const MethodData &p_method) { - const ExposedClass *return_class = p_context.find_exposed_class(p_method.return_type); - if (return_class) { - TEST_COND(return_class->is_singleton, - "Method return type is a singleton: '", p_class.name, ".", p_method.name, "'."); + if (p_method.return_type.name != StringName()) { + const ExposedClass *return_class = p_context.find_exposed_class(p_method.return_type); + if (return_class) { + TEST_COND(return_class->is_singleton, + "Method return type is a singleton: '", p_class.name, ".", p_method.name, "'."); + + if (p_class.api_type == ClassDB::API_CORE) { + TEST_COND(return_class->api_type == ClassDB::API_EDITOR, + "Method '", p_class.name, ".", p_method.name, "' has return type '", return_class->name, + "' from the editor API. Core API cannot have dependencies on the editor API."); + } + } else { + // Look for types that don't inherit Object + TEST_FAIL_COND(!p_context.has_type(p_method.return_type), + "Method return type '", p_method.return_type.name, "' not found: '", p_class.name, ".", p_method.name, "'."); + } } for (const List<ArgumentData>::Element *F = p_method.arguments.front(); F; F = F->next()) { @@ -383,7 +402,14 @@ void validate_method(const Context &p_context, const ExposedClass &p_class, cons if (arg_class) { TEST_COND(arg_class->is_singleton, "Argument type is a singleton: '", arg.name, "' of method '", p_class.name, ".", p_method.name, "'."); + + if (p_class.api_type == ClassDB::API_CORE) { + TEST_COND(arg_class->api_type == ClassDB::API_EDITOR, + "Argument '", arg.name, "' of method '", p_class.name, ".", p_method.name, "' has type '", + arg_class->name, "' from the editor API. Core API cannot have dependencies on the editor API."); + } } else { + // Look for types that don't inherit Object TEST_FAIL_COND(!p_context.has_type(arg.type), "Argument type '", arg.type.name, "' not found: '", arg.name, "' of method", p_class.name, ".", p_method.name, "'."); } @@ -407,8 +433,15 @@ void validate_signal(const Context &p_context, const ExposedClass &p_class, cons const ExposedClass *arg_class = p_context.find_exposed_class(arg.type); if (arg_class) { TEST_COND(arg_class->is_singleton, - "Argument class is a singleton: '", arg.name, "' of signal", p_class.name, ".", p_signal.name, "'."); + "Argument class is a singleton: '", arg.name, "' of signal '", p_class.name, ".", p_signal.name, "'."); + + if (p_class.api_type == ClassDB::API_CORE) { + TEST_COND(arg_class->api_type == ClassDB::API_EDITOR, + "Argument '", arg.name, "' of signal '", p_class.name, ".", p_signal.name, "' has type '", + arg_class->name, "' from the editor API. Core API cannot have dependencies on the editor API."); + } } else { + // Look for types that don't inherit Object TEST_FAIL_COND(!p_context.has_type(arg.type), "Argument type '", arg.type.name, "' not found: '", arg.name, "' of signal", p_class.name, ".", p_signal.name, "'."); } diff --git a/tests/test_main.cpp b/tests/test_main.cpp index 2697eb6399..df43b7424f 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -33,6 +33,7 @@ #include "core/templates/list.h" #include "test_aabb.h" +#include "test_array.h" #include "test_astar.h" #include "test_basis.h" #include "test_class_db.h" @@ -65,6 +66,7 @@ #include "test_random_number_generator.h" #include "test_rect2.h" #include "test_render.h" +#include "test_resource.h" #include "test_shader_lang.h" #include "test_string.h" #include "test_text_server.h" diff --git a/tests/test_path_follow_2d.h b/tests/test_path_follow_2d.h new file mode 100644 index 0000000000..28b62de5bb --- /dev/null +++ b/tests/test_path_follow_2d.h @@ -0,0 +1,229 @@ +/*************************************************************************/ +/* test_path_follow_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEST_PATH_FOLLOW_2D_H +#define TEST_PATH_FOLLOW_2D_H + +#include "scene/2d/path_2d.h" +#include "scene/resources/curve.h" + +#include "tests/test_macros.h" + +namespace TestPathFollow2D { + +TEST_CASE("[PathFollow2D] Sampling with unit offset") { + const Ref<Curve2D> &curve = memnew(Curve2D()); + curve->add_point(Vector2(0, 0)); + curve->add_point(Vector2(100, 0)); + curve->add_point(Vector2(100, 100)); + curve->add_point(Vector2(0, 100)); + curve->add_point(Vector2(0, 0)); + const Ref<Path2D> &path = memnew(Path2D()); + path->set_curve(curve); + const Ref<PathFollow2D> &path_follow_2d = memnew(PathFollow2D()); + path->add_child(path_follow_2d); + + path_follow_2d->set_unit_offset(0); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 0))); + + path_follow_2d->set_unit_offset(0.125); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 0))); + + path_follow_2d->set_unit_offset(0.25); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 0))); + + path_follow_2d->set_unit_offset(0.375); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 50))); + + path_follow_2d->set_unit_offset(0.5); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 100))); + + path_follow_2d->set_unit_offset(0.625); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 100))); + + path_follow_2d->set_unit_offset(0.75); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 100))); + + path_follow_2d->set_unit_offset(0.875); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 50))); + + path_follow_2d->set_unit_offset(1); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 0))); +} + +TEST_CASE("[PathFollow2D] Sampling with offset") { + const Ref<Curve2D> &curve = memnew(Curve2D()); + curve->add_point(Vector2(0, 0)); + curve->add_point(Vector2(100, 0)); + curve->add_point(Vector2(100, 100)); + curve->add_point(Vector2(0, 100)); + curve->add_point(Vector2(0, 0)); + const Ref<Path2D> &path = memnew(Path2D()); + path->set_curve(curve); + const Ref<PathFollow2D> &path_follow_2d = memnew(PathFollow2D()); + path->add_child(path_follow_2d); + + path_follow_2d->set_offset(0); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 0))); + + path_follow_2d->set_offset(50); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 0))); + + path_follow_2d->set_offset(100); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 0))); + + path_follow_2d->set_offset(150); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 50))); + + path_follow_2d->set_offset(200); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 100))); + + path_follow_2d->set_offset(250); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 100))); + + path_follow_2d->set_offset(300); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 100))); + + path_follow_2d->set_offset(350); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 50))); + + path_follow_2d->set_offset(400); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 0))); +} + +TEST_CASE("[PathFollow2D] Removal of a point in curve") { + const Ref<Curve2D> &curve = memnew(Curve2D()); + curve->add_point(Vector2(0, 0)); + curve->add_point(Vector2(100, 0)); + curve->add_point(Vector2(100, 100)); + const Ref<Path2D> &path = memnew(Path2D()); + path->set_curve(curve); + const Ref<PathFollow2D> &path_follow_2d = memnew(PathFollow2D()); + path->add_child(path_follow_2d); + + path_follow_2d->set_unit_offset(0.5); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 0))); + + curve->remove_point(1); + + CHECK_MESSAGE( + path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 50)), + "Path follow's position should be updated after removing a point from the curve"); +} + +TEST_CASE("[PathFollow2D] Setting h_offset and v_offset") { + const Ref<Curve2D> &curve = memnew(Curve2D()); + curve->add_point(Vector2(0, 0)); + curve->add_point(Vector2(100, 0)); + const Ref<Path2D> &path = memnew(Path2D()); + path->set_curve(curve); + const Ref<PathFollow2D> &path_follow_2d = memnew(PathFollow2D()); + path->add_child(path_follow_2d); + + path_follow_2d->set_unit_offset(0.5); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 0))); + + path_follow_2d->set_h_offset(25); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(75, 0))); + + path_follow_2d->set_v_offset(25); + CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(75, 25))); +} + +TEST_CASE("[PathFollow2D] Unit offset out of range") { + const Ref<Curve2D> &curve = memnew(Curve2D()); + curve->add_point(Vector2(0, 0)); + curve->add_point(Vector2(100, 0)); + const Ref<Path2D> &path = memnew(Path2D()); + path->set_curve(curve); + const Ref<PathFollow2D> &path_follow_2d = memnew(PathFollow2D()); + path->add_child(path_follow_2d); + + path_follow_2d->set_loop(true); + + path_follow_2d->set_unit_offset(-0.3); + CHECK_MESSAGE( + path_follow_2d->get_unit_offset() == 0.7, + "Unit Offset should loop back from the end in the opposite direction"); + + path_follow_2d->set_unit_offset(1.3); + CHECK_MESSAGE( + path_follow_2d->get_unit_offset() == 0.3, + "Unit Offset should loop back from the end in the opposite direction"); + + path_follow_2d->set_loop(false); + + path_follow_2d->set_unit_offset(-0.3); + CHECK_MESSAGE( + path_follow_2d->get_unit_offset() == 0, + "Unit Offset should be clamped at 0"); + + path_follow_2d->set_unit_offset(1.3); + CHECK_MESSAGE( + path_follow_2d->get_unit_offset() == 1, + "Unit Offset should be clamped at 1"); +} + +TEST_CASE("[PathFollow2D] Offset out of range") { + const Ref<Curve2D> &curve = memnew(Curve2D()); + curve->add_point(Vector2(0, 0)); + curve->add_point(Vector2(100, 0)); + const Ref<Path2D> &path = memnew(Path2D()); + path->set_curve(curve); + const Ref<PathFollow2D> &path_follow_2d = memnew(PathFollow2D()); + path->add_child(path_follow_2d); + + path_follow_2d->set_loop(true); + + path_follow_2d->set_offset(-50); + CHECK_MESSAGE( + path_follow_2d->get_offset() == 50, + "Offset should loop back from the end in the opposite direction"); + + path_follow_2d->set_offset(150); + CHECK_MESSAGE( + path_follow_2d->get_offset() == 50, + "Offset should loop back from the end in the opposite direction"); + + path_follow_2d->set_loop(false); + + path_follow_2d->set_offset(-50); + CHECK_MESSAGE( + path_follow_2d->get_offset() == 0, + "Offset should be clamped at 0"); + + path_follow_2d->set_offset(150); + CHECK_MESSAGE( + path_follow_2d->get_offset() == 100, + "Offset should be clamped at 1"); +} +} // namespace TestPathFollow2D + +#endif // TEST_PATH_FOLLOW_2D_H diff --git a/tests/test_path_follow_3d.h b/tests/test_path_follow_3d.h new file mode 100644 index 0000000000..b6b4c88222 --- /dev/null +++ b/tests/test_path_follow_3d.h @@ -0,0 +1,220 @@ +/*************************************************************************/ +/* test_path_follow_3d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEST_PATH_FOLLOW_3D_H +#define TEST_PATH_FOLLOW_3D_H + +#include "scene/3d/path_3d.h" +#include "scene/resources/curve.h" + +#include "tests/test_macros.h" + +namespace TestPathFollow3D { + +TEST_CASE("[PathFollow3D] Sampling with unit offset") { + const Ref<Curve3D> &curve = memnew(Curve3D()); + curve->add_point(Vector3(0, 0, 0)); + curve->add_point(Vector3(100, 0, 0)); + curve->add_point(Vector3(100, 100, 0)); + curve->add_point(Vector3(100, 100, 100)); + curve->add_point(Vector3(100, 0, 100)); + const Path3D *path = memnew(Path3D); + path->set_curve(curve); + const PathFollow3D *path_follow_3d = memnew(PathFollow3D); + path->add_child(path_follow_3d); + + path_follow_3d->set_unit_offset(0); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(0, 0, 0)); + + path_follow_3d->set_unit_offset(0.125); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(50, 0, 0)); + + path_follow_3d->set_unit_offset(0.25); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 0, 0); + + path_follow_3d->set_unit_offset(0.375); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 50, 0))); + + path_follow_3d->set_unit_offset(0.5); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 0))); + + path_follow_3d->set_unit_offset(0.625); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 50))); + + path_follow_3d->set_unit_offset(0.75); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 100))); + + path_follow_3d->set_unit_offset(0.875); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 50, 100))); + + path_follow_3d->set_unit_offset(1); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 0, 100))); + + memdelete(path); +} + +TEST_CASE("[PathFollow3D] Sampling with offset") { + const Ref<Curve3D> &curve = memnew(Curve3D()); + curve->add_point(Vector3(0, 0, 0)); + curve->add_point(Vector3(100, 0, 0)); + curve->add_point(Vector3(100, 100, 0)); + curve->add_point(Vector3(100, 100, 100)); + curve->add_point(Vector3(100, 0, 100)); + const Path3D *path = memnew(Path3D); + path->set_curve(curve); + const PathFollow3D *path_follow_3d = memnew(PathFollow3D); + path->add_child(path_follow_3d); + + path_follow_3d->set_offset(0); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(0, 0, 0)); + + path_follow_3d->set_offset(50); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(50, 0, 0)); + + path_follow_3d->set_offset(100); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 0, 0); + + path_follow_3d->set_offset(150); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 50, 0))); + + path_follow_3d->set_offset(200); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 0))); + + path_follow_3d->set_offset(250); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 50))); + + path_follow_3d->set_offset(300); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 100))); + + path_follow_3d->set_offset(350); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 50, 100))); + + path_follow_3d->set_offset(400); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 0, 100))); + + memdelete(path); +} + +TEST_CASE("[PathFollow3D] Removal of a point in curve") { + const Ref<Curve3D> &curve = memnew(Curve3D()); + curve->add_point(Vector3(0, 0, 0)); + curve->add_point(Vector3(100, 0, 0)); + curve->add_point(Vector3(100, 100, 0)); + const Path3D *path = memnew(Path3D); + path->set_curve(curve); + const PathFollow3D *path_follow_3d = memnew(PathFollow3D); + path->add_child(path_follow_3d); + + path_follow_3d->set_unit_offset(0.5); + CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector2(100, 0, 0))); + + curve->remove_point(1); + + CHECK_MESSAGE( + path_follow_3d->get_transform().get_origin().is_equal_approx(Vector2(50, 50, 0)), + "Path follow's position should be updated after removing a point from the curve"); + + memdelete(path); +} + +TEST_CASE("[PathFollow3D] Unit offset out of range") { + const Ref<Curve3D> &curve = memnew(Curve3D()); + curve->add_point(Vector3(0, 0, 0)); + curve->add_point(Vector3(100, 0, 0)); + const Path3D *path = memnew(Path3D); + path->set_curve(curve); + const PathFollow3D *path_follow_3d = memnew(PathFollow3D); + path->add_child(path_follow_3d); + + path_follow_3d->set_loop(true); + + path_follow_3d->set_unit_offset(-0.3); + CHECK_MESSAGE( + path_follow_3d->get_unit_offset() == 0.7, + "Unit Offset should loop back from the end in the opposite direction"); + + path_follow_3d->set_unit_offset(1.3); + CHECK_MESSAGE( + path_follow_3d->get_unit_offset() == 0.3, + "Unit Offset should loop back from the end in the opposite direction"); + + path_follow_3d->set_loop(false); + + path_follow_3d->set_unit_offset(-0.3); + CHECK_MESSAGE( + path_follow_3d->get_unit_offset() == 0, + "Unit Offset should be clamped at 0"); + + path_follow_3d->set_unit_offset(1.3); + CHECK_MESSAGE( + path_follow_3d->get_unit_offset() == 1, + "Unit Offset should be clamped at 1"); + + memdelete(path); +} + +TEST_CASE("[PathFollow3D] Offset out of range") { + const Ref<Curve3D> &curve = memnew(Curve3D()); + curve->add_point(Vector3(0, 0, 0)); + curve->add_point(Vector3(100, 0, 0)); + const Path3D *path = memnew(Path3D); + path->set_curve(curve); + const PathFollow3D *path_follow_3d = memnew(PathFollow3D); + path->add_child(path_follow_3d); + + path_follow_3d->set_loop(true); + + path_follow_3d->set_offset(-50); + CHECK_MESSAGE( + path_follow_3d->get_offset() == 50, + "Offset should loop back from the end in the opposite direction"); + + path_follow_3d->set_offset(150); + CHECK_MESSAGE( + path_follow_3d->get_offset() == 50, + "Offset should loop back from the end in the opposite direction"); + + path_follow_3d->set_loop(false); + + path_follow_3d->set_offset(-50); + CHECK_MESSAGE( + path_follow_3d->get_offset() == 0, + "Offset should be clamped at 0"); + + path_follow_3d->set_offset(150); + CHECK_MESSAGE( + path_follow_3d->get_offset() == 100, + "Offset should be clamped at max value of curve"); + + memdelete(path); +} +} // namespace TestPathFollow3D + +#endif // TEST_PATH_FOLLOW_3D_H diff --git a/tests/test_render.cpp b/tests/test_render.cpp index 2a4ae8bd73..72b2840098 100644 --- a/tests/test_render.cpp +++ b/tests/test_render.cpp @@ -183,8 +183,8 @@ public: //vs->light_set_shadow( lightaux, true ); light = vs->instance_create2(lightaux, scenario); Transform lla; - //lla.set_look_at(Vector3(),Vector3(1,-1,1),Vector3(0,1,0)); - lla.set_look_at(Vector3(), Vector3(-0.000000, -0.836026, -0.548690), Vector3(0, 1, 0)); + //lla.set_look_at(Vector3(),Vector3(1, -1, 1)); + lla.set_look_at(Vector3(), Vector3(0.0, -0.836026, -0.548690)); vs->instance_set_transform(light, lla); diff --git a/tests/test_resource.h b/tests/test_resource.h new file mode 100644 index 0000000000..cee3281995 --- /dev/null +++ b/tests/test_resource.h @@ -0,0 +1,114 @@ +/*************************************************************************/ +/* test_resource.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEST_RESOURCE +#define TEST_RESOURCE + +#include "core/io/resource.h" +#include "core/io/resource_loader.h" +#include "core/io/resource_saver.h" +#include "core/os/os.h" + +#include "thirdparty/doctest/doctest.h" + +namespace TestResource { + +TEST_CASE("[Resource] Duplication") { + Ref<Resource> resource = memnew(Resource); + resource->set_name("Hello world"); + Ref<Resource> child_resource = memnew(Resource); + child_resource->set_name("I'm a child resource"); + resource->set_meta("other_resource", child_resource); + + Ref<Resource> resource_dupe = resource->duplicate(); + const Ref<Resource> &resource_dupe_reference = resource_dupe; + resource_dupe->set_name("Changed name"); + child_resource->set_name("My name was changed too"); + + CHECK_MESSAGE( + resource_dupe->get_name() == "Changed name", + "Duplicated resource should have the new name."); + CHECK_MESSAGE( + resource_dupe_reference->get_name() == "Changed name", + "Reference to the duplicated resource should have the new name."); + CHECK_MESSAGE( + resource->get_name() == "Hello world", + "Original resource name should not be affected after editing the duplicate's name."); + CHECK_MESSAGE( + Ref<Resource>(resource_dupe->get_meta("other_resource"))->get_name() == "My name was changed too", + "Duplicated resource should share its child resource with the original."); +} + +TEST_CASE("[Resource] Saving and loading") { + Ref<Resource> resource = memnew(Resource); + resource->set_name("Hello world"); + resource->set_meta(" ExampleMetadata ", Vector2i(40, 80)); + resource->set_meta("string", "The\nstring\nwith\nunnecessary\nline\n\t\\\nbreaks"); + Ref<Resource> child_resource = memnew(Resource); + child_resource->set_name("I'm a child resource"); + resource->set_meta("other_resource", child_resource); + const String save_path_binary = OS::get_singleton()->get_cache_path().plus_file("resource.res"); + const String save_path_text = OS::get_singleton()->get_cache_path().plus_file("resource.tres"); + ResourceSaver::save(save_path_binary, resource); + ResourceSaver::save(save_path_text, resource); + + const Ref<Resource> &loaded_resource_binary = ResourceLoader::load(save_path_binary); + CHECK_MESSAGE( + loaded_resource_binary->get_name() == "Hello world", + "The loaded resource name should be equal to the expected value."); + CHECK_MESSAGE( + loaded_resource_binary->get_meta(" ExampleMetadata ") == Vector2i(40, 80), + "The loaded resource metadata should be equal to the expected value."); + CHECK_MESSAGE( + loaded_resource_binary->get_meta("string") == "The\nstring\nwith\nunnecessary\nline\n\t\\\nbreaks", + "The loaded resource metadata should be equal to the expected value."); + const Ref<Resource> &loaded_child_resource_binary = loaded_resource_binary->get_meta("other_resource"); + CHECK_MESSAGE( + loaded_child_resource_binary->get_name() == "I'm a child resource", + "The loaded child resource name should be equal to the expected value."); + + const Ref<Resource> &loaded_resource_text = ResourceLoader::load(save_path_text); + CHECK_MESSAGE( + loaded_resource_text->get_name() == "Hello world", + "The loaded resource name should be equal to the expected value."); + CHECK_MESSAGE( + loaded_resource_text->get_meta(" ExampleMetadata ") == Vector2i(40, 80), + "The loaded resource metadata should be equal to the expected value."); + CHECK_MESSAGE( + loaded_resource_text->get_meta("string") == "The\nstring\nwith\nunnecessary\nline\n\t\\\nbreaks", + "The loaded resource metadata should be equal to the expected value."); + const Ref<Resource> &loaded_child_resource_text = loaded_resource_text->get_meta("other_resource"); + CHECK_MESSAGE( + loaded_child_resource_text->get_name() == "I'm a child resource", + "The loaded child resource name should be equal to the expected value."); +} +} // namespace TestResource + +#endif // TEST_RESOURCE |