From fc9e6ce14dab9461069995a290d299a35831c662 Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 3 Jan 2025 17:51:56 +0100 Subject: [PATCH] test: add test for KeyValuePairsCompilerT6 --- .github/workflows/ci.yaml | 3 + premake5.lua | 2 + .../KeyValuePairs/KeyValuePairsCompilerT6.cpp | 112 ++++++++------- .../KeyValuePairs/KeyValuePairsCompilerT6.h | 23 +--- src/ObjCompiling/Game/T6/ObjCompilerT6.cpp | 2 +- src/Utils/Utils/MemoryManager.h | 53 +++---- .../Utils/TestMemoryManager.h | 14 ++ test/ObjCompilingTests.lua | 58 ++++++++ .../KeyValuePairsCompilerT6Test.cpp | 130 ++++++++++++++++++ 9 files changed, 307 insertions(+), 90 deletions(-) create mode 100644 test/ObjCommonTestUtils/Utils/TestMemoryManager.h create mode 100644 test/ObjCompilingTests.lua create mode 100644 test/ObjCompilingTests/Game/T6/KeyValuePairs/KeyValuePairsCompilerT6Test.cpp diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b3d90c21..02f4f100 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -49,6 +49,7 @@ jobs: working-directory: ${{ github.workspace }}/build/lib/Release_x86/tests run: | ./ObjCommonTests + ./ObjCompilingTests ./ObjLoadingTests ./ParserTests ./ZoneCodeGeneratorLibTests @@ -86,6 +87,8 @@ jobs: $combinedExitCode = 0 ./ObjCommonTests $combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE) + ./ObjCompilingTests + $combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE) ./ObjLoadingTests $combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE) ./ParserTests diff --git a/premake5.lua b/premake5.lua index 331ae3e4..7ff24f46 100644 --- a/premake5.lua +++ b/premake5.lua @@ -172,6 +172,7 @@ group "" -- ======================== include "test/ObjCommonTestUtils.lua" include "test/ObjCommonTests.lua" +include "test/ObjCompilingTests.lua" include "test/ObjLoadingTests.lua" include "test/ParserTestUtils.lua" include "test/ParserTests.lua" @@ -182,6 +183,7 @@ include "test/ZoneCommonTests.lua" group "Tests" ObjCommonTestUtils:project() ObjCommonTests:project() + ObjCompilingTests:project() ObjLoadingTests:project() ParserTestUtils:project() ParserTests:project() diff --git a/src/ObjCompiling/Game/T6/KeyValuePairs/KeyValuePairsCompilerT6.cpp b/src/ObjCompiling/Game/T6/KeyValuePairs/KeyValuePairsCompilerT6.cpp index 11c98ea1..8cba6771 100644 --- a/src/ObjCompiling/Game/T6/KeyValuePairs/KeyValuePairsCompilerT6.cpp +++ b/src/ObjCompiling/Game/T6/KeyValuePairs/KeyValuePairsCompilerT6.cpp @@ -2,6 +2,7 @@ #include "Game/T6/CommonT6.h" #include "Game/T6/T6.h" +#include "KeyValuePairs/KeyValuePairsCreator.h" #include #include @@ -9,54 +10,73 @@ using namespace T6; -KeyValuePairsCompiler::KeyValuePairsCompiler(MemoryManager& memory, - const Zone& zone, - const ZoneDefinition& zoneDefinition, - ZoneAssetCreationStateContainer& zoneStates) - : m_memory(memory), - m_zone(zone), - m_zone_definition(zoneDefinition), - m_kvp_creator(zoneStates.GetZoneAssetCreationState()) +namespace { -} - -std::optional KeyValuePairsCompiler::GetHandlingAssetType() const -{ - return std::nullopt; -} - -AssetCreationResult KeyValuePairsCompiler::CreateAsset(const std::string& assetName, AssetCreationContext& context) -{ - return AssetCreationResult::NoAction(); -} - -void KeyValuePairsCompiler::FinalizeZone(AssetCreationContext& context) -{ - m_kvp_creator.Finalize(m_zone_definition); - const auto commonKvps = m_kvp_creator.GetFinalKeyValuePairs(); - if (commonKvps.empty()) - return; - - auto* gameKvps = m_memory.Alloc(); - gameKvps->name = m_memory.Dup(m_zone.m_name.c_str()); - gameKvps->numVariables = commonKvps.size(); - gameKvps->keyValuePairs = m_memory.Alloc(commonKvps.size()); - - const auto namespaceHash = Common::Com_HashKey(m_zone.m_name.c_str(), 64); - for (auto kvpIndex = 0u; kvpIndex < gameKvps->numVariables; kvpIndex++) + class KeyValuePairsCompiler final : public IAssetCreator { - const auto& commonKvp = commonKvps[kvpIndex]; - auto& gameKvp = gameKvps->keyValuePairs[kvpIndex]; + public: + KeyValuePairsCompiler(MemoryManager& memory, const Zone& zone, const ZoneDefinition& zoneDefinition, ZoneAssetCreationStateContainer& zoneStates) + : m_memory(memory), + m_zone(zone), + m_zone_definition(zoneDefinition), + m_kvp_creator(zoneStates.GetZoneAssetCreationState()) + { + } - assert(commonKvp.m_key_str || commonKvp.m_key_hash); - if (commonKvp.m_key_str) - gameKvp.keyHash = Common::Com_HashKey(commonKvp.m_key_str->c_str(), 64); - else - gameKvp.keyHash = *commonKvp.m_key_hash; + [[nodiscard]] std::optional GetHandlingAssetType() const override + { + return std::nullopt; + } - gameKvp.namespaceHash = namespaceHash; - gameKvp.value = m_memory.Dup(commonKvp.m_value.c_str()); + AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override + { + return AssetCreationResult::NoAction(); + } + + void FinalizeZone(AssetCreationContext& context) override + { + m_kvp_creator.Finalize(m_zone_definition); + const auto commonKvps = m_kvp_creator.GetFinalKeyValuePairs(); + if (commonKvps.empty()) + return; + + auto* gameKvps = m_memory.Alloc(); + gameKvps->name = m_memory.Dup(m_zone.m_name.c_str()); + gameKvps->numVariables = commonKvps.size(); + gameKvps->keyValuePairs = m_memory.Alloc(commonKvps.size()); + + const auto namespaceHash = Common::Com_HashKey(m_zone.m_name.c_str(), 64); + for (auto kvpIndex = 0u; kvpIndex < gameKvps->numVariables; kvpIndex++) + { + const auto& commonKvp = commonKvps[kvpIndex]; + auto& gameKvp = gameKvps->keyValuePairs[kvpIndex]; + + assert(commonKvp.m_key_str || commonKvp.m_key_hash); + if (commonKvp.m_key_str) + gameKvp.keyHash = Common::Com_HashKey(commonKvp.m_key_str->c_str(), 64); + else + gameKvp.keyHash = *commonKvp.m_key_hash; + + gameKvp.namespaceHash = namespaceHash; + gameKvp.value = m_memory.Dup(commonKvp.m_value.c_str()); + } + + context.AddAsset(AssetRegistration(m_zone.m_name, gameKvps)); + } + + private: + MemoryManager& m_memory; + const Zone& m_zone; + const ZoneDefinition& m_zone_definition; + KeyValuePairsCreator& m_kvp_creator; + }; +} // namespace + +namespace T6 +{ + std::unique_ptr + CreateKeyValuePairsCompiler(MemoryManager& memory, const Zone& zone, const ZoneDefinition& zoneDefinition, ZoneAssetCreationStateContainer& zoneStates) + { + return std::make_unique(memory, zone, zoneDefinition, zoneStates); } - - context.AddAsset(AssetRegistration(m_zone.m_name, gameKvps)); -} +} // namespace T6 diff --git a/src/ObjCompiling/Game/T6/KeyValuePairs/KeyValuePairsCompilerT6.h b/src/ObjCompiling/Game/T6/KeyValuePairs/KeyValuePairsCompilerT6.h index fa5ea50e..c68c06b5 100644 --- a/src/ObjCompiling/Game/T6/KeyValuePairs/KeyValuePairsCompilerT6.h +++ b/src/ObjCompiling/Game/T6/KeyValuePairs/KeyValuePairsCompilerT6.h @@ -1,27 +1,16 @@ #pragma once #include "Asset/IAssetCreator.h" -#include "Game/T6/T6.h" -#include "KeyValuePairs/KeyValuePairsCreator.h" +#include "Asset/IZoneAssetCreationState.h" +#include "SearchPath/ISearchPath.h" #include "Utils/MemoryManager.h" #include "Zone/Definition/ZoneDefinition.h" #include "Zone/Zone.h" +#include + namespace T6 { - class KeyValuePairsCompiler final : public IAssetCreator - { - public: - KeyValuePairsCompiler(MemoryManager& memory, const Zone& zone, const ZoneDefinition& zoneDefinition, ZoneAssetCreationStateContainer& zoneStates); - - [[nodiscard]] std::optional GetHandlingAssetType() const override; - AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override; - void FinalizeZone(AssetCreationContext& context) override; - - private: - MemoryManager& m_memory; - const Zone& m_zone; - const ZoneDefinition& m_zone_definition; - KeyValuePairsCreator& m_kvp_creator; - }; + std::unique_ptr + CreateKeyValuePairsCompiler(MemoryManager& memory, const Zone& zone, const ZoneDefinition& zoneDefinition, ZoneAssetCreationStateContainer& zoneStates); } // namespace T6 diff --git a/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp b/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp index 807f8aae..9be2a476 100644 --- a/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp +++ b/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp @@ -20,7 +20,7 @@ namespace { auto& memory = *zone.GetMemory(); - collection.AddAssetCreator(std::make_unique(memory, zone, zoneDefinition.m_zone_definition, zoneStates)); + collection.AddAssetCreator(CreateKeyValuePairsCompiler(memory, zone, zoneDefinition.m_zone_definition, zoneStates)); } void ConfigurePostProcessors(AssetCreatorCollection& collection, diff --git a/src/Utils/Utils/MemoryManager.h b/src/Utils/Utils/MemoryManager.h index bc26f1ee..c9eeefb5 100644 --- a/src/Utils/Utils/MemoryManager.h +++ b/src/Utils/Utils/MemoryManager.h @@ -6,6 +6,33 @@ class MemoryManager { +public: + MemoryManager(); + virtual ~MemoryManager(); + MemoryManager(const MemoryManager& other) = delete; + MemoryManager(MemoryManager&& other) noexcept = default; + MemoryManager& operator=(const MemoryManager& other) = delete; + MemoryManager& operator=(MemoryManager&& other) noexcept = default; + + void* AllocRaw(size_t size); + char* Dup(const char* str); + + template std::add_pointer_t Alloc(const size_t count = 1u) + { + return static_cast>(AllocRaw(sizeof(T) * count)); + } + + template std::add_pointer_t Create(ValType&&... val) + { + Allocation* allocation = new Allocation(std::forward(val)...); + m_destructible.emplace_back(allocation, &allocation->m_entry); + return &allocation->m_entry; + } + + void Free(const void* data); + void Delete(const void* data); + +protected: class IDestructible { public: @@ -47,30 +74,4 @@ class MemoryManager std::vector m_allocations; std::vector m_destructible; - -public: - MemoryManager(); - virtual ~MemoryManager(); - MemoryManager(const MemoryManager& other) = delete; - MemoryManager(MemoryManager&& other) noexcept = default; - MemoryManager& operator=(const MemoryManager& other) = delete; - MemoryManager& operator=(MemoryManager&& other) noexcept = default; - - void* AllocRaw(size_t size); - char* Dup(const char* str); - - template std::add_pointer_t Alloc(const size_t count = 1u) - { - return static_cast>(AllocRaw(sizeof(T) * count)); - } - - template std::add_pointer_t Create(ValType&&... val) - { - Allocation* allocation = new Allocation(std::forward(val)...); - m_destructible.emplace_back(allocation, &allocation->m_entry); - return &allocation->m_entry; - } - - void Free(const void* data); - void Delete(const void* data); }; diff --git a/test/ObjCommonTestUtils/Utils/TestMemoryManager.h b/test/ObjCommonTestUtils/Utils/TestMemoryManager.h new file mode 100644 index 00000000..3ac27e41 --- /dev/null +++ b/test/ObjCommonTestUtils/Utils/TestMemoryManager.h @@ -0,0 +1,14 @@ +#pragma once + +#include "Utils/MemoryManager.h" + +#include + +class TestMemoryManager : public MemoryManager +{ +public: + [[nodiscard]] size_t GetAllocationCount() const + { + return m_allocations.size() + m_destructible.size(); + } +}; diff --git a/test/ObjCompilingTests.lua b/test/ObjCompilingTests.lua new file mode 100644 index 00000000..fc08d7a7 --- /dev/null +++ b/test/ObjCompilingTests.lua @@ -0,0 +1,58 @@ +ObjCompilingTests = {} + +function ObjCompilingTests:include(includes) + if includes:handle(self:name()) then + includedirs { + path.join(TestFolder(), "ObjCompilingTests") + } + end +end + +function ObjCompilingTests:link(links) + +end + +function ObjCompilingTests:use() + +end + +function ObjCompilingTests:name() + return "ObjCompilingTests" +end + +function ObjCompilingTests:project() + local folder = TestFolder() + local includes = Includes:create() + local links = Links:create() + + project(self:name()) + targetdir(TargetDirectoryTest) + location "%{wks.location}/test/%{prj.name}" + kind "ConsoleApp" + language "C++" + + files { + path.join(folder, "ObjCompilingTests/**.h"), + path.join(folder, "ObjCompilingTests/**.cpp") + } + + vpaths { + ["*"] = { + path.join(folder, "ObjCompilingTests") + } + } + + self:include(includes) + ObjCommonTestUtils:include(includes) + ParserTestUtils:include(includes) + ObjLoading:include(includes) + ObjCompiling:include(includes) + catch2:include(includes) + + links:linkto(ObjCommonTestUtils) + links:linkto(ParserTestUtils) + links:linkto(ObjLoading) + links:linkto(ObjCompiling) + links:linkto(catch2) + links:linkall() +end diff --git a/test/ObjCompilingTests/Game/T6/KeyValuePairs/KeyValuePairsCompilerT6Test.cpp b/test/ObjCompilingTests/Game/T6/KeyValuePairs/KeyValuePairsCompilerT6Test.cpp new file mode 100644 index 00000000..b25715b9 --- /dev/null +++ b/test/ObjCompilingTests/Game/T6/KeyValuePairs/KeyValuePairsCompilerT6Test.cpp @@ -0,0 +1,130 @@ +#include "Game/T6/KeyValuePairs/KeyValuePairsCompilerT6.h" + +#include "Game/T6/CommonT6.h" +#include "Game/T6/GameAssetPoolT6.h" +#include "KeyValuePairs/KeyValuePairsCreator.h" +#include "Utils/TestMemoryManager.h" + +#include +#include +#include +#include + +using namespace T6; +using namespace std::string_literals; + +namespace +{ + class TestContext + { + public: + TestContext() + : m_memory(), + m_zone("test", 0, IGame::GetGameById(GameId::T6)), + m_zone_definition(), + m_zone_states(m_zone), + m_creators(m_zone), + m_ignored_assets(), + m_context(m_zone, &m_creators, &m_ignored_assets), + m_kvp_creator(m_zone_states.GetZoneAssetCreationState()) + { + } + + std::unique_ptr CreateSut() + { + return CreateKeyValuePairsCompiler(m_memory, m_zone, m_zone_definition, m_zone_states); + } + + TestMemoryManager m_memory; + Zone m_zone; + ZoneDefinition m_zone_definition; + ZoneAssetCreationStateContainer m_zone_states; + AssetCreatorCollection m_creators; + IgnoredAssetLookup m_ignored_assets; + AssetCreationContext m_context; + + KeyValuePairsCreator& m_kvp_creator; + }; +} // namespace + +namespace test::game::t6::keyvaluepairs +{ + TEST_CASE("KeyValuePairsCompilerT6: Does not handle any asset type", "[keyvaluepairs][t6]") + { + TestContext testContext; + const auto sut = testContext.CreateSut(); + + REQUIRE(!sut->GetHandlingAssetType().has_value()); + } + + TEST_CASE("KeyValuePairsCompilerT6: Does not take any action", "[keyvaluepairs][t6]") + { + TestContext testContext; + const auto sut = testContext.CreateSut(); + + REQUIRE(sut->CreateAsset("anyAsset", testContext.m_context).HasTakenAction() == false); + } + + TEST_CASE("KeyValuePairsCompilerT6: Does nothing without any KeyValuePairs", "[keyvaluepairs][t6]") + { + TestContext testContext; + const auto sut = testContext.CreateSut(); + + sut->FinalizeZone(testContext.m_context); + + REQUIRE(testContext.m_memory.GetAllocationCount() == 0u); + REQUIRE(testContext.m_zone.m_pools->GetTotalAssetCount() == 0u); + } + + TEST_CASE("KeyValuePairsCompilerT6: Creates KeyValuePairs asset with identical name to the zone", "[keyvaluepairs][t6]") + { + TestContext testContext; + const auto sut = testContext.CreateSut(); + + testContext.m_kvp_creator.AddKeyValuePair(CommonKeyValuePair("ipak_read", "test_ipak")); + + sut->FinalizeZone(testContext.m_context); + + REQUIRE(testContext.m_memory.GetAllocationCount() > 0u); + REQUIRE(testContext.m_zone.m_pools->GetTotalAssetCount() == 1u); + + XAssetInfo* assetInfo = *dynamic_cast(testContext.m_zone.m_pools.get())->m_key_value_pairs->begin(); + REQUIRE(assetInfo); + REQUIRE(assetInfo->m_name == "test"); + + auto* asset = assetInfo->Asset(); + REQUIRE(asset->name == "test"s); + REQUIRE(asset->numVariables == 1u); + REQUIRE(asset->keyValuePairs != nullptr); + + REQUIRE(asset->keyValuePairs[0].keyHash == 0x0001bdc1); + REQUIRE(asset->keyValuePairs[0].namespaceHash == 0x0000d2d3); + REQUIRE(asset->keyValuePairs[0].value == "test_ipak"s); + } + + TEST_CASE("KeyValuePairsCompilerT6: Creates KeyValuePairs asset with predefined hash", "[keyvaluepairs][t6]") + { + TestContext testContext; + const auto sut = testContext.CreateSut(); + + testContext.m_kvp_creator.AddKeyValuePair(CommonKeyValuePair(0xDDEEFFAA, "hello_there")); + + sut->FinalizeZone(testContext.m_context); + + REQUIRE(testContext.m_memory.GetAllocationCount() > 0u); + REQUIRE(testContext.m_zone.m_pools->GetTotalAssetCount() == 1u); + + XAssetInfo* assetInfo = *dynamic_cast(testContext.m_zone.m_pools.get())->m_key_value_pairs->begin(); + REQUIRE(assetInfo); + REQUIRE(assetInfo->m_name == "test"); + + auto* asset = assetInfo->Asset(); + REQUIRE(asset->name == "test"s); + REQUIRE(asset->numVariables == 1u); + REQUIRE(asset->keyValuePairs != nullptr); + + REQUIRE(asset->keyValuePairs[0].keyHash == 0xDDEEFFAA); + REQUIRE(asset->keyValuePairs[0].namespaceHash == 0x0000d2d3); + REQUIRE(asset->keyValuePairs[0].value == "hello_there"s); + } +} // namespace test::game::t6::keyvaluepairs