From 4c8c5ef3866723124fe8cf2c8bdd3b846549b129 Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:18 -0500 Subject: QtDBus: Add unit tests for QDBusAbstractAdaptor Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- tests/auto/qdbusabstractadaptor/myobject.h | 286 +++++ .../qdbusabstractadaptor/qdbusabstractadaptor.pro | 9 +- .../qdbusabstractadaptor/qmyserver/qmyserver.cpp | 167 +++ .../qdbusabstractadaptor/qmyserver/qmyserver.pro | 5 + tests/auto/qdbusabstractadaptor/test/test.pro | 7 + .../tst_qdbusabstractadaptor.cpp | 1091 ++++++++++++++------ 6 files changed, 1240 insertions(+), 325 deletions(-) create mode 100644 tests/auto/qdbusabstractadaptor/myobject.h create mode 100644 tests/auto/qdbusabstractadaptor/qmyserver/qmyserver.cpp create mode 100644 tests/auto/qdbusabstractadaptor/qmyserver/qmyserver.pro create mode 100644 tests/auto/qdbusabstractadaptor/test/test.pro diff --git a/tests/auto/qdbusabstractadaptor/myobject.h b/tests/auto/qdbusabstractadaptor/myobject.h new file mode 100644 index 0000000..7353fa6 --- /dev/null +++ b/tests/auto/qdbusabstractadaptor/myobject.h @@ -0,0 +1,286 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** +****************************************************************************/ + +#ifndef MYOBJECT_H +#define MYOBJECT_H + +#include +#include + +extern const char *slotSpy; +extern QString valueSpy; + +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(); +}; + +#endif // MYOBJECT_H \ No newline at end of file diff --git a/tests/auto/qdbusabstractadaptor/qdbusabstractadaptor.pro b/tests/auto/qdbusabstractadaptor/qdbusabstractadaptor.pro index 16358c5..c3e3f7f 100644 --- a/tests/auto/qdbusabstractadaptor/qdbusabstractadaptor.pro +++ b/tests/auto/qdbusabstractadaptor/qdbusabstractadaptor.pro @@ -1,10 +1,9 @@ load(qttest_p4) QT = core contains(QT_CONFIG,dbus): { - SOURCES += tst_qdbusabstractadaptor.cpp - QT += dbus + TEMPLATE = subdirs + CONFIG += ordered + SUBDIRS = qmyserver test } else { - SOURCES += ../qdbusmarshall/dummy.cpp + SOURCES += ../qdbusmarshall/dummy.cpp } - - diff --git a/tests/auto/qdbusabstractadaptor/qmyserver/qmyserver.cpp b/tests/auto/qdbusabstractadaptor/qmyserver/qmyserver.cpp new file mode 100644 index 0000000..238bc38 --- /dev/null +++ b/tests/auto/qdbusabstractadaptor/qmyserver/qmyserver.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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 "../myobject.h" + +static const char serviceName[] = "com.trolltech.autotests.qmyserver"; +static const char objectPath[] = "/com/trolltech/qmyserver"; +//static const char *interfaceName = serviceName; + +const char *slotSpy; +QString valueSpy; + +Q_DECLARE_METATYPE(QDBusConnection::RegisterOptions) + +class MyServer : public QDBusServer +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "com.trolltech.autotests.qmyserver") + +public: + MyServer(QString addr = "unix:tmpdir=/tmp", QObject* parent = 0) + : QDBusServer(addr, parent), + m_conn("none"), + obj(NULL) + { + connect(this, SIGNAL(newConnection(const QDBusConnection&)), SLOT(handleConnection(const QDBusConnection&))); + } + + ~MyServer() + { + if (obj) + obj->deleteLater(); + } + +public slots: + QString address() const + { + return QDBusServer::address(); + } + + bool isConnected() const + { + return m_conn.isConnected(); + } + + void emitSignal(const QString& interface, const QString& name, const QDBusVariant& parameter) + { + if (interface.endsWith('2')) + obj->if2->emitSignal(name, parameter.variant()); + else if (interface.endsWith('3')) + obj->if3->emitSignal(name, parameter.variant()); + else if (interface.endsWith('4')) + obj->if4->emitSignal(name, parameter.variant()); + else + obj->emitSignal(name, parameter.variant()); + } + + void emitSignal2(const QString& interface, const QString& name) + { + if (interface.endsWith('2')) + obj->if2->emitSignal(name, QVariant()); + else if (interface.endsWith('3')) + obj->if3->emitSignal(name, QVariant()); + else if (interface.endsWith('4')) + obj->if4->emitSignal(name, QVariant()); + else + obj->emitSignal(name, QVariant()); + } + + void newMyObject(int nInterfaces = 4) + { + if (obj) + obj->deleteLater(); + obj = new MyObject(nInterfaces); + } + + void registerMyObject(const QString & path, int options) + { + m_conn.registerObject(path, obj, (QDBusConnection::RegisterOptions)options); + } + + QString slotSpyServer() + { + return QLatin1String(slotSpy); + } + + QString valueSpyServer() + { + return valueSpy; + } + + void clearValueSpy() + { + valueSpy.clear(); + } + +private slots: + void handleConnection(const QDBusConnection& con) + { + m_conn = con; + } + +private: + QDBusConnection m_conn; + MyObject* obj; +}; + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + QDBusConnection con = QDBusConnection::sessionBus(); + if (!con.isConnected()) + exit(1); + + if (!con.registerService(serviceName)) + exit(2); + + MyServer server; + con.registerObject(objectPath, &server, QDBusConnection::ExportAllSlots); + + printf("ready.\n"); + + return app.exec(); +} + +#include "qmyserver.moc" \ No newline at end of file diff --git a/tests/auto/qdbusabstractadaptor/qmyserver/qmyserver.pro b/tests/auto/qdbusabstractadaptor/qmyserver/qmyserver.pro new file mode 100644 index 0000000..f4fe02c --- /dev/null +++ b/tests/auto/qdbusabstractadaptor/qmyserver/qmyserver.pro @@ -0,0 +1,5 @@ +SOURCES = qmyserver.cpp +HEADERS = ../myobject.h +TARGET = qmyserver +QT += dbus +QT -= gui diff --git a/tests/auto/qdbusabstractadaptor/test/test.pro b/tests/auto/qdbusabstractadaptor/test/test.pro new file mode 100644 index 0000000..014a9e8 --- /dev/null +++ b/tests/auto/qdbusabstractadaptor/test/test.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +SOURCES += ../tst_qdbusabstractadaptor.cpp +HEADERS += ../myobject.h +TARGET = ../tst_qdbusabstractadaptor + +QT = core +QT += dbus diff --git a/tests/auto/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp b/tests/auto/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp index a64b3d2..9250350 100644 --- a/tests/auto/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp +++ b/tests/auto/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp @@ -46,6 +46,11 @@ #include #include "../qdbusmarshall/common.h" +#include "myobject.h" + +static const char serviceName[] = "com.trolltech.autotests.qmyserver"; +static const char objectPath[] = "/com/trolltech/qmyserver"; +static const char *interfaceName = serviceName; const char *slotSpy; QString valueSpy; @@ -73,273 +78,6 @@ namespace QTest { } 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 @@ -593,6 +331,191 @@ public slots: } }; +void newMyObjectPeer(int nInterfaces = 4) +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "newMyObject"); + req << nInterfaces; + QDBusMessage reply = QDBusConnection::sessionBus().call(req); +} + +void registerMyObjectPeer(const QString & path, QDBusConnection::RegisterOptions options = QDBusConnection::ExportAdaptors) +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "registerMyObject"); + req << path; + req << (int)options; + QDBusMessage reply = QDBusConnection::sessionBus().call(req); +} + +void emitSignalPeer(const QString &interface, const QString &name, const QVariant ¶meter) +{ + if (parameter.isValid()) + { + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "emitSignal"); + req << interface; + req << name; + req << QVariant::fromValue(QDBusVariant(parameter)); + QDBusConnection::sessionBus().send(req); + } + else + { + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "emitSignal2"); + req << interface; + req << name; + QDBusConnection::sessionBus().send(req); + } + + QTest::qWait(1000); +} + +const char* slotSpyPeer() +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "slotSpyServer"); + QDBusMessage reply = QDBusConnection::sessionBus().call(req); + return reply.arguments().at(0).toString().toLatin1().data(); +} + +QString valueSpyPeer() +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "valueSpyServer"); + QDBusMessage reply = QDBusConnection::sessionBus().call(req); + return reply.arguments().at(0).toString(); +} + +void clearValueSpyPeer() +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "clearValueSpy"); + QDBusMessage reply = QDBusConnection::sessionBus().call(req); +} + +class tst_QDBusAbstractAdaptor: public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + + 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 methodCallsPeer_data(); + void methodCallsPeer(); + void methodCallScriptablePeer(); + void signalEmissionsPeer_data(); + void signalEmissionsPeer(); + void sameSignalDifferentPathsPeer(); + void sameObjectDifferentPathsPeer(); + void scriptableSignalOrNotPeer(); + void overloadedSignalEmissionPeer_data(); + void overloadedSignalEmissionPeer(); + void readPropertiesPeer(); + void readPropertiesInvalidInterfacePeer(); + void readPropertiesEmptyInterfacePeer_data(); + void readPropertiesEmptyInterfacePeer(); + void readAllPropertiesPeer(); + void readAllPropertiesInvalidInterfacePeer(); + void readAllPropertiesEmptyInterfacePeer_data(); + void readAllPropertiesEmptyInterfacePeer(); + void writePropertiesPeer(); + + void typeMatching_data(); + void typeMatching(); + + void methodWithMoreThanOneReturnValue(); + void methodWithMoreThanOneReturnValuePeer(); +private: + QProcess proc; +}; + +class WaitForQMyServer: public QObject +{ + Q_OBJECT +public: + WaitForQMyServer(); + bool ok(); +public Q_SLOTS: + void ownerChange(const QString &name) + { + if (name == serviceName) + loop.quit(); + } + +private: + QEventLoop loop; +}; + +WaitForQMyServer::WaitForQMyServer() +{ + QDBusConnection con = QDBusConnection::sessionBus(); + if (!ok()) { + connect(con.interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)), + SLOT(ownerChange(QString))); + QTimer::singleShot(2000, &loop, SLOT(quit())); + loop.exec(); + } +} + +bool WaitForQMyServer::ok() +{ + return QDBusConnection::sessionBus().isConnected() && + QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName); +} + +void tst_QDBusAbstractAdaptor::initTestCase() +{ + commonInit(); + + // start peer server + #ifdef Q_OS_WIN + proc.start("qmyserver"); + #else + proc.start("./qmyserver/qmyserver"); + #endif + QVERIFY(proc.waitForStarted()); + + WaitForQMyServer w; + QVERIFY(w.ok()); + //QTest::qWait(2000); + + // get peer server address + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "address"); + QDBusMessage rpl = QDBusConnection::sessionBus().call(req); + QVERIFY(rpl.type() == QDBusMessage::ReplyMessage); + QString address = rpl.arguments().at(0).toString(); + + // connect to peer server + QDBusConnection peercon = QDBusConnection::connectToPeer(address, "peer"); + QVERIFY(peercon.isConnected()); + + QDBusMessage req2 = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "isConnected"); + QDBusMessage rpl2 = QDBusConnection::sessionBus().call(req2); + QVERIFY(rpl2.type() == QDBusMessage::ReplyMessage); + QVERIFY(rpl2.arguments().at(0).toBool()); +} + +void tst_QDBusAbstractAdaptor::cleanupTestCase() +{ + proc.close(); + proc.kill(); +} + void tst_QDBusAbstractAdaptor::methodCalls_data() { QTest::addColumn("nInterfaces"); @@ -1151,71 +1074,577 @@ void tst_QDBusAbstractAdaptor::writeProperties() } } -#if 0 -void tst_QDBusAbstractAdaptor::adaptorIntrospection_data() +void tst_QDBusAbstractAdaptor::methodCallsPeer_data() { methodCalls_data(); } -void tst_QDBusAbstractAdaptor::adaptorIntrospection() +void tst_QDBusAbstractAdaptor::methodCallsPeer() { - QDBusConnection con = QDBus::sessionBus(); + QDBusConnection con("peer"); 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); + // must fail: no object + QDBusInterface if1(QString(), "/", "local.Interface1", con); + QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage); } - QDBusObject dobj = con.findObject(con.baseService(), "/"); - QVERIFY(dobj.isValid()); + QFETCH(int, nInterfaces); + newMyObjectPeer(nInterfaces); + registerMyObjectPeer("/"); - QString xml = dobj.introspect(); - QVERIFY(!xml.isEmpty()); + QDBusInterface if1(QString(), "/", "local.Interface1", con); + QDBusInterface if2(QString(), "/", "local.Interface2", con); + QDBusInterface if3(QString(), "/", "local.Interface3", con); + QDBusInterface if4(QString(), "/", "local.Interface4", con); - 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); - } + // 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(slotSpyPeer(), "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(slotSpyPeer(), "void Interface3::methodVoid()"); + QCOMPARE(if3.call(QDBus::BlockWithGui, "methodInt", 42).type(), QDBusMessage::ReplyMessage); + QCOMPARE(slotSpyPeer(), "void Interface3::methodInt(int)"); + QCOMPARE(if3.call(QDBus::BlockWithGui, "methodString", QString("")).type(), QDBusMessage::ReplyMessage); + QCOMPARE(slotSpyPeer(), "void Interface3::methodString(QString)"); + + if (!nInterfaces--) + return; + + // method overloading: different interfaces + QCOMPARE(if4.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ReplyMessage); + QCOMPARE(slotSpyPeer(), "void Interface4::method()"); + + // method overloading: different parameters + QCOMPARE(if4.call(QDBus::BlockWithGui, "method.i", 42).type(), QDBusMessage::ReplyMessage); + QCOMPARE(slotSpyPeer(), "void Interface4::method(int)"); + QCOMPARE(if4.call(QDBus::BlockWithGui, "method.s", QString()).type(), QDBusMessage::ReplyMessage); + QCOMPARE(slotSpyPeer(), "void Interface4::method(QString)"); +} + +void tst_QDBusAbstractAdaptor::methodCallScriptablePeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(2); + registerMyObjectPeer("/"); + + QDBusInterface if2(QString(), "/", "local.Interface2", con); + + QCOMPARE(if2.call(QDBus::BlockWithGui,"scriptableMethod").type(), QDBusMessage::ReplyMessage); + QCOMPARE(slotSpyPeer(), "void Interface2::scriptableMethod()"); +} + +void tst_QDBusAbstractAdaptor::signalEmissionsPeer_data() +{ + signalEmissions_data(); +} + +void tst_QDBusAbstractAdaptor::signalEmissionsPeer() +{ + QFETCH(QString, interface); + QFETCH(QString, name); + QFETCH(QVariant, parameter); + + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(3); + registerMyObjectPeer("/", QDBusConnection::ExportAdaptors + | QDBusConnection::ExportScriptableSignals); + + // connect all signals and emit only one + { + QDBusSignalSpy spy; + con.connect(QString(), "/", "local.Interface2", "signal", + &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/", "local.Interface3", "signalVoid", + &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/", "local.Interface3", "signalInt", + &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/", "local.Interface3", "signalString", + &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/", "local.MyObject", "scriptableSignalVoid", + &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/", "local.MyObject", "scriptableSignalInt", + &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/", "local.MyObject", "scriptableSignalString", + &spy, SLOT(slot(QDBusMessage))); + + emitSignalPeer(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(QString(), "/", interface, name, &spy, SLOT(slot(QDBusMessage))); + emitSignalPeer("local.Interface2", "signal", QVariant()); + emitSignalPeer("local.Interface3", "signalVoid", QVariant()); + emitSignalPeer("local.Interface3", "signalInt", QVariant(1)); + emitSignalPeer("local.Interface3", "signalString", QVariant("foo")); + emitSignalPeer("local.MyObject", "scriptableSignalVoid", QVariant()); + emitSignalPeer("local.MyObject", "scriptableSignalInt", QVariant(1)); + emitSignalPeer("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::sameSignalDifferentPathsPeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(2); + + registerMyObjectPeer("/p1"); + registerMyObjectPeer("/p2"); + + QDBusSignalSpy spy; + con.connect(QString(), "/p1", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); + emitSignalPeer("local.Interface2", 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(QString(), "/p2", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); + emitSignalPeer("local.Interface2", QString(), QVariant()); + QTest::qWait(200); + + QCOMPARE(spy.count, 2); +} + +void tst_QDBusAbstractAdaptor::sameObjectDifferentPathsPeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(2); + + registerMyObjectPeer("/p1"); + registerMyObjectPeer("/p2", 0); // don't export anything + + QDBusSignalSpy spy; + con.connect(QString(), "/p1", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/p2", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); + emitSignalPeer("local.Interface2", 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::scriptableSignalOrNotPeer() +{ + QDBusConnection con("peer");; + QVERIFY(con.isConnected()); + + { + newMyObjectPeer(0); + + registerMyObjectPeer("/p1", QDBusConnection::ExportScriptableSignals); + registerMyObjectPeer("/p2", 0); // don't export anything + + QDBusSignalSpy spy; + con.connect(QString(), "/p1", "local.MyObject", "scriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/p2", "local.MyObject", "scriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/p1", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/p2", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); + emitSignalPeer("local.MyObject", "scriptableSignalVoid", QVariant()); + emitSignalPeer("local.MyObject", "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()); + } + + { + newMyObjectPeer(0); + + registerMyObjectPeer("/p1", QDBusConnection::ExportScriptableSignals); + registerMyObjectPeer("/p2", QDBusConnection::ExportScriptableSignals + | QDBusConnection::ExportNonScriptableSignals); + + QDBusSignalSpy spy; + con.connect(QString(), "/p1", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/p2", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); + emitSignalPeer("local.MyObject", "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(QString(), "/p1", "local.MyObject", "destroyed", &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/p2", "local.MyObject", "destroyed", &spy, SLOT(slot(QDBusMessage))); + + { + newMyObjectPeer(0); + + registerMyObjectPeer("/p1", QDBusConnection::ExportScriptableSignals); + registerMyObjectPeer("/p2", QDBusConnection::ExportScriptableSignals + | QDBusConnection::ExportNonScriptableSignals); + } // <--- QObject emits the destroyed(QObject*) signal at this point + + QTest::qWait(200); + + QCOMPARE(spy.count, 0); + } +} + +void tst_QDBusAbstractAdaptor::overloadedSignalEmissionPeer_data() +{ + overloadedSignalEmission_data(); +} + +void tst_QDBusAbstractAdaptor::overloadedSignalEmissionPeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QString interface = "local.Interface4"; + QString name = "signal"; + QFETCH(QVariant, parameter); + //QDBusInterface *if4 = new QDBusInterface(QString(), "/", interface, con); + + // connect all signals and emit only one + { + QDBusSignalSpy spy; + con.connect(QString(), "/", "local.Interface4", "signal", "", + &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/", "local.Interface4", "signal", "i", + &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/", "local.Interface4", "signal", "s", + &spy, SLOT(slot(QDBusMessage))); + + emitSignalPeer(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(QString(), "/", interface, name, signature, &spy, SLOT(slot(QDBusMessage))); + emitSignalPeer("local.Interface4", "signal", QVariant()); + emitSignalPeer("local.Interface4", "signal", QVariant(1)); + emitSignalPeer("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::readPropertiesPeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QDBusInterface properties(QString(), "/", "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::readPropertiesInvalidInterfacePeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QDBusInterface properties(QString(), "/", "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::readPropertiesEmptyInterfacePeer_data() +{ + readPropertiesEmptyInterface_data(); +} + +void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterfacePeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QDBusInterface properties(QString(), "/", "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::readAllPropertiesPeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QDBusInterface properties(QString(), "/", "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::readAllPropertiesInvalidInterfacePeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con); + + // test an invalid interface: + QDBusReply reply = properties.call(QDBus::BlockWithGui, "GetAll", "local.DoesntExist"); + QVERIFY(!reply.isValid()); +} + +void tst_QDBusAbstractAdaptor::readAllPropertiesEmptyInterfacePeer_data() +{ + readAllPropertiesEmptyInterface_data(); +} + +void tst_QDBusAbstractAdaptor::readAllPropertiesEmptyInterfacePeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QDBusInterface properties(QString(), "/", "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::writePropertiesPeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con); + for (int i = 2; i <= 4; ++i) { + QString name = QString("Interface%1").arg(i); + + clearValueSpyPeer(); + properties.call(QDBus::BlockWithGui, "Set", "local." + name, QString("prop1"), + qVariantFromValue(QDBusVariant(name))); + QVERIFY(valueSpyPeer().isEmpty()); // call mustn't have succeeded + + properties.call(QDBus::BlockWithGui, "Set", "local." + name, QString("prop2"), + qVariantFromValue(QDBusVariant(name))); + QCOMPARE(valueSpyPeer(), name); + QCOMPARE(QString(slotSpyPeer()), 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); + } } } @@ -1438,6 +1867,28 @@ void tst_QDBusAbstractAdaptor::methodWithMoreThanOneReturnValue() QCOMPARE(qdbus_cast(reply.arguments().at(1)), testString); } +void tst_QDBusAbstractAdaptor::methodWithMoreThanOneReturnValuePeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QString testString = "This is a test string."; + + QDBusInterface remote(QString(), "/", "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" -- cgit v0.12