VariantSerialization.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  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 <SerializeContextFixture.h>
  9. #include <AzCore/Asset/AssetSerializer.h>
  10. #include <AzCore/std/any.h>
  11. #include <AzCore/std/containers/variant.h>
  12. #include <AzCore/Component/Entity.h>
  13. #include <AzCore/Serialization/Utils.h>
  14. namespace UnitTest
  15. {
  16. class VariantSerializationTest
  17. : public LeakDetectionFixture
  18. {
  19. public:
  20. // We must expose the class for serialization first.
  21. void SetUp() override
  22. {
  23. LeakDetectionFixture::SetUp();
  24. m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
  25. AZ::Entity::Reflect(m_serializeContext.get());
  26. }
  27. void TearDown() override
  28. {
  29. m_serializeContext->EnableRemoveReflection();
  30. AZ::Entity::Reflect(m_serializeContext.get());
  31. m_serializeContext->DisableRemoveReflection();
  32. m_serializeContext.reset();
  33. LeakDetectionFixture::TearDown();
  34. }
  35. protected:
  36. AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
  37. };
  38. struct VariantWrapper
  39. {
  40. AZ_TYPE_INFO(VariantWrapper, "{B086FD5B-1E6F-4CB1-9379-80C35DA3B430}");
  41. AZ_CLASS_ALLOCATOR(VariantWrapper, AZ::SystemAllocator);
  42. static void Reflect(AZ::ReflectContext* context)
  43. {
  44. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  45. {
  46. serializeContext->Class<VariantWrapper>()
  47. ->Field("WrappedField", &VariantWrapper::m_wrappedVariant)
  48. ;
  49. }
  50. }
  51. AZStd::variant<uint64_t>* m_wrappedVariant{};
  52. };
  53. TEST_F(VariantSerializationTest, VariantWithMonostateAlternativeSerializesCorrectly)
  54. {
  55. using TestVariant1 = AZStd::variant<AZStd::monostate>;
  56. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  57. [](AZ::SerializeContext* serializeContext)
  58. {
  59. serializeContext->RegisterGenericType<TestVariant1>();
  60. } });
  61. TestVariant1 testVariant;
  62. AZStd::vector<char> byteBuffer;
  63. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  64. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  65. objStream->WriteClass(&testVariant);
  66. objStream->Finalize();
  67. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  68. TestVariant1 loadVariant;
  69. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadVariant, m_serializeContext.get()));
  70. EXPECT_EQ(testVariant, loadVariant);
  71. }
  72. TEST_F(VariantSerializationTest, VariantWithOneAlternativeSerializesCorrectly)
  73. {
  74. using TestVariant1 = AZStd::variant<AZ::Entity>;
  75. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  76. [](AZ::SerializeContext* serializeContext)
  77. {
  78. serializeContext->RegisterGenericType<TestVariant1>();
  79. }});
  80. TestVariant1 testVariant{ AZ::Entity("Variant") };
  81. AZStd::vector<char> byteBuffer;
  82. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  83. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  84. objStream->WriteClass(&testVariant);
  85. objStream->Finalize();
  86. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  87. TestVariant1 loadVariant;
  88. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadVariant, m_serializeContext.get()));
  89. EXPECT_EQ(testVariant.index(), loadVariant.index());
  90. ASSERT_EQ(0U, testVariant.index());
  91. EXPECT_EQ(AZStd::get<0>(testVariant).GetName(), AZStd::get<0>(loadVariant).GetName());
  92. }
  93. TEST_F(VariantSerializationTest, VariantWithOneAlternativeWhichIsPointerTypeSerializesCorrectly)
  94. {
  95. using TestVariant1 = AZStd::variant<AZ::Entity*>;
  96. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  97. [](AZ::SerializeContext* serializeContext)
  98. {
  99. serializeContext->RegisterGenericType<TestVariant1>();
  100. } });
  101. TestVariant1 testVariant{ aznew AZ::Entity(AZ::EntityId(42), "Variant Pointer") };
  102. AZStd::vector<char> byteBuffer;
  103. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  104. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  105. objStream->WriteClass(&testVariant);
  106. objStream->Finalize();
  107. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  108. TestVariant1 loadVariant;
  109. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadVariant, m_serializeContext.get()));
  110. EXPECT_EQ(testVariant.index(), loadVariant.index());
  111. ASSERT_EQ(0U, testVariant.index());
  112. AZ::Entity* testEntity = AZStd::get<0>(testVariant);
  113. AZ::Entity* loadEntity = AZStd::get<0>(loadVariant);
  114. EXPECT_NE(testEntity, loadEntity);
  115. ASSERT_NE(loadEntity, nullptr);
  116. EXPECT_EQ(testEntity->GetId(), loadEntity->GetId());
  117. EXPECT_EQ(testEntity->GetName(), loadEntity->GetName());
  118. delete testEntity;
  119. delete loadEntity;
  120. AZStd::get<0>(testVariant) = nullptr;
  121. AZStd::get<0>(loadVariant) = nullptr;
  122. }
  123. TEST_F(VariantSerializationTest, MultipleAlternativeSerializesCorrectly)
  124. {
  125. using TestVariant1 = AZStd::variant<int32_t, AZStd::string>;
  126. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  127. [](AZ::SerializeContext* serializeContext)
  128. {
  129. serializeContext->RegisterGenericType<TestVariant1>();
  130. } });
  131. // Store integer in variant and attempt to serialize it out and back in
  132. constexpr int32_t expectedIntValue = 0x85;
  133. TestVariant1 sourceVariant{ expectedIntValue };
  134. TestVariant1 loadIntVariant;
  135. {
  136. AZStd::vector<char> byteBuffer;
  137. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  138. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  139. objStream->WriteClass(&sourceVariant);
  140. objStream->Finalize();
  141. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  142. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadIntVariant, m_serializeContext.get()));
  143. }
  144. EXPECT_EQ(sourceVariant.index(), loadIntVariant.index());
  145. ASSERT_EQ(0U, loadIntVariant.index());
  146. int32_t loadIntValue = AZStd::get<0>(loadIntVariant);
  147. EXPECT_EQ(expectedIntValue, loadIntValue);
  148. // Update source variant with string value and attempt to serialize it out and back in
  149. const AZStd::string expectedStringValue = "Our Dog Food Eats the Dog";
  150. sourceVariant = expectedStringValue;
  151. TestVariant1 loadStringVariant;
  152. {
  153. AZStd::vector<char> byteBuffer;
  154. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  155. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_BINARY);
  156. objStream->WriteClass(&sourceVariant);
  157. objStream->Finalize();
  158. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  159. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadStringVariant, m_serializeContext.get()));
  160. }
  161. EXPECT_EQ(sourceVariant.index(), loadStringVariant.index());
  162. ASSERT_EQ(1U, loadStringVariant.index());
  163. const AZStd::string& loadStringValue = AZStd::get<1>(loadStringVariant);
  164. EXPECT_EQ(expectedStringValue, loadStringValue);
  165. }
  166. TEST_F(VariantSerializationTest, VariantStoringAnyAlternativeSerializesCorrectly)
  167. {
  168. using TestVariant1 = AZStd::variant<AZStd::any>;
  169. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  170. [](AZ::SerializeContext* serializeContext)
  171. {
  172. serializeContext->RegisterGenericType<TestVariant1>();
  173. } });
  174. // Store integer in variant and attempt to serialize it out and back in
  175. constexpr int32_t expectedIntValue = 0x2A;
  176. TestVariant1 sourceVariant{ AZStd::make_any<int32_t>(expectedIntValue) };
  177. AZStd::any& sourceAnyValue = AZStd::get<0>(sourceVariant);
  178. EXPECT_TRUE(sourceAnyValue.is<int32_t>());
  179. int32_t* sourceIntValue = AZStd::any_cast<int32_t>(&sourceAnyValue);
  180. ASSERT_NE(nullptr, sourceIntValue);
  181. EXPECT_EQ(expectedIntValue, *sourceIntValue);
  182. TestVariant1 loadAnyVariant1;
  183. {
  184. AZStd::vector<char> byteBuffer;
  185. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  186. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  187. objStream->WriteClass(&sourceVariant);
  188. objStream->Finalize();
  189. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  190. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadAnyVariant1, m_serializeContext.get()));
  191. }
  192. EXPECT_EQ(sourceVariant.index(), loadAnyVariant1.index());
  193. ASSERT_EQ(0U, loadAnyVariant1.index());
  194. AZStd::any& loadAnyValue = AZStd::get<0>(loadAnyVariant1);
  195. EXPECT_TRUE(loadAnyValue.is<int32_t>());
  196. int32_t* loadIntValue = AZStd::any_cast<int32_t>(&loadAnyValue);
  197. ASSERT_NE(nullptr, loadIntValue);
  198. EXPECT_EQ(expectedIntValue, *loadIntValue);
  199. }
  200. TEST_F(VariantSerializationTest, AnyStoringVariantSavesAlternativeAndLoadsAlternativeCorrectly)
  201. {
  202. using TestVariant1 = AZStd::variant<int32_t>;
  203. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  204. [](AZ::SerializeContext* serializeContext)
  205. {
  206. serializeContext->RegisterGenericType<TestVariant1>();
  207. } });
  208. // Store integer in variant and attempt to serialize it out and back in
  209. constexpr int32_t expectedIntValue = 0170;
  210. AZStd::any sourceAny = AZStd::make_any<TestVariant1>(AZStd::in_place_type_t<int32_t>{}, expectedIntValue);
  211. EXPECT_TRUE(sourceAny.is<TestVariant1>());
  212. TestVariant1* sourceVariantValue = AZStd::any_cast<TestVariant1>(&sourceAny);
  213. ASSERT_NE(nullptr, sourceVariantValue);
  214. EXPECT_EQ(expectedIntValue, AZStd::get<0>(*sourceVariantValue));
  215. AZStd::any loadAny;
  216. {
  217. AZStd::vector<char> byteBuffer;
  218. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  219. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_JSON);
  220. objStream->WriteClass(&sourceAny);
  221. objStream->Finalize();
  222. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  223. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadAny, m_serializeContext.get()));
  224. }
  225. // Due to the Variant Serialization only writing out the alternative to disk and the AZStd::any class
  226. // being only able to determine the type dynamically, the type that is stored in the any is the
  227. // alternative, not the variant
  228. EXPECT_TRUE(loadAny.is<int>());
  229. int* loadIntValue = AZStd::any_cast<int>(&loadAny);
  230. ASSERT_NE(nullptr, loadIntValue);
  231. EXPECT_EQ(expectedIntValue, *loadIntValue);
  232. }
  233. TEST_F(VariantSerializationTest, TypeWhichWrapsVariantSavesAndLoadsCorrectly)
  234. {
  235. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  236. [](AZ::SerializeContext* serializeContext)
  237. {
  238. VariantWrapper::Reflect(serializeContext);
  239. } });
  240. // Store integer in variant and attempt to serialize it out and back in
  241. constexpr int32_t expectedIntValue = 7001;
  242. VariantWrapper saveWrapper;
  243. saveWrapper.m_wrappedVariant = new AZStd::variant<uint64_t>(expectedIntValue);
  244. EXPECT_EQ(expectedIntValue, AZStd::get<0>(*saveWrapper.m_wrappedVariant));
  245. VariantWrapper loadWrapper;
  246. {
  247. AZStd::vector<char> byteBuffer;
  248. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  249. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_JSON);
  250. objStream->WriteClass(&saveWrapper);
  251. objStream->Finalize();
  252. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  253. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadWrapper, m_serializeContext.get()));
  254. }
  255. ASSERT_NE(nullptr, loadWrapper.m_wrappedVariant);
  256. EXPECT_NE(saveWrapper.m_wrappedVariant, loadWrapper.m_wrappedVariant);
  257. ASSERT_EQ(0U, loadWrapper.m_wrappedVariant->index());
  258. EXPECT_EQ(expectedIntValue, AZStd::get<0>(*loadWrapper.m_wrappedVariant));
  259. delete saveWrapper.m_wrappedVariant;
  260. // SerializeCotnext IObjectFactory allocates memory for types without AZClassAllocator using azmalloc
  261. // None of the AZStd::containers implement the AZ_CLASS_ALLOCATOR, so it uses the os allocator by default
  262. azdestroy(loadWrapper.m_wrappedVariant);
  263. }
  264. TEST_F(VariantSerializationTest, VariantStoringVariantSerializesCorrectly)
  265. {
  266. using InnerVariant = AZStd::variant<float, int32_t>;
  267. using VariantCeption = AZStd::variant<bool, InnerVariant, bool>;
  268. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  269. [](AZ::SerializeContext* serializeContext)
  270. {
  271. serializeContext->RegisterGenericType<VariantCeption>();
  272. } });
  273. // Store integer in variant and attempt to serialize it out and back in
  274. constexpr int32_t expectedIntValue = -43;
  275. // Sets the int32_t element of the inner variant
  276. // Therefore the outer variant index should be 1 and the inner variant index should be 1
  277. VariantCeption sourceCeptionVariant{ InnerVariant{expectedIntValue} };
  278. VariantCeption loadCeptionVariant;
  279. {
  280. AZStd::vector<char> byteBuffer;
  281. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  282. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  283. objStream->WriteClass(&sourceCeptionVariant);
  284. objStream->Finalize();
  285. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  286. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadCeptionVariant, m_serializeContext.get()));
  287. }
  288. EXPECT_EQ(sourceCeptionVariant.index(), loadCeptionVariant.index());
  289. ASSERT_EQ(1U, loadCeptionVariant.index());
  290. InnerVariant& innerVariant = AZStd::get<1>(loadCeptionVariant);
  291. EXPECT_EQ(1U, innerVariant.index());
  292. EXPECT_EQ(expectedIntValue, AZStd::get<1>(innerVariant));
  293. }
  294. TEST_F(VariantSerializationTest, SavingVariantWithIntAlternativeCanBeLoadedByVariantWithIntAlternativeAtDifferentIndex)
  295. {
  296. using SaveVariant = AZStd::variant<int32_t>;
  297. using LoadVariant = AZStd::variant<bool, double, const int32_t, int32_t>;
  298. // Store integer in variant and attempt to serialize it out and back in
  299. constexpr int32_t expectedIntValue = 72;
  300. // Sets the int32_t element of the source variant which is the zeroth index
  301. SaveVariant sourceVariant{ expectedIntValue };
  302. AZStd::vector<char> byteBuffer;
  303. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  304. {
  305. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  306. [](AZ::SerializeContext* serializeContext)
  307. {
  308. serializeContext->RegisterGenericType<SaveVariant>();
  309. }}
  310. );
  311. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  312. objStream->WriteClass(&sourceVariant);
  313. objStream->Finalize();
  314. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  315. }
  316. ScopedSerializeContextReflector loadReflector(*m_serializeContext, {
  317. [](AZ::SerializeContext* serializeContext)
  318. {
  319. serializeContext->RegisterGenericType<LoadVariant>();
  320. } }
  321. );
  322. LoadVariant loadVariant;
  323. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadVariant, m_serializeContext.get()));
  324. // Source variant should have different index than loaded variant
  325. EXPECT_EQ(0U, sourceVariant.index());
  326. EXPECT_NE(sourceVariant.index(), loadVariant.index());
  327. // The AZ Serialization system does not distinguish between const and non-const.
  328. // As the LoadVariant type has const int32_t as the 2nd index, it is the alternative that will be loaded
  329. constexpr size_t expectedLoadIndex = 2U;
  330. ASSERT_EQ(expectedLoadIndex, loadVariant.index());
  331. EXPECT_TRUE(AZStd::holds_alternative<const int32_t>(loadVariant));
  332. EXPECT_EQ(AZStd::get<0>(sourceVariant), AZStd::get<expectedLoadIndex>(loadVariant));
  333. }
  334. TEST_F(VariantSerializationTest, SavingVariantWithIntAlternativeAndLoadingToVariantWithInnerVariantPointerSucceeds)
  335. {
  336. using SaveVariant = AZStd::variant<int32_t>;
  337. using LoadVariant = AZStd::variant<bool, AZStd::variant<int32_t>*>;
  338. // Store integer in variant and attempt to serialize it out and back in
  339. constexpr int32_t expectedIntValue = 146;
  340. // Sets the int32_t element of the source variant which is the zeroth index
  341. SaveVariant sourceVariant{ expectedIntValue };
  342. EXPECT_EQ(0U, sourceVariant.index());
  343. AZStd::vector<char> byteBuffer;
  344. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  345. {
  346. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  347. [](AZ::SerializeContext* serializeContext)
  348. {
  349. serializeContext->RegisterGenericType<SaveVariant>();
  350. } }
  351. );
  352. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  353. objStream->WriteClass(&sourceVariant);
  354. objStream->Finalize();
  355. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  356. }
  357. ScopedSerializeContextReflector loadReflector(*m_serializeContext, {
  358. [](AZ::SerializeContext* serializeContext)
  359. {
  360. serializeContext->RegisterGenericType<LoadVariant>();
  361. } }
  362. );
  363. LoadVariant loadVariant;
  364. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadVariant, m_serializeContext.get()));
  365. constexpr size_t expectedLoadIndex = 1U;
  366. ASSERT_EQ(expectedLoadIndex, loadVariant.index());
  367. ASSERT_TRUE(AZStd::holds_alternative<AZStd::variant<int32_t>*>(loadVariant));
  368. AZStd::variant<int32_t>*& innerVariant = AZStd::get<expectedLoadIndex>(loadVariant);
  369. ASSERT_NE(nullptr, innerVariant);
  370. EXPECT_TRUE(AZStd::holds_alternative<int32_t>(*innerVariant));
  371. int32_t* loadInt = AZStd::get_if<int32_t>(innerVariant);
  372. ASSERT_NE(nullptr, loadInt);
  373. EXPECT_EQ(expectedIntValue, *loadInt);
  374. azdestroy(innerVariant);
  375. }
  376. TEST_F(VariantSerializationTest, SavingVariantWithIntAlternativeAndLoadingToVariantWithInnerVariantPointerWhichHasAnIntPointerSucceeds)
  377. {
  378. using SaveVariant = AZStd::variant<int32_t>;
  379. using LoadVariant = AZStd::variant<AZStd::variant<int32_t*>*, double>;
  380. // Store integer in variant and attempt to serialize it out and back in
  381. constexpr int32_t expectedIntValue = 146;
  382. // Sets the int32_t element of the source variant which is the zeroth index
  383. SaveVariant sourceVariant{ expectedIntValue };
  384. EXPECT_EQ(0U, sourceVariant.index());
  385. AZStd::vector<char> byteBuffer;
  386. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  387. {
  388. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  389. [](AZ::SerializeContext* serializeContext)
  390. {
  391. serializeContext->RegisterGenericType<SaveVariant>();
  392. } }
  393. );
  394. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  395. objStream->WriteClass(&sourceVariant);
  396. objStream->Finalize();
  397. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  398. }
  399. ScopedSerializeContextReflector loadReflector(*m_serializeContext, {
  400. [](AZ::SerializeContext* serializeContext)
  401. {
  402. serializeContext->RegisterGenericType<LoadVariant>();
  403. } }
  404. );
  405. LoadVariant loadVariant;
  406. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadVariant, m_serializeContext.get()));
  407. constexpr size_t expectedLoadIndex = 0U;
  408. ASSERT_EQ(expectedLoadIndex, loadVariant.index());
  409. ASSERT_TRUE(AZStd::holds_alternative<AZStd::variant<int32_t*>*>(loadVariant));
  410. AZStd::variant<int32_t*>*& innerVariant = AZStd::get<expectedLoadIndex>(loadVariant);
  411. ASSERT_NE(nullptr, innerVariant);
  412. EXPECT_TRUE(AZStd::holds_alternative<int32_t*>(*innerVariant));
  413. int32_t* loadInt = AZStd::get<0>(*innerVariant);
  414. ASSERT_NE(nullptr, loadInt);
  415. EXPECT_EQ(expectedIntValue, *loadInt);
  416. azdestroy(loadInt);
  417. azdestroy(innerVariant);
  418. }
  419. TEST_F(VariantSerializationTest, SavingVariantWithIntAlternativeAndLoadingToVariantWithInnerVariantIntTypeAndIntPointerTypeAndIntValueTypeChoosesIntValueType)
  420. {
  421. using SaveVariant = AZStd::variant<int32_t>;
  422. using LoadVariant = AZStd::variant<AZStd::variant<int32_t*>*, int32_t*, int32_t>;
  423. // Store integer in variant and attempt to serialize it out and back in
  424. constexpr int32_t expectedIntValue = 146;
  425. // Sets the int32_t element of the source variant which is the zeroth index
  426. SaveVariant sourceVariant{ expectedIntValue };
  427. EXPECT_EQ(0U, sourceVariant.index());
  428. AZStd::vector<char> byteBuffer;
  429. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  430. {
  431. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  432. [](AZ::SerializeContext* serializeContext)
  433. {
  434. serializeContext->RegisterGenericType<SaveVariant>();
  435. } }
  436. );
  437. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  438. objStream->WriteClass(&sourceVariant);
  439. objStream->Finalize();
  440. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  441. }
  442. ScopedSerializeContextReflector loadReflector(*m_serializeContext, {
  443. [](AZ::SerializeContext* serializeContext)
  444. {
  445. serializeContext->RegisterGenericType<LoadVariant>();
  446. } }
  447. );
  448. LoadVariant loadVariant;
  449. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadVariant, m_serializeContext.get()));
  450. constexpr size_t expectedLoadIndex = 2U;
  451. ASSERT_EQ(expectedLoadIndex, loadVariant.index());
  452. int32_t loadInt = AZStd::get<expectedLoadIndex>(loadVariant);
  453. EXPECT_EQ(expectedIntValue, loadInt);
  454. }
  455. TEST_F(VariantSerializationTest, SavingIntAlternativeAndLoadingToRootVariantSucceeds)
  456. {
  457. using LoadVariant = AZStd::variant<int32_t*>;
  458. // Store integer in variant and attempt to serialize it out and back in
  459. constexpr int32_t expectedIntValue = 146;
  460. AZStd::vector<char> byteBuffer;
  461. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  462. {
  463. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  464. objStream->WriteClass(&expectedIntValue);
  465. objStream->Finalize();
  466. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  467. }
  468. ScopedSerializeContextReflector loadReflector(*m_serializeContext, {
  469. [](AZ::SerializeContext* serializeContext)
  470. {
  471. serializeContext->RegisterGenericType<LoadVariant>();
  472. } }
  473. );
  474. LoadVariant loadVariant;
  475. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadVariant, m_serializeContext.get()));
  476. constexpr size_t expectedLoadIndex = 0U;
  477. ASSERT_EQ(expectedLoadIndex, loadVariant.index());
  478. int32_t* loadInt = AZStd::get<expectedLoadIndex>(loadVariant);
  479. EXPECT_EQ(expectedIntValue, *loadInt);
  480. azdestroy(loadInt);
  481. }
  482. TEST_F(VariantSerializationTest, SavingAssetAlternativeAndLoadingToRootVariantSucceeds)
  483. {
  484. using SaveVariant = AZStd::variant<AZ::Data::Asset<AZ::Data::AssetData>>;
  485. using LoadVariant = AZStd::variant<AZ::Data::Asset<AZ::Data::AssetData>>;
  486. AZ::Data::AssetType sliceAssetTypeId("{C62C7A87-9C09-4148-A985-12F2C99C0A45}");
  487. AZ::Data::Asset<AZ::Data::AssetData> saveAsset(AZ::Data::AssetId{}, sliceAssetTypeId);
  488. SaveVariant saveVariant(saveAsset);
  489. AZStd::vector<char> byteBuffer;
  490. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  491. {
  492. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  493. [](AZ::SerializeContext* serializeContext)
  494. {
  495. serializeContext->RegisterGenericType<SaveVariant>();
  496. } }
  497. );
  498. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  499. objStream->WriteClass(&saveVariant);
  500. objStream->Finalize();
  501. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  502. }
  503. ScopedSerializeContextReflector loadReflector(*m_serializeContext, {
  504. [](AZ::SerializeContext* serializeContext)
  505. {
  506. serializeContext->RegisterGenericType<LoadVariant>();
  507. } }
  508. );
  509. LoadVariant loadVariant;
  510. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadVariant, m_serializeContext.get()));
  511. constexpr size_t expectedLoadIndex = 0U;
  512. ASSERT_EQ(expectedLoadIndex, loadVariant.index());
  513. AZ::Data::Asset<AZ::Data::AssetData>& loadAsset= AZStd::get<expectedLoadIndex>(loadVariant);
  514. EXPECT_FALSE(loadAsset.GetId().IsValid());
  515. }
  516. TEST_F(VariantSerializationTest, SavingVariantWithIntAlternativeAndLoadingToVariantWithoutIntAlternativeFails)
  517. {
  518. using SaveVariant = AZStd::variant<int32_t>;
  519. using LoadVariant = AZStd::variant<bool, double>;
  520. // Store integer in variant and attempt to serialize it out and back in
  521. constexpr int32_t expectedIntValue = 72;
  522. // Sets the int32_t element of the source variant which is the zeroth index
  523. SaveVariant sourceVariant{ expectedIntValue };
  524. EXPECT_EQ(0U, sourceVariant.index());
  525. AZStd::vector<char> byteBuffer;
  526. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  527. {
  528. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  529. [](AZ::SerializeContext* serializeContext)
  530. {
  531. serializeContext->RegisterGenericType<SaveVariant>();
  532. } }
  533. );
  534. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  535. objStream->WriteClass(&sourceVariant);
  536. objStream->Finalize();
  537. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  538. }
  539. ScopedSerializeContextReflector loadReflector(*m_serializeContext, {
  540. [](AZ::SerializeContext* serializeContext)
  541. {
  542. serializeContext->RegisterGenericType<LoadVariant>();
  543. } }
  544. );
  545. LoadVariant loadVariant;
  546. AZ_TEST_START_TRACE_SUPPRESSION;
  547. EXPECT_FALSE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadVariant, m_serializeContext.get()));
  548. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  549. }
  550. TEST_F(VariantSerializationTest, SavingVariantWithVectorOfStringAlternativeAndIsAbleToLoadCorrectly)
  551. {
  552. using SaveVariant = AZStd::variant<AZStd::vector<AZStd::string>, float>;
  553. using LoadVariant = AZStd::variant<bool, AZStd::vector<AZStd::string>>;
  554. // Store a vector of strings and attempt serialized to a stream and back
  555. const AZStd::string expectedStringValue1{ "ChimeYard" };
  556. const AZStd::string expectedStringValue2{ "BirdCakeFactory" };
  557. // Sets the vector of string element which corresponds to index 1 of the source variant
  558. SaveVariant sourceVariant{ AZStd::vector<AZStd::string>{expectedStringValue1, expectedStringValue2} };
  559. EXPECT_EQ(0U, sourceVariant.index());
  560. AZStd::vector<char> byteBuffer;
  561. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  562. {
  563. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  564. [](AZ::SerializeContext* serializeContext)
  565. {
  566. serializeContext->RegisterGenericType<SaveVariant>();
  567. } }
  568. );
  569. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_BINARY);
  570. objStream->WriteClass(&sourceVariant);
  571. objStream->Finalize();
  572. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  573. }
  574. ScopedSerializeContextReflector loadReflector(*m_serializeContext, {
  575. [](AZ::SerializeContext* serializeContext)
  576. {
  577. serializeContext->RegisterGenericType<LoadVariant>();
  578. } }
  579. );
  580. LoadVariant loadVariant;
  581. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadVariant, m_serializeContext.get()));
  582. ASSERT_EQ(1, loadVariant.index());
  583. EXPECT_EQ(AZStd::get<0>(sourceVariant), AZStd::get<1>(loadVariant));
  584. }
  585. TEST_F(VariantSerializationTest, SavingVectorOfVectorTypeIsAbleToLoadIntoVariantCorrectly)
  586. {
  587. using SaveType = AZStd::vector<AZStd::vector<AZStd::string>>;
  588. using LoadVariant = AZStd::variant<SaveType>;
  589. // Store a vector of vector of strings and attempt serialized to a stream and back
  590. const AZStd::string expectedStringValue1{ "Zubat Key" };
  591. const AZStd::string expectedStringValue2{ "Yubioh Key" };
  592. const AZStd::string expectedStringValue3{ "Gelato Token" };
  593. SaveType twoStepsVectorAndTwoStepsBack;
  594. // Set the inner vector first element to have an expected string value of "Yubioh Key" and "Gelato Token"
  595. twoStepsVectorAndTwoStepsBack.emplace_back();
  596. twoStepsVectorAndTwoStepsBack.back().push_back(expectedStringValue2);
  597. twoStepsVectorAndTwoStepsBack.back().push_back(expectedStringValue3);
  598. // Set the inner vector second element to have an expected string value of "Gelato Token" and "Zubat Key"
  599. twoStepsVectorAndTwoStepsBack.emplace_back();
  600. twoStepsVectorAndTwoStepsBack.back().push_back(expectedStringValue3);
  601. twoStepsVectorAndTwoStepsBack.back().push_back(expectedStringValue1);
  602. AZStd::vector<char> byteBuffer;
  603. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  604. {
  605. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  606. [](AZ::SerializeContext* serializeContext)
  607. {
  608. serializeContext->RegisterGenericType<SaveType>();
  609. } }
  610. );
  611. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_BINARY);
  612. objStream->WriteClass(&twoStepsVectorAndTwoStepsBack);
  613. objStream->Finalize();
  614. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  615. }
  616. ScopedSerializeContextReflector loadReflector(*m_serializeContext, {
  617. [](AZ::SerializeContext* serializeContext)
  618. {
  619. serializeContext->RegisterGenericType<LoadVariant>();
  620. } }
  621. );
  622. LoadVariant loadVariant;
  623. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadVariant, m_serializeContext.get()));
  624. ASSERT_EQ(0, loadVariant.index());
  625. EXPECT_EQ(twoStepsVectorAndTwoStepsBack, AZStd::get<0>(loadVariant));
  626. }
  627. TEST_F(VariantSerializationTest, SavingandLoadingVectorOfVariants_IsAbleToLoadAlternativesAtIndex1OrHigher_WithoutCrashing)
  628. {
  629. using VariantVectorA = AZStd::vector<AZStd::variant<AZStd::string, int32_t>>;
  630. using VariantVectorB = AZStd::vector<AZStd::variant<int32_t, AZStd::string>>;
  631. VariantVectorA varA;
  632. VariantVectorB varB;
  633. varA.push_back(1);
  634. varA.push_back("str");
  635. varB.push_back(1);
  636. varB.push_back("str");
  637. // VariantVectorA, works fine.
  638. {
  639. AZStd::vector<char> byteBuffer;
  640. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  641. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  642. [](AZ::SerializeContext* serializeContext)
  643. {
  644. serializeContext->RegisterGenericType<VariantVectorA>();
  645. } }
  646. );
  647. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_BINARY);
  648. objStream->WriteClass(&varA);
  649. objStream->Finalize();
  650. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  651. VariantVectorA loadVariant;
  652. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadVariant, m_serializeContext.get()));
  653. }
  654. // VariantVectorB, should also work fine.
  655. {
  656. AZStd::vector<char> byteBuffer;
  657. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  658. ScopedSerializeContextReflector scopedReflector(*m_serializeContext, {
  659. [](AZ::SerializeContext* serializeContext)
  660. {
  661. serializeContext->RegisterGenericType<VariantVectorB>();
  662. } }
  663. );
  664. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_BINARY);
  665. objStream->WriteClass(&varB);
  666. objStream->Finalize();
  667. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  668. VariantVectorB loadVariant;
  669. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadVariant, m_serializeContext.get()));
  670. }
  671. }
  672. }