EntityInspectorTests.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  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. /*
  9. * Copyright (c) Contributors to the Open 3D Engine Project.
  10. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  11. *
  12. * SPDX-License-Identifier: Apache-2.0 OR MIT
  13. *
  14. */
  15. // Test Environment
  16. #include <AzCore/UnitTest/TestTypes.h>
  17. #include <AzCore/Component/Component.h>
  18. #include <AzCore/Serialization/SerializeContext.h>
  19. #include <AzCore/UserSettings/UserSettingsComponent.h>
  20. #include <AzToolsFramework/Application/ToolsApplication.h>
  21. #include <AzToolsFramework/API/ToolsApplicationAPI.h>
  22. #include <AzToolsFramework/Entity/EditorEntityContextBus.h>
  23. #include <AzToolsFramework/Entity/EditorEntityHelpers.h>
  24. #include <AzToolsFramework/UnitTest/ToolsTestApplication.h>
  25. // Inspector Test Includes
  26. #include <AzToolsFramework/UI/ComponentPalette/ComponentPaletteUtil.hxx>
  27. namespace UnitTest
  28. {
  29. // Test component that is NOT available for a user to interact with
  30. // It does not appear in the Add Component menu in the Editor
  31. // It is not a system or game component
  32. class Inspector_TestComponent1
  33. : public AZ::Component
  34. {
  35. public:
  36. AZ_COMPONENT(Inspector_TestComponent1, "{BD25A077-DF38-4B67-BEA5-F4587A747A36}", AZ::Component);
  37. static void Reflect(AZ::ReflectContext* context)
  38. {
  39. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  40. {
  41. serializeContext->Class<Inspector_TestComponent1, AZ::Component>()
  42. ->Field("Data", &Inspector_TestComponent1::m_data)
  43. ;
  44. if (AZ::EditContext* editContext = serializeContext->GetEditContext())
  45. {
  46. editContext->Class<Inspector_TestComponent1>("InspectorTestComponent1", "Component 1 for AZ Tools Framework Unit Tests")
  47. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  48. ->Attribute(AZ::Edit::Attributes::AddableByUser, false)
  49. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide)
  50. ->Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::NotPushable)
  51. ->Attribute(AZ::Edit::Attributes::HideIcon, true);
  52. }
  53. }
  54. }
  55. static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
  56. {
  57. services.push_back(AZ_CRC("InspectorTestService1"));
  58. }
  59. static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
  60. {
  61. services.push_back(AZ_CRC("InspectorTestService1"));
  62. }
  63. ~Inspector_TestComponent1() override
  64. {
  65. }
  66. void SetData(int data)
  67. {
  68. m_data = data;
  69. };
  70. int GetData()
  71. {
  72. return m_data;
  73. }
  74. private:
  75. void Init() override
  76. {}
  77. void Activate() override
  78. {}
  79. void Deactivate() override
  80. {}
  81. /// Whether this entity is locked
  82. int m_data = 0;
  83. };
  84. // Test component that IS available for a user to interact with
  85. // It does appear in the Add Component menu in the editor and is a game component
  86. class Inspector_TestComponent2
  87. : public AZ::Component
  88. {
  89. public:
  90. AZ_COMPONENT(Inspector_TestComponent2, "{57D1C818-FD31-4FCD-A4DB-705EABF4E98B}", AZ::Component);
  91. static void Reflect(AZ::ReflectContext* context)
  92. {
  93. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  94. {
  95. serializeContext->Class<Inspector_TestComponent2, AZ::Component>()
  96. ->Field("Data", &Inspector_TestComponent2::m_data)
  97. ;
  98. if (AZ::EditContext* editContext = serializeContext->GetEditContext())
  99. {
  100. editContext->Class<Inspector_TestComponent2>("InspectorTestComponent2", "Component 2 for AZ Tools Framework Unit Tests")
  101. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  102. ->Attribute(AZ::Edit::Attributes::AddableByUser, true)
  103. ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game"))
  104. ->Attribute(AZ::Edit::Attributes::Category, "Inspector Test Components")
  105. ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Tag.png")
  106. ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Tag.png")
  107. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  108. ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components")
  109. ->DataElement(AZ::Edit::UIHandlers::Default, &Inspector_TestComponent2::m_data, "Data", "The component's Data");
  110. }
  111. }
  112. }
  113. static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
  114. {
  115. services.push_back(AZ_CRC("InspectorTestService2"));
  116. }
  117. static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
  118. {
  119. services.push_back(AZ_CRC("InspectorTestService2"));
  120. }
  121. ~Inspector_TestComponent2() override
  122. {
  123. }
  124. void SetData(int data)
  125. {
  126. m_data = data;
  127. };
  128. int GetData()
  129. {
  130. return m_data;
  131. }
  132. private:
  133. void Init() override
  134. {}
  135. void Activate() override
  136. {}
  137. void Deactivate() override
  138. {}
  139. /// Whether this entity is locked
  140. int m_data = 0;
  141. };
  142. // Test component that IS available for a user to interact with
  143. // It does appear in an Add Component menu and is a system component
  144. class Inspector_TestComponent3
  145. : public AZ::Component
  146. {
  147. public:
  148. AZ_COMPONENT(Inspector_TestComponent3, "{552CCFB1-135E-4B02-A492-25A3BBDFA381}", AZ::Component);
  149. static void Reflect(AZ::ReflectContext* context)
  150. {
  151. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  152. {
  153. serializeContext->Class<Inspector_TestComponent3, AZ::Component>()
  154. ->Field("Data", &Inspector_TestComponent3::m_data)
  155. ;
  156. if (AZ::EditContext* editContext = serializeContext->GetEditContext())
  157. {
  158. editContext->Class<Inspector_TestComponent3>("InspectorTestComponent3", "Component 3 for AZ Tools Framework Unit Tests")
  159. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  160. ->Attribute(AZ::Edit::Attributes::AddableByUser, true)
  161. ->Attribute(AZ::Edit::Attributes::Category, "Inspector Test Components")
  162. ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Tag.png")
  163. ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Tag.png")
  164. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  165. ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components")
  166. ->DataElement(AZ::Edit::UIHandlers::Default, &Inspector_TestComponent3::m_data, "Data", "The component's Data");
  167. }
  168. }
  169. }
  170. static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
  171. {
  172. services.push_back(AZ_CRC("InspectorTestService3"));
  173. }
  174. static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
  175. {
  176. services.push_back(AZ_CRC("InspectorTestService3"));
  177. }
  178. ~Inspector_TestComponent3() override
  179. {
  180. }
  181. void SetData(int data)
  182. {
  183. m_data = data;
  184. };
  185. int GetData()
  186. {
  187. return m_data;
  188. }
  189. private:
  190. void Init() override
  191. {}
  192. void Activate() override
  193. {}
  194. void Deactivate() override
  195. {}
  196. /// Whether this entity is locked
  197. int m_data = 0;
  198. };
  199. // Component Filters for Testing
  200. bool Filter_IsTestComponent1(const AZ::SerializeContext::ClassData& classData)
  201. {
  202. AZ::Uuid testComponent1_typeId = azrtti_typeid<Inspector_TestComponent1>();
  203. return classData.m_typeId == testComponent1_typeId;
  204. }
  205. // Component Filters for Testing
  206. bool Filter_IsTestComponent2(const AZ::SerializeContext::ClassData& classData)
  207. {
  208. AZ::Uuid testComponent2_typeId = azrtti_typeid<Inspector_TestComponent2>();
  209. return classData.m_typeId == testComponent2_typeId;
  210. }
  211. // Component Filters for Testing
  212. bool Filter_IsTestComponent3(const AZ::SerializeContext::ClassData& classData)
  213. {
  214. AZ::Uuid testComponent3_typeId = azrtti_typeid<Inspector_TestComponent2>();
  215. return classData.m_typeId == testComponent3_typeId;
  216. }
  217. class ComponentPaletteTests
  218. : public LeakDetectionFixture
  219. {
  220. public:
  221. ComponentPaletteTests()
  222. : LeakDetectionFixture()
  223. { }
  224. void SetUp() override
  225. {
  226. AZ::ComponentApplication::Descriptor componentApplicationDesc;
  227. componentApplicationDesc.m_useExistingAllocator = true;
  228. m_application = aznew ToolsTestApplication("ComponentPaletteTests");
  229. AZ::ComponentApplication::StartupParameters startupParameters;
  230. startupParameters.m_loadSettingsRegistry = false;
  231. m_application->Start(componentApplicationDesc, startupParameters);
  232. // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
  233. // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
  234. // in the unit tests.
  235. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
  236. }
  237. void TearDown() override
  238. {
  239. // Release all slice asset references, so AssetManager doens't complain.
  240. delete m_application;
  241. }
  242. public:
  243. ToolsTestApplication* m_application = nullptr;
  244. };
  245. // Test pushing slices to create news slices that could result in cyclic
  246. // dependency, e.g. push slice1 => slice2 and slice2 => slice1 at the same
  247. // time.
  248. TEST_F(ComponentPaletteTests, TestComponentPalleteUtilities)
  249. {
  250. AZ::SerializeContext* context = m_application->GetSerializeContext();
  251. // Register our test components (This process also reflects them to the appropriate contexts)
  252. auto* Inspector_TestComponent1Descriptor = Inspector_TestComponent1::CreateDescriptor();
  253. auto* Inspector_TestComponent2Descriptor = Inspector_TestComponent2::CreateDescriptor();
  254. auto* Inspector_TestComponent3Descriptor = Inspector_TestComponent3::CreateDescriptor();
  255. m_application->RegisterComponentDescriptor(Inspector_TestComponent1Descriptor);
  256. m_application->RegisterComponentDescriptor(Inspector_TestComponent2Descriptor);
  257. m_application->RegisterComponentDescriptor(Inspector_TestComponent3Descriptor);
  258. AZ::Uuid testComponent1_typeId = azrtti_typeid<Inspector_TestComponent1>();
  259. AZ::Uuid testComponent2_typeId = azrtti_typeid<Inspector_TestComponent2>();
  260. //////////////////////////////////////////////////////////////////////////
  261. // TEST OffersRequiredServices()
  262. //////////////////////////////////////////////////////////////////////////
  263. // Verify that OffersRequiredServices returns true with the services provided by the component.
  264. AZ::ComponentDescriptor::DependencyArrayType testComponent1_ProvidedServices;
  265. Inspector_TestComponent1::GetProvidedServices(testComponent1_ProvidedServices);
  266. AZ_TEST_ASSERT(testComponent1_ProvidedServices.size() == 1);
  267. const AZ::SerializeContext::ClassData* testComponent1_ClassData = context->FindClassData(testComponent1_typeId);
  268. EXPECT_TRUE(AzToolsFramework::OffersRequiredServices(testComponent1_ClassData, testComponent1_ProvidedServices));
  269. // Verify that OffersRequiredServices returns when given services provided by a different component
  270. AZ::ComponentDescriptor::DependencyArrayType testComponent2_ProvidedServices;
  271. Inspector_TestComponent2::GetProvidedServices(testComponent2_ProvidedServices);
  272. AZ_TEST_ASSERT(testComponent2_ProvidedServices.size() == 1);
  273. AZ_TEST_ASSERT(testComponent1_ProvidedServices != testComponent2_ProvidedServices);
  274. EXPECT_FALSE(AzToolsFramework::OffersRequiredServices(testComponent1_ClassData, testComponent2_ProvidedServices));
  275. // verify that OffersRequiredServices returns true when provided with an empty list of services
  276. EXPECT_TRUE(AzToolsFramework::OffersRequiredServices(testComponent1_ClassData, AZ::ComponentDescriptor::DependencyArrayType()));
  277. //////////////////////////////////////////////////////////////////////////
  278. // TEST IsAddableByUser()
  279. //////////////////////////////////////////////////////////////////////////
  280. // Verify that IsAddableByUser returns false when given a component that is not editable or viewable by the user
  281. EXPECT_FALSE(AzToolsFramework::ComponentPaletteUtil::IsAddableByUser(testComponent1_ClassData));
  282. // Verify that IsAddableByUser returns true when given a component that has the appropriate edit context reflection
  283. const AZ::SerializeContext::ClassData* testComponent2_ClassData = context->FindClassData(testComponent2_typeId);
  284. EXPECT_TRUE(AzToolsFramework::ComponentPaletteUtil::IsAddableByUser(testComponent2_ClassData));
  285. //////////////////////////////////////////////////////////////////////////
  286. // TEST ContainsEditableComponents()
  287. //////////////////////////////////////////////////////////////////////////
  288. // Remove reflection of Test Component 2 for the first test
  289. m_application->UnregisterComponentDescriptor(Inspector_TestComponent2Descriptor);
  290. context->EnableRemoveReflection();
  291. Inspector_TestComponent2::Reflect(context);
  292. context->DisableRemoveReflection();
  293. // Verify that there are no components that satisfy the AppearsInGameComponentMenu filter without service dependency conditions
  294. EXPECT_FALSE(AzToolsFramework::ComponentPaletteUtil::ContainsEditableComponents(context, &Filter_IsTestComponent2, AZ::ComponentDescriptor::DependencyArrayType()));
  295. // Reflect Test Component 2 for subsequent tests
  296. m_application->RegisterComponentDescriptor(Inspector_TestComponent2Descriptor);
  297. // Verify that there is now a component that satisfies the AppearsInGameComponentMenu filter without service dependency conditions
  298. EXPECT_TRUE(AzToolsFramework::ComponentPaletteUtil::ContainsEditableComponents(context, &Filter_IsTestComponent2, AZ::ComponentDescriptor::DependencyArrayType()));
  299. // Verify that true is returned here because test component 2 is editable and provides test component 2 services
  300. EXPECT_TRUE(AzToolsFramework::ComponentPaletteUtil::ContainsEditableComponents(context, &Filter_IsTestComponent2, testComponent2_ProvidedServices));
  301. // Verify that false is returned here because test component 2 does not provide any of the required services
  302. EXPECT_FALSE(AzToolsFramework::ComponentPaletteUtil::ContainsEditableComponents(context, &Filter_IsTestComponent2, testComponent1_ProvidedServices));
  303. // Verify that even though Test Component 1 exists and is returned by the filter and there are no services to match, false is returned
  304. // because Test Component 1 is not editable.
  305. EXPECT_FALSE(AzToolsFramework::ComponentPaletteUtil::ContainsEditableComponents(context, &Filter_IsTestComponent1, AZ::ComponentDescriptor::DependencyArrayType()));
  306. // Verify that true is returned here when a system component is editable
  307. EXPECT_TRUE(AzToolsFramework::ComponentPaletteUtil::ContainsEditableComponents(context, &Filter_IsTestComponent3, AZ::ComponentDescriptor::DependencyArrayType()));
  308. }
  309. }