Components.cpp 84 KB

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