Components.cpp 84 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059
  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 "FileIOBaseTestTypes.h"
  9. #include <AzCore/Math/Crc.h>
  10. #include <AzCore/Math/Sfmt.h>
  11. #include <AzCore/Component/Component.h>
  12. #include <AzCore/Component/ComponentApplication.h>
  13. #include <AzCore/Component/TickBus.h>
  14. #include <AzCore/Component/EntityUtils.h>
  15. #include <AzCore/IO/Streamer/StreamerComponent.h>
  16. #include <AzCore/Serialization/ObjectStream.h>
  17. #include <AzCore/UserSettings/UserSettingsComponent.h>
  18. #include <AzCore/IO/SystemFile.h>
  19. #include <AzCore/Memory/AllocationRecords.h>
  20. #include <AzCore/Memory/IAllocator.h>
  21. #include <AzCore/Task/TaskGraphSystemComponent.h>
  22. #include <AzCore/UnitTest/TestTypes.h>
  23. #include <AzCore/std/parallel/containers/concurrent_unordered_set.h>
  24. #include <AZTestShared/Utils/Utils.h>
  25. #include <AzTest/Utils.h>
  26. #if defined(HAVE_BENCHMARK)
  27. #include <benchmark/benchmark.h>
  28. #endif
  29. using namespace AZ;
  30. using namespace AZ::Debug;
  31. namespace UnitTest
  32. {
  33. class Components
  34. : public LeakDetectionFixture
  35. {
  36. public:
  37. Components()
  38. : LeakDetectionFixture()
  39. {
  40. }
  41. };
  42. TEST_F(Components, Test)
  43. {
  44. ComponentApplication app;
  45. //////////////////////////////////////////////////////////////////////////
  46. // Create application environment code driven
  47. ComponentApplication::Descriptor appDesc;
  48. appDesc.m_memoryBlocksByteSize = 10 * 1024 * 1024;
  49. appDesc.m_recordingMode = AllocationRecords::Mode::RECORD_FULL;
  50. AZ::ComponentApplication::StartupParameters startupParameters;
  51. startupParameters.m_loadSettingsRegistry = false;
  52. Entity* systemEntity = app.Create(appDesc, startupParameters);
  53. systemEntity->CreateComponent<TaskGraphSystemComponent>();
  54. systemEntity->CreateComponent<StreamerComponent>();
  55. systemEntity->CreateComponent(AZ::Uuid("{CAE3A025-FAC9-4537-B39E-0A800A2326DF}")); // JobManager component
  56. systemEntity->CreateComponent(AZ::Uuid("{D5A73BCC-0098-4d1e-8FE4-C86101E374AC}")); // AssetDatabase component
  57. systemEntity->Init();
  58. systemEntity->Activate();
  59. app.Destroy();
  60. //////////////////////////////////////////////////////////////////////////
  61. //////////////////////////////////////////////////////////////////////////
  62. // Create application environment data driven
  63. systemEntity = app.Create(appDesc);
  64. systemEntity->Init();
  65. systemEntity->Activate();
  66. app.Destroy();
  67. //////////////////////////////////////////////////////////////////////////
  68. }
  69. //////////////////////////////////////////////////////////////////////////
  70. // Some component message bus, this is not really part of the component framework
  71. // but this is way components are suppose to communicate... using the EBus
  72. class SimpleComponentMessages
  73. : public AZ::EBusTraits
  74. {
  75. public:
  76. virtual ~SimpleComponentMessages() {}
  77. virtual void DoA(int a) = 0;
  78. virtual void DoB(int b) = 0;
  79. };
  80. typedef AZ::EBus<SimpleComponentMessages> SimpleComponentMessagesBus;
  81. //////////////////////////////////////////////////////////////////////////
  82. class SimpleComponent
  83. : public Component
  84. , public SimpleComponentMessagesBus::Handler
  85. , public TickBus::Handler
  86. {
  87. public:
  88. AZ_RTTI(SimpleComponent, "{6DFA17AF-014C-4624-B453-96E1F9807491}", Component)
  89. AZ_CLASS_ALLOCATOR(SimpleComponent, SystemAllocator);
  90. SimpleComponent()
  91. : m_a(0)
  92. , m_b(0)
  93. , m_isInit(false)
  94. , m_isActivated(false)
  95. {
  96. }
  97. //////////////////////////////////////////////////////////////////////////
  98. // Component base
  99. void Init() override { m_isInit = true; m_isTicked = false; }
  100. void Activate() override
  101. {
  102. SimpleComponentMessagesBus::Handler::BusConnect();
  103. // This is a very tricky (but valid example)... here we use the TickBus... thread safe
  104. // event queue, to queue the connection to be executed from the main thread, just before tick.
  105. // By using this even though TickBus is executed in single thread mode (main thread) for
  106. // performance reasons, you can technically issue command from multiple thread.
  107. // This requires advanced knowledge of the EBus and it's NOT recommended as a schema for
  108. // generic functionality. You should just call TickBus::Handler::BusConnect(GetEntityId()); in place
  109. // make sure you are doing this from the main thread.
  110. TickBus::QueueFunction(&TickBus::Handler::BusConnect, this);
  111. m_isActivated = true;
  112. }
  113. void Deactivate() override
  114. {
  115. SimpleComponentMessagesBus::Handler::BusDisconnect();
  116. TickBus::Handler::BusDisconnect();
  117. m_isActivated = false;
  118. }
  119. //////////////////////////////////////////////////////////////////////////
  120. //////////////////////////////////////////////////////////////////////////
  121. // SimpleComponentMessagesBus
  122. void DoA(int a) override { m_a = a; }
  123. void DoB(int b) override { m_b = b; }
  124. //////////////////////////////////////////////////////////////////////////
  125. //////////////////////////////////////////////////////////////////////////
  126. // TickBus
  127. void OnTick(float deltaTime, ScriptTimePoint time) override
  128. {
  129. m_isTicked = true;
  130. AZ_TEST_ASSERT(deltaTime >= 0);
  131. AZ_TEST_ASSERT(time.Get().time_since_epoch().count() != 0);
  132. }
  133. //////////////////////////////////////////////////////////////////////////
  134. int m_a;
  135. int m_b;
  136. bool m_isInit;
  137. bool m_isActivated;
  138. bool m_isTicked;
  139. };
  140. // Example how to implement custom desciptors
  141. class SimpleComponentDescriptor
  142. : public ComponentDescriptorHelper<SimpleComponent>
  143. {
  144. public:
  145. void Reflect(ReflectContext* /*reflection*/) const override
  146. {
  147. }
  148. };
  149. TEST_F(Components, SimpleTest)
  150. {
  151. SimpleComponentDescriptor descriptor;
  152. ComponentApplication componentApp;
  153. ComponentApplication::Descriptor desc;
  154. desc.m_useExistingAllocator = true;
  155. AZ::ComponentApplication::StartupParameters startupParameters;
  156. startupParameters.m_loadSettingsRegistry = false;
  157. Entity* systemEntity = componentApp.Create(desc, startupParameters);
  158. AZ_TEST_ASSERT(systemEntity);
  159. systemEntity->Init();
  160. Entity* entity = aznew Entity("My Entity");
  161. AZ_TEST_ASSERT(entity->GetState() == Entity::State::Constructed);
  162. // Make sure its possible to set the id of the entity before inited.
  163. AZ::EntityId newId = AZ::Entity::MakeId();
  164. entity->SetId(newId);
  165. AZ_TEST_ASSERT(entity->GetId() == newId);
  166. AZ_TEST_START_TRACE_SUPPRESSION;
  167. entity->SetId(SystemEntityId); // this is disallowed.
  168. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  169. // we can always create components directly when we have the factory
  170. // but it is intended to be used in generic way...
  171. SimpleComponent* comp1 = aznew SimpleComponent;
  172. AZ_TEST_ASSERT(comp1 != nullptr);
  173. AZ_TEST_ASSERT(comp1->GetEntity() == nullptr);
  174. AZ_TEST_ASSERT(comp1->GetId() == InvalidComponentId);
  175. bool result = entity->AddComponent(comp1);
  176. AZ_TEST_ASSERT(result);
  177. // try to find it
  178. SimpleComponent* comp2 = entity->FindComponent<SimpleComponent>();
  179. AZ_TEST_ASSERT(comp1 == comp2);
  180. // init entity
  181. entity->Init();
  182. AZ_TEST_ASSERT(entity->GetState() == Entity::State::Init);
  183. AZ_TEST_ASSERT(comp1->m_isInit);
  184. AZ_TEST_ASSERT(comp1->GetEntity() == entity);
  185. AZ_TEST_ASSERT(comp1->GetId() != InvalidComponentId); // id is set only for attached components
  186. // Make sure its NOT possible to set the id of the entity after INIT
  187. newId = AZ::Entity::MakeId();
  188. AZ::EntityId oldID = entity->GetId();
  189. AZ_TEST_START_TRACE_SUPPRESSION;
  190. entity->SetId(newId); // this should not work because its init.
  191. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  192. AZ_TEST_ASSERT(entity->GetId() == oldID); // id should be unaffected.
  193. // try to send a component message, since it's not active nobody should listen to it
  194. SimpleComponentMessagesBus::Broadcast(&SimpleComponentMessagesBus::Events::DoA, 1);
  195. AZ_TEST_ASSERT(comp1->m_a == 0); // it should still be 0
  196. // activate
  197. entity->Activate();
  198. AZ_TEST_ASSERT(entity->GetState() == Entity::State::Active);
  199. AZ_TEST_ASSERT(comp1->m_isActivated);
  200. // now the component should be active responsive to message
  201. SimpleComponentMessagesBus::Broadcast(&SimpleComponentMessagesBus::Events::DoA, 1);
  202. AZ_TEST_ASSERT(comp1->m_a == 1);
  203. // Make sure its NOT possible to set the id of the entity after Activate
  204. newId = AZ::Entity::MakeId();
  205. AZ_TEST_START_TRACE_SUPPRESSION;
  206. entity->SetId(newId); // this should not work because its init.
  207. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  208. // test the tick events
  209. componentApp.Tick(); // first tick will set-up timers and have 0 delta time
  210. AZ_TEST_ASSERT(comp1->m_isTicked);
  211. componentApp.Tick(); // this will dispatch actual valid delta time
  212. // make sure we can't remove components while active
  213. AZ_TEST_START_TRACE_SUPPRESSION;
  214. AZ_TEST_ASSERT(entity->RemoveComponent(comp1) == false);
  215. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  216. // make sure we can't add components while active
  217. {
  218. SimpleComponent anotherComp;
  219. AZ_TEST_START_TRACE_SUPPRESSION;
  220. AZ_TEST_ASSERT(entity->AddComponent(&anotherComp) == false);
  221. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  222. }
  223. AZ_TEST_START_TRACE_SUPPRESSION;
  224. AZ_TEST_ASSERT(entity->CreateComponent<SimpleComponent>() == nullptr);
  225. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  226. AZ_TEST_START_TRACE_SUPPRESSION;
  227. AZ_TEST_ASSERT(entity->CreateComponent(azrtti_typeid<SimpleComponent>()) == nullptr);
  228. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  229. // deactivate
  230. entity->Deactivate();
  231. AZ_TEST_ASSERT(entity->GetState() == Entity::State::Init);
  232. AZ_TEST_ASSERT(comp1->m_isActivated == false);
  233. // try to send a component message, since it's not active nobody should listen to it
  234. SimpleComponentMessagesBus::Broadcast(&SimpleComponentMessagesBus::Events::DoA, 2);
  235. AZ_TEST_ASSERT(comp1->m_a == 1);
  236. // make sure we can remove components
  237. AZ_TEST_ASSERT(entity->RemoveComponent(comp1));
  238. AZ_TEST_ASSERT(comp1->GetEntity() == nullptr);
  239. AZ_TEST_ASSERT(comp1->GetId() == InvalidComponentId);
  240. delete comp1;
  241. delete entity;
  242. descriptor.BusDisconnect(); // disconnect from the descriptor bus (so the app doesn't try to clean us up)
  243. }
  244. //////////////////////////////////////////////////////////////////////////
  245. // Component A
  246. class ComponentA
  247. : public Component
  248. {
  249. public:
  250. AZ_CLASS_ALLOCATOR(ComponentA, SystemAllocator);
  251. AZ_RTTI(ComponentA, "{4E93E03A-0B71-4630-ACCA-C6BB78E6DEB9}", Component)
  252. void Activate() override {}
  253. void Deactivate() override {}
  254. };
  255. /// Custom descriptor... example
  256. class ComponentADescriptor
  257. : public ComponentDescriptorHelper<ComponentA>
  258. {
  259. public:
  260. AZ_CLASS_ALLOCATOR(ComponentADescriptor, SystemAllocator);
  261. ComponentADescriptor()
  262. : m_isDependent(false)
  263. {
  264. }
  265. void GetProvidedServices(DependencyArrayType& provided, const Component* instance) const override
  266. {
  267. (void)instance;
  268. provided.push_back(AZ_CRC_CE("ServiceA"));
  269. }
  270. void GetDependentServices(DependencyArrayType& dependent, const Component* instance) const override
  271. {
  272. (void)instance;
  273. if (m_isDependent)
  274. {
  275. dependent.push_back(AZ_CRC_CE("ServiceD"));
  276. }
  277. }
  278. void Reflect(ReflectContext* /*reflection*/) const override {}
  279. bool m_isDependent;
  280. };
  281. //////////////////////////////////////////////////////////////////////////
  282. //////////////////////////////////////////////////////////////////////////
  283. // Component B
  284. class ComponentB
  285. : public Component
  286. {
  287. public:
  288. AZ_COMPONENT(ComponentB, "{30B266B3-AFD6-4173-8BEB-39134A3167E3}")
  289. void Activate() override {}
  290. void Deactivate() override {}
  291. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceB")); }
  292. static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent) { dependent.push_back(AZ_CRC_CE("ServiceE")); }
  293. static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible) { incompatible.push_back(AZ_CRC_CE("ServiceF")); }
  294. static void Reflect(ReflectContext* /*reflection*/) {}
  295. };
  296. //////////////////////////////////////////////////////////////////////////
  297. //////////////////////////////////////////////////////////////////////////
  298. // Component C
  299. class ComponentC
  300. : public Component
  301. {
  302. public:
  303. AZ_COMPONENT(ComponentC, "{A24C5D97-641F-4A92-90BB-647213A9D054}");
  304. void Activate() override {}
  305. void Deactivate() override {}
  306. static void GetRequiredServices(ComponentDescriptor::DependencyArrayType& required) { required.push_back(AZ_CRC_CE("ServiceB")); }
  307. static void Reflect(ReflectContext* /*reflection*/) {}
  308. };
  309. //////////////////////////////////////////////////////////////////////////
  310. //////////////////////////////////////////////////////////////////////////
  311. // Component D
  312. class ComponentD
  313. : public Component
  314. {
  315. public:
  316. AZ_COMPONENT(ComponentD, "{90888AD7-9D15-4356-8B95-C233A2E3083C}");
  317. void Activate() override {}
  318. void Deactivate() override {}
  319. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceD")); }
  320. static void Reflect(ReflectContext* /*reflection*/) {}
  321. };
  322. //////////////////////////////////////////////////////////////////////////
  323. //////////////////////////////////////////////////////////////////////////
  324. // Component E
  325. class ComponentE
  326. : public Component
  327. {
  328. public:
  329. AZ_COMPONENT(ComponentE, "{8D28A94A-9F70-4ADA-999E-D8A56A3048FB}", Component);
  330. void Activate() override {}
  331. void Deactivate() override {}
  332. static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent) { dependent.push_back(AZ_CRC_CE("ServiceD")); dependent.push_back(AZ_CRC_CE("ServiceA")); }
  333. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceE")); }
  334. static void Reflect(ReflectContext* /*reflection*/) {}
  335. };
  336. //////////////////////////////////////////////////////////////////////////
  337. //////////////////////////////////////////////////////////////////////////
  338. // Component E2 - provides ServiceE but has no dependencies
  339. class ComponentE2
  340. : public Component
  341. {
  342. public:
  343. AZ_COMPONENT(ComponentE2, "{33FE383C-92E0-48A4-A89A-91283DFC714A}", Component);
  344. void Activate() override {}
  345. void Deactivate() override {}
  346. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceE")); }
  347. static void Reflect(ReflectContext* /*reflection*/) {}
  348. };
  349. //////////////////////////////////////////////////////////////////////////
  350. //////////////////////////////////////////////////////////////////////////
  351. // Component F
  352. class ComponentF
  353. : public Component
  354. {
  355. public:
  356. AZ_COMPONENT(ComponentF, "{9A04F820-DFB6-42CF-9D1B-F970CEF1A02A}");
  357. void Activate() override {}
  358. void Deactivate() override {}
  359. static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible) { incompatible.push_back(AZ_CRC_CE("ServiceA")); }
  360. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceF")); }
  361. static void Reflect(ReflectContext* /*reflection*/) {}
  362. };
  363. //////////////////////////////////////////////////////////////////////////
  364. //////////////////////////////////////////////////////////////////////////
  365. // Component G - has cyclic dependency with H
  366. class ComponentG
  367. : public Component
  368. {
  369. public:
  370. AZ_COMPONENT(ComponentG, "{1CF8894A-CFE4-42FE-8127-63416DF734E1}");
  371. void Activate() override {}
  372. void Deactivate() override {}
  373. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceG")); }
  374. static void GetRequiredServices(ComponentDescriptor::DependencyArrayType& required) { required.push_back(AZ_CRC_CE("ServiceH")); }
  375. static void Reflect(ReflectContext* /*reflection*/) {}
  376. };
  377. //////////////////////////////////////////////////////////////////////////
  378. //////////////////////////////////////////////////////////////////////////
  379. // Component H - has cyclic dependency with G
  380. class ComponentH
  381. : public Component
  382. {
  383. public:
  384. AZ_COMPONENT(ComponentH, "{2FCF9245-B579-45D1-950B-A6779CA16F66}");
  385. void Activate() override {}
  386. void Deactivate() override {}
  387. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceH")); }
  388. static void GetRequiredServices(ComponentDescriptor::DependencyArrayType& required) { required.push_back(AZ_CRC_CE("ServiceG")); }
  389. static void Reflect(ReflectContext* /*reflection*/) {}
  390. };
  391. //////////////////////////////////////////////////////////////////////////
  392. //////////////////////////////////////////////////////////////////////////
  393. // Component I - incompatible with other components providing the same service
  394. class ComponentI
  395. : public Component
  396. {
  397. public:
  398. AZ_COMPONENT(ComponentI, "{5B509DB8-5D8A-4141-8701-4244E2F99025}");
  399. void Activate() override {}
  400. void Deactivate() override {}
  401. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceI")); }
  402. static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceI")); }
  403. static void Reflect(ReflectContext* /*reflection*/) {}
  404. };
  405. //////////////////////////////////////////////////////////////////////////
  406. //////////////////////////////////////////////////////////////////////////
  407. // Component J - "accidentally" provides same service twice
  408. class ComponentJ
  409. : public Component
  410. {
  411. public:
  412. AZ_COMPONENT(ComponentJ, "{67D56E5D-AB39-4BC3-AB1B-5B1F622E2A7F}");
  413. void Activate() override {}
  414. void Deactivate() override {}
  415. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceJ")); provided.push_back(AZ_CRC_CE("ServiceJ")); }
  416. static void Reflect(ReflectContext* /*reflection*/) {}
  417. };
  418. //////////////////////////////////////////////////////////////////////////
  419. //////////////////////////////////////////////////////////////////////////
  420. // Component K - depends on component that declared its provided service twice
  421. class ComponentK
  422. : public Component
  423. {
  424. public:
  425. AZ_COMPONENT(ComponentK, "{9FEB506A-03BD-485B-A5D5-133B34E290F5}");
  426. void Activate() override {}
  427. void Deactivate() override {}
  428. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceK")); }
  429. static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent) { dependent.push_back(AZ_CRC_CE("ServiceJ")); }
  430. static void Reflect(ReflectContext* /*reflection*/) {}
  431. };
  432. //////////////////////////////////////////////////////////////////////////
  433. //////////////////////////////////////////////////////////////////////////
  434. // Component L - "accidentally" depends on same service twice
  435. class ComponentL
  436. : public Component
  437. {
  438. public:
  439. AZ_COMPONENT(ComponentL, "{17A80803-C0F1-4595-A29D-AAD81D69B82E}");
  440. void Activate() override {}
  441. void Deactivate() override {}
  442. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceL")); }
  443. static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent) { dependent.push_back(AZ_CRC_CE("ServiceA")); dependent.push_back(AZ_CRC_CE("ServiceA")); }
  444. static void Reflect(ReflectContext* /*reflection*/) {}
  445. };
  446. //////////////////////////////////////////////////////////////////////////
  447. //////////////////////////////////////////////////////////////////////////
  448. // Component M - "accidentally" depends on and requires the same service
  449. class ComponentM
  450. : public Component
  451. {
  452. public:
  453. AZ_COMPONENT(ComponentM, "{74A118BC-2049-4C90-82B1-094934BD86F7}");
  454. void Activate() override {}
  455. void Deactivate() override {}
  456. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceM")); }
  457. static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent) { dependent.push_back(AZ_CRC_CE("ServiceA")); }
  458. static void GetRequiredServices(ComponentDescriptor::DependencyArrayType& dependent) { dependent.push_back(AZ_CRC_CE("ServiceA")); }
  459. static void Reflect(ReflectContext* /*reflection*/) {}
  460. };
  461. //////////////////////////////////////////////////////////////////////////
  462. //////////////////////////////////////////////////////////////////////////
  463. // Component N - "accidentally" lists an incompatibility twice
  464. class ComponentN
  465. : public Component
  466. {
  467. public:
  468. AZ_COMPONENT(ComponentN, "{B1026620-ED77-4897-B3EF-D03D4DDAF84B}");
  469. void Activate() override {}
  470. void Deactivate() override {}
  471. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceN")); }
  472. static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceA")); provided.push_back(AZ_CRC_CE("ServiceA")); }
  473. static void Reflect(ReflectContext* /*reflection*/) {}
  474. };
  475. //////////////////////////////////////////////////////////////////////////
  476. //////////////////////////////////////////////////////////////////////////
  477. // Component O - "accidentally" lists its own service twice in incompatibility list
  478. class ComponentO
  479. : public Component
  480. {
  481. public:
  482. AZ_COMPONENT(ComponentO, "{14916FA3-8A74-4974-AED9-43CB222C6883}");
  483. void Activate() override {}
  484. void Deactivate() override {}
  485. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceO")); }
  486. static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("ServiceO")); provided.push_back(AZ_CRC_CE("ServiceO")); }
  487. static void Reflect(ReflectContext* /*reflection*/) {}
  488. };
  489. //////////////////////////////////////////////////////////////////////////
  490. //////////////////////////////////////////////////////////////////////////
  491. // Component P - no services at all
  492. class ComponentP
  493. : public Component
  494. {
  495. public:
  496. AZ_COMPONENT(ComponentP, "{0D71F310-FEBC-418D-9C4B-847C89DF6606}");
  497. void Activate() override {}
  498. void Deactivate() override {}
  499. static void Reflect(ReflectContext* /*reflection*/) {}
  500. };
  501. //////////////////////////////////////////////////////////////////////////
  502. class ComponentDependency
  503. : public Components
  504. {
  505. protected:
  506. void SetUp() override
  507. {
  508. LeakDetectionFixture::SetUp();
  509. // component descriptors are cleaned up when application shuts down
  510. m_descriptorComponentA = aznew ComponentADescriptor;
  511. aznew ComponentB::DescriptorType;
  512. aznew ComponentC::DescriptorType;
  513. aznew ComponentD::DescriptorType;
  514. aznew ComponentE::DescriptorType;
  515. aznew ComponentE2::DescriptorType;
  516. aznew ComponentF::DescriptorType;
  517. aznew ComponentG::DescriptorType;
  518. aznew ComponentH::DescriptorType;
  519. aznew ComponentI::DescriptorType;
  520. aznew ComponentJ::DescriptorType;
  521. aznew ComponentK::DescriptorType;
  522. aznew ComponentL::DescriptorType;
  523. aznew ComponentM::DescriptorType;
  524. aznew ComponentN::DescriptorType;
  525. aznew ComponentO::DescriptorType;
  526. aznew ComponentP::DescriptorType;
  527. m_componentApp = aznew ComponentApplication();
  528. ComponentApplication::Descriptor desc;
  529. desc.m_useExistingAllocator = true;
  530. Entity* systemEntity = m_componentApp->Create(desc, {});
  531. systemEntity->Init();
  532. m_entity = aznew Entity();
  533. }
  534. void TearDown() override
  535. {
  536. delete m_entity;
  537. delete m_componentApp;
  538. LeakDetectionFixture::TearDown();
  539. }
  540. void CreateComponents_ABCDE()
  541. {
  542. m_entity->CreateComponent<ComponentA>();
  543. m_entity->CreateComponent<ComponentB>();
  544. m_entity->CreateComponent<ComponentC>();
  545. m_entity->CreateComponent<ComponentD>();
  546. m_entity->CreateComponent<ComponentE>();
  547. }
  548. ComponentADescriptor* m_descriptorComponentA;
  549. ComponentApplication* m_componentApp;
  550. Entity *m_entity; // an entity to mess with in each test
  551. };
  552. TEST_F(ComponentDependency, FixtureSanityCheck)
  553. {
  554. // Tests that Setup/TearDown work as expected
  555. }
  556. TEST_F(ComponentDependency, IsComponentReadyToAdd_ExaminesRequiredServices)
  557. {
  558. ComponentC* componentC = aznew ComponentC;
  559. ComponentDescriptor::DependencyArrayType requiredServices;
  560. EXPECT_FALSE(m_entity->IsComponentReadyToAdd(componentC, &requiredServices)); // we require B component to be added
  561. ASSERT_EQ(1, requiredServices.size());
  562. Crc32 requiredService = requiredServices[0];
  563. EXPECT_EQ(Crc32("ServiceB"), requiredService);
  564. m_entity->CreateComponent<ComponentB>();
  565. EXPECT_TRUE(m_entity->IsComponentReadyToAdd(componentC)); // we require B component to be added
  566. delete componentC;
  567. }
  568. TEST_F(ComponentDependency, IsComponentReadyToAdd_ExaminesIncompatibleServices)
  569. {
  570. ComponentA* componentA = m_entity->CreateComponent<ComponentA>();
  571. ComponentB* componentB = m_entity->CreateComponent<ComponentB>(); // B incompatible with F
  572. ComponentF* componentF = aznew ComponentF(); // F incompatible with A
  573. Entity::ComponentArrayType incompatible;
  574. EXPECT_FALSE(m_entity->IsComponentReadyToAdd(componentF, nullptr, &incompatible));
  575. EXPECT_EQ(2, incompatible.size());
  576. bool incompatibleWithComponentA = AZStd::find(incompatible.begin(), incompatible.end(), componentA) != incompatible.end();
  577. bool incompatibleWithComponentB = AZStd::find(incompatible.begin(), incompatible.end(), componentB) != incompatible.end();
  578. EXPECT_TRUE(incompatibleWithComponentA);
  579. EXPECT_TRUE(incompatibleWithComponentB);
  580. delete componentF;
  581. }
  582. TEST_F(ComponentDependency, Init_DoesNotChangeComponentOrder)
  583. {
  584. Entity::ComponentArrayType originalOrder = m_entity->GetComponents();
  585. m_entity->Init(); // Init should not change the component order
  586. EXPECT_EQ(originalOrder, m_entity->GetComponents());
  587. }
  588. TEST_F(ComponentDependency, Activate_SortsComponentsCorrectly)
  589. {
  590. CreateComponents_ABCDE();
  591. m_entity->Init();
  592. m_entity->Activate(); // here components will be sorted based on order
  593. const Entity::ComponentArrayType& components = m_entity->GetComponents();
  594. EXPECT_TRUE(components[0]->RTTI_IsTypeOf(AzTypeInfo<ComponentA>::Uuid()));
  595. EXPECT_TRUE(components[1]->RTTI_IsTypeOf(AzTypeInfo<ComponentD>::Uuid()));
  596. EXPECT_TRUE(components[2]->RTTI_IsTypeOf(AzTypeInfo<ComponentE>::Uuid()));
  597. EXPECT_TRUE(components[3]->RTTI_IsTypeOf(AzTypeInfo<ComponentB>::Uuid()));
  598. EXPECT_TRUE(components[4]->RTTI_IsTypeOf(AzTypeInfo<ComponentC>::Uuid()));
  599. }
  600. TEST_F(ComponentDependency, Deactivate_DoesNotChangeComponentOrder)
  601. {
  602. CreateComponents_ABCDE();
  603. m_entity->Init();
  604. m_entity->Activate();
  605. Entity::ComponentArrayType orderAfterActivate = m_entity->GetComponents();
  606. m_entity->Deactivate();
  607. EXPECT_EQ(orderAfterActivate, m_entity->GetComponents());
  608. }
  609. TEST_F(ComponentDependency, CachedDependency_PreventsComponentSort)
  610. {
  611. CreateComponents_ABCDE();
  612. m_entity->Init();
  613. m_entity->Activate();
  614. m_entity->Deactivate();
  615. Entity::ComponentArrayType originalSortedOrder = m_entity->GetComponents();
  616. m_descriptorComponentA->m_isDependent = true; // now A should depend on D (but only after we notify the entity of the change)
  617. m_entity->Activate();
  618. // order should be unchanged (because we cache the dependency)
  619. EXPECT_EQ(originalSortedOrder, m_entity->GetComponents());
  620. }
  621. TEST_F(ComponentDependency, InvalidatingDependency_CausesComponentSort)
  622. {
  623. CreateComponents_ABCDE();
  624. m_entity->Init();
  625. m_entity->Activate();
  626. m_entity->Deactivate();
  627. m_descriptorComponentA->m_isDependent = true; // now A should depend on D
  628. m_entity->InvalidateDependencies();
  629. m_entity->Activate();
  630. // check the new order
  631. const Entity::ComponentArrayType& components = m_entity->GetComponents();
  632. EXPECT_TRUE(components[0]->RTTI_IsTypeOf(AzTypeInfo<ComponentD>::Uuid()));
  633. EXPECT_TRUE(components[1]->RTTI_IsTypeOf(AzTypeInfo<ComponentA>::Uuid()));
  634. EXPECT_TRUE(components[2]->RTTI_IsTypeOf(AzTypeInfo<ComponentE>::Uuid()));
  635. EXPECT_TRUE(components[3]->RTTI_IsTypeOf(AzTypeInfo<ComponentB>::Uuid()));
  636. EXPECT_TRUE(components[4]->RTTI_IsTypeOf(AzTypeInfo<ComponentC>::Uuid()));
  637. }
  638. TEST_F(ComponentDependency, IsComponentReadyToRemove_ExaminesRequiredServices)
  639. {
  640. ComponentB* componentB = m_entity->CreateComponent<ComponentB>();
  641. ComponentC* componentC = m_entity->CreateComponent<ComponentC>();
  642. Entity::ComponentArrayType requiredComponents;
  643. EXPECT_FALSE(m_entity->IsComponentReadyToRemove(componentB, &requiredComponents)); // component C requires us
  644. ASSERT_EQ(1, requiredComponents.size());
  645. Component* requiredComponent = requiredComponents[0];
  646. EXPECT_EQ(componentC, requiredComponent);
  647. m_entity->RemoveComponent(componentC);
  648. delete componentC;
  649. EXPECT_TRUE(m_entity->IsComponentReadyToRemove(componentB)); // we should be ready for remove
  650. }
  651. // there was once a bug where, if multiple different component types provided the same service,
  652. // those components didn't necessarily sort before components that depended on that service
  653. TEST_F(ComponentDependency, DependingOnSameServiceFromTwoDifferentComponents_PutsServiceProvidersFirst)
  654. {
  655. m_entity->CreateComponent<ComponentD>(); // no dependencies
  656. Component* e2 = m_entity->CreateComponent<ComponentE2>(); // no dependencies
  657. Component* e = m_entity->CreateComponent<ComponentE>(); // depends on ServiceD
  658. Component* b = m_entity->CreateComponent<ComponentB>(); // depends on ServiceE (provided by E and E2)
  659. EXPECT_EQ(Entity::DependencySortResult::Success, m_entity->EvaluateDependencies());
  660. const AZ::Entity::ComponentArrayType& components = m_entity->GetComponents();
  661. auto locationB = AZStd::find(components.begin(), components.end(), b);
  662. auto locationE = AZStd::find(components.begin(), components.end(), e);
  663. auto locationE2 = AZStd::find(components.begin(), components.end(), e2);
  664. EXPECT_LT(locationE, locationB);
  665. EXPECT_LT(locationE2, locationB);
  666. }
  667. TEST_F(ComponentDependency, ComponentsThatProvideNoServices_SortedLast)
  668. {
  669. // components providing no services
  670. Component* c = m_entity->CreateComponent<ComponentC>(); // requires ServiceB
  671. Component* p = m_entity->CreateComponent<ComponentP>();
  672. // components providing a service
  673. Component* b = m_entity->CreateComponent<ComponentB>();
  674. Component* d = m_entity->CreateComponent<ComponentD>();
  675. Component* i = m_entity->CreateComponent<ComponentI>();
  676. Component* k = m_entity->CreateComponent<ComponentK>();
  677. // the only dependency between these components is that C requires B
  678. EXPECT_EQ(Entity::DependencySortResult::DSR_OK, m_entity->EvaluateDependencies());
  679. const AZ::Entity::ComponentArrayType& components = m_entity->GetComponents();
  680. const ptrdiff_t numComponents = m_entity->GetComponents().size();
  681. ptrdiff_t maxIndexOfComponentProvidingServices = PTRDIFF_MIN;
  682. for (Component* component : { b, d, i, k })
  683. {
  684. ptrdiff_t index = AZStd::distance(components.begin(), AZStd::find(components.begin(), components.end(), component));
  685. EXPECT_TRUE(index >= 0 && index < numComponents);
  686. maxIndexOfComponentProvidingServices = AZStd::max(maxIndexOfComponentProvidingServices, index);
  687. }
  688. ptrdiff_t minIndexOfComponentProvidingNoServices = PTRDIFF_MAX;
  689. for (Component* component : { c, p })
  690. {
  691. ptrdiff_t index = AZStd::distance(components.begin(), AZStd::find(components.begin(), components.end(), component));
  692. EXPECT_TRUE(index >= 0 && index < numComponents);
  693. minIndexOfComponentProvidingNoServices = AZStd::min(minIndexOfComponentProvidingNoServices, index);
  694. }
  695. EXPECT_LT(maxIndexOfComponentProvidingServices, minIndexOfComponentProvidingNoServices);
  696. }
  697. // there was once a bug where we didn't check requirements if there was only 1 component
  698. TEST_F(ComponentDependency, OneComponentRequiringService_FailsDueToMissingRequirements)
  699. {
  700. m_entity->CreateComponent<ComponentG>(); // requires ServiceH
  701. EXPECT_EQ(Entity::DependencySortResult::MissingRequiredService, m_entity->EvaluateDependencies());
  702. }
  703. // there was once a bug where we didn't check requirements of components that provided no services
  704. TEST_F(ComponentDependency, RequiringServiceWithoutProvidingService_FailsDueToMissingRequirements)
  705. {
  706. m_entity->CreateComponent<ComponentC>(); // requires ServiceB
  707. m_entity->CreateComponent<ComponentC>(); // requires ServiceB
  708. EXPECT_EQ(Entity::DependencySortResult::MissingRequiredService, m_entity->EvaluateDependencies());
  709. // there was also once a bug where failed sorts would result in components vanishing
  710. EXPECT_EQ(2, m_entity->GetComponents().size());
  711. }
  712. TEST_F(ComponentDependency, ComponentIncompatibleWithServiceItProvides_IsOkByItself)
  713. {
  714. m_entity->CreateComponent<ComponentI>(); // incompatible with ServiceI
  715. EXPECT_EQ(Entity::DependencySortResult::Success, m_entity->EvaluateDependencies());
  716. }
  717. TEST_F(ComponentDependency, TwoInstancesOfComponentIncompatibleWithServiceItProvides_AreIncompatible)
  718. {
  719. m_entity->CreateComponent<ComponentI>(); // incompatible with ServiceI
  720. m_entity->CreateComponent<ComponentI>(); // incompatible with ServiceI
  721. EXPECT_EQ(Entity::DependencySortResult::HasIncompatibleServices, m_entity->EvaluateDependencies());
  722. }
  723. // there was once a bug where failures due to cyclic dependencies would result in components vanishing
  724. TEST_F(ComponentDependency, FailureDueToCyclicDependencies_LeavesComponentsInPlace)
  725. {
  726. m_entity->CreateComponent<ComponentG>(); // requires ServiceH
  727. m_entity->CreateComponent<ComponentH>(); // requires ServiceG
  728. EXPECT_EQ(Entity::DependencySortResult::HasCyclicDependency, m_entity->EvaluateDependencies());
  729. // there was also once a bug where failed sorts would result in components vanishing
  730. EXPECT_EQ(2, m_entity->GetComponents().size());
  731. }
  732. TEST_F(ComponentDependency, ComponentWithoutDescriptor_FailsDueToUnregisteredDescriptor)
  733. {
  734. CreateComponents_ABCDE();
  735. // delete ComponentB's descriptor
  736. ComponentDescriptorBus::Event(azrtti_typeid<ComponentB>(), &ComponentDescriptorBus::Events::ReleaseDescriptor);
  737. EXPECT_EQ(Entity::DependencySortResult::DescriptorNotRegistered, m_entity->EvaluateDependencies());
  738. }
  739. TEST_F(ComponentDependency, StableSort_GetsSameResultsEveryTime)
  740. {
  741. // put a bunch of components on the entity
  742. CreateComponents_ABCDE();
  743. CreateComponents_ABCDE();
  744. CreateComponents_ABCDE();
  745. // throw in components whose dependencies could make the sort order ambiguous
  746. m_entity->CreateComponent<ComponentI>(); // I is incompatible with itself, but depends on nothing
  747. m_entity->CreateComponent<ComponentP>(); // P has no service declarations whatsoever
  748. m_entity->CreateComponent<ComponentP>();
  749. m_entity->CreateComponent<ComponentP>();
  750. m_entity->CreateComponent<ComponentK>(); // K depends on J (but J not present)
  751. m_entity->CreateComponent<ComponentK>();
  752. m_entity->CreateComponent<ComponentK>();
  753. // set Component IDs (using seeded random) so we get same results each time this test runs
  754. u32 randSeed[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
  755. Sfmt randGen(randSeed, AZ_ARRAY_SIZE(randSeed));
  756. AZStd::unordered_map<Component*, ComponentId> componentIds;
  757. for (Component* component : m_entity->GetComponents())
  758. {
  759. ComponentId id = randGen.Rand64();
  760. componentIds[component] = id;
  761. component->SetId(id);
  762. }
  763. // perform initial sort
  764. EXPECT_EQ(Entity::DependencySortResult::Success, m_entity->EvaluateDependencies());
  765. const AZ::Entity::ComponentArrayType originalSortedOrder = m_entity->GetComponents();
  766. // try shuffling the components a bunch of times
  767. // we should always get the same sorted results
  768. for (int iteration = 0; iteration < 50; ++iteration)
  769. {
  770. AZ::Entity::ComponentArrayType componentsToShuffle = m_entity->GetComponents();
  771. // remove all components from entity
  772. for (Component* component : componentsToShuffle)
  773. {
  774. m_entity->RemoveComponent(component);
  775. }
  776. // shuffle components
  777. for (int i = 0; i < 200; ++i)
  778. {
  779. size_t swapA = randGen.Rand64() % componentsToShuffle.size();
  780. size_t swapB = randGen.Rand64() % componentsToShuffle.size();
  781. AZStd::swap(componentsToShuffle[swapA], componentsToShuffle[swapB]);
  782. }
  783. // put components back on entity
  784. for (Component* component : componentsToShuffle)
  785. {
  786. m_entity->AddComponent(component);
  787. // removing components resets their ID
  788. // set it back to previous value so sort results are the same
  789. component->SetId(componentIds[component]);
  790. }
  791. EXPECT_EQ(Entity::DependencySortResult::Success, m_entity->EvaluateDependencies());
  792. const AZ::Entity::ComponentArrayType& sorted = m_entity->GetComponents();
  793. EXPECT_EQ(originalSortedOrder, sorted);
  794. if (HasFailure())
  795. {
  796. break;
  797. }
  798. };
  799. }
  800. // Check that invalid user input, in the form of services accidentally listed multiple times,
  801. // is handled appropriately and doesn't result in infinite loops.
  802. TEST_F(ComponentDependency, ComponentAccidentallyProvidingSameServiceTwice_IsOk)
  803. {
  804. m_entity->CreateComponent<ComponentJ>(); // provides ServiceJ twice
  805. EXPECT_EQ(Entity::DependencySortResult::Success, m_entity->EvaluateDependencies());
  806. }
  807. TEST_F(ComponentDependency, DependingOnComponentWhichAccidentallyProvidesSameServiceTwice_IsOk)
  808. {
  809. m_entity->CreateComponent<ComponentJ>(); // provides ServiceJ twice
  810. m_entity->CreateComponent<ComponentK>(); // depends on ServiceJ
  811. EXPECT_EQ(Entity::DependencySortResult::Success, m_entity->EvaluateDependencies());
  812. EXPECT_EQ(azrtti_typeid<ComponentJ>(), azrtti_typeid(m_entity->GetComponents()[0]));
  813. EXPECT_EQ(azrtti_typeid<ComponentK>(), azrtti_typeid(m_entity->GetComponents()[1]));
  814. }
  815. TEST_F(ComponentDependency, ComponentAccidentallyDependingOnSameServiceTwice_IsOk)
  816. {
  817. m_entity->CreateComponent<ComponentL>(); // depends on ServiceA twice
  818. m_entity->CreateComponent<ComponentA>();
  819. EXPECT_EQ(Entity::DependencySortResult::Success, m_entity->EvaluateDependencies());
  820. EXPECT_EQ(azrtti_typeid<ComponentA>(), azrtti_typeid(m_entity->GetComponents()[0]));
  821. EXPECT_EQ(azrtti_typeid<ComponentL>(), azrtti_typeid(m_entity->GetComponents()[1]));
  822. }
  823. TEST_F(ComponentDependency, ComponentAccidentallyDependingAndRequiringSameService_IsOk)
  824. {
  825. m_entity->CreateComponent<ComponentM>(); // depends on ServiceA and requires Service A
  826. m_entity->CreateComponent<ComponentA>();
  827. EXPECT_EQ(Entity::DependencySortResult::Success, m_entity->EvaluateDependencies());
  828. EXPECT_EQ(azrtti_typeid<ComponentA>(), azrtti_typeid(m_entity->GetComponents()[0]));
  829. EXPECT_EQ(azrtti_typeid<ComponentM>(), azrtti_typeid(m_entity->GetComponents()[1]));
  830. }
  831. TEST_F(ComponentDependency, ComponentAccidentallyListsIncompatibleServiceTwice_IsOkByItself)
  832. {
  833. m_entity->CreateComponent<ComponentN>(); // incompatible with ServiceA twice
  834. EXPECT_EQ(Entity::DependencySortResult::Success, m_entity->EvaluateDependencies());
  835. }
  836. TEST_F(ComponentDependency, ComponentAccidentallyListsIncompatibleServiceTwice_IncompatibilityStillDetected)
  837. {
  838. m_entity->CreateComponent<ComponentN>(); // incompatible with ServiceA twice
  839. m_entity->CreateComponent<ComponentA>();
  840. EXPECT_EQ(Entity::DependencySortResult::HasIncompatibleServices, m_entity->EvaluateDependencies());
  841. }
  842. TEST_F(ComponentDependency, ComponentAccidentallyListingIncompatibilityWithSelfTwice_IsOkByItself)
  843. {
  844. m_entity->CreateComponent<ComponentO>(); // incompatible with ServiceO twice
  845. EXPECT_EQ(Entity::DependencySortResult::Success, m_entity->EvaluateDependencies());
  846. }
  847. TEST_F(ComponentDependency, TwoInstancesOfComponentAccidentallyListingIncompatibilityWithSelfTwice_AreIncompatible)
  848. {
  849. m_entity->CreateComponent<ComponentO>(); // incompatible with ServiceO twice
  850. m_entity->CreateComponent<ComponentO>(); // incompatible with ServiceO twice
  851. EXPECT_EQ(Entity::DependencySortResult::HasIncompatibleServices, m_entity->EvaluateDependencies());
  852. }
  853. /**
  854. * UserSettingsComponent test
  855. */
  856. class UserSettingsTestApp
  857. : public ComponentApplication
  858. , public UserSettingsFileLocatorBus::Handler
  859. {
  860. AZ::Test::ScopedAutoTempDirectory m_tempDir;
  861. public:
  862. AZ_CLASS_ALLOCATOR(UserSettingsTestApp, SystemAllocator)
  863. AZStd::string ResolveFilePath(u32 providerId) override
  864. {
  865. auto filePath = AZ::IO::Path(m_tempDir.GetDirectory());
  866. if (providerId == UserSettings::CT_GLOBAL)
  867. {
  868. filePath /= "GlobalUserSettings.xml";
  869. }
  870. else if (providerId == UserSettings::CT_LOCAL)
  871. {
  872. filePath /= "LocalUserSettings.xml";
  873. }
  874. return filePath.Native();
  875. }
  876. void SetSettingsRegistrySpecializations(SettingsRegistryInterface::Specializations& specializations) override
  877. {
  878. ComponentApplication::SetSettingsRegistrySpecializations(specializations);
  879. specializations.Append("test");
  880. specializations.Append("usersettingstest");
  881. }
  882. };
  883. class MyUserSettings
  884. : public UserSettings
  885. {
  886. public:
  887. AZ_CLASS_ALLOCATOR(MyUserSettings, SystemAllocator);
  888. AZ_RTTI(MyUserSettings, "{ACC60C7B-60D8-4491-AD5D-42BA6656CC1F}", UserSettings);
  889. static void Reflect(AZ::SerializeContext* sc)
  890. {
  891. sc->Class<MyUserSettings>()
  892. ->Field("intOption1", &MyUserSettings::m_intOption1);
  893. }
  894. int m_intOption1;
  895. };
  896. using UserSettingsTestFixture = UnitTest::LeakDetectionFixture;
  897. TEST_F(UserSettingsTestFixture, Test)
  898. {
  899. UserSettingsTestApp app;
  900. //////////////////////////////////////////////////////////////////////////
  901. // Create application environment code driven
  902. ComponentApplication::Descriptor appDesc;
  903. appDesc.m_memoryBlocksByteSize = 10 * 1024 * 1024;
  904. AZ::ComponentApplication::StartupParameters startupParameters;
  905. startupParameters.m_loadSettingsRegistry = false;
  906. Entity* systemEntity = app.Create(appDesc, startupParameters);
  907. app.UserSettingsFileLocatorBus::Handler::BusConnect();
  908. MyUserSettings::Reflect(app.GetSerializeContext());
  909. UserSettingsComponent* globalUserSettingsComponent = systemEntity->CreateComponent<UserSettingsComponent>();
  910. AZ_TEST_ASSERT(globalUserSettingsComponent);
  911. globalUserSettingsComponent->SetProviderId(UserSettings::CT_GLOBAL);
  912. UserSettingsComponent* localUserSettingsComponent = systemEntity->CreateComponent<UserSettingsComponent>();
  913. AZ_TEST_ASSERT(localUserSettingsComponent);
  914. localUserSettingsComponent->SetProviderId(UserSettings::CT_LOCAL);
  915. systemEntity->Init();
  916. systemEntity->Activate();
  917. AZStd::intrusive_ptr<MyUserSettings> myGlobalUserSettings = UserSettings::CreateFind<MyUserSettings>(AZ_CRC_CE("MyUserSettings"), UserSettings::CT_GLOBAL);
  918. AZ_TEST_ASSERT(myGlobalUserSettings);
  919. myGlobalUserSettings->m_intOption1 = 10;
  920. AZStd::intrusive_ptr<MyUserSettings> storedGlobalSettings = UserSettings::CreateFind<MyUserSettings>(AZ_CRC_CE("MyUserSettings"), UserSettings::CT_GLOBAL);
  921. AZ_TEST_ASSERT(myGlobalUserSettings == storedGlobalSettings);
  922. AZ_TEST_ASSERT(storedGlobalSettings->m_intOption1 == 10);
  923. AZStd::intrusive_ptr<MyUserSettings> myLocalUserSettings = UserSettings::CreateFind<MyUserSettings>(AZ_CRC_CE("MyUserSettings"), UserSettings::CT_LOCAL);
  924. AZ_TEST_ASSERT(myLocalUserSettings);
  925. myLocalUserSettings->m_intOption1 = 20;
  926. AZStd::intrusive_ptr<MyUserSettings> storedLocalSettings = UserSettings::CreateFind<MyUserSettings>(AZ_CRC_CE("MyUserSettings"), UserSettings::CT_LOCAL);
  927. AZ_TEST_ASSERT(myLocalUserSettings == storedLocalSettings);
  928. AZ_TEST_ASSERT(storedLocalSettings->m_intOption1 == 20);
  929. // Deactivating will not trigger saving of user options, saving must be performed manually.
  930. UserSettingsComponentRequestBus::Broadcast(&UserSettingsComponentRequests::Save);
  931. systemEntity->Deactivate();
  932. // Deactivate() should have cleared all the registered user options
  933. storedGlobalSettings = UserSettings::Find<MyUserSettings>(AZ_CRC_CE("MyUserSettings"), UserSettings::CT_GLOBAL);
  934. AZ_TEST_ASSERT(!storedGlobalSettings);
  935. storedLocalSettings = UserSettings::Find<MyUserSettings>(AZ_CRC_CE("MyUserSettings"), UserSettings::CT_LOCAL);
  936. AZ_TEST_ASSERT(!storedLocalSettings);
  937. systemEntity->Activate();
  938. // Verify that upon re-activation, we successfully loaded all settings saved during deactivation
  939. storedGlobalSettings = UserSettings::Find<MyUserSettings>(AZ_CRC_CE("MyUserSettings"), UserSettings::CT_GLOBAL);
  940. AZ_TEST_ASSERT(storedGlobalSettings);
  941. myGlobalUserSettings = UserSettings::CreateFind<MyUserSettings>(AZ_CRC_CE("MyUserSettings"), UserSettings::CT_GLOBAL);
  942. AZ_TEST_ASSERT(myGlobalUserSettings == storedGlobalSettings);
  943. AZ_TEST_ASSERT(storedGlobalSettings->m_intOption1 == 10);
  944. storedLocalSettings = UserSettings::Find<MyUserSettings>(AZ_CRC_CE("MyUserSettings"), UserSettings::CT_LOCAL);
  945. AZ_TEST_ASSERT(storedLocalSettings);
  946. myLocalUserSettings = UserSettings::CreateFind<MyUserSettings>(AZ_CRC_CE("MyUserSettings"), UserSettings::CT_LOCAL);
  947. AZ_TEST_ASSERT(myLocalUserSettings == storedLocalSettings);
  948. AZ_TEST_ASSERT(storedLocalSettings->m_intOption1 == 20);
  949. myGlobalUserSettings = nullptr;
  950. storedGlobalSettings = nullptr;
  951. UserSettings::Release(myLocalUserSettings);
  952. UserSettings::Release(storedLocalSettings);
  953. app.Destroy();
  954. //////////////////////////////////////////////////////////////////////////
  955. }
  956. class SimpleEntityRefTestComponent
  957. : public Component
  958. {
  959. public:
  960. AZ_COMPONENT(SimpleEntityRefTestComponent, "{ED4D3C2A-454D-47B0-B04E-9A26DC55D03B}");
  961. SimpleEntityRefTestComponent(EntityId useId = EntityId())
  962. : m_entityId(useId) {}
  963. void Activate() override {}
  964. void Deactivate() override {}
  965. static void Reflect(ReflectContext* reflection)
  966. {
  967. SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(reflection);
  968. if (serializeContext)
  969. {
  970. serializeContext->Class<SimpleEntityRefTestComponent>()
  971. ->Field("entityId", &SimpleEntityRefTestComponent::m_entityId);
  972. }
  973. }
  974. EntityId m_entityId;
  975. };
  976. class ComplexEntityRefTestComponent
  977. : public Component
  978. {
  979. public:
  980. AZ_COMPONENT(ComplexEntityRefTestComponent, "{BCCCD213-4A77-474C-B432-48DE6DB2FE4D}");
  981. ComplexEntityRefTestComponent()
  982. : m_entityIdHashMap(3) // create some buckets to make sure we distribute elements even when we have less than load factor
  983. , m_entityIdHashSet(3) // create some buckets to make sure we distribute elements even when we have less than load factor
  984. {
  985. }
  986. void Activate() override {}
  987. void Deactivate() override {}
  988. static void Reflect(ReflectContext* reflection)
  989. {
  990. SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(reflection);
  991. if (serializeContext)
  992. {
  993. serializeContext->Class<ComplexEntityRefTestComponent>()
  994. ->Field("entityIds", &ComplexEntityRefTestComponent::m_entityIds)
  995. ->Field("entityIdHashMap", &ComplexEntityRefTestComponent::m_entityIdHashMap)
  996. ->Field("entityIdHashSet", &ComplexEntityRefTestComponent::m_entityIdHashSet)
  997. ->Field("entityId", &ComplexEntityRefTestComponent::m_entityIdIntMap);
  998. }
  999. }
  1000. AZStd::vector<EntityId> m_entityIds;
  1001. AZStd::unordered_map<EntityId, int> m_entityIdHashMap;
  1002. AZStd::unordered_set<EntityId> m_entityIdHashSet;
  1003. AZStd::map<EntityId, int> m_entityIdIntMap;
  1004. };
  1005. struct EntityIdRemapContainer
  1006. {
  1007. AZ_TYPE_INFO(EntityIdRemapContainer, "{63854212-37E9-480B-8E46-529682AB9EF7}");
  1008. AZ_CLASS_ALLOCATOR(EntityIdRemapContainer, AZ::SystemAllocator);
  1009. static void Reflect(SerializeContext& serializeContext)
  1010. {
  1011. serializeContext.Class<EntityIdRemapContainer>()
  1012. ->Field("Entity", &EntityIdRemapContainer::m_entity)
  1013. ->Field("Id", &EntityIdRemapContainer::m_id)
  1014. ->Field("otherId", &EntityIdRemapContainer::m_otherId)
  1015. ;
  1016. }
  1017. AZ::Entity* m_entity;
  1018. AZ::EntityId m_id;
  1019. AZ::EntityId m_otherId;
  1020. };
  1021. TEST_F(Components, EntityUtilsTest)
  1022. {
  1023. EntityId id1 = Entity::MakeId();
  1024. {
  1025. EntityId id2 = Entity::MakeId();
  1026. EntityId id3 = Entity::MakeId();
  1027. EntityId id4 = Entity::MakeId();
  1028. EntityId id5 = Entity::MakeId();
  1029. SimpleEntityRefTestComponent testComponent1(id1);
  1030. SimpleEntityRefTestComponent testComponent2(id2);
  1031. SimpleEntityRefTestComponent testComponent3(id3);
  1032. Entity testEntity(id1);
  1033. testEntity.AddComponent(&testComponent1);
  1034. testEntity.AddComponent(&testComponent2);
  1035. testEntity.AddComponent(&testComponent3);
  1036. SerializeContext context;
  1037. const ComponentDescriptor* entityRefTestDescriptor = SimpleEntityRefTestComponent::CreateDescriptor();
  1038. entityRefTestDescriptor->Reflect(&context);
  1039. Entity::Reflect(&context);
  1040. unsigned int nReplaced = EntityUtils::ReplaceEntityRefs(
  1041. &testEntity
  1042. , [=](EntityId key, bool /*isEntityId*/) -> EntityId
  1043. {
  1044. if (key == id1)
  1045. {
  1046. return id4;
  1047. }
  1048. if (key == id2)
  1049. {
  1050. return id5;
  1051. }
  1052. return key;
  1053. }
  1054. , &context
  1055. );
  1056. AZ_TEST_ASSERT(nReplaced == 2);
  1057. AZ_TEST_ASSERT(testEntity.GetId() == id1);
  1058. AZ_TEST_ASSERT(testComponent1.m_entityId == id4);
  1059. AZ_TEST_ASSERT(testComponent2.m_entityId == id5);
  1060. AZ_TEST_ASSERT(testComponent3.m_entityId == id3);
  1061. testEntity.RemoveComponent(&testComponent1);
  1062. testEntity.RemoveComponent(&testComponent2);
  1063. testEntity.RemoveComponent(&testComponent3);
  1064. delete entityRefTestDescriptor;
  1065. }
  1066. // Test entity IDs replacement in special containers (that require update as a result of EntityId replacement)
  1067. {
  1068. // special crafted id, so we can change the hashing structure as
  1069. // we replace the entities ID
  1070. EntityId id2(1);
  1071. EntityId id3(13);
  1072. EntityId replace2(14);
  1073. EntityId replace3(3);
  1074. SerializeContext context;
  1075. const ComponentDescriptor* entityRefTestDescriptor = ComplexEntityRefTestComponent::CreateDescriptor();
  1076. entityRefTestDescriptor->Reflect(&context);
  1077. Entity::Reflect(&context);
  1078. ComplexEntityRefTestComponent testComponent1;
  1079. Entity testEntity(id1);
  1080. testEntity.AddComponent(&testComponent1);
  1081. // vector (baseline, it should not change, same with all other AZStd containers not tested below)
  1082. testComponent1.m_entityIds.push_back(id2);
  1083. testComponent1.m_entityIds.push_back(id3);
  1084. testComponent1.m_entityIds.push_back(EntityId(32));
  1085. // hash map
  1086. testComponent1.m_entityIdHashMap.insert(AZStd::make_pair(id2, 1));
  1087. testComponent1.m_entityIdHashMap.insert(AZStd::make_pair(id3, 2));
  1088. testComponent1.m_entityIdHashMap.insert(AZStd::make_pair(EntityId(32), 3));
  1089. testComponent1.m_entityIdHashMap.insert(AZStd::make_pair(EntityId(5), 4));
  1090. testComponent1.m_entityIdHashMap.insert(AZStd::make_pair(EntityId(16), 5));
  1091. // hash set
  1092. testComponent1.m_entityIdHashSet.insert(id2);
  1093. testComponent1.m_entityIdHashSet.insert(id3);
  1094. testComponent1.m_entityIdHashSet.insert(EntityId(32));
  1095. testComponent1.m_entityIdHashSet.insert(EntityId(5));
  1096. testComponent1.m_entityIdHashSet.insert(EntityId(16));
  1097. // map
  1098. testComponent1.m_entityIdIntMap.insert(AZStd::make_pair(id2, 1));
  1099. testComponent1.m_entityIdIntMap.insert(AZStd::make_pair(id3, 2));
  1100. testComponent1.m_entityIdIntMap.insert(AZStd::make_pair(EntityId(32), 3));
  1101. testComponent1.m_entityIdIntMap.insert(AZStd::make_pair(EntityId(5), 4));
  1102. testComponent1.m_entityIdIntMap.insert(AZStd::make_pair(EntityId(16), 5));
  1103. // set is currently not supported in the serializer, when implemented if it uses the same Associative container storage (which it should) it should just work
  1104. unsigned int nReplaced = EntityUtils::ReplaceEntityRefs(
  1105. &testEntity
  1106. , [=](EntityId key, bool /*isEntityId*/) -> EntityId
  1107. {
  1108. if (key == id2)
  1109. {
  1110. return replace2;
  1111. }
  1112. if (key == id3)
  1113. {
  1114. return replace3;
  1115. }
  1116. return key;
  1117. }
  1118. , &context
  1119. );
  1120. AZ_TEST_ASSERT(nReplaced == 8);
  1121. AZ_TEST_ASSERT(testEntity.GetId() == id1);
  1122. AZ_TEST_ASSERT(AZStd::find(testComponent1.m_entityIds.begin(), testComponent1.m_entityIds.end(), id2) == testComponent1.m_entityIds.end());
  1123. AZ_TEST_ASSERT(AZStd::find(testComponent1.m_entityIds.begin(), testComponent1.m_entityIds.end(), replace2) != testComponent1.m_entityIds.end());
  1124. AZ_TEST_ASSERT(AZStd::find(testComponent1.m_entityIds.begin(), testComponent1.m_entityIds.end(), replace3) != testComponent1.m_entityIds.end());
  1125. AZ_TEST_ASSERT(AZStd::find(testComponent1.m_entityIds.begin(), testComponent1.m_entityIds.end(), EntityId(32)) != testComponent1.m_entityIds.end());
  1126. AZ_TEST_ASSERT(testComponent1.m_entityIdHashMap.find(id2) == testComponent1.m_entityIdHashMap.end());
  1127. AZ_TEST_ASSERT(testComponent1.m_entityIdHashMap.find(replace2) != testComponent1.m_entityIdHashMap.end());
  1128. AZ_TEST_ASSERT(testComponent1.m_entityIdHashMap.find(replace3) != testComponent1.m_entityIdHashMap.end());
  1129. AZ_TEST_ASSERT(testComponent1.m_entityIdHashMap.find(EntityId(32)) != testComponent1.m_entityIdHashMap.end());
  1130. AZ_TEST_ASSERT(testComponent1.m_entityIdHashSet.find(id2) == testComponent1.m_entityIdHashSet.end());
  1131. AZ_TEST_ASSERT(testComponent1.m_entityIdHashSet.find(replace2) != testComponent1.m_entityIdHashSet.end());
  1132. AZ_TEST_ASSERT(testComponent1.m_entityIdHashSet.find(replace3) != testComponent1.m_entityIdHashSet.end());
  1133. AZ_TEST_ASSERT(testComponent1.m_entityIdHashSet.find(EntityId(32)) != testComponent1.m_entityIdHashSet.end());
  1134. AZ_TEST_ASSERT(testComponent1.m_entityIdIntMap.find(id2) == testComponent1.m_entityIdIntMap.end());
  1135. AZ_TEST_ASSERT(testComponent1.m_entityIdIntMap.find(replace2) != testComponent1.m_entityIdIntMap.end());
  1136. AZ_TEST_ASSERT(testComponent1.m_entityIdIntMap.find(replace3) != testComponent1.m_entityIdIntMap.end());
  1137. AZ_TEST_ASSERT(testComponent1.m_entityIdIntMap.find(EntityId(32)) != testComponent1.m_entityIdIntMap.end());
  1138. testEntity.RemoveComponent(&testComponent1);
  1139. delete entityRefTestDescriptor;
  1140. }
  1141. }
  1142. // Temporary disabled. This will be re-enabled in the short term upon completion of SPEC-7384 and
  1143. // fixed in the long term upon completion of SPEC-4849
  1144. TEST_F(Components, DISABLED_EntityIdGeneration)
  1145. {
  1146. // Generate 1 million ids across 100 threads, and ensure that none collide
  1147. AZStd::concurrent_unordered_set<AZ::EntityId> entityIds;
  1148. auto GenerateIdThread = [&entityIds]()
  1149. {
  1150. for (size_t i = 0; i < AZ_TRAIT_UNIT_TEST_ENTITY_ID_GEN_TEST_COUNT; ++i)
  1151. {
  1152. EXPECT_TRUE(entityIds.insert(Entity::MakeId()));
  1153. }
  1154. };
  1155. //////////////////////////////////////////////////////////////////////////
  1156. // test generating EntityIDs from multiple threads
  1157. {
  1158. AZStd::vector<AZStd::thread> threads;
  1159. for (size_t i = 0; i < 100; ++i)
  1160. {
  1161. threads.emplace_back(GenerateIdThread);
  1162. }
  1163. for (AZStd::thread& thread : threads)
  1164. {
  1165. thread.join();
  1166. }
  1167. }
  1168. }
  1169. //=========================================================================
  1170. // Component Configuration
  1171. class ConfigurableComponentConfig : public ComponentConfig
  1172. {
  1173. public:
  1174. AZ_CLASS_ALLOCATOR(ConfigurableComponentConfig , SystemAllocator)
  1175. AZ_RTTI(ConfigurableComponentConfig, "{109C5A93-5571-4D45-BD2F-3938BF63AD83}", ComponentConfig);
  1176. int m_intVal = 0;
  1177. };
  1178. class ConfigurableComponent : public Component
  1179. {
  1180. public:
  1181. AZ_COMPONENT(ConfigurableComponent, "{E3103830-70F3-47AE-8F22-EF09BF3D57E9}");
  1182. static void Reflect(ReflectContext*) {}
  1183. int m_intVal = 0;
  1184. protected:
  1185. void Activate() override {}
  1186. void Deactivate() override {}
  1187. bool ReadInConfig(const ComponentConfig* baseConfig) override
  1188. {
  1189. if (auto config = azrtti_cast<const ConfigurableComponentConfig*>(baseConfig))
  1190. {
  1191. m_intVal = config->m_intVal;
  1192. return true;
  1193. }
  1194. return false;
  1195. }
  1196. bool WriteOutConfig(ComponentConfig* outBaseConfig) const override
  1197. {
  1198. if (auto config = azrtti_cast<ConfigurableComponentConfig*>(outBaseConfig))
  1199. {
  1200. config->m_intVal = m_intVal;
  1201. return true;
  1202. }
  1203. return false;
  1204. }
  1205. };
  1206. class UnconfigurableComponent : public Component
  1207. {
  1208. public:
  1209. AZ_COMPONENT(UnconfigurableComponent, "{772E3AA6-67AC-4655-B6C4-70BC45BAFD35}");
  1210. static void Reflect(ReflectContext*) {}
  1211. void Activate() override {}
  1212. void Deactivate() override {}
  1213. };
  1214. // fixture for testing ComponentConfig stuff
  1215. class ComponentConfiguration
  1216. : public Components
  1217. {
  1218. public:
  1219. void SetUp() override
  1220. {
  1221. Components::SetUp();
  1222. m_descriptors.emplace_back(ConfigurableComponent::CreateDescriptor());
  1223. m_descriptors.emplace_back(UnconfigurableComponent::CreateDescriptor());
  1224. }
  1225. void TearDown() override
  1226. {
  1227. m_descriptors.clear();
  1228. m_descriptors.set_capacity(0);
  1229. Components::TearDown();
  1230. }
  1231. AZStd::vector<AZStd::unique_ptr<ComponentDescriptor>> m_descriptors;
  1232. };
  1233. TEST_F(ComponentConfiguration, SetConfiguration_Succeeds)
  1234. {
  1235. ConfigurableComponentConfig config;
  1236. config.m_intVal = 5;
  1237. ConfigurableComponent component;
  1238. EXPECT_TRUE(component.SetConfiguration(config));
  1239. EXPECT_EQ(component.m_intVal, 5);
  1240. }
  1241. TEST_F(ComponentConfiguration, SetConfigurationOnActiveEntity_DoesNothing)
  1242. {
  1243. ConfigurableComponentConfig config;
  1244. config.m_intVal = 5;
  1245. Entity entity;
  1246. auto component = entity.CreateComponent<ConfigurableComponent>();
  1247. entity.Init();
  1248. entity.Activate();
  1249. EXPECT_EQ(Entity::State::Active, entity.GetState());
  1250. EXPECT_FALSE(component->SetConfiguration(config));
  1251. EXPECT_NE(component->m_intVal, 5);
  1252. }
  1253. TEST_F(ComponentConfiguration, SetWrongKindOfConfiguration_DoesNothing)
  1254. {
  1255. ComponentConfig config; // base config type
  1256. ConfigurableComponent component;
  1257. component.m_intVal = 19;
  1258. EXPECT_FALSE(component.SetConfiguration(config));
  1259. EXPECT_EQ(component.m_intVal, 19);
  1260. }
  1261. TEST_F(ComponentConfiguration, GetConfiguration_Succeeds)
  1262. {
  1263. ConfigurableComponent component;
  1264. component.m_intVal = 9;
  1265. ConfigurableComponentConfig config;
  1266. component.GetConfiguration(config);
  1267. EXPECT_EQ(component.m_intVal, 9);
  1268. }
  1269. TEST_F(ComponentConfiguration, SetConfigurationOnUnconfigurableComponent_Fails)
  1270. {
  1271. UnconfigurableComponent component;
  1272. ConfigurableComponentConfig config;
  1273. EXPECT_FALSE(component.SetConfiguration(config));
  1274. }
  1275. TEST_F(ComponentConfiguration, GetConfigurationOnUnconfigurableComponent_Fails)
  1276. {
  1277. UnconfigurableComponent component;
  1278. ConfigurableComponentConfig config;
  1279. EXPECT_FALSE(component.GetConfiguration(config));
  1280. }
  1281. //=========================================================================
  1282. TEST_F(Components, GenerateNewIdsAndFixRefsExistingMapTest)
  1283. {
  1284. SerializeContext context;
  1285. Entity::Reflect(&context);
  1286. EntityIdRemapContainer::Reflect(context);
  1287. const AZ::EntityId testId(21);
  1288. const AZ::EntityId nonMappedId(5465);
  1289. EntityIdRemapContainer testContainer1;
  1290. testContainer1.m_entity = aznew Entity(testId);
  1291. testContainer1.m_id = testId;
  1292. testContainer1.m_otherId = nonMappedId;
  1293. EntityIdRemapContainer clonedContainer;
  1294. context.CloneObjectInplace(clonedContainer, &testContainer1);
  1295. // Check cloned entity has same ids
  1296. EXPECT_NE(nullptr, clonedContainer.m_entity);
  1297. EXPECT_EQ(testContainer1.m_entity->GetId(), clonedContainer.m_entity->GetId());
  1298. EXPECT_EQ(testContainer1.m_id, clonedContainer.m_id);
  1299. EXPECT_EQ(testContainer1.m_otherId, clonedContainer.m_otherId);
  1300. // Generated new Ids in the testContainer store the results in the newIdMap
  1301. // The m_entity Entity id values should be remapped to a new value
  1302. AZStd::unordered_map<AZ::EntityId, AZ::EntityId> newIdMap;
  1303. EntityUtils::GenerateNewIdsAndFixRefs(&testContainer1, newIdMap, &context);
  1304. EXPECT_EQ(testContainer1.m_entity->GetId(), testContainer1.m_id);
  1305. EXPECT_NE(clonedContainer.m_entity->GetId(), testContainer1.m_entity->GetId());
  1306. EXPECT_NE(clonedContainer.m_id, testContainer1.m_id);
  1307. EXPECT_EQ(clonedContainer.m_otherId, testContainer1.m_otherId);
  1308. // Use the existing newIdMap to generate entityIds for the clonedContainer
  1309. // The testContainer1 and ClonedContainer should now have the same ids again
  1310. EntityUtils::GenerateNewIdsAndFixRefs(&clonedContainer, newIdMap, &context);
  1311. EXPECT_EQ(clonedContainer.m_entity->GetId(), clonedContainer.m_id);
  1312. EXPECT_EQ(testContainer1.m_entity->GetId(), clonedContainer.m_entity->GetId());
  1313. EXPECT_EQ(testContainer1.m_id, clonedContainer.m_id);
  1314. EXPECT_EQ(testContainer1.m_otherId, clonedContainer.m_otherId);
  1315. // Use a new map to generate entityIds for the clonedContainer
  1316. // The testContainer1 and ClonedContainer should have different ids again
  1317. AZStd::map<AZ::EntityId, AZ::EntityId> clonedIdMap; // Using regular map to test that different map types works with GenerateNewIdsAndFixRefs
  1318. EntityUtils::GenerateNewIdsAndFixRefs(&clonedContainer, clonedIdMap, &context);
  1319. EXPECT_EQ(clonedContainer.m_entity->GetId(), clonedContainer.m_id);
  1320. EXPECT_NE(testContainer1.m_entity->GetId(), clonedContainer.m_entity->GetId());
  1321. EXPECT_NE(testContainer1.m_id, clonedContainer.m_id);
  1322. EXPECT_EQ(testContainer1.m_otherId, clonedContainer.m_otherId);
  1323. delete testContainer1.m_entity;
  1324. delete clonedContainer.m_entity;
  1325. }
  1326. //=========================================================================
  1327. // Component Configuration versioning
  1328. // Version 1 of a configuration for a HydraComponent
  1329. class HydraConfigV1
  1330. : public ComponentConfig
  1331. {
  1332. public:
  1333. AZ_CLASS_ALLOCATOR(HydraConfigV1, SystemAllocator)
  1334. AZ_RTTI(HydraConfigV1, "{02198FDB-5CDB-4983-BC0B-CF1AA20FF2AF}", ComponentConfig);
  1335. int m_numHeads = 1;
  1336. };
  1337. // To add fields, inherit from previous version.
  1338. class HydraConfigV2
  1339. : public HydraConfigV1
  1340. {
  1341. public:
  1342. AZ_CLASS_ALLOCATOR(HydraConfigV2, SystemAllocator)
  1343. AZ_RTTI(HydraConfigV2, "{BC68C167-6B01-489C-8415-626455670C34}", HydraConfigV1);
  1344. int m_numArms = 2; // now the hydra has multiple arms, as well as multiple heads
  1345. };
  1346. // To make a breaking change, start from scratch by inheriting from base ComponentConfig.
  1347. class HydraConfigV3
  1348. : public ComponentConfig
  1349. {
  1350. public:
  1351. AZ_CLASS_ALLOCATOR(HydraConfigV3, SystemAllocator)
  1352. AZ_RTTI(HydraConfigV3, "{71C41829-AA51-4179-B8B4-3C278CBB26AA}", ComponentConfig);
  1353. int m_numHeads = 1;
  1354. int m_numArmsPerHead = 2; // now we require each head to have the same number of arms
  1355. };
  1356. // A component with many heads, and many arms
  1357. class HydraComponent
  1358. : public Component
  1359. {
  1360. public:
  1361. AZ_RTTI(HydraComponent, "", Component);
  1362. AZ_CLASS_ALLOCATOR(HydraComponent, AZ::SystemAllocator);
  1363. // serialized data
  1364. HydraConfigV3 m_config;
  1365. // runtime data
  1366. int m_numArms;
  1367. HydraComponent() = default;
  1368. void Activate() override
  1369. {
  1370. m_numArms = m_config.m_numHeads * m_config.m_numArmsPerHead;
  1371. }
  1372. void Deactivate() override {}
  1373. bool ReadInConfig(const ComponentConfig* baseConfig) override
  1374. {
  1375. if (auto v1 = azrtti_cast<const HydraConfigV1*>(baseConfig))
  1376. {
  1377. m_config.m_numHeads = v1->m_numHeads;
  1378. // v2 is based on v1
  1379. if (auto v2 = azrtti_cast<const HydraConfigV2*>(v1))
  1380. {
  1381. // v2 let user specify the total number of arms, but now we force each head to have same number of arms
  1382. if (v2->m_numHeads <= 0)
  1383. {
  1384. m_config.m_numArmsPerHead = 0;
  1385. }
  1386. else
  1387. {
  1388. m_config.m_numArmsPerHead = v2->m_numArms / v2->m_numHeads;
  1389. }
  1390. }
  1391. else
  1392. {
  1393. // v1 assumed 2 arms per head
  1394. m_config.m_numArmsPerHead = 2;
  1395. }
  1396. return true;
  1397. }
  1398. if (auto v3 = azrtti_cast<const HydraConfigV3*>(baseConfig))
  1399. {
  1400. m_config = *v3;
  1401. return true;
  1402. }
  1403. return false;
  1404. }
  1405. bool WriteOutConfig(ComponentConfig* outBaseConfig) const override
  1406. {
  1407. if (auto v1 = azrtti_cast<HydraConfigV1*>(outBaseConfig))
  1408. {
  1409. v1->m_numHeads = m_config.m_numHeads;
  1410. // v2 is based on v1
  1411. if (auto v2 = azrtti_cast<HydraConfigV2*>(v1))
  1412. {
  1413. v2->m_numArms = m_config.m_numHeads * m_config.m_numArmsPerHead;
  1414. }
  1415. return true;
  1416. }
  1417. if (auto v3 = azrtti_cast<HydraConfigV3*>(outBaseConfig))
  1418. {
  1419. *v3 = m_config;
  1420. return true;
  1421. }
  1422. return false;
  1423. }
  1424. };
  1425. TEST_F(Components, SetConfigurationV1_Succeeds)
  1426. {
  1427. HydraConfigV1 config;
  1428. config.m_numHeads = 3;
  1429. HydraComponent component;
  1430. EXPECT_TRUE(component.SetConfiguration(config));
  1431. EXPECT_EQ(component.m_config.m_numHeads, 3);
  1432. }
  1433. TEST_F(Components, GetConfigurationV1_Succeeds)
  1434. {
  1435. HydraConfigV1 config;
  1436. HydraComponent component;
  1437. component.m_config.m_numHeads = 8;
  1438. EXPECT_TRUE(component.GetConfiguration(config));
  1439. EXPECT_EQ(config.m_numHeads, component.m_config.m_numHeads);
  1440. }
  1441. TEST_F(Components, SetConfigurationV2_Succeeds)
  1442. {
  1443. HydraConfigV2 config;
  1444. config.m_numHeads = 4;
  1445. config.m_numArms = 12;
  1446. HydraComponent component;
  1447. EXPECT_TRUE(component.SetConfiguration(config));
  1448. EXPECT_EQ(component.m_config.m_numHeads, config.m_numHeads);
  1449. EXPECT_EQ(component.m_config.m_numArmsPerHead, 3);
  1450. }
  1451. TEST_F(Components, GetConfigurationV2_Succeeds)
  1452. {
  1453. HydraConfigV2 config;
  1454. HydraComponent component;
  1455. component.m_config.m_numHeads = 12;
  1456. component.m_config.m_numArmsPerHead = 1;
  1457. EXPECT_TRUE(component.GetConfiguration(config));
  1458. EXPECT_EQ(config.m_numHeads, component.m_config.m_numHeads);
  1459. EXPECT_EQ(config.m_numArms, 12);
  1460. }
  1461. TEST_F(Components, SetConfigurationV3_Succeeds)
  1462. {
  1463. HydraConfigV3 config;
  1464. config.m_numHeads = 2;
  1465. config.m_numArmsPerHead = 4;
  1466. HydraComponent component;
  1467. EXPECT_TRUE(component.SetConfiguration(config));
  1468. EXPECT_EQ(component.m_config.m_numHeads, config.m_numHeads);
  1469. EXPECT_EQ(component.m_config.m_numArmsPerHead, config.m_numArmsPerHead);
  1470. }
  1471. TEST_F(Components, GetConfigurationV3_Succeeds)
  1472. {
  1473. HydraConfigV3 config;
  1474. HydraComponent component;
  1475. component.m_config.m_numHeads = 94;
  1476. component.m_config.m_numArmsPerHead = 18;
  1477. EXPECT_TRUE(component.GetConfiguration(config));
  1478. EXPECT_EQ(config.m_numHeads, component.m_config.m_numHeads);
  1479. EXPECT_EQ(config.m_numArmsPerHead, component.m_config.m_numArmsPerHead);
  1480. }
  1481. TEST_F(Components, RemoveDuplicateServicesOfAndAfterIterator_EmptyList_ReturnsFalse)
  1482. {
  1483. AZ::ComponentDescriptor::DependencyArrayType dependencyList;
  1484. const ComponentDescriptor::DependencyArrayType::iterator dependencyIter = dependencyList.begin();
  1485. const bool servicesRemoved = EntityUtils::RemoveDuplicateServicesOfAndAfterIterator(dependencyIter, dependencyList, nullptr);
  1486. EXPECT_FALSE(servicesRemoved);
  1487. }
  1488. TEST_F(Components, RemoveDuplicateServicesOfAndAfterIterator_OnlyOneService_ReturnsFalse)
  1489. {
  1490. AZ::ComponentDescriptor::DependencyArrayType dependencyList;
  1491. dependencyList.push_back(AZ_CRC_CE("SomeService"));
  1492. const ComponentDescriptor::DependencyArrayType::iterator dependencyIter = dependencyList.begin();
  1493. const bool servicesRemoved = EntityUtils::RemoveDuplicateServicesOfAndAfterIterator(dependencyIter, dependencyList, nullptr);
  1494. EXPECT_FALSE(servicesRemoved);
  1495. }
  1496. TEST_F(Components, RemoveDuplicateServicesOfAndAfterIterator_NoDuplicates_ReturnsFalse)
  1497. {
  1498. AZ::ComponentDescriptor::DependencyArrayType dependencyList;
  1499. dependencyList.push_back(AZ_CRC_CE("SomeService"));
  1500. dependencyList.push_back(AZ_CRC_CE("AnotherService"));
  1501. dependencyList.push_back(AZ_CRC_CE("YetAnotherService"));
  1502. for (ComponentDescriptor::DependencyArrayType::iterator dependencyIter = dependencyList.begin();
  1503. dependencyIter != dependencyList.end();
  1504. ++dependencyIter)
  1505. {
  1506. const bool servicesRemoved = EntityUtils::RemoveDuplicateServicesOfAndAfterIterator(dependencyIter, dependencyList, nullptr);
  1507. EXPECT_FALSE(servicesRemoved);
  1508. }
  1509. // Make sure no services were removed.
  1510. EXPECT_EQ(dependencyList.size(), 3);
  1511. EXPECT_EQ(dependencyList[0], AZ_CRC_CE("SomeService"));
  1512. EXPECT_EQ(dependencyList[1], AZ_CRC_CE("AnotherService"));
  1513. EXPECT_EQ(dependencyList[2], AZ_CRC_CE("YetAnotherService"));
  1514. }
  1515. TEST_F(Components, RemoveDuplicateServicesOfAndAfterIterator_DuplicateAfterIterator_ReturnsTrueClearsDuplicates)
  1516. {
  1517. AZ::ComponentDescriptor::DependencyArrayType dependencyList;
  1518. dependencyList.push_back(AZ_CRC_CE("SomeService"));
  1519. dependencyList.push_back(AZ_CRC_CE("AnotherService"));
  1520. dependencyList.push_back(AZ_CRC_CE("YetAnotherService"));
  1521. dependencyList.push_back(AZ_CRC_CE("SomeService"));
  1522. ComponentDescriptor::DependencyArrayType::iterator dependencyIter = dependencyList.begin();
  1523. EXPECT_TRUE(EntityUtils::RemoveDuplicateServicesOfAndAfterIterator(dependencyIter, dependencyList, nullptr));
  1524. ++dependencyIter;
  1525. EXPECT_FALSE(EntityUtils::RemoveDuplicateServicesOfAndAfterIterator(dependencyIter, dependencyList, nullptr));
  1526. ++dependencyIter;
  1527. EXPECT_FALSE(EntityUtils::RemoveDuplicateServicesOfAndAfterIterator(dependencyIter, dependencyList, nullptr));
  1528. ++dependencyIter;
  1529. EXPECT_EQ(dependencyIter, dependencyList.end());
  1530. // Make sure the service was removed.
  1531. EXPECT_EQ(dependencyList.size(), 3);
  1532. EXPECT_EQ(dependencyList[0], AZ_CRC_CE("SomeService"));
  1533. EXPECT_EQ(dependencyList[1], AZ_CRC_CE("AnotherService"));
  1534. EXPECT_EQ(dependencyList[2], AZ_CRC_CE("YetAnotherService"));
  1535. }
  1536. TEST_F(Components, RemoveDuplicateServicesOfAndAfterIterator_2DuplicatesAfterIterator_ReturnsTrueClearsDuplicates)
  1537. {
  1538. AZ::ComponentDescriptor::DependencyArrayType dependencyList;
  1539. dependencyList.push_back(AZ_CRC_CE("SomeService"));
  1540. dependencyList.push_back(AZ_CRC_CE("AnotherService"));
  1541. dependencyList.push_back(AZ_CRC_CE("SomeService"));
  1542. dependencyList.push_back(AZ_CRC_CE("YetAnotherService"));
  1543. dependencyList.push_back(AZ_CRC_CE("SomeService"));
  1544. ComponentDescriptor::DependencyArrayType::iterator dependencyIter = dependencyList.begin();
  1545. EXPECT_TRUE(EntityUtils::RemoveDuplicateServicesOfAndAfterIterator(dependencyIter, dependencyList, nullptr));
  1546. ++dependencyIter;
  1547. EXPECT_FALSE(EntityUtils::RemoveDuplicateServicesOfAndAfterIterator(dependencyIter, dependencyList, nullptr));
  1548. ++dependencyIter;
  1549. EXPECT_FALSE(EntityUtils::RemoveDuplicateServicesOfAndAfterIterator(dependencyIter, dependencyList, nullptr));
  1550. ++dependencyIter;
  1551. EXPECT_EQ(dependencyIter, dependencyList.end());
  1552. // Make sure the service was removed.
  1553. EXPECT_EQ(dependencyList.size(), 3);
  1554. EXPECT_EQ(dependencyList[0], AZ_CRC_CE("SomeService"));
  1555. EXPECT_EQ(dependencyList[1], AZ_CRC_CE("AnotherService"));
  1556. EXPECT_EQ(dependencyList[2], AZ_CRC_CE("YetAnotherService"));
  1557. }
  1558. // The duplicate check logic only checks after the current iterator for performance reasons.
  1559. // This function is primarily used in loops that are already iterating over the service dependencies.
  1560. TEST_F(Components, RemoveDuplicateServicesOfAndAfterIterator_DuplicateBeforeIterator_ReturnsFalseDuplicateRemains)
  1561. {
  1562. AZ::ComponentDescriptor::DependencyArrayType dependencyList;
  1563. dependencyList.push_back(AZ_CRC_CE("SomeService"));
  1564. dependencyList.push_back(AZ_CRC_CE("AnotherService"));
  1565. dependencyList.push_back(AZ_CRC_CE("YetAnotherService"));
  1566. dependencyList.push_back(AZ_CRC_CE("SomeService"));
  1567. ComponentDescriptor::DependencyArrayType::iterator dependencyIter = dependencyList.begin();
  1568. // Skip the first element to leave a duplicate before the iterator.
  1569. ++dependencyIter;
  1570. EXPECT_FALSE(EntityUtils::RemoveDuplicateServicesOfAndAfterIterator(dependencyIter, dependencyList, nullptr));
  1571. ++dependencyIter;
  1572. EXPECT_FALSE(EntityUtils::RemoveDuplicateServicesOfAndAfterIterator(dependencyIter, dependencyList, nullptr));
  1573. ++dependencyIter;
  1574. EXPECT_FALSE(EntityUtils::RemoveDuplicateServicesOfAndAfterIterator(dependencyIter, dependencyList, nullptr));
  1575. ++dependencyIter;
  1576. EXPECT_EQ(dependencyIter, dependencyList.end());
  1577. // Make sure the service was not removed.
  1578. EXPECT_EQ(dependencyList.size(), 4);
  1579. EXPECT_EQ(dependencyList[0], AZ_CRC_CE("SomeService"));
  1580. EXPECT_EQ(dependencyList[1], AZ_CRC_CE("AnotherService"));
  1581. EXPECT_EQ(dependencyList[2], AZ_CRC_CE("YetAnotherService"));
  1582. EXPECT_EQ(dependencyList[3], AZ_CRC_CE("SomeService"));
  1583. }
  1584. TEST_F(Components, RemoveDuplicateServicesOfAndAfterIterator_DuplicateBeforeAndAfterIterator_ReturnsTrueListUpdated)
  1585. {
  1586. AZ::ComponentDescriptor::DependencyArrayType dependencyList;
  1587. dependencyList.push_back(AZ_CRC_CE("SomeService"));
  1588. dependencyList.push_back(AZ_CRC_CE("AnotherService"));
  1589. dependencyList.push_back(AZ_CRC_CE("SomeService"));
  1590. dependencyList.push_back(AZ_CRC_CE("YetAnotherService"));
  1591. dependencyList.push_back(AZ_CRC_CE("SomeService"));
  1592. ComponentDescriptor::DependencyArrayType::iterator dependencyIter = dependencyList.begin();
  1593. // Skip the first element to leave a duplicate before the iterator.
  1594. ++dependencyIter;
  1595. EXPECT_FALSE(EntityUtils::RemoveDuplicateServicesOfAndAfterIterator(dependencyIter, dependencyList, nullptr));
  1596. ++dependencyIter;
  1597. EXPECT_TRUE(EntityUtils::RemoveDuplicateServicesOfAndAfterIterator(dependencyIter, dependencyList, nullptr));
  1598. ++dependencyIter;
  1599. EXPECT_FALSE(EntityUtils::RemoveDuplicateServicesOfAndAfterIterator(dependencyIter, dependencyList, nullptr));
  1600. ++dependencyIter;
  1601. EXPECT_EQ(dependencyIter, dependencyList.end());
  1602. // Make sure one service was removed, and another not removed.
  1603. EXPECT_EQ(dependencyList.size(), 4);
  1604. EXPECT_EQ(dependencyList[0], AZ_CRC_CE("SomeService"));
  1605. EXPECT_EQ(dependencyList[1], AZ_CRC_CE("AnotherService"));
  1606. EXPECT_EQ(dependencyList[2], AZ_CRC_CE("SomeService"));
  1607. EXPECT_EQ(dependencyList[3], AZ_CRC_CE("YetAnotherService"));
  1608. }
  1609. class ComponentDeclImpl
  1610. : public AZ::Component
  1611. {
  1612. public:
  1613. AZ_COMPONENT_DECL(ComponentDeclImpl);
  1614. void Activate() override {}
  1615. void Deactivate() override {}
  1616. static void Reflect(AZ::ReflectContext*) {}
  1617. };
  1618. AZ_COMPONENT_IMPL(ComponentDeclImpl, "ComponentDeclImpl", "{8E5C2D28-8A6D-402E-8018-5AEC828CC3B1}");
  1619. template<class T, class U>
  1620. class TemplateComponent
  1621. : public ComponentDeclImpl
  1622. {
  1623. public:
  1624. AZ_COMPONENT_DECL((TemplateComponent, AZ_CLASS, AZ_CLASS));
  1625. };
  1626. AZ_COMPONENT_IMPL_INLINE((TemplateComponent, AZ_CLASS, AZ_CLASS), "TemplateComponent", "{E8B62C59-CAAC-466C-A583-4FCAABC399E6}", ComponentDeclImpl);
  1627. TEST_F(Components, ComponentDecl_ComponentImpl_Macros_ProvidesCompleteComponentDescriptor_Succeeds)
  1628. {
  1629. {
  1630. auto componentDeclImplDescriptor = AZStd::unique_ptr<AZ::ComponentDescriptor>(ComponentDeclImpl::CreateDescriptor());
  1631. ASSERT_NE(nullptr, componentDeclImplDescriptor);
  1632. auto componentDeclImplComponent = AZStd::unique_ptr<AZ::Component>(componentDeclImplDescriptor->CreateComponent());
  1633. EXPECT_NE(nullptr, componentDeclImplComponent);
  1634. }
  1635. {
  1636. using SpecializedComponent = TemplateComponent<int, int>;
  1637. auto specializedDescriptor = AZStd::unique_ptr<AZ::ComponentDescriptor>(SpecializedComponent::CreateDescriptor());
  1638. ASSERT_NE(nullptr, specializedDescriptor);
  1639. auto specializedDescriptorComponent = AZStd::unique_ptr<AZ::Component>(specializedDescriptor->CreateComponent());
  1640. EXPECT_NE(nullptr, specializedDescriptorComponent);
  1641. }
  1642. }
  1643. } // namespace UnitTest
  1644. #if defined(HAVE_BENCHMARK)
  1645. namespace Benchmark
  1646. {
  1647. static void BM_ComponentDependencySort(::benchmark::State& state)
  1648. {
  1649. // descriptors are cleaned up when ComponentApplication shuts down
  1650. aznew UnitTest::ComponentADescriptor;
  1651. aznew UnitTest::ComponentB::DescriptorType;
  1652. aznew UnitTest::ComponentC::DescriptorType;
  1653. aznew UnitTest::ComponentD::DescriptorType;
  1654. aznew UnitTest::ComponentE::DescriptorType;
  1655. aznew UnitTest::ComponentE2::DescriptorType;
  1656. ComponentApplication componentApp;
  1657. ComponentApplication::Descriptor desc;
  1658. desc.m_useExistingAllocator = true;
  1659. AZ::ComponentApplication::StartupParameters startupParameters;
  1660. startupParameters.m_loadSettingsRegistry = false;
  1661. Entity* systemEntity = componentApp.Create(desc, startupParameters);
  1662. systemEntity->Init();
  1663. while(state.KeepRunning())
  1664. {
  1665. // create components to sort
  1666. state.PauseTiming();
  1667. AZ::Entity::ComponentArrayType components;
  1668. AZ_Assert((state.range(0) % 6) == 0, "Multiple of 6 required");
  1669. while ((int)components.size() < state.range(0))
  1670. {
  1671. components.push_back(aznew UnitTest::ComponentA());
  1672. components.push_back(aznew UnitTest::ComponentB());
  1673. components.push_back(aznew UnitTest::ComponentC());
  1674. components.push_back(aznew UnitTest::ComponentD());
  1675. components.push_back(aznew UnitTest::ComponentE());
  1676. components.push_back(aznew UnitTest::ComponentE2());
  1677. }
  1678. state.ResumeTiming();
  1679. // do sort
  1680. Entity::DependencySortOutcome outcome = Entity::DependencySort(components);
  1681. // cleanup
  1682. state.PauseTiming();
  1683. AZ_Assert(outcome.IsSuccess(), "Sort failed");
  1684. for (Component* component : components)
  1685. {
  1686. delete component;
  1687. }
  1688. state.ResumeTiming();
  1689. }
  1690. }
  1691. BENCHMARK(BM_ComponentDependencySort)->Arg(6)->Arg(60);
  1692. } // Benchmark
  1693. #endif // HAVE_BENCHMARK