ctkAbstractPythonManagerTest.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. // Qt includes
  2. #include <QTemporaryFile>
  3. #include <QTextStream>
  4. // CTK includes
  5. #include "ctkAbstractPythonManager.h"
  6. #include "ctkTest.h"
  7. // PythonQt includes
  8. #include <PythonQt.h>
  9. // STD includes
  10. #include <cstdlib>
  11. #include <iostream>
  12. //-----------------------------------------------------------------------------
  13. #if QT_VERSION < 0x040700
  14. Q_DECLARE_METATYPE(QVariant)
  15. #endif
  16. //-----------------------------------------------------------------------------
  17. class ctkAbstractPythonManagerTester: public QObject
  18. {
  19. Q_OBJECT
  20. private:
  21. ctkAbstractPythonManager PythonManager;
  22. private Q_SLOTS:
  23. void testDefaults();
  24. void testIsPythonInitialized();
  25. void testSetInitializationFlags();
  26. void testSetSystemExitExceptionHandlerEnabled();
  27. void testPythonErrorOccured();
  28. void testPythonErrorOccured_data();
  29. void testInitialize();
  30. void testMainContext();
  31. void testAddObjectToPythonMain();
  32. //void testRegisterPythonQtDecorator(); // TODO
  33. //void testRegisterClassForPythonQt(); // TODO
  34. void testExecuteString();
  35. void testExecuteString_data();
  36. void testExecuteFile();
  37. void testExecuteFile_data();
  38. void testPythonAttributes();
  39. void testPythonAttributes_data();
  40. void testPythonAttributeValues();
  41. void testPythonAttributeValues_data();
  42. void testPythonModule();
  43. void testPythonModule_data();
  44. void testPythonObject();
  45. void testPythonObject_data();
  46. };
  47. Q_DECLARE_METATYPE(PyObject*)
  48. // ----------------------------------------------------------------------------
  49. void ctkAbstractPythonManagerTester::testDefaults()
  50. {
  51. QCOMPARE(this->PythonManager.pythonErrorOccured(), false);
  52. this->PythonManager.resetErrorFlag();
  53. this->PythonManager.registerPythonQtDecorator(0);
  54. this->PythonManager.registerClassForPythonQt(0);
  55. this->PythonManager.registerCPPClassForPythonQt(0);
  56. this->PythonManager.addWrapperFactory(0);
  57. }
  58. // ----------------------------------------------------------------------------
  59. void ctkAbstractPythonManagerTester::testIsPythonInitialized()
  60. {
  61. QCOMPARE(this->PythonManager.isPythonInitialized(), false);
  62. }
  63. // ----------------------------------------------------------------------------
  64. void ctkAbstractPythonManagerTester::testSetInitializationFlags()
  65. {
  66. QCOMPARE(this->PythonManager.initializationFlags(), PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
  67. int flagsToSetPreInit = PythonQt::RedirectStdOut;
  68. int expectedFlagsPreInit = PythonQt::RedirectStdOut;
  69. this->PythonManager.setInitializationFlags(flagsToSetPreInit);
  70. QCOMPARE(this->PythonManager.initializationFlags(), expectedFlagsPreInit);
  71. this->PythonManager.mainContext();
  72. int flagsToSetPostInit = 0;
  73. int expectedFlagsPostInit = PythonQt::RedirectStdOut;
  74. this->PythonManager.setInitializationFlags(flagsToSetPostInit);
  75. QCOMPARE(this->PythonManager.initializationFlags(), expectedFlagsPostInit);
  76. QCOMPARE(this->PythonManager.isPythonInitialized(), true);
  77. }
  78. // ----------------------------------------------------------------------------
  79. void ctkAbstractPythonManagerTester::testSetSystemExitExceptionHandlerEnabled()
  80. {
  81. QCOMPARE(this->PythonManager.systemExitExceptionHandlerEnabled(), false);
  82. this->PythonManager.setSystemExitExceptionHandlerEnabled(true);
  83. QCOMPARE(this->PythonManager.systemExitExceptionHandlerEnabled(), true);
  84. }
  85. // ----------------------------------------------------------------------------
  86. void ctkAbstractPythonManagerTester::testInitialize()
  87. {
  88. QVERIFY(this->PythonManager.initialize());
  89. this->testDefaults();
  90. }
  91. // ----------------------------------------------------------------------------
  92. void ctkAbstractPythonManagerTester::testMainContext()
  93. {
  94. QVERIFY(this->PythonManager.mainContext());
  95. this->testDefaults();
  96. }
  97. // ----------------------------------------------------------------------------
  98. void ctkAbstractPythonManagerTester::testPythonErrorOccured()
  99. {
  100. QFETCH(QString, pythonCode);
  101. QFETCH(bool, errorOccured);
  102. this->PythonManager.executeString(pythonCode);
  103. QCOMPARE(this->PythonManager.pythonErrorOccured(), errorOccured);
  104. if(errorOccured)
  105. {
  106. this->PythonManager.resetErrorFlag();
  107. }
  108. }
  109. // ----------------------------------------------------------------------------
  110. void ctkAbstractPythonManagerTester::testPythonErrorOccured_data()
  111. {
  112. QTest::addColumn<QString>("pythonCode");
  113. QTest::addColumn<bool>("errorOccured");
  114. QTest::newRow("0") << QString("2 + 2") << false;
  115. QTest::newRow("1") << QString("raise Exception('This exception is expected')") << true;
  116. }
  117. // ----------------------------------------------------------------------------
  118. void ctkAbstractPythonManagerTester::testAddObjectToPythonMain()
  119. {
  120. QObject * object = new QObject(this);
  121. object->setProperty("happy", true);
  122. this->PythonManager.addObjectToPythonMain("testAddObjectToPythonMain", object);
  123. QVariant returnValue = this->PythonManager.executeString("testAddObjectToPythonMain.happy",
  124. ctkAbstractPythonManager::EvalInput);
  125. this->PythonManager.resetErrorFlag();
  126. QCOMPARE(returnValue, QVariant(true));
  127. }
  128. // ----------------------------------------------------------------------------
  129. void ctkAbstractPythonManagerTester::testExecuteString()
  130. {
  131. QFETCH(QString, stringToExecute);
  132. QFETCH(int, executeStringMode);
  133. QFETCH(bool, errorOccured);
  134. QFETCH(QVariant, expectedReturnValue);
  135. QFETCH(QString, expectedVariableName);
  136. QFETCH(QVariant, expectedVariableValue);
  137. QVariant returnValue = this->PythonManager.executeString(
  138. stringToExecute,
  139. static_cast<ctkAbstractPythonManager::ExecuteStringMode>(executeStringMode));
  140. QCOMPARE(this->PythonManager.pythonErrorOccured(), errorOccured);
  141. if (errorOccured)
  142. {
  143. this->PythonManager.resetErrorFlag();
  144. return;
  145. }
  146. QCOMPARE(returnValue, expectedReturnValue);
  147. QCOMPARE(this->PythonManager.getVariable(expectedVariableName), expectedVariableValue);
  148. }
  149. // ----------------------------------------------------------------------------
  150. void ctkAbstractPythonManagerTester::testExecuteString_data()
  151. {
  152. QTest::addColumn<QString>("stringToExecute");
  153. QTest::addColumn<int>("executeStringMode");
  154. QTest::addColumn<bool>("errorOccured");
  155. QTest::addColumn<QVariant>("expectedReturnValue");
  156. QTest::addColumn<QString>("expectedVariableName");
  157. QTest::addColumn<QVariant>("expectedVariableValue");
  158. QTest::newRow("0") << QString("a = 6542")
  159. << static_cast<int>(ctkAbstractPythonManager::FileInput)
  160. << false
  161. << QVariant() << QString("a") << QVariant(6542);
  162. QTest::newRow("1") << QString("6543")
  163. << static_cast<int>(ctkAbstractPythonManager::FileInput)
  164. << false
  165. << QVariant() << QString("a") << QVariant(6542);
  166. QTest::newRow("2") << QString("b = 6544")
  167. << static_cast<int>(ctkAbstractPythonManager::EvalInput)
  168. << true
  169. << QVariant() << QString("b") << QVariant();
  170. QTest::newRow("3") << QString("7")
  171. << static_cast<int>(ctkAbstractPythonManager::EvalInput)
  172. << false
  173. << QVariant(7) << QString("b") << QVariant();
  174. QTest::newRow("4") << QString("sys.getrecursionlimit()")
  175. << static_cast<int>(ctkAbstractPythonManager::FileInput)
  176. << false
  177. << QVariant() << QString() << QVariant();
  178. // This assume the default 'recursionlimit' has not been changed
  179. QTest::newRow("5") << QString("sys.getrecursionlimit()")
  180. << static_cast<int>(ctkAbstractPythonManager::EvalInput)
  181. << false
  182. << QVariant(1000) << QString() << QVariant();
  183. }
  184. // ----------------------------------------------------------------------------
  185. void ctkAbstractPythonManagerTester::testExecuteFile()
  186. {
  187. QFETCH(QString, stringToExecute);
  188. QFETCH(bool, pythonErrorExpected);
  189. QTemporaryFile pythonFile("testExecuteFile-XXXXXX.py");
  190. QVERIFY(pythonFile.open());
  191. QTextStream out(&pythonFile);
  192. out << stringToExecute;
  193. pythonFile.close();
  194. this->PythonManager.executeFile(pythonFile.fileName());
  195. QCOMPARE(this->PythonManager.pythonErrorOccured(), pythonErrorExpected);
  196. }
  197. // ----------------------------------------------------------------------------
  198. void ctkAbstractPythonManagerTester::testExecuteFile_data()
  199. {
  200. QTest::addColumn<QString>("stringToExecute");
  201. QTest::addColumn<bool>("pythonErrorExpected");
  202. QTest::newRow("0-emptyfile") << QString("")
  203. << false;
  204. QTest::newRow("1-helloworld") << QString("print 'Hello world'")
  205. << false;
  206. QTest::newRow("2-syntaxerror") << QString("print '") // SyntaxError
  207. << true;
  208. QTest::newRow("3-check __file__ attribute") << QString("print 'This file is: %s' % __file__")
  209. << false;
  210. }
  211. // ----------------------------------------------------------------------------
  212. void ctkAbstractPythonManagerTester::testPythonAttributes()
  213. {
  214. QFETCH(QString, pythonVariableName);
  215. QFETCH(QStringList, expectedAttributeList);
  216. QString test_path = __FILE__; // return the local path of this source file
  217. test_path.lastIndexOf("/");
  218. test_path.replace(test_path.lastIndexOf("/"),
  219. test_path.size() - test_path.lastIndexOf("/"),
  220. "/PythonAttributes-test.py");
  221. this->PythonManager.executeFile(test_path);
  222. QStringList AttributeList = this->PythonManager.pythonAttributes(pythonVariableName, QString("__main__").toLatin1(), false);
  223. foreach (const QString& expectedAttribute, expectedAttributeList)
  224. {
  225. QVERIFY(AttributeList.contains(expectedAttribute));
  226. }
  227. }
  228. // ----------------------------------------------------------------------------
  229. void ctkAbstractPythonManagerTester::testPythonAttributes_data()
  230. {
  231. QTest::addColumn<QString>("pythonVariableName");
  232. QTest::addColumn<QStringList>("expectedAttributeList");
  233. QTest::newRow("d.foo_class()")
  234. << "d.foo_class()"
  235. << (QStringList()
  236. << "FOO_CLASS_MEMBER"
  237. << "foo_class_method"
  238. << "foo_instance_member"
  239. << "foo_instance_method"
  240. << "instantiate_bar");
  241. QTest::newRow("d.foo_class().instantiate_bar()")
  242. << "d.foo_class().instantiate_bar()"
  243. << (QStringList()
  244. << "BAR_CLASS_MEMBER"
  245. << "bar_class_method"
  246. << "bar_instance_member"
  247. << "bar_instance_method");
  248. QTest::newRow("d.foo_class().instantiate_bar().bar_maths(5)")
  249. << "d.foo_class().instantiate_bar().bar_maths(5)"
  250. << (QStringList()
  251. << "MATHS_CLASS_MEMBER"
  252. << "maths_instance_member"
  253. << "maths_instance_method");
  254. QTest::newRow("MultipleArg( 5 + 5 , '(')")
  255. << "MultipleArg( 5 + 5 , '(')"
  256. << (QStringList()
  257. << "multipleArg_instance_member_num"
  258. << "multipleArg_instance_member_str"
  259. << "multipleArg_instance_member_other");
  260. QTest::newRow("MultipleArg( 5 % 5 + 1, '\"', 0.1)")
  261. << "MultipleArg( 5 % 5 + 1, '\"', 0.1)"
  262. << (QStringList()
  263. << "multipleArg_instance_member_num"
  264. << "multipleArg_instance_member_str"
  265. << "multipleArg_instance_member_other");
  266. }
  267. // ----------------------------------------------------------------------------
  268. void ctkAbstractPythonManagerTester::testPythonAttributeValues()
  269. {
  270. QFETCH(QString, code);
  271. QFETCH(QVariant, expectedValue);
  272. QString test_path = __FILE__; // return the local path of this source file
  273. test_path.lastIndexOf("/");
  274. test_path.replace(test_path.lastIndexOf("/"),
  275. test_path.size() - test_path.lastIndexOf("/"),
  276. "/PythonAttributes-test.py");
  277. this->PythonManager.executeFile(test_path);
  278. this->PythonManager.executeString(QString("value=%1").arg(code));
  279. QCOMPARE(
  280. this->PythonManager.getVariable("value"),
  281. expectedValue);
  282. }
  283. // ----------------------------------------------------------------------------
  284. void ctkAbstractPythonManagerTester::testPythonAttributeValues_data()
  285. {
  286. QTest::addColumn<QString>("code");
  287. QTest::addColumn<QVariant>("expectedValue");
  288. QString code;
  289. code = "d.foo_class().instantiate_bar().bar_maths(5).MATHS_CLASS_MEMBER";
  290. QTest::newRow(code.toLatin1())
  291. << code
  292. << QVariant(0.1);
  293. code = "d.foo_class().instantiate_bar().bar_maths(5).maths_instance_member";
  294. QTest::newRow(code.toLatin1())
  295. << code
  296. << QVariant(5);
  297. code = "MultipleArg( 5 + 5 , '(').multipleArg_instance_member_num";
  298. QTest::newRow(code.toLatin1())
  299. << code
  300. << QVariant(10);
  301. code = "MultipleArg( 5 + 5 , '(').multipleArg_instance_member_str";
  302. QTest::newRow(code.toLatin1())
  303. << code
  304. << QVariant("(");
  305. code = "MultipleArg( 5 + 5 , '(').multipleArg_instance_member_other";
  306. QTest::newRow(code.toLatin1())
  307. << code
  308. << QVariant(0);
  309. code = "MultipleArg( 5 % 5 + 1, '\"', 0.1).multipleArg_instance_member_num";
  310. QTest::newRow(code.toLatin1())
  311. << code
  312. << QVariant(1.1);
  313. code = "MultipleArg( 5 % 5 + 1, '\"', 0.1).multipleArg_instance_member_str";
  314. QTest::newRow(code.toLatin1())
  315. << code
  316. << QVariant("\"");
  317. code = "MultipleArg( 5 % 5 + 1, '\"', 0.1).multipleArg_instance_member_other";
  318. QTest::newRow(code.toLatin1())
  319. << code
  320. << QVariant(0.1);
  321. }
  322. // ----------------------------------------------------------------------------
  323. void ctkAbstractPythonManagerTester::testPythonModule()
  324. {
  325. QFETCH(QString, pythonCode);
  326. QFETCH(QString, inputModuleList);
  327. QFETCH(QString, expectedReturnedString);
  328. this->PythonManager.executeString(pythonCode);
  329. PyObject* returnedPyObject = this->PythonManager.pythonModule(inputModuleList);
  330. PyObject* returnedPyString;
  331. if(returnedPyObject)
  332. {
  333. returnedPyString = PyObject_GetAttrString(returnedPyObject, "__name__");
  334. }
  335. else
  336. {
  337. returnedPyString = PyString_FromString("");
  338. }
  339. QString returnedString = PyString_AsString(returnedPyString);
  340. QCOMPARE(returnedString, expectedReturnedString);
  341. }
  342. // ----------------------------------------------------------------------------
  343. void ctkAbstractPythonManagerTester::testPythonModule_data()
  344. {
  345. QTest::addColumn<QString>("pythonCode");
  346. QTest::addColumn<QString>("inputModuleList");
  347. QTest::addColumn<QString>("expectedReturnedString");
  348. QTest::newRow("0") << ""
  349. << "__main__"
  350. << "__main__";
  351. QTest::newRow("1") << ""
  352. << "__main__.__builtins__"
  353. << "__builtin__";
  354. QTest::newRow("2") << "class foo: pass"
  355. << "__main__.foo"
  356. << "foo";
  357. QTest::newRow("3") << ""
  358. << "__main__.NOT_A_MODULE"
  359. << "";
  360. }
  361. //-----------------------------------------------------------------------------
  362. void ctkAbstractPythonManagerTester::testPythonObject()
  363. {
  364. QFETCH(QString, pythonCode);
  365. QFETCH(QString, inputPythonVariableNameAndFunction);
  366. QFETCH(QString, expectedReturnedString);
  367. this->PythonManager.executeString(pythonCode);
  368. PyObject* returnedPyObject = this->PythonManager.pythonObject(inputPythonVariableNameAndFunction);
  369. PyObject* returnedPyObjectString;
  370. if (returnedPyObject)
  371. {
  372. returnedPyObjectString = PyObject_GetAttrString(returnedPyObject, "__name__");
  373. }
  374. else
  375. {
  376. returnedPyObjectString = PyString_FromString("");
  377. }
  378. QString returnedString = PyString_AsString(returnedPyObjectString);
  379. QCOMPARE(returnedString, expectedReturnedString);
  380. }
  381. //-----------------------------------------------------------------------------
  382. void ctkAbstractPythonManagerTester::testPythonObject_data()
  383. {
  384. QTest::addColumn<QString>("pythonCode");
  385. QTest::addColumn<QString>("inputPythonVariableNameAndFunction");
  386. QTest::addColumn<QString>("expectedReturnedString");
  387. QTest::newRow("0") << "foo = []"
  388. << "__main__.foo.append"
  389. << "append";
  390. QTest::newRow("1") << ""
  391. << "__main__.__builtins__.dir"
  392. << "dir";
  393. QTest::newRow("2") << "class foo: bar = []"
  394. << "__main__.foo.bar.reverse"
  395. << "reverse";
  396. QTest::newRow("3") << ""
  397. << "__main__.__builtins__.NOT_A_FUNCTION"
  398. << "";
  399. }
  400. // ----------------------------------------------------------------------------
  401. CTK_TEST_MAIN(ctkAbstractPythonManagerTest)
  402. #include "moc_ctkAbstractPythonManagerTest.cpp"