PythonAssociativeTests.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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 <EditorPythonBindings/PythonCommon.h>
  9. #include <pybind11/embed.h>
  10. #include <pybind11/pybind11.h>
  11. #include "PythonTraceMessageSink.h"
  12. #include "PythonTestingUtility.h"
  13. #include <AzCore/Serialization/SerializeContext.h>
  14. #include <AzCore/std/containers/unordered_set.h>
  15. #include <AzCore/StringFunc/StringFunc.h>
  16. #include <AzCore/RTTI/BehaviorContext.h>
  17. #include <Source/PythonSystemComponent.h>
  18. #include <Source/PythonReflectionComponent.h>
  19. #include <Source/PythonMarshalComponent.h>
  20. namespace UnitTest
  21. {
  22. struct PythonReflectUnorderedSet
  23. {
  24. AZ_TYPE_INFO(PythonReflectUnorderedSet, "{A596466F-2F29-4479-A721-0E50FA704962}");
  25. AZStd::unordered_set<AZ::u8> m_u8Set {1,2};
  26. AZStd::unordered_set<AZ::u16> m_u16Set {4,8};
  27. AZStd::unordered_set<AZ::u32> m_u32Set {16,32};
  28. AZStd::unordered_set<AZ::u64> m_u64Set {64,128};
  29. AZStd::unordered_set<AZ::s8> m_s8Set {-1,-2};
  30. AZStd::unordered_set<AZ::s16> m_s16Set {-4,-8};
  31. AZStd::unordered_set<AZ::s32> m_s32Set {-16,-32};
  32. AZStd::unordered_set<AZ::s64> m_s64Set {-64,-128};
  33. AZStd::unordered_set<double> m_floatSet {1.0f, 2.0f};
  34. AZStd::unordered_set<float> m_doubleSet {0.1, 0.2};
  35. AZStd::unordered_set<AZStd::string> m_stringSet {"one", "two"};
  36. void Reflect(AZ::ReflectContext* context)
  37. {
  38. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  39. {
  40. serializeContext->RegisterGenericType<decltype(m_u8Set)>();
  41. serializeContext->RegisterGenericType<decltype(m_u16Set)>();
  42. serializeContext->RegisterGenericType<decltype(m_u32Set)>();
  43. serializeContext->RegisterGenericType<decltype(m_u64Set)>();
  44. serializeContext->RegisterGenericType<decltype(m_s8Set)>();
  45. serializeContext->RegisterGenericType<decltype(m_s16Set)>();
  46. serializeContext->RegisterGenericType<decltype(m_s32Set)>();
  47. serializeContext->RegisterGenericType<decltype(m_s64Set)>();
  48. serializeContext->RegisterGenericType<decltype(m_floatSet)>();
  49. serializeContext->RegisterGenericType<decltype(m_doubleSet)>();
  50. serializeContext->RegisterGenericType<decltype(m_stringSet)>();
  51. }
  52. if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
  53. {
  54. behaviorContext->Class<PythonReflectUnorderedSet>()
  55. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  56. ->Attribute(AZ::Script::Attributes::Module, "test.set")
  57. ->Property("u8Set", BehaviorValueProperty(&PythonReflectUnorderedSet::m_u8Set) )
  58. ->Property("u16Set", BehaviorValueProperty(&PythonReflectUnorderedSet::m_u16Set))
  59. ->Property("u32Set", BehaviorValueProperty(&PythonReflectUnorderedSet::m_u32Set))
  60. ->Property("u64Set", BehaviorValueProperty(&PythonReflectUnorderedSet::m_u64Set))
  61. ->Property("s8Set", BehaviorValueProperty(&PythonReflectUnorderedSet::m_s8Set))
  62. ->Property("s16Set", BehaviorValueProperty(&PythonReflectUnorderedSet::m_s16Set))
  63. ->Property("s32Set", BehaviorValueProperty(&PythonReflectUnorderedSet::m_s32Set))
  64. ->Property("s64Set", BehaviorValueProperty(&PythonReflectUnorderedSet::m_s64Set))
  65. ->Property("floatSet", BehaviorValueProperty(&PythonReflectUnorderedSet::m_floatSet))
  66. ->Property("doubleSet", BehaviorValueProperty(&PythonReflectUnorderedSet::m_doubleSet))
  67. ->Property("stringSet", BehaviorValueProperty(&PythonReflectUnorderedSet::m_stringSet))
  68. ;
  69. }
  70. }
  71. };
  72. //////////////////////////////////////////////////////////////////////////
  73. // fixtures
  74. struct PythonAssociativeTest
  75. : public PythonTestingFixture
  76. {
  77. PythonTraceMessageSink m_testSink;
  78. void SetUp() override
  79. {
  80. PythonTestingFixture::SetUp();
  81. PythonTestingFixture::RegisterComponentDescriptors();
  82. }
  83. void TearDown() override
  84. {
  85. // clearing up memory
  86. m_testSink.CleanUp();
  87. PythonTestingFixture::TearDown();
  88. }
  89. };
  90. TEST_F(PythonAssociativeTest, SimpleUnorderedSet_Assignment)
  91. {
  92. enum class LogTypes
  93. {
  94. Skip = 0,
  95. Update,
  96. };
  97. m_testSink.m_evaluateMessage = [](const char* window, const char* message) -> int
  98. {
  99. if (AZ::StringFunc::Equal(window, "python"))
  100. {
  101. if (AZ::StringFunc::StartsWith(message, "Update"))
  102. {
  103. return aznumeric_cast<int>(LogTypes::Update);
  104. }
  105. }
  106. return aznumeric_cast<int>(LogTypes::Skip);
  107. };
  108. PythonReflectUnorderedSet pythonReflectUnorderedSet;
  109. pythonReflectUnorderedSet.Reflect(m_app.GetSerializeContext());
  110. pythonReflectUnorderedSet.Reflect(m_app.GetBehaviorContext());
  111. AZ::Entity e;
  112. Activate(e);
  113. SimulateEditorBecomingInitialized();
  114. try
  115. {
  116. pybind11::exec(R"(
  117. import azlmbr.test.set
  118. tester = azlmbr.test.set.PythonReflectUnorderedSet()
  119. def updateNumberDataSet(memberSet, dataSet):
  120. memberSet = dataSet
  121. for value in memberSet:
  122. if (value in dataSet):
  123. print ('Update_worked_{}'.format(memberSet))
  124. updateNumberDataSet(tester.u8Set, {2, 1})
  125. updateNumberDataSet(tester.u16Set, {8, 4})
  126. updateNumberDataSet(tester.u32Set, {32, 16})
  127. updateNumberDataSet(tester.u64Set, {128, 64})
  128. updateNumberDataSet(tester.s8Set, {-2, -1})
  129. updateNumberDataSet(tester.s16Set, {-8, -4})
  130. updateNumberDataSet(tester.s32Set, {-32, -16})
  131. updateNumberDataSet(tester.s64Set, {-128, -64})
  132. from azlmbr.math import Math_IsClose
  133. def updateFloatDataSet(memberFloatSet, dataSet):
  134. memberFloatSet = dataSet
  135. for dataItem in dataSet:
  136. for memberItem in memberFloatSet:
  137. if (Math_IsClose(dataItem, memberItem)):
  138. print ('Update_float_worked_{}'.format(memberFloatSet))
  139. updateFloatDataSet(tester.floatSet, {4.0, 8.0})
  140. updateFloatDataSet(tester.doubleSet, {0.4, 0.8})
  141. stringDataSet = {'three','four'}
  142. tester.stringSet = stringDataSet
  143. for dataItem in stringDataSet:
  144. for memberItem in tester.stringSet:
  145. if (dataItem == memberItem):
  146. print ('Update_string_worked')
  147. )");
  148. }
  149. catch ([[maybe_unused]] const std::exception& e)
  150. {
  151. AZ_Error("UnitTest", false, "Failed with Python exception of %s", e.what());
  152. }
  153. e.Deactivate();
  154. EXPECT_EQ(22, m_testSink.m_evaluationMap[aznumeric_cast<int>(LogTypes::Update)]);
  155. }
  156. TEST_F(PythonAssociativeTest, SimpleUnorderedSet_Creation)
  157. {
  158. enum class LogTypes
  159. {
  160. Skip = 0,
  161. Create,
  162. };
  163. m_testSink.m_evaluateMessage = [](const char* window, const char* message) -> int
  164. {
  165. if (AZ::StringFunc::Equal(window, "python"))
  166. {
  167. if (AZ::StringFunc::StartsWith(message, "Create"))
  168. {
  169. return aznumeric_cast<int>(LogTypes::Create);
  170. }
  171. }
  172. return aznumeric_cast<int>(LogTypes::Skip);
  173. };
  174. PythonReflectUnorderedSet pythonReflectUnorderedSet;
  175. pythonReflectUnorderedSet.Reflect(m_app.GetSerializeContext());
  176. pythonReflectUnorderedSet.Reflect(m_app.GetBehaviorContext());
  177. AZ::Entity e;
  178. Activate(e);
  179. SimulateEditorBecomingInitialized();
  180. try
  181. {
  182. pybind11::exec(R"(
  183. import azlmbr.test.set
  184. tester = azlmbr.test.set.PythonReflectUnorderedSet()
  185. if (tester.u8Set == {1, 2}):
  186. print ('Create_Works_u8Set')
  187. if (tester.u16Set == {4, 8}):
  188. print ('Create_Works_u16Set')
  189. if (tester.u32Set == {16, 32}):
  190. print ('Create_Works_u32Set')
  191. if (tester.u64Set == {64, 128}):
  192. print ('Create_Works_u64Set')
  193. if (tester.s8Set == {-1, -2}):
  194. print ('Create_Works_s8Set')
  195. if (tester.s16Set == {-4, -8}):
  196. print ('Create_Works_s16Set')
  197. if (tester.s32Set == {-16, -32}):
  198. print ('Create_Works_s32Set')
  199. if (tester.s64Set == {-64, -128}):
  200. print ('Create_Works_s64Set')
  201. from azlmbr.math import Math_IsClose
  202. for value in tester.floatSet:
  203. if (Math_IsClose(value, 1.0) or Math_IsClose(value, 2.0)):
  204. print ('Create_Works_floatSet')
  205. for value in tester.doubleSet:
  206. if (Math_IsClose(value, 0.1) or Math_IsClose(value, 0.2)):
  207. print ('Create_Works_doubleSet')
  208. for value in tester.stringSet:
  209. if ((value == 'one') or (value == 'two')):
  210. print ('Create_Works_stringSet')
  211. )");
  212. }
  213. catch ([[maybe_unused]] const std::exception& e)
  214. {
  215. AZ_Error("UnitTest", false, "Failed with Python exception of %s", e.what());
  216. }
  217. e.Deactivate();
  218. EXPECT_EQ(14, m_testSink.m_evaluationMap[aznumeric_cast<int>(LogTypes::Create)]);
  219. }
  220. }