#include #if JULIET_DEBUG #include #include #include #include #include #include #include #include #include namespace UnitTest { internal void TestEntityAllocationAndWiring() { Log(LogLevel::Message, LogCategory::Game, "[UnitTest] Running TestEntityAllocationAndWiring..."); TempArena tempArena = scratch_begin(nullptr, 0); World testWorld{}; InitWorld(&testWorld, tempArena.Arena); InitEntityManager(&testWorld); EntityManager& manager = *testWorld.EntityManager; // 1. Allocate Inert Entity via AllocateEntity Entity* base_entity = allocate_entity(manager, Inert::kind); Assert(base_entity != nullptr); Assert(base_entity->ID == 0); // Pure memory allocator leaves ID unassigned (0) until MakeEntity or deserialization base_entity->ID = ++EntityManager::ID; Assert(base_entity->ID > 0); Assert(base_entity->derived_kind == Inert::kind); Assert(base_entity->derived != nullptr); Assert(base_entity->is_dirty == true); // 2. Validate mutual back-pointer wiring auto* derived = reinterpret_cast(base_entity->derived); Assert(derived->base == base_entity); // 3. DownCast verification Inert* inert = DownCast(base_entity); Assert(inert != nullptr); Assert(inert->base == base_entity); // 4. Validate typed array tracking typed_entity_array& inert_array = manager.by_type[ENTITY(Inert)]; Assert(inert_array.count == 1); Assert(inert_array.array == derived); ShutdownEntityManager(); ShutdownWorld(&testWorld); scratch_end(tempArena); Log(LogLevel::Message, LogCategory::Game, "[UnitTest] PASSED: TestEntityAllocationAndWiring"); } internal void TestInPlaceDeserialization() { Log(LogLevel::Message, LogCategory::Game, "[UnitTest] Running TestInPlaceDeserialization..."); TempArena tempArena = scratch_begin(nullptr, 0); World testWorld{}; InitWorld(&testWorld, tempArena.Arena); InitEntityManager(&testWorld); EntityManager& manager = *testWorld.EntityManager; // 1. In-memory .jasset text fixture (no streams or files needed) String asset_content = ConstString("; class\n" "Inert\n" "; version\n" "1\n" "; class_version\n" "1\n" "; id\n" "42\n" "; position\n" "12.5 -44.0 108.2 1.0\n" "; MeshInstance\n" "42\n"); ByteBuffer buffer = { .Data = reinterpret_cast(asset_content.Str), .Size = asset_content.Size }; // 2. Tokenize into Archive Archive load_ar = {}; load_ar.arena = tempArena.Arena; load_ar.loading = true; load_ar.base = tokenize_archive(tempArena.Arena, buffer); // 3. Deserialize in-place Entity* loaded_base = deserialize_entity(load_ar, manager); // 4. Verify in-place allocations and values Assert(loaded_base != nullptr); Assert(loaded_base->ID == 42); Assert(EntityManager::ID > 42); // Generator counter advanced past loaded ID Assert(loaded_base->position.x == 12.5f); Assert(loaded_base->position.y == -44.0f); Assert(loaded_base->position.z == 108.2f); Assert(loaded_base->is_dirty == false); Inert* loaded_inert = DownCast(loaded_base); Assert(loaded_inert != nullptr); Assert(loaded_inert->base == loaded_base); Assert(loaded_inert->MeshInstance == 42); ShutdownEntityManager(); ShutdownWorld(&testWorld); scratch_end(tempArena); Log(LogLevel::Message, LogCategory::Game, "[UnitTest] PASSED: TestInPlaceDeserialization"); } internal void TestDirtyTrackingLifecycle() { Log(LogLevel::Message, LogCategory::Game, "[UnitTest] Running TestDirtyTrackingLifecycle..."); TempArena tempArena = scratch_begin(nullptr, 0); World testWorld{}; InitWorld(&testWorld, tempArena.Arena); InitEntityManager(&testWorld); EntityManager& manager = *testWorld.EntityManager; Entity* entity = allocate_entity(manager, Inert::kind); Assert(entity->is_dirty == true); // Simulate save entity->is_dirty = false; Assert(entity->is_dirty == false); // Simulate mutation entity->position.x += 1.0f; entity->is_dirty = true; Assert(entity->is_dirty == true); ShutdownEntityManager(); ShutdownWorld(&testWorld); scratch_end(tempArena); Log(LogLevel::Message, LogCategory::Game, "[UnitTest] PASSED: TestDirtyTrackingLifecycle"); } void WorldUnitTest() { Log(LogLevel::Message, LogCategory::Game, "=================================================="); Log(LogLevel::Message, LogCategory::Game, "Starting Entity Allocation & Lifecycle Unit Tests"); Log(LogLevel::Message, LogCategory::Game, "=================================================="); TestEntityAllocationAndWiring(); TestInPlaceDeserialization(); // TestSwapAndPopPointerFixup(); // Deferred to Entity_Removal_Brainstorm.md TestDirtyTrackingLifecycle(); Log(LogLevel::Message, LogCategory::Game, "=================================================="); Log(LogLevel::Message, LogCategory::Game, "All Entity Lifecycle Unit Tests PASSED Successfully"); Log(LogLevel::Message, LogCategory::Game, "=================================================="); } } // namespace UnitTest #endif