3
0

MaterialAssetTests.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  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 <AzTest/AzTest.h>
  9. #include <Common/RPITestFixture.h>
  10. #include <Common/SerializeTester.h>
  11. #include <Common/ShaderAssetTestUtils.h>
  12. #include <Common/ErrorMessageFinder.h>
  13. #include <Material/MaterialAssetTestUtils.h>
  14. #include <Atom/RPI.Reflect/Material/MaterialAsset.h>
  15. #include <Atom/RPI.Reflect/Material/MaterialAssetCreator.h>
  16. #include <Atom/RPI.Reflect/Material/MaterialTypeAssetCreator.h>
  17. namespace UnitTest
  18. {
  19. using namespace AZ;
  20. using namespace RPI;
  21. class MaterialAssetTests
  22. : public RPITestFixture
  23. {
  24. protected:
  25. Data::Asset<MaterialTypeAsset> m_testMaterialTypeAsset;
  26. Data::Asset<ImageAsset> m_testImageAsset;
  27. Data::Asset<ImageAsset> m_testAttachmentImageAsset;
  28. void SetUp() override
  29. {
  30. RPITestFixture::SetUp();
  31. auto materialSrgLayout = CreateCommonTestMaterialSrgLayout();
  32. // Since this test doesn't actually instantiate a Material, it won't need to instantiate this ImageAsset, so all we
  33. // need is an asset reference with a valid ID.
  34. m_testImageAsset = Data::Asset<ImageAsset>{ Uuid::CreateRandom(), azrtti_typeid<StreamingImageAsset>() };
  35. m_testAttachmentImageAsset = Data::Asset<AttachmentImageAsset>{ Uuid::CreateRandom(), azrtti_typeid<AttachmentImageAsset>() };
  36. auto shaderAsset = CreateTestShaderAsset(Uuid::CreateRandom(), materialSrgLayout);
  37. MaterialTypeAssetCreator materialTypeCreator;
  38. materialTypeCreator.Begin(Uuid::CreateRandom());
  39. materialTypeCreator.AddShader(shaderAsset);
  40. AddCommonTestMaterialProperties(materialTypeCreator);
  41. materialTypeCreator.SetPropertyValue(Name{ "MyBool" }, true);
  42. materialTypeCreator.SetPropertyValue(Name{ "MyInt" }, 1);
  43. materialTypeCreator.SetPropertyValue(Name{ "MyUInt" }, 2u);
  44. materialTypeCreator.SetPropertyValue(Name{ "MyFloat" }, 3.3f);
  45. materialTypeCreator.SetPropertyValue(Name{ "MyFloat2" }, Vector2{ 4.4f, 5.5f });
  46. materialTypeCreator.SetPropertyValue(Name{ "MyFloat3" }, Vector3{ 6.6f, 7.7f, 8.8f });
  47. materialTypeCreator.SetPropertyValue(Name{ "MyFloat4" }, Vector4{ 9.9f, 10.1f, 11.11f, 12.12f });
  48. materialTypeCreator.SetPropertyValue(Name{ "MyColor" }, Color{ 0.1f, 0.2f, 0.3f, 0.4f });
  49. materialTypeCreator.SetPropertyValue(Name{ "MyImage" }, m_testImageAsset);
  50. materialTypeCreator.SetPropertyValue(Name{ "MyEnum" }, 1u);
  51. materialTypeCreator.SetPropertyValue(Name{ "MyAttachmentImage" }, m_testAttachmentImageAsset);
  52. EXPECT_TRUE(materialTypeCreator.End(m_testMaterialTypeAsset));
  53. }
  54. void TearDown() override
  55. {
  56. m_testMaterialTypeAsset.Reset();
  57. RPITestFixture::TearDown();
  58. }
  59. };
  60. TEST_F(MaterialAssetTests, Basic)
  61. {
  62. auto validate = [this](Data::Asset<MaterialAsset> materialAsset)
  63. {
  64. EXPECT_EQ(m_testMaterialTypeAsset, materialAsset->GetMaterialTypeAsset());
  65. EXPECT_EQ(materialAsset->GetPropertyValues().size(), 11);
  66. EXPECT_EQ(materialAsset->GetPropertyValues()[0].GetValue<bool>(), true);
  67. EXPECT_EQ(materialAsset->GetPropertyValues()[1].GetValue<int32_t>(), -2);
  68. EXPECT_EQ(materialAsset->GetPropertyValues()[2].GetValue<uint32_t>(), 12);
  69. EXPECT_EQ(materialAsset->GetPropertyValues()[3].GetValue<float>(), 1.5f);
  70. EXPECT_EQ(materialAsset->GetPropertyValues()[4].GetValue<Vector2>(), Vector2(0.1f, 0.2f));
  71. EXPECT_EQ(materialAsset->GetPropertyValues()[5].GetValue<Vector3>(), Vector3(1.1f, 1.2f, 1.3f));
  72. EXPECT_EQ(materialAsset->GetPropertyValues()[6].GetValue<Vector4>(), Vector4(2.1f, 2.2f, 2.3f, 2.4f));
  73. EXPECT_EQ(materialAsset->GetPropertyValues()[7].GetValue<Color>(), Color(1.0f, 1.0f, 1.0f, 1.0f));
  74. EXPECT_EQ(materialAsset->GetPropertyValues()[8].GetValue<Data::Asset<ImageAsset>>(), m_testImageAsset);
  75. EXPECT_EQ(materialAsset->GetPropertyValues()[9].GetValue<uint32_t>(), 1u);
  76. EXPECT_EQ(materialAsset->GetPropertyValues()[10].GetValue<Data::Asset<ImageAsset>>(), m_testAttachmentImageAsset);
  77. };
  78. // Test basic process of creating a valid asset...
  79. Data::AssetId assetId(Uuid::CreateRandom());
  80. MaterialAssetCreator creator;
  81. creator.Begin(assetId, m_testMaterialTypeAsset);
  82. creator.SetPropertyValue(Name{ "MyFloat2" }, Vector2{ 0.1f, 0.2f });
  83. creator.SetPropertyValue(Name{ "MyFloat3" }, Vector3{ 1.1f, 1.2f, 1.3f });
  84. creator.SetPropertyValue(Name{ "MyFloat4" }, Vector4{ 2.1f, 2.2f, 2.3f, 2.4f });
  85. creator.SetPropertyValue(Name{ "MyColor" }, Color{ 1.0f, 1.0f, 1.0f, 1.0f });
  86. creator.SetPropertyValue(Name{ "MyInt" }, -2);
  87. creator.SetPropertyValue(Name{ "MyUInt" }, 12u);
  88. creator.SetPropertyValue(Name{ "MyFloat" }, 1.5f);
  89. creator.SetPropertyValue(Name{ "MyBool" }, true);
  90. creator.SetPropertyValue(Name{ "MyImage" }, m_testImageAsset);
  91. creator.SetPropertyValue(Name{ "MyEnum" }, 1u);
  92. creator.SetPropertyValue(Name{ "MyAttachmentImage" }, m_testAttachmentImageAsset);
  93. Data::Asset<MaterialAsset> materialAsset;
  94. EXPECT_TRUE(creator.End(materialAsset));
  95. EXPECT_EQ(assetId, materialAsset->GetId());
  96. EXPECT_EQ(Data::AssetData::AssetStatus::Ready, materialAsset->GetStatus());
  97. validate(materialAsset);
  98. // Also test serialization...
  99. SerializeTester<RPI::MaterialAsset> tester(GetSerializeContext());
  100. tester.SerializeOut(materialAsset.Get());
  101. // Using a filter that skips loading assets because we are using a dummy image asset
  102. ObjectStream::FilterDescriptor noAssets{ AZ::Data::AssetFilterNoAssetLoading };
  103. Data::Asset<RPI::MaterialAsset> serializedAsset = tester.SerializeIn(Data::AssetId(Uuid::CreateRandom()), noAssets);
  104. validate(serializedAsset);
  105. }
  106. TEST_F(MaterialAssetTests, PropertyDefaultValuesComeFromParentMaterial)
  107. {
  108. Data::AssetId assetId(Uuid::CreateRandom());
  109. MaterialAssetCreator creator;
  110. creator.Begin(assetId, m_testMaterialTypeAsset);
  111. creator.SetPropertyValue(Name{ "MyFloat" }, 3.14f);
  112. Data::Asset<MaterialAsset> materialAsset;
  113. EXPECT_TRUE(creator.End(materialAsset));
  114. EXPECT_EQ(assetId, materialAsset->GetId());
  115. EXPECT_EQ(Data::AssetData::AssetStatus::Ready, materialAsset->GetStatus());
  116. // Also test serialization...
  117. SerializeTester<RPI::MaterialAsset> tester(GetSerializeContext());
  118. tester.SerializeOut(materialAsset.Get());
  119. // Using a filter that skips loading assets because we are using a dummy image asset
  120. ObjectStream::FilterDescriptor noAssets{ AZ::Data::AssetFilterNoAssetLoading };
  121. materialAsset = tester.SerializeIn(Data::AssetId(Uuid::CreateRandom()), noAssets);
  122. EXPECT_EQ(materialAsset->GetPropertyValues().size(), 11);
  123. EXPECT_EQ(materialAsset->GetPropertyValues()[0].GetValue<bool>(), true);
  124. EXPECT_EQ(materialAsset->GetPropertyValues()[1].GetValue<int32_t>(), 1);
  125. EXPECT_EQ(materialAsset->GetPropertyValues()[2].GetValue<uint32_t>(), 2);
  126. EXPECT_EQ(materialAsset->GetPropertyValues()[3].GetValue<float>(), 3.14f);
  127. EXPECT_EQ(materialAsset->GetPropertyValues()[4].GetValue<Vector2>(), Vector2(4.4f, 5.5f));
  128. EXPECT_EQ(materialAsset->GetPropertyValues()[5].GetValue<Vector3>(), Vector3(6.6f, 7.7f, 8.8f));
  129. EXPECT_EQ(materialAsset->GetPropertyValues()[6].GetValue<Vector4>(), Vector4(9.9f, 10.1f, 11.11f, 12.12f));
  130. EXPECT_EQ(materialAsset->GetPropertyValues()[7].GetValue<Color>(), Color(0.1f, 0.2f, 0.3f, 0.4f));
  131. EXPECT_EQ(materialAsset->GetPropertyValues()[8].GetValue<Data::Asset<ImageAsset>>(), m_testImageAsset);
  132. EXPECT_EQ(materialAsset->GetPropertyValues()[9].GetValue<uint32_t>(), 1u);
  133. EXPECT_EQ(materialAsset->GetPropertyValues()[10].GetValue<Data::Asset<ImageAsset>>(), m_testAttachmentImageAsset);
  134. }
  135. TEST_F(MaterialAssetTests, MaterialWithNoSRGOrProperties)
  136. {
  137. // Making a material with no properties and no SRG allows us to create simple shaders
  138. // that don't need any input, for example a debug shader that just renders surface normals.
  139. Data::Asset<MaterialTypeAsset> emptyMaterialTypeAsset;
  140. MaterialTypeAssetCreator materialTypeCreator;
  141. materialTypeCreator.Begin(Uuid::CreateRandom());
  142. EXPECT_TRUE(materialTypeCreator.End(emptyMaterialTypeAsset));
  143. Data::Asset<MaterialAsset> materialAsset;
  144. MaterialAssetCreator materialCreator;
  145. materialCreator.Begin(Uuid::CreateRandom(), emptyMaterialTypeAsset);
  146. EXPECT_TRUE(materialCreator.End(materialAsset));
  147. EXPECT_EQ(emptyMaterialTypeAsset, materialAsset->GetMaterialTypeAsset());
  148. EXPECT_EQ(materialAsset->GetPropertyValues().size(), 0);
  149. }
  150. TEST_F(MaterialAssetTests, SetPropertyWithImageAssetSubclass)
  151. {
  152. // In the above test we called SetProperty(m_testImageAsset) which is an ImageAsset. Just to be safe, we also test
  153. // to make sure it still works when using the leaf type of StreamingImageAsset.
  154. // Since this test doesn't actually instantiate a Material, it won't need to instantiate this ImageAsset, so all we
  155. // need is an asset reference with a valid ID.
  156. Data::Asset<StreamingImageAsset> streamingImageAsset = Data::Asset<StreamingImageAsset>{ Uuid::CreateRandom(), azrtti_typeid<StreamingImageAsset>() };
  157. Data::AssetId assetId(Uuid::CreateRandom());
  158. MaterialAssetCreator creator;
  159. creator.Begin(assetId, m_testMaterialTypeAsset);
  160. creator.SetPropertyValue(Name{ "MyImage" }, streamingImageAsset);
  161. Data::Asset<MaterialAsset> materialAsset;
  162. EXPECT_TRUE(creator.End(materialAsset));
  163. EXPECT_EQ(materialAsset->GetPropertyValues()[8].GetValue<Data::Asset<ImageAsset>>(), streamingImageAsset);
  164. // Also test serialization...
  165. SerializeTester<RPI::MaterialAsset> tester(GetSerializeContext());
  166. tester.SerializeOut(materialAsset.Get());
  167. // Using a filter that skips loading assets because we are using a dummy image asset
  168. ObjectStream::FilterDescriptor noAssets{ AZ::Data::AssetFilterNoAssetLoading };
  169. Data::Asset<RPI::MaterialAsset> serializedAsset = tester.SerializeIn(Data::AssetId(Uuid::CreateRandom()), noAssets);
  170. EXPECT_EQ(serializedAsset->GetPropertyValues()[8].GetValue<Data::Asset<ImageAsset>>(), streamingImageAsset);
  171. }
  172. TEST_F(MaterialAssetTests, UpgradeMaterialAsset)
  173. {
  174. // Here we test the main way that a material asset upgrade would be applied at runtime: A material type is updated to
  175. // both rename properties, set new values *and* change the order in which properties appear in the layout.
  176. // Various permutations of the ordering of 'rename' and 'setValue' actions are tested.
  177. auto materialSrgLayout = CreateCommonTestMaterialSrgLayout();
  178. auto shaderAsset = CreateTestShaderAsset(Uuid::CreateRandom(), materialSrgLayout);
  179. // Construct the material asset with materialTypeAsset version 1
  180. Data::AssetId assetId(Uuid::CreateRandom());
  181. MaterialTypeAssetCreator materialTypeCreator;
  182. materialTypeCreator.Begin(Uuid::CreateRandom());
  183. // Prepare material type asset version 3 with update actions
  184. materialTypeCreator.SetVersion(3);
  185. {
  186. MaterialVersionUpdate versionUpdate(2);
  187. versionUpdate.AddAction(MaterialVersionUpdate::Action(
  188. AZ::Name{ "rename" },
  189. {
  190. { Name{ "from" }, AZStd::string("MyInt") },
  191. { Name{ "to" }, AZStd::string("MyIntIntermediateRename") }
  192. } ));
  193. versionUpdate.AddAction(MaterialVersionUpdate::Action(
  194. AZ::Name{ "setValue" },
  195. {
  196. { Name("name"), AZStd::string("MyFloat") },
  197. { Name("value"), 3.14f }
  198. } ));
  199. versionUpdate.AddAction(MaterialVersionUpdate::Action(
  200. AZ::Name{ "setValue" },
  201. {
  202. { Name("name"), AZStd::string("MyFloat2") },
  203. { Name("value"), 2.0f }
  204. } ));
  205. versionUpdate.AddAction(MaterialVersionUpdate::Action(
  206. AZ::Name{ "setValue" },
  207. {
  208. { Name("name"), AZStd::string("MyUInt") },
  209. { Name("value"), 314u }
  210. } ));
  211. materialTypeCreator.AddVersionUpdate(versionUpdate);
  212. }
  213. {
  214. MaterialVersionUpdate versionUpdate(3);
  215. versionUpdate.AddAction(MaterialVersionUpdate::Action(
  216. AZ::Name{ "setValue" },
  217. {
  218. { Name("name"), AZStd::string("MyFloat3") },
  219. { Name("value"), 3.0f }
  220. } ));
  221. versionUpdate.AddAction(MaterialVersionUpdate::Action(
  222. AZ::Name{ "rename" },
  223. {
  224. { Name{ "from" }, AZStd::string("MyIntIntermediateRename") },
  225. { Name{ "to" }, AZStd::string("MyIntFinalRename") }
  226. } ));
  227. versionUpdate.AddAction(MaterialVersionUpdate::Action(
  228. AZ::Name{ "rename" },
  229. {
  230. { Name{ "from" }, AZStd::string("MyUInt") },
  231. { Name{ "to" }, AZStd::string("MyUIntRenamed") }
  232. } ));
  233. versionUpdate.AddAction(MaterialVersionUpdate::Action(
  234. AZ::Name{ "rename" },
  235. {
  236. { Name{ "from" }, AZStd::string("MyFloat") },
  237. { Name{ "to" }, AZStd::string("MyFloatRenamed") }
  238. } ));
  239. materialTypeCreator.AddVersionUpdate(versionUpdate);
  240. }
  241. materialTypeCreator.AddShader(shaderAsset);
  242. // Now we add the properties in a different order from before, and use the new names.
  243. AddMaterialPropertyForSrg(materialTypeCreator, Name{ "MyUIntRenamed" }, MaterialPropertyDataType::UInt, Name{ "m_uint" });
  244. AddMaterialPropertyForSrg(materialTypeCreator, Name{ "MyFloatRenamed" }, MaterialPropertyDataType::Float, Name{ "m_float" });
  245. AddMaterialPropertyForSrg(materialTypeCreator, Name{ "MyIntFinalRename" }, MaterialPropertyDataType::Int, Name{ "m_int" });
  246. AddMaterialPropertyForSrg(materialTypeCreator, Name{ "MyFloat2" }, MaterialPropertyDataType::Float, Name{ "m_float2" });
  247. AddMaterialPropertyForSrg(materialTypeCreator, Name{ "MyFloat3" }, MaterialPropertyDataType::Float, Name{ "m_float3" });
  248. Data::Asset<MaterialTypeAsset> testMaterialTypeAssetV3;
  249. EXPECT_TRUE(materialTypeCreator.End(testMaterialTypeAssetV3));
  250. // Expected warning messages
  251. ErrorMessageFinder warningFinder;
  252. auto ExpectOverwriteMessage = [&warningFinder](uint32_t version, const char *name, const char *finalName)
  253. {
  254. if (finalName == nullptr)
  255. {
  256. warningFinder.AddExpectedErrorMessage(AZStd::string::format(
  257. "SetValue operation of update to version %u has detected (and overwritten) a previous value for '%s'.",
  258. version, name));
  259. }
  260. else
  261. {
  262. warningFinder.AddExpectedErrorMessage(AZStd::string::format(
  263. "SetValue operation of update to version %u has detected (and overwritten) a previous value for '%s' "
  264. "(final name of this property: '%s').",
  265. version, name, finalName));
  266. }
  267. };
  268. warningFinder.AddExpectedErrorMessage("Automatic updates have been applied. Consider updating the .material source file");
  269. warningFinder.AddExpectedErrorMessage("This material is based on version '1'");
  270. warningFinder.AddExpectedErrorMessage("material type is now at version '3'");
  271. ExpectOverwriteMessage(2, "MyFloat", "MyFloatRenamed");
  272. ExpectOverwriteMessage(2, "MyFloat2", nullptr);
  273. ExpectOverwriteMessage(2, "MyUInt", "MyUIntRenamed");
  274. MaterialAssetCreator creator;
  275. creator.Begin(assetId, testMaterialTypeAssetV3);
  276. creator.SetMaterialTypeVersion(1);
  277. // Set some properties to non-default values
  278. creator.SetPropertyValue(Name{ "MyInt" }, 7);
  279. creator.SetPropertyValue(Name{ "MyUInt" }, 8u);
  280. creator.SetPropertyValue(Name{ "MyFloat" }, 9.0f);
  281. creator.SetPropertyValue(Name{ "MyFloat2" }, 10.0f);
  282. Data::Asset<MaterialAsset> materialAsset;
  283. EXPECT_TRUE(creator.End(materialAsset));
  284. warningFinder.CheckExpectedErrorsFound();
  285. // Since the MaterialAsset has already been updated, and the warnings reported once, we
  286. // should not see any warnings reported again on subsequent property accesses.
  287. warningFinder.Reset();
  288. // Check that the properties have been properly updated, and that their index corresponds to the latest property layout.
  289. auto FindIndex = [&materialAsset](const Name &propertyId)
  290. {
  291. return materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId);
  292. };
  293. EXPECT_FALSE(FindIndex(Name{"MyUInt"}).IsValid());
  294. MaterialPropertyIndex myUIntIndex = FindIndex(Name{"MyUIntRenamed"});
  295. EXPECT_EQ(0, myUIntIndex.GetIndex());
  296. EXPECT_EQ(314u, materialAsset->GetPropertyValues()[myUIntIndex.GetIndex()].GetValue<uint32_t>());
  297. EXPECT_FALSE(FindIndex(Name{"MyFloat"}).IsValid());
  298. MaterialPropertyIndex myFloatIndex = FindIndex(Name{"MyFloatRenamed"});
  299. EXPECT_EQ(1, myFloatIndex.GetIndex());
  300. EXPECT_EQ(3.14f, materialAsset->GetPropertyValues()[myFloatIndex.GetIndex()].GetValue<float>());
  301. EXPECT_FALSE(FindIndex(Name{"MyInt"}).IsValid());
  302. EXPECT_FALSE(FindIndex(Name{"MyIntIntermediateRename"}).IsValid());
  303. MaterialPropertyIndex myIntIndex = FindIndex(Name{"MyIntFinalRename"});
  304. EXPECT_EQ(2, myIntIndex.GetIndex());
  305. EXPECT_EQ(7, materialAsset->GetPropertyValues()[myIntIndex.GetIndex()].GetValue<int32_t>());
  306. MaterialPropertyIndex myFloat2Index = FindIndex(Name{"MyFloat2"});
  307. EXPECT_EQ(3, myFloat2Index.GetIndex());
  308. EXPECT_EQ(2.0f, materialAsset->GetPropertyValues()[myFloat2Index.GetIndex()].GetValue<float>());
  309. MaterialPropertyIndex myFloat3Index = FindIndex(Name{"MyFloat3"});
  310. EXPECT_EQ(4, myFloat3Index.GetIndex());
  311. EXPECT_EQ(3.0f, materialAsset->GetPropertyValues()[myFloat3Index.GetIndex()].GetValue<float>());
  312. }
  313. TEST_F(MaterialAssetTests, Error_NoBegin)
  314. {
  315. Data::AssetId assetId(Uuid::CreateRandom());
  316. AZ_TEST_START_ASSERTTEST;
  317. MaterialAssetCreator creator;
  318. creator.SetPropertyValue(Name{ "MyBool" }, true);
  319. creator.SetPropertyValue(Name{ "MyImage" }, m_testImageAsset);
  320. Data::Asset<MaterialAsset> materialAsset;
  321. EXPECT_FALSE(creator.End(materialAsset));
  322. AZ_TEST_STOP_ASSERTTEST(3);
  323. }
  324. TEST_F(MaterialAssetTests, Error_SetPropertyInvalidInputs)
  325. {
  326. Data::AssetId assetId(Uuid::CreateRandom());
  327. // We use local functions to easily start a new MaterialAssetCreator for each test case because
  328. // the AssetCreator would just skip subsequent operations after the first failure is detected.
  329. auto expectCreatorError = [this](const char* expectedErrorMessage, AZStd::function<void(MaterialAssetCreator& creator)> passBadInput)
  330. {
  331. MaterialAssetCreator creator;
  332. creator.Begin(Uuid::CreateRandom(), m_testMaterialTypeAsset);
  333. ErrorMessageFinder errorMessageFinder;
  334. errorMessageFinder.AddExpectedErrorMessage(expectedErrorMessage);
  335. errorMessageFinder.AddIgnoredErrorMessage("Failed to build", true);
  336. passBadInput(creator);
  337. Data::Asset<MaterialAsset> materialAsset;
  338. EXPECT_FALSE(creator.End(materialAsset));
  339. errorMessageFinder.CheckExpectedErrorsFound();
  340. EXPECT_TRUE(creator.GetErrorCount() > 0);
  341. };
  342. auto expectCreatorWarning = [this](AZStd::function<void(MaterialAssetCreator& creator)> passBadInput)
  343. {
  344. MaterialAssetCreator creator;
  345. creator.Begin(Uuid::CreateRandom(), m_testMaterialTypeAsset);
  346. passBadInput(creator);
  347. Data::Asset<MaterialAsset> material;
  348. creator.End(material);
  349. EXPECT_EQ(1, creator.GetWarningCount());
  350. };
  351. // Invalid input ID
  352. expectCreatorWarning([](MaterialAssetCreator& creator)
  353. {
  354. creator.SetPropertyValue(Name{ "BoolDoesNotExist" }, MaterialPropertyValue(false));
  355. });
  356. // Invalid image input ID
  357. expectCreatorWarning([this](MaterialAssetCreator& creator)
  358. {
  359. creator.SetPropertyValue(Name{ "ImageDoesNotExist" }, m_testImageAsset);
  360. });
  361. // Test data type mismatches...
  362. expectCreatorError("Type mismatch",
  363. [this](MaterialAssetCreator& creator)
  364. {
  365. creator.SetPropertyValue(Name{ "MyBool" }, m_testImageAsset);
  366. });
  367. expectCreatorError("Type mismatch",
  368. [](MaterialAssetCreator& creator)
  369. {
  370. creator.SetPropertyValue(Name{ "MyFloat" }, AZ::Vector4{});
  371. });
  372. expectCreatorError("Type mismatch",
  373. [](MaterialAssetCreator& creator)
  374. {
  375. creator.SetPropertyValue(Name{ "MyColor" }, MaterialPropertyValue(false));
  376. });
  377. expectCreatorError("Type mismatch",
  378. [](MaterialAssetCreator& creator)
  379. {
  380. creator.SetPropertyValue(Name{ "MyImage" }, true);
  381. });
  382. expectCreatorError("can only accept UInt value",
  383. [](MaterialAssetCreator& creator)
  384. {
  385. creator.SetPropertyValue(Name{ "MyEnum" }, -1);
  386. });
  387. }
  388. }