Components.cpp 84 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058
  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("ServiceA", 0x808b9021));
  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("ServiceD", 0xf0e164ae));
  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("ServiceB", 0x1982c19b)); }
  290. static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent) { dependent.push_back(AZ_CRC("ServiceE", 0x87e65438)); }
  291. static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible) { incompatible.push_back(AZ_CRC("ServiceF", 0x1eef0582)); }
  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("ServiceB", 0x1982c19b)); }
  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("ServiceD", 0xf0e164ae)); }
  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("ServiceD", 0xf0e164ae)); dependent.push_back(AZ_CRC("ServiceA", 0x808b9021)); }
  331. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC("ServiceE", 0x87e65438)); }
  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("ServiceE", 0x87e65438)); }
  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("ServiceA", 0x808b9021)); }
  358. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC("ServiceF", 0x1eef0582)); }
  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("ServiceG")); }
  372. static void GetRequiredServices(ComponentDescriptor::DependencyArrayType& required) { required.push_back(AZ_CRC("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("ServiceH")); }
  386. static void GetRequiredServices(ComponentDescriptor::DependencyArrayType& required) { required.push_back(AZ_CRC("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("ServiceI")); }
  400. static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC("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("ServiceJ")); provided.push_back(AZ_CRC("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("ServiceK")); }
  427. static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent) { dependent.push_back(AZ_CRC("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("ServiceL")); }
  441. static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent) { dependent.push_back(AZ_CRC("ServiceA")); dependent.push_back(AZ_CRC("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("ServiceM")); }
  455. static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent) { dependent.push_back(AZ_CRC("ServiceA")); }
  456. static void GetRequiredServices(ComponentDescriptor::DependencyArrayType& dependent) { dependent.push_back(AZ_CRC("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("ServiceN")); }
  470. static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC("ServiceA")); provided.push_back(AZ_CRC("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("ServiceO")); }
  484. static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC("ServiceO")); provided.push_back(AZ_CRC("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("MyUserSettings", 0x65286904), UserSettings::CT_GLOBAL);
  916. AZ_TEST_ASSERT(myGlobalUserSettings);
  917. myGlobalUserSettings->m_intOption1 = 10;
  918. AZStd::intrusive_ptr<MyUserSettings> storedGlobalSettings = UserSettings::CreateFind<MyUserSettings>(AZ_CRC("MyUserSettings", 0x65286904), 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("MyUserSettings", 0x65286904), UserSettings::CT_LOCAL);
  922. AZ_TEST_ASSERT(myLocalUserSettings);
  923. myLocalUserSettings->m_intOption1 = 20;
  924. AZStd::intrusive_ptr<MyUserSettings> storedLocalSettings = UserSettings::CreateFind<MyUserSettings>(AZ_CRC("MyUserSettings", 0x65286904), 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("MyUserSettings", 0x65286904), UserSettings::CT_GLOBAL);
  932. AZ_TEST_ASSERT(!storedGlobalSettings);
  933. storedLocalSettings = UserSettings::Find<MyUserSettings>(AZ_CRC("MyUserSettings", 0x65286904), 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("MyUserSettings", 0x65286904), UserSettings::CT_GLOBAL);
  938. AZ_TEST_ASSERT(storedGlobalSettings);
  939. myGlobalUserSettings = UserSettings::CreateFind<MyUserSettings>(AZ_CRC("MyUserSettings", 0x65286904), UserSettings::CT_GLOBAL);
  940. AZ_TEST_ASSERT(myGlobalUserSettings == storedGlobalSettings);
  941. AZ_TEST_ASSERT(storedGlobalSettings->m_intOption1 == 10);
  942. storedLocalSettings = UserSettings::Find<MyUserSettings>(AZ_CRC("MyUserSettings", 0x65286904), UserSettings::CT_LOCAL);
  943. AZ_TEST_ASSERT(storedLocalSettings);
  944. myLocalUserSettings = UserSettings::CreateFind<MyUserSettings>(AZ_CRC("MyUserSettings", 0x65286904), 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("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("SomeService"));
  1498. dependencyList.push_back(AZ_CRC("AnotherService"));
  1499. dependencyList.push_back(AZ_CRC("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("SomeService"));
  1510. EXPECT_EQ(dependencyList[1], AZ_CRC("AnotherService"));
  1511. EXPECT_EQ(dependencyList[2], AZ_CRC("YetAnotherService"));
  1512. }
  1513. TEST_F(Components, RemoveDuplicateServicesOfAndAfterIterator_DuplicateAfterIterator_ReturnsTrueClearsDuplicates)
  1514. {
  1515. AZ::ComponentDescriptor::DependencyArrayType dependencyList;
  1516. dependencyList.push_back(AZ_CRC("SomeService"));
  1517. dependencyList.push_back(AZ_CRC("AnotherService"));
  1518. dependencyList.push_back(AZ_CRC("YetAnotherService"));
  1519. dependencyList.push_back(AZ_CRC("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("SomeService"));
  1531. EXPECT_EQ(dependencyList[1], AZ_CRC("AnotherService"));
  1532. EXPECT_EQ(dependencyList[2], AZ_CRC("YetAnotherService"));
  1533. }
  1534. TEST_F(Components, RemoveDuplicateServicesOfAndAfterIterator_2DuplicatesAfterIterator_ReturnsTrueClearsDuplicates)
  1535. {
  1536. AZ::ComponentDescriptor::DependencyArrayType dependencyList;
  1537. dependencyList.push_back(AZ_CRC("SomeService"));
  1538. dependencyList.push_back(AZ_CRC("AnotherService"));
  1539. dependencyList.push_back(AZ_CRC("SomeService"));
  1540. dependencyList.push_back(AZ_CRC("YetAnotherService"));
  1541. dependencyList.push_back(AZ_CRC("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("SomeService"));
  1553. EXPECT_EQ(dependencyList[1], AZ_CRC("AnotherService"));
  1554. EXPECT_EQ(dependencyList[2], AZ_CRC("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("SomeService"));
  1562. dependencyList.push_back(AZ_CRC("AnotherService"));
  1563. dependencyList.push_back(AZ_CRC("YetAnotherService"));
  1564. dependencyList.push_back(AZ_CRC("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("SomeService"));
  1578. EXPECT_EQ(dependencyList[1], AZ_CRC("AnotherService"));
  1579. EXPECT_EQ(dependencyList[2], AZ_CRC("YetAnotherService"));
  1580. EXPECT_EQ(dependencyList[3], AZ_CRC("SomeService"));
  1581. }
  1582. TEST_F(Components, RemoveDuplicateServicesOfAndAfterIterator_DuplicateBeforeAndAfterIterator_ReturnsTrueListUpdated)
  1583. {
  1584. AZ::ComponentDescriptor::DependencyArrayType dependencyList;
  1585. dependencyList.push_back(AZ_CRC("SomeService"));
  1586. dependencyList.push_back(AZ_CRC("AnotherService"));
  1587. dependencyList.push_back(AZ_CRC("SomeService"));
  1588. dependencyList.push_back(AZ_CRC("YetAnotherService"));
  1589. dependencyList.push_back(AZ_CRC("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("SomeService"));
  1603. EXPECT_EQ(dependencyList[1], AZ_CRC("AnotherService"));
  1604. EXPECT_EQ(dependencyList[2], AZ_CRC("SomeService"));
  1605. EXPECT_EQ(dependencyList[3], AZ_CRC("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