BehaviorContext.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  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 <AzCore/UnitTest/TestTypes.h>
  9. #include <AzCore/RTTI/BehaviorContext.h>
  10. #include <AzCore/Outcome/Outcome.h>
  11. namespace UnitTest
  12. {
  13. enum class TestEnum
  14. {
  15. One = 1,
  16. Two = 2
  17. };
  18. }
  19. // give the enum values types
  20. namespace AZ
  21. {
  22. AZ_TYPE_INFO_SPECIALIZE(UnitTest::TestEnum, "{F8EBD52B-D805-4A47-82CA-41E1DC176BCD}")
  23. }
  24. namespace UnitTest
  25. {
  26. using Counter0 = CreationCounter<16, 0>;
  27. struct TypingStruct
  28. {
  29. AZ_TYPE_INFO(TypingStruct, "{89D2E524-9F90-49E9-8620-0DA8FF308222}")
  30. const char* m_stringValue = "";
  31. };
  32. class BehaviorClassTest
  33. : public LeakDetectionFixture
  34. {
  35. public:
  36. void SetUp() override
  37. {
  38. Counter0::Reset();
  39. m_context.Class<Counter0>("Counter0")
  40. ->Property("val", static_cast<int& (Counter0::*)()>(&Counter0::val), nullptr);
  41. m_context.Class<TypingStruct>("TypingStruct")
  42. ->Property("stringValue", BehaviorValueGetter(&TypingStruct::m_stringValue), BehaviorValueSetter(&TypingStruct::m_stringValue))
  43. ;
  44. m_counter0Class = m_context.m_typeToClassMap[azrtti_typeid<Counter0>()];
  45. m_typingClass = m_context.m_typeToClassMap[azrtti_typeid<TypingStruct>()];
  46. }
  47. AZ::BehaviorContext m_context;
  48. AZ::BehaviorClass* m_counter0Class;
  49. AZ::BehaviorClass* m_typingClass;
  50. };
  51. class BehaviorContextTestFixture
  52. : public LeakDetectionFixture
  53. {
  54. public:
  55. AZ::BehaviorContext m_behaviorContext;
  56. };
  57. TEST_F(BehaviorClassTest, BehaviorClass_Typing_ConstCharStar)
  58. {
  59. auto findIter = m_typingClass->m_properties.find("stringValue");
  60. EXPECT_TRUE(findIter != m_typingClass->m_properties.end());
  61. if (findIter != m_typingClass->m_properties.end())
  62. {
  63. EXPECT_EQ(AZ::BehaviorParameter::TR_STRING, findIter->second->m_getter->GetResult()->m_traits & AZ::BehaviorParameter::TR_STRING);
  64. }
  65. }
  66. TEST_F(BehaviorClassTest, BehaviorClass_Create_WasCreated)
  67. {
  68. EXPECT_EQ(0, Counter0::s_count);
  69. auto instance1 = m_counter0Class->Create();
  70. EXPECT_TRUE(instance1.IsValid());
  71. EXPECT_EQ(1, Counter0::s_count);
  72. EXPECT_EQ(0, Counter0::s_copied);
  73. EXPECT_EQ(0, Counter0::s_moved);
  74. m_counter0Class->Destroy(instance1);
  75. }
  76. TEST_F(BehaviorClassTest, BehaviorClass_CopyValid_WasCopied)
  77. {
  78. EXPECT_EQ(0, Counter0::s_count);
  79. auto instance1 = m_counter0Class->Create();
  80. EXPECT_TRUE(instance1.IsValid());
  81. EXPECT_EQ(1, Counter0::s_count);
  82. EXPECT_EQ(0, Counter0::s_copied);
  83. EXPECT_EQ(0, Counter0::s_moved);
  84. auto instance2 = m_counter0Class->Clone(instance1);
  85. EXPECT_TRUE(instance2.IsValid());
  86. EXPECT_EQ(2, Counter0::s_count);
  87. EXPECT_EQ(1, Counter0::s_copied);
  88. EXPECT_EQ(0, Counter0::s_moved);
  89. m_counter0Class->Destroy(instance2);
  90. m_counter0Class->Destroy(instance1);
  91. }
  92. TEST_F(BehaviorClassTest, BehaviorClass_CopyInvalid_WasNoop)
  93. {
  94. EXPECT_EQ(0, Counter0::s_count);
  95. auto instance1 = m_counter0Class->Clone(AZ::BehaviorObject());
  96. EXPECT_FALSE(instance1.IsValid());
  97. EXPECT_EQ(0, Counter0::s_count);
  98. EXPECT_EQ(0, Counter0::s_copied);
  99. EXPECT_EQ(0, Counter0::s_moved);
  100. m_counter0Class->Destroy(instance1);
  101. }
  102. TEST_F(BehaviorClassTest, BehaviorClass_Move_WasMoved)
  103. {
  104. EXPECT_EQ(0, Counter0::s_count);
  105. auto instance1 = m_counter0Class->Create();
  106. EXPECT_TRUE(instance1.IsValid());
  107. EXPECT_EQ(1, Counter0::s_count);
  108. EXPECT_EQ(0, Counter0::s_copied);
  109. EXPECT_EQ(0, Counter0::s_moved);
  110. auto instance2 = m_counter0Class->Move(AZStd::move(instance1));
  111. EXPECT_TRUE(instance2.IsValid());
  112. EXPECT_EQ(1, Counter0::s_count);
  113. EXPECT_EQ(0, Counter0::s_copied);
  114. EXPECT_EQ(1, Counter0::s_moved);
  115. m_counter0Class->Destroy(instance2);
  116. }
  117. TEST_F(BehaviorClassTest, BehaviorClass_MoveInvalid_WasNoop)
  118. {
  119. EXPECT_EQ(0, Counter0::s_count);
  120. auto instance1 = m_counter0Class->Move(AZ::BehaviorObject());
  121. EXPECT_FALSE(instance1.IsValid());
  122. EXPECT_EQ(0, Counter0::s_count);
  123. EXPECT_EQ(0, Counter0::s_copied);
  124. EXPECT_EQ(0, Counter0::s_moved);
  125. m_counter0Class->Destroy(instance1);
  126. }
  127. class ClassWithConstMethod
  128. {
  129. public:
  130. AZ_TYPE_INFO(ClassWithConstMethod, "{39235130-3339-41F6-AC70-0D6EF6B5145D}");
  131. void ConstMethod() const
  132. {
  133. }
  134. };
  135. using BehaviorContextConstTest = LeakDetectionFixture;
  136. TEST_F(BehaviorContextConstTest, BehaviorContext_BindConstMethods_Compiles)
  137. {
  138. AZ::BehaviorContext bc;
  139. bc.Class<ClassWithConstMethod>()
  140. ->Method("ConstMethod", &ClassWithConstMethod::ConstMethod)
  141. ;
  142. }
  143. class EBusWithConstEvent
  144. : public AZ::EBusTraits
  145. {
  146. public:
  147. virtual void ConstEvent() const = 0;
  148. };
  149. using EBusWithConstEventBus = AZ::EBus<EBusWithConstEvent>;
  150. TEST_F(BehaviorContextConstTest, BehaviorContext_BindConstEvents_Compiles)
  151. {
  152. AZ::BehaviorContext bc;
  153. bc.EBus<EBusWithConstEventBus>("EBusWithConstEventBus")
  154. ->Event("ConstEvent", &EBusWithConstEvent::ConstEvent)
  155. ;
  156. }
  157. void MethodAcceptingTemplate(const AZStd::vector<int>&)
  158. { }
  159. TEST_F(BehaviorContextTestFixture, OnDemandReflection_Unreflect_IsRemoved)
  160. {
  161. // Test reflecting with OnDemandReflection
  162. m_behaviorContext.Method("TestTemplatedOnDemandReflection", &MethodAcceptingTemplate);
  163. EXPECT_TRUE(m_behaviorContext.IsOnDemandTypeReflected(azrtti_typeid<AZStd::vector<int>>()));
  164. EXPECT_NE(m_behaviorContext.m_typeToClassMap.find(azrtti_typeid<AZStd::vector<int>>()), m_behaviorContext.m_typeToClassMap.end());
  165. // Test unreflecting OnDemandReflection
  166. m_behaviorContext.EnableRemoveReflection();
  167. m_behaviorContext.Method("TestTemplatedOnDemandReflection", &MethodAcceptingTemplate);
  168. m_behaviorContext.DisableRemoveReflection();
  169. EXPECT_FALSE(m_behaviorContext.IsOnDemandTypeReflected(azrtti_typeid<AZStd::vector<int>>()));
  170. EXPECT_EQ(m_behaviorContext.m_typeToClassMap.find(azrtti_typeid<AZStd::vector<int>>()), m_behaviorContext.m_typeToClassMap.end());
  171. }
  172. // Used for on demand reflection to pick up the vector and string types
  173. AZStd::string globalMethodContainers(const AZStd::vector<AZStd::string>& value)
  174. {
  175. return value[0];
  176. }
  177. TEST_F(BehaviorContextTestFixture, ContainerMethods)
  178. {
  179. AZ::BehaviorContext behaviorContext;
  180. behaviorContext.Method("containerMethod", &globalMethodContainers);
  181. auto containerType = azrtti_typeid<AZStd::vector<AZStd::string>>();
  182. EXPECT_TRUE(behaviorContext.IsOnDemandTypeReflected(containerType));
  183. AZ::BehaviorMethod* insertMethod = nullptr;
  184. AZ::BehaviorMethod* sizeMethod = nullptr;
  185. AZ::BehaviorMethod* assignAtMethod = nullptr;
  186. const auto classIter(behaviorContext.m_typeToClassMap.find(containerType));
  187. EXPECT_FALSE(classIter == behaviorContext.m_typeToClassMap.end());
  188. const AZ::BehaviorClass* behaviorClass = classIter->second;
  189. if (behaviorClass)
  190. {
  191. auto methodIt = behaviorClass->m_methods.find("Insert");
  192. EXPECT_TRUE(methodIt != behaviorClass->m_methods.end());
  193. if (methodIt != behaviorClass->m_methods.end())
  194. {
  195. insertMethod = methodIt->second;
  196. }
  197. methodIt = behaviorClass->m_methods.find("Size");
  198. EXPECT_TRUE(methodIt != behaviorClass->m_methods.end());
  199. if (methodIt != behaviorClass->m_methods.end())
  200. {
  201. sizeMethod = methodIt->second;
  202. }
  203. methodIt = behaviorClass->m_methods.find("AssignAt");
  204. EXPECT_TRUE(methodIt != behaviorClass->m_methods.end());
  205. if (methodIt != behaviorClass->m_methods.end())
  206. {
  207. assignAtMethod = methodIt->second;
  208. }
  209. }
  210. EXPECT_TRUE(insertMethod != nullptr);
  211. EXPECT_TRUE(sizeMethod != nullptr);
  212. EXPECT_TRUE(assignAtMethod != nullptr);
  213. if (insertMethod && sizeMethod && assignAtMethod)
  214. {
  215. const int MaxParameterCount = 40;
  216. AZStd::vector<AZStd::string> container;
  217. // Insert
  218. {
  219. AZStd::array<AZ::BehaviorArgument, MaxParameterCount> params;
  220. AZ::BehaviorArgument* paramFirst(params.begin());
  221. AZ::BehaviorArgument* paramIter = paramFirst;
  222. AZ::Outcome<void,void> insertOutcome;
  223. AZ::BehaviorArgument result(&insertOutcome);
  224. paramIter->Set(&container);
  225. ++paramIter;
  226. // Index
  227. AZ::BehaviorArgument indexParameter;
  228. AZ::u64 index = 0;
  229. indexParameter.Set<AZ::u64>(&index);
  230. paramIter->Set(indexParameter);
  231. ++paramIter;
  232. // Value to insert
  233. AZ::BehaviorArgument strParameter;
  234. AZStd::string str = "Hello";
  235. strParameter.Set<AZStd::string>(&str);
  236. paramIter->Set(strParameter);
  237. ++paramIter;
  238. insertMethod->Call(paramFirst, static_cast<unsigned int>(params.size()), &result);
  239. EXPECT_FALSE(insertOutcome.IsSuccess());
  240. }
  241. // Size
  242. {
  243. AZStd::array<AZ::BehaviorArgument, MaxParameterCount> params;
  244. AZ::BehaviorArgument* paramFirst(params.begin());
  245. AZ::BehaviorArgument* paramIter = paramFirst;
  246. paramIter->Set(&container);
  247. ++paramIter;
  248. int containerSize = 0;
  249. AZ::BehaviorArgument result(&containerSize);
  250. sizeMethod->Call(paramFirst, static_cast<unsigned int>(params.size()), &result);
  251. int* sizePtr = result.GetAsUnsafe<int>();
  252. EXPECT_TRUE(sizePtr != nullptr);
  253. EXPECT_EQ(*sizePtr, 1);
  254. }
  255. // AssignAt
  256. {
  257. AZStd::array<AZ::BehaviorArgument, MaxParameterCount> params;
  258. AZ::BehaviorArgument* paramFirst(params.begin());
  259. AZ::BehaviorArgument* paramIter = paramFirst;
  260. paramIter->Set(&container);
  261. ++paramIter;
  262. // Index
  263. AZ::BehaviorArgument indexParameter;
  264. AZ::u64 index = 4;
  265. indexParameter.Set<AZ::u64>(&index);
  266. paramIter->Set(indexParameter);
  267. ++paramIter;
  268. // Value to insert
  269. AZ::BehaviorArgument strParameter;
  270. AZStd::string str = "Hello";
  271. strParameter.Set<AZStd::string>(&str);
  272. paramIter->Set(strParameter);
  273. ++paramIter;
  274. assignAtMethod->Call(paramFirst, static_cast<unsigned int>(params.size()));
  275. }
  276. // Size
  277. {
  278. AZStd::array<AZ::BehaviorArgument, MaxParameterCount> params;
  279. AZ::BehaviorArgument* paramFirst(params.begin());
  280. AZ::BehaviorArgument* paramIter = paramFirst;
  281. paramIter->Set(&container);
  282. ++paramIter;
  283. int containerSize = 0;
  284. AZ::BehaviorArgument result(&containerSize);
  285. sizeMethod->Call(paramFirst, static_cast<unsigned int>(params.size()), &result);
  286. int* sizePtr = result.GetAsUnsafe<int>();
  287. EXPECT_TRUE(sizePtr != nullptr);
  288. EXPECT_EQ(*sizePtr, 5);
  289. }
  290. }
  291. }
  292. class EBusWithAZStdVectorEvent
  293. : public AZ::EBusTraits
  294. {
  295. public:
  296. virtual AZStd::string MoveContainer(const AZStd::vector<int>&) = 0;
  297. virtual AZStd::pair<AZStd::string, AZStd::string> ExtractPair(const AZStd::unordered_map<AZStd::string, AZStd::string>&) = 0;
  298. };
  299. using EBusWithAZStdVectorEventBus = AZ::EBus<EBusWithAZStdVectorEvent>;
  300. class BehaviorEBusWithAZStdVectorHandler
  301. : public EBusWithAZStdVectorEventBus::Handler
  302. , public AZ::BehaviorEBusHandler
  303. {
  304. public:
  305. AZ_EBUS_BEHAVIOR_BINDER(BehaviorEBusWithAZStdVectorHandler, "{B372D229-AE1F-411D-882E-0984AA3DC6F7}", AZ::SystemAllocator
  306. , MoveContainer
  307. , ExtractPair
  308. );
  309. // User code
  310. AZStd::string MoveContainer(const AZStd::vector<int>& lvalueContainer) override
  311. {
  312. // you can get the index yourself or use the FN_xxx enum FN_OnEvent
  313. AZStd::string result{};
  314. CallResult(result, FN_MoveContainer, lvalueContainer);
  315. return result;
  316. }
  317. AZStd::pair<AZStd::string, AZStd::string> ExtractPair(const AZStd::unordered_map<AZStd::string, AZStd::string>& stringMap) override
  318. {
  319. AZStd::pair<AZStd::string, AZStd::string> result{};
  320. CallResult(result, FN_ExtractPair, stringMap);
  321. return result;
  322. }
  323. };
  324. TEST_F(BehaviorContextTestFixture, EBusHandlers_Events_OnDemandReflection_Parameters)
  325. {
  326. // Test reflecting with EBus handler with an event that accepts an AZStd::vector
  327. m_behaviorContext.EBus<EBusWithAZStdVectorEventBus>("EBusWithAZStdVectorEventBus")
  328. ->Handler<BehaviorEBusWithAZStdVectorHandler>();
  329. // Validate that OnDemandReflection for function parameters works
  330. const AZ::Uuid vectorIntTypeid = AZ::AzTypeInfo<AZStd::vector<int>>::Uuid();
  331. auto vectorIntClassIt = m_behaviorContext.m_typeToClassMap.find(vectorIntTypeid);
  332. EXPECT_NE(m_behaviorContext.m_typeToClassMap.end(), vectorIntClassIt);
  333. EXPECT_TRUE(m_behaviorContext.IsOnDemandTypeReflected(vectorIntTypeid));
  334. // Validate that OnDemandReflection for the return value works
  335. const AZ::Uuid stringTypeid = AZ::AzTypeInfo<AZStd::string>::Uuid();
  336. auto stringClassIt = m_behaviorContext.m_typeToClassMap.find(stringTypeid);
  337. EXPECT_NE(m_behaviorContext.m_typeToClassMap.end(), stringClassIt);
  338. // Validate that OnDemandReflection works for all handler member functions
  339. const AZ::Uuid stringToStringMapTypeid = AZ::AzTypeInfo<AZStd::unordered_map<AZStd::string, AZStd::string>>::Uuid();
  340. auto stringToStringMapClassIt = m_behaviorContext.m_typeToClassMap.find(stringToStringMapTypeid);
  341. EXPECT_NE(m_behaviorContext.m_typeToClassMap.end(), stringToStringMapClassIt);
  342. EXPECT_TRUE(m_behaviorContext.IsOnDemandTypeReflected(stringToStringMapTypeid));
  343. const AZ::Uuid pairStringStringTypeid = AZ::AzTypeInfo<AZStd::pair<AZStd::string, AZStd::string>>::Uuid();
  344. auto pairStringsTringTypeid = m_behaviorContext.m_typeToClassMap.find(pairStringStringTypeid);
  345. EXPECT_NE(m_behaviorContext.m_typeToClassMap.end(), pairStringsTringTypeid);
  346. EXPECT_TRUE(m_behaviorContext.IsOnDemandTypeReflected(pairStringStringTypeid));
  347. }
  348. void FuncWithAcceptsVectorWithPointerValueTypeByRef(AZStd::vector<int*>&)
  349. {
  350. }
  351. void FuncWithAcceptsVectorWithPointerValueTypeByConstRef(const AZStd::vector<int*>&)
  352. {
  353. }
  354. void FuncWithAcceptsVectorWithPointerValueTypeByPointer(AZStd::vector<int*>*)
  355. {
  356. }
  357. void FuncWithAcceptsVectorWithPointerValueTypeByConstPointer(const AZStd::vector<int*>*)
  358. {
  359. }
  360. void FuncWithAcceptsVectorWithPointerValueTypeByConst(const AZStd::vector<int*>)
  361. {
  362. }
  363. TEST_F(BehaviorContextTestFixture, MethodReflectionWithRefParam_DoesNotCauseAssert_WhenBoundToScriptContext)
  364. {
  365. m_behaviorContext.Method("MethodWithVectorParam", &FuncWithAcceptsVectorWithPointerValueTypeByRef);
  366. AZ::ScriptContext scriptContext;
  367. AZ_TEST_START_TRACE_SUPPRESSION;
  368. scriptContext.BindTo(&m_behaviorContext);
  369. AZ_TEST_STOP_TRACE_SUPPRESSION(0);
  370. }
  371. TEST_F(BehaviorContextTestFixture, MethodReflectionWithConstRefParam_DoesNotCauseAssert_WhenBoundToScriptContext)
  372. {
  373. m_behaviorContext.Method("MethodWithVectorParam", &FuncWithAcceptsVectorWithPointerValueTypeByConstRef);
  374. AZ::ScriptContext scriptContext;
  375. AZ_TEST_START_TRACE_SUPPRESSION;
  376. scriptContext.BindTo(&m_behaviorContext);
  377. AZ_TEST_STOP_TRACE_SUPPRESSION(0);
  378. }
  379. TEST_F(BehaviorContextTestFixture, MethodReflectionWithPointerParam_DoesNotCauseAssert_WhenBoundToScriptContext)
  380. {
  381. m_behaviorContext.Method("MethodWithVectorParam", &FuncWithAcceptsVectorWithPointerValueTypeByPointer);
  382. AZ::ScriptContext scriptContext;
  383. AZ_TEST_START_TRACE_SUPPRESSION;
  384. scriptContext.BindTo(&m_behaviorContext);
  385. AZ_TEST_STOP_TRACE_SUPPRESSION(0);
  386. }
  387. TEST_F(BehaviorContextTestFixture, MethodReflectionWithConstPointerParam_DoesNotCauseAssert_WhenBoundToScriptContext)
  388. {
  389. m_behaviorContext.Method("MethodWithVectorParam", &FuncWithAcceptsVectorWithPointerValueTypeByConstPointer);
  390. AZ::ScriptContext scriptContext;
  391. AZ_TEST_START_TRACE_SUPPRESSION;
  392. scriptContext.BindTo(&m_behaviorContext);
  393. AZ_TEST_STOP_TRACE_SUPPRESSION(0);
  394. }
  395. TEST_F(BehaviorContextTestFixture, MethodReflectionWithConstParam_DoesNotCauseAssert_WhenBoundToScriptContext)
  396. {
  397. m_behaviorContext.Method("MethodWithVectorParam", &FuncWithAcceptsVectorWithPointerValueTypeByConst);
  398. AZ::ScriptContext scriptContext;
  399. AZ_TEST_START_TRACE_SUPPRESSION;
  400. scriptContext.BindTo(&m_behaviorContext);
  401. AZ_TEST_STOP_TRACE_SUPPRESSION(0);
  402. }
  403. TEST_F(BehaviorContextTestFixture, MethodWhichReturnsAzEvent_WithNoAzBehaviorAzEventDescription_FailsValidation)
  404. {
  405. using TestAzEvent = AZ::Event<float>;
  406. auto TestMethodWhichReturnsAzEvent = [](TestAzEvent& testEvent) -> TestAzEvent&
  407. {
  408. return testEvent;
  409. };
  410. UnitTest::TestRunner::Instance().StartAssertTests();
  411. // Test reflecting function which returns AZ::Event
  412. m_behaviorContext.Method("TestMethodWhichReturnsAzEvent", TestMethodWhichReturnsAzEvent);
  413. int numErrors = UnitTest::TestRunner::Instance().StopAssertTests();
  414. EXPECT_EQ(1, numErrors);
  415. }
  416. TEST_F(BehaviorContextTestFixture, MethodWhichReturnsAzEvent_WithEmptyEventName_FailsValidation)
  417. {
  418. using TestAzEvent = AZ::Event<float>;
  419. auto TestMethodWhichReturnsAzEvent = [](TestAzEvent& testEvent) -> TestAzEvent&
  420. {
  421. return testEvent;
  422. };
  423. // Test reflecting function which returns AZ::Event
  424. AZ::BehaviorAzEventDescription behaviorEventDesc;
  425. // m_eventName member is not set, validation should fail
  426. behaviorEventDesc.m_parameterNames.push_back("Scale");
  427. UnitTest::TestRunner::Instance().StartAssertTests();
  428. m_behaviorContext.Method("TestMethodWhichReturnsAzEvent", TestMethodWhichReturnsAzEvent)
  429. ->Attribute(AZ::Script::Attributes::AzEventDescription, AZStd::move(behaviorEventDesc));
  430. int numErrors = UnitTest::TestRunner::Instance().StopAssertTests();
  431. EXPECT_EQ(1, numErrors);
  432. }
  433. TEST_F(BehaviorContextTestFixture, MethodWhichReturnsAzEvent_WithParameterNameWhichIsEmpty_FailsValidation)
  434. {
  435. using TestAzEvent = AZ::Event<float>;
  436. auto TestMethodWhichReturnsAzEvent = [](TestAzEvent& testEvent) -> TestAzEvent&
  437. {
  438. return testEvent;
  439. };
  440. // Test reflecting function which returns AZ::Event
  441. AZ::BehaviorAzEventDescription behaviorEventDesc;
  442. behaviorEventDesc.m_eventName = "TestAzEvent";
  443. behaviorEventDesc.m_parameterNames.push_back(""); // Parameter name is empty, validation should fail
  444. UnitTest::TestRunner::Instance().StartAssertTests();
  445. m_behaviorContext.Method("TestMethodWhichReturnsAzEvent", TestMethodWhichReturnsAzEvent)
  446. ->Attribute(AZ::Script::Attributes::AzEventDescription, AZStd::move(behaviorEventDesc));
  447. int numErrors = UnitTest::TestRunner::Instance().StopAssertTests();
  448. EXPECT_EQ(1, numErrors);
  449. }
  450. TEST_F(BehaviorContextTestFixture, MethodWhichReturnsAzEvent_WithMismatchNumberOfParameters_FailsValidation)
  451. {
  452. using TestAzEvent = AZ::Event<float>;
  453. auto TestMethodWhichReturnsAzEvent = [](TestAzEvent& testEvent) -> TestAzEvent&
  454. {
  455. return testEvent;
  456. };
  457. // Test reflecting function which returns AZ::Event
  458. AZ::BehaviorAzEventDescription behaviorEventDesc;
  459. behaviorEventDesc.m_eventName = "TestAzEvent";
  460. // The AZ Event accepts one parameters.
  461. // Two parameter names are being added here
  462. behaviorEventDesc.m_parameterNames.push_back("Scale");
  463. behaviorEventDesc.m_parameterNames.push_back("Size");
  464. UnitTest::TestRunner::Instance().StartAssertTests();
  465. m_behaviorContext.Method("TestMethodWhichReturnsAzEvent", TestMethodWhichReturnsAzEvent)
  466. ->Attribute(AZ::Script::Attributes::AzEventDescription, AZStd::move(behaviorEventDesc));
  467. int numErrors = UnitTest::TestRunner::Instance().StopAssertTests();
  468. EXPECT_LE(1, numErrors);
  469. }
  470. TEST_F(BehaviorContextTestFixture, MethodWhichReturnsAzEvent_WithCompleteAzBehaviorAzEventDescriptionription_PassesValidation)
  471. {
  472. using TestAzEvent = AZ::Event<float>;
  473. auto TestMethodWhichReturnsAzEvent = [](TestAzEvent& testEvent) -> TestAzEvent&
  474. {
  475. return testEvent;
  476. };
  477. // Test reflecting function which returns AZ::Event
  478. AZ::BehaviorAzEventDescription behaviorEventDesc;
  479. behaviorEventDesc.m_eventName = "TestAzEvent";
  480. behaviorEventDesc.m_parameterNames.push_back("Scale");
  481. UnitTest::TestRunner::Instance().StartAssertTests();
  482. m_behaviorContext.Method("TestMethodWhichReturnsAzEvent", TestMethodWhichReturnsAzEvent)
  483. ->Attribute(AZ::Script::Attributes::AzEventDescription, AZStd::move(behaviorEventDesc));
  484. int numErrors = UnitTest::TestRunner::Instance().StopAssertTests();
  485. EXPECT_EQ(0, numErrors);
  486. }
  487. class ClassWithEnumClass
  488. {
  489. public:
  490. AZ_TYPE_INFO(ClassWithEnumClass, "{DF867F22-00B6-4D8B-9967-B17E3CBA6AFC}");
  491. TestEnum m_testEnumValue = TestEnum::Two;
  492. };
  493. TEST_F(BehaviorContextTestFixture, DISABLED_ClassWithEnumClass_CanAccessEnumClass_WhenBound)
  494. {
  495. m_behaviorContext.Class<ClassWithEnumClass>("ClassWithEnumClass")
  496. ->Property("TestEnumValue", BehaviorValueProperty(&ClassWithEnumClass::m_testEnumValue))
  497. ;
  498. AZ::BehaviorClass* behaviorClass = m_behaviorContext.m_classes["ClassWithEnumClass"];
  499. AZ::BehaviorProperty* behaviorProperty = behaviorClass->m_properties["TestEnumValue"];
  500. AZ::BehaviorObject instance = behaviorClass->Create();
  501. // read the property that stores a class enum value
  502. {
  503. TestEnum enumValue = TestEnum::One;
  504. EXPECT_TRUE(behaviorProperty->m_getter->InvokeResult(enumValue, instance));
  505. EXPECT_EQ(TestEnum::Two, enumValue);
  506. }
  507. // now set the property to One and validate it
  508. {
  509. TestEnum enumValue = TestEnum::Two;
  510. EXPECT_TRUE(behaviorProperty->m_setter->Invoke(instance, TestEnum::One));
  511. EXPECT_TRUE(behaviorProperty->m_getter->InvokeResult(enumValue, instance));
  512. EXPECT_EQ(TestEnum::One, enumValue);
  513. }
  514. behaviorClass->Destroy(instance);
  515. }
  516. class BroadcastEBusWithLambda : public AZ::EBusTraits
  517. {
  518. public:
  519. static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
  520. static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
  521. int AddValues(int a, int b)
  522. {
  523. return a + b;
  524. }
  525. };
  526. using BroadcastEBusWithLambdaBus = AZ::EBus<BroadcastEBusWithLambda>;
  527. TEST_F(BehaviorContextTestFixture, BehaviorContext_BindLambdaToBroadcastEBus_Compiles)
  528. {
  529. AZ::BehaviorContext bc;
  530. bc.EBus<BroadcastEBusWithLambdaBus>("BroadcastEBusWithLambdaBus")
  531. ->Event(
  532. "TestBroadcast",
  533. [](BroadcastEBusWithLambda* handler, int a, int b)
  534. {
  535. handler->AddValues(a, b);
  536. })
  537. ->Event(
  538. "TestBroadcastWithReturn",
  539. [](BroadcastEBusWithLambda* handler, int a, int b) -> int
  540. {
  541. return handler->AddValues(a, b);
  542. })
  543. ;
  544. }
  545. class EventEBusWithLambda : public AZ::EBusTraits
  546. {
  547. public:
  548. static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
  549. static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
  550. typedef int BusIdType;
  551. int AddValues(int a, int b)
  552. {
  553. return a + b;
  554. }
  555. };
  556. using EventEBusWithLambdaBus = AZ::EBus<EventEBusWithLambda>;
  557. TEST_F(BehaviorContextTestFixture, BehaviorContext_BindLambdaToEventEBus_Compiles)
  558. {
  559. AZ::BehaviorContext bc;
  560. bc.EBus<EventEBusWithLambdaBus>("EventEBusWithLambdaBus")
  561. ->Event(
  562. "TestEvent",
  563. [](EventEBusWithLambda* handler, int a, int b)
  564. {
  565. handler->AddValues(a, b);
  566. })
  567. ->Event(
  568. "TestEventWithReturn",
  569. [](EventEBusWithLambda* handler, int a, int b) -> int
  570. {
  571. return handler->AddValues(a, b);
  572. })
  573. ;
  574. }
  575. } // namespace UnitTest