diff --git a/tests/PythonQtTestMain.cpp b/tests/PythonQtTestMain.cpp index 0c3ee42..f2bc682 100644 --- a/tests/PythonQtTestMain.cpp +++ b/tests/PythonQtTestMain.cpp @@ -48,14 +48,21 @@ int main( int argc, char **argv ) PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut); + int failCount = 0; PythonQtTestApi api; - QTest::qExec(&api, argc, argv); + failCount += QTest::qExec(&api, argc, argv); PythonQtTestSignalHandler signalHandler; - QTest::qExec(&signalHandler, argc, argv); + failCount += QTest::qExec(&signalHandler, argc, argv); PythonQtTestSlotCalling slotCalling; - QTest::qExec(&slotCalling, argc, argv); + failCount += QTest::qExec(&slotCalling, argc, argv); PythonQt::cleanup(); - return 0; + + if (failCount>0) { + std::cerr << "Tests failed: " << failCount << std::endl; + } else { + std::cout << "All tests passed successfully." << std::endl; + } + return failCount; } diff --git a/tests/PythonQtTests.cpp b/tests/PythonQtTests.cpp index 7585be7..8543faf 100644 --- a/tests/PythonQtTests.cpp +++ b/tests/PythonQtTests.cpp @@ -45,6 +45,7 @@ void PythonQtTestSlotCalling::initTestCase() { _helper = new PythonQtTestSlotCallingHelper(this); PythonQtObjectPtr main = PythonQt::self()->getMainModule(); + main.evalScript("import PythonQt"); PythonQt::self()->addObject(main, "obj", _helper); } @@ -52,6 +53,78 @@ void PythonQtTestSlotCalling::init() { } +void* polymorphic_ClassB_Handler(const void* ptr, char** className) { + ClassB* o = (ClassB*)ptr; + if (o->type()==2) { + *className = "ClassB"; + return (ClassB*)o; + } + if (o->type()==3) { + *className = "ClassC"; + return (ClassC*)o; + } + if (o->type()==4) { + *className = "ClassD"; + return (ClassD*)o; + } + return NULL; +} + +void PythonQtTestSlotCalling::testInheritance() { + PythonQt::self()->registerCPPClass("ClassA",NULL,NULL, PythonQtCreateObject); + PythonQt::self()->registerCPPClass("ClassB",NULL,NULL, PythonQtCreateObject); + PythonQt::self()->registerCPPClass("ClassC",NULL,NULL, PythonQtCreateObject); + PythonQt::self()->addParentClass("ClassC", "ClassA", PythonQtUpcastingOffset()); + PythonQt::self()->addParentClass("ClassC", "ClassB", PythonQtUpcastingOffset()); + PythonQt::self()->registerClass(&ClassD::staticMetaObject, NULL, PythonQtCreateObject); + PythonQt::self()->addParentClass("ClassD", "ClassA", PythonQtUpcastingOffset()); + PythonQt::self()->addParentClass("ClassD", "ClassB", PythonQtUpcastingOffset()); + + PythonQtObjectPtr classA = PythonQt::self()->getMainModule().getVariable("PythonQt.ClassA"); + PythonQtObjectPtr classB = PythonQt::self()->getMainModule().getVariable("PythonQt.ClassB"); + PythonQtObjectPtr classC = PythonQt::self()->getMainModule().getVariable("PythonQt.ClassC"); + PythonQtObjectPtr classD = PythonQt::self()->getMainModule().getVariable("PythonQt.ClassD"); + QVERIFY(classA); + QVERIFY(classB); + QVERIFY(classC); + QVERIFY(classD); + + QVERIFY(_helper->runScript("a = PythonQt.ClassA();\nif obj.getClassAPtr(a).getX()==1: obj.setPassed();\n")); + QEXPECT_FAIL("", "ClassB can not be converted to ClassA", Continue); + QVERIFY(_helper->runScript("a = PythonQt.ClassB();\nif obj.getClassAPtr(a).getX()==1: obj.setPassed();\n")); + QVERIFY(_helper->runScript("a = PythonQt.ClassC();\nif obj.getClassAPtr(a).getX()==1: obj.setPassed();\n")); + QVERIFY(_helper->runScript("a = PythonQt.ClassD();\nif obj.getClassAPtr(a).getX()==1: obj.setPassed();\n")); + + QEXPECT_FAIL("", "ClassA can not be converted to ClassB", Continue); + QVERIFY(_helper->runScript("a = PythonQt.ClassA();\nif obj.getClassBPtr(a).getY()==2: obj.setPassed();\n")); + QVERIFY(_helper->runScript("a = PythonQt.ClassB();\nif obj.getClassBPtr(a).getY()==2: obj.setPassed();\n")); + QVERIFY(_helper->runScript("a = PythonQt.ClassC();\nif obj.getClassBPtr(a).getY()==2: obj.setPassed();\n")); + QVERIFY(_helper->runScript("a = PythonQt.ClassD();\nif obj.getClassBPtr(a).getY()==2: obj.setPassed();\n")); + + QEXPECT_FAIL("", "ClassA can not be converted to ClassC", Continue); + QVERIFY(_helper->runScript("a = PythonQt.ClassA();\nif obj.getClassCPtr(a).getX()==1: obj.setPassed();\n")); + QEXPECT_FAIL("", "ClassB can not be converted to ClassC", Continue); + QVERIFY(_helper->runScript("a = PythonQt.ClassB();\nif obj.getClassCPtr(a).getX()==1: obj.setPassed();\n")); + QVERIFY(_helper->runScript("a = PythonQt.ClassC();\nif obj.getClassCPtr(a).getX()==1: obj.setPassed();\n")); + QEXPECT_FAIL("", "ClassD can not be converted to ClassC", Continue); + QVERIFY(_helper->runScript("a = PythonQt.ClassD();\nif obj.getClassCPtr(a).getX()==1: obj.setPassed();\n")); + + QVERIFY(_helper->runScript("if type(obj.createClassA())==PythonQt.ClassA: obj.setPassed();\n")); + QVERIFY(_helper->runScript("if type(obj.createClassB())==PythonQt.ClassB: obj.setPassed();\n")); + QVERIFY(_helper->runScript("if type(obj.createClassCAsA())==PythonQt.ClassA: obj.setPassed();\n")); + QVERIFY(_helper->runScript("if type(obj.createClassCAsB())==PythonQt.ClassB: obj.setPassed();\n")); + QVERIFY(_helper->runScript("if type(obj.createClassD())==PythonQt.ClassD: obj.setPassed();\n")); + QVERIFY(_helper->runScript("if type(obj.createClassDAsA())==PythonQt.ClassA: obj.setPassed();\n")); + QVERIFY(_helper->runScript("if type(obj.createClassDAsB())==PythonQt.ClassB: obj.setPassed();\n")); + + PythonQt::self()->addPolymorphicHandler("ClassB", polymorphic_ClassB_Handler); + + QVERIFY(_helper->runScript("if type(obj.getClassBPtr(obj.createClassB()))==PythonQt.ClassB: obj.setPassed();\n")); + QVERIFY(_helper->runScript("if type(obj.createClassCAsB())==PythonQt.ClassC: obj.setPassed();\n")); + QVERIFY(_helper->runScript("if type(obj.createClassDAsB())==PythonQt.ClassD: obj.setPassed();\n")); + +} + void PythonQtTestSlotCalling::testNoArgSlotCall() { QVERIFY(_helper->runScript("obj.testNoArg(); obj.setPassed();\n")); @@ -70,6 +143,29 @@ void PythonQtTestSlotCalling::testOverloadedCall() QVERIFY(_helper->runScript("obj.overload(12,13); obj.setPassed();\n", 6)); } +void PythonQtTestSlotCalling::testPyObjectSlotCall() +{ + QVERIFY(_helper->runScript("if obj.getPyObject(PythonQt)==PythonQt: obj.setPassed();\n")); + QVERIFY(_helper->runScript("if obj.getPyObject('Hello')=='Hello': obj.setPassed();\n")); + QVERIFY(_helper->runScript("if obj.getPyObjectFromVariant(PythonQt)==PythonQt: obj.setPassed();\n")); + QVERIFY(_helper->runScript("if obj.getPyObjectFromVariant2(PythonQt)==PythonQt: obj.setPassed();\n")); +// QVERIFY(_helper->runScript("if obj.getPyObjectFromPtr(PythonQt)==PythonQt: obj.setPassed();\n")); +} + +void PythonQtTestSlotCalling::testCPPSlotCalls() +{ + // test QColor compare operation + QVERIFY(_helper->runScript("if PythonQt.QtGui.QColor(1,2,3)==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();obj.testNoArg()\n")); + QVERIFY(_helper->runScript("if PythonQt.QtGui.QColor(1,2,3)!=PythonQt.QtGui.QColor(3,2,1): obj.setPassed();obj.testNoArg()\n")); + + // test passing/returning QColors + QVERIFY(_helper->runScript("if obj.getQColor1(PythonQt.QtGui.QColor(1,2,3))==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();\n")); + QVERIFY(_helper->runScript("if obj.getQColor2(PythonQt.QtGui.QColor(1,2,3))==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();\n")); + QVERIFY(_helper->runScript("if obj.getQColor3(PythonQt.QtGui.QColor(1,2,3))==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();\n")); + QVERIFY(_helper->runScript("if obj.getQColor4(PythonQt.QtGui.QColor(1,2,3))==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();\n")); + QVERIFY(_helper->runScript("if obj.getQColor5()==PythonQt.QtGui.QColor(1,2,3): obj.setPassed();\n")); +} + void PythonQtTestSlotCalling::testPODSlotCalls() { QVERIFY(_helper->runScript("if obj.getBool(False)==False: obj.setPassed();\n")); @@ -209,8 +305,9 @@ void PythonQtTestSignalHandler::testRecursiveSignalHandler() void PythonQtTestApi::initTestCase() { _helper = new PythonQtTestApiHelper(); - PythonQtObjectPtr main = PythonQt::self()->getMainModule(); - PythonQt::self()->addObject(main, "obj", _helper); + _main = PythonQt::self()->getMainModule(); + _main.evalScript("import PythonQt"); + _main.addObject("obj", _helper); } bool PythonQtTestApiHelper::call(const QString& function, const QVariantList& args, const QVariant& expectedResult) { @@ -275,6 +372,42 @@ void PythonQtTestApi::testImporter() PyRun_SimpleString("import bla\n"); } +void PythonQtTestApi::testQtNamespace() +{ + QVERIFY(!_main.getVariable("PythonQt.QtCore.Qt.red").toInt()==Qt::red); + QVERIFY(_main.getVariable("PythonQt.QtCore.Qt.FlatCap").toInt()==Qt::FlatCap); + QVERIFY(PythonQtObjectPtr(_main.getVariable("PythonQt.QtCore.Qt.escape"))); +} + +void PythonQtTestApi::testQColorDecorators() +{ + PythonQtObjectPtr colorClass = _main.getVariable("PythonQt.QtGui.QColor"); + QVERIFY(colorClass); + // verify that the class is in the correct module + QVERIFY(colorClass.getVariable("__module__") == "PythonQt.QtGui"); + // test on Qt module as well: + colorClass = _main.getVariable("PythonQt.Qt.QColor"); + QVERIFY(colorClass); + // constructors + QVERIFY(qVariantValue(colorClass.call(QVariantList() << 1 << 2 << 3)) == QColor(1,2,3)); + QVERIFY(qVariantValue(colorClass.call()) == QColor()); + QEXPECT_FAIL("", "Testing non-existing constructor", Continue); + QVERIFY(colorClass.call(QVariantList() << 1 << 2) != QVariant()); + + // check for decorated Cmyk enum value + QVERIFY(colorClass.getVariable("Cmyk").toInt() == QColor::Cmyk); + PythonQtObjectPtr staticMethod = colorClass.getVariable("fromRgb"); + QVERIFY(staticMethod); + // direct call of static method via class + QVERIFY(qVariantValue(colorClass.call("fromRgb", QVariantList() << 1 << 2 << 3)) == QColor(1,2,3)); + // direct call of static method + QVERIFY(qVariantValue(staticMethod.call(QVariantList() << 1 << 2 << 3)) == QColor(1,2,3)); + PythonQtObjectPtr publicMethod = colorClass.getVariable("red"); + QVERIFY(publicMethod); + // call with passing self in: + QVERIFY(colorClass.call("red", QVariantList() << QColor(255,0,0)).toInt() == 255); +} + QByteArray PythonQtTestApiHelper::readFileAsBytes(const QString& filename) { QByteArray b; diff --git a/tests/PythonQtTests.h b/tests/PythonQtTests.h index 6b14ebc..f163f77 100644 --- a/tests/PythonQtTests.h +++ b/tests/PythonQtTests.h @@ -63,12 +63,77 @@ private slots: void testVariables(); void testRedirect(); void testImporter(); + void testQColorDecorators(); + void testQtNamespace(); private: PythonQtTestApiHelper* _helper; + PythonQtObjectPtr _main; }; +class ClassA { +public: + ClassA() { x = 1; } + int x; +}; + +class ClassB { +public: + ClassB() { y = 2; } + int y; + + virtual int type() { return 2; } +}; + +class ClassC : public ClassA, public ClassB { +public: + ClassC() { z = 3; } + int z; + + virtual int type() { return 3; } +}; + +class ClassD : public QObject, public ClassA, public ClassB { + Q_OBJECT +public: + ClassD() { d = 4; } + public slots: + int getD() { return d; } +private: + int d; + + virtual int type() { return 4; } +}; + +class ClassAWrapper : public QObject { + Q_OBJECT +public slots: + ClassA* new_ClassA() { return new ClassA; } + int getX(ClassA* o) { return o->x; } +}; + +class ClassBWrapper : public QObject { + Q_OBJECT +public slots: + ClassB* new_ClassB() { return new ClassB; } + int getY(ClassB* o) { return o->y; } +}; + +class ClassCWrapper : public QObject { + Q_OBJECT +public slots: + ClassC* new_ClassC() { return new ClassC; } + int getZ(ClassC* o) { return o->z; } +}; + +class ClassDWrapper : public QObject { + Q_OBJECT + public slots: + ClassD* new_ClassD() { return new ClassD; } +}; + + //! test the PythonQt api (helper) class PythonQtTestApiHelper : public QObject , public PythonQtImportFileInterface { @@ -99,6 +164,7 @@ private: bool _passed; }; + // test implementation of the wrapper factory class PythonQtTestCppFactory : public PythonQtCppWrapperFactory { @@ -174,13 +240,14 @@ private slots: void testNoArgSlotCall(); void testPODSlotCalls(); + void testCPPSlotCalls(); void testQVariantSlotCalls(); void testObjectSlotCalls(); void testMultiArgsSlotCall(); - + void testPyObjectSlotCall(); void testOverloadedCall(); - void testCppFactory(); + void testInheritance(); private: PythonQtTestSlotCallingHelper* _helper; @@ -236,6 +303,19 @@ public slots: QStringList getQStringList(const QStringList& l) { _called = true; return l; } QVariant getQVariant(const QVariant& var) { _called = true; return var; } + // QColor as representative for C++ value classes + QColor getQColor1(const QColor& var) { _called = true; return var; } + QColor getQColor2(QColor& var) { _called = true; return var; } + QColor getQColor3(QColor* col) { _called = true; return *col; } + QColor getQColor4(const QVariant& color) { _called = true; return qVariantValue(color); } + QColor* getQColor5() { _called = true; static QColor c(1,2,3); return &c; } + + PyObject* getPyObject(PyObject* obj) { _called = true; return obj; } + PyObject* getPyObjectFromVariant(const QVariant& val) { _called = true; return PythonQtObjectPtr(val); }; + QVariant getPyObjectFromVariant2(const QVariant& val) { _called = true; return val; }; + // this does not yet work but is not required to work: + //PyObject* getPyObjectFromPtr(const PythonQtObjectPtr& val) { _called = true; return val; }; + //! testing pointer passing PythonQtTestSlotCallingHelper* getTestObject(PythonQtTestSlotCallingHelper* obj) { _called = true; return obj; } //! testing inheritance checking @@ -245,9 +325,6 @@ public slots: QObject* getNewObject() { _called = true; return new PythonQtTestSlotCallingHelper(NULL); } QVariantList getMultiArgs(int a, double b, const QString& str) { _called = true; return (QVariantList() << a << b << str); } - // more exotic, not yet tested - //void setByteArray(QByteArray array) { qDebug() << array.data(); } - //void setCharPtr(char* data) { qDebug() << data; } //! cpp wrapper factory test PQCppObject* createPQCppObject(int h) { _called = true; return new PQCppObject(h); } @@ -261,6 +338,20 @@ public slots: //! cpp wrapper factory test PQCppObjectNoWrap* getPQCppObjectNoWrap(PQCppObjectNoWrap* p) { _called = true; return p; } + ClassA* getClassAPtr(ClassA* o) { _called = true; return o; } + ClassB* getClassBPtr(ClassB* o) { _called = true; return o; } + ClassC* getClassCPtr(ClassC* o) { _called = true; return o; } + ClassD* getClassDPtr(ClassD* o) { _called = true; return o; } + + ClassA* createClassA() { _called = true; return new ClassA; } + ClassB* createClassB() { _called = true; return new ClassB; } + ClassC* createClassC() { _called = true; return new ClassC; } + ClassD* createClassD() { _called = true; return new ClassD; } + ClassA* createClassCAsA() { _called = true; return new ClassC; } + ClassB* createClassCAsB() { _called = true; return new ClassC; } + ClassA* createClassDAsA() { _called = true; return new ClassD; } + ClassB* createClassDAsB() { _called = true; return new ClassD; } + private: bool _passed; bool _called;