ctkAbstractPythonManagerTest.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  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 testPythonModule();
  41. void testPythonModule_data();
  42. void testPythonObject();
  43. void testPythonObject_data();
  44. };
  45. Q_DECLARE_METATYPE(PyObject*)
  46. // ----------------------------------------------------------------------------
  47. void ctkAbstractPythonManagerTester::testDefaults()
  48. {
  49. QCOMPARE(this->PythonManager.pythonErrorOccured(), false);
  50. this->PythonManager.resetErrorFlag();
  51. this->PythonManager.registerPythonQtDecorator(0);
  52. this->PythonManager.registerClassForPythonQt(0);
  53. this->PythonManager.registerCPPClassForPythonQt(0);
  54. this->PythonManager.addWrapperFactory(0);
  55. }
  56. // ----------------------------------------------------------------------------
  57. void ctkAbstractPythonManagerTester::testIsPythonInitialized()
  58. {
  59. QCOMPARE(this->PythonManager.isPythonInitialized(), false);
  60. }
  61. // ----------------------------------------------------------------------------
  62. void ctkAbstractPythonManagerTester::testSetInitializationFlags()
  63. {
  64. QCOMPARE(this->PythonManager.initializationFlags(), PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
  65. int flagsToSetPreInit = PythonQt::RedirectStdOut;
  66. int expectedFlagsPreInit = PythonQt::RedirectStdOut;
  67. this->PythonManager.setInitializationFlags(flagsToSetPreInit);
  68. QCOMPARE(this->PythonManager.initializationFlags(), expectedFlagsPreInit);
  69. this->PythonManager.mainContext();
  70. int flagsToSetPostInit = 0;
  71. int expectedFlagsPostInit = PythonQt::RedirectStdOut;
  72. this->PythonManager.setInitializationFlags(flagsToSetPostInit);
  73. QCOMPARE(this->PythonManager.initializationFlags(), expectedFlagsPostInit);
  74. QCOMPARE(this->PythonManager.isPythonInitialized(), true);
  75. }
  76. // ----------------------------------------------------------------------------
  77. void ctkAbstractPythonManagerTester::testSetSystemExitExceptionHandlerEnabled()
  78. {
  79. QCOMPARE(this->PythonManager.systemExitExceptionHandlerEnabled(), false);
  80. this->PythonManager.setSystemExitExceptionHandlerEnabled(true);
  81. QCOMPARE(this->PythonManager.systemExitExceptionHandlerEnabled(), true);
  82. }
  83. // ----------------------------------------------------------------------------
  84. void ctkAbstractPythonManagerTester::testInitialize()
  85. {
  86. QVERIFY(this->PythonManager.initialize());
  87. this->testDefaults();
  88. }
  89. // ----------------------------------------------------------------------------
  90. void ctkAbstractPythonManagerTester::testMainContext()
  91. {
  92. QVERIFY(this->PythonManager.mainContext());
  93. this->testDefaults();
  94. }
  95. // ----------------------------------------------------------------------------
  96. void ctkAbstractPythonManagerTester::testPythonErrorOccured()
  97. {
  98. QFETCH(QString, pythonCode);
  99. QFETCH(bool, errorOccured);
  100. this->PythonManager.executeString(pythonCode);
  101. QCOMPARE(this->PythonManager.pythonErrorOccured(), errorOccured);
  102. if(errorOccured)
  103. {
  104. this->PythonManager.resetErrorFlag();
  105. }
  106. }
  107. // ----------------------------------------------------------------------------
  108. void ctkAbstractPythonManagerTester::testPythonErrorOccured_data()
  109. {
  110. QTest::addColumn<QString>("pythonCode");
  111. QTest::addColumn<bool>("errorOccured");
  112. QTest::newRow("0") << QString("2 + 2") << false;
  113. QTest::newRow("1") << QString("raise Exception('This exception is expected')") << true;
  114. }
  115. // ----------------------------------------------------------------------------
  116. void ctkAbstractPythonManagerTester::testAddObjectToPythonMain()
  117. {
  118. QObject * object = new QObject(this);
  119. object->setProperty("happy", true);
  120. this->PythonManager.addObjectToPythonMain("testAddObjectToPythonMain", object);
  121. QVariant returnValue = this->PythonManager.executeString("testAddObjectToPythonMain.happy",
  122. ctkAbstractPythonManager::EvalInput);
  123. this->PythonManager.resetErrorFlag();
  124. QCOMPARE(returnValue, QVariant(true));
  125. }
  126. // ----------------------------------------------------------------------------
  127. void ctkAbstractPythonManagerTester::testExecuteString()
  128. {
  129. QFETCH(QString, stringToExecute);
  130. QFETCH(int, executeStringMode);
  131. QFETCH(bool, errorOccured);
  132. QFETCH(QVariant, expectedReturnValue);
  133. QFETCH(QString, expectedVariableName);
  134. QFETCH(QVariant, expectedVariableValue);
  135. QVariant returnValue = this->PythonManager.executeString(
  136. stringToExecute,
  137. static_cast<ctkAbstractPythonManager::ExecuteStringMode>(executeStringMode));
  138. QCOMPARE(this->PythonManager.pythonErrorOccured(), errorOccured);
  139. if (errorOccured)
  140. {
  141. this->PythonManager.resetErrorFlag();
  142. return;
  143. }
  144. QCOMPARE(returnValue, expectedReturnValue);
  145. QCOMPARE(this->PythonManager.getVariable(expectedVariableName), expectedVariableValue);
  146. }
  147. // ----------------------------------------------------------------------------
  148. void ctkAbstractPythonManagerTester::testExecuteString_data()
  149. {
  150. QTest::addColumn<QString>("stringToExecute");
  151. QTest::addColumn<int>("executeStringMode");
  152. QTest::addColumn<bool>("errorOccured");
  153. QTest::addColumn<QVariant>("expectedReturnValue");
  154. QTest::addColumn<QString>("expectedVariableName");
  155. QTest::addColumn<QVariant>("expectedVariableValue");
  156. QTest::newRow("0") << QString("a = 6542")
  157. << static_cast<int>(ctkAbstractPythonManager::FileInput)
  158. << false
  159. << QVariant() << QString("a") << QVariant(6542);
  160. QTest::newRow("1") << QString("6543")
  161. << static_cast<int>(ctkAbstractPythonManager::FileInput)
  162. << false
  163. << QVariant() << QString("a") << QVariant(6542);
  164. QTest::newRow("2") << QString("b = 6544")
  165. << static_cast<int>(ctkAbstractPythonManager::EvalInput)
  166. << true
  167. << QVariant() << QString("b") << QVariant();
  168. QTest::newRow("3") << QString("7")
  169. << static_cast<int>(ctkAbstractPythonManager::EvalInput)
  170. << false
  171. << QVariant(7) << QString("b") << QVariant();
  172. QTest::newRow("4") << QString("sys.getrecursionlimit()")
  173. << static_cast<int>(ctkAbstractPythonManager::FileInput)
  174. << false
  175. << QVariant() << QString() << QVariant();
  176. // This assume the default 'recursionlimit' has not been changed
  177. QTest::newRow("5") << QString("sys.getrecursionlimit()")
  178. << static_cast<int>(ctkAbstractPythonManager::EvalInput)
  179. << false
  180. << QVariant(1000) << QString() << QVariant();
  181. }
  182. // ----------------------------------------------------------------------------
  183. void ctkAbstractPythonManagerTester::testExecuteFile()
  184. {
  185. QFETCH(QString, stringToExecute);
  186. QFETCH(bool, pythonErrorExpected);
  187. QTemporaryFile pythonFile("testExecuteFile-XXXXXX.py");
  188. QVERIFY(pythonFile.open());
  189. QTextStream out(&pythonFile);
  190. out << stringToExecute;
  191. pythonFile.close();
  192. this->PythonManager.executeFile(pythonFile.fileName());
  193. QCOMPARE(this->PythonManager.pythonErrorOccured(), pythonErrorExpected);
  194. }
  195. // ----------------------------------------------------------------------------
  196. void ctkAbstractPythonManagerTester::testExecuteFile_data()
  197. {
  198. QTest::addColumn<QString>("stringToExecute");
  199. QTest::addColumn<bool>("pythonErrorExpected");
  200. QTest::newRow("0-emptyfile") << QString("")
  201. << false;
  202. QTest::newRow("1-helloworld") << QString("print 'Hello world'")
  203. << false;
  204. QTest::newRow("2-syntaxerror") << QString("print '") // SyntaxError
  205. << true;
  206. QTest::newRow("3-check __file__ attribute") << QString("print 'This file is: %s' % __file__")
  207. << false;
  208. }
  209. // ----------------------------------------------------------------------------
  210. void ctkAbstractPythonManagerTester::testPythonAttributes()
  211. {
  212. QFETCH(QString, pythonVariableName);
  213. QFETCH(QStringList, expectedAttributeList);
  214. QString test_path = __FILE__; // return the local path of this source file
  215. // replace "ctkAbstractPythonManagerTest.py" by "PythonAttributes-test.py"
  216. test_path.lastIndexOf("/");
  217. test_path.replace(test_path.lastIndexOf("/"),
  218. test_path.size() - test_path.lastIndexOf("/"),
  219. "/PythonAttributes-test.py");
  220. this->PythonManager.executeFile(test_path);
  221. QStringList AttributeList = this->PythonManager.pythonAttributes(pythonVariableName, QString("__main__").toLatin1(), false);
  222. foreach (const QString& expectedAttribute, expectedAttributeList)
  223. {
  224. QVERIFY(AttributeList.contains(expectedAttribute));
  225. }
  226. }
  227. // ----------------------------------------------------------------------------
  228. void ctkAbstractPythonManagerTester::testPythonAttributes_data()
  229. {
  230. QTest::addColumn<QString>("pythonVariableName");
  231. QTest::addColumn<QStringList>("expectedAttributeList");
  232. QTest::newRow("d.foo_class()")
  233. << "d.foo_class()"
  234. << (QStringList()
  235. << "FOO_CLASS_MEMBER"
  236. << "foo_class_method"
  237. << "foo_instance_member"
  238. << "foo_instance_method"
  239. << "instantiate_bar");
  240. QTest::newRow("d.foo_class().instantiate_bar()")
  241. << "d.foo_class().instantiate_bar()"
  242. << (QStringList()
  243. << "BAR_CLASS_MEMBER"
  244. << "bar_class_method"
  245. << "bar_instance_member"
  246. << "bar_instance_method");
  247. }
  248. // ----------------------------------------------------------------------------
  249. void ctkAbstractPythonManagerTester::testPythonModule()
  250. {
  251. QFETCH(QString, pythonCode);
  252. QFETCH(QString, inputModuleList);
  253. QFETCH(QString, expectedReturnedString);
  254. this->PythonManager.executeString(pythonCode);
  255. PyObject* returnedPyObject = this->PythonManager.pythonModule(inputModuleList);
  256. PyObject* returnedPyString;
  257. if(returnedPyObject)
  258. {
  259. returnedPyString = PyObject_GetAttrString(returnedPyObject, "__name__");
  260. }
  261. else
  262. {
  263. returnedPyString = PyString_FromString("");
  264. }
  265. QString returnedString = PyString_AsString(returnedPyString);
  266. QCOMPARE(returnedString, expectedReturnedString);
  267. }
  268. // ----------------------------------------------------------------------------
  269. void ctkAbstractPythonManagerTester::testPythonModule_data()
  270. {
  271. QTest::addColumn<QString>("pythonCode");
  272. QTest::addColumn<QString>("inputModuleList");
  273. QTest::addColumn<QString>("expectedReturnedString");
  274. QTest::newRow("0") << ""
  275. << "__main__"
  276. << "__main__";
  277. QTest::newRow("1") << ""
  278. << "__main__.__builtins__"
  279. << "__builtin__";
  280. QTest::newRow("2") << "class foo: pass"
  281. << "__main__.foo"
  282. << "foo";
  283. QTest::newRow("3") << ""
  284. << "__main__.NOT_A_MODULE"
  285. << "";
  286. }
  287. //-----------------------------------------------------------------------------
  288. void ctkAbstractPythonManagerTester::testPythonObject()
  289. {
  290. QFETCH(QString, pythonCode);
  291. QFETCH(QString, inputPythonVariableNameAndFunction);
  292. QFETCH(QString, expectedReturnedString);
  293. this->PythonManager.executeString(pythonCode);
  294. PyObject* returnedPyObject = this->PythonManager.pythonObject(inputPythonVariableNameAndFunction);
  295. PyObject* returnedPyObjectString;
  296. if (returnedPyObject)
  297. {
  298. returnedPyObjectString = PyObject_GetAttrString(returnedPyObject, "__name__");
  299. }
  300. else
  301. {
  302. returnedPyObjectString = PyString_FromString("");
  303. }
  304. QString returnedString = PyString_AsString(returnedPyObjectString);
  305. QCOMPARE(returnedString, expectedReturnedString);
  306. }
  307. //-----------------------------------------------------------------------------
  308. void ctkAbstractPythonManagerTester::testPythonObject_data()
  309. {
  310. QTest::addColumn<QString>("pythonCode");
  311. QTest::addColumn<QString>("inputPythonVariableNameAndFunction");
  312. QTest::addColumn<QString>("expectedReturnedString");
  313. QTest::newRow("0") << "foo = []"
  314. << "__main__.foo.append"
  315. << "append";
  316. QTest::newRow("1") << ""
  317. << "__main__.__builtins__.dir"
  318. << "dir";
  319. QTest::newRow("2") << "class foo: bar = []"
  320. << "__main__.foo.bar.reverse"
  321. << "reverse";
  322. QTest::newRow("3") << ""
  323. << "__main__.__builtins__.NOT_A_FUNCTION"
  324. << "";
  325. }
  326. // ----------------------------------------------------------------------------
  327. CTK_TEST_MAIN(ctkAbstractPythonManagerTest)
  328. #include "moc_ctkAbstractPythonManagerTest.cpp"