AssetSerializerTests.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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/Asset/AssetSerializer.h>
  9. #include <AzCore/IO/GenericStreams.h>
  10. #include <AzCore/UnitTest/TestTypes.h>
  11. #include <AZTestShared/Utils/Utils.h>
  12. class AssetSerializerTest
  13. : public UnitTest::LeakDetectionFixture
  14. {
  15. public:
  16. void SetUp() override
  17. {
  18. UnitTest::LeakDetectionFixture::SetUp();
  19. // Fill in v0 and v1 of the test data with subsets of our v2 test asset.
  20. memcpy(m_testSerializedAssetVersion0, m_testSerializedAssetVersion2, AZ_ARRAY_SIZE(m_testSerializedAssetVersion0));
  21. memcpy(m_testSerializedAssetVersion1, m_testSerializedAssetVersion2, AZ_ARRAY_SIZE(m_testSerializedAssetVersion1));
  22. // Fill in v0 and v1 of the test strings with subsets of our v2 test string.
  23. m_testAssetStringVersion0 = m_testAssetStringVersion2.substr(0, m_testAssetStringVersion2.find(",hint="));
  24. m_testAssetStringVersion1 = m_testAssetStringVersion2.substr(0, m_testAssetStringVersion2.find(",loadBehavior="));
  25. }
  26. void TearDown() override
  27. {
  28. UnitTest::LeakDetectionFixture::TearDown();
  29. }
  30. protected:
  31. const AZ::Data::AssetId m_testAssetId{ AZ::Uuid("{01234567-89AB-CDEF-FEDC-BA9876543210}"), 0x33774488 };
  32. const AZ::Data::AssetType m_testAssetType{ AZ::Uuid("{00112233-4455-6677-8899-AABBCCDDEEFF}") };
  33. const AZStd::string m_testAssetHint{ "abcd" };
  34. // Pick a test value that's not a default value.
  35. const AZ::Data::AssetLoadBehavior m_testAssetLoadBehavior{ AZ::Data::AssetLoadBehavior::NoLoad };
  36. // Buffer to contain v0 of serialized data (AssetId + AssetType)
  37. uint8_t m_testSerializedAssetVersion0[0x30];
  38. // Buffer to contain v1 of serialized data (AssetId + AssetType + AssetHint)
  39. uint8_t m_testSerializedAssetVersion1[0x3C];
  40. // Buffer containing v2 of serialized data (AssetId + AssetType + AssetHint + AssetLoadBehavior)
  41. uint8_t m_testSerializedAssetVersion2[0x3D]
  42. {
  43. // AssetId - Uuid
  44. 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
  45. 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
  46. // AssetId - SubId (account for little endianness)
  47. 0x88, 0x44, 0x77, 0x33,
  48. // AssetId - pad bytes
  49. 0x00, 0x00, 0x00, 0x00,
  50. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  51. // Asset Type
  52. 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
  53. 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
  54. // Asset Hint Size (account for little endianness)
  55. 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  56. // Asset Hint
  57. 'a', 'b', 'c', 'd',
  58. // Asset Load Behavior
  59. aznumeric_cast<uint8_t>(AZ::Data::AssetLoadBehavior::NoLoad)
  60. };
  61. AZStd::string m_testAssetStringVersion0;
  62. AZStd::string m_testAssetStringVersion1;
  63. const AZStd::string m_testAssetStringVersion2
  64. {
  65. "id={01234567-89AB-CDEF-FEDC-BA9876543210}:33774488,type={00112233-4455-6677-8899-AABBCCDDEEFF},hint={abcd},loadBehavior=2"
  66. };
  67. };
  68. TEST_F(AssetSerializerTest, Load_LoadEmptyStream_LoadUnsuccessful)
  69. {
  70. // Create a memory stream that's too small.
  71. uint8_t memBuffer[] = { 0 };
  72. AZ::IO::MemoryStream memStream(memBuffer, AZ_ARRAY_SIZE(memBuffer));
  73. // Try to load the data from the stream into a new asset
  74. constexpr bool isDataBigEndian = false;
  75. constexpr unsigned int version = 0;
  76. AZ::Data::Asset<AZ::Data::AssetData> testAsset;
  77. bool success = AZ::AssetSerializer::s_serializer.Load(&testAsset, memStream, version, isDataBigEndian);
  78. // Verify that the Load was unsuccessful
  79. EXPECT_FALSE(success);
  80. }
  81. TEST_F(AssetSerializerTest, Load_LoadVersion0Data_LoadSuccessful)
  82. {
  83. // Create a test asset with an arbitrary set of expected values. (v0 is AssetId + AssetType, default hint and loadBehavior)
  84. AZ::Data::Asset<AZ::Data::AssetData> expectedAsset(m_testAssetId, m_testAssetType, AZStd::string());
  85. // Create a stream buffer that should match our expected asset, using version 0 of serialized data.
  86. AZ::IO::MemoryStream memStream(m_testSerializedAssetVersion0, AZ_ARRAY_SIZE(m_testSerializedAssetVersion0));
  87. // Load the data from the stream into a new asset
  88. constexpr bool isDataBigEndian = false;
  89. constexpr unsigned int version = 0;
  90. AZ::Data::Asset<AZ::Data::AssetData> testAsset;
  91. bool success = AZ::AssetSerializer::s_serializer.Load(&testAsset, memStream, version, isDataBigEndian);
  92. // Verify that the data read back in via Load matches the expected asset.
  93. EXPECT_TRUE(success);
  94. EXPECT_EQ(testAsset, expectedAsset);
  95. }
  96. TEST_F(AssetSerializerTest, Load_LoadVersion1Data_LoadSuccessful)
  97. {
  98. // Create a test asset with an arbitrary set of expected values. (v1 is AssetId + AssetType + AssetHint, default loadBehavior)
  99. AZ::Data::Asset<AZ::Data::AssetData> expectedAsset(m_testAssetId, m_testAssetType, m_testAssetHint);
  100. // Create a stream buffer that should match our expected asset, using version 1 of serialized data.
  101. AZ::IO::MemoryStream memStream(m_testSerializedAssetVersion1, AZ_ARRAY_SIZE(m_testSerializedAssetVersion1));
  102. // Load the data from the stream into a new asset
  103. constexpr bool isDataBigEndian = false;
  104. constexpr unsigned int version = 1;
  105. AZ::Data::Asset<AZ::Data::AssetData> testAsset;
  106. bool success = AZ::AssetSerializer::s_serializer.Load(&testAsset, memStream, version, isDataBigEndian);
  107. // Verify that the data read back in via Load matches the expected asset.
  108. EXPECT_TRUE(success);
  109. EXPECT_EQ(testAsset, expectedAsset);
  110. }
  111. TEST_F(AssetSerializerTest, Load_LoadVersion2Data_LoadSuccessful)
  112. {
  113. // Create a test asset with an arbitrary set of expected values. (v2 is AssetId + AssetType + AssetHint + AssetLoadBehavior)
  114. AZ::Data::Asset<AZ::Data::AssetData> expectedAsset(m_testAssetId, m_testAssetType, m_testAssetHint);
  115. expectedAsset.SetAutoLoadBehavior(m_testAssetLoadBehavior);
  116. // Create a stream buffer that should match our expected asset, using version 2 of serialized data.
  117. AZ::IO::MemoryStream memStream(m_testSerializedAssetVersion2, AZ_ARRAY_SIZE(m_testSerializedAssetVersion2));
  118. // Load the data from the stream into a new asset
  119. constexpr bool isDataBigEndian = false;
  120. constexpr unsigned int version = 2;
  121. AZ::Data::Asset<AZ::Data::AssetData> testAsset;
  122. bool success = AZ::AssetSerializer::s_serializer.Load(&testAsset, memStream, version, isDataBigEndian);
  123. // Verify that the data read back in via Load matches the expected asset.
  124. EXPECT_TRUE(success);
  125. EXPECT_EQ(testAsset, expectedAsset);
  126. }
  127. TEST_F(AssetSerializerTest, Save_SaveValidAsset_SaveSuccessful)
  128. {
  129. // Create a test asset with an arbitrary set of expected values.
  130. AZ::Data::Asset<AZ::Data::AssetData> testAsset(m_testAssetId, m_testAssetType, m_testAssetHint);
  131. testAsset.SetAutoLoadBehavior(m_testAssetLoadBehavior);
  132. // Create a memory stream to save into, and initialize it with bad data.
  133. // Also, make it larger than our expected size to verify that the Save doesn't try to write more than expected.
  134. char memBuffer[AZ_ARRAY_SIZE(m_testSerializedAssetVersion2) * 2];
  135. memset(memBuffer, 'X', AZ_ARRAY_SIZE(memBuffer));
  136. AZ::IO::MemoryStream memStream(memBuffer, AZ_ARRAY_SIZE(memBuffer), 0);
  137. // Save the test asset.
  138. constexpr bool isDataBigEndian = false;
  139. size_t bytesWritten = AZ::AssetSerializer::s_serializer.Save(&testAsset, memStream, isDataBigEndian);
  140. // Verify that the number of bytes returned is the same amount actually written into the mem stream.
  141. EXPECT_EQ(bytesWritten, memStream.GetLength());
  142. // Verify that the number of bytes written matches the expected size.
  143. EXPECT_EQ(bytesWritten, AZ_ARRAY_SIZE(m_testSerializedAssetVersion2));
  144. // Verify that the bytes written match the expected buffer
  145. EXPECT_EQ(0, memcmp(m_testSerializedAssetVersion2, memBuffer, AZ_ARRAY_SIZE(m_testSerializedAssetVersion2)));
  146. }
  147. TEST_F(AssetSerializerTest, DataToText_ConvertValidAsset_ConversionSuccessful)
  148. {
  149. // Create a memory stream containing the test serialized asset data.
  150. AZ::IO::MemoryStream memStream(m_testSerializedAssetVersion2, AZ_ARRAY_SIZE(m_testSerializedAssetVersion2));
  151. // Create a string buffer initialized with bad values and convert the serialized asset into text via DataToText.
  152. char stringBuffer[0x1000];
  153. memset(stringBuffer, 'X', AZ_ARRAY_SIZE(stringBuffer));
  154. AZ::IO::MemoryStream stringStream(stringBuffer, AZ_ARRAY_SIZE(stringBuffer), 0);
  155. constexpr bool isDataBigEndian = false;
  156. size_t stringSize = AZ::AssetSerializer::s_serializer.DataToText(memStream, stringStream, isDataBigEndian);
  157. // Verify that the result matches expectations.
  158. AZStd::string resultString(stringBuffer, stringSize);
  159. EXPECT_EQ(resultString, m_testAssetStringVersion2);
  160. }
  161. TEST_F(AssetSerializerTest, TextToData_ConvertVersion0Data_ConversionSuccessful)
  162. {
  163. // Create a test asset with an arbitrary set of expected values. (v0 contains AssetId + AssetType, default hint and loadBehavior)
  164. AZ::Data::Asset<AZ::Data::AssetData> testAsset(m_testAssetId, m_testAssetType, AZStd::string());
  165. // Save the asset into a memory stream.
  166. // We can't just use any of our test asset buffers directly because we need one saved in the latest version format and size,
  167. // but only with version 0 asset data in it.
  168. char testAssetBuffer[0x1000];
  169. AZ::IO::MemoryStream testAssetStream(testAssetBuffer, AZ_ARRAY_SIZE(testAssetBuffer), 0);
  170. constexpr bool isDataBigEndian = false;
  171. size_t testAssetBytesWritten = AZ::AssetSerializer::s_serializer.Save(&testAsset, testAssetStream, isDataBigEndian);
  172. // Make sure the amount written matches the expected size
  173. // (AssetId + AsssetType + AssetHint size + 0-length AssetHint string + AssetLoadBehavior)
  174. EXPECT_EQ(testAssetBytesWritten, sizeof(AZ::Data::AssetId) + sizeof(AZ::Data::AssetType) + sizeof(uint64_t) + 0 +
  175. sizeof(AZ::Data::AssetLoadBehavior));
  176. // Create an arbitrarily large memory stream to hold our converted data, and initialize to bad values.
  177. char memBuffer[0x1000];
  178. memset(memBuffer, 'X', AZ_ARRAY_SIZE(memBuffer));
  179. AZ::IO::MemoryStream memStream(memBuffer, AZ_ARRAY_SIZE(memBuffer), 0);
  180. // Convert a version 0 text string to data
  181. constexpr unsigned int version = 0;
  182. size_t bytesWritten = AZ::AssetSerializer::s_serializer.TextToData(m_testAssetStringVersion0.c_str(),
  183. version, memStream, isDataBigEndian);
  184. // Make sure the result value matches the actual amount written into the stream
  185. EXPECT_EQ(bytesWritten, memStream.GetLength());
  186. // Make sure the amount written matches the expected size
  187. EXPECT_EQ(bytesWritten, testAssetBytesWritten);
  188. // Make sure the data written matches the expected data
  189. EXPECT_EQ(0, memcmp(testAssetBuffer, memBuffer, testAssetBytesWritten));
  190. }
  191. TEST_F(AssetSerializerTest, TextToData_ConvertVersion1Data_ConversionSuccessful)
  192. {
  193. // Create a test asset with an arbitrary set of expected values. (v1 contains AssetId + AssetType + AssetHint, default loadBehavior)
  194. AZ::Data::Asset<AZ::Data::AssetData> testAsset(m_testAssetId, m_testAssetType, m_testAssetHint);
  195. // Save the asset into a memory stream.
  196. // We can't just use any of our test asset buffers directly because we need one saved in the latest version format and size,
  197. // but only with version 1 asset data in it.
  198. char testAssetBuffer[0x1000];
  199. AZ::IO::MemoryStream testAssetStream(testAssetBuffer, AZ_ARRAY_SIZE(testAssetBuffer), 0);
  200. constexpr bool isDataBigEndian = false;
  201. size_t testAssetBytesWritten = AZ::AssetSerializer::s_serializer.Save(&testAsset, testAssetStream, isDataBigEndian);
  202. // Make sure the amount written matches the expected size (same *size* as our test v2 data, just different data in it)
  203. EXPECT_EQ(testAssetBytesWritten, AZ_ARRAY_SIZE(m_testSerializedAssetVersion2));
  204. // Create an arbitrarily large memory stream to hold our converted data, and initialize to bad values.
  205. char memBuffer[0x1000];
  206. memset(memBuffer, 'X', AZ_ARRAY_SIZE(memBuffer));
  207. AZ::IO::MemoryStream memStream(memBuffer, AZ_ARRAY_SIZE(memBuffer), 0);
  208. // Convert a version 1 text string to data
  209. constexpr unsigned int version = 1;
  210. size_t bytesWritten = AZ::AssetSerializer::s_serializer.TextToData(m_testAssetStringVersion1.c_str(),
  211. version, memStream, isDataBigEndian);
  212. // Make sure the result value matches the actual amount written into the stream
  213. EXPECT_EQ(bytesWritten, memStream.GetLength());
  214. // Make sure the amount written matches the expected size
  215. EXPECT_EQ(bytesWritten, testAssetBytesWritten);
  216. // Make sure the data written matches the expected data
  217. EXPECT_EQ(0, memcmp(testAssetBuffer, memBuffer, testAssetBytesWritten));
  218. }
  219. TEST_F(AssetSerializerTest, TextToData_ConvertVersion2Data_ConversionSuccessful)
  220. {
  221. // Create an arbitrarily large memory stream to hold our converted data, and initialize to bad values.
  222. char memBuffer[0x1000];
  223. memset(memBuffer, 'X', AZ_ARRAY_SIZE(memBuffer));
  224. AZ::IO::MemoryStream memStream(memBuffer, AZ_ARRAY_SIZE(memBuffer), 0);
  225. // Convert a version 2 text string to data
  226. constexpr bool isDataBigEndian = false;
  227. constexpr unsigned int version = 2;
  228. size_t bytesWritten = AZ::AssetSerializer::s_serializer.TextToData(m_testAssetStringVersion2.c_str(),
  229. version, memStream, isDataBigEndian);
  230. // Make sure the result value matches the actual amount written into the stream
  231. EXPECT_EQ(bytesWritten, memStream.GetLength());
  232. // Make sure the amount written matches the expected size
  233. EXPECT_EQ(bytesWritten, AZ_ARRAY_SIZE(m_testSerializedAssetVersion2));
  234. // Make sure the data written matches the expected data
  235. EXPECT_EQ(0, memcmp(m_testSerializedAssetVersion2, memBuffer, AZ_ARRAY_SIZE(m_testSerializedAssetVersion2)));
  236. }
  237. TEST_F(AssetSerializerTest, Clone_CloneValidAsset_CloneSuccessful)
  238. {
  239. // Create an expected asset with an arbitrary set of expected values.
  240. AZ::Data::Asset<AZ::Data::AssetData> expectedAsset(m_testAssetId, m_testAssetType, m_testAssetHint);
  241. expectedAsset.SetAutoLoadBehavior(m_testAssetLoadBehavior);
  242. // Create an empty test asset
  243. AZ::Data::Asset<AZ::Data::AssetData> testAsset;
  244. // Verify that the empty asset doesn't match before the Clone, and does match afterwards.
  245. EXPECT_NE(expectedAsset, testAsset);
  246. AZ::AssetSerializer::s_serializer.Clone(&expectedAsset, &testAsset);
  247. EXPECT_EQ(expectedAsset, testAsset);
  248. }
  249. TEST_F(AssetSerializerTest, CompareValueData_CompareDifferentAssets_CompareReturnsFalse)
  250. {
  251. // Create an expected asset with an arbitrary set of expected values.
  252. AZ::Data::Asset<AZ::Data::AssetData> expectedAsset(m_testAssetId, m_testAssetType, m_testAssetHint);
  253. expectedAsset.SetAutoLoadBehavior(m_testAssetLoadBehavior);
  254. // Create an empty test asset
  255. AZ::Data::Asset<AZ::Data::AssetData> testAsset;
  256. EXPECT_FALSE(AZ::AssetSerializer::s_serializer.CompareValueData(&expectedAsset, &testAsset));
  257. }
  258. TEST_F(AssetSerializerTest, CompareValueData_CompareEquivalentAssets_CompareReturnsTrue)
  259. {
  260. // Create an expected asset with an arbitrary set of expected values.
  261. AZ::Data::Asset<AZ::Data::AssetData> expectedAsset(m_testAssetId, m_testAssetType, m_testAssetHint);
  262. expectedAsset.SetAutoLoadBehavior(m_testAssetLoadBehavior);
  263. // Create a second asset with the same data
  264. AZ::Data::Asset<AZ::Data::AssetData> testAsset(m_testAssetId, m_testAssetType, m_testAssetHint);
  265. expectedAsset.SetAutoLoadBehavior(m_testAssetLoadBehavior);
  266. EXPECT_TRUE(AZ::AssetSerializer::s_serializer.CompareValueData(&expectedAsset, &testAsset));
  267. }