diff --git a/CMakeLists.txt b/CMakeLists.txt index 840077f..0094216 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,6 +118,7 @@ if (BUILD_TESTING) tests/WorldQueryTests.cpp tests/CommandBufferTests.cpp tests/SystemSchedulerTests.cpp + tests/EngineIntegrationTests.cpp ) target_include_directories(safecrowd_tests diff --git a/tests/EngineIntegrationTests.cpp b/tests/EngineIntegrationTests.cpp new file mode 100644 index 0000000..adb2c63 --- /dev/null +++ b/tests/EngineIntegrationTests.cpp @@ -0,0 +1,101 @@ +#include "TestSupport.h" + +#include +#include + +#include "engine/EngineRuntime.h" + +namespace { + +struct Position { + float x{0.0f}; + float y{0.0f}; +}; + +struct Activated { + int fixedStepSeen{0}; +}; + +class StartupSpawnPositionSystem : public safecrowd::engine::EngineSystem { +public: + void update(safecrowd::engine::EngineWorld& world, + const safecrowd::engine::EngineStepContext&) override { + world.commands().spawnEntity(Position{3.0f, 4.0f}); + } +}; + +class QueryAndActivateSystem : public safecrowd::engine::EngineSystem { +public: + std::size_t& queriedCount; + std::size_t& visibleActivatedCountDuringUpdate; + std::size_t& scheduledActivationCount; + + QueryAndActivateSystem(std::size_t& queriedCountRef, + std::size_t& visibleActivatedCountDuringUpdateRef, + std::size_t& scheduledActivationCountRef) + : queriedCount(queriedCountRef), + visibleActivatedCountDuringUpdate(visibleActivatedCountDuringUpdateRef), + scheduledActivationCount(scheduledActivationCountRef) {} + + void update(safecrowd::engine::EngineWorld& world, + const safecrowd::engine::EngineStepContext& step) override { + const auto positionedEntities = world.query().view(); + queriedCount = positionedEntities.size(); + scheduledActivationCount = 0; + + for (const auto entity : positionedEntities) { + if (!world.query().contains(entity)) { + world.commands().addComponent(entity, Activated{ + .fixedStepSeen = static_cast(step.fixedStepIndex), + }); + ++scheduledActivationCount; + } + } + + visibleActivatedCountDuringUpdate = world.query().view().size(); + } +}; + +} // namespace + +SC_TEST(EngineIntegration_QueryReadAndDeferredMutationFlow_AppliesAfterStepFrame) { + std::size_t queriedCount = 0; + std::size_t visibleActivatedCountDuringUpdate = 0; + std::size_t scheduledActivationCount = 0; + + safecrowd::engine::EngineRuntime runtime({ + .fixedDeltaTime = 0.25, + .maxCatchUpSteps = 4, + .baseSeed = 7, + }); + + runtime.addSystem( + std::make_unique(), + {.phase = safecrowd::engine::UpdatePhase::Startup, + .triggerPolicy = safecrowd::engine::TriggerPolicy::EveryFrame}); + runtime.addSystem(std::make_unique( + queriedCount, + visibleActivatedCountDuringUpdate, + scheduledActivationCount)); + + runtime.play(); + + const auto beforeStepPositioned = runtime.world().query().view(); + const auto beforeStepActivated = runtime.world().query().view(); + SC_EXPECT_EQ(beforeStepPositioned.size(), std::size_t{1}); + SC_EXPECT_TRUE(beforeStepActivated.empty()); + + runtime.stepFrame(0.25); + + const auto activatedEntities = runtime.world().query().view(); + const auto fullyMatchedEntities = runtime.world().query().view(); + + SC_EXPECT_EQ(queriedCount, std::size_t{1}); + SC_EXPECT_EQ(scheduledActivationCount, std::size_t{1}); + SC_EXPECT_EQ(visibleActivatedCountDuringUpdate, std::size_t{0}); + SC_EXPECT_EQ(activatedEntities.size(), std::size_t{1}); + SC_EXPECT_EQ(fullyMatchedEntities.size(), std::size_t{1}); + + const auto& activated = runtime.world().query().get(activatedEntities.front()); + SC_EXPECT_EQ(activated.fixedStepSeen, 1); +}