Components.cpp 84 KB

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