SliceUpgradeTests.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  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 <AzCore/PlatformDef.h>
  9. AZ_PUSH_DISABLE_WARNING(,"-Wdelete-non-virtual-dtor")
  10. #include <AzCore/Asset/AssetManager.h>
  11. #include <AzCore/Memory/PoolAllocator.h>
  12. #include <AzCore/IO/FileIO.h>
  13. #include <AzCore/IO/Streamer/Streamer.h>
  14. #include <AzCore/IO/Streamer/StreamerComponent.h>
  15. #include <AzCore/IO/SystemFile.h>
  16. #include <AzCore/Serialization/Utils.h>
  17. #include <AzCore/Slice/SliceComponent.h>
  18. #include <AzCore/Slice/SliceMetadataInfoComponent.h>
  19. #include <AzCore/Slice/SliceAssetHandler.h>
  20. #include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
  21. #include <CustomSerializeContextTestFixture.h>
  22. #include "SliceUpgradeTestsData.h"
  23. namespace UnitTest
  24. {
  25. class SliceUpgradeTest_MockCatalog final
  26. : public AZ::Data::AssetCatalog
  27. , public AZ::Data::AssetCatalogRequestBus::Handler
  28. {
  29. public:
  30. AZ_CLASS_ALLOCATOR(SliceUpgradeTest_MockCatalog, AZ::SystemAllocator);
  31. SliceUpgradeTest_MockCatalog()
  32. {
  33. AZ::Data::AssetCatalogRequestBus::Handler::BusConnect();
  34. }
  35. ~SliceUpgradeTest_MockCatalog() override
  36. {
  37. AZ::Data::AssetCatalogRequestBus::Handler::BusDisconnect();
  38. DisableCatalog();
  39. }
  40. //////////////////////////////////////////////////////////////////////////
  41. // AssetCatalogRequestBus
  42. AZ::Data::AssetInfo GetAssetInfoById(const AZ::Data::AssetId& id) override
  43. {
  44. AZ::Data::AssetInfo result;
  45. auto itr = m_assetInfoMap.find(id);
  46. if (itr != m_assetInfoMap.end())
  47. {
  48. result = itr->second;
  49. }
  50. return result;
  51. }
  52. //////////////////////////////////////////////////////////////////////////
  53. const AZ::Data::AssetInfo& GenerateSliceAssetInfo(AZ::Data::AssetId assetId, const char* assetHintName = "datapatch_test.slice")
  54. {
  55. EXPECT_TRUE(assetId.IsValid());
  56. AZ::Data::AssetInfo& assetInfo = m_assetInfoMap[assetId];
  57. assetInfo.m_assetId = assetId;
  58. assetInfo.m_assetType = AZ::AzTypeInfo<AZ::SliceAsset>::Uuid();
  59. assetInfo.m_relativePath = AZStd::string::format("%s-%s", assetId.ToString<AZStd::string>().c_str(), assetHintName);
  60. return assetInfo;
  61. }
  62. AZ::Data::AssetStreamInfo GetStreamInfoForLoad(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType) override
  63. {
  64. EXPECT_EQ(assetType, AZ::AzTypeInfo<AZ::SliceAsset>::Uuid());
  65. AZ::Data::AssetStreamInfo info;
  66. info.m_streamFlags = AZ::IO::OpenMode::ModeRead;
  67. auto assetInfoItr = m_assetInfoMap.find(assetId);
  68. if (assetInfoItr != m_assetInfoMap.end())
  69. {
  70. info.m_streamName = assetInfoItr->second.m_relativePath;
  71. }
  72. if (!info.m_streamName.empty())
  73. {
  74. info.m_dataLen = static_cast<size_t>(AZ::IO::SystemFile::Length(info.m_streamName.c_str()));
  75. }
  76. return info;
  77. }
  78. AZ::Data::AssetStreamInfo GetStreamInfoForSave(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType) override
  79. {
  80. AZ::Data::AssetStreamInfo info;
  81. info = GetStreamInfoForLoad(assetId, assetType);
  82. info.m_streamFlags = AZ::IO::OpenMode::ModeWrite;
  83. return info;
  84. }
  85. private:
  86. AZStd::unordered_map<AZ::Data::AssetId, AZ::Data::AssetInfo> m_assetInfoMap;
  87. };
  88. class SliceUpgradeTest : public CustomSerializeContextTestFixture
  89. {
  90. protected:
  91. AZStd::unique_ptr<AZ::ComponentDescriptor> m_sliceDescriptor;
  92. AZStd::unique_ptr<SliceUpgradeTest_MockCatalog> m_mockCatalog;
  93. AZStd::unique_ptr<AZ::IO::Streamer> m_streamer;
  94. AZStd::unique_ptr<AZ::SliceComponent> m_rootSliceComponent;
  95. AZStd::unordered_map<AZ::Data::AssetId, AZ::Data::Asset<AZ::SliceAsset>> m_sliceAssets;
  96. AZStd::unordered_map<AZ::Data::AssetId, AZStd::vector<char>> m_sliceStreams;
  97. public:
  98. void SetUp() override
  99. {
  100. CustomSerializeContextTestFixture::SetUp();
  101. m_streamer = AZStd::make_unique<AZ::IO::Streamer>(AZStd::thread_desc{}, AZ::StreamerComponent::CreateStreamerStack());
  102. AZ::Interface<AZ::IO::IStreamer>::Register(m_streamer.get());
  103. m_sliceDescriptor.reset(AZ::SliceComponent::CreateDescriptor());
  104. m_sliceDescriptor->Reflect(m_serializeContext.get());
  105. AZ::SliceMetadataInfoComponent::Reflect(m_serializeContext.get());
  106. AzFramework::SimpleAssetReferenceBase::Reflect(m_serializeContext.get());
  107. AZ::Entity::Reflect(m_serializeContext.get());
  108. AZ::DataPatch::Reflect(m_serializeContext.get());
  109. AZ::Data::AssetManager::Descriptor desc;
  110. AZ::Data::AssetManager::Create(desc);
  111. AZ::Data::AssetManager::Instance().RegisterHandler(aznew AZ::SliceAssetHandler(m_serializeContext.get()), AZ::AzTypeInfo<AZ::SliceAsset>::Uuid());
  112. m_mockCatalog.reset(aznew SliceUpgradeTest_MockCatalog());
  113. AZ::Data::AssetManager::Instance().RegisterCatalog(m_mockCatalog.get(), AZ::AzTypeInfo<AZ::SliceAsset>::Uuid());
  114. m_rootSliceComponent.reset(aznew AZ::SliceComponent);
  115. m_rootSliceComponent->Instantiate();
  116. }
  117. void TearDown() override
  118. {
  119. m_rootSliceComponent.reset();
  120. {
  121. AZStd::unordered_map<AZ::Data::AssetId, AZ::Data::Asset<AZ::SliceAsset>> clean_sliceAssets;
  122. m_sliceAssets.swap(clean_sliceAssets);
  123. AZStd::unordered_map<AZ::Data::AssetId, AZStd::vector<char>> clean_sliceStreams;
  124. m_sliceStreams.swap(clean_sliceStreams);
  125. }
  126. m_mockCatalog.reset();
  127. AZ::Data::AssetManager::Destroy();
  128. m_sliceDescriptor.reset();
  129. m_serializeContext.reset();
  130. AZ::Interface<AZ::IO::IStreamer>::Unregister(m_streamer.get());
  131. m_streamer.reset();
  132. CustomSerializeContextTestFixture::TearDown();
  133. }
  134. void SaveSliceAssetToStream(AZ::Data::AssetId sliceAssetId)
  135. {
  136. auto sliceAssetItr = m_sliceAssets.find(sliceAssetId);
  137. ASSERT_NE(sliceAssetItr, m_sliceAssets.end());
  138. AZ::Entity* sliceAssetEntity = sliceAssetItr->second.GetAs<AZ::SliceAsset>()->GetEntity();
  139. AZStd::vector<char>& buf = m_sliceStreams[sliceAssetId];
  140. buf.clear();
  141. AZ::IO::ByteContainerStream<AZStd::vector<char>> stream(&buf);
  142. AZ::ObjectStream* objStream = AZ::ObjectStream::Create(&stream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  143. objStream->WriteClass(sliceAssetEntity);
  144. EXPECT_TRUE(objStream->Finalize());
  145. }
  146. void SaveRawSliceAssetXML(AZ::Data::AssetId sliceAssetId, const char* sliceStr, size_t sliceStrSize)
  147. {
  148. // Create empty slice asset placeholder which will be filled.
  149. const AZ::Data::AssetInfo& assetInfo = m_mockCatalog->GenerateSliceAssetInfo(sliceAssetId);
  150. AZ::Data::Asset<AZ::SliceAsset> sliceAssetHolder =
  151. AZ::Data::AssetManager::Instance().CreateAsset<AZ::SliceAsset>(assetInfo.m_assetId, AZ::Data::AssetLoadBehavior::Default);
  152. m_sliceAssets.emplace(assetInfo.m_assetId, sliceAssetHolder);
  153. AZStd::vector<char>& buf = m_sliceStreams[sliceAssetId];
  154. buf.resize_no_construct(sliceStrSize);
  155. memcpy(buf.data(), sliceStr, sliceStrSize);
  156. }
  157. /**
  158. * We "simulate" slice operations by doing everything without involving disk operations.
  159. *
  160. * If the argument `entity` is NOT from an existing slice instance, SaveAsSlice transfers
  161. * the ownership of `entity` to the newly created slice asset, so don't use or delete it
  162. * after calling SaveAsSlice.
  163. */
  164. AZ::Data::AssetId SaveAsSlice(AZ::Entity* entity, const AZ::Uuid& newAssetUuid = AZ::Uuid::CreateRandom(), const char* assetHintName = "datapatch_test.slice")
  165. {
  166. AZ::Entity* sliceEntity = aznew AZ::Entity();
  167. AZ::SliceComponent* sliceComponent = nullptr;
  168. AZ::SliceComponent::SliceInstanceAddress sliceInstAddress = m_rootSliceComponent->FindSlice(entity);
  169. if (sliceInstAddress.IsValid())
  170. {
  171. AZ::SliceComponent* tempSliceComponent = aznew AZ::SliceComponent();
  172. // borrow the slice instance for making nested slice
  173. sliceInstAddress = tempSliceComponent->AddSliceInstance(sliceInstAddress.GetReference(), sliceInstAddress.GetInstance());
  174. AZ::SliceComponent::SliceInstanceToSliceInstanceMap sourceToCloneSliceInstanceMap;
  175. sliceComponent = tempSliceComponent->Clone(*m_serializeContext, &sourceToCloneSliceInstanceMap);
  176. // return the slice instance back
  177. m_rootSliceComponent->AddSliceInstance(sliceInstAddress.GetReference(), sliceInstAddress.GetInstance());
  178. delete tempSliceComponent;
  179. }
  180. else
  181. {
  182. sliceComponent = aznew AZ::SliceComponent();
  183. sliceComponent->SetSerializeContext(m_serializeContext.get());
  184. sliceComponent->AddEntity(entity);
  185. }
  186. sliceComponent->SetSerializeContext(m_serializeContext.get());
  187. sliceEntity->AddComponent(sliceComponent);
  188. sliceEntity->Init();
  189. sliceEntity->Activate();
  190. const AZ::Data::AssetInfo& assetInfo = m_mockCatalog->GenerateSliceAssetInfo(AZ::Data::AssetId(newAssetUuid, 1), assetHintName);
  191. AZ::Data::Asset<AZ::SliceAsset> sliceAssetHolder =
  192. AZ::Data::AssetManager::Instance().CreateAsset<AZ::SliceAsset>(assetInfo.m_assetId, AZ::Data::AssetLoadBehavior::Default);
  193. sliceAssetHolder.GetAs<AZ::SliceAsset>()->SetData(sliceEntity, sliceComponent);
  194. // Hold on to sliceAssetHolder so it's not ref-counted away.
  195. m_sliceAssets.emplace(assetInfo.m_assetId, sliceAssetHolder);
  196. // Serialize the slice to a stream, so later we can de-serialize it back with different data versions.
  197. SaveSliceAssetToStream(assetInfo.m_assetId);
  198. return assetInfo.m_assetId;
  199. }
  200. AZ::Entity* InstantiateSlice(AZ::Data::AssetId sliceAssetId)
  201. {
  202. auto sliceAssetItr = m_sliceAssets.find(sliceAssetId);
  203. EXPECT_NE(sliceAssetItr, m_sliceAssets.end());
  204. AZ::SliceComponent::SliceInstanceAddress sliceInstAddress = m_rootSliceComponent->AddSlice(sliceAssetItr->second);
  205. m_rootSliceComponent->Instantiate();
  206. const AZ::SliceComponent::InstantiatedContainer* entityContainer = sliceInstAddress.GetInstance()->GetInstantiated();
  207. // For convenience reason, only single entity slices are allowed for now.
  208. EXPECT_EQ(entityContainer->m_entities.size(), 1);
  209. return entityContainer->m_entities[0];
  210. }
  211. void ReloadSliceAssetFromStream(AZ::Data::AssetId sliceAssetId)
  212. {
  213. auto sliceAssetItr = m_sliceAssets.find(sliceAssetId);
  214. ASSERT_NE(sliceAssetItr, m_sliceAssets.end());
  215. auto sliceStreamItr = m_sliceStreams.find(sliceAssetId);
  216. ASSERT_NE(sliceStreamItr, m_sliceStreams.end());
  217. AZ::IO::ByteContainerStream<AZStd::vector<char>> stream(&sliceStreamItr->second);
  218. stream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  219. AZ::Entity* newSliceAssetEntity = AZ::Utils::LoadObjectFromStream<AZ::Entity>(stream, m_serializeContext.get());
  220. ASSERT_NE(newSliceAssetEntity, nullptr);
  221. AZ::SliceComponent* newSliceAssetComponent = newSliceAssetEntity->FindComponent<AZ::SliceComponent>();
  222. ASSERT_NE(newSliceAssetComponent, nullptr);
  223. newSliceAssetComponent->SetSerializeContext(m_serializeContext.get());
  224. sliceAssetItr->second.GetAs<AZ::SliceAsset>()->SetData(newSliceAssetEntity, newSliceAssetComponent);
  225. }
  226. };
  227. TEST_F(SliceUpgradeTest, IntermmediateDataTypeChange)
  228. {
  229. TestDataA::Reflect(m_serializeContext.get());
  230. AzToolsFramework::Components::EditorComponentBase::Reflect(m_serializeContext.get());
  231. TestComponentA_V0::Reflect(m_serializeContext.get());
  232. AZ::Entity* entityA = aznew AZ::Entity();
  233. TestComponentA_V0* component = entityA->CreateComponent<TestComponentA_V0>();
  234. component->m_data.m_val = TestDataA_ExpectedVal;
  235. AZ::Data::AssetId sliceAssetId = SaveAsSlice(entityA);
  236. entityA = nullptr;
  237. AZ::Entity* instantiatedSliceEntity0 = InstantiateSlice(sliceAssetId);
  238. TestComponentA_V0* testComponentA = instantiatedSliceEntity0->FindComponent<TestComponentA_V0>();
  239. AZ_TEST_ASSERT(testComponentA != nullptr);
  240. AZ_TEST_ASSERT(testComponentA->m_data.m_val == TestDataA_ExpectedVal);
  241. const float TestDataA_OverrideVal = 2.5f;
  242. // Create a nested slice with overridding value.
  243. testComponentA->m_data.m_val = TestDataA_OverrideVal;
  244. AZ::Data::AssetId nestedSliceAssetId = SaveAsSlice(instantiatedSliceEntity0);
  245. m_rootSliceComponent->RemoveEntity(instantiatedSliceEntity0, true, true);
  246. instantiatedSliceEntity0 = nullptr;
  247. AZ::Entity* instantiatedNestedSliceEntity0 = InstantiateSlice(nestedSliceAssetId);
  248. testComponentA = instantiatedNestedSliceEntity0->FindComponent<TestComponentA_V0>();
  249. AZ_TEST_ASSERT(testComponentA->m_data.m_val == TestDataA_OverrideVal);
  250. m_rootSliceComponent->RemoveEntity(instantiatedNestedSliceEntity0, true, true);
  251. instantiatedNestedSliceEntity0 = nullptr;
  252. // Replace TestComponentA_V0 in Serialization context with TestComponentA_V1.
  253. m_serializeContext->EnableRemoveReflection();
  254. TestComponentA_V0::Reflect(m_serializeContext.get());
  255. m_serializeContext->DisableRemoveReflection();
  256. NewTestDataA::Reflect(m_serializeContext.get());
  257. TestComponentA_V1::Reflect(m_serializeContext.get());
  258. ReloadSliceAssetFromStream(nestedSliceAssetId);
  259. instantiatedNestedSliceEntity0 = InstantiateSlice(nestedSliceAssetId);
  260. TestComponentA_V1* testComponentA_V1 = instantiatedNestedSliceEntity0->FindComponent<TestComponentA_V1>();
  261. AZ_TEST_ASSERT(testComponentA_V1 != nullptr);
  262. EXPECT_EQ(testComponentA_V1->m_data.m_val, TestDataA_OverrideVal);
  263. }
  264. TEST_F(SliceUpgradeTest, TypeChangeInUnorderedMap)
  265. {
  266. TestDataB_V0::Reflect(m_serializeContext.get());
  267. AzToolsFramework::Components::EditorComponentBase::Reflect(m_serializeContext.get());
  268. TestComponentB_V0::Reflect(m_serializeContext.get());
  269. AZ::Entity* entityA = aznew AZ::Entity();
  270. TestComponentB_V0* componentB = entityA->CreateComponent<TestComponentB_V0>();
  271. componentB->m_unorderedMap.emplace(17, TestDataB_V0(17));
  272. componentB->m_unorderedMap.emplace(29, TestDataB_V0(29));
  273. componentB->m_unorderedMap.emplace(37, TestDataB_V0(37));
  274. AZ::Data::AssetId sliceAssetId = SaveAsSlice(entityA);
  275. entityA = nullptr;
  276. componentB = nullptr;
  277. AZ::Entity* instantiatedSliceEntity0 = InstantiateSlice(sliceAssetId);
  278. componentB = instantiatedSliceEntity0->FindComponent<TestComponentB_V0>();
  279. ASSERT_NE(componentB, nullptr);
  280. EXPECT_EQ(componentB->m_unorderedMap.size(), 3);
  281. auto foundItr = componentB->m_unorderedMap.find(17);
  282. EXPECT_NE(foundItr, componentB->m_unorderedMap.end());
  283. EXPECT_EQ(foundItr->second.m_data, 17);
  284. foundItr = componentB->m_unorderedMap.find(29);
  285. EXPECT_NE(foundItr, componentB->m_unorderedMap.end());
  286. EXPECT_EQ(foundItr->second.m_data, 29);
  287. foundItr = componentB->m_unorderedMap.find(37);
  288. EXPECT_NE(foundItr, componentB->m_unorderedMap.end());
  289. EXPECT_EQ(foundItr->second.m_data, 37);
  290. // Creat a nested slice with overridding value.
  291. componentB->m_unorderedMap[29].m_data = 92;
  292. AZ::Data::AssetId nestedSliceAssetId = SaveAsSlice(instantiatedSliceEntity0);
  293. m_rootSliceComponent->RemoveEntity(instantiatedSliceEntity0, true, true);
  294. instantiatedSliceEntity0 = nullptr;
  295. AZ::Entity* instantiatedNestedSliceEntity0 = InstantiateSlice(nestedSliceAssetId);
  296. componentB = instantiatedNestedSliceEntity0->FindComponent<TestComponentB_V0>();
  297. ASSERT_NE(componentB, nullptr);
  298. EXPECT_EQ(componentB->m_unorderedMap.size(), 3);
  299. foundItr = componentB->m_unorderedMap.find(29);
  300. EXPECT_NE(foundItr, componentB->m_unorderedMap.end());
  301. EXPECT_EQ(foundItr->second.m_data, 92);
  302. m_serializeContext->EnableRemoveReflection();
  303. TestComponentB_V0::Reflect(m_serializeContext.get());
  304. TestDataB_V0::Reflect(m_serializeContext.get());
  305. m_serializeContext->DisableRemoveReflection();
  306. TestDataB_V1::Reflect(m_serializeContext.get());
  307. TestComponentB_V0_1::Reflect(m_serializeContext.get());
  308. ReloadSliceAssetFromStream(sliceAssetId);
  309. ReloadSliceAssetFromStream(nestedSliceAssetId);
  310. instantiatedNestedSliceEntity0 = InstantiateSlice(nestedSliceAssetId);
  311. TestComponentB_V0_1* componentB1 = instantiatedNestedSliceEntity0->FindComponent<TestComponentB_V0_1>();
  312. ASSERT_NE(componentB1, nullptr);
  313. EXPECT_EQ(componentB1->m_unorderedMap.size(), 3);
  314. auto foundItr_B1 = componentB1->m_unorderedMap.find(17);
  315. EXPECT_NE(foundItr_B1, componentB1->m_unorderedMap.end());
  316. EXPECT_EQ(foundItr_B1->second.m_info, 30.5f);
  317. foundItr_B1 = componentB1->m_unorderedMap.find(29);
  318. EXPECT_NE(foundItr_B1, componentB1->m_unorderedMap.end());
  319. EXPECT_EQ(foundItr_B1->second.m_info, 105.5f);
  320. foundItr_B1 = componentB1->m_unorderedMap.find(37);
  321. EXPECT_NE(foundItr_B1, componentB1->m_unorderedMap.end());
  322. EXPECT_EQ(foundItr_B1->second.m_info, 50.5f);
  323. }
  324. TEST_F(SliceUpgradeTest, TypeChangeInVector)
  325. {
  326. TestDataB_V0::Reflect(m_serializeContext.get());
  327. AzToolsFramework::Components::EditorComponentBase::Reflect(m_serializeContext.get());
  328. TestComponentC_V0::Reflect(m_serializeContext.get());
  329. AZ::Entity* entityA = aznew AZ::Entity();
  330. TestComponentC_V0* componentC = entityA->CreateComponent<TestComponentC_V0>();
  331. componentC->m_vec.push_back(TestDataB_V0(17));
  332. componentC->m_vec.push_back(TestDataB_V0(29));
  333. componentC->m_vec.push_back(TestDataB_V0(37));
  334. AZ::Data::AssetId sliceAssetId = SaveAsSlice(entityA);
  335. entityA = nullptr;
  336. componentC = nullptr;
  337. AZ::Entity* instantiatedSliceEntity0 = InstantiateSlice(sliceAssetId);
  338. componentC = instantiatedSliceEntity0->FindComponent<TestComponentC_V0>();
  339. ASSERT_NE(componentC, nullptr);
  340. EXPECT_EQ(componentC->m_vec.size(), 3);
  341. EXPECT_EQ(componentC->m_vec[0].m_data, 17);
  342. EXPECT_EQ(componentC->m_vec[1].m_data, 29);
  343. EXPECT_EQ(componentC->m_vec[2].m_data, 37);
  344. // Creat a nested slice with overridding value.
  345. componentC->m_vec[1].m_data = 92;
  346. AZ::Data::AssetId nestedSliceAssetId = SaveAsSlice(instantiatedSliceEntity0);
  347. m_rootSliceComponent->RemoveEntity(instantiatedSliceEntity0, true, true);
  348. instantiatedSliceEntity0 = nullptr;
  349. AZ::Entity* instantiatedNestedSliceEntity0 = InstantiateSlice(nestedSliceAssetId);
  350. componentC = instantiatedNestedSliceEntity0->FindComponent<TestComponentC_V0>();
  351. ASSERT_NE(componentC, nullptr);
  352. EXPECT_EQ(componentC->m_vec.size(), 3);
  353. EXPECT_EQ(componentC->m_vec[1].m_data, 92);
  354. m_serializeContext->EnableRemoveReflection();
  355. TestComponentC_V0::Reflect(m_serializeContext.get());
  356. TestDataB_V0::Reflect(m_serializeContext.get());
  357. m_serializeContext->DisableRemoveReflection();
  358. TestDataB_V1::Reflect(m_serializeContext.get());
  359. TestComponentC_V0_1::Reflect(m_serializeContext.get());
  360. ReloadSliceAssetFromStream(sliceAssetId);
  361. ReloadSliceAssetFromStream(nestedSliceAssetId);
  362. instantiatedNestedSliceEntity0 = InstantiateSlice(nestedSliceAssetId);
  363. TestComponentC_V0_1* componentC1 = instantiatedNestedSliceEntity0->FindComponent<TestComponentC_V0_1>();
  364. ASSERT_NE(componentC1, nullptr);
  365. EXPECT_EQ(componentC1->m_vec.size(), 3);
  366. EXPECT_EQ(componentC1->m_vec[0].m_info, 30.5f);
  367. EXPECT_EQ(componentC1->m_vec[1].m_info, 105.5f);
  368. EXPECT_EQ(componentC1->m_vec[2].m_info, 50.5f);
  369. }
  370. TEST_F(SliceUpgradeTest, UpgradeSkipVersion_TypeChange_FloatToDouble)
  371. {
  372. // 1. Create an entity with a TestComponentE_V4 with the default value for m_data
  373. AzToolsFramework::Components::EditorComponentBase::Reflect(m_serializeContext.get());
  374. TestComponentE_V4::Reflect(m_serializeContext.get());
  375. AZ::Entity* testEntity = aznew AZ::Entity();
  376. TestComponentE_V4* componentEV4 = testEntity->CreateComponent<TestComponentE_V4>();
  377. componentEV4->m_data = V4_DefaultData;
  378. // 2. Create a slice out of our default entity configuration
  379. AZ::Data::AssetId sliceAssetId = SaveAsSlice(testEntity);
  380. // 3. Clean everything up
  381. componentEV4 = nullptr;
  382. testEntity = nullptr;
  383. // 4. Instantiate the slice we just created and verify that it contains default data
  384. AZ::Entity* instantiatedSliceEntity = InstantiateSlice(sliceAssetId);
  385. componentEV4 = instantiatedSliceEntity->FindComponent<TestComponentE_V4>();
  386. ASSERT_NE(componentEV4, nullptr);
  387. EXPECT_FLOAT_EQ(componentEV4->m_data, V4_DefaultData);
  388. // 5. Override the data in our new slice and save it as a nested slice.
  389. componentEV4->m_data = V4_OverrideData;
  390. AZ::Data::AssetId nestedSliceAssetId = SaveAsSlice(instantiatedSliceEntity);
  391. // 6. Clean everything up
  392. m_rootSliceComponent->RemoveEntity(instantiatedSliceEntity, true, true);
  393. componentEV4 = nullptr;
  394. instantiatedSliceEntity = nullptr;
  395. // 7. Instantiate the nested slice we just created and verify that it contains overridden data
  396. instantiatedSliceEntity = InstantiateSlice(nestedSliceAssetId);
  397. componentEV4 = instantiatedSliceEntity->FindComponent<TestComponentE_V4>();
  398. ASSERT_NE(componentEV4, nullptr);
  399. EXPECT_FLOAT_EQ(componentEV4->m_data, V4_OverrideData);
  400. // 8. Clean everything up
  401. m_rootSliceComponent->RemoveEntity(instantiatedSliceEntity, true, true);
  402. componentEV4 = nullptr;
  403. instantiatedSliceEntity = nullptr;
  404. // 9. Remove TestComponentE_V4 from the serialize context and add TestComponentE_V5
  405. m_serializeContext->EnableRemoveReflection();
  406. TestComponentE_V4::Reflect(m_serializeContext.get());
  407. m_serializeContext->DisableRemoveReflection();
  408. TestComponentE_V5::Reflect(m_serializeContext.get());
  409. // 10. Reload our slice assets
  410. ReloadSliceAssetFromStream(sliceAssetId);
  411. ReloadSliceAssetFromStream(nestedSliceAssetId);
  412. // 11. Instantiate our nested slice and verify that the V4->V5 upgrade has
  413. // been applied to the data patch and then patch has been properly applied
  414. instantiatedSliceEntity = InstantiateSlice(nestedSliceAssetId);
  415. TestComponentE_V5* componentEV5 = instantiatedSliceEntity->FindComponent<TestComponentE_V5>();
  416. ASSERT_NE(componentEV5, nullptr);
  417. EXPECT_EQ(componentEV5->m_data, V5_ExpectedData);
  418. // 12. Clean everything up
  419. m_rootSliceComponent->RemoveEntity(instantiatedSliceEntity, true, true);
  420. componentEV5 = nullptr;
  421. instantiatedSliceEntity = nullptr;
  422. // 13. Remove TestComponentE_V5 from the serialize context and add TestComponentE_V6_1
  423. m_serializeContext->EnableRemoveReflection();
  424. TestComponentE_V5::Reflect(m_serializeContext.get());
  425. m_serializeContext->DisableRemoveReflection();
  426. TestComponentE_V6_1::Reflect(m_serializeContext.get());
  427. // 14. Reload our slice assets
  428. ReloadSliceAssetFromStream(sliceAssetId);
  429. ReloadSliceAssetFromStream(nestedSliceAssetId);
  430. // 15. Instantiate our nested slice and verify that the V4->V5 and V5->V6 upgrades have
  431. // been applied to the data patch and then patch has been properly applied
  432. instantiatedSliceEntity = InstantiateSlice(nestedSliceAssetId);
  433. TestComponentE_V6_1* componentEV6_1 = instantiatedSliceEntity->FindComponent<TestComponentE_V6_1>();
  434. ASSERT_NE(componentEV6_1, nullptr);
  435. EXPECT_DOUBLE_EQ(componentEV6_1->m_data, V6_ExpectedData_NoSkip);
  436. // 16. Clean everything up
  437. m_rootSliceComponent->RemoveEntity(instantiatedSliceEntity, true, true);
  438. componentEV6_1 = nullptr;
  439. instantiatedSliceEntity = nullptr;
  440. // 17. Remove TestComponentE_V6_1 from the serialize context and add TestComponentE_V6_2
  441. m_serializeContext->EnableRemoveReflection();
  442. TestComponentE_V6_1::Reflect(m_serializeContext.get());
  443. m_serializeContext->DisableRemoveReflection();
  444. TestComponentE_V6_2::Reflect(m_serializeContext.get());
  445. // 18. Reload our slice assets
  446. ReloadSliceAssetFromStream(sliceAssetId);
  447. ReloadSliceAssetFromStream(nestedSliceAssetId);
  448. // 19. Instantiate our nested slice and verify that the V4->V6 upgrade has
  449. // been applied to the data patch and then patch has been properly applied
  450. instantiatedSliceEntity = InstantiateSlice(nestedSliceAssetId);
  451. TestComponentE_V6_2* componentEV6_2 = instantiatedSliceEntity->FindComponent<TestComponentE_V6_2>();
  452. ASSERT_NE(componentEV6_2, nullptr);
  453. EXPECT_TRUE(AZ::IsClose(componentEV6_2->m_data, V6_ExpectedData_Skip, 0.000001));
  454. // 20. Clean everything up
  455. m_rootSliceComponent->RemoveEntity(instantiatedSliceEntity, true, true);
  456. componentEV6_2 = nullptr;
  457. instantiatedSliceEntity = nullptr;
  458. }
  459. TEST_F(SliceUpgradeTest, TypeChangeTests)
  460. {
  461. // TEST TYPES
  462. SliceUpgradeTestAsset::Reflect(m_serializeContext.get());
  463. AzFramework::SimpleAssetReference<SliceUpgradeTestAsset>::Register(*m_serializeContext.get());
  464. AzToolsFramework::Components::EditorComponentBase::Reflect(m_serializeContext.get());
  465. TestComponentD_V1::Reflect(m_serializeContext.get());
  466. AZ::Entity* entity = aznew AZ::Entity();
  467. entity->CreateComponent<TestComponentD_V1>();
  468. // Supply a specific Asset Guid to help with debugging
  469. AZ::Data::AssetId sliceAssetId = SaveAsSlice(entity, AZ::Uuid{ "{10000000-0000-0000-0000-000000000000}" }, "datapatch_base.slice");
  470. entity = nullptr;
  471. AZ::Entity* instantiatedSliceEntity = InstantiateSlice(sliceAssetId);
  472. TestComponentD_V1* testComponent = instantiatedSliceEntity->FindComponent<TestComponentD_V1>();
  473. ASSERT_NE(testComponent, nullptr);
  474. EXPECT_EQ(testComponent->m_firstData, Value1_Initial);
  475. EXPECT_EQ(testComponent->m_secondData, Value2_Initial);
  476. EXPECT_EQ(testComponent->m_asset, AssetPath_Initial);
  477. // Create a nested slice with overridden data.
  478. testComponent->m_firstData = Value1_Override;
  479. testComponent->m_secondData = Value2_Override;
  480. testComponent->m_asset = AssetPath_Override;
  481. AZ::Data::AssetId nestedSliceAssetId = SaveAsSlice(instantiatedSliceEntity, AZ::Uuid{ "{20000000-0000-0000-0000-000000000000}" }, "datapatch_nested.slice");
  482. m_rootSliceComponent->RemoveEntity(instantiatedSliceEntity, true, true);
  483. instantiatedSliceEntity = nullptr;
  484. AZ::Entity* instantiatedNestedSliceEntity = InstantiateSlice(nestedSliceAssetId);
  485. testComponent = instantiatedNestedSliceEntity->FindComponent<TestComponentD_V1>();
  486. EXPECT_EQ(testComponent->m_firstData, Value1_Override);
  487. EXPECT_EQ(testComponent->m_secondData, Value2_Override);
  488. EXPECT_EQ(testComponent->m_asset, AssetPath_Override);
  489. m_rootSliceComponent->RemoveEntity(instantiatedNestedSliceEntity, true, true);
  490. instantiatedNestedSliceEntity = nullptr;
  491. // Replace TestComponentD_V1 in Serialization context with TestComponentD_V2.
  492. m_serializeContext->EnableRemoveReflection();
  493. TestComponentD_V1::Reflect(m_serializeContext.get());
  494. m_serializeContext->DisableRemoveReflection();
  495. TestComponentD_V2::Reflect(m_serializeContext.get());
  496. ReloadSliceAssetFromStream(sliceAssetId);
  497. ReloadSliceAssetFromStream(nestedSliceAssetId);
  498. instantiatedNestedSliceEntity = InstantiateSlice(nestedSliceAssetId);
  499. TestComponentD_V2* newTestComponent = instantiatedNestedSliceEntity->FindComponent<TestComponentD_V2>();
  500. ASSERT_NE(newTestComponent, nullptr);
  501. EXPECT_EQ(newTestComponent->m_firstData, Value1_Final);
  502. EXPECT_EQ(newTestComponent->m_secondData, Value2_Final);
  503. EXPECT_EQ(newTestComponent->m_asset.GetAssetPath(), AZStd::string(AssetPath_Override));
  504. }
  505. } // namespace UnitTest
  506. AZ_POP_DISABLE_WARNING