ctkAbstractPythonManagerTest.cpp 12 KB

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