SliceBuilderTests.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AssetBuilderSDK/SerializationDependencies.h>
  9. #include <AzCore/Serialization/SerializeContext.h>
  10. #include <AzTest/AzTest.h>
  11. #include <AzToolsFramework/Slice/SliceUtilities.h>
  12. #include <AzCore/Asset/AssetSerializer.h>
  13. #include <AzCore/IO/ByteContainerStream.h>
  14. #include <AzCore/Slice/SliceAssetHandler.h>
  15. #include <AzCore/std/smart_ptr/make_shared.h>
  16. #include <AzCore/UnitTest/TestTypes.h>
  17. #include <AzCore/Component/ComponentApplication.h>
  18. #include <AzFramework/Asset/GenericAssetHandler.h>
  19. #include <Builders/SliceBuilder/SliceBuilderWorker.h>
  20. #include <AzCore/Slice/SliceComponent.h>
  21. #include <AzCore/Slice/SliceMetadataInfoComponent.h>
  22. #include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
  23. #include <Builders/SliceBuilder/SliceBuilderComponent.h>
  24. #include "AzFramework/Asset/SimpleAsset.h"
  25. #include "Tests/AZTestShared/Utils/Utils.h"
  26. namespace UnitTest
  27. {
  28. using namespace SliceBuilder;
  29. using namespace AZ;
  30. struct MockAsset
  31. : public AZ::Data::AssetData
  32. {
  33. AZ_CLASS_ALLOCATOR(MockAsset, AZ::SystemAllocator)
  34. AZ_RTTI(MockAsset, "{6A98A05A-5B8B-455B-BA92-508A7CF76024}", AZ::Data::AssetData);
  35. static void Reflect(ReflectContext* reflection)
  36. {
  37. SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(reflection);
  38. if (serializeContext)
  39. {
  40. serializeContext->Class<MockAsset>()
  41. ->Field("value", &MockAsset::m_value);
  42. }
  43. }
  44. int m_value = 0;
  45. };
  46. struct MockAssetRefComponent
  47. : public AZ::Component
  48. {
  49. AZ_COMPONENT(MockAssetRefComponent, "{92A6CEC4-BB83-4BED-B062-8A69302E0C9D}");
  50. static void Reflect(ReflectContext* reflection)
  51. {
  52. SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(reflection);
  53. if (serializeContext)
  54. {
  55. serializeContext->Class<MockAssetRefComponent, AZ::Component>()
  56. ->Field("asset", &MockAssetRefComponent::m_asset);
  57. }
  58. }
  59. void Activate() override {}
  60. void Deactivate() override {}
  61. Data::Asset<MockAsset> m_asset;
  62. };
  63. class MockSimpleSliceAsset
  64. {
  65. public:
  66. AZ_TYPE_INFO(MockSimpleSliceAsset, "{923AE476-3491-49F7-A77C-70C896C1B1FD}");
  67. static const char* GetFileFilter()
  68. {
  69. return "*.txt;";
  70. }
  71. };
  72. struct MockSubType
  73. {
  74. AZ_TYPE_INFO(MockSubType, "{25824223-EE7E-4F44-8181-6D3AC5119BB9}");
  75. static void Reflect(ReflectContext* reflection)
  76. {
  77. SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(reflection);
  78. if (serializeContext)
  79. {
  80. serializeContext->Class<MockSubType>()
  81. ->Version(m_version);
  82. }
  83. }
  84. static int m_version;
  85. };
  86. int MockSubType::m_version = 1;
  87. struct MockComponent : AZ::Component
  88. {
  89. AZ_COMPONENT(MockComponent, "{0A556691-1658-48B7-9745-5FDBA8E13D11}");
  90. static void Reflect(ReflectContext* reflection)
  91. {
  92. SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(reflection);
  93. if (serializeContext)
  94. {
  95. serializeContext->Class<MockComponent, AZ::Component>()
  96. ->Field("subdata", &MockComponent::m_subData);
  97. }
  98. }
  99. void Activate() override {}
  100. void Deactivate() override {}
  101. MockSubType m_subData{};
  102. };
  103. namespace SliceBuilder
  104. {
  105. struct MockSimpleSliceAssetRefComponent
  106. : public AZ::Component
  107. {
  108. AZ_COMPONENT(MockSimpleSliceAssetRefComponent, "{C3B2F100-D08C-4912-AC16-57506B190C2F}");
  109. static void Reflect(ReflectContext* reflection)
  110. {
  111. SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(reflection);
  112. AzFramework::SimpleAssetReference<MockSimpleSliceAsset>::Register(*serializeContext);
  113. if (serializeContext)
  114. {
  115. serializeContext->Class<MockSimpleSliceAssetRefComponent, AZ::Component>()
  116. ->Field("asset", &MockSimpleSliceAssetRefComponent::m_asset);
  117. }
  118. }
  119. void Activate() override {}
  120. void Deactivate() override {}
  121. AzFramework::SimpleAssetReference<MockSimpleSliceAsset> m_asset;
  122. };
  123. }
  124. struct MockEditorComponent
  125. : public AzToolsFramework::Components::EditorComponentBase
  126. {
  127. AZ_EDITOR_COMPONENT(MockEditorComponent, "{550BA62B-9A98-4A6E-BF7D-7BC939796CF5}");
  128. static void Reflect(ReflectContext* reflection)
  129. {
  130. SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(reflection);
  131. if (serializeContext)
  132. {
  133. serializeContext->Class<MockEditorComponent, AzToolsFramework::Components::EditorComponentBase>()
  134. ->Field("uuid", &MockEditorComponent::m_uuid);
  135. }
  136. }
  137. void BuildGameEntity(AZ::Entity* gameEntity) override
  138. {
  139. auto* assetComponent = aznew MockAssetRefComponent;
  140. assetComponent->m_asset = Data::AssetManager::Instance().CreateAsset<MockAsset>(AZ::Data::AssetId(m_uuid, 0), AZ::Data::AssetLoadBehavior::Default);
  141. gameEntity->AddComponent(assetComponent);
  142. }
  143. AZ::Uuid m_uuid;
  144. };
  145. using namespace AZ::Data;
  146. class SliceBuilderTest_MockCatalog
  147. : public AssetCatalog
  148. , public AZ::Data::AssetCatalogRequestBus::Handler
  149. {
  150. private:
  151. AZ::Uuid randomUuid = AZ::Uuid::CreateRandom();
  152. AZStd::vector<AssetId> m_mockAssetIds;
  153. public:
  154. AZ_CLASS_ALLOCATOR(SliceBuilderTest_MockCatalog, AZ::SystemAllocator);
  155. SliceBuilderTest_MockCatalog()
  156. {
  157. AssetCatalogRequestBus::Handler::BusConnect();
  158. }
  159. ~SliceBuilderTest_MockCatalog()
  160. {
  161. AssetCatalogRequestBus::Handler::BusDisconnect();
  162. }
  163. AssetId GenerateMockAssetId()
  164. {
  165. AssetId assetId = AssetId(AZ::Uuid::CreateRandom(), 0);
  166. m_mockAssetIds.push_back(assetId);
  167. return assetId;
  168. }
  169. //////////////////////////////////////////////////////////////////////////
  170. // AssetCatalogRequestBus
  171. AssetInfo GetAssetInfoById(const AssetId& id) override
  172. {
  173. AssetInfo result;
  174. result.m_assetType = AZ::AzTypeInfo<AZ::SliceAsset>::Uuid();
  175. for (const AssetId& assetId : m_mockAssetIds)
  176. {
  177. if (assetId == id)
  178. {
  179. result.m_assetId = id;
  180. break;
  181. }
  182. }
  183. return result;
  184. }
  185. //////////////////////////////////////////////////////////////////////////
  186. AssetStreamInfo GetStreamInfoForLoad(const AssetId& id, const AssetType& type) override
  187. {
  188. EXPECT_TRUE(type == AzTypeInfo<SliceAsset>::Uuid());
  189. AssetStreamInfo info;
  190. info.m_dataOffset = 0;
  191. info.m_streamFlags = IO::OpenMode::ModeRead;
  192. for (int i = 0; i < m_mockAssetIds.size(); ++i)
  193. {
  194. if (m_mockAssetIds[i] == id)
  195. {
  196. info.m_streamName = AZStd::string::format("MockSliceAssetName%d", i);
  197. }
  198. }
  199. if (!info.m_streamName.empty())
  200. {
  201. // this ensures tha parallel running unit tests do not overlap their files that they use.
  202. AZ::IO::Path fullName = GetTestFolderPath() / AZStd::string::format("%s-%s", randomUuid.ToString<AZStd::string>().c_str(), info.m_streamName.c_str());
  203. info.m_streamName = AZStd::move(fullName.Native());
  204. info.m_dataLen = static_cast<size_t>(IO::SystemFile::Length(info.m_streamName.c_str()));
  205. }
  206. else
  207. {
  208. info.m_dataLen = 0;
  209. }
  210. return info;
  211. }
  212. AssetStreamInfo GetStreamInfoForSave(const AssetId& id, const AssetType& type) override
  213. {
  214. AssetStreamInfo info;
  215. info = GetStreamInfoForLoad(id, type);
  216. info.m_streamFlags = IO::OpenMode::ModeWrite;
  217. return info;
  218. }
  219. bool SaveAsset(Asset<SliceAsset>& asset)
  220. {
  221. volatile bool isDone = false;
  222. volatile bool succeeded = false;
  223. AssetBusCallbacks callbacks;
  224. callbacks.SetCallbacks(nullptr, nullptr, nullptr,
  225. [&isDone, &succeeded](const Asset<AssetData>& /*asset*/, bool isSuccessful, AssetBusCallbacks& /*callbacks*/)
  226. {
  227. isDone = true;
  228. succeeded = isSuccessful;
  229. }, nullptr, nullptr, nullptr);
  230. callbacks.BusConnect(asset.GetId());
  231. asset.Save();
  232. while (!isDone)
  233. {
  234. AssetManager::Instance().DispatchEvents();
  235. }
  236. return succeeded;
  237. }
  238. };
  239. class DependencyTest
  240. : public LeakDetectionFixture
  241. , public ComponentApplicationBus::Handler
  242. {
  243. public:
  244. //////////////////////////////////////////////////////////////////////////
  245. // ComponentApplicationMessages
  246. ComponentApplication* GetApplication() override { return nullptr; }
  247. void RegisterComponentDescriptor(const ComponentDescriptor*) override { }
  248. void UnregisterComponentDescriptor(const ComponentDescriptor*) override { }
  249. void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler&) override { }
  250. void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override { }
  251. void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { }
  252. void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { }
  253. void SignalEntityActivated(Entity*) override { }
  254. void SignalEntityDeactivated(Entity*) override { }
  255. bool AddEntity(Entity*) override { return true; }
  256. bool RemoveEntity(Entity*) override { return true; }
  257. bool DeleteEntity(const AZ::EntityId&) override { return true; }
  258. Entity* FindEntity(const AZ::EntityId&) override { return nullptr; }
  259. SerializeContext* GetSerializeContext() override { return m_serializeContext; }
  260. BehaviorContext* GetBehaviorContext() override { return nullptr; }
  261. JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; }
  262. const char* GetEngineRoot() const override { return nullptr; }
  263. const char* GetExecutableFolder() const override { return nullptr; }
  264. void EnumerateEntities(const EntityCallback& /*callback*/) override {}
  265. void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {}
  266. //////////////////////////////////////////////////////////////////////////
  267. void SetUp() override
  268. {
  269. LeakDetectionFixture::SetUp();
  270. m_serializeContext = aznew SerializeContext(true, true);
  271. ComponentApplicationBus::Handler::BusConnect();
  272. AZ::Interface<AZ::ComponentApplicationRequests>::Register(this);
  273. m_sliceDescriptor = SliceComponent::CreateDescriptor();
  274. m_mockAssetDescriptor = MockAssetRefComponent::CreateDescriptor();
  275. m_mockSimpleAssetDescriptor = SliceBuilder::MockSimpleSliceAssetRefComponent::CreateDescriptor();
  276. m_sliceDescriptor->Reflect(m_serializeContext);
  277. m_mockAssetDescriptor->Reflect(m_serializeContext);
  278. m_mockSimpleAssetDescriptor->Reflect(m_serializeContext);
  279. AzFramework::SimpleAssetReferenceBase::Reflect(m_serializeContext);
  280. MockAsset::Reflect(m_serializeContext);
  281. MockEditorComponent::Reflect(m_serializeContext);
  282. Entity::Reflect(m_serializeContext);
  283. DataPatch::Reflect(m_serializeContext);
  284. SliceMetadataInfoComponent::Reflect(m_serializeContext);
  285. AzToolsFramework::Components::EditorComponentBase::Reflect(m_serializeContext);
  286. // Create database
  287. Data::AssetManager::Descriptor desc;
  288. Data::AssetManager::Create(desc);
  289. Data::AssetManager::Instance().RegisterHandler(aznew SliceAssetHandler(m_serializeContext), AzTypeInfo<AZ::SliceAsset>::Uuid());
  290. Data::AssetManager::Instance().RegisterHandler(aznew AzFramework::GenericAssetHandler<MockAsset>("Mock Asset", "Other", "mockasset"), AZ::AzTypeInfo<MockAsset>::Uuid());
  291. m_catalog.reset(aznew SliceBuilderTest_MockCatalog());
  292. AssetManager::Instance().RegisterCatalog(m_catalog.get(), AzTypeInfo<AZ::SliceAsset>::Uuid());
  293. }
  294. void TearDown() override
  295. {
  296. m_catalog->DisableCatalog();
  297. AZ::Interface<AZ::ComponentApplicationRequests>::Unregister(this);
  298. ComponentApplicationBus::Handler::BusDisconnect();
  299. Data::AssetManager::Destroy();
  300. m_catalog.reset();
  301. delete m_mockSimpleAssetDescriptor;
  302. delete m_mockAssetDescriptor;
  303. delete m_sliceDescriptor;
  304. delete m_serializeContext;
  305. LeakDetectionFixture::TearDown();
  306. }
  307. void VerifyDependency(AZ::Data::Asset<SliceAsset>& sliceAsset, AZ::Data::AssetId mockAssetId)
  308. {
  309. AZ::PlatformTagSet platformTags;
  310. AZ::Data::Asset<SliceAsset> exportSliceAsset;
  311. AZStd::shared_ptr<AZ::Data::AssetDataStream> assetDataStream = AZStd::make_shared<AZ::Data::AssetDataStream>();
  312. // Save the slice asset into a memory buffer, then hand ownership of the buffer to assetDataStream
  313. {
  314. AZ::SliceAssetHandler assetHandler;
  315. assetHandler.SetSerializeContext(nullptr);
  316. AZStd::vector<AZ::u8> charBuffer;
  317. AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8>> charStream(&charBuffer);
  318. assetHandler.SaveAssetData(sliceAsset, &charStream);
  319. assetDataStream->Open(AZStd::move(charBuffer));
  320. }
  321. bool result = SliceBuilderWorker::GetCompiledSliceAsset(assetDataStream, "MockAsset.slice", platformTags, exportSliceAsset);
  322. ASSERT_TRUE(result);
  323. AssetBuilderSDK::JobProduct jobProduct;
  324. ASSERT_TRUE(SliceBuilderWorker::OutputSliceJob(exportSliceAsset, "test.slice", jobProduct));
  325. ASSERT_EQ(jobProduct.m_dependencies.size(), 1);
  326. ASSERT_EQ(jobProduct.m_dependencies[0].m_dependencyId, mockAssetId);
  327. }
  328. void BuildSliceWithSimpleAssetReference(
  329. const char* simpleAssetPath,
  330. AZStd::vector<AssetBuilderSDK::ProductDependency>& productDependencies,
  331. AssetBuilderSDK::ProductPathDependencySet& productPathDependencies)
  332. {
  333. auto* assetComponent = aznew SliceBuilder::MockSimpleSliceAssetRefComponent;
  334. assetComponent->m_asset.SetAssetPath(simpleAssetPath);
  335. auto sliceAsset = AZ::Test::CreateSliceFromComponent(assetComponent, m_catalog->GenerateMockAssetId());
  336. AZ::SliceAssetHandler assetHandler;
  337. assetHandler.SetSerializeContext(nullptr);
  338. AZStd::shared_ptr<AZ::Data::AssetDataStream> assetDataStream = AZStd::make_shared<AZ::Data::AssetDataStream>();
  339. // Save the slice asset into a memory buffer, then hand ownership of the buffer to assetDataStream
  340. {
  341. AZStd::vector<AZ::u8> charBuffer;
  342. AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8>> charStream(&charBuffer);
  343. assetHandler.SaveAssetData(sliceAsset, &charStream);
  344. assetDataStream->Open(AZStd::move(charBuffer));
  345. }
  346. AZ::PlatformTagSet platformTags;
  347. AZ::Data::Asset<SliceAsset> exportSliceAsset;
  348. bool result = SliceBuilderWorker::GetCompiledSliceAsset(assetDataStream, "MockAsset.slice", platformTags, exportSliceAsset);
  349. ASSERT_TRUE(result);
  350. AssetBuilderSDK::JobProduct jobProduct;
  351. ASSERT_TRUE(SliceBuilderWorker::OutputSliceJob(exportSliceAsset, "test.slice", jobProduct));
  352. productDependencies = AZStd::move(jobProduct.m_dependencies);
  353. productPathDependencies = AZStd::move(jobProduct.m_pathDependencies);
  354. }
  355. SerializeContext* m_serializeContext;
  356. ComponentDescriptor* m_sliceDescriptor;
  357. ComponentDescriptor* m_mockAssetDescriptor;
  358. ComponentDescriptor* m_mockSimpleAssetDescriptor;
  359. AZStd::unique_ptr<SliceBuilderTest_MockCatalog> m_catalog;
  360. };
  361. TEST_F(DependencyTest, SimpleSliceTest)
  362. {
  363. // Test a slice containing a component that references an asset
  364. // Should return a dependency on the asset
  365. auto* assetComponent = aznew MockAssetRefComponent;
  366. AZ::Data::AssetId mockAssetId(AZ::Uuid::CreateRandom(), 0);
  367. assetComponent->m_asset = Data::AssetManager::Instance().CreateAsset<MockAsset>(mockAssetId, AZ::Data::AssetLoadBehavior::Default);
  368. auto sliceAsset = AZ::Test::CreateSliceFromComponent(assetComponent, m_catalog->GenerateMockAssetId());
  369. VerifyDependency(sliceAsset, mockAssetId);
  370. }
  371. TEST_F(DependencyTest, NestedSliceTest)
  372. {
  373. // Test a slice that references another slice, which contains a reference to an asset.
  374. // Should return only a dependency on the asset, and not the inner slice
  375. auto* outerSliceEntity = aznew AZ::Entity;
  376. auto* assetComponent = aznew MockAssetRefComponent;
  377. AZ::Data::AssetId mockAssetId(m_catalog->GenerateMockAssetId());
  378. assetComponent->m_asset = Data::AssetManager::Instance().CreateAsset<MockAsset>(mockAssetId, AZ::Data::AssetLoadBehavior::Default);
  379. auto innerSliceAsset = AZ::Test::CreateSliceFromComponent(assetComponent, m_catalog->GenerateMockAssetId());
  380. AZ::Data::AssetId outerSliceAssetId(m_catalog->GenerateMockAssetId());
  381. auto outerSliceAsset = Data::AssetManager::Instance().CreateAsset<AZ::SliceAsset>(outerSliceAssetId, AZ::Data::AssetLoadBehavior::Default);
  382. AZ::SliceComponent* outerSlice = outerSliceEntity->CreateComponent<AZ::SliceComponent>();
  383. outerSlice->SetIsDynamic(true);
  384. outerSliceAsset.Get()->SetData(outerSliceEntity, outerSlice);
  385. outerSlice->AddSlice(innerSliceAsset);
  386. VerifyDependency(outerSliceAsset, mockAssetId);
  387. }
  388. TEST_F(DependencyTest, DataPatchTest)
  389. {
  390. // Test a slice that references another slice, with the outer slice being data-patched to have a reference to an asset
  391. // Should return a dependency on the asset, but not the inner slice
  392. auto* outerSliceEntity = aznew AZ::Entity;
  393. auto* assetComponent = aznew MockAssetRefComponent;
  394. AZ::Data::AssetId outerSliceAssetId(m_catalog->GenerateMockAssetId());
  395. auto outerSliceAsset = Data::AssetManager::Instance().CreateAsset<AZ::SliceAsset>(outerSliceAssetId, AZ::Data::AssetLoadBehavior::Default);
  396. auto innerSliceAsset = AZ::Test::CreateSliceFromComponent(nullptr, m_catalog->GenerateMockAssetId());
  397. AZ::SliceComponent* outerSlice = outerSliceEntity->CreateComponent<AZ::SliceComponent>();
  398. outerSlice->SetIsDynamic(true);
  399. outerSliceAsset.Get()->SetData(outerSliceEntity, outerSlice);
  400. outerSlice->AddSlice(innerSliceAsset);
  401. outerSlice->Instantiate();
  402. auto* sliceRef = outerSlice->GetSlice(innerSliceAsset);
  403. auto& instances = sliceRef->GetInstances();
  404. AZ::Data::AssetId mockAssetId(m_catalog->GenerateMockAssetId());
  405. assetComponent->m_asset = Data::AssetManager::Instance().CreateAsset<MockAsset>(mockAssetId, AZ::Data::AssetLoadBehavior::Default);
  406. for (const AZ::SliceComponent::SliceInstance& i : instances)
  407. {
  408. const AZ::SliceComponent::InstantiatedContainer* container = i.GetInstantiated();
  409. container->m_entities[0]->AddComponent(assetComponent);
  410. sliceRef->ComputeDataPatch();
  411. }
  412. VerifyDependency(outerSliceAsset, mockAssetId);
  413. delete assetComponent;
  414. }
  415. TEST_F(DependencyTest, DynamicAssetReferenceTest)
  416. {
  417. // Test a slice that has a component which synthesizes an asset reference at runtime
  418. // Should return a dependency on the asset
  419. auto* assetComponent = aznew MockEditorComponent;
  420. AZ::Data::AssetId mockAssetId(AZ::Uuid::CreateRandom(), 0);
  421. assetComponent->m_uuid = mockAssetId.m_guid;
  422. auto sliceAsset = AZ::Test::CreateSliceFromComponent(assetComponent, m_catalog->GenerateMockAssetId());
  423. VerifyDependency(sliceAsset, mockAssetId);
  424. }
  425. TEST_F(DependencyTest, Slice_HasPopulatedSimpleAssetReference_HasCorrectProductDependency)
  426. {
  427. // Test a slice containing a component with a simple asset reference
  428. // Should return a path dependency
  429. AZStd::vector<AssetBuilderSDK::ProductDependency> productDependencies;
  430. AssetBuilderSDK::ProductPathDependencySet productPathDependencySet;
  431. constexpr char testPath[] = "some/test/path.txt";
  432. BuildSliceWithSimpleAssetReference(testPath, productDependencies, productPathDependencySet);
  433. ASSERT_EQ(productDependencies.size(), 0);
  434. ASSERT_EQ(productPathDependencySet.size(), 1);
  435. auto& dependency = *productPathDependencySet.begin();
  436. ASSERT_STREQ(dependency.m_dependencyPath.c_str(), testPath);
  437. }
  438. TEST_F(DependencyTest, Slice_HasEmptySimpleAssetReference_HasNoProductDependency)
  439. {
  440. // Test a slice containing a component with an empty simple asset reference
  441. // Should not return a path dependency
  442. AZStd::vector<AssetBuilderSDK::ProductDependency> productDependencies;
  443. AssetBuilderSDK::ProductPathDependencySet productPathDependencySet;
  444. BuildSliceWithSimpleAssetReference("", productDependencies, productPathDependencySet);
  445. ASSERT_EQ(productDependencies.size(), 0);
  446. ASSERT_EQ(productPathDependencySet.size(), 0);
  447. }
  448. struct ServiceTestComponent
  449. : public AZ::Component
  450. {
  451. AZ_COMPONENT(ServiceTestComponent, "{CBC4FCB6-FFD2-4097-844D-A01B09042DF4}");
  452. static void Reflect(ReflectContext* reflection)
  453. {
  454. SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(reflection);
  455. if (serializeContext)
  456. {
  457. serializeContext->Class<ServiceTestComponent, AZ::Component>()
  458. ->Field("field", &ServiceTestComponent::m_field);
  459. }
  460. }
  461. static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  462. {
  463. if (m_enableServiceDependency)
  464. {
  465. required.push_back(AZ_CRC_CE("SomeService"));
  466. }
  467. }
  468. void Activate() override {}
  469. void Deactivate() override {}
  470. int m_field{};
  471. static bool m_enableServiceDependency;
  472. };
  473. bool ServiceTestComponent::m_enableServiceDependency = false;
  474. TEST_F(DependencyTest, SliceFingerprint_ChangesWhenComponentServicesChange)
  475. {
  476. using namespace AzToolsFramework::Fingerprinting;
  477. AZStd::unique_ptr<ComponentDescriptor> descriptor(ServiceTestComponent::CreateDescriptor());
  478. descriptor->Reflect(m_serializeContext);
  479. auto* assetComponent = aznew ServiceTestComponent;
  480. auto sliceAsset = AZ::Test::CreateSliceFromComponent(assetComponent, m_catalog->GenerateMockAssetId());
  481. SliceComponent* sourcePrefab = sliceAsset.Get() ? sliceAsset.Get()->GetComponent() : nullptr;
  482. TypeFingerprint fingerprintNoService, fingerprintWithService;
  483. {
  484. TypeFingerprinter fingerprinter(*m_serializeContext);
  485. fingerprintNoService = fingerprinter.GenerateFingerprintForAllTypesInObject(sourcePrefab);
  486. }
  487. ServiceTestComponent::m_enableServiceDependency = true;
  488. {
  489. TypeFingerprinter fingerprinter(*m_serializeContext);
  490. fingerprintWithService = fingerprinter.GenerateFingerprintForAllTypesInObject(sourcePrefab);
  491. }
  492. ASSERT_NE(fingerprintNoService, fingerprintWithService);
  493. ServiceTestComponent::m_enableServiceDependency = false;
  494. {
  495. // Check again to make sure the fingerprint is stable
  496. TypeFingerprinter fingerprinter(*m_serializeContext);
  497. TypeFingerprint fingerprintNoServiceDoubleCheck = fingerprinter.GenerateFingerprintForAllTypesInObject(sourcePrefab);
  498. ASSERT_EQ(fingerprintNoService, fingerprintNoServiceDoubleCheck);
  499. }
  500. }
  501. struct BuilderRegisterListener : AssetBuilderSDK::AssetBuilderBus::Handler
  502. {
  503. BuilderRegisterListener()
  504. {
  505. BusConnect();
  506. }
  507. ~BuilderRegisterListener()
  508. {
  509. BusDisconnect();
  510. }
  511. void RegisterBuilderInformation(const AssetBuilderSDK::AssetBuilderDesc& desc) override
  512. {
  513. m_desc = desc;
  514. }
  515. AssetBuilderSDK::AssetBuilderDesc m_desc;
  516. };
  517. TEST_F(DependencyTest, SliceBuilderFingerprint_ChangesWhenNestedTypeChanges)
  518. {
  519. BuilderRegisterListener listener;
  520. AZStd::string fingerprintA, fingerprintB;
  521. auto* descriptor = MockComponent::CreateDescriptor();
  522. descriptor->Reflect(m_serializeContext);
  523. MockSubType::Reflect(m_serializeContext);
  524. {
  525. BuilderPluginComponent builder;
  526. builder.Activate();
  527. fingerprintA = listener.m_desc.m_analysisFingerprint;
  528. }
  529. // Unreflect the sub type, change the version, and reflect again
  530. m_serializeContext->EnableRemoveReflection();
  531. MockSubType::Reflect(m_serializeContext);
  532. m_serializeContext->DisableRemoveReflection();
  533. MockSubType::m_version = 2;
  534. MockSubType::Reflect(m_serializeContext);
  535. {
  536. BuilderPluginComponent builder;
  537. builder.Activate();
  538. fingerprintB = listener.m_desc.m_analysisFingerprint;
  539. }
  540. delete descriptor;
  541. EXPECT_STRNE(fingerprintA.c_str(), fingerprintB.c_str());
  542. }
  543. }