PrefabLoadTemplateTests.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  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 <AzToolsFramework/Prefab/PrefabDomUtils.h>
  9. #include <Prefab/MockPrefabFileIOActionValidator.h>
  10. #include <Prefab/PrefabTestData.h>
  11. #include <Prefab/PrefabTestDataUtils.h>
  12. #include <Prefab/PrefabTestDomUtils.h>
  13. #include <Prefab/PrefabTestFixture.h>
  14. namespace UnitTest
  15. {
  16. using PrefabLoadTemplateTest = PrefabTestFixture;
  17. TEST_F(PrefabLoadTemplateTest, LoadTemplate_TemplateWithNoNestedInstance)
  18. {
  19. TemplateData templateData;
  20. templateData.m_filePath = "path/to/template/with/no/nested/instance";
  21. MockPrefabFileIOActionValidator mockIOActionValidator;
  22. mockIOActionValidator.ReadPrefabDom(
  23. templateData.m_filePath, PrefabTestDomUtils::CreatePrefabDom());
  24. templateData.m_id = m_prefabLoaderInterface->LoadTemplateFromFile(templateData.m_filePath);
  25. PrefabTestDataUtils::ValidateTemplateLoad(templateData);
  26. }
  27. TEST_F(PrefabLoadTemplateTest, LoadTemplate_TemplateWithOneNestedInstance_WithNoPatches)
  28. {
  29. TemplateData sourceTemplateData;
  30. sourceTemplateData.m_filePath = "path/to/template/with/no/nested/instance";
  31. TemplateData targetTemplateData;
  32. targetTemplateData.m_filePath = "path/to/template/with/one/nested/instance";
  33. InstanceData targetTemplateInstanceData = PrefabTestDataUtils::CreateInstanceDataWithNoPatches(
  34. "sourceTemplateInstance", sourceTemplateData.m_filePath);
  35. targetTemplateData.m_instancesData[targetTemplateInstanceData.m_name] = targetTemplateInstanceData;
  36. MockPrefabFileIOActionValidator mockIOActionValidator;
  37. mockIOActionValidator.ReadPrefabDom(
  38. sourceTemplateData.m_filePath, PrefabTestDomUtils::CreatePrefabDom());
  39. mockIOActionValidator.ReadPrefabDom(
  40. targetTemplateData.m_filePath, PrefabTestDomUtils::CreatePrefabDom({ targetTemplateInstanceData }));
  41. targetTemplateData.m_id = m_prefabLoaderInterface->LoadTemplateFromFile(targetTemplateData.m_filePath);
  42. sourceTemplateData.m_id = m_prefabSystemComponent->GetTemplateIdFromFilePath(sourceTemplateData.m_filePath);
  43. LinkData linkData = PrefabTestDataUtils::CreateLinkData(
  44. targetTemplateInstanceData, sourceTemplateData.m_id, targetTemplateData.m_id);
  45. PrefabTestDataUtils::CheckIfTemplatesConnected(sourceTemplateData, targetTemplateData, linkData);
  46. }
  47. TEST_F(PrefabLoadTemplateTest, LoadTemplate_TemplateDependingOnItself_TemplateLoadedWithErrorsAdded)
  48. {
  49. TemplateData templateData;
  50. templateData.m_filePath = "path/to/template/depending/on/itself";
  51. auto templatePrefabDom = PrefabTestDomUtils::CreatePrefabDom({
  52. PrefabTestDataUtils::CreateInstanceDataWithNoPatches("instance", templateData.m_filePath) });
  53. MockPrefabFileIOActionValidator mockIOActionValidator;
  54. mockIOActionValidator.ReadPrefabDom(templateData.m_filePath, templatePrefabDom);
  55. AZ_TEST_START_TRACE_SUPPRESSION;
  56. templateData.m_id = m_prefabLoaderInterface->LoadTemplateFromFile(templateData.m_filePath);
  57. AZ_TEST_STOP_TRACE_SUPPRESSION(3);
  58. templateData.m_isLoadedWithErrors = true;
  59. PrefabTestDataUtils::ValidateTemplateLoad(templateData);
  60. }
  61. TEST_F(PrefabLoadTemplateTest, LoadTemplate_SourceTemplateDependingOnTargetTemplate_TemplatesLoadedWithErrorsAdded)
  62. {
  63. // Prepare two Template Data which has cyclical dependency between them.
  64. // Set data of expected source Template.
  65. TemplateData sourceTemplateData;
  66. sourceTemplateData.m_filePath = "path/to/source/template";
  67. // Set data of expected target Template.
  68. TemplateData targetTemplateData;
  69. targetTemplateData.m_filePath = "path/to/target/template";
  70. // Set data of expected nested Instance in source Template.
  71. // The Template of this Instance is target Template so that
  72. // source Template depends on target Template.
  73. InstanceData sourceTemplateInstanceData = PrefabTestDataUtils::CreateInstanceDataWithNoPatches(
  74. "targetTemplateInstance", targetTemplateData.m_filePath);
  75. // Data of expected nested Instance in target Template.
  76. // The Template of this Instance is source Template so that
  77. // target Template depends on source Template.
  78. InstanceData targetTemplateInstanceData = PrefabTestDataUtils::CreateInstanceDataWithNoPatches(
  79. "sourceTemplateInstance", sourceTemplateData.m_filePath);
  80. // Set expected target Template's Instance data.
  81. // There should be NO Instance data in expected source Template
  82. // since cyclical dependency will be detected and LoadTemplate will stop.
  83. targetTemplateData.m_instancesData[targetTemplateInstanceData.m_name] = targetTemplateInstanceData;
  84. // Create PrefabDoms for both source/target Template.
  85. auto sourceTemplatePrefabDom = PrefabTestDomUtils::CreatePrefabDom({ sourceTemplateInstanceData });
  86. auto targetTemplatePrefabDom = PrefabTestDomUtils::CreatePrefabDom({ targetTemplateInstanceData });
  87. // The mock file IO will let the PrefabSystemComponent read expected PrefabDoms while calling LoadTemplate.
  88. MockPrefabFileIOActionValidator mockIOActionValidator;
  89. mockIOActionValidator.ReadPrefabDom(
  90. sourceTemplateData.m_filePath, sourceTemplatePrefabDom);
  91. mockIOActionValidator.ReadPrefabDom(
  92. targetTemplateData.m_filePath, targetTemplatePrefabDom);
  93. // Load target and source Templates and get their Ids.
  94. AZ_TEST_START_TRACE_SUPPRESSION;
  95. targetTemplateData.m_id = m_prefabLoaderInterface->LoadTemplateFromFile(targetTemplateData.m_filePath);
  96. AZ_TEST_STOP_TRACE_SUPPRESSION(4);
  97. sourceTemplateData.m_id = m_prefabSystemComponent->GetTemplateIdFromFilePath(sourceTemplateData.m_filePath);
  98. // Because of cyclical dependency, the two Templates should be loaded with errors.
  99. sourceTemplateData.m_isLoadedWithErrors = true;
  100. targetTemplateData.m_isLoadedWithErrors = true;
  101. // Set expected data of Link from source Template to target Template.
  102. // There should be no Link from target Template to source Template.
  103. LinkData linkData = PrefabTestDataUtils::CreateLinkData(
  104. targetTemplateInstanceData, sourceTemplateData.m_id, targetTemplateData.m_id);
  105. // Verify if actual source/target Templates have the expected Template data.
  106. // Also check if actual Link from source to target has the expected Link data.
  107. PrefabTestDataUtils::CheckIfTemplatesConnected(sourceTemplateData, targetTemplateData, linkData);
  108. }
  109. TEST_F(PrefabLoadTemplateTest, LoadTemplate_InstanceWithEmptySource_TemplateLoadedWithErrorsAdded)
  110. {
  111. TemplateData templateData;
  112. templateData.m_filePath = "path/to/template/with/no/instance/source";
  113. templateData.m_isLoadedWithErrors = true;
  114. auto templatePrefabDom = PrefabTestDomUtils::CreatePrefabDom({
  115. PrefabTestDataUtils::CreateInstanceDataWithNoPatches("templateInstance", "") });
  116. MockPrefabFileIOActionValidator mockIOActionValidator;
  117. mockIOActionValidator.ReadPrefabDom(templateData.m_filePath, templatePrefabDom);
  118. AZ_TEST_START_TRACE_SUPPRESSION;
  119. templateData.m_id = m_prefabLoaderInterface->LoadTemplateFromFile(templateData.m_filePath);
  120. AZ_TEST_STOP_TRACE_SUPPRESSION(2);
  121. PrefabTestDataUtils::ValidateTemplateLoad(templateData);
  122. }
  123. TEST_F(PrefabLoadTemplateTest, LoadTemplate_InstanceWithEmptyName_TemplateLoadedWithErrorsAdded)
  124. {
  125. TemplateData templateData;
  126. templateData.m_filePath = "path/to/template/with/no/instance/name";
  127. templateData.m_isLoadedWithErrors = true;
  128. auto templatePrefabDom = PrefabTestDomUtils::CreatePrefabDom({
  129. PrefabTestDataUtils::CreateInstanceDataWithNoPatches("", "template/instance/source") });
  130. MockPrefabFileIOActionValidator mockIOActionValidator;
  131. mockIOActionValidator.ReadPrefabDom(templateData.m_filePath, templatePrefabDom);
  132. AZ_TEST_START_TRACE_SUPPRESSION;
  133. templateData.m_id = m_prefabLoaderInterface->LoadTemplateFromFile(templateData.m_filePath);
  134. AZ_TEST_STOP_TRACE_SUPPRESSION(2);
  135. PrefabTestDataUtils::ValidateTemplateLoad(templateData);
  136. }
  137. TEST_F(PrefabLoadTemplateTest, LoadTemplate_OpenSourceTemplateFileFailed_TemplateLoadedWithErrorsAdded)
  138. {
  139. TemplateData templateData;
  140. templateData.m_filePath = "path/to/template";
  141. templateData.m_isLoadedWithErrors = true;
  142. InstanceData templateInstanceData = PrefabTestDataUtils::CreateInstanceDataWithNoPatches(
  143. "templateInstance", "wrong/path");
  144. MockPrefabFileIOActionValidator mockIOActionValidator;
  145. mockIOActionValidator.ReadPrefabDom(
  146. templateData.m_filePath,
  147. PrefabTestDomUtils::CreatePrefabDom({ templateInstanceData }));
  148. mockIOActionValidator.ReadPrefabDom(
  149. templateInstanceData.m_source, PrefabTestDomUtils::CreatePrefabDom(),
  150. AZ::IO::ResultCode::Success, AZ::IO::ResultCode::Error);
  151. AZ_TEST_START_TRACE_SUPPRESSION;
  152. templateData.m_id = m_prefabLoaderInterface->LoadTemplateFromFile(templateData.m_filePath);
  153. AZ_TEST_STOP_TRACE_SUPPRESSION(3);
  154. PrefabTestDataUtils::ValidateTemplateLoad(templateData);
  155. }
  156. TEST_F(PrefabLoadTemplateTest, LoadTemplate_MultiLevelTemplates_WithNoPatches)
  157. {
  158. MockPrefabFileIOActionValidator mockIOActionValidator;
  159. AZStd::vector<TemplateData> templatesData;
  160. const int nestedHierarchyLevel = 3;
  161. for (int i = 0; i < nestedHierarchyLevel; i++)
  162. {
  163. TemplateData templateData;
  164. templateData.m_filePath = AZStd::string::format("path/to/level/%d/template", i);
  165. templatesData.emplace_back(templateData);
  166. if (i != 0)
  167. {
  168. InstanceData templateInstanceData = PrefabTestDataUtils::CreateInstanceDataWithNoPatches(
  169. AZStd::string::format("level%dTemplateInstance", i), templatesData[i - 1].m_filePath);
  170. templatesData[i].m_instancesData[templateInstanceData.m_name] = templateInstanceData;
  171. mockIOActionValidator.ReadPrefabDom(
  172. templatesData[i].m_filePath, PrefabTestDomUtils::CreatePrefabDom({ templateInstanceData }));
  173. }
  174. else
  175. {
  176. mockIOActionValidator.ReadPrefabDom(
  177. templatesData[i].m_filePath, PrefabTestDomUtils::CreatePrefabDom());
  178. }
  179. }
  180. templatesData.back().m_id = m_prefabLoaderInterface->LoadTemplateFromFile(templatesData.back().m_filePath);
  181. for (int i = nestedHierarchyLevel - 2; i >= 0; i--)
  182. {
  183. templatesData[i].m_id = m_prefabSystemComponent->GetTemplateIdFromFilePath(templatesData[i].m_filePath);
  184. LinkData linkData = PrefabTestDataUtils::CreateLinkData(
  185. templatesData[i + 1].m_instancesData[AZStd::string::format("level%dTemplateInstance", i + 1)],
  186. templatesData[i].m_id, templatesData[i + 1].m_id);
  187. PrefabTestDataUtils::CheckIfTemplatesConnected(templatesData[i], templatesData[i + 1], linkData);
  188. }
  189. }
  190. TEST_F(PrefabLoadTemplateTest, LoadTemplate_TemplateWithMultiInstances_WithNoPatches)
  191. {
  192. MockPrefabFileIOActionValidator mockIOActionValidator;
  193. AZStd::vector<TemplateData> sourceTemplatesData;
  194. AZStd::vector<InstanceData> targetTemplateInstancesData;
  195. TemplateData targetTemplateData;
  196. targetTemplateData.m_filePath = "path/to/target/template";
  197. const int numInstances = 3;
  198. for (int i = 0; i < numInstances; i++)
  199. {
  200. TemplateData sourceTemplateData;
  201. sourceTemplateData.m_filePath = AZStd::string::format("path/to/source/%d/template", i);
  202. InstanceData targetTemplateInstanceData = PrefabTestDataUtils::CreateInstanceDataWithNoPatches(
  203. AZStd::string::format("source%dTemplateInstance", i), sourceTemplateData.m_filePath);
  204. targetTemplateData.m_instancesData[targetTemplateInstanceData.m_name] = targetTemplateInstanceData;
  205. mockIOActionValidator.ReadPrefabDom(
  206. sourceTemplateData.m_filePath, PrefabTestDomUtils::CreatePrefabDom());
  207. sourceTemplatesData.emplace_back(sourceTemplateData);
  208. targetTemplateInstancesData.emplace_back(targetTemplateInstanceData);
  209. }
  210. mockIOActionValidator.ReadPrefabDom(
  211. targetTemplateData.m_filePath, PrefabTestDomUtils::CreatePrefabDom(targetTemplateInstancesData));
  212. targetTemplateData.m_id = m_prefabLoaderInterface->LoadTemplateFromFile(targetTemplateData.m_filePath);
  213. for (int i = 0; i < numInstances; i++)
  214. {
  215. sourceTemplatesData[i].m_id = m_prefabSystemComponent->GetTemplateIdFromFilePath(sourceTemplatesData[i].m_filePath);
  216. LinkData linkFromSourceData = PrefabTestDataUtils::CreateLinkData(targetTemplateInstancesData[i],
  217. sourceTemplatesData[i].m_id, targetTemplateData.m_id);
  218. PrefabTestDataUtils::CheckIfTemplatesConnected(sourceTemplatesData[i], targetTemplateData, linkFromSourceData);
  219. }
  220. }
  221. TEST_F(PrefabLoadTemplateTest, LoadTemplate_LoadCorruptedPrefabFileData_InvalidTemplateIdReturned)
  222. {
  223. const AZStd::string corruptedPrefabContent = "{ Corrupted PrefabDom";
  224. AZ::IO::Path pathToCorruptedPrefab("path/to/corrupted/prefab/file");
  225. pathToCorruptedPrefab.MakePreferred();
  226. MockPrefabFileIOActionValidator mockIOActionValidator;
  227. mockIOActionValidator.ReadPrefabDom(pathToCorruptedPrefab, corruptedPrefabContent);
  228. AZ_TEST_START_TRACE_SUPPRESSION;
  229. TemplateId templateId = m_prefabLoaderInterface->LoadTemplateFromFile(pathToCorruptedPrefab);
  230. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  231. EXPECT_EQ(templateId, AzToolsFramework::Prefab::InvalidTemplateId);
  232. }
  233. TEST_F(PrefabLoadTemplateTest, LoadTemplate_LoadFromString_InvalidPathReturnsInvalidTemplateId)
  234. {
  235. PrefabDom emptyPrefabDom = PrefabTestDomUtils::CreatePrefabDom();
  236. AZStd::string emptyPrefabDomStr = PrefabTestDomUtils::DomToString(emptyPrefabDom);
  237. AZ_TEST_START_TRACE_SUPPRESSION;
  238. EXPECT_EQ(m_prefabLoaderInterface->LoadTemplateFromString(emptyPrefabDomStr, "|?<>"), AzToolsFramework::Prefab::InvalidTemplateId);
  239. EXPECT_EQ(m_prefabLoaderInterface->LoadTemplateFromString(emptyPrefabDomStr, "notAFile/"), AzToolsFramework::Prefab::InvalidTemplateId);
  240. AZ_TEST_STOP_TRACE_SUPPRESSION(2);
  241. }
  242. TEST_F(PrefabLoadTemplateTest, LoadTemplate_LoadFromString_LoadsEmptyPrefab)
  243. {
  244. TemplateData templateData;
  245. templateData.m_filePath = "path/to/empty/prefab";
  246. PrefabDom emptyPrefabDom = PrefabTestDomUtils::CreatePrefabDom();
  247. AZStd::string emptyPrefabDomStr = PrefabTestDomUtils::DomToString(emptyPrefabDom);
  248. templateData.m_id = m_prefabLoaderInterface->LoadTemplateFromString(
  249. emptyPrefabDomStr,
  250. templateData.m_filePath
  251. );
  252. PrefabTestDataUtils::ValidateTemplateLoad(templateData);
  253. }
  254. TEST_F(PrefabLoadTemplateTest, LoadTemplate_LoadFromString_TemplateDependingOnItself_LoadedWithErrors)
  255. {
  256. TemplateData templateData;
  257. templateData.m_filePath = "path/to/self/dependency";
  258. PrefabDom selfDependentPrefab = PrefabTestDomUtils::CreatePrefabDom(
  259. { PrefabTestDataUtils::CreateInstanceDataWithNoPatches("instance", templateData.m_filePath) }
  260. );
  261. AZStd::string selfDependentPrefabStr = PrefabTestDomUtils::DomToString(selfDependentPrefab);
  262. AZ_TEST_START_TRACE_SUPPRESSION;
  263. templateData.m_id = m_prefabLoaderInterface->LoadTemplateFromString(
  264. selfDependentPrefabStr,
  265. templateData.m_filePath);
  266. AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // produces different counts in Jenkins vs local
  267. templateData.m_isLoadedWithErrors = true;
  268. PrefabTestDataUtils::ValidateTemplateLoad(templateData);
  269. }
  270. TEST_F(PrefabLoadTemplateTest, LoadTemplate_LoadFromString_CorruptedReturnsInvalidTemplateId)
  271. {
  272. AZStd::string corruptPrefab = "{ Corrupted PrefabDom";
  273. AZ_TEST_START_TRACE_SUPPRESSION;
  274. TemplateId templateId = m_prefabLoaderInterface->LoadTemplateFromString(corruptPrefab);
  275. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  276. EXPECT_EQ(templateId, AzToolsFramework::Prefab::InvalidTemplateId);
  277. }
  278. }