/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include "../qdbusmarshall/common.h" const char *slotSpy; QString valueSpy; QT_BEGIN_NAMESPACE namespace QTest { char *toString(QDBusMessage::MessageType t) { switch (t) { case QDBusMessage::InvalidMessage: return qstrdup("InvalidMessage"); case QDBusMessage::MethodCallMessage: return qstrdup("MethodCallMessage"); case QDBusMessage::ReplyMessage: return qstrdup("ReplyMessage"); case QDBusMessage::ErrorMessage: return qstrdup("ErrorMessage"); case QDBusMessage::SignalMessage: return qstrdup("SignalMessage"); default: return 0; } } } QT_END_NAMESPACE class tst_QDBusAbstractAdaptor: public QObject { Q_OBJECT private slots: void initTestCase() { commonInit(); } void methodCalls_data(); void methodCalls(); void methodCallScriptable(); void signalEmissions_data(); void signalEmissions(); void sameSignalDifferentPaths(); void sameObjectDifferentPaths(); void scriptableSignalOrNot(); void overloadedSignalEmission_data(); void overloadedSignalEmission(); void readProperties(); void readPropertiesInvalidInterface(); void readPropertiesEmptyInterface_data(); void readPropertiesEmptyInterface(); void readAllProperties(); void readAllPropertiesInvalidInterface(); void readAllPropertiesEmptyInterface_data(); void readAllPropertiesEmptyInterface(); void writeProperties(); void typeMatching_data(); void typeMatching(); void methodWithMoreThanOneReturnValue(); }; class QDBusSignalSpy: public QObject { Q_OBJECT public slots: void slot(const QDBusMessage &msg) { ++count; interface = msg.interface(); name = msg.member(); signature = msg.signature(); path = msg.path(); value.clear(); if (msg.arguments().count()) value = msg.arguments().at(0); } public: QDBusSignalSpy() : count(0) { } int count; QString interface; QString name; QString signature; QString path; QVariant value; }; class Interface1: public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "local.Interface1") public: Interface1(QObject *parent) : QDBusAbstractAdaptor(parent) { } }; class Interface2: public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "local.Interface2") Q_PROPERTY(QString prop1 READ prop1) Q_PROPERTY(QString prop2 READ prop2 WRITE setProp2 SCRIPTABLE true) Q_PROPERTY(QUrl nonDBusProperty READ nonDBusProperty) public: Interface2(QObject *parent) : QDBusAbstractAdaptor(parent) { setAutoRelaySignals(true); } QString prop1() const { return QLatin1String("QString Interface2::prop1() const"); } QString prop2() const { return QLatin1String("QString Interface2::prop2() const"); } void setProp2(const QString &value) { slotSpy = "void Interface2::setProp2(const QString &)"; valueSpy = value; } QUrl nonDBusProperty() const { return QUrl(); } void emitSignal(const QString &, const QVariant &) { emit signal(); } public slots: void method() { slotSpy = "void Interface2::method()"; } Q_SCRIPTABLE void scriptableMethod() { slotSpy = "void Interface2::scriptableMethod()"; } signals: void signal(); }; class Interface3: public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "local.Interface3") Q_PROPERTY(QString prop1 READ prop1) Q_PROPERTY(QString prop2 READ prop2 WRITE setProp2) Q_PROPERTY(QString interface3prop READ interface3prop) public: Interface3(QObject *parent) : QDBusAbstractAdaptor(parent) { setAutoRelaySignals(true); } QString prop1() const { return QLatin1String("QString Interface3::prop1() const"); } QString prop2() const { return QLatin1String("QString Interface3::prop2() const"); } void setProp2(const QString &value) { slotSpy = "void Interface3::setProp2(const QString &)"; valueSpy = value; } QString interface3prop() const { return QLatin1String("QString Interface3::interface3prop() const"); } void emitSignal(const QString &name, const QVariant &value) { if (name == "signalVoid") emit signalVoid(); else if (name == "signalInt") emit signalInt(value.toInt()); else if (name == "signalString") emit signalString(value.toString()); } public slots: void methodVoid() { slotSpy = "void Interface3::methodVoid()"; } void methodInt(int) { slotSpy = "void Interface3::methodInt(int)"; } void methodString(QString) { slotSpy = "void Interface3::methodString(QString)"; } int methodStringString(const QString &s, QString &out) { slotSpy = "int Interface3::methodStringString(const QString &, QString &)"; out = s; return 42; } signals: void signalVoid(); void signalInt(int); void signalString(const QString &); }; class Interface4: public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "local.Interface4") Q_PROPERTY(QString prop1 READ prop1) Q_PROPERTY(QString prop2 READ prop2 WRITE setProp2) Q_PROPERTY(QString interface4prop READ interface4prop) public: Interface4(QObject *parent) : QDBusAbstractAdaptor(parent) { setAutoRelaySignals(true); } QString prop1() const { return QLatin1String("QString Interface4::prop1() const"); } QString prop2() const { return QLatin1String("QString Interface4::prop2() const"); } QString interface4prop() const { return QLatin1String("QString Interface4::interface4prop() const"); } void setProp2(const QString &value) { slotSpy = "void Interface4::setProp2(const QString &)"; valueSpy = value; } void emitSignal(const QString &, const QVariant &value) { switch (value.type()) { case QVariant::Invalid: emit signal(); break; case QVariant::Int: emit signal(value.toInt()); break; case QVariant::String: emit signal(value.toString()); break; default: break; } } public slots: void method() { slotSpy = "void Interface4::method()"; } void method(int) { slotSpy = "void Interface4::method(int)"; } void method(QString) { slotSpy = "void Interface4::method(QString)"; } signals: void signal(); void signal(int); void signal(const QString &); }; class MyObject: public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "local.MyObject") public: Interface1 *if1; Interface2 *if2; Interface3 *if3; Interface4 *if4; MyObject(int n = 4) : if1(0), if2(0), if3(0), if4(0) { switch (n) { case 4: if4 = new Interface4(this); case 3: if3 = new Interface3(this); case 2: if2 = new Interface2(this); case 1: if1 = new Interface1(this); } } void emitSignal(const QString &name, const QVariant &value) { if (name == "scriptableSignalVoid") emit scriptableSignalVoid(); else if (name == "scriptableSignalInt") emit scriptableSignalInt(value.toInt()); else if (name == "scriptableSignalString") emit scriptableSignalString(value.toString()); else if (name == "nonScriptableSignalVoid") emit nonScriptableSignalVoid(); } signals: Q_SCRIPTABLE void scriptableSignalVoid(); Q_SCRIPTABLE void scriptableSignalInt(int); Q_SCRIPTABLE void scriptableSignalString(QString); void nonScriptableSignalVoid(); }; class TypesInterface: public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "local.TypesInterface") public: TypesInterface(QObject *parent) : QDBusAbstractAdaptor(parent) { } union { bool b; uchar uc; short s; ushort us; int i; uint ui; qlonglong ll; qulonglong ull; double d; } dataSpy; QVariant variantSpy; QString stringSpy; QVariantList listSpy; QStringList stringlistSpy; QByteArray bytearraySpy; QVariantMap mapSpy; StringStringMap ssmapSpy; LLDateTimeMap lldtmapSpy; MyStruct structSpy; public slots: void methodBool(bool b) { slotSpy = "void TypesInterface::methodBool(bool)"; dataSpy.b = b; } void methodUChar(uchar uc) { slotSpy = "void TypesInterface::methodUChar(uchar)"; dataSpy.uc = uc; } void methodShort(short s) { slotSpy = "void TypesInterface::methodShort(short)"; dataSpy.s = s; } void methodUShort(ushort us) { slotSpy = "void TypesInterface::methodUShort(ushort)"; dataSpy.us = us; } void methodInt(int i) { slotSpy = "void TypesInterface::methodInt(int)"; dataSpy.i = i; } void methodUInt(uint ui) { slotSpy = "void TypesInterface::methodUInt(uint)"; dataSpy.ui = ui; } void methodLongLong(qlonglong ll) { slotSpy = "void TypesInterface::methodLongLong(qlonglong)"; dataSpy.ll = ll; } void methodULongLong(qulonglong ull) { slotSpy = "void TypesInterface::methodULongLong(qulonglong)"; dataSpy.ull = ull; } void methodDouble(double d) { slotSpy = "void TypesInterface::methodDouble(double)"; dataSpy.d = d; } void methodString(const QString &s) { slotSpy = "void TypesInterface::methodString(const QString &)"; stringSpy = s; } void methodObjectPath(const QDBusObjectPath &op) { slotSpy = "void TypesInterface::methodObjectPath(const QDBusObjectPath &)"; stringSpy = op.path(); } void methodSignature(const QDBusSignature &s) { slotSpy = "void TypesInterface::methodSignature(const QDBusSignature &)"; stringSpy = s.signature(); } void methodVariant(const QDBusVariant &v) { slotSpy = "void TypesInterface::methodVariant(const QDBusVariant &)"; variantSpy = v.variant(); } void methodList(const QVariantList &l) { slotSpy = "void TypesInterface::methodList(const QVariantList &)"; listSpy = l; } void methodStringList(const QStringList &sl) { slotSpy = "void TypesInterface::methodStringList(const QStringList &)"; stringlistSpy = sl; } void methodByteArray(const QByteArray &ba) { slotSpy = "void TypesInterface::methodByteArray(const QByteArray &)"; bytearraySpy = ba; } void methodMap(const QVariantMap &m) { slotSpy = "void TypesInterface::methodMap(const QVariantMap &)"; mapSpy = m; } void methodSSMap(const StringStringMap &ssmap) { slotSpy = "void TypesInterface::methodSSMap(const StringStringMap &)"; ssmapSpy = ssmap; } void methodLLDateTimeMap(const LLDateTimeMap &lldtmap) { slotSpy = "void TypesInterface::methodLLDateTimeMap(const LLDateTimeMap &)"; lldtmapSpy = lldtmap; } void methodStruct(const MyStruct &s) { slotSpy = "void TypesInterface::methodStruct(const MyStruct &)"; structSpy = s; } bool retrieveBool() { return dataSpy.b; } uchar retrieveUChar() { return dataSpy.uc; } short retrieveShort() { return dataSpy.s; } ushort retrieveUShort() { return dataSpy.us; } int retrieveInt() { return dataSpy.i; } uint retrieveUInt() { return dataSpy.ui; } qlonglong retrieveLongLong() { return dataSpy.ll; } qulonglong retrieveULongLong() { return dataSpy.ull; } double retrieveDouble() { return dataSpy.d; } QString retrieveString() { return stringSpy; } QDBusObjectPath retrieveObjectPath() { return QDBusObjectPath(stringSpy); } QDBusSignature retrieveSignature() { return QDBusSignature(stringSpy); } QDBusVariant retrieveVariant() { return QDBusVariant(variantSpy); } QVariantList retrieveList() { return listSpy; } QStringList retrieveStringList() { return stringlistSpy; } QByteArray retrieveByteArray() { return bytearraySpy; } QVariantMap retrieveMap() { return mapSpy; } StringStringMap retrieveSSMap() { return ssmapSpy; } LLDateTimeMap retrieveLLDateTimeMap() { return lldtmapSpy; } MyStruct retrieveStruct() { return structSpy; } }; void tst_QDBusAbstractAdaptor::methodCalls_data() { QTest::addColumn("nInterfaces"); QTest::newRow("0") << 0; QTest::newRow("1") << 1; QTest::newRow("2") << 2; QTest::newRow("3") << 3; QTest::newRow("4") << 4; } void tst_QDBusAbstractAdaptor::methodCalls() { QDBusConnection con = QDBusConnection::sessionBus(); QVERIFY(con.isConnected()); //QDBusInterface emptycon.baseService(), "/", QString()); { // must fail: no object QDBusInterface if1(con.baseService(), "/", "local.Interface1", con); QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage); } QFETCH(int, nInterfaces); MyObject obj(nInterfaces); con.registerObject("/", &obj); QDBusInterface if1(con.baseService(), "/", "local.Interface1", con); QDBusInterface if2(con.baseService(), "/", "local.Interface2", con); QDBusInterface if3(con.baseService(), "/", "local.Interface3", con); QDBusInterface if4(con.baseService(), "/", "local.Interface4", con); // must fail: no such method QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage); if (!nInterfaces--) return; if (!nInterfaces--) return; // simple call: one such method exists QCOMPARE(if2.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ReplyMessage); QCOMPARE(slotSpy, "void Interface2::method()"); if (!nInterfaces--) return; // multiple methods in multiple interfaces, no name overlap QCOMPARE(if1.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ErrorMessage); QCOMPARE(if1.call(QDBus::BlockWithGui, "methodInt").type(), QDBusMessage::ErrorMessage); QCOMPARE(if1.call(QDBus::BlockWithGui, "methodString").type(), QDBusMessage::ErrorMessage); QCOMPARE(if2.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ErrorMessage); QCOMPARE(if2.call(QDBus::BlockWithGui, "methodInt").type(), QDBusMessage::ErrorMessage); QCOMPARE(if2.call(QDBus::BlockWithGui, "methodString").type(), QDBusMessage::ErrorMessage); QCOMPARE(if3.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ReplyMessage); QCOMPARE(slotSpy, "void Interface3::methodVoid()"); QCOMPARE(if3.call(QDBus::BlockWithGui, "methodInt", 42).type(), QDBusMessage::ReplyMessage); QCOMPARE(slotSpy, "void Interface3::methodInt(int)"); QCOMPARE(if3.call(QDBus::BlockWithGui, "methodString", QString("")).type(), QDBusMessage::ReplyMessage); QCOMPARE(slotSpy, "void Interface3::methodString(QString)"); if (!nInterfaces--) return; // method overloading: different interfaces QCOMPARE(if4.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ReplyMessage); QCOMPARE(slotSpy, "void Interface4::method()"); // method overloading: different parameters QCOMPARE(if4.call(QDBus::BlockWithGui, "method.i", 42).type(), QDBusMessage::ReplyMessage); QCOMPARE(slotSpy, "void Interface4::method(int)"); QCOMPARE(if4.call(QDBus::BlockWithGui, "method.s", QString()).type(), QDBusMessage::ReplyMessage); QCOMPARE(slotSpy, "void Interface4::method(QString)"); } void tst_QDBusAbstractAdaptor::methodCallScriptable() { QDBusConnection con = QDBusConnection::sessionBus(); QVERIFY(con.isConnected()); MyObject obj(2); con.registerObject("/", &obj); QDBusInterface if2(con.baseService(), "/", "local.Interface2", con); QCOMPARE(if2.call(QDBus::BlockWithGui,"scriptableMethod").type(), QDBusMessage::ReplyMessage); QCOMPARE(slotSpy, "void Interface2::scriptableMethod()"); } static void emitSignal(MyObject *obj, const QString &iface, const QString &name, const QVariant ¶meter) { if (iface.endsWith('2')) obj->if2->emitSignal(name, parameter); else if (iface.endsWith('3')) obj->if3->emitSignal(name, parameter); else if (iface.endsWith('4')) obj->if4->emitSignal(name, parameter); else obj->emitSignal(name, parameter); QTest::qWait(200); } void tst_QDBusAbstractAdaptor::signalEmissions_data() { QTest::addColumn("interface"); QTest::addColumn("name"); QTest::addColumn("signature"); QTest::addColumn("parameter"); QTest::newRow("Interface2.signal") << "local.Interface2" << "signal" << QString() << QVariant(); QTest::newRow("Interface3.signalVoid") << "local.Interface3" << "signalVoid" << QString() << QVariant(); QTest::newRow("Interface3.signalInt") << "local.Interface3" << "signalInt" << "i" << QVariant(1); QTest::newRow("Interface3.signalString") << "local.Interface3" << "signalString" << "s" << QVariant("foo"); QTest::newRow("MyObject.scriptableSignalVoid") << "local.MyObject" << "scriptableSignalVoid" << QString() << QVariant(); QTest::newRow("MyObject.scriptableSignalInt") << "local.MyObject" << "scriptableSignalInt" << "i" << QVariant(1); QTest::newRow("MyObject.nySignalString") << "local.MyObject" << "scriptableSignalString" << "s" << QVariant("foo"); } void tst_QDBusAbstractAdaptor::signalEmissions() { QFETCH(QString, interface); QFETCH(QString, name); QFETCH(QVariant, parameter); QDBusConnection con = QDBusConnection::sessionBus(); QVERIFY(con.isConnected()); con.registerService("com.trolltech.tst_QDBusAbstractAdaptor"); MyObject obj(3); con.registerObject("/", &obj, QDBusConnection::ExportAdaptors | QDBusConnection::ExportScriptableSignals); // connect all signals and emit only one { QDBusSignalSpy spy; con.connect(con.baseService(), "/", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); con.connect(con.baseService(), "/", "local.Interface3", "signalVoid", &spy, SLOT(slot(QDBusMessage))); con.connect(con.baseService(), "/", "local.Interface3", "signalInt", &spy, SLOT(slot(QDBusMessage))); con.connect(con.baseService(), "/", "local.Interface3", "signalString", &spy, SLOT(slot(QDBusMessage))); con.connect(con.baseService(), "/", "local.MyObject", "scriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); con.connect(con.baseService(), "/", "local.MyObject", "scriptableSignalInt", &spy, SLOT(slot(QDBusMessage))); con.connect(con.baseService(), "/", "local.MyObject", "scriptableSignalString", &spy, SLOT(slot(QDBusMessage))); emitSignal(&obj, interface, name, parameter); QCOMPARE(spy.count, 1); QCOMPARE(spy.interface, interface); QCOMPARE(spy.name, name); QTEST(spy.signature, "signature"); QCOMPARE(spy.value, parameter); } // connect one signal and emit them all { QDBusSignalSpy spy; con.connect(con.baseService(), "/", interface, name, &spy, SLOT(slot(QDBusMessage))); emitSignal(&obj, "local.Interface2", "signal", QVariant()); emitSignal(&obj, "local.Interface3", "signalVoid", QVariant()); emitSignal(&obj, "local.Interface3", "signalInt", QVariant(1)); emitSignal(&obj, "local.Interface3", "signalString", QVariant("foo")); emitSignal(&obj, "local.MyObject", "scriptableSignalVoid", QVariant()); emitSignal(&obj, "local.MyObject", "scriptableSignalInt", QVariant(1)); emitSignal(&obj, "local.MyObject", "scriptableSignalString", QVariant("foo")); QCOMPARE(spy.count, 1); QCOMPARE(spy.interface, interface); QCOMPARE(spy.name, name); QTEST(spy.signature, "signature"); QCOMPARE(spy.value, parameter); } } void tst_QDBusAbstractAdaptor::sameSignalDifferentPaths() { QDBusConnection con = QDBusConnection::sessionBus(); QVERIFY(con.isConnected()); MyObject obj(2); con.registerObject("/p1",&obj); con.registerObject("/p2",&obj); QDBusSignalSpy spy; con.connect(con.baseService(), "/p1", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); obj.if2->emitSignal(QString(), QVariant()); QTest::qWait(200); QCOMPARE(spy.count, 1); QCOMPARE(spy.interface, QString("local.Interface2")); QCOMPARE(spy.name, QString("signal")); QVERIFY(spy.signature.isEmpty()); // now connect the other one spy.count = 0; con.connect(con.baseService(), "/p2", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); obj.if2->emitSignal(QString(), QVariant()); QTest::qWait(200); QCOMPARE(spy.count, 2); } void tst_QDBusAbstractAdaptor::sameObjectDifferentPaths() { QDBusConnection con = QDBusConnection::sessionBus(); QVERIFY(con.isConnected()); MyObject obj(2); con.registerObject("/p1",&obj); con.registerObject("/p2",&obj, 0); // don't export anything QDBusSignalSpy spy; con.connect(con.baseService(), "/p1", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); con.connect(con.baseService(), "/p2", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); obj.if2->emitSignal(QString(), QVariant()); QTest::qWait(200); QCOMPARE(spy.count, 1); QCOMPARE(spy.interface, QString("local.Interface2")); QCOMPARE(spy.name, QString("signal")); QVERIFY(spy.signature.isEmpty()); } void tst_QDBusAbstractAdaptor::scriptableSignalOrNot() { QDBusConnection con = QDBusConnection::sessionBus(); QVERIFY(con.isConnected()); { MyObject obj(0); con.registerObject("/p1",&obj, QDBusConnection::ExportScriptableSignals); con.registerObject("/p2",&obj, 0); // don't export anything QDBusSignalSpy spy; con.connect(con.baseService(), "/p1", "local.MyObject", "scriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); con.connect(con.baseService(), "/p2", "local.MyObject", "scriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); con.connect(con.baseService(), "/p1", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); con.connect(con.baseService(), "/p2", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); obj.emitSignal("scriptableSignalVoid", QVariant()); obj.emitSignal("nonScriptableSignalVoid", QVariant()); QTest::qWait(200); QCOMPARE(spy.count, 1); // only /p1 must have emitted QCOMPARE(spy.interface, QString("local.MyObject")); QCOMPARE(spy.name, QString("scriptableSignalVoid")); QCOMPARE(spy.path, QString("/p1")); QVERIFY(spy.signature.isEmpty()); } { MyObject obj(0); con.registerObject("/p1",&obj, QDBusConnection::ExportScriptableSignals); con.registerObject("/p2",&obj, QDBusConnection::ExportScriptableSignals | QDBusConnection::ExportNonScriptableSignals); QDBusSignalSpy spy; con.connect(con.baseService(), "/p1", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); con.connect(con.baseService(), "/p2", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); obj.emitSignal("nonScriptableSignalVoid", QVariant()); QTest::qWait(200); QCOMPARE(spy.count, 1); // only /p2 must have emitted now QCOMPARE(spy.interface, QString("local.MyObject")); QCOMPARE(spy.name, QString("nonScriptableSignalVoid")); QCOMPARE(spy.path, QString("/p2")); QVERIFY(spy.signature.isEmpty()); } { QDBusSignalSpy spy; con.connect(con.baseService(), "/p1", "local.MyObject", "destroyed", &spy, SLOT(slot(QDBusMessage))); con.connect(con.baseService(), "/p2", "local.MyObject", "destroyed", &spy, SLOT(slot(QDBusMessage))); { MyObject obj(0); con.registerObject("/p1",&obj, QDBusConnection::ExportScriptableSignals); con.registerObject("/p2",&obj, QDBusConnection::ExportScriptableSignals | QDBusConnection::ExportNonScriptableSignals); } // <--- QObject emits the destroyed(QObject*) signal at this point QTest::qWait(200); QCOMPARE(spy.count, 0); } } void tst_QDBusAbstractAdaptor::overloadedSignalEmission_data() { QTest::addColumn("signature"); QTest::addColumn("parameter"); QTest::newRow("void") << QString("") << QVariant(); QTest::newRow("int") << "i" << QVariant(1); QTest::newRow("string") << "s" << QVariant("foo"); } void tst_QDBusAbstractAdaptor::overloadedSignalEmission() { QDBusConnection con = QDBusConnection::sessionBus(); QVERIFY(con.isConnected()); MyObject obj; con.registerObject("/", &obj); QString interface = "local.Interface4"; QString name = "signal"; QFETCH(QVariant, parameter); //QDBusInterface *if4 = new QDBusInterface(con.baseService(), "/", interface, con); // connect all signals and emit only one { QDBusSignalSpy spy; con.connect(con.baseService(), "/", "local.Interface4", "signal", "", &spy, SLOT(slot(QDBusMessage))); con.connect(con.baseService(), "/", "local.Interface4", "signal", "i", &spy, SLOT(slot(QDBusMessage))); con.connect(con.baseService(), "/", "local.Interface4", "signal", "s", &spy, SLOT(slot(QDBusMessage))); emitSignal(&obj, interface, name, parameter); QCOMPARE(spy.count, 1); QCOMPARE(spy.interface, interface); QCOMPARE(spy.name, name); QTEST(spy.signature, "signature"); QCOMPARE(spy.value, parameter); } QFETCH(QString, signature); // connect one signal and emit them all { QDBusSignalSpy spy; con.connect(con.baseService(), "/", interface, name, signature, &spy, SLOT(slot(QDBusMessage))); emitSignal(&obj, "local.Interface4", "signal", QVariant()); emitSignal(&obj, "local.Interface4", "signal", QVariant(1)); emitSignal(&obj, "local.Interface4", "signal", QVariant("foo")); QCOMPARE(spy.count, 1); QCOMPARE(spy.interface, interface); QCOMPARE(spy.name, name); QTEST(spy.signature, "signature"); QCOMPARE(spy.value, parameter); } } void tst_QDBusAbstractAdaptor::readProperties() { QDBusConnection con = QDBusConnection::sessionBus(); QVERIFY(con.isConnected()); MyObject obj; con.registerObject("/", &obj); QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con); for (int i = 2; i <= 4; ++i) { QString name = QString("Interface%1").arg(i); for (int j = 1; j <= 2; ++j) { QString propname = QString("prop%1").arg(j); QDBusReply reply = properties.call(QDBus::BlockWithGui, "Get", "local." + name, propname); QVariant value = reply; QCOMPARE(value.userType(), int(QVariant::String)); QCOMPARE(value.toString(), QString("QString %1::%2() const").arg(name, propname)); } } } void tst_QDBusAbstractAdaptor::readPropertiesInvalidInterface() { QDBusConnection con = QDBusConnection::sessionBus(); QVERIFY(con.isConnected()); MyObject obj; con.registerObject("/", &obj); QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con); // test an invalid interface: QDBusReply reply = properties.call(QDBus::BlockWithGui, "Get", "local.DoesntExist", "prop1"); QVERIFY(!reply.isValid()); } void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterface_data() { QTest::addColumn("expectedProperties"); QTest::addColumn("existing"); QVariantMap expectedProperties; expectedProperties["prop1"] = QVariant(); expectedProperties["prop2"] = QVariant(); expectedProperties["interface3prop"] = "QString Interface3::interface3prop() const"; expectedProperties["interface4prop"] = "QString Interface4::interface4prop() const"; QTest::newRow("existing") << expectedProperties << true; expectedProperties.clear(); expectedProperties["prop5"] = QVariant(); expectedProperties["foobar"] = QVariant(); QTest::newRow("non-existing") << expectedProperties << false; } void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterface() { QDBusConnection con = QDBusConnection::sessionBus(); QVERIFY(con.isConnected()); MyObject obj; con.registerObject("/", &obj); QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con); QFETCH(QVariantMap, expectedProperties); QFETCH(bool, existing); QVariantMap::ConstIterator it = expectedProperties.constBegin(); for ( ; it != expectedProperties.constEnd(); ++it) { QDBusReply reply = properties.call(QDBus::BlockWithGui, "Get", "", it.key()); if (existing) { QVERIFY2(reply.isValid(), qPrintable(it.key())); } else { QVERIFY2(!reply.isValid(), qPrintable(it.key())); continue; } QCOMPARE(int(reply.value().type()), int(QVariant::String)); if (it.value().isValid()) QCOMPARE(reply.value().toString(), it.value().toString()); } } void tst_QDBusAbstractAdaptor::readAllProperties() { QDBusConnection con = QDBusConnection::sessionBus(); QVERIFY(con.isConnected()); MyObject obj; con.registerObject("/", &obj); QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con); for (int i = 2; i <= 4; ++i) { QString name = QString("Interface%1").arg(i); QDBusReply reply = properties.call(QDBus::BlockWithGui, "GetAll", "local." + name); for (int j = 1; j <= 2; ++j) { QString propname = QString("prop%1").arg(j); QVERIFY2(reply.value().contains(propname), qPrintable(propname + " on " + name)); QVariant value = reply.value().value(propname); QCOMPARE(value.userType(), int(QVariant::String)); QCOMPARE(value.toString(), QString("QString %1::%2() const").arg(name, propname)); } } } void tst_QDBusAbstractAdaptor::readAllPropertiesInvalidInterface() { QDBusConnection con = QDBusConnection::sessionBus(); QVERIFY(con.isConnected()); MyObject obj; con.registerObject("/", &obj); QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con); // test an invalid interface: QDBusReply reply = properties.call(QDBus::BlockWithGui, "GetAll", "local.DoesntExist"); QVERIFY(!reply.isValid()); } void tst_QDBusAbstractAdaptor::readAllPropertiesEmptyInterface_data() { readPropertiesEmptyInterface_data(); } void tst_QDBusAbstractAdaptor::readAllPropertiesEmptyInterface() { QDBusConnection con = QDBusConnection::sessionBus(); QVERIFY(con.isConnected()); MyObject obj; con.registerObject("/", &obj); QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con); QDBusReply reply = properties.call(QDBus::BlockWithGui, "GetAll", ""); QVERIFY(reply.isValid()); QVariantMap allprops = reply; QFETCH(QVariantMap, expectedProperties); QFETCH(bool, existing); QVariantMap::ConstIterator it = expectedProperties.constBegin(); if (existing) { for ( ; it != expectedProperties.constEnd(); ++it) { QVERIFY2(allprops.contains(it.key()), qPrintable(it.key())); QVariant propvalue = allprops.value(it.key()); QVERIFY2(!propvalue.isNull(), qPrintable(it.key())); QVERIFY2(propvalue.isValid(), qPrintable(it.key())); QString stringvalue = propvalue.toString(); QVERIFY2(!stringvalue.isEmpty(), qPrintable(it.key())); if (it.value().isValid()) QCOMPARE(stringvalue, it.value().toString()); // remove this property from the map allprops.remove(it.key()); } QVERIFY2(allprops.isEmpty(), qPrintable(QStringList(allprops.keys()).join(" "))); } else { for ( ; it != expectedProperties.constEnd(); ++it) QVERIFY2(!allprops.contains(it.key()), qPrintable(it.key())); } } void tst_QDBusAbstractAdaptor::writeProperties() { QDBusConnection con = QDBusConnection::sessionBus(); QVERIFY(con.isConnected()); MyObject obj; con.registerObject("/", &obj); QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con); for (int i = 2; i <= 4; ++i) { QString name = QString("Interface%1").arg(i); valueSpy.clear(); properties.call(QDBus::BlockWithGui, "Set", "local." + name, QString("prop1"), qVariantFromValue(QDBusVariant(name))); QVERIFY(valueSpy.isEmpty()); // call mustn't have succeeded properties.call(QDBus::BlockWithGui, "Set", "local." + name, QString("prop2"), qVariantFromValue(QDBusVariant(name))); QCOMPARE(valueSpy, name); QCOMPARE(QString(slotSpy), QString("void %1::setProp2(const QString &)").arg(name)); } } #if 0 void tst_QDBusAbstractAdaptor::adaptorIntrospection_data() { methodCalls_data(); } void tst_QDBusAbstractAdaptor::adaptorIntrospection() { QDBusConnection con = QDBus::sessionBus(); QVERIFY(con.isConnected()); QObject obj; con.registerObject("/", &obj); QFETCH(int, nInterfaces); switch (nInterfaces) { case 4: new Interface4(&obj); case 3: new Interface3(&obj); case 2: new Interface2(&obj); case 1: new Interface1(&obj); } QDBusObject dobj = con.findObject(con.baseService(), "/"); QVERIFY(dobj.isValid()); QString xml = dobj.introspect(); QVERIFY(!xml.isEmpty()); QStringList interfaces = dobj.interfaces(); QCOMPARE(interfaces.count(), nInterfaces + 2); switch (nInterfaces) { case 4: { QVERIFY(interfaces.contains("local.Interface4")); QDBusInterface iface(dobj, "local.Interface4"); QCOMPARE(iface.methodData(), Interface4::methodData); QCOMPARE(iface.signalData(), Interface4::signalData); QCOMPARE(iface.propertyData(), Interface4::propertyData); } case 3: { QVERIFY(interfaces.contains("local.Interface3")); QDBusInterface iface(dobj, "local.Interface3"); QCOMPARE(iface.methodData(), Interface3::methodData); QCOMPARE(iface.signalData(), Interface3::signalData); QCOMPARE(iface.propertyData(), Interface3::propertyData); } case 2: { QVERIFY(interfaces.contains("local.Interface2")); QDBusInterface iface(dobj, "local.Interface2"); QCOMPARE(iface.methodData(), Interface2::methodData); QCOMPARE(iface.signalData(), Interface2::signalData); QCOMPARE(iface.propertyData(), Interface2::propertyData); } case 1: { QVERIFY(interfaces.contains("local.Interface1")); QDBusInterface iface(dobj, "local.Interface1"); QCOMPARE(iface.methodData(), Interface1::methodData); QCOMPARE(iface.signalData(), Interface1::signalData); QCOMPARE(iface.propertyData(), Interface1::propertyData); } } } void tst_QDBusAbstractAdaptor::objectTreeIntrospection() { QDBusConnection con = QDBus::sessionBus(); QVERIFY(con.isConnected()); { QDBusObject dobj = con.findObject(con.baseService(), "/"); QString xml = dobj.introspect(); QDBusIntrospection::Object tree = QDBusIntrospection::parseObject(xml); QVERIFY(tree.childObjects.isEmpty()); } QObject root; con.registerObject("/", &root); { QDBusObject dobj = con.findObject(con.baseService(), "/"); QString xml = dobj.introspect(); QDBusIntrospection::Object tree = QDBusIntrospection::parseObject(xml); QVERIFY(tree.childObjects.isEmpty()); } QObject p1; con.registerObject("/p1", &p1); { QDBusObject dobj = con.findObject(con.baseService(), "/"); QString xml = dobj.introspect(); QDBusIntrospection::Object tree = QDBusIntrospection::parseObject(xml); QVERIFY(tree.childObjects.contains("p1")); } con.unregisterObject("/"); { QDBusObject dobj = con.findObject(con.baseService(), "/"); QString xml = dobj.introspect(); QDBusIntrospection::Object tree = QDBusIntrospection::parseObject(xml); QVERIFY(tree.childObjects.contains("p1")); } con.registerObject("/p1/q/r", &root); { QDBusObject dobj = con.findObject(con.baseService(), "/p1"); QString xml = dobj.introspect(); QDBusIntrospection::Object tree = QDBusIntrospection::parseObject(xml); QVERIFY(tree.childObjects.contains("q")); } { QDBusObject dobj = con.findObject(con.baseService(), "/p1/q"); QString xml = dobj.introspect(); QDBusIntrospection::Object tree = QDBusIntrospection::parseObject(xml); QVERIFY(tree.childObjects.contains("r")); } con.unregisterObject("/p1", QDBusConnection::UnregisterTree); { QDBusObject dobj = con.findObject(con.baseService(), "/"); QString xml = dobj.introspect(); QDBusIntrospection::Object tree = QDBusIntrospection::parseObject(xml); QVERIFY(tree.childObjects.isEmpty()); } QObject p2; con.registerObject("/p2", &p2, QDBusConnection::ExportChildObjects); { QDBusObject dobj = con.findObject(con.baseService(), "/"); QString xml = dobj.introspect(); QDBusIntrospection::Object tree = QDBusIntrospection::parseObject(xml); QVERIFY(!tree.childObjects.contains("p1")); QVERIFY(tree.childObjects.contains("p2")); } QObject q; q.setParent(&p2); { QDBusObject dobj = con.findObject(con.baseService(), "/p2"); QString xml = dobj.introspect(); QDBusIntrospection::Object tree = QDBusIntrospection::parseObject(xml); QVERIFY(!tree.childObjects.contains("q")); } q.setObjectName("q"); { QDBusObject dobj = con.findObject(con.baseService(), "/p2"); QString xml = dobj.introspect(); QDBusIntrospection::Object tree = QDBusIntrospection::parseObject(xml); QVERIFY(tree.childObjects.contains("q")); } q.setParent(0); { QDBusObject dobj = con.findObject(con.baseService(), "/p2"); QString xml = dobj.introspect(); QDBusIntrospection::Object tree = QDBusIntrospection::parseObject(xml); QVERIFY(!tree.childObjects.contains("q")); } } #endif void tst_QDBusAbstractAdaptor::typeMatching_data() { QTest::addColumn("basename"); QTest::addColumn("signature"); QTest::addColumn("value"); QTest::newRow("bool") << "Bool" << "b" << QVariant(true); QTest::newRow("byte") << "UChar" << "y" << qVariantFromValue(uchar(42)); QTest::newRow("short") << "Short" << "n" << qVariantFromValue(short(-43)); QTest::newRow("ushort") << "UShort" << "q" << qVariantFromValue(ushort(44)); QTest::newRow("int") << "Int" << "i" << QVariant(42); QTest::newRow("uint") << "UInt" << "u" << QVariant(42U); QTest::newRow("qlonglong") << "LongLong" << "x" << QVariant(Q_INT64_C(42)); QTest::newRow("qulonglong") << "ULongLong" << "t" << QVariant(Q_UINT64_C(42)); QTest::newRow("double") << "Double" << "d" << QVariant(2.5); QTest::newRow("string") << "String" << "s" << QVariant("Hello, World!"); QTest::newRow("variant") << "Variant" << "v" << qVariantFromValue(QDBusVariant("Hello again!")); QTest::newRow("list") << "List" << "av" << QVariant(QVariantList() << 42 << QString("foo") << QByteArray("bar") << qVariantFromValue(QDBusVariant(QString("baz")))); QTest::newRow("stringlist") << "StringList" << "as" << QVariant(QStringList() << "Hello" << "world"); QTest::newRow("bytearray") << "ByteArray" << "ay" << QVariant(QByteArray("foo")); QVariantMap map; map["one"] = 1; // int map["The answer to life, the Universe and everything"] = 42u; // uint map["In the beginning..."] = QString("There was nothing"); // string map["but Unix came and said"] = QByteArray("\"Hello, World\""); // bytearray map["two"] = qVariantFromValue(short(2)); // short QTest::newRow("map") << "Map" << "a{sv}" << QVariant(map); StringStringMap ssmap; ssmap["a"] = "A"; ssmap["A"] = "a"; QTest::newRow("ssmap") << "SSMap" << "a{ss}" << qVariantFromValue(ssmap); LLDateTimeMap lldtmap; lldtmap[-1] = QDateTime(); QDateTime now = QDateTime::currentDateTime(); lldtmap[now.toTime_t()] = now; // array of struct of int64 and struct of 3 ints and struct of 4 ints and int QTest::newRow("lldtmap") << "LLDateTimeMap" << "a{x((iii)(iiii)i)}" << qVariantFromValue(lldtmap); MyStruct s; s.i = 42; s.s = "A value"; QTest::newRow("struct") << "Struct" << "(is)" << qVariantFromValue(s); } void tst_QDBusAbstractAdaptor::typeMatching() { QObject obj; new TypesInterface(&obj); QDBusConnection con = QDBusConnection::sessionBus(); con.registerObject("/types", &obj); QFETCH(QString, basename); QFETCH(QString, signature); QFETCH(QVariant, value); QDBusMessage reply; QDBusInterface iface(con.baseService(), "/types", "local.TypesInterface", con); reply = iface.callWithArgumentList(QDBus::BlockWithGui, "method" + basename, QVariantList() << value); QCOMPARE(reply.type(), QDBusMessage::ReplyMessage); reply = iface.call(QDBus::BlockWithGui, "retrieve" + basename); QCOMPARE(reply.type(), QDBusMessage::ReplyMessage); QCOMPARE(reply.arguments().count(), 1); const QVariant &retval = reply.arguments().at(0); QVERIFY(compare(retval, value)); } void tst_QDBusAbstractAdaptor::methodWithMoreThanOneReturnValue() { QDBusConnection con = QDBusConnection::sessionBus(); QVERIFY(con.isConnected()); MyObject obj; con.registerObject("/", &obj); QString testString = "This is a test string."; QDBusInterface remote(con.baseService(), "/", "local.Interface3", con); QDBusMessage reply = remote.call(QDBus::BlockWithGui, "methodStringString", testString); QVERIFY(reply.arguments().count() == 2); QDBusReply intreply = reply; QVERIFY(intreply.isValid()); QCOMPARE(intreply.value(), 42); QCOMPARE(reply.arguments().at(1).userType(), int(QVariant::String)); QCOMPARE(qdbus_cast(reply.arguments().at(1)), testString); } QTEST_MAIN(tst_QDBusAbstractAdaptor) #include "tst_qdbusabstractadaptor.moc"