You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
351 lines
13 KiB
C++
351 lines
13 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
#include <AzTest/AzTest.h>
|
|
|
|
#include <AzCore/Serialization/ObjectStream.h>
|
|
#include <AzCore/Serialization/SerializeContext.h>
|
|
#include <AzCore/Serialization/Utils.h>
|
|
#include <AzCore/std/smart_ptr/make_shared.h>
|
|
|
|
#include <AzCore/Serialization/Json/JsonUtils.h>
|
|
|
|
#include <Atom/RPI.Edit/Common/ConvertibleSource.h>
|
|
#include <Atom/RPI.Reflect/System/AnyAsset.h>
|
|
|
|
#include <Common/AnyAssetBuilder.h>
|
|
|
|
#include <Tests.Builders/BuilderTestFixture.h>
|
|
|
|
namespace UnitTest
|
|
{
|
|
using namespace AZ;
|
|
|
|
// Basic test class which is also used for output class of convertible class test
|
|
class Test1
|
|
{
|
|
public:
|
|
AZ_TYPE_INFO(Test1, "{A3369968-6E98-4319-A4CA-A0E2CF9F2E7C}");
|
|
AZ_CLASS_ALLOCATOR(Test1, AZ::SystemAllocator, 0);
|
|
|
|
static void Reflect(ReflectContext* context)
|
|
{
|
|
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
|
{
|
|
serializeContext->Class<Test1>()
|
|
->Version(1)
|
|
->Field("m_data", &Test1::m_data)
|
|
->Field("m_isConverted", &Test1::m_isConverted)
|
|
;
|
|
}
|
|
}
|
|
|
|
AZStd::string m_data = "Test1";
|
|
bool m_isConverted = false;
|
|
};
|
|
|
|
// Test class with convertible source
|
|
class Test2Source :
|
|
public RPI::ConvertibleSource
|
|
{
|
|
public:
|
|
AZ_TYPE_INFO(Test2Source, "{D472B405-F688-4EAF-A361-D8D1C63E303D}");
|
|
AZ_CLASS_ALLOCATOR(Test2Source, AZ::SystemAllocator, 0);
|
|
|
|
static void Reflect(ReflectContext* context)
|
|
{
|
|
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
|
{
|
|
serializeContext->Class<Test2Source, ConvertibleSource>()
|
|
->Version(1)
|
|
;
|
|
}
|
|
}
|
|
|
|
// ConvertibleSource overrides...
|
|
bool Convert(TypeId& outTypeId, AZStd::shared_ptr<void>& outData) const override
|
|
{
|
|
// convert this to Test1
|
|
outTypeId = AzTypeInfo<Test1>::Uuid();
|
|
auto data = aznew Test1();
|
|
data->m_isConverted = true;
|
|
outData = AZStd::shared_ptr<void>(data);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
class TestAssetData
|
|
: public Data::AssetData
|
|
{
|
|
public:
|
|
AZ_CLASS_ALLOCATOR(TestAssetData, AZ::SystemAllocator, 0);
|
|
AZ_RTTI(TestAssetData, "{A7D2C40A-2559-4DF7-A308-D52286EE16D8}", Data::AssetData);
|
|
};
|
|
|
|
// Test class type with AssetId and Asset reference
|
|
class TestAssetIdReference
|
|
{
|
|
public:
|
|
AZ_TYPE_INFO(TestAssetIdReference, "{87DC6B1E-4660-4AEA-AEE1-6F50EF7FA0D7}");
|
|
AZ_CLASS_ALLOCATOR(TestAssetIdReference, AZ::SystemAllocator, 0);
|
|
|
|
virtual ~TestAssetIdReference() = default;
|
|
|
|
static void Reflect(ReflectContext* context)
|
|
{
|
|
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
|
{
|
|
serializeContext->Class<TestAssetIdReference>()
|
|
->Version(1)
|
|
// Not supported by Json Serializer yet. LY-105721
|
|
//->Field("m_asset", &TestAssetIdReference::m_asset)
|
|
->Field("EmptyAssetId", &TestAssetIdReference::m_emptyAssetId)
|
|
->Field("ValidAssetId", &TestAssetIdReference::m_validAssetId)
|
|
->Field("DuplicateAssetId", &TestAssetIdReference::m_duplicateAssetId)
|
|
->Field("AssetIdInContainer", &TestAssetIdReference::m_assetIdInContainer)
|
|
;
|
|
}
|
|
}
|
|
|
|
TestAssetIdReference()
|
|
: m_asset(Data::AssetLoadBehavior::NoLoad)
|
|
{
|
|
}
|
|
|
|
virtual void Init()
|
|
{
|
|
m_validAssetId = Data::AssetId(Uuid::CreateRandom(), 1);
|
|
m_duplicateAssetId = m_validAssetId;
|
|
m_asset = Data::Asset<Data::AssetData>(Data::AssetId(Uuid::CreateRandom(), 0), TestAssetData::TYPEINFO_Uuid());
|
|
m_assetIdInContainer.push_back(Data::AssetId(Uuid::CreateRandom(), 0));
|
|
}
|
|
|
|
Data::Asset<TestAssetData> m_asset;
|
|
Data::AssetId m_emptyAssetId;
|
|
Data::AssetId m_validAssetId;
|
|
Data::AssetId m_duplicateAssetId;
|
|
AZStd::vector<Data::AssetId> m_assetIdInContainer;
|
|
|
|
// The total amount of unique asset ids referenced by this class object
|
|
// one from m_asset, one from m_validAssetId
|
|
static const int s_uniqueAssetIdCount = 2;
|
|
};
|
|
|
|
class DerivedTestAssetIdReference
|
|
: public TestAssetIdReference
|
|
{
|
|
public:
|
|
AZ_TYPE_INFO(DerivedTestAssetIdReference, "{B5778901-A553-41B2-B411-CF8FBE2B1E10}");
|
|
AZ_CLASS_ALLOCATOR(DerivedTestAssetIdReference, AZ::SystemAllocator, 0);
|
|
|
|
static void Reflect(ReflectContext* context)
|
|
{
|
|
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
|
{
|
|
serializeContext->Class<DerivedTestAssetIdReference, TestAssetIdReference>()
|
|
->Version(1)
|
|
;
|
|
}
|
|
}
|
|
};
|
|
|
|
// Test class includes member which is a class that has asset id and asset reference as members
|
|
class TestIndirectAssetIdReference
|
|
{
|
|
public:
|
|
AZ_TYPE_INFO(TestIndirectAssetIdReference, "{402D2672-55CD-46B9-9387-E34D6B10F88A}");
|
|
AZ_CLASS_ALLOCATOR(TestIndirectAssetIdReference, AZ::SystemAllocator, 0);
|
|
|
|
static void Reflect(ReflectContext* context)
|
|
{
|
|
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
|
{
|
|
serializeContext->Class<TestIndirectAssetIdReference>()
|
|
->Version(1)
|
|
->Field("m_object", &TestIndirectAssetIdReference::m_object)
|
|
->Field("m_objectPtr", &TestIndirectAssetIdReference::m_objectPtr)
|
|
->Field("m_objects", &TestIndirectAssetIdReference::m_objects)
|
|
->Field("m_objectWithBase", &TestIndirectAssetIdReference::m_objectWithBase)
|
|
;
|
|
}
|
|
}
|
|
|
|
void Init()
|
|
{
|
|
m_object.Init();
|
|
m_objectPtr = AZStd::make_unique<TestAssetIdReference>();
|
|
m_objectPtr->Init();
|
|
m_objects["Test4"].Init();
|
|
m_objectWithBase.Init();
|
|
}
|
|
|
|
TestAssetIdReference m_object;
|
|
AZStd::unique_ptr<TestAssetIdReference> m_objectPtr = nullptr;
|
|
AZStd::unordered_map<AZStd::string, TestAssetIdReference> m_objects;
|
|
DerivedTestAssetIdReference m_objectWithBase;
|
|
|
|
static const int s_uniqueAssetIdCount = 4 * TestAssetIdReference::s_uniqueAssetIdCount;
|
|
};
|
|
|
|
class AnyAssetBuilderTests
|
|
: public BuilderTestFixture
|
|
{
|
|
protected:
|
|
|
|
RPI::AnyAssetHandler* m_assetHandler;
|
|
|
|
void SetUp() override
|
|
{
|
|
BuilderTestFixture::SetUp();
|
|
|
|
Test1::Reflect(m_context.get());
|
|
Test2Source::Reflect(m_context.get());
|
|
TestAssetIdReference::Reflect(m_context.get());
|
|
DerivedTestAssetIdReference::Reflect(m_context.get());
|
|
TestIndirectAssetIdReference::Reflect(m_context.get());
|
|
m_assetHandler = new RPI::AnyAssetHandler();
|
|
m_assetHandler->m_serializeContext = m_context.get();
|
|
m_assetHandler->Register();
|
|
}
|
|
|
|
void TearDown() override
|
|
{
|
|
m_assetHandler->Unregister();
|
|
delete m_assetHandler;
|
|
BuilderTestFixture::TearDown();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Helper function to generate source AnyAsset and save it to specified folder
|
|
template<typename T>
|
|
void SaveClassToAnyAssetSourceFile(T& data, const char* saveFileName)
|
|
{
|
|
JsonSerializationUtils::SaveObjectToFile<T>(&data, saveFileName);
|
|
}
|
|
|
|
Data::Asset<Data::AssetData> LoadAssetFromFile(const char* assetFile)
|
|
{
|
|
Data::Asset<Data::AssetData> outAsset(m_assetHandler->CreateAsset(Data::AssetId(Uuid::CreateRandom(), 1), Data::AssetType()),
|
|
Data::AssetLoadBehavior::PreLoad);
|
|
AZ::u64 fileLength = 0;
|
|
AZ::IO::FileIOBase::GetInstance()->Size(assetFile, fileLength);
|
|
AZStd::shared_ptr<AZ::Data::AssetDataStream> stream = AZStd::make_shared<AZ::Data::AssetDataStream>();
|
|
stream->Open(assetFile, 0, fileLength);
|
|
stream->BlockUntilLoadComplete();
|
|
m_assetHandler->LoadAssetData(outAsset, stream, {});
|
|
return outAsset;
|
|
}
|
|
|
|
};
|
|
|
|
TEST_F(AnyAssetBuilderTests, ProcessJobBasic)
|
|
{
|
|
// Basic test: test data before and after are same. Test data class doesn't have converter or asset reference.
|
|
RPI::AnyAssetBuilder builder;
|
|
AssetBuilderSDK::ProcessJobRequest request;
|
|
AssetBuilderSDK::ProcessJobResponse response;
|
|
|
|
// Initial job request
|
|
const char* testAssetName = "AnyAssetTest.source";
|
|
request.m_fullPath = testAssetName;
|
|
request.m_tempDirPath = m_currentDir;
|
|
|
|
Test1 test1;
|
|
test1.m_data = "first";
|
|
SaveClassToAnyAssetSourceFile<Test1>(test1, testAssetName);
|
|
|
|
// Process
|
|
builder.ProcessJob(request, response);
|
|
|
|
// verify job output
|
|
EXPECT_TRUE(response.m_resultCode == AssetBuilderSDK::ProcessJobResult_Success);
|
|
EXPECT_TRUE(response.m_outputProducts.size() == 1);
|
|
EXPECT_TRUE(response.m_outputProducts[0].m_dependencies.size() == 0);
|
|
|
|
// verify input and output data are same
|
|
auto outAsset = LoadAssetFromFile(response.m_outputProducts[0].m_productFileName.c_str());
|
|
auto outTest1 = static_cast<RPI::AnyAsset*>(outAsset.GetData())->GetDataAs<Test1>();
|
|
EXPECT_TRUE(test1.m_data == outTest1->m_data);
|
|
}
|
|
|
|
TEST_F(AnyAssetBuilderTests, ProcessJobConvert)
|
|
{
|
|
RPI::AnyAssetBuilder builder;
|
|
AssetBuilderSDK::ProcessJobRequest request;
|
|
AssetBuilderSDK::ProcessJobResponse response;
|
|
|
|
// Initial job request
|
|
const char* testAssetName = "AnyAssetTest.source";
|
|
request.m_fullPath = testAssetName;
|
|
request.m_tempDirPath = m_currentDir;
|
|
|
|
// Test data class which has a converter
|
|
Test2Source test2;
|
|
SaveClassToAnyAssetSourceFile<Test2Source>(test2, testAssetName);
|
|
|
|
builder.ProcessJob(request, response);
|
|
EXPECT_TRUE(response.m_resultCode == AssetBuilderSDK::ProcessJobResult_Success);
|
|
|
|
auto outAsset = LoadAssetFromFile(response.m_outputProducts[0].m_productFileName.c_str());
|
|
auto outTest2 = static_cast<RPI::AnyAsset*>(outAsset.GetData())->GetDataAs<Test1>();
|
|
EXPECT_TRUE(outTest2 != nullptr);
|
|
EXPECT_TRUE(outTest2->m_isConverted);
|
|
}
|
|
|
|
TEST_F(AnyAssetBuilderTests, ProcessJobDependencyDirect)
|
|
{
|
|
RPI::AnyAssetBuilder builder;
|
|
AssetBuilderSDK::ProcessJobRequest request;
|
|
AssetBuilderSDK::ProcessJobResponse response;
|
|
|
|
// Initial job request once
|
|
const char* testAssetName = "AnyAssetTest.source";
|
|
request.m_fullPath = testAssetName;
|
|
request.m_tempDirPath = m_currentDir;
|
|
|
|
// Test class which has asset id and asset reference as member variables
|
|
TestAssetIdReference objectHasAssetIds;
|
|
objectHasAssetIds.Init();
|
|
SaveClassToAnyAssetSourceFile<TestAssetIdReference>(objectHasAssetIds, testAssetName);
|
|
|
|
builder.ProcessJob(request, response);
|
|
EXPECT_TRUE(response.m_resultCode == AssetBuilderSDK::ProcessJobResult_Success);
|
|
|
|
auto outAsset = LoadAssetFromFile(response.m_outputProducts[0].m_productFileName.c_str());
|
|
auto outTest3 = static_cast<RPI::AnyAsset*>(outAsset.GetData())->GetDataAs<TestAssetIdReference>();
|
|
EXPECT_TRUE(outTest3 != nullptr);
|
|
EXPECT_TRUE(response.m_outputProducts[0].m_dependencies.size() == objectHasAssetIds.s_uniqueAssetIdCount);
|
|
}
|
|
|
|
TEST_F(AnyAssetBuilderTests, ProcessJobDependencyIndirect)
|
|
{
|
|
RPI::AnyAssetBuilder builder;
|
|
AssetBuilderSDK::ProcessJobRequest request;
|
|
AssetBuilderSDK::ProcessJobResponse response;
|
|
|
|
// Initial job request once
|
|
const char* testAssetName = "AnyAssetTest.source";
|
|
request.m_fullPath = testAssetName;
|
|
request.m_tempDirPath = m_currentDir;
|
|
|
|
// Test class includes member which its class has asset id and asset reference as children
|
|
TestIndirectAssetIdReference test4;
|
|
test4.Init();
|
|
SaveClassToAnyAssetSourceFile<TestIndirectAssetIdReference>(test4, testAssetName);
|
|
|
|
builder.ProcessJob(request, response);
|
|
EXPECT_TRUE(response.m_resultCode == AssetBuilderSDK::ProcessJobResult_Success);
|
|
|
|
auto outAsset = LoadAssetFromFile(response.m_outputProducts[0].m_productFileName.c_str());
|
|
auto outTest4 = static_cast<RPI::AnyAsset*>(outAsset.GetData())->GetDataAs<TestIndirectAssetIdReference>();
|
|
EXPECT_TRUE(outTest4 != nullptr);
|
|
EXPECT_TRUE(response.m_outputProducts[0].m_dependencies.size() == test4.s_uniqueAssetIdCount);
|
|
}
|
|
} // namespace UnitTests
|