PrefabFocusTests.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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/Component/EntityId.h>
  9. #include <AzToolsFramework/Entity/EditorEntityHelpers.h>
  10. #include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
  11. #include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
  12. #include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
  13. #include <Prefab/PrefabTestFixture.h>
  14. namespace UnitTest
  15. {
  16. class PrefabFocusTests
  17. : public PrefabTestFixture
  18. {
  19. protected:
  20. void GenerateTestHierarchy()
  21. {
  22. /*
  23. * City (Prefab Container)
  24. * |_ City
  25. * |_ Street (Prefab Container)
  26. * |_ Car (Prefab Container)
  27. * | |_ Passenger
  28. * |_ SportsCar (Prefab Container)
  29. * |_ Passenger
  30. */
  31. // Create loose entities
  32. m_entityMap[Passenger1EntityName] = CreateEntity(Passenger1EntityName);
  33. m_entityMap[Passenger2EntityName] = CreateEntity(Passenger2EntityName);
  34. m_entityMap[CityEntityName] = CreateEntity(CityEntityName);
  35. AddRequiredEditorComponents({
  36. m_entityMap[Passenger1EntityName]->GetId(),
  37. m_entityMap[Passenger2EntityName]->GetId(),
  38. m_entityMap[CityEntityName]->GetId() });
  39. // Call HandleEntitiesAdded to the loose entities to register them with the Prefab EOS
  40. AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
  41. &AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded,
  42. AzToolsFramework::EntityList{ m_entityMap[Passenger1EntityName], m_entityMap[Passenger2EntityName], m_entityMap[CityEntityName] });
  43. // Initialize Prefab EOS Interface
  44. AzToolsFramework::PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
  45. AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
  46. ASSERT_TRUE(prefabEditorEntityOwnershipInterface);
  47. // Create a car prefab from the passenger1 entity. The container entity will be created as part of the process.
  48. AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> carInstance =
  49. m_prefabSystemComponent->CreatePrefab({ m_entityMap[Passenger1EntityName] }, {}, "test/car");
  50. ASSERT_TRUE(carInstance);
  51. m_instanceMap[CarEntityName] = carInstance.get();
  52. // Create a sportscar prefab from the passenger2 entity. The container entity will be created as part of the process.
  53. AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> sportsCarInstance =
  54. m_prefabSystemComponent->CreatePrefab({ m_entityMap[Passenger2EntityName] }, {}, "test/sportsCar");
  55. ASSERT_TRUE(sportsCarInstance);
  56. m_instanceMap[SportsCarEntityName] = sportsCarInstance.get();
  57. // Create a street prefab that nests the car and sportscar instances created above. The container entity will be created as part of the process.
  58. AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> streetInstance =
  59. m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList(AZStd::move(carInstance), AZStd::move(sportsCarInstance)), "test/street");
  60. ASSERT_TRUE(streetInstance);
  61. m_instanceMap[StreetEntityName] = streetInstance.get();
  62. // Use the Prefab EOS root instance as the City instance. This will ensure functions that go through the EOS work in these tests too.
  63. m_rootInstance = prefabEditorEntityOwnershipInterface->GetRootPrefabInstance();
  64. ASSERT_TRUE(m_rootInstance.has_value());
  65. m_rootInstance->get().AddEntity(*m_entityMap[CityEntityName]);
  66. m_rootInstance->get().AddInstance(AZStd::move(streetInstance));
  67. m_instanceMap[CityEntityName] = &m_rootInstance->get();
  68. }
  69. void SetUpEditorFixtureImpl() override
  70. {
  71. PrefabTestFixture::SetUpEditorFixtureImpl();
  72. m_prefabFocusInterface = AZ::Interface<PrefabFocusInterface>::Get();
  73. ASSERT_TRUE(m_prefabFocusInterface != nullptr);
  74. m_prefabFocusPublicInterface = AZ::Interface<PrefabFocusPublicInterface>::Get();
  75. ASSERT_TRUE(m_prefabFocusPublicInterface != nullptr);
  76. AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult(
  77. m_editorEntityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId);
  78. GenerateTestHierarchy();
  79. }
  80. void TearDownEditorFixtureImpl() override
  81. {
  82. m_rootInstance->get().Reset();
  83. PrefabTestFixture::TearDownEditorFixtureImpl();
  84. }
  85. AZStd::unordered_map<AZStd::string, AZ::Entity*> m_entityMap;
  86. AZStd::unordered_map<AZStd::string, Instance*> m_instanceMap;
  87. InstanceOptionalReference m_rootInstance;
  88. PrefabFocusInterface* m_prefabFocusInterface = nullptr;
  89. PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr;
  90. AzFramework::EntityContextId m_editorEntityContextId = AzFramework::EntityContextId::CreateNull();
  91. inline static const char* CityEntityName = "City";
  92. inline static const char* StreetEntityName = "Street";
  93. inline static const char* CarEntityName = "Car";
  94. inline static const char* SportsCarEntityName = "SportsCar";
  95. inline static const char* Passenger1EntityName = "Passenger1";
  96. inline static const char* Passenger2EntityName = "Passenger2";
  97. };
  98. TEST_F(PrefabFocusTests, FocusOnOwningPrefabRootContainer)
  99. {
  100. // Verify FocusOnOwningPrefab works when passing the container entity of the root prefab.
  101. {
  102. m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[CityEntityName]->GetContainerEntityId());
  103. EXPECT_EQ(
  104. m_prefabFocusInterface->GetFocusedPrefabTemplateId(m_editorEntityContextId),
  105. m_instanceMap[CityEntityName]->GetTemplateId());
  106. auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(m_editorEntityContextId);
  107. EXPECT_TRUE(instance.has_value());
  108. EXPECT_EQ(&instance->get(), m_instanceMap[CityEntityName]);
  109. }
  110. }
  111. TEST_F(PrefabFocusTests, FocusOnOwningPrefabRootEntity)
  112. {
  113. // Verify FocusOnOwningPrefab works when passing a nested entity of the root prefab.
  114. {
  115. m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_entityMap[CityEntityName]->GetId());
  116. EXPECT_EQ(
  117. m_prefabFocusInterface->GetFocusedPrefabTemplateId(m_editorEntityContextId),
  118. m_instanceMap[CityEntityName]->GetTemplateId());
  119. auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(m_editorEntityContextId);
  120. EXPECT_TRUE(instance.has_value());
  121. EXPECT_EQ(&instance->get(), m_instanceMap[CityEntityName]);
  122. }
  123. }
  124. TEST_F(PrefabFocusTests, FocusOnOwningPrefabNestedContainer)
  125. {
  126. // Verify FocusOnOwningPrefab works when passing the container entity of a nested prefab.
  127. {
  128. m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[CarEntityName]->GetContainerEntityId());
  129. EXPECT_EQ(
  130. m_prefabFocusInterface->GetFocusedPrefabTemplateId(m_editorEntityContextId),
  131. m_instanceMap[CarEntityName]->GetTemplateId());
  132. auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(m_editorEntityContextId);
  133. EXPECT_TRUE(instance.has_value());
  134. EXPECT_EQ(&instance->get(), m_instanceMap[CarEntityName]);
  135. }
  136. }
  137. TEST_F(PrefabFocusTests, FocusOnOwningPrefabNestedEntity)
  138. {
  139. // Verify FocusOnOwningPrefab works when passing a nested entity of the a nested prefab.
  140. {
  141. m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_entityMap[Passenger1EntityName]->GetId());
  142. EXPECT_EQ(
  143. m_prefabFocusInterface->GetFocusedPrefabTemplateId(m_editorEntityContextId),
  144. m_instanceMap[CarEntityName]->GetTemplateId());
  145. auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(m_editorEntityContextId);
  146. EXPECT_TRUE(instance.has_value());
  147. EXPECT_EQ(&instance->get(), m_instanceMap[CarEntityName]);
  148. }
  149. }
  150. TEST_F(PrefabFocusTests, FocusOnOwningPrefabClear)
  151. {
  152. // Verify FocusOnOwningPrefab points to the root prefab when the focus is cleared.
  153. {
  154. AzToolsFramework::PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
  155. AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
  156. AzToolsFramework::Prefab::InstanceOptionalReference rootPrefabInstance =
  157. prefabEditorEntityOwnershipInterface->GetRootPrefabInstance();
  158. EXPECT_TRUE(rootPrefabInstance.has_value());
  159. m_prefabFocusPublicInterface->FocusOnOwningPrefab(AZ::EntityId());
  160. EXPECT_EQ(
  161. m_prefabFocusInterface->GetFocusedPrefabTemplateId(m_editorEntityContextId),
  162. rootPrefabInstance->get().GetTemplateId());
  163. auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(m_editorEntityContextId);
  164. EXPECT_TRUE(instance.has_value());
  165. EXPECT_EQ(&instance->get(), &rootPrefabInstance->get());
  166. }
  167. }
  168. TEST_F(PrefabFocusTests, FocusOnParentOfFocusedPrefabLeaf)
  169. {
  170. // Call FocusOnParentOfFocusedPrefab on a leaf instance and verify the parent is focused correctly.
  171. {
  172. m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[CarEntityName]->GetContainerEntityId());
  173. m_prefabFocusPublicInterface->FocusOnParentOfFocusedPrefab(m_editorEntityContextId);
  174. EXPECT_EQ(
  175. &m_prefabFocusInterface->GetFocusedPrefabInstance(m_editorEntityContextId)->get(),
  176. m_instanceMap[StreetEntityName]
  177. );
  178. }
  179. }
  180. TEST_F(PrefabFocusTests, FocusOnParentOfFocusedPrefabRoot)
  181. {
  182. // Call FocusOnParentOfFocusedPrefab on the root instance and verify the operation fails.
  183. {
  184. m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[CityEntityName]->GetContainerEntityId());
  185. auto outcome = m_prefabFocusPublicInterface->FocusOnParentOfFocusedPrefab(m_editorEntityContextId);
  186. EXPECT_FALSE(outcome.IsSuccess());
  187. }
  188. }
  189. TEST_F(PrefabFocusTests, IsOwningPrefabBeingFocusedContent)
  190. {
  191. // Verify IsOwningPrefabBeingFocused returns true for all entities in a focused prefab (container/nested)
  192. {
  193. m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[CityEntityName]->GetContainerEntityId());
  194. EXPECT_TRUE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[CityEntityName]->GetContainerEntityId()));
  195. EXPECT_TRUE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_entityMap[CityEntityName]->GetId()));
  196. }
  197. }
  198. TEST_F(PrefabFocusTests, IsOwningPrefabBeingFocusedAncestorsDescendants)
  199. {
  200. // Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (ancestors/descendants)
  201. {
  202. m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[StreetEntityName]->GetContainerEntityId());
  203. EXPECT_TRUE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[StreetEntityName]->GetContainerEntityId()));
  204. EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[CityEntityName]->GetContainerEntityId()));
  205. EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_entityMap[CityEntityName]->GetId()));
  206. EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[CarEntityName]->GetContainerEntityId()));
  207. EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger1EntityName]->GetId()));
  208. }
  209. }
  210. TEST_F(PrefabFocusTests, IsOwningPrefabBeingFocusedSiblings)
  211. {
  212. // Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (siblings)
  213. {
  214. m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[SportsCarEntityName]->GetContainerEntityId());
  215. EXPECT_TRUE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[SportsCarEntityName]->GetContainerEntityId()));
  216. EXPECT_TRUE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger2EntityName]->GetId()));
  217. EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[CarEntityName]->GetContainerEntityId()));
  218. EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger1EntityName]->GetId()));
  219. }
  220. }
  221. }