From 36ad6b8e8f268e5f15dfd1b95ee2a264cb2eb0b3 Mon Sep 17 00:00:00 2001 From: Romain BOULLARD Date: Sun, 30 Aug 2026 23:56:09 +0200 Subject: [PATCH] Cascading remove test --- Bigfoot/Sources/Engine/Asset/AssetLibrary.cpp | 6 +- .../Include/Engine/Asset/AssetContainer.hpp | 10 +-- .../Include/Engine/Asset/AssetLibrary.hpp | 6 +- Bigfoot/Tests/Engine/Asset/AssetLibrary.cpp | 64 +++++++++++++++++++ 4 files changed, 75 insertions(+), 11 deletions(-) diff --git a/Bigfoot/Sources/Engine/Asset/AssetLibrary.cpp b/Bigfoot/Sources/Engine/Asset/AssetLibrary.cpp index 0ea4f15..5f8d23c 100644 --- a/Bigfoot/Sources/Engine/Asset/AssetLibrary.cpp +++ b/Bigfoot/Sources/Engine/Asset/AssetLibrary.cpp @@ -69,9 +69,9 @@ bool AssetLibrary::IsLoaded(const UUID& p_uuid) const /****************************************************************************************/ -void AssetLibrary::ProcessPendingRemovals() { - - for (const auto [typeId, container] : m_assetContainers) +void AssetLibrary::ProcessPendingRemovals() +{ + for (const auto [typeId, container]: m_assetContainers) { container->ProcessPendingRemovals(); } diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetContainer.hpp b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetContainer.hpp index aee91a1..a0abeaf 100644 --- a/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetContainer.hpp +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetContainer.hpp @@ -27,11 +27,11 @@ class ContainerHandle { public: /** - * Constructor - * - * \param p_assetContainer The originating assetcontainer - * \param p_uuid The UUID of tha asset - */ + * Constructor + * + * \param p_assetContainer The originating assetcontainer + * \param p_uuid The UUID of tha asset + */ ContainerHandle(AssetContainerBase* p_assetContainer, const UUID p_uuid); /* diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetLibrary.hpp b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetLibrary.hpp index 0d87369..049c8f7 100644 --- a/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetLibrary.hpp +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetLibrary.hpp @@ -91,9 +91,9 @@ class AssetLibrary bool IsLoaded(const UUID& p_uuid) const; /** - * Loop through the AssetContainers to remove the pending assets marked for removal - * - */ + * Loop through the AssetContainers to remove the pending assets marked for removal + * + */ void ProcessPendingRemovals(); AssetLibrary& operator=(const AssetLibrary& p_library) = default; diff --git a/Bigfoot/Tests/Engine/Asset/AssetLibrary.cpp b/Bigfoot/Tests/Engine/Asset/AssetLibrary.cpp index 22c3070..3726cbf 100644 --- a/Bigfoot/Tests/Engine/Asset/AssetLibrary.cpp +++ b/Bigfoot/Tests/Engine/Asset/AssetLibrary.cpp @@ -170,6 +170,70 @@ TEST_F(AssetLibraryFixture, ProcessPendingRemovals_ShouldNotRemoveAssetsThatAreN /****************************************************************************************/ +TEST_F(AssetLibraryFixture, ProcessPendingRemovals_ShouldCascadeThroughHardReferencedAssetsOneLevelPerCall) +{ + UUID leafUUID; + UUID middleUUID; + UUID rootUUID; + + { + // leaf + AssetA* leaf = static_cast(m_containerA.Insert()->GetAsset()); + leafUUID = leaf->GetHeader().uuid; + + // middle --> leaf + AssetB* middle = static_cast(m_containerB.Insert()->GetAsset()); + middle->GetAsset().ref_a = HardReference {leafUUID}; + middleUUID = middle->GetHeader().uuid; + + // root + // / \ + // v v + // middle --> leaf + AssetC* root = static_cast(m_containerC.Insert()->GetAsset()); + root->GetAsset().asset_b_ref = HardReference {middleUUID}; + root->GetAsset().inner_table->asset_a_ref = HardReference {leafUUID}; + rootUUID = root->GetHeader().uuid; + + const HardReference rootRef {rootUUID}; + const HardReference middleRef {middleUUID}; + const HardReference leafRef {leafUUID}; + + ASSERT_NE(rootRef.Get(), nullptr); + ASSERT_NE(middleRef.Get(), nullptr); + ASSERT_NE(leafRef.Get(), nullptr); + } + + // Releasing the outer HardReferences only drops root's count to zero: middle and leaf are + // still kept alive by root's own internal HardReferences to them. + EXPECT_TRUE(m_containerC.IsMarkedForRemove(rootUUID)); + EXPECT_FALSE(m_containerB.IsMarkedForRemove(middleUUID)); + EXPECT_FALSE(m_containerA.IsMarkedForRemove(leafUUID)); + EXPECT_TRUE(m_library.IsLoaded(rootUUID)); + EXPECT_TRUE(m_library.IsLoaded(middleUUID)); + EXPECT_TRUE(m_library.IsLoaded(leafUUID)); + + // 1st pass: removing root destroys its HardReference to middle, dropping middle's count to + // zero; leaf is still held alive by middle's own HardReference to it. + m_library.ProcessPendingRemovals(); + EXPECT_FALSE(m_library.IsLoaded(rootUUID)); + EXPECT_TRUE(m_containerB.IsMarkedForRemove(middleUUID)); + EXPECT_TRUE(m_library.IsLoaded(middleUUID)); + EXPECT_TRUE(m_library.IsLoaded(leafUUID)); + + // 2nd pass: removing middle destroys its HardReference to leaf, dropping leaf's count to zero. + m_library.ProcessPendingRemovals(); + EXPECT_FALSE(m_library.IsLoaded(middleUUID)); + EXPECT_TRUE(m_containerA.IsMarkedForRemove(leafUUID)); + EXPECT_TRUE(m_library.IsLoaded(leafUUID)); + + // 3rd pass: nothing references leaf anymore, it finally gets removed. + m_library.ProcessPendingRemovals(); + EXPECT_FALSE(m_library.IsLoaded(leafUUID)); +} + +/****************************************************************************************/ + TEST_F(AssetLibraryFixture, SetActiveAssetLibrary_ShouldSetTheActiveAssetLibraryToTheGivenLibrary) { SetActiveAssetLibrary(&m_library);