PythonTupleTests.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  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 <Source/PythonSystemComponent.h>
  14. #include <Source/PythonReflectionComponent.h>
  15. #include <Source/PythonMarshalComponent.h>
  16. #include <Source/PythonProxyObject.h>
  17. #include <AzCore/RTTI/BehaviorContext.h>
  18. #include <AzFramework/StringFunc/StringFunc.h>
  19. #include "PythonPairTests.h"
  20. namespace UnitTest
  21. {
  22. //////////////////////////////////////////////////////////////////////////
  23. // test class/structs
  24. struct PythonReflectionTupleTypes
  25. {
  26. AZ_TYPE_INFO(PythonReflectionTupleTypes, "{D5C9223B-8F12-49A9-8EDF-603357C3A6DF}");
  27. template <typename... Args>
  28. struct TupleOf
  29. {
  30. using TupleType = AZStd::tuple<Args...>;
  31. TupleType m_tuple;
  32. explicit TupleOf(const TupleType& tuple)
  33. {
  34. m_tuple = tuple;
  35. }
  36. const TupleType& ReturnTuple() const
  37. {
  38. return m_tuple;
  39. }
  40. void AcceptTuple(const TupleType& other)
  41. {
  42. m_tuple = other;
  43. }
  44. void RegisterGenericType(AZ::SerializeContext& serializeContext)
  45. {
  46. serializeContext.RegisterGenericType<TupleType>();
  47. }
  48. };
  49. TupleOf<> m_tupleOfEmptiness{ AZStd::make_tuple() };
  50. TupleOf<bool, int, float> m_tupleOfBasicTypes{ AZStd::make_tuple(true, 2, 3.0f) };
  51. TupleOf<AZStd::string, AZStd::string> m_tupleOfStrings { AZStd::make_tuple("one", "two")};
  52. TupleOf<bool, AZStd::string, MyCustomType> m_tupleWithCustomType{ AZStd::make_tuple(true, "one", MyCustomType()) };
  53. void Reflect(AZ::ReflectContext* context)
  54. {
  55. MyCustomType::Reflect(context);
  56. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  57. {
  58. m_tupleOfEmptiness.RegisterGenericType(*serializeContext);
  59. m_tupleOfBasicTypes.RegisterGenericType(*serializeContext);
  60. m_tupleOfStrings.RegisterGenericType(*serializeContext);
  61. m_tupleWithCustomType.RegisterGenericType(*serializeContext);
  62. }
  63. if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
  64. {
  65. behaviorContext->Class<PythonReflectionTupleTypes>()
  66. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  67. ->Attribute(AZ::Script::Attributes::Module, "test.tuple")
  68. ->Method(
  69. "return_empty_tuple",
  70. [](PythonReflectionTupleTypes* self)
  71. {
  72. return self->m_tupleOfEmptiness.ReturnTuple();
  73. },
  74. nullptr, "")
  75. ->Method(
  76. "accept_empty_tuple",
  77. [](PythonReflectionTupleTypes* self, const TupleOf<>::TupleType& tuple)
  78. {
  79. self->m_tupleOfEmptiness.AcceptTuple(tuple);
  80. },
  81. nullptr, "")
  82. ->Method(
  83. "return_tuple_of_basic_types",
  84. [](PythonReflectionTupleTypes* self)
  85. {
  86. return self->m_tupleOfBasicTypes.ReturnTuple();
  87. },
  88. nullptr, "")
  89. ->Method(
  90. "accept_tuple_of_basic_types",
  91. [](PythonReflectionTupleTypes* self, const TupleOf<bool, int, float>::TupleType& tuple)
  92. {
  93. self->m_tupleOfBasicTypes.AcceptTuple(tuple);
  94. },
  95. nullptr, "")
  96. ->Method(
  97. "return_tuple_of_strings",
  98. [](PythonReflectionTupleTypes* self)
  99. {
  100. return self->m_tupleOfStrings.ReturnTuple();
  101. },
  102. nullptr, "")
  103. ->Method(
  104. "accept_tuple_of_strings",
  105. [](PythonReflectionTupleTypes* self, const TupleOf<AZStd::string, AZStd::string>::TupleType& tuple)
  106. {
  107. self->m_tupleOfStrings.AcceptTuple(tuple);
  108. },
  109. nullptr, "")
  110. ->Method(
  111. "return_tuple_with_custom_type",
  112. [](PythonReflectionTupleTypes* self)
  113. {
  114. return self->m_tupleWithCustomType.ReturnTuple();
  115. },
  116. nullptr, "")
  117. ->Method(
  118. "accept_tuple_with_custom_type",
  119. [](PythonReflectionTupleTypes* self, const TupleOf<bool, AZStd::string, MyCustomType>::TupleType& tuple)
  120. {
  121. self->m_tupleWithCustomType.AcceptTuple(tuple);
  122. },
  123. nullptr, "")
  124. ;
  125. }
  126. }
  127. };
  128. //////////////////////////////////////////////////////////////////////////
  129. // fixtures
  130. struct PythonReflectionTupleTests
  131. : public PythonTestingFixture
  132. {
  133. PythonTraceMessageSink m_testSink;
  134. void SetUp() override
  135. {
  136. PythonTestingFixture::SetUp();
  137. PythonTestingFixture::RegisterComponentDescriptors();
  138. }
  139. void TearDown() override
  140. {
  141. // clearing up memory
  142. m_testSink.CleanUp();
  143. PythonTestingFixture::TearDown();
  144. }
  145. };
  146. TEST_F(PythonReflectionTupleTests, SimpleTuplesConstructed)
  147. {
  148. enum class LogTypes
  149. {
  150. Skip = 0,
  151. TupleTypeTest_ConstructWithDefaultValues,
  152. TupleTypeTest_ConstructWithParameters,
  153. TupleTypeTest_UseConstructedAsParameterToCpp,
  154. TupleTypeTest_ReturnTupleAsListFromCpp,
  155. TupleTypeTest_TupleReturnedAsListWithCorrectValues,
  156. TupleTypeTest_TupleReturnedWithCorrectValues,
  157. TupleTypeTest_UsePythonListAsParameter,
  158. TupleTypeTest_PythonListReturnedWithCorrectValues
  159. };
  160. m_testSink.m_evaluateMessage = [](const char* window, const char* message) -> int
  161. {
  162. if (AzFramework::StringFunc::Equal(window, "python"))
  163. {
  164. if (AzFramework::StringFunc::StartsWith(message, "TupleTypeTest_ConstructWithDefaultValues"))
  165. {
  166. return static_cast<int>(LogTypes::TupleTypeTest_ConstructWithDefaultValues);
  167. }
  168. else if (AzFramework::StringFunc::StartsWith(message, "TupleTypeTest_ConstructWithParameters"))
  169. {
  170. return static_cast<int>(LogTypes::TupleTypeTest_ConstructWithParameters);
  171. }
  172. else if (AzFramework::StringFunc::StartsWith(message, "TupleTypeTest_UseConstructedAsParameterToCpp"))
  173. {
  174. return static_cast<int>(LogTypes::TupleTypeTest_UseConstructedAsParameterToCpp);
  175. }
  176. else if (AzFramework::StringFunc::StartsWith(message, "TupleTypeTest_ReturnTupleAsListFromCpp"))
  177. {
  178. return static_cast<int>(LogTypes::TupleTypeTest_ReturnTupleAsListFromCpp);
  179. }
  180. else if (AzFramework::StringFunc::StartsWith(message, "TupleTypeTest_TupleReturnedAsListWithCorrectValues"))
  181. {
  182. return static_cast<int>(LogTypes::TupleTypeTest_TupleReturnedAsListWithCorrectValues);
  183. }
  184. else if (AzFramework::StringFunc::StartsWith(message, "TupleTypeTest_TupleReturnedWithCorrectValues"))
  185. {
  186. return static_cast<int>(LogTypes::TupleTypeTest_TupleReturnedWithCorrectValues);
  187. }
  188. else if (AzFramework::StringFunc::StartsWith(message, "TupleTypeTest_UsePythonListAsParameter"))
  189. {
  190. return static_cast<int>(LogTypes::TupleTypeTest_UsePythonListAsParameter);
  191. }
  192. else if (AzFramework::StringFunc::StartsWith(message, "TupleTypeTest_PythonListReturnedWithCorrectValues"))
  193. {
  194. return static_cast<int>(LogTypes::TupleTypeTest_PythonListReturnedWithCorrectValues);
  195. }
  196. }
  197. return static_cast<int>(LogTypes::Skip);
  198. };
  199. PythonReflectionTupleTypes pythonReflectionTupleTypes;
  200. pythonReflectionTupleTypes.Reflect(m_app.GetSerializeContext());
  201. pythonReflectionTupleTypes.Reflect(m_app.GetBehaviorContext());
  202. AZ::Entity e;
  203. Activate(e);
  204. SimulateEditorBecomingInitialized();
  205. try
  206. {
  207. pybind11::exec(R"(
  208. import azlmbr.test.tuple
  209. import azlmbr.object
  210. import azlmbr.std
  211. # Create the test fixture
  212. test = azlmbr.object.create('PythonReflectionTupleTypes')
  213. # Create a tuple with default values
  214. test_tuple = azlmbr.object.create('AZStd::tuple<bool, int, float>')
  215. if (test_tuple):
  216. print ('TupleTypeTest_ConstructWithDefaultValues')
  217. # Create a tuple with parameters and verify that the parameters can be read back correctly.
  218. test_tuple = azlmbr.object.construct('AZStd::tuple<bool, int, float>', True, 5, 10.0)
  219. if (test_tuple and test_tuple.Get0() == True and test_tuple.Get1() == 5 and test_tuple.Get2() == 10.0):
  220. print ('TupleTypeTest_ConstructWithParameters')
  221. # Use the tuple as a parameter to a reflected C++ method
  222. test.accept_tuple_of_basic_types(test_tuple)
  223. print ('TupleTypeTest_UseConstructedAsParameterToCpp')
  224. # Test out the tuple as a single return value that's a list
  225. result = test.return_tuple_of_basic_types()
  226. if (result and len(result) == 3):
  227. print ('TupleTypeTest_ReturnTupleAsListFromCpp')
  228. # Verify the results that were returned are the same ones we sent in.
  229. if (result and len(result) == 3 and result[0] == True and result[1] == 5 and result[2] == 10.0):
  230. print ('TupleTypeTest_TupleReturnedAsListWithCorrectValues')
  231. # Test out the tuple as comma-separated return values extracted from the list
  232. a, b, c = test.return_tuple_of_basic_types()
  233. if (a == True and b == 5 and c == 10.0):
  234. print ('TupleTypeTest_TupleReturnedWithCorrectValues')
  235. # Use the tuple as a parameter to a reflected C++ method
  236. test.accept_tuple_of_basic_types([False, 10, 20.0])
  237. print ('TupleTypeTest_UsePythonListAsParameter')
  238. a, b, c = test.return_tuple_of_basic_types()
  239. if (a == False and b == 10 and c == 20.0):
  240. print ('TupleTypeTest_PythonListReturnedWithCorrectValues')
  241. )");
  242. } catch ([[maybe_unused]] const pybind11::error_already_set& ex)
  243. {
  244. AZ_Warning("UnitTest", false, "Failed with Python exception of %s", ex.what());
  245. FAIL();
  246. }
  247. e.Deactivate();
  248. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::TupleTypeTest_ConstructWithDefaultValues)]);
  249. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::TupleTypeTest_ConstructWithParameters)]);
  250. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::TupleTypeTest_UseConstructedAsParameterToCpp)]);
  251. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::TupleTypeTest_ReturnTupleAsListFromCpp)]);
  252. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::TupleTypeTest_TupleReturnedAsListWithCorrectValues)]);
  253. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::TupleTypeTest_TupleReturnedWithCorrectValues)]);
  254. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::TupleTypeTest_UsePythonListAsParameter)]);
  255. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::TupleTypeTest_PythonListReturnedWithCorrectValues)]);
  256. }
  257. TEST_F(PythonReflectionTupleTests, EmptyTupleConvertedCorrectly)
  258. {
  259. enum class LogTypes
  260. {
  261. Skip = 0,
  262. TupleTypeTest_Input,
  263. TupleTypeTest_Output,
  264. };
  265. m_testSink.m_evaluateMessage = [](const char* window, const char* message) -> int
  266. {
  267. if (AzFramework::StringFunc::Equal(window, "python"))
  268. {
  269. if (AzFramework::StringFunc::StartsWith(message, "TupleTypeTest_Input"))
  270. {
  271. return static_cast<int>(LogTypes::TupleTypeTest_Input);
  272. }
  273. else if (AzFramework::StringFunc::StartsWith(message, "TupleTypeTest_Output"))
  274. {
  275. return static_cast<int>(LogTypes::TupleTypeTest_Output);
  276. }
  277. }
  278. return static_cast<int>(LogTypes::Skip);
  279. };
  280. PythonReflectionTupleTypes pythonReflectionTupleTypes;
  281. pythonReflectionTupleTypes.Reflect(m_app.GetSerializeContext());
  282. pythonReflectionTupleTypes.Reflect(m_app.GetBehaviorContext());
  283. AZ::Entity e;
  284. Activate(e);
  285. SimulateEditorBecomingInitialized();
  286. try
  287. {
  288. pybind11::exec(R"(
  289. import azlmbr.test.tuple
  290. import azlmbr.object
  291. import azlmbr.std
  292. # Create the test fixture
  293. test = azlmbr.object.create('PythonReflectionTupleTypes')
  294. # Verify that an empty tuple is returned correctly
  295. result = test.return_empty_tuple()
  296. if (len(result) == 0):
  297. print ('TupleTypeTest_Output_empty')
  298. # Create a tuple from a Python list and verify the values are correct
  299. test.accept_empty_tuple([])
  300. result = test.return_empty_tuple()
  301. if (len(result) == 0):
  302. print ('TupleTypeTest_Input_empty_list')
  303. # Create a tuple from a Python tuple and verify the values are correct
  304. test.accept_empty_tuple(())
  305. result = test.return_empty_tuple()
  306. if (len(result) == 0):
  307. print ('TupleTypeTest_Input_empty')
  308. )");
  309. } catch ([[maybe_unused]] const pybind11::error_already_set& ex)
  310. {
  311. AZ_Warning("UnitTest", false, "Failed with Python exception of %s", ex.what());
  312. FAIL();
  313. }
  314. e.Deactivate();
  315. EXPECT_EQ(2, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::TupleTypeTest_Input)]);
  316. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::TupleTypeTest_Output)]);
  317. }
  318. TEST_F(PythonReflectionTupleTests, InputsAndOutputsConvertedCorrectly)
  319. {
  320. enum class LogTypes
  321. {
  322. Skip = 0,
  323. TupleTypeTest_Input,
  324. TupleTypeTest_Output,
  325. };
  326. m_testSink.m_evaluateMessage = [](const char* window, const char* message) -> int
  327. {
  328. if (AzFramework::StringFunc::Equal(window, "python"))
  329. {
  330. if (AzFramework::StringFunc::StartsWith(message, "TupleTypeTest_Input"))
  331. {
  332. return static_cast<int>(LogTypes::TupleTypeTest_Input);
  333. }
  334. else if (AzFramework::StringFunc::StartsWith(message, "TupleTypeTest_Output"))
  335. {
  336. return static_cast<int>(LogTypes::TupleTypeTest_Output);
  337. }
  338. }
  339. return static_cast<int>(LogTypes::Skip);
  340. };
  341. PythonReflectionTupleTypes pythonReflectionTupleTypes;
  342. pythonReflectionTupleTypes.Reflect(m_app.GetSerializeContext());
  343. pythonReflectionTupleTypes.Reflect(m_app.GetBehaviorContext());
  344. AZ::Entity e;
  345. Activate(e);
  346. SimulateEditorBecomingInitialized();
  347. try
  348. {
  349. pybind11::exec(R"(
  350. import azlmbr.test.tuple
  351. import azlmbr.object
  352. import azlmbr.std
  353. # Create the test fixture
  354. test = azlmbr.object.create('PythonReflectionTupleTypes')
  355. # Verify that a tuple of basic types (bool, int, float) is returned correctly
  356. result = test.return_tuple_of_basic_types()
  357. if (len(result) == 3):
  358. print ('TupleTypeTest_Output_bool_int_float')
  359. # Create a tuple from a Python list and verify the values are correct
  360. test.accept_tuple_of_basic_types([True, 42, 1000.0])
  361. result = test.return_tuple_of_basic_types()
  362. if (len(result) == 3 and result[0] == True and result[1] == 42 and result[2] == 1000.0):
  363. print ('TupleTypeTest_Input_bool_int_float_list')
  364. # Create a tuple from a Python tuple and verify the values are correct
  365. test.accept_tuple_of_basic_types((False, 24, -25.0))
  366. result = test.return_tuple_of_basic_types()
  367. if (len(result) == 3 and result[0] == False and result[1] == 24 and result[2] == -25.0):
  368. print ('TupleTypeTest_Input_bool_int_float')
  369. # Verify that a tuple of strings (string, string) is returned correctly
  370. result = test.return_tuple_of_strings()
  371. if (len(result) == 2):
  372. print ('TupleTypeTest_Output_string_string')
  373. # Create a tuple from a Python list and verify the values are correct
  374. test.accept_tuple_of_strings(['ghi', 'jkl'])
  375. result = test.return_tuple_of_strings()
  376. if (len(result) == 2 and result[0] == 'ghi' and result[1] == 'jkl'):
  377. print ('TupleTypeTest_Input_string_string_list')
  378. # Create a tuple from a Python tuple and verify the values are correct
  379. test.accept_tuple_of_strings(('abc', 'def'))
  380. result = test.return_tuple_of_strings()
  381. if (len(result) == 2 and result[0] == 'abc' and result[1] == 'def'):
  382. print ('TupleTypeTest_Input_string_string')
  383. )");
  384. } catch ([[maybe_unused]] const pybind11::error_already_set& ex)
  385. {
  386. AZ_Warning("UnitTest", false, "Failed with Python exception of %s", ex.what());
  387. FAIL();
  388. }
  389. e.Deactivate();
  390. EXPECT_EQ(4, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::TupleTypeTest_Input)]);
  391. EXPECT_EQ(2, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::TupleTypeTest_Output)]);
  392. }
  393. TEST_F(PythonReflectionTupleTests, CustomTypesConvertedCorrectly)
  394. {
  395. enum class LogTypes
  396. {
  397. Skip = 0,
  398. TupleCustomTypeTest_Input,
  399. TupleCustomTypeTest_Output,
  400. };
  401. m_testSink.m_evaluateMessage = [](const char* window, const char* message) -> int
  402. {
  403. if (AzFramework::StringFunc::Equal(window, "python"))
  404. {
  405. if (AzFramework::StringFunc::StartsWith(message, "TupleCustomTypeTest_Input"))
  406. {
  407. return static_cast<int>(LogTypes::TupleCustomTypeTest_Input);
  408. }
  409. else if (AzFramework::StringFunc::StartsWith(message, "TupleCustomTypeTest_Output"))
  410. {
  411. return static_cast<int>(LogTypes::TupleCustomTypeTest_Output);
  412. }
  413. }
  414. return static_cast<int>(LogTypes::Skip);
  415. };
  416. PythonReflectionTupleTypes pythonReflectionPairTypes;
  417. pythonReflectionPairTypes.Reflect(m_app.GetSerializeContext());
  418. pythonReflectionPairTypes.Reflect(m_app.GetBehaviorContext());
  419. AZ::Entity e;
  420. Activate(e);
  421. SimulateEditorBecomingInitialized();
  422. try
  423. {
  424. pybind11::exec(R"(
  425. import azlmbr.test.pair
  426. import azlmbr.object
  427. import azlmbr.std
  428. # Create the test fixture
  429. test = azlmbr.object.create('PythonReflectionTupleTypes')
  430. result = test.return_tuple_with_custom_type()
  431. if (len(result) == 3):
  432. print ('TupleCustomTypeTest_Output')
  433. custom = azlmbr.object.create('MyCustomType')
  434. custom.set_data(42)
  435. test.accept_tuple_with_custom_type((True, 'def', custom))
  436. result = test.return_tuple_with_custom_type()
  437. if (len(result) == 3 and result[0] == True and result[1] == 'def' and result[2].get_data() == 42):
  438. print ('TupleCustomTypeTest_Input')
  439. )");
  440. } catch ([[maybe_unused]] const pybind11::error_already_set& ex)
  441. {
  442. AZ_Warning("UnitTest", false, "Failed with Python exception of %s", ex.what());
  443. FAIL();
  444. }
  445. e.Deactivate();
  446. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::TupleCustomTypeTest_Input)]);
  447. EXPECT_EQ(1, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::TupleCustomTypeTest_Output)]);
  448. }
  449. TEST_F(PythonReflectionTupleTests, UnsupportedTypesLogErrors)
  450. {
  451. enum class LogTypes
  452. {
  453. Skip = 0,
  454. TupleUnsupportedTypeTest_CannotConvert
  455. };
  456. m_testSink.m_evaluateMessage = [](const char* window, const char* message) -> int
  457. {
  458. if (AzFramework::StringFunc::Equal(window, "python"))
  459. {
  460. if (AzFramework::StringFunc::Contains(message, "accept_tuple_of_basic_types"))
  461. {
  462. return static_cast<int>(LogTypes::TupleUnsupportedTypeTest_CannotConvert);
  463. }
  464. }
  465. return static_cast<int>(LogTypes::Skip);
  466. };
  467. PythonReflectionTupleTypes pythonReflectionDictionaryTypes;
  468. pythonReflectionDictionaryTypes.Reflect(m_app.GetSerializeContext());
  469. pythonReflectionDictionaryTypes.Reflect(m_app.GetBehaviorContext());
  470. AZ::Entity e;
  471. Activate(e);
  472. SimulateEditorBecomingInitialized();
  473. AZ_TEST_START_TRACE_SUPPRESSION;
  474. try
  475. {
  476. pybind11::exec(R"(
  477. import azlmbr.test.pair
  478. import azlmbr.object
  479. import azlmbr.std
  480. # Create the test fixture
  481. test = azlmbr.object.create('PythonReflectionTupleTypes')
  482. # This should fail because it's passing [bool, int] to a tuple expecting [bool, int, float]
  483. test.accept_tuple_of_basic_types([True, 5])
  484. # This should fail because it's passing [int, string, bool] to a tuple expecting [bool, int, float]
  485. test.accept_tuple_of_basic_types([5, 'abc', True])
  486. # This should fail because it's passing [bool, int, float, float] to a tuple expecting [bool, int, float]
  487. test.accept_tuple_of_basic_types([True, 5, 10.0, 10.0])
  488. # This should fail because it's passing a set instead of a tuple or list
  489. test.accept_tuple_of_basic_types({True, 5, 10.0})
  490. )");
  491. } catch ([[maybe_unused]] const pybind11::error_already_set& ex)
  492. {
  493. AZ_Warning("UnitTest", false, "Failed with Python exception of %s", ex.what());
  494. FAIL();
  495. }
  496. AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
  497. e.Deactivate();
  498. EXPECT_EQ(4, m_testSink.m_evaluationMap[static_cast<int>(LogTypes::TupleUnsupportedTypeTest_CannotConvert)]);
  499. }
  500. }