diff options
author | max-001 <maxsmits21@kpnmail.nl> | 2024-11-21 09:46:06 +0100 |
---|---|---|
committer | max-001 <maxsmits21@kpnmail.nl> | 2024-11-21 09:46:06 +0100 |
commit | 7588439db08a671764345764eb05bcb853a90d76 (patch) | |
tree | 6847d8aa1b1b911dde55d529330c7144c6fafbf0 /src/test | |
parent | ba3b97467ffa9df03d74e87bd567e3dfc521df05 (diff) | |
parent | 1cc120a0031cfc19c35240da8390d9129b4d75a3 (diff) |
Merge remote-tracking branch 'origin/master' into max/doxygen
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/test/DBTest.cpp | 28 | ||||
-rw-r--r-- | src/test/ECSTest.cpp | 236 | ||||
-rw-r--r-- | src/test/EventTest.cpp | 254 | ||||
-rw-r--r-- | src/test/ParticleTest.cpp | 2 | ||||
-rw-r--r-- | src/test/RenderSystemTest.cpp | 174 | ||||
-rw-r--r-- | src/test/SceneManagerTest.cpp | 122 | ||||
-rw-r--r-- | src/test/ValueBrokerTest.cpp | 63 |
8 files changed, 883 insertions, 1 deletions
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 49c8151..dc985a3 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -3,5 +3,10 @@ target_sources(test_main PUBLIC PhysicsTest.cpp ScriptTest.cpp ParticleTest.cpp + EventTest.cpp + ECSTest.cpp + SceneManagerTest.cpp + ValueBrokerTest.cpp + DBTest.cpp ) diff --git a/src/test/DBTest.cpp b/src/test/DBTest.cpp new file mode 100644 index 0000000..e80814c --- /dev/null +++ b/src/test/DBTest.cpp @@ -0,0 +1,28 @@ +#include <crepe/facade/DB.h> +#include <gtest/gtest.h> + +using namespace std; +using namespace crepe; +using namespace testing; + +class DBTest : public Test { +public: + DB db; +}; + +TEST_F(DBTest, ReadWrite) { + db.set("foo", "bar"); + EXPECT_EQ(db.get("foo"), "bar"); +} + +TEST_F(DBTest, Nonexistant) { + EXPECT_THROW(db.get("foo"), std::out_of_range); + db.set("foo", "bar"); + EXPECT_NO_THROW(db.get("foo")); +} + +TEST_F(DBTest, Has) { + EXPECT_EQ(db.has("foo"), false); + db.set("foo", "bar"); + EXPECT_EQ(db.has("foo"), true); +} diff --git a/src/test/ECSTest.cpp b/src/test/ECSTest.cpp new file mode 100644 index 0000000..d5a5826 --- /dev/null +++ b/src/test/ECSTest.cpp @@ -0,0 +1,236 @@ +#include <gtest/gtest.h> + +#define protected public + +#include <crepe/ComponentManager.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/Metadata.h> +#include <crepe/api/Transform.h> +#include <crepe/api/Vector2.h> + +using namespace std; +using namespace crepe; + +class ECSTest : public ::testing::Test { +public: + ComponentManager mgr{}; +}; + +TEST_F(ECSTest, createGameObject) { + GameObject obj = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + + vector<reference_wrapper<Metadata>> metadata = mgr.get_components_by_type<Metadata>(); + vector<reference_wrapper<Transform>> transform = mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 1); + EXPECT_EQ(transform.size(), 1); + + EXPECT_EQ(metadata[0].get().name, "body"); + EXPECT_EQ(metadata[0].get().tag, "person"); + EXPECT_EQ(metadata[0].get().parent, -1); + EXPECT_EQ(metadata[0].get().children.size(), 0); + + EXPECT_EQ(transform[0].get().position.x, 0); + EXPECT_EQ(transform[0].get().position.y, 0); + EXPECT_EQ(transform[0].get().rotation, 0); + EXPECT_EQ(transform[0].get().scale, 1); +} + +TEST_F(ECSTest, deleteAllGameObjects) { + GameObject obj0 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + GameObject obj1 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + + mgr.delete_all_components(); + + vector<reference_wrapper<Metadata>> metadata = mgr.get_components_by_type<Metadata>(); + vector<reference_wrapper<Transform>> transform = mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 0); + EXPECT_EQ(transform.size(), 0); + + GameObject obj2 = mgr.new_object("body2", "person2", Vector2{1, 0}, 5, 1); + + metadata = mgr.get_components_by_type<Metadata>(); + transform = mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 1); + EXPECT_EQ(transform.size(), 1); + + EXPECT_EQ(metadata[0].get().game_object_id, 0); + EXPECT_EQ(metadata[0].get().name, "body2"); + EXPECT_EQ(metadata[0].get().tag, "person2"); + EXPECT_EQ(metadata[0].get().parent, -1); + EXPECT_EQ(metadata[0].get().children.size(), 0); + + EXPECT_EQ(transform[0].get().game_object_id, 0); + EXPECT_EQ(transform[0].get().position.x, 1); + EXPECT_EQ(transform[0].get().position.y, 0); + EXPECT_EQ(transform[0].get().rotation, 5); + EXPECT_EQ(transform[0].get().scale, 1); +} + +TEST_F(ECSTest, deleteGameObject) { + GameObject obj0 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + GameObject obj1 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + + mgr.delete_all_components_of_id(0); + + vector<reference_wrapper<Metadata>> metadata = mgr.get_components_by_type<Metadata>(); + vector<reference_wrapper<Transform>> transform = mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 1); + EXPECT_EQ(transform.size(), 1); + + EXPECT_EQ(metadata[0].get().game_object_id, 1); + EXPECT_EQ(metadata[0].get().name, "body"); + EXPECT_EQ(metadata[0].get().tag, "person"); + EXPECT_EQ(metadata[0].get().parent, -1); + EXPECT_EQ(metadata[0].get().children.size(), 0); + + EXPECT_EQ(transform[0].get().game_object_id, 1); + EXPECT_EQ(transform[0].get().position.x, 0); + EXPECT_EQ(transform[0].get().position.y, 0); + EXPECT_EQ(transform[0].get().rotation, 0); + EXPECT_EQ(transform[0].get().scale, 1); +} + +TEST_F(ECSTest, manyGameObjects) { + for (int i = 0; i < 5000; i++) { + GameObject obj = mgr.new_object("body", "person", Vector2{0, 0}, 0, i); + } + + vector<reference_wrapper<Metadata>> metadata = mgr.get_components_by_type<Metadata>(); + vector<reference_wrapper<Transform>> transform = mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 5000); + EXPECT_EQ(transform.size(), 5000); + for (int i = 0; i < 5000; i++) { + EXPECT_EQ(metadata[i].get().game_object_id, i); + EXPECT_EQ(metadata[i].get().name, "body"); + EXPECT_EQ(metadata[i].get().tag, "person"); + EXPECT_EQ(metadata[i].get().parent, -1); + EXPECT_EQ(metadata[i].get().children.size(), 0); + + EXPECT_EQ(transform[i].get().game_object_id, i); + EXPECT_EQ(transform[i].get().position.x, 0); + EXPECT_EQ(transform[i].get().position.y, 0); + EXPECT_EQ(transform[i].get().rotation, 0); + EXPECT_EQ(transform[i].get().scale, i); + } + + mgr.delete_components<Metadata>(); + + metadata = mgr.get_components_by_type<Metadata>(); + transform = mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 0); + EXPECT_EQ(transform.size(), 5000); + + for (int i = 0; i < 10000 - 5000; i++) { + string tag = "person" + to_string(i); + GameObject obj = mgr.new_object("body", tag, Vector2{0, 0}, i, 0); + } + + metadata = mgr.get_components_by_type<Metadata>(); + transform = mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 10000 - 5000); + EXPECT_EQ(transform.size(), 10000); +} + +TEST_F(ECSTest, getComponentsByID) { + GameObject obj0 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + GameObject obj1 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + + vector<reference_wrapper<Metadata>> metadata = mgr.get_components_by_id<Metadata>(0); + vector<reference_wrapper<Transform>> transform = mgr.get_components_by_id<Transform>(1); + + EXPECT_EQ(metadata.size(), 1); + EXPECT_EQ(transform.size(), 1); + + EXPECT_EQ(metadata[0].get().game_object_id, 0); + EXPECT_EQ(metadata[0].get().name, "body"); + EXPECT_EQ(metadata[0].get().tag, "person"); + EXPECT_EQ(metadata[0].get().parent, -1); + EXPECT_EQ(metadata[0].get().children.size(), 0); + + EXPECT_EQ(transform[0].get().game_object_id, 1); + EXPECT_EQ(transform[0].get().position.x, 0); + EXPECT_EQ(transform[0].get().position.y, 0); + EXPECT_EQ(transform[0].get().rotation, 0); + EXPECT_EQ(transform[0].get().scale, 1); +} + +TEST_F(ECSTest, tooMuchComponents) { + try { + GameObject obj0 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + obj0.add_component<Transform>(Vector2{10, 10}, 0, 1); + } catch (const exception & e) { + EXPECT_EQ(e.what(), + string("Exceeded maximum number of instances for this component type")); + } + + try { + GameObject obj1 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + obj1.add_component<Metadata>("body", "person"); + } catch (const exception & e) { + EXPECT_EQ(e.what(), + string("Exceeded maximum number of instances for this component type")); + } + + vector<reference_wrapper<Metadata>> metadata = mgr.get_components_by_type<Metadata>(); + + EXPECT_EQ(metadata.size(), 2); + EXPECT_EQ(metadata[0].get().name, "body"); + EXPECT_EQ(metadata[1].get().name, "body"); +} + +TEST_F(ECSTest, partentChild) { + { + GameObject body = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + GameObject right_leg = mgr.new_object("rightLeg", "person", Vector2{1, 1}, 0, 1); + GameObject left_leg = mgr.new_object("leftLeg", "person", Vector2{1, 1}, 0, 1); + GameObject right_foot = mgr.new_object("rightFoot", "person", Vector2{2, 2}, 0, 1); + GameObject left_foot = mgr.new_object("leftFoot", "person", Vector2{2, 2}, 0, 1); + + // Set the parent of each GameObject + right_foot.set_parent(right_leg); + left_foot.set_parent(left_leg); + right_leg.set_parent(body); + left_leg.set_parent(body); + } + + // Get the Metadata and Transform components of each GameObject + vector<reference_wrapper<Metadata>> metadata = mgr.get_components_by_type<Metadata>(); + + // Check IDs + EXPECT_EQ(metadata[0].get().game_object_id, 0); + EXPECT_EQ(metadata[1].get().game_object_id, 1); + EXPECT_EQ(metadata[2].get().game_object_id, 2); + EXPECT_EQ(metadata[3].get().game_object_id, 3); + EXPECT_EQ(metadata[4].get().game_object_id, 4); + + // Check the parent-child relationships + EXPECT_EQ(metadata[0].get().name, "body"); + EXPECT_EQ(metadata[1].get().name, "rightLeg"); + EXPECT_EQ(metadata[2].get().name, "leftLeg"); + EXPECT_EQ(metadata[3].get().name, "rightFoot"); + EXPECT_EQ(metadata[4].get().name, "leftFoot"); + + EXPECT_EQ(metadata[0].get().parent, -1); + EXPECT_EQ(metadata[1].get().parent, 0); + EXPECT_EQ(metadata[2].get().parent, 0); + EXPECT_EQ(metadata[3].get().parent, 1); + EXPECT_EQ(metadata[4].get().parent, 2); + + EXPECT_EQ(metadata[0].get().children.size(), 2); + EXPECT_EQ(metadata[1].get().children.size(), 1); + EXPECT_EQ(metadata[2].get().children.size(), 1); + EXPECT_EQ(metadata[3].get().children.size(), 0); + EXPECT_EQ(metadata[4].get().children.size(), 0); + + EXPECT_EQ(metadata[0].get().children[0], 1); + EXPECT_EQ(metadata[0].get().children[1], 2); + EXPECT_EQ(metadata[1].get().children[0], 3); + EXPECT_EQ(metadata[2].get().children[0], 4); +} diff --git a/src/test/EventTest.cpp b/src/test/EventTest.cpp new file mode 100644 index 0000000..b0e6c9c --- /dev/null +++ b/src/test/EventTest.cpp @@ -0,0 +1,254 @@ + +#include "api/Event.h" +#include "api/EventManager.h" +#include "api/IKeyListener.h" +#include "api/IMouseListener.h" +#include <gmock/gmock.h> +#include <gtest/gtest.h> +using namespace std; +using namespace std::chrono_literals; +using namespace crepe; + +class EventManagerTest : public ::testing::Test { +protected: + void SetUp() override { + // Clear any existing subscriptions or events before each test + EventManager::get_instance().clear(); + } + + void TearDown() override { + // Ensure cleanup after each test + EventManager::get_instance().clear(); + } +}; +class MockKeyListener : public IKeyListener { +public: + MOCK_METHOD(bool, on_key_pressed, (const KeyPressEvent & event), (override)); + MOCK_METHOD(bool, on_key_released, (const KeyReleaseEvent & event), (override)); +}; + +class MockMouseListener : public IMouseListener { +public: + MOCK_METHOD(bool, on_mouse_clicked, (const MouseClickEvent & event), (override)); + MOCK_METHOD(bool, on_mouse_pressed, (const MousePressEvent & event), (override)); + MOCK_METHOD(bool, on_mouse_released, (const MouseReleaseEvent & event), (override)); + MOCK_METHOD(bool, on_mouse_moved, (const MouseMoveEvent & event), (override)); +}; + +TEST_F(EventManagerTest, EventSubscription) { + EventHandler<KeyPressEvent> key_handler = [](const KeyPressEvent & e) { + std::cout << "Key Event Triggered" << std::endl; + return true; + }; + + // Subscribe to KeyPressEvent + EventManager::get_instance().subscribe<KeyPressEvent>(key_handler, 1); + + // Verify subscription (not directly verifiable; test by triggering event) + + EventManager::get_instance().trigger_event<KeyPressEvent>( + KeyPressEvent{ + .repeat = true, + .key = Keycode::A, + }, + 1); + EventManager::get_instance().trigger_event<KeyPressEvent>( + KeyPressEvent{ + .repeat = true, + .key = Keycode::A, + + }, + EventManager::CHANNEL_ALL); +} +TEST_F(EventManagerTest, EventManagerTest_trigger_all_channels) { + bool triggered = false; + + EventHandler<MouseClickEvent> mouse_handler = [&](const MouseClickEvent & e) { + triggered = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; + }; + EventManager::get_instance().subscribe<MouseClickEvent>(mouse_handler, + EventManager::CHANNEL_ALL); + + MouseClickEvent click_event{ + .mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}; + EventManager::get_instance().trigger_event<MouseClickEvent>(click_event, + EventManager::CHANNEL_ALL); + + EXPECT_TRUE(triggered); +} +TEST_F(EventManagerTest, EventManagerTest_trigger_one_channel) { + bool triggered = false; + int test_channel = 1; + EventHandler<MouseClickEvent> mouse_handler = [&](const MouseClickEvent & e) { + triggered = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; + }; + EventManager::get_instance().subscribe<MouseClickEvent>(mouse_handler, test_channel); + + MouseClickEvent click_event{ + .mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}; + EventManager::get_instance().trigger_event<MouseClickEvent>(click_event, + EventManager::CHANNEL_ALL); + + EXPECT_FALSE(triggered); + EventManager::get_instance().trigger_event<MouseClickEvent>(click_event, test_channel); +} + +TEST_F(EventManagerTest, EventManagerTest_callback_propagation) { + EventManager & event_manager = EventManager::get_instance(); + + // Flags to track handler calls + bool triggered_true = false; + bool triggered_false = false; + + // Handlers + EventHandler<MouseClickEvent> mouse_handler_true = [&](const MouseClickEvent & e) { + triggered_true = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return true; // Stops propagation + }; + + EventHandler<MouseClickEvent> mouse_handler_false = [&](const MouseClickEvent & e) { + triggered_false = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + + // Test event + MouseClickEvent click_event{ + .mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}; + event_manager.subscribe<MouseClickEvent>(mouse_handler_true, EventManager::CHANNEL_ALL); + event_manager.subscribe<MouseClickEvent>(mouse_handler_false, EventManager::CHANNEL_ALL); + + // Trigger event + event_manager.trigger_event<MouseClickEvent>(click_event, EventManager::CHANNEL_ALL); + + // Check that only the true handler was triggered + EXPECT_TRUE(triggered_true); + EXPECT_FALSE(triggered_false); + + // Reset and clear + triggered_true = false; + triggered_false = false; + event_manager.clear(); + event_manager.subscribe<MouseClickEvent>(mouse_handler_false, EventManager::CHANNEL_ALL); + event_manager.subscribe<MouseClickEvent>(mouse_handler_true, EventManager::CHANNEL_ALL); + + // Trigger event again + event_manager.trigger_event<MouseClickEvent>(click_event, EventManager::CHANNEL_ALL); + + // Check that both handlers were triggered + EXPECT_TRUE(triggered_true); + EXPECT_TRUE(triggered_false); +} + +TEST_F(EventManagerTest, EventManagerTest_queue_dispatch) { + EventManager & event_manager = EventManager::get_instance(); + bool triggered1 = false; + bool triggered2 = false; + int test_channel = 1; + EventHandler<MouseClickEvent> mouse_handler1 = [&](const MouseClickEvent & e) { + triggered1 = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + EventHandler<MouseClickEvent> mouse_handler2 = [&](const MouseClickEvent & e) { + triggered2 = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + event_manager.subscribe<MouseClickEvent>(mouse_handler1); + event_manager.subscribe<MouseClickEvent>(mouse_handler2, test_channel); + + event_manager.queue_event<MouseClickEvent>( + MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}); + event_manager.queue_event<MouseClickEvent>( + MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}, + test_channel); + event_manager.dispatch_events(); + EXPECT_TRUE(triggered1); + EXPECT_TRUE(triggered2); +} + +TEST_F(EventManagerTest, EventManagerTest_unsubscribe) { + EventManager & event_manager = EventManager::get_instance(); + + // Flags to track if handlers are triggered + bool triggered1 = false; + bool triggered2 = false; + + // Define EventHandlers + EventHandler<MouseClickEvent> mouse_handler1 = [&](const MouseClickEvent & e) { + triggered1 = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + + EventHandler<MouseClickEvent> mouse_handler2 = [&](const MouseClickEvent & e) { + triggered2 = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + // Subscribe handlers + subscription_t handler1_id = event_manager.subscribe<MouseClickEvent>(mouse_handler1); + subscription_t handler2_id = event_manager.subscribe<MouseClickEvent>(mouse_handler2); + + // Queue events + event_manager.queue_event<MouseClickEvent>( + MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}); + + // Dispatch events - both handlers should be triggered + event_manager.dispatch_events(); + EXPECT_TRUE(triggered1); // Handler 1 should be triggered + EXPECT_TRUE(triggered2); // Handler 2 should be triggered + + // Reset flags + triggered1 = false; + triggered2 = false; + + // Unsubscribe handler1 + event_manager.unsubscribe(handler1_id); + + // Queue the same event again + event_manager.queue_event<MouseClickEvent>( + MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}); + + // Dispatch events - only handler 2 should be triggered, handler 1 should NOT + event_manager.dispatch_events(); + EXPECT_FALSE(triggered1); // Handler 1 should NOT be triggered + EXPECT_TRUE(triggered2); // Handler 2 should be triggered + + // Reset flags + triggered2 = false; + + // Unsubscribe handler2 + event_manager.unsubscribe(handler2_id); + + // Queue the event again + event_manager.queue_event<MouseClickEvent>( + MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}); + + // Dispatch events - no handler should be triggered + event_manager.dispatch_events(); + EXPECT_FALSE(triggered1); // Handler 1 should NOT be triggered + EXPECT_FALSE(triggered2); // Handler 2 should NOT be triggered +} diff --git a/src/test/ParticleTest.cpp b/src/test/ParticleTest.cpp index 4e655a9..d9bbba0 100644 --- a/src/test/ParticleTest.cpp +++ b/src/test/ParticleTest.cpp @@ -28,7 +28,7 @@ public: GameObject game_object = mgr.new_object("", "", Vector2{0, 0}, 0, 0); Color color(0, 0, 0, 0); - Sprite test_sprite = game_object.add_component<Sprite>( + Sprite & test_sprite = game_object.add_component<Sprite>( make_shared<Texture>("../asset/texture/img.png"), color, FlipSettings{true, true}); diff --git a/src/test/RenderSystemTest.cpp b/src/test/RenderSystemTest.cpp new file mode 100644 index 0000000..ac479d3 --- /dev/null +++ b/src/test/RenderSystemTest.cpp @@ -0,0 +1,174 @@ +#include "api/Camera.h" +#include <functional> +#include <gtest/gtest.h> +#include <memory> +#include <vector> + +#define private public +#define protected public + +#include <crepe/ComponentManager.h> +#include <crepe/api/Color.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/Sprite.h> +#include <crepe/api/Texture.h> + +#include <crepe/system/RenderSystem.h> + +using namespace std; +using namespace crepe; +using namespace testing; + +class RenderSystemTest : public Test { +public: + ComponentManager mgr{}; + RenderSystem sys{mgr}; + GameObject entity1 = this->mgr.new_object("name"); + GameObject entity2 = this->mgr.new_object("name"); + GameObject entity3 = this->mgr.new_object("name"); + GameObject entity4 = this->mgr.new_object("name"); + + void SetUp() override { + auto & sprite1 + = entity1.add_component<Sprite>(make_shared<Texture>("../asset/texture/img.png"), + Color(0, 0, 0, 0), FlipSettings{false, false}); + ASSERT_NE(sprite1.sprite_image.get(), nullptr); + sprite1.order_in_layer = 5; + sprite1.sorting_in_layer = 5; + EXPECT_EQ(sprite1.order_in_layer, 5); + EXPECT_EQ(sprite1.sorting_in_layer, 5); + auto & sprite2 + = entity2.add_component<Sprite>(make_shared<Texture>("../asset/texture/img.png"), + Color(0, 0, 0, 0), FlipSettings{false, false}); + ASSERT_NE(sprite2.sprite_image.get(), nullptr); + sprite2.sorting_in_layer = 2; + sprite2.order_in_layer = 1; + + EXPECT_EQ(sprite2.sorting_in_layer, 2); + EXPECT_EQ(sprite2.order_in_layer, 1); + + auto & sprite3 + = entity3.add_component<Sprite>(make_shared<Texture>("../asset/texture/img.png"), + Color(0, 0, 0, 0), FlipSettings{false, false}); + ASSERT_NE(sprite3.sprite_image.get(), nullptr); + sprite3.sorting_in_layer = 1; + sprite3.order_in_layer = 2; + + EXPECT_EQ(sprite3.sorting_in_layer, 1); + EXPECT_EQ(sprite3.order_in_layer, 2); + + auto & sprite4 + = entity4.add_component<Sprite>(make_shared<Texture>("../asset/texture/img.png"), + Color(0, 0, 0, 0), FlipSettings{false, false}); + ASSERT_NE(sprite4.sprite_image.get(), nullptr); + sprite4.sorting_in_layer = 1; + sprite4.order_in_layer = 1; + EXPECT_EQ(sprite4.sorting_in_layer, 1); + EXPECT_EQ(sprite4.order_in_layer, 1); + } +}; + +TEST_F(RenderSystemTest, expected_throws) { + GameObject entity1 = this->mgr.new_object("NAME"); + + // no texture img + EXPECT_ANY_THROW({ + entity1.add_component<Sprite>(make_shared<Texture>("NO_IMAGE"), Color(0, 0, 0, 0), + FlipSettings{false, false}); + }); + + // No camera + EXPECT_ANY_THROW({ this->sys.update(); }); +} + +TEST_F(RenderSystemTest, make_sprites) {} + +TEST_F(RenderSystemTest, sorting_sprites) { + vector<reference_wrapper<Sprite>> sprites = this->mgr.get_components_by_type<Sprite>(); + ASSERT_EQ(sprites.size(), 4); + + vector<reference_wrapper<Sprite>> sorted_sprites = this->sys.sort(sprites); + ASSERT_EQ(sorted_sprites.size(), 4); + + // Expected order after sorting: + // 1. sorting_in_layer: 1, order_in_layer: 1 (entity4) + // 2. sorting_in_layer: 1, order_in_layer: 2 (entity3) + // 3. sorting_in_layer: 2, order_in_layer: 1 (entity2) + // 4. sorting_in_layer: 5, order_in_layer: 5 (entity1) + + EXPECT_EQ(sorted_sprites[0].get().sorting_in_layer, 1); + EXPECT_EQ(sorted_sprites[0].get().order_in_layer, 1); + + EXPECT_EQ(sorted_sprites[1].get().sorting_in_layer, 1); + EXPECT_EQ(sorted_sprites[1].get().order_in_layer, 2); + + EXPECT_EQ(sorted_sprites[2].get().sorting_in_layer, 2); + EXPECT_EQ(sorted_sprites[2].get().order_in_layer, 1); + + EXPECT_EQ(sorted_sprites[3].get().sorting_in_layer, 5); + EXPECT_EQ(sorted_sprites[3].get().order_in_layer, 5); + + for (size_t i = 1; i < sorted_sprites.size(); ++i) { + const Sprite & prev = sorted_sprites[i - 1].get(); + const Sprite & curr = sorted_sprites[i].get(); + + if (prev.sorting_in_layer == curr.sorting_in_layer) { + EXPECT_LE(prev.order_in_layer, curr.order_in_layer); + } else { + EXPECT_LE(prev.sorting_in_layer, curr.sorting_in_layer); + } + } +} + +TEST_F(RenderSystemTest, Update) { + entity1.add_component<Camera>(Color::WHITE); + { + vector<reference_wrapper<Sprite>> sprites = this->mgr.get_components_by_type<Sprite>(); + ASSERT_EQ(sprites.size(), 4); + + EXPECT_EQ(sprites[0].get().game_object_id, 0); + EXPECT_EQ(sprites[1].get().game_object_id, 1); + EXPECT_EQ(sprites[2].get().game_object_id, 2); + EXPECT_EQ(sprites[3].get().game_object_id, 3); + } + this->sys.update(); + { + vector<reference_wrapper<Sprite>> sprites = this->mgr.get_components_by_type<Sprite>(); + ASSERT_EQ(sprites.size(), 4); + + EXPECT_EQ(sprites[0].get().game_object_id, 0); + EXPECT_EQ(sprites[1].get().game_object_id, 1); + EXPECT_EQ(sprites[2].get().game_object_id, 2); + EXPECT_EQ(sprites[3].get().game_object_id, 3); + } +} + +TEST_F(RenderSystemTest, Camera) { + { + auto cameras = this->mgr.get_components_by_type<Camera>(); + EXPECT_NE(cameras.size(), 1); + } + { + entity1.add_component<Camera>(Color::WHITE); + auto cameras = this->mgr.get_components_by_type<Camera>(); + EXPECT_EQ(cameras.size(), 1); + } + + //TODO improve with newer version +} +TEST_F(RenderSystemTest, Color) { + entity1.add_component<Camera>(Color::WHITE); + auto & sprite = this->mgr.get_components_by_id<Sprite>(entity1.id).front().get(); + ASSERT_NE(sprite.sprite_image.get(), nullptr); + + sprite.color = Color::GREEN; + EXPECT_EQ(sprite.color.r, Color::GREEN.r); + EXPECT_EQ(sprite.color.g, Color::GREEN.g); + EXPECT_EQ(sprite.color.b, Color::GREEN.b); + EXPECT_EQ(sprite.color.a, Color::GREEN.a); + this->sys.update(); + EXPECT_EQ(sprite.color.r, Color::GREEN.r); + EXPECT_EQ(sprite.color.g, Color::GREEN.g); + EXPECT_EQ(sprite.color.b, Color::GREEN.b); + EXPECT_EQ(sprite.color.a, Color::GREEN.a); +} diff --git a/src/test/SceneManagerTest.cpp b/src/test/SceneManagerTest.cpp new file mode 100644 index 0000000..69e1171 --- /dev/null +++ b/src/test/SceneManagerTest.cpp @@ -0,0 +1,122 @@ +#include <crepe/ComponentManager.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/Metadata.h> +#include <crepe/api/Scene.h> +#include <crepe/api/SceneManager.h> +#include <crepe/api/Transform.h> +#include <crepe/api/Vector2.h> +#include <gtest/gtest.h> + +using namespace std; +using namespace crepe; + +class ConcreteScene1 : public Scene { +public: + using Scene::Scene; + + void load_scene() { + auto & mgr = this->component_manager; + GameObject object1 = mgr.new_object("scene_1", "tag_scene_1", Vector2{0, 0}, 0, 1); + GameObject object2 = mgr.new_object("scene_1", "tag_scene_1", Vector2{1, 0}, 0, 1); + GameObject object3 = mgr.new_object("scene_1", "tag_scene_1", Vector2{2, 0}, 0, 1); + } +}; + +class ConcreteScene2 : public Scene { +public: + using Scene::Scene; + + void load_scene() { + auto & mgr = this->component_manager; + GameObject object1 = mgr.new_object("scene_2", "tag_scene_2", Vector2{0, 0}, 0, 1); + GameObject object2 = mgr.new_object("scene_2", "tag_scene_2", Vector2{0, 1}, 0, 1); + GameObject object3 = mgr.new_object("scene_2", "tag_scene_2", Vector2{0, 2}, 0, 1); + GameObject object4 = mgr.new_object("scene_2", "tag_scene_2", Vector2{0, 3}, 0, 1); + } +}; + +class SceneManagerTest : public ::testing::Test { +public: + ComponentManager component_mgr{}; + SceneManager scene_mgr{component_mgr}; +}; + +TEST_F(SceneManagerTest, loadScene) { + scene_mgr.add_scene<ConcreteScene1>("scene1"); + scene_mgr.add_scene<ConcreteScene2>("scene2"); + + scene_mgr.load_next_scene(); + + vector<reference_wrapper<Metadata>> metadata + = component_mgr.get_components_by_type<Metadata>(); + vector<reference_wrapper<Transform>> transform + = component_mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 3); + EXPECT_EQ(transform.size(), 3); + + EXPECT_EQ(metadata[0].get().game_object_id, 0); + EXPECT_EQ(metadata[0].get().name, "scene_1"); + EXPECT_EQ(metadata[0].get().tag, "tag_scene_1"); + EXPECT_EQ(metadata[0].get().parent, -1); + EXPECT_EQ(metadata[0].get().children.size(), 0); + EXPECT_EQ(transform[0].get().position.x, 0); + EXPECT_EQ(transform[0].get().position.y, 0); + + EXPECT_EQ(metadata[1].get().game_object_id, 1); + EXPECT_EQ(metadata[1].get().name, "scene_1"); + EXPECT_EQ(metadata[1].get().tag, "tag_scene_1"); + EXPECT_EQ(metadata[1].get().parent, -1); + EXPECT_EQ(metadata[1].get().children.size(), 0); + EXPECT_EQ(transform[1].get().position.x, 1); + EXPECT_EQ(transform[1].get().position.y, 0); + + EXPECT_EQ(metadata[2].get().game_object_id, 2); + EXPECT_EQ(metadata[2].get().name, "scene_1"); + EXPECT_EQ(metadata[2].get().tag, "tag_scene_1"); + EXPECT_EQ(metadata[2].get().parent, -1); + EXPECT_EQ(metadata[2].get().children.size(), 0); + EXPECT_EQ(transform[2].get().position.x, 2); + EXPECT_EQ(transform[2].get().position.y, 0); + + scene_mgr.set_next_scene("scene2"); + scene_mgr.load_next_scene(); + + metadata = component_mgr.get_components_by_type<Metadata>(); + transform = component_mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 4); + EXPECT_EQ(transform.size(), 4); + + EXPECT_EQ(metadata[0].get().game_object_id, 0); + EXPECT_EQ(metadata[0].get().name, "scene_2"); + EXPECT_EQ(metadata[0].get().tag, "tag_scene_2"); + EXPECT_EQ(metadata[0].get().parent, -1); + EXPECT_EQ(metadata[0].get().children.size(), 0); + EXPECT_EQ(transform[0].get().position.x, 0); + EXPECT_EQ(transform[0].get().position.y, 0); + + EXPECT_EQ(metadata[1].get().game_object_id, 1); + EXPECT_EQ(metadata[1].get().name, "scene_2"); + EXPECT_EQ(metadata[1].get().tag, "tag_scene_2"); + EXPECT_EQ(metadata[1].get().parent, -1); + EXPECT_EQ(metadata[1].get().children.size(), 0); + EXPECT_EQ(transform[1].get().position.x, 0); + EXPECT_EQ(transform[1].get().position.y, 1); + + EXPECT_EQ(metadata[2].get().game_object_id, 2); + EXPECT_EQ(metadata[2].get().name, "scene_2"); + EXPECT_EQ(metadata[2].get().tag, "tag_scene_2"); + EXPECT_EQ(metadata[2].get().parent, -1); + EXPECT_EQ(metadata[2].get().children.size(), 0); + EXPECT_EQ(transform[2].get().position.x, 0); + EXPECT_EQ(transform[2].get().position.y, 2); + + EXPECT_EQ(metadata[3].get().game_object_id, 3); + EXPECT_EQ(metadata[3].get().name, "scene_2"); + EXPECT_EQ(metadata[3].get().tag, "tag_scene_2"); + EXPECT_EQ(metadata[3].get().parent, -1); + EXPECT_EQ(metadata[3].get().children.size(), 0); + EXPECT_EQ(transform[3].get().position.x, 0); + EXPECT_EQ(transform[3].get().position.y, 3); +} diff --git a/src/test/ValueBrokerTest.cpp b/src/test/ValueBrokerTest.cpp new file mode 100644 index 0000000..e6bb058 --- /dev/null +++ b/src/test/ValueBrokerTest.cpp @@ -0,0 +1,63 @@ +#include <gtest/gtest.h> + +#include <crepe/ValueBroker.h> +#include <crepe/util/Proxy.h> + +using namespace std; +using namespace crepe; +using namespace testing; + +class ValueBrokerTest : public Test { +public: + int read_count = 0; + int write_count = 0; + int value = 0; + + ValueBroker<int> broker{ + [this](const int & target) -> void { + this->write_count++; + this->value = target; + }, + [this]() -> const int & { + this->read_count++; + return this->value; + }, + }; + Proxy<int> proxy{broker}; + + void SetUp() override { + ASSERT_EQ(read_count, 0); + ASSERT_EQ(write_count, 0); + } +}; + +TEST_F(ValueBrokerTest, BrokerWrite) { + broker.set(0); + EXPECT_EQ(read_count, 0); + EXPECT_EQ(write_count, 1); +} + +TEST_F(ValueBrokerTest, BrokerRead) { + broker.get(); + EXPECT_EQ(read_count, 1); + EXPECT_EQ(write_count, 0); +} + +TEST_F(ValueBrokerTest, ProxyWrite) { + proxy = 0; + EXPECT_EQ(read_count, 0); + EXPECT_EQ(write_count, 1); +} + +void dummy(int) {} +TEST_F(ValueBrokerTest, ProxyRead) { + dummy(proxy); + EXPECT_EQ(read_count, 1); + EXPECT_EQ(write_count, 0); +} + +TEST_F(ValueBrokerTest, ProxyReadWrite) { + proxy = proxy; + ASSERT_EQ(read_count, 1); + ASSERT_EQ(write_count, 1); +} |