PythonGlobalsTests.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  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 "PythonTestingUtility.h"
  9. #include "PythonTraceMessageSink.h"
  10. #include <EditorPythonBindings/PythonCommon.h>
  11. #include <pybind11/embed.h>
  12. #include <pybind11/pybind11.h>
  13. #include <Source/PythonSystemComponent.h>
  14. #include <Source/PythonReflectionComponent.h>
  15. #include <Source/PythonProxyObject.h>
  16. #include <AzCore/RTTI/BehaviorContext.h>
  17. #include <AzFramework/StringFunc/StringFunc.h>
  18. namespace UnitTest
  19. {
  20. void AcceptTwoStrings([[maybe_unused]] AZStd::string stringValue1, [[maybe_unused]] AZStd::string stringValue2)
  21. {
  22. AZ_TracePrintf("python", stringValue1.empty() ? "stringValue1_is_empty" : "stringValue1_has_data");
  23. AZ_TracePrintf("python", stringValue2.empty() ? "stringValue2_is_empty" : "stringValue2_has_data");
  24. }
  25. //////////////////////////////////////////////////////////////////////////
  26. // test class/struts
  27. struct PythonGlobalsTester
  28. {
  29. AZ_TYPE_INFO(PythonGlobalsTester, "{00EC83FE-2E9D-42D0-8A59-2940669C7BCA}");
  30. enum GlobalEnums : AZ::u16
  31. {
  32. GE_NONE,
  33. GE_LUMBER = 101,
  34. GE_YARD
  35. };
  36. enum class MyTypes
  37. {
  38. One = 1,
  39. Two = 2,
  40. };
  41. static AZ::s32 s_staticValue;
  42. static AZ::u32 s_pingCount;
  43. static GlobalEnums s_result1;
  44. static GlobalEnums s_result2;
  45. static constexpr AZ::u8 s_one = 1;
  46. static AZ::Uuid s_myTypeId;
  47. static AZStd::string s_myString;
  48. static AZ::s32 GetValue()
  49. {
  50. return s_staticValue;
  51. }
  52. static void SetValue(AZ::s32 value)
  53. {
  54. s_staticValue = value;
  55. }
  56. static AZ::u32 Ping()
  57. {
  58. ++s_pingCount;
  59. return s_pingCount;
  60. }
  61. static void Reset()
  62. {
  63. s_pingCount = 0;
  64. s_staticValue = 0;
  65. s_result1 = GlobalEnums::GE_NONE;
  66. s_result2 = GlobalEnums::GE_NONE;
  67. s_myTypeId = AZ::TypeId::CreateString("{DEADBEE5-F983-4153-848A-EE9F99502811}");
  68. s_myString = AZStd::string("my string");
  69. }
  70. void Reflect(AZ::ReflectContext* context)
  71. {
  72. if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
  73. {
  74. // Methods
  75. behaviorContext->Method("ping", &PythonGlobalsTester::Ping)
  76. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  77. ->Attribute(AZ::Script::Attributes::Module, "test.pinger");
  78. behaviorContext->Method("reset", &PythonGlobalsTester::Reset)
  79. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation);
  80. behaviorContext->Method("accept_two_strings", AcceptTwoStrings)
  81. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation);
  82. // Property
  83. behaviorContext->Property("constantNumber", []() { return PythonGlobalsTester::GetValue(); }, nullptr)
  84. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation);
  85. behaviorContext->Property("coolProperty", &PythonGlobalsTester::GetValue, &PythonGlobalsTester::SetValue)
  86. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation);
  87. behaviorContext->Property("pingCount", BehaviorValueGetter(&s_pingCount), BehaviorValueSetter(&s_pingCount))
  88. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation);
  89. // Enums
  90. behaviorContext->EnumProperty<GlobalEnums::GE_LUMBER>("GE_LUMBER")
  91. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation);
  92. behaviorContext->EnumProperty<GlobalEnums::GE_YARD>("GE_YARD")
  93. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation);
  94. // azlmbr.my.enum.One
  95. behaviorContext->EnumProperty<aznumeric_cast<int>(MyTypes::One)>("One")
  96. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  97. ->Attribute(AZ::Script::Attributes::Module, "my.enum")
  98. ;
  99. // azlmbr.my.enum.Two
  100. behaviorContext->EnumProperty<aznumeric_cast<int>(MyTypes::Two)>("Two")
  101. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  102. ->Attribute(AZ::Script::Attributes::Module, "my.enum")
  103. ;
  104. behaviorContext->Property("result1", []() { return s_result1; }, [](GlobalEnums value) { s_result1 = value; })
  105. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation);
  106. behaviorContext->Property("result2", []() { return s_result2; }, [](GlobalEnums value) { s_result2 = value; })
  107. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation);
  108. // Constants
  109. behaviorContext->ConstantProperty("ONE", []() { return s_one; })
  110. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation);
  111. // azlmbr.constant.MY_TYPE
  112. behaviorContext->ConstantProperty("MY_TYPE", []() { return s_myTypeId; })
  113. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  114. ->Attribute(AZ::Script::Attributes::Module, "constant")
  115. ;
  116. // azlmbr.constant.MY_STRING
  117. behaviorContext->ConstantProperty("MY_STRING", []() { return s_myString; })
  118. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  119. ->Attribute(AZ::Script::Attributes::Module, "constant")
  120. ;
  121. }
  122. }
  123. };
  124. AZ::s32 PythonGlobalsTester::s_staticValue = 0;
  125. AZ::u32 PythonGlobalsTester::s_pingCount = 0;
  126. PythonGlobalsTester::GlobalEnums PythonGlobalsTester::s_result1 = PythonGlobalsTester::GlobalEnums::GE_NONE;
  127. PythonGlobalsTester::GlobalEnums PythonGlobalsTester::s_result2 = PythonGlobalsTester::GlobalEnums::GE_NONE;
  128. AZ::Uuid PythonGlobalsTester::s_myTypeId;
  129. AZStd::string PythonGlobalsTester::s_myString;
  130. //////////////////////////////////////////////////////////////////////////
  131. // fixtures
  132. struct PythonGlobalsTests
  133. : public PythonTestingFixture
  134. {
  135. PythonTraceMessageSink m_testSink;
  136. void SetUp() override
  137. {
  138. PythonTestingFixture::SetUp();
  139. PythonTestingFixture::RegisterComponentDescriptors();
  140. }
  141. void TearDown() override
  142. {
  143. // clearing up memory
  144. m_testSink.CleanUp();
  145. PythonTestingFixture::TearDown();
  146. }
  147. void Deactivate(AZ::Entity& entity)
  148. {
  149. auto editorPythonEventsInterface = AZ::Interface<AzToolsFramework::EditorPythonEventsInterface>::Get();
  150. if (editorPythonEventsInterface)
  151. {
  152. editorPythonEventsInterface->StopPython();
  153. }
  154. entity.Deactivate();
  155. }
  156. };
  157. //////////////////////////////////////////////////////////////////////////
  158. // tests
  159. TEST_F(PythonGlobalsTests, GlobalMethodTest)
  160. {
  161. PythonGlobalsTester pythonGlobalsTester;
  162. pythonGlobalsTester.Reflect(m_app.GetBehaviorContext());
  163. AZ::Entity e;
  164. Activate(e);
  165. SimulateEditorBecomingInitialized();
  166. try
  167. {
  168. pybind11::exec(R"(
  169. # testing global methods
  170. import azlmbr.globals
  171. import azlmbr.test.pinger
  172. azlmbr.globals.reset()
  173. for i in range(830):
  174. azlmbr.test.pinger.ping()
  175. )");
  176. }
  177. catch ([[maybe_unused]] const std::exception& e)
  178. {
  179. AZ_Error("UnitTest", false, "Failed on with Python exception: %s", e.what());
  180. }
  181. Deactivate(e);
  182. EXPECT_EQ(830, PythonGlobalsTester::s_pingCount);
  183. }
  184. TEST_F(PythonGlobalsTests, GlobalPropertyTest)
  185. {
  186. enum class LogTypes
  187. {
  188. Skip = 0,
  189. GlobalPropertyTest_NotNone,
  190. GlobalPropertyTest_Is40,
  191. GlobalPropertyTest_Is42,
  192. GlobalPropertyTest_PingWorked,
  193. };
  194. m_testSink.m_evaluateMessage = [](const char* window, const char* message) -> int
  195. {
  196. if (AzFramework::StringFunc::Equal(window, "python"))
  197. {
  198. if (AzFramework::StringFunc::Equal(message, "GlobalPropertyTest_NotNone"))
  199. {
  200. return static_cast<int>(LogTypes::GlobalPropertyTest_NotNone);
  201. }
  202. else if (AzFramework::StringFunc::Equal(message, "GlobalPropertyTest_Is40"))
  203. {
  204. return static_cast<int>(LogTypes::GlobalPropertyTest_Is40);
  205. }
  206. else if (AzFramework::StringFunc::Equal(message, "GlobalPropertyTest_Is42"))
  207. {
  208. return static_cast<int>(LogTypes::GlobalPropertyTest_Is42);
  209. }
  210. else if (AzFramework::StringFunc::Equal(message, "GlobalPropertyTest_PingWorked"))
  211. {
  212. return static_cast<int>(LogTypes::GlobalPropertyTest_PingWorked);
  213. }
  214. }
  215. return static_cast<int>(LogTypes::Skip);
  216. };
  217. PythonGlobalsTester pythonGlobalsTester;
  218. pythonGlobalsTester.Reflect(m_app.GetBehaviorContext());
  219. AZ::Entity e;
  220. Activate(e);
  221. SimulateEditorBecomingInitialized();
  222. try
  223. {
  224. pybind11::exec(R"(
  225. import azlmbr.globals
  226. import azlmbr.test.pinger
  227. # testing global properties
  228. if (azlmbr.globals.property.constantNumber == 0):
  229. print ('GlobalPropertyTest_NotNone')
  230. azlmbr.globals.property.coolProperty = 40
  231. if (azlmbr.globals.property.coolProperty == 40):
  232. print ('GlobalPropertyTest_Is40')
  233. azlmbr.globals.property.coolProperty = azlmbr.globals.property.coolProperty + 2
  234. if (azlmbr.globals.property.constantNumber == 42):
  235. print ('GlobalPropertyTest_Is42')
  236. azlmbr.globals.property.pingCount = 0
  237. for i in range(830):
  238. azlmbr.test.pinger.ping()
  239. if (azlmbr.globals.property.pingCount == 830):
  240. print ('GlobalPropertyTest_PingWorked')
  241. )");
  242. }
  243. catch ([[maybe_unused]] const std::exception& e)
  244. {
  245. AZ_Error("UnitTest", false, "Failed on with Python exception: %s", e.what());
  246. }
  247. Deactivate(e);
  248. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::GlobalPropertyTest_NotNone)]);
  249. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::GlobalPropertyTest_Is40)]);
  250. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::GlobalPropertyTest_Is42)]);
  251. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::GlobalPropertyTest_PingWorked)]);
  252. }
  253. TEST_F(PythonGlobalsTests, GlobalEnumTest)
  254. {
  255. enum class LogTypes
  256. {
  257. Skip = 0,
  258. GlobalEnumTest_Lumber,
  259. GlobalEnumTest_Yard
  260. };
  261. m_testSink.m_evaluateMessage = [](const char* window, const char* message) -> int
  262. {
  263. if (AzFramework::StringFunc::Equal(window, "python"))
  264. {
  265. if (AzFramework::StringFunc::Equal(message, "GlobalEnumTest_Lumber"))
  266. {
  267. return static_cast<int>(LogTypes::GlobalEnumTest_Lumber);
  268. }
  269. else if (AzFramework::StringFunc::Equal(message, "GlobalEnumTest_Yard"))
  270. {
  271. return static_cast<int>(LogTypes::GlobalEnumTest_Yard);
  272. }
  273. }
  274. return static_cast<int>(LogTypes::Skip);
  275. };
  276. PythonGlobalsTester pythonGlobalsTester;
  277. pythonGlobalsTester.Reflect(m_app.GetBehaviorContext());
  278. AZ::Entity e;
  279. Activate(e);
  280. SimulateEditorBecomingInitialized();
  281. try
  282. {
  283. pybind11::exec(R"(
  284. import azlmbr.globals
  285. azlmbr.globals.reset()
  286. # testing global enum constant values
  287. if (azlmbr.globals.property.GE_LUMBER == 101):
  288. print ('GlobalEnumTest_Lumber')
  289. if (azlmbr.globals.property.GE_YARD == 102):
  290. print ('GlobalEnumTest_Yard')
  291. azlmbr.globals.property.result1 = azlmbr.globals.property.GE_LUMBER
  292. azlmbr.globals.property.result2 = azlmbr.globals.property.GE_YARD
  293. )");
  294. }
  295. catch ([[maybe_unused]] const std::exception& e)
  296. {
  297. AZ_Error("UnitTest", false, "Failed on with Python exception: %s", e.what());
  298. }
  299. Deactivate(e);
  300. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::GlobalEnumTest_Lumber)]);
  301. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::GlobalEnumTest_Yard)]);
  302. EXPECT_EQ(PythonGlobalsTester::GlobalEnums::GE_LUMBER, PythonGlobalsTester::s_result1);
  303. EXPECT_EQ(PythonGlobalsTester::GlobalEnums::GE_YARD, PythonGlobalsTester::s_result2);
  304. }
  305. TEST_F(PythonGlobalsTests, GlobalConstantTest)
  306. {
  307. enum class LogTypes
  308. {
  309. Skip = 0,
  310. GlobalConstantTest_Fetch,
  311. GlobalConstantTest_Adds
  312. };
  313. m_testSink.m_evaluateMessage = [](const char* window, const char* message) -> int
  314. {
  315. if (AzFramework::StringFunc::Equal(window, "python"))
  316. {
  317. if (AzFramework::StringFunc::Equal(message, "GlobalConstantTest_Fetch"))
  318. {
  319. return static_cast<int>(LogTypes::GlobalConstantTest_Fetch);
  320. }
  321. else if (AzFramework::StringFunc::Equal(message, "GlobalConstantTest_Adds"))
  322. {
  323. return static_cast<int>(LogTypes::GlobalConstantTest_Adds);
  324. }
  325. }
  326. return static_cast<int>(LogTypes::Skip);
  327. };
  328. PythonGlobalsTester pythonGlobalsTester;
  329. pythonGlobalsTester.Reflect(m_app.GetBehaviorContext());
  330. AZ::Entity e;
  331. Activate(e);
  332. SimulateEditorBecomingInitialized();
  333. try
  334. {
  335. pybind11::exec(R"(
  336. import azlmbr.globals
  337. azlmbr.globals.reset()
  338. # testing global enum constant values
  339. if (azlmbr.globals.property.ONE == 1):
  340. print ('GlobalConstantTest_Fetch')
  341. a = azlmbr.globals.property.ONE
  342. b = azlmbr.globals.property.ONE
  343. if ((a + b) == 2):
  344. print ('GlobalConstantTest_Adds')
  345. )");
  346. }
  347. catch ([[maybe_unused]] const std::exception& e)
  348. {
  349. AZ_Error("UnitTest", false, "Failed on with Python exception: %s", e.what());
  350. }
  351. Deactivate(e);
  352. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::GlobalConstantTest_Fetch)]);
  353. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::GlobalConstantTest_Adds)]);
  354. }
  355. TEST_F(PythonGlobalsTests, TryAcceptTwoStrings)
  356. {
  357. PythonGlobalsTester pythonGlobalsTester;
  358. pythonGlobalsTester.Reflect(m_app.GetBehaviorContext());
  359. AZ::Entity e;
  360. Activate(e);
  361. SimulateEditorBecomingInitialized();
  362. enum class LogTypes
  363. {
  364. Skip = 0,
  365. stringValue1_has_data,
  366. stringValue2_is_empty
  367. };
  368. m_testSink.m_evaluateMessage = [](const char* window, const char* message) -> int
  369. {
  370. if (AzFramework::StringFunc::Equal(window, "python"))
  371. {
  372. if (AzFramework::StringFunc::Equal(message, "stringValue1_has_data"))
  373. {
  374. return aznumeric_cast<int>(LogTypes::stringValue1_has_data);
  375. }
  376. else if (AzFramework::StringFunc::Equal(message, "stringValue2_is_empty"))
  377. {
  378. return aznumeric_cast<int>(LogTypes::stringValue2_is_empty);
  379. }
  380. }
  381. return aznumeric_cast<int>(LogTypes::Skip);
  382. };
  383. try
  384. {
  385. pybind11::exec(R"(
  386. import azlmbr.globals
  387. azlmbr.globals.accept_two_strings("Test 01", "")
  388. )");
  389. }
  390. catch ([[maybe_unused]] const std::exception& e)
  391. {
  392. AZ_Error("UnitTest", false, "Failed on with Python exception: %s", e.what());
  393. }
  394. Deactivate(e);
  395. EXPECT_EQ(1, m_testSink.m_evaluationMap[aznumeric_cast<int>(LogTypes::stringValue1_has_data)]);
  396. EXPECT_EQ(1, m_testSink.m_evaluationMap[aznumeric_cast<int>(LogTypes::stringValue2_is_empty)]);
  397. }
  398. TEST_F(PythonGlobalsTests, GlobalListAllClasses)
  399. {
  400. PythonGlobalsTester pythonGlobalsTester;
  401. pythonGlobalsTester.Reflect(m_app.GetBehaviorContext());
  402. AZ::Entity e;
  403. Activate(e);
  404. SimulateEditorBecomingInitialized();
  405. enum class LogTypes
  406. {
  407. Skip = 0,
  408. ClassesFound
  409. };
  410. m_testSink.m_evaluateMessage = [](const char* window, const char* message) -> int
  411. {
  412. if (AzFramework::StringFunc::Equal(window, "python"))
  413. {
  414. if (AzFramework::StringFunc::Equal(message, "ClassListFound"))
  415. {
  416. return aznumeric_cast<int>(LogTypes::ClassesFound);
  417. }
  418. }
  419. return aznumeric_cast<int>(LogTypes::Skip);
  420. };
  421. try
  422. {
  423. pybind11::exec(R"(
  424. import azlmbr.object
  425. classList = azlmbr.object.list_classes()
  426. if (len(classList) > 0):
  427. print ('ClassListFound')
  428. )");
  429. }
  430. catch ([[maybe_unused]] const std::exception& e)
  431. {
  432. AZ_Error("UnitTest", false, "Failed on with Python exception: %s", e.what());
  433. }
  434. Deactivate(e);
  435. EXPECT_EQ(1, m_testSink.m_evaluationMap[aznumeric_cast<int>(LogTypes::ClassesFound)]);
  436. }
  437. TEST_F(PythonGlobalsTests, GlobalModuleDefinedTypeId)
  438. {
  439. PythonGlobalsTester pythonGlobalsTester;
  440. pythonGlobalsTester.Reflect(m_app.GetBehaviorContext());
  441. AZ::Entity e;
  442. Activate(e);
  443. SimulateEditorBecomingInitialized();
  444. enum class LogTypes
  445. {
  446. Skip = 0,
  447. TypeIsValid,
  448. StringTypeIsValid,
  449. EnumIsValid,
  450. };
  451. m_testSink.m_evaluateMessage = [](const char* window, const char* message) -> int
  452. {
  453. if (AzFramework::StringFunc::Equal(window, "python"))
  454. {
  455. if (AzFramework::StringFunc::Equal(message, "TypeIsValid"))
  456. {
  457. return aznumeric_cast<int>(LogTypes::TypeIsValid);
  458. }
  459. else if (AzFramework::StringFunc::Equal(message, "StringTypeIsValid"))
  460. {
  461. return aznumeric_cast<int>(LogTypes::StringTypeIsValid);
  462. }
  463. else if (AzFramework::StringFunc::Equal(message, "EnumIsValid"))
  464. {
  465. return aznumeric_cast<int>(LogTypes::EnumIsValid);
  466. }
  467. }
  468. return aznumeric_cast<int>(LogTypes::Skip);
  469. };
  470. try
  471. {
  472. pybind11::exec(R"(
  473. import azlmbr.constant
  474. import azlmbr.my.enum
  475. import azlmbr.globals
  476. azlmbr.globals.reset()
  477. type = azlmbr.constant.MY_TYPE
  478. if (type.ToString().startswith('{DEADBEE5-')):
  479. print ('TypeIsValid')
  480. if (azlmbr.constant.MY_STRING == 'my string'):
  481. print ('StringTypeIsValid')
  482. if (azlmbr.my.enum.One == 1):
  483. print ('EnumIsValid')
  484. if (azlmbr.my.enum.Two == 2):
  485. print ('EnumIsValid')
  486. )");
  487. }
  488. catch ([[maybe_unused]] const std::exception& e)
  489. {
  490. AZ_Error("UnitTest", false, "Failed on with Python exception: %s", e.what());
  491. }
  492. Deactivate(e);
  493. EXPECT_EQ(1, m_testSink.m_evaluationMap[aznumeric_cast<int>(LogTypes::TypeIsValid)]);
  494. EXPECT_EQ(1, m_testSink.m_evaluationMap[aznumeric_cast<int>(LogTypes::StringTypeIsValid)]);
  495. EXPECT_EQ(2, m_testSink.m_evaluationMap[aznumeric_cast<int>(LogTypes::EnumIsValid)]);
  496. }
  497. TEST_F(PythonGlobalsTests, CompareEqualityOperators)
  498. {
  499. AZ::Entity e;
  500. Activate(e);
  501. SimulateEditorBecomingInitialized();
  502. enum class LogTypes
  503. {
  504. Skip = 0,
  505. IsGreaterThan,
  506. IsGreaterEqualTo,
  507. IsLessThan,
  508. IsLessEqualTo,
  509. };
  510. m_testSink.m_evaluateMessage = [](const char* window, const char* message) -> int
  511. {
  512. if (AzFramework::StringFunc::Equal(window, "python"))
  513. {
  514. if (AzFramework::StringFunc::StartsWith(message, "IsGreaterThan"))
  515. {
  516. return aznumeric_cast<int>(LogTypes::IsGreaterThan);
  517. }
  518. else if (AzFramework::StringFunc::StartsWith(message, "IsGreaterEqualTo"))
  519. {
  520. return aznumeric_cast<int>(LogTypes::IsGreaterEqualTo);
  521. }
  522. else if (AzFramework::StringFunc::StartsWith(message, "IsLessThan"))
  523. {
  524. return aznumeric_cast<int>(LogTypes::IsLessThan);
  525. }
  526. else if (AzFramework::StringFunc::StartsWith(message, "IsLessEqualTo"))
  527. {
  528. return aznumeric_cast<int>(LogTypes::IsLessEqualTo);
  529. }
  530. }
  531. return aznumeric_cast<int>(LogTypes::Skip);
  532. };
  533. try
  534. {
  535. pybind11::exec(R"(
  536. import azlmbr.math
  537. import azlmbr.globals
  538. pointA = azlmbr.math.Vector2(40.0)
  539. pointB = azlmbr.math.Vector2(2.0)
  540. if (pointB < pointA):
  541. print ('IsLessThan')
  542. if (pointB <= pointA):
  543. print ('IsLessEqualTo')
  544. if (pointB <= pointB):
  545. print ('IsLessEqualTo')
  546. if (pointA > pointB):
  547. print ('IsGreaterThan')
  548. if (pointA >= pointB):
  549. print ('IsGreaterEqualTo')
  550. if (pointA >= pointA):
  551. print ('IsGreaterEqualTo')
  552. if (pointB >= pointA):
  553. print ('IsGreaterEqualTo')
  554. )");
  555. }
  556. catch ([[maybe_unused]] const std::exception& e)
  557. {
  558. AZ_Error("UnitTest", false, "Failed on with Python exception: %s", e.what());
  559. }
  560. Deactivate(e);
  561. EXPECT_EQ(1, m_testSink.m_evaluationMap[aznumeric_cast<int>(LogTypes::IsGreaterThan)]);
  562. EXPECT_EQ(2, m_testSink.m_evaluationMap[aznumeric_cast<int>(LogTypes::IsGreaterEqualTo)]);
  563. EXPECT_EQ(1, m_testSink.m_evaluationMap[aznumeric_cast<int>(LogTypes::IsLessThan)]);
  564. EXPECT_EQ(2, m_testSink.m_evaluationMap[aznumeric_cast<int>(LogTypes::IsLessEqualTo)]);
  565. }
  566. }