AssetCommon.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  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/UnitTest/TestTypes.h>
  9. #include <AzCore/Asset/AssetCommon.h>
  10. #include <AzCore/Asset/AssetInternal/WeakAsset.h>
  11. namespace UnitTest
  12. {
  13. using namespace AZ;
  14. using namespace AZ::Data;
  15. using AssetIdTest = LeakDetectionFixture;
  16. TEST_F(AssetIdTest, AssetId_PrintDecimalSubId_SubIdIsDecimal)
  17. {
  18. // Arbitrary GUID, sub ID picked that will be different in decimal and hexadecimal.
  19. AssetId id("{A9F596D7-9913-4BA4-AD4E-7E477FB9B542}", 20);
  20. AZStd::string asString = id.ToString<AZStd::string>(AZ::Data::AssetId::SubIdDisplayType::Decimal);
  21. ASSERT_EQ(asString.size(), 41);
  22. ASSERT_EQ(asString[39], '2');
  23. ASSERT_EQ(asString[40], '0');
  24. }
  25. TEST_F(AssetIdTest, AssetId_PrintHexadecimalSubId_SubIdIsHex)
  26. {
  27. // Arbitrary GUID, sub ID picked that will be different in decimal and hexadecimal.
  28. AssetId id("{A9F596D7-9913-4BA4-AD4E-7E477FB9B542}", 20);
  29. AZStd::string asString = id.ToString<AZStd::string>(AZ::Data::AssetId::SubIdDisplayType::Hex);
  30. ASSERT_EQ(asString.size(), 41);
  31. ASSERT_EQ(asString[39], '1');
  32. ASSERT_EQ(asString[40], '4');
  33. }
  34. TEST_F(AssetIdTest, AssetIdLessThanOperator_LHSEqualsRHS_ReturnsFalse)
  35. {
  36. AssetId left("{88888888-4444-4444-4444-CCCCCCCCCCCC}", 1);
  37. AssetId right("{88888888-4444-4444-4444-CCCCCCCCCCCC}", 1);
  38. ASSERT_FALSE(left < right);
  39. }
  40. TEST_F(AssetIdTest, AssetIdLessThanOperator_GuidsEqualLHSSubIdLessThanRHS_ReturnsTrue)
  41. {
  42. AssetId left("{EEEEEEEE-EEEE-BBBB-BBBB-CCCCCCCCCCCC}", 0);
  43. AssetId right("{EEEEEEEE-EEEE-BBBB-BBBB-CCCCCCCCCCCC}", 1);
  44. ASSERT_TRUE(left < right);
  45. }
  46. TEST_F(AssetIdTest, AssetIdLessThanOperator_GuidsEqualLHSSubIdGreaterThanRHS_ReturnsFalse)
  47. {
  48. AssetId left("{66666666-2222-4444-3333-CCCCCCCCCCCC}", 4);
  49. AssetId right("{66666666-2222-4444-3333-CCCCCCCCCCCC}", 2);
  50. ASSERT_FALSE(left < right);
  51. }
  52. TEST_F(AssetIdTest, AssetIdLessThanOperator_LHSGuidLessThanRHS_ReturnsTrue)
  53. {
  54. AssetId left("{00000000-4444-4444-4444-CCCCCCCCCCCC}", 1);
  55. AssetId right("{10000000-4444-4444-4444-CCCCCCCCCCCC}", 1);
  56. ASSERT_TRUE(left < right);
  57. }
  58. TEST_F(AssetIdTest, AssetIdLessThanOperator_LHSGuidGreaterThanRHS_ReturnsFalse)
  59. {
  60. AssetId left("{10200000-4444-4444-4444-CCCCCCCCCCCC}", 1);
  61. AssetId right("{10000000-4444-4444-4444-CCCCCCCCCCCC}", 1);
  62. ASSERT_FALSE(left < right);
  63. }
  64. TEST_F(AssetIdTest, ToFixedString_ResultIsAccurate_Succeeds)
  65. {
  66. AssetId id("{A9F596D7-9913-4BA4-AD4E-7E477FB9B542}", 0xFEDC1234);
  67. const AZStd::string dynamic = id.ToString<AZStd::string>(AZ::Data::AssetId::SubIdDisplayType::Hex);
  68. const AssetId::FixedString fixed = id.ToFixedString();
  69. EXPECT_STREQ(dynamic.c_str(), fixed.c_str());
  70. }
  71. TEST_F(AssetIdTest, ToFixedString_FormatSpecifier_Succeeds)
  72. {
  73. AssetId source("{A9F596D7-9913-4BA4-AD4E-7E477FB9B542}", 0xFEDC1234);
  74. const AZStd::string dynamic = AZStd::string::format("%s", source.ToString<AZStd::string>().c_str());
  75. const AZStd::string fixed = AZStd::string::format("%s", source.ToFixedString().c_str());
  76. EXPECT_EQ(dynamic, fixed);
  77. }
  78. TEST_F(AssetIdTest, CreateString_SubIdIsNotNegative_Succeeds)
  79. {
  80. auto assetId = AssetId::CreateString("{A9F596D7-FFFF-4BA4-AD4E-7E477FB9B542}:0xFFFFFFFF");
  81. AZStd::string asString = assetId.ToString<AZStd::string>(AZ::Data::AssetId::SubIdDisplayType::Decimal);
  82. auto subId = asString.substr(asString.find_first_of(':') + 1);
  83. EXPECT_STRCASEEQ(subId.c_str(), "4294967295");
  84. }
  85. using AssetTest = LeakDetectionFixture;
  86. TEST_F(AssetTest, AssetPreserveHintTest_Const_Copy)
  87. {
  88. // test to make sure that when we copy asset<T>s around using copy operations
  89. // that the asset Hint is preserved in the case of assets being copied from things missing asset hints.
  90. AssetId id("{52C79B55-B5AA-4841-AFC8-683D77716287}", 1);
  91. AssetId idWithDifferentAssetId("{EA554205-D887-4A01-9E39-A318DDE4C0FC}", 1);
  92. AssetType typeOfExample("{A99E8722-1F1D-4CA9-B89B-921EB3D907A9}");
  93. Asset<AssetData> assetWithHint(id, typeOfExample, "an asset hint");
  94. Asset<AssetData> differentAssetEntirely(idWithDifferentAssetId, typeOfExample, "");
  95. Asset<AssetData> sameAssetWithoutHint(id, typeOfExample, "");
  96. Asset<AssetData> sameAssetWithDifferentHint(id, typeOfExample, "a different hint");
  97. // if we copy an asset from one with the same id, but no hint, preserve the sources hint.
  98. assetWithHint = sameAssetWithoutHint;
  99. ASSERT_STREQ(assetWithHint.GetHint().c_str(), "an asset hint");
  100. // if we copy from an asset with same id, but with a different hint, we do not preserve the hint.
  101. assetWithHint = sameAssetWithDifferentHint;
  102. ASSERT_STREQ(assetWithHint.GetHint().c_str(), "a different hint");
  103. // if we copy different assets (different id or sub) the hint must be copied.
  104. // even if its empty.
  105. assetWithHint = Asset<AssetData>(id, typeOfExample, "an asset hint");
  106. assetWithHint = differentAssetEntirely;
  107. ASSERT_STREQ(assetWithHint.GetHint().c_str(), "");
  108. // ensure copy construction copies the hint.
  109. Asset<AssetData> copied(sameAssetWithDifferentHint);
  110. ASSERT_STREQ(copied.GetHint().c_str(), "a different hint");
  111. }
  112. TEST_F(AssetTest, AssetPreserveHintTest_Rvalue_Ref_Move)
  113. {
  114. // test to make sure that when we move asset<T>s around using move operators
  115. // that the asset Hint is preserved in the case of assets being moved from things missing asset hints.
  116. AssetId id("{52C79B55-B5AA-4841-AFC8-683D77716287}", 1);
  117. AssetId idWithDifferentAssetId("{EA554205-D887-4A01-9E39-A318DDE4C0FC}", 1);
  118. AssetType typeOfExample("{A99E8722-1F1D-4CA9-B89B-921EB3D907A9}");
  119. Asset<AssetData> assetWithHint(id, typeOfExample, "an asset hint");
  120. Asset<AssetData> differentAssetEntirely(idWithDifferentAssetId, typeOfExample, "");
  121. Asset<AssetData> sameAssetWithoutHint(id, typeOfExample, "");
  122. Asset<AssetData> sameAssetWithDifferentHint(id, typeOfExample, "a different hint");
  123. // if we move an asset from one with the same id, but no hint, preserve the sources hint.
  124. assetWithHint = AZStd::move(sameAssetWithoutHint);
  125. ASSERT_STREQ(assetWithHint.GetHint().c_str(), "an asset hint");
  126. // if we move from an asset with same id, but with a different hint, we do not preserve the hint.
  127. assetWithHint = AZStd::move(sameAssetWithDifferentHint);
  128. ASSERT_STREQ(assetWithHint.GetHint().c_str(), "a different hint");
  129. // if we move different assets (different id or sub) the hint must be copied.
  130. // even if its empty.
  131. assetWithHint = Asset<AssetData>(id, typeOfExample, "an asset hint");
  132. assetWithHint = AZStd::move(differentAssetEntirely);
  133. ASSERT_STREQ(assetWithHint.GetHint().c_str(), "");
  134. // ensure move construction copies the hint.
  135. Asset<AssetData> copied(Asset<AssetData>(id, typeOfExample, "a different hint"));
  136. ASSERT_STREQ(copied.GetHint().c_str(), "a different hint");
  137. }
  138. TEST_F(LeakDetectionFixture, AssetReleaseRetainsAssetState_Id_Type_Hint)
  139. {
  140. const AssetId id("{52C79B55-B5AA-4841-AFC8-683D77716287}", 1);
  141. const AssetType type("{A99E8722-1F1D-4CA9-B89B-921EB3D907A9}");
  142. const AZStd::string hint("an asset hint");
  143. Asset<AssetData> assetWithHint(id, type, hint);
  144. assetWithHint.Release();
  145. EXPECT_EQ(assetWithHint.GetId(), id);
  146. EXPECT_EQ(assetWithHint.GetType(), type);
  147. EXPECT_EQ(assetWithHint.GetHint(), hint);
  148. }
  149. TEST_F(LeakDetectionFixture, AssetResetDefaultsAssetState_Id_Type_Hint)
  150. {
  151. const AssetId id("{52C79B55-B5AA-4841-AFC8-683D77716287}", 1);
  152. const AssetType type("{A99E8722-1F1D-4CA9-B89B-921EB3D907A9}");
  153. const AZStd::string hint("an asset hint");
  154. Asset<AssetData> assetWithHint(id, type, hint);
  155. assetWithHint.Reset();
  156. EXPECT_EQ(assetWithHint.GetId(), AssetId());
  157. EXPECT_EQ(assetWithHint.GetType(), AssetType::CreateNull());
  158. EXPECT_EQ(assetWithHint.GetHint(), AZStd::string{});
  159. }
  160. using WeakAssetTest = LeakDetectionFixture;
  161. // Expose the internal weak use count of AssetData for verification in unit tests.
  162. class TestAssetData : public AssetData
  163. {
  164. public:
  165. static inline const AssetId ArbitraryAssetId{ "{E14BD18D-A933-4CBD-B64E-25F14D5E69E4}", 1 };
  166. TestAssetData(const AssetId& assetId = ArbitraryAssetId) : AssetData(assetId) {}
  167. int GetWeakUseCount() { return m_weakUseCount.load(); }
  168. };
  169. // Asset cancellation is temporarily disabled, re-enable this test when cancellation is more stable
  170. TEST_F(WeakAssetTest, DISABLED_WeakAsset_ConstructionAndDestruction_UpdatesAssetDataWeakRefCount)
  171. {
  172. TestAssetData testData;
  173. EXPECT_EQ(testData.GetWeakUseCount(), 0);
  174. // When transitioning the weak use count from 1 to 0, one assert will fire due to the asset manager not being initialized.
  175. AZ_TEST_START_TRACE_SUPPRESSION;
  176. {
  177. AssetInternal::WeakAsset<TestAssetData> weakAsset(&testData, AssetLoadBehavior::Default);
  178. EXPECT_EQ(testData.GetWeakUseCount(), 1);
  179. }
  180. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  181. EXPECT_EQ(testData.GetWeakUseCount(), 0);
  182. }
  183. // Asset cancellation is temporarily disabled, re-enable this test when cancellation is more stable
  184. TEST_F(WeakAssetTest, DISABLED_WeakAsset_MoveOperatorWithDifferentData_UpdatesOldAssetDataWeakRefCount)
  185. {
  186. TestAssetData testData;
  187. EXPECT_EQ(testData.GetWeakUseCount(), 0);
  188. AssetInternal::WeakAsset<TestAssetData> weakAsset(&testData, AssetLoadBehavior::Default);
  189. EXPECT_EQ(testData.GetWeakUseCount(), 1);
  190. // When transitioning the weak use count from 1 to 0, one assert will fire due to the asset manager not being initialized.
  191. AZ_TEST_START_TRACE_SUPPRESSION;
  192. weakAsset = {};
  193. EXPECT_EQ(testData.GetWeakUseCount(), 0);
  194. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  195. }
  196. // Asset cancellation is temporarily disabled, re-enable this test when cancellation is more stable
  197. TEST_F(WeakAssetTest, DISABLED_WeakAsset_MoveOperatorWithSameData_PreservesAssetDataWeakRefCount)
  198. {
  199. TestAssetData testData;
  200. EXPECT_EQ(testData.GetWeakUseCount(), 0);
  201. // When transitioning the weak use count from 1 to 0, one assert will fire due to the asset manager not being initialized.
  202. AZ_TEST_START_TRACE_SUPPRESSION;
  203. {
  204. AssetInternal::WeakAsset<TestAssetData> weakAsset(&testData, AssetLoadBehavior::Default);
  205. EXPECT_EQ(testData.GetWeakUseCount(), 1);
  206. weakAsset = { &testData, AssetLoadBehavior::Default };
  207. EXPECT_EQ(testData.GetWeakUseCount(), 1);
  208. }
  209. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  210. }
  211. // Asset cancellation is temporarily disabled, re-enable this test when cancellation is more stable
  212. TEST_F(WeakAssetTest, DISABLED_WeakAsset_AssignmentOperator_CopiesDataAndIncrementsWeakRefCount)
  213. {
  214. TestAssetData testData;
  215. EXPECT_EQ(testData.GetWeakUseCount(), 0);
  216. // When transitioning the weak use count from 1 to 0, one assert will fire due to the asset manager not being initialized.
  217. AZ_TEST_START_TRACE_SUPPRESSION;
  218. {
  219. const AssetInternal::WeakAsset<TestAssetData> weakAsset(&testData, AssetLoadBehavior::PreLoad);
  220. EXPECT_EQ(testData.GetWeakUseCount(), 1);
  221. AssetInternal::WeakAsset<TestAssetData> weakAsset2;
  222. weakAsset2 = weakAsset;
  223. EXPECT_EQ(testData.GetWeakUseCount(), 2);
  224. EXPECT_EQ(weakAsset.GetId(), weakAsset2.GetId());
  225. }
  226. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  227. }
  228. }