summaryrefslogtreecommitdiffstats
path: root/tests/auto/dbus
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/dbus')
-rw-r--r--tests/auto/dbus/dbus.pro20
-rw-r--r--tests/auto/dbus/qdbusabstractadaptor/.gitignore1
-rw-r--r--tests/auto/dbus/qdbusabstractadaptor/myobject.h286
-rw-r--r--tests/auto/dbus/qdbusabstractadaptor/qdbusabstractadaptor.pro9
-rw-r--r--tests/auto/dbus/qdbusabstractadaptor/qmyserver/qmyserver.cpp167
-rw-r--r--tests/auto/dbus/qdbusabstractadaptor/qmyserver/qmyserver.pro5
-rw-r--r--tests/auto/dbus/qdbusabstractadaptor/test/test.pro6
-rw-r--r--tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp1894
-rw-r--r--tests/auto/dbus/qdbusabstractinterface/com.trolltech.QtDBus.Pinger.xml34
-rw-r--r--tests/auto/dbus/qdbusabstractinterface/interface.cpp62
-rw-r--r--tests/auto/dbus/qdbusabstractinterface/interface.h115
-rw-r--r--tests/auto/dbus/qdbusabstractinterface/pinger.cpp67
-rw-r--r--tests/auto/dbus/qdbusabstractinterface/pinger.h152
-rw-r--r--tests/auto/dbus/qdbusabstractinterface/qdbusabstractinterface.pro10
-rw-r--r--tests/auto/dbus/qdbusabstractinterface/qpinger/qpinger.cpp131
-rw-r--r--tests/auto/dbus/qdbusabstractinterface/qpinger/qpinger.pro5
-rw-r--r--tests/auto/dbus/qdbusabstractinterface/test/test.pro13
-rw-r--r--tests/auto/dbus/qdbusabstractinterface/tst_qdbusabstractinterface.cpp1301
-rw-r--r--tests/auto/dbus/qdbusconnection/.gitignore1
-rw-r--r--tests/auto/dbus/qdbusconnection/qdbusconnection.pro11
-rw-r--r--tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp1305
-rw-r--r--tests/auto/dbus/qdbusconnection_no_bus/qdbusconnection_no_bus.pro9
-rw-r--r--tests/auto/dbus/qdbusconnection_no_bus/tst_qdbusconnection_no_bus.cpp84
-rw-r--r--tests/auto/dbus/qdbuscontext/.gitignore1
-rw-r--r--tests/auto/dbus/qdbuscontext/qdbuscontext.pro11
-rw-r--r--tests/auto/dbus/qdbuscontext/tst_qdbuscontext.cpp93
-rw-r--r--tests/auto/dbus/qdbusinterface/.gitignore1
-rw-r--r--tests/auto/dbus/qdbusinterface/myobject.h164
-rw-r--r--tests/auto/dbus/qdbusinterface/qdbusinterface.pro11
-rw-r--r--tests/auto/dbus/qdbusinterface/qmyserver/qmyserver.cpp155
-rw-r--r--tests/auto/dbus/qdbusinterface/qmyserver/qmyserver.pro5
-rw-r--r--tests/auto/dbus/qdbusinterface/test/test.pro6
-rw-r--r--tests/auto/dbus/qdbusinterface/tst_qdbusinterface.cpp1139
-rw-r--r--tests/auto/dbus/qdbuslocalcalls/.gitignore1
-rw-r--r--tests/auto/dbus/qdbuslocalcalls/qdbuslocalcalls.pro11
-rw-r--r--tests/auto/dbus/qdbuslocalcalls/tst_qdbuslocalcalls.cpp277
-rw-r--r--tests/auto/dbus/qdbusmarshall/.gitignore2
-rw-r--r--tests/auto/dbus/qdbusmarshall/common.h755
-rw-r--r--tests/auto/dbus/qdbusmarshall/dummy.cpp44
-rw-r--r--tests/auto/dbus/qdbusmarshall/qdbusmarshall.pro14
-rw-r--r--tests/auto/dbus/qdbusmarshall/qpong/qpong.cpp81
-rw-r--r--tests/auto/dbus/qdbusmarshall/qpong/qpong.pro6
-rw-r--r--tests/auto/dbus/qdbusmarshall/test/test.pro9
-rw-r--r--tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp1172
-rw-r--r--tests/auto/dbus/qdbusmetaobject/.gitignore1
-rw-r--r--tests/auto/dbus/qdbusmetaobject/qdbusmetaobject.pro10
-rw-r--r--tests/auto/dbus/qdbusmetaobject/tst_qdbusmetaobject.cpp688
-rw-r--r--tests/auto/dbus/qdbusmetatype/.gitignore1
-rw-r--r--tests/auto/dbus/qdbusmetatype/qdbusmetatype.pro10
-rw-r--r--tests/auto/dbus/qdbusmetatype/tst_qdbusmetatype.cpp383
-rw-r--r--tests/auto/dbus/qdbuspendingcall/.gitignore1
-rw-r--r--tests/auto/dbus/qdbuspendingcall/qdbuspendingcall.pro6
-rw-r--r--tests/auto/dbus/qdbuspendingcall/tst_qdbuspendingcall.cpp556
-rw-r--r--tests/auto/dbus/qdbuspendingreply/.gitignore1
-rw-r--r--tests/auto/dbus/qdbuspendingreply/qdbuspendingreply.pro4
-rw-r--r--tests/auto/dbus/qdbuspendingreply/tst_qdbuspendingreply.cpp597
-rw-r--r--tests/auto/dbus/qdbusreply/.gitignore1
-rw-r--r--tests/auto/dbus/qdbusreply/qdbusreply.pro10
-rw-r--r--tests/auto/dbus/qdbusreply/tst_qdbusreply.cpp377
-rw-r--r--tests/auto/dbus/qdbusservicewatcher/qdbusservicewatcher.pro8
-rw-r--r--tests/auto/dbus/qdbusservicewatcher/tst_qdbusservicewatcher.cpp275
-rw-r--r--tests/auto/dbus/qdbusthreading/.gitignore1
-rw-r--r--tests/auto/dbus/qdbusthreading/qdbusthreading.pro11
-rw-r--r--tests/auto/dbus/qdbusthreading/tst_qdbusthreading.cpp613
-rw-r--r--tests/auto/dbus/qdbustype/qdbustype.pro10
-rw-r--r--tests/auto/dbus/qdbustype/tst_qdbustype.cpp273
-rw-r--r--tests/auto/dbus/qdbusxmlparser/.gitignore1
-rw-r--r--tests/auto/dbus/qdbusxmlparser/qdbusxmlparser.pro10
-rw-r--r--tests/auto/dbus/qdbusxmlparser/tst_qdbusxmlparser.cpp600
69 files changed, 14094 insertions, 0 deletions
diff --git a/tests/auto/dbus/dbus.pro b/tests/auto/dbus/dbus.pro
new file mode 100644
index 0000000000..6dd8ce325c
--- /dev/null
+++ b/tests/auto/dbus/dbus.pro
@@ -0,0 +1,20 @@
+TEMPLATE=subdirs
+SUBDIRS=\
+ qdbusabstractadaptor \
+ qdbusabstractinterface \
+ qdbusconnection \
+ qdbusconnection_no_bus \
+ qdbuscontext \
+ qdbusinterface \
+ qdbuslocalcalls \
+ qdbusmarshall \
+ qdbusmetaobject \
+ qdbusmetatype \
+ qdbuspendingcall \
+ qdbuspendingreply \
+ qdbusreply \
+ qdbusservicewatcher \
+ qdbustype \
+ qdbusthreading \
+ qdbusxmlparser \
+
diff --git a/tests/auto/dbus/qdbusabstractadaptor/.gitignore b/tests/auto/dbus/qdbusabstractadaptor/.gitignore
new file mode 100644
index 0000000000..201dd9cda0
--- /dev/null
+++ b/tests/auto/dbus/qdbusabstractadaptor/.gitignore
@@ -0,0 +1 @@
+tst_qdbusabstractadaptor
diff --git a/tests/auto/dbus/qdbusabstractadaptor/myobject.h b/tests/auto/dbus/qdbusabstractadaptor/myobject.h
new file mode 100644
index 0000000000..2aaaa7ecc5
--- /dev/null
+++ b/tests/auto/dbus/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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MYOBJECT_H
+#define MYOBJECT_H
+
+#include <QtCore/QObject>
+#include <QtDBus/QtDBus>
+
+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/dbus/qdbusabstractadaptor/qdbusabstractadaptor.pro b/tests/auto/dbus/qdbusabstractadaptor/qdbusabstractadaptor.pro
new file mode 100644
index 0000000000..480509853f
--- /dev/null
+++ b/tests/auto/dbus/qdbusabstractadaptor/qdbusabstractadaptor.pro
@@ -0,0 +1,9 @@
+load(qttest_p4)
+QT = core core-private
+contains(QT_CONFIG,dbus): {
+ TEMPLATE = subdirs
+ CONFIG += ordered
+ SUBDIRS = qmyserver test
+} else {
+ SOURCES += ../qdbusmarshall/dummy.cpp
+}
diff --git a/tests/auto/dbus/qdbusabstractadaptor/qmyserver/qmyserver.cpp b/tests/auto/dbus/qdbusabstractadaptor/qmyserver/qmyserver.cpp
new file mode 100644
index 0000000000..a06232c4bd
--- /dev/null
+++ b/tests/auto/dbus/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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/QtCore>
+#include <QtDBus/QtDBus>
+
+#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/dbus/qdbusabstractadaptor/qmyserver/qmyserver.pro b/tests/auto/dbus/qdbusabstractadaptor/qmyserver/qmyserver.pro
new file mode 100644
index 0000000000..f4fe02c4eb
--- /dev/null
+++ b/tests/auto/dbus/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/dbus/qdbusabstractadaptor/test/test.pro b/tests/auto/dbus/qdbusabstractadaptor/test/test.pro
new file mode 100644
index 0000000000..52aa578fd4
--- /dev/null
+++ b/tests/auto/dbus/qdbusabstractadaptor/test/test.pro
@@ -0,0 +1,6 @@
+load(qttest_p4)
+SOURCES += ../tst_qdbusabstractadaptor.cpp
+HEADERS += ../myobject.h
+TARGET = ../tst_qdbusabstractadaptor
+
+QT = core core-private dbus
diff --git a/tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp b/tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp
new file mode 100644
index 0000000000..ff684ff522
--- /dev/null
+++ b/tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp
@@ -0,0 +1,1894 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qcoreapplication.h>
+#include <qdebug.h>
+
+#include <QtTest/QtTest>
+
+#include <QtDBus>
+
+#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;
+
+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 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 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 &parameter)
+{
+ 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<int>("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 &parameter)
+{
+ 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<QString>("interface");
+ QTest::addColumn<QString>("name");
+ QTest::addColumn<QString>("signature");
+ QTest::addColumn<QVariant>("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<QString>("signature");
+ QTest::addColumn<QVariant>("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<QVariant> 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<QVariant> reply = properties.call(QDBus::BlockWithGui, "Get", "local.DoesntExist", "prop1");
+ QVERIFY(!reply.isValid());
+}
+
+void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterface_data()
+{
+ QTest::addColumn<QVariantMap>("expectedProperties");
+ QTest::addColumn<bool>("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<QVariant> 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<QVariantMap> 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<QVariantMap> 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<QVariantMap> 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));
+ }
+}
+
+void tst_QDBusAbstractAdaptor::methodCallsPeer_data()
+{
+ methodCalls_data();
+}
+
+void tst_QDBusAbstractAdaptor::methodCallsPeer()
+{
+ QDBusConnection con("peer");
+ QVERIFY(con.isConnected());
+
+ {
+ // must fail: no object
+ QDBusInterface if1(QString(), "/", "local.Interface1", con);
+ QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage);
+ }
+
+ QFETCH(int, nInterfaces);
+ newMyObjectPeer(nInterfaces);
+ registerMyObjectPeer("/");
+
+ QDBusInterface if1(QString(), "/", "local.Interface1", con);
+ QDBusInterface if2(QString(), "/", "local.Interface2", con);
+ QDBusInterface if3(QString(), "/", "local.Interface3", con);
+ QDBusInterface if4(QString(), "/", "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(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<QVariant> 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<QVariant> 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<QVariant> 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<QVariantMap> 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<QVariantMap> 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<QVariantMap> 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);
+ }
+ }
+}
+
+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<QString>("basename");
+ QTest::addColumn<QString>("signature");
+ QTest::addColumn<QVariant>("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<int> intreply = reply;
+ QVERIFY(intreply.isValid());
+ QCOMPARE(intreply.value(), 42);
+
+ QCOMPARE(reply.arguments().at(1).userType(), int(QVariant::String));
+ QCOMPARE(qdbus_cast<QString>(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<int> intreply = reply;
+ QVERIFY(intreply.isValid());
+ QCOMPARE(intreply.value(), 42);
+
+ QCOMPARE(reply.arguments().at(1).userType(), int(QVariant::String));
+ QCOMPARE(qdbus_cast<QString>(reply.arguments().at(1)), testString);
+}
+
+QTEST_MAIN(tst_QDBusAbstractAdaptor)
+
+#include "tst_qdbusabstractadaptor.moc"
diff --git a/tests/auto/dbus/qdbusabstractinterface/com.trolltech.QtDBus.Pinger.xml b/tests/auto/dbus/qdbusabstractinterface/com.trolltech.QtDBus.Pinger.xml
new file mode 100644
index 0000000000..d945ec9b43
--- /dev/null
+++ b/tests/auto/dbus/qdbusabstractinterface/com.trolltech.QtDBus.Pinger.xml
@@ -0,0 +1,34 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="com.trolltech.QtDBus.Pinger">
+ <property name="stringProp" type="s" access="readwrite"/>
+ <property name="variantProp" type="v" access="readwrite"/>
+ <property name="complexProp" type="(s)" access="readwrite">
+ <annotation name="com.trolltech.QtDBus.QtTypeName" value="RegisteredType"/>
+ </property>
+ <signal name="voidSignal"/>
+ <signal name="stringSignal">
+ <arg type="s"/>
+ </signal>
+ <signal name="complexSignal">
+ <arg name="" type="(s)"/>
+ <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="RegisteredType"/>
+ </signal>
+ <method name="voidMethod" />
+ <method name="sleepMethod">
+ <arg type="i" />
+ <arg type="i" direction="out"/>
+ </method>
+ <method name="stringMethod">
+ <arg type="s" direction="out"/>
+ </method>
+ <method name="complexMethod">
+ <arg type="(s)" direction="out"/>
+ <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="RegisteredType"/>
+ </method>
+ <method name="multiOutMethod">
+ <arg type="s" direction="out"/>
+ <arg type="i" direction="out"/>
+ </method>
+ </interface>
+</node>
diff --git a/tests/auto/dbus/qdbusabstractinterface/interface.cpp b/tests/auto/dbus/qdbusabstractinterface/interface.cpp
new file mode 100644
index 0000000000..849db93084
--- /dev/null
+++ b/tests/auto/dbus/qdbusabstractinterface/interface.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "interface.h"
+#include <QThread>
+
+Interface::Interface()
+{
+}
+
+// Export the sleep function
+// TODO QT5: remove this class, QThread::msleep is now public
+class FriendlySleepyThread : public QThread {
+public:
+ using QThread::msleep;
+};
+
+int Interface::sleepMethod(int msec)
+{
+ FriendlySleepyThread::msleep(msec);
+ return 42;
+}
+
+#include "moc_interface.cpp"
diff --git a/tests/auto/dbus/qdbusabstractinterface/interface.h b/tests/auto/dbus/qdbusabstractinterface/interface.h
new file mode 100644
index 0000000000..0fb15fe6c5
--- /dev/null
+++ b/tests/auto/dbus/qdbusabstractinterface/interface.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INTERFACE_H
+#define INTERFACE_H
+
+#include <QtCore/QObject>
+#include <QtDBus/QDBusArgument>
+
+struct RegisteredType
+{
+ inline RegisteredType(const QString &str = QString()) : s(str) {}
+ inline bool operator==(const RegisteredType &other) const { return s == other.s; }
+ QString s;
+};
+Q_DECLARE_METATYPE(RegisteredType)
+
+inline QDBusArgument &operator<<(QDBusArgument &s, const RegisteredType &data)
+{
+ s.beginStructure();
+ s << data.s;
+ s.endStructure();
+ return s;
+}
+
+inline const QDBusArgument &operator>>(const QDBusArgument &s, RegisteredType &data)
+{
+ s.beginStructure();
+ s >> data.s;
+ s.endStructure();
+ return s;
+}
+
+struct UnregisteredType
+{
+ QString s;
+};
+Q_DECLARE_METATYPE(UnregisteredType)
+
+class Interface: public QObject
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "com.trolltech.QtDBus.Pinger")
+ Q_PROPERTY(QString stringProp READ stringProp WRITE setStringProp SCRIPTABLE true)
+ Q_PROPERTY(QDBusVariant variantProp READ variantProp WRITE setVariantProp SCRIPTABLE true)
+ Q_PROPERTY(RegisteredType complexProp READ complexProp WRITE setComplexProp SCRIPTABLE true)
+
+ friend class tst_QDBusAbstractInterface;
+ friend class PingerServer;
+ QString m_stringProp;
+ QDBusVariant m_variantProp;
+ RegisteredType m_complexProp;
+
+public:
+ Interface();
+
+ QString stringProp() const { return m_stringProp; }
+ void setStringProp(const QString &s) { m_stringProp = s; }
+ QDBusVariant variantProp() const { return m_variantProp; }
+ void setVariantProp(const QDBusVariant &v) { m_variantProp = v; }
+ RegisteredType complexProp() const { return m_complexProp; }
+ void setComplexProp(const RegisteredType &r) { m_complexProp = r; }
+
+public slots:
+ Q_SCRIPTABLE void voidMethod() {}
+ Q_SCRIPTABLE int sleepMethod(int);
+ Q_SCRIPTABLE QString stringMethod() { return "Hello, world"; }
+ Q_SCRIPTABLE RegisteredType complexMethod() { return RegisteredType("Hello, world"); }
+ Q_SCRIPTABLE QString multiOutMethod(int &value) { value = 42; return "Hello, world"; }
+
+signals:
+ Q_SCRIPTABLE void voidSignal();
+ Q_SCRIPTABLE void stringSignal(const QString &);
+ Q_SCRIPTABLE void complexSignal(RegisteredType);
+};
+
+#endif // INTERFACE_H
diff --git a/tests/auto/dbus/qdbusabstractinterface/pinger.cpp b/tests/auto/dbus/qdbusabstractinterface/pinger.cpp
new file mode 100644
index 0000000000..24113fbb1b
--- /dev/null
+++ b/tests/auto/dbus/qdbusabstractinterface/pinger.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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 QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ * This file was generated by qdbusxml2cpp version 0.7
+ * Command line was: qdbusxml2cpp -i interface.h -p pinger com.trolltech.QtDBus.Pinger.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This is an auto-generated file.
+ * This file may have been hand-edited. Look for HAND-EDIT comments
+ * before re-generating it.
+ */
+
+#include "pinger.h"
+
+/*
+ * Implementation of interface class ComTrolltechQtDBusPingerInterface
+ */
+
+ComTrolltechQtDBusPingerInterface::ComTrolltechQtDBusPingerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
+ : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
+{
+}
+
+ComTrolltechQtDBusPingerInterface::~ComTrolltechQtDBusPingerInterface()
+{
+}
+
diff --git a/tests/auto/dbus/qdbusabstractinterface/pinger.h b/tests/auto/dbus/qdbusabstractinterface/pinger.h
new file mode 100644
index 0000000000..739a14229f
--- /dev/null
+++ b/tests/auto/dbus/qdbusabstractinterface/pinger.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** 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 QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ * This file was generated by qdbusxml2cpp version 0.7
+ * Command line was: qdbusxml2cpp -i interface.h -p pinger com.trolltech.QtDBus.Pinger.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This is an auto-generated file.
+ * Do not edit! All changes made to it will be lost.
+ */
+
+#ifndef PINGER_H_1246463415
+#define PINGER_H_1246463415
+
+#include <QtCore/QObject>
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+#include <QtDBus/QtDBus>
+#include "interface.h"
+
+/*
+ * Proxy class for interface com.trolltech.QtDBus.Pinger
+ */
+class ComTrolltechQtDBusPingerInterface: public QDBusAbstractInterface
+{
+ Q_OBJECT
+public:
+ static inline const char *staticInterfaceName()
+ { return "com.trolltech.QtDBus.Pinger"; }
+
+public:
+ ComTrolltechQtDBusPingerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
+
+ ~ComTrolltechQtDBusPingerInterface();
+
+ Q_PROPERTY(RegisteredType complexProp READ complexProp WRITE setComplexProp)
+ inline RegisteredType complexProp() const
+ { return qvariant_cast< RegisteredType >(property("complexProp")); }
+ inline void setComplexProp(RegisteredType value)
+ { setProperty("complexProp", qVariantFromValue(value)); }
+
+ Q_PROPERTY(QString stringProp READ stringProp WRITE setStringProp)
+ inline QString stringProp() const
+ { return qvariant_cast< QString >(property("stringProp")); }
+ inline void setStringProp(const QString &value)
+ { setProperty("stringProp", qVariantFromValue(value)); }
+
+ Q_PROPERTY(QDBusVariant variantProp READ variantProp WRITE setVariantProp)
+ inline QDBusVariant variantProp() const
+ { return qvariant_cast< QDBusVariant >(property("variantProp")); }
+ inline void setVariantProp(const QDBusVariant &value)
+ { setProperty("variantProp", qVariantFromValue(value)); }
+
+public Q_SLOTS: // METHODS
+ inline QDBusPendingReply<RegisteredType> complexMethod()
+ {
+ QList<QVariant> argumentList;
+ return asyncCallWithArgumentList(QLatin1String("complexMethod"), argumentList);
+ }
+
+ inline QDBusPendingReply<QString, int> multiOutMethod()
+ {
+ QList<QVariant> argumentList;
+ return asyncCallWithArgumentList(QLatin1String("multiOutMethod"), argumentList);
+ }
+ inline QDBusReply<QString> multiOutMethod(int &out1)
+ {
+ QList<QVariant> argumentList;
+ QDBusMessage reply = callWithArgumentList(QDBus::Block, QLatin1String("multiOutMethod"), argumentList);
+ if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 2) {
+ out1 = qdbus_cast<int>(reply.arguments().at(1));
+ }
+ return reply;
+ }
+
+ inline QDBusPendingReply<int> sleepMethod(int in0)
+ {
+ QList<QVariant> argumentList;
+ argumentList << qVariantFromValue(in0);
+ return asyncCallWithArgumentList(QLatin1String("sleepMethod"), argumentList);
+ }
+
+ inline QDBusPendingReply<QString> stringMethod()
+ {
+ QList<QVariant> argumentList;
+ return asyncCallWithArgumentList(QLatin1String("stringMethod"), argumentList);
+ }
+
+ inline QDBusPendingReply<> voidMethod()
+ {
+ QList<QVariant> argumentList;
+ return asyncCallWithArgumentList(QLatin1String("voidMethod"), argumentList);
+ }
+
+Q_SIGNALS: // SIGNALS
+ void complexSignal(RegisteredType in0);
+ void stringSignal(const QString &in0);
+ void voidSignal();
+};
+
+namespace com {
+ namespace trolltech {
+ namespace QtDBus {
+ typedef ::ComTrolltechQtDBusPingerInterface Pinger;
+ }
+ }
+}
+#endif
diff --git a/tests/auto/dbus/qdbusabstractinterface/qdbusabstractinterface.pro b/tests/auto/dbus/qdbusabstractinterface/qdbusabstractinterface.pro
new file mode 100644
index 0000000000..f9077b92cf
--- /dev/null
+++ b/tests/auto/dbus/qdbusabstractinterface/qdbusabstractinterface.pro
@@ -0,0 +1,10 @@
+load(qttest_p4)
+contains(QT_CONFIG,dbus): {
+ TEMPLATE = subdirs
+ CONFIG += ordered
+ SUBDIRS = qpinger test
+} else {
+ SOURCES += ../qdbusmarshall/dummy.cpp
+}
+
+OTHER_FILES += com.trolltech.QtDBus.Pinger.xml
diff --git a/tests/auto/dbus/qdbusabstractinterface/qpinger/qpinger.cpp b/tests/auto/dbus/qdbusabstractinterface/qpinger/qpinger.cpp
new file mode 100644
index 0000000000..393d6470c8
--- /dev/null
+++ b/tests/auto/dbus/qdbusabstractinterface/qpinger/qpinger.cpp
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/QtCore>
+#include <QtDBus/QtDBus>
+#include "../interface.h"
+
+static const char serviceName[] = "com.trolltech.autotests.qpinger";
+static const char objectPath[] = "/com/trolltech/qpinger";
+//static const char *interfaceName = serviceName;
+
+class PingerServer : public QDBusServer
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "com.trolltech.autotests.qpinger")
+public:
+ PingerServer(QString addr = "unix:tmpdir=/tmp", QObject* parent = 0)
+ : QDBusServer(addr, parent),
+ m_conn("none")
+ {
+ connect(this, SIGNAL(newConnection(const QDBusConnection&)), SLOT(handleConnection(const QDBusConnection&)));
+ reset();
+ }
+
+public slots:
+ QString address() const
+ {
+ return QDBusServer::address();
+ }
+
+ bool isConnected() const
+ {
+ return m_conn.isConnected();
+ }
+
+ void reset()
+ {
+ targetObj.m_stringProp = "This is a test";
+ targetObj.m_variantProp = QDBusVariant(QVariant(42));
+ targetObj.m_complexProp = RegisteredType("This is a test");
+ }
+
+ void voidSignal()
+ {
+ emit targetObj.voidSignal();
+ }
+
+ void stringSignal(const QString& value)
+ {
+ emit targetObj.stringSignal(value);
+ }
+
+ void complexSignal(const QString& value)
+ {
+ RegisteredType reg(value);
+ emit targetObj.complexSignal(reg);
+ }
+
+private slots:
+ void handleConnection(const QDBusConnection& con)
+ {
+ m_conn = con;
+ m_conn.registerObject("/", &targetObj, QDBusConnection::ExportScriptableContents);
+ }
+
+private:
+ Interface targetObj;
+ QDBusConnection m_conn;
+};
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+
+ // register the meta types
+ qDBusRegisterMetaType<RegisteredType>();
+ qRegisterMetaType<UnregisteredType>();
+
+ QDBusConnection con = QDBusConnection::sessionBus();
+ if (!con.isConnected())
+ exit(1);
+
+ if (!con.registerService(serviceName))
+ exit(2);
+
+ PingerServer server;
+ con.registerObject(objectPath, &server, QDBusConnection::ExportAllSlots);
+
+ printf("ready.\n");
+
+ return app.exec();
+}
+
+#include "qpinger.moc"
diff --git a/tests/auto/dbus/qdbusabstractinterface/qpinger/qpinger.pro b/tests/auto/dbus/qdbusabstractinterface/qpinger/qpinger.pro
new file mode 100644
index 0000000000..27545bbb0f
--- /dev/null
+++ b/tests/auto/dbus/qdbusabstractinterface/qpinger/qpinger.pro
@@ -0,0 +1,5 @@
+SOURCES = qpinger.cpp ../interface.cpp
+HEADERS = ../interface.h
+TARGET = qpinger
+QT += dbus
+QT -= gui
diff --git a/tests/auto/dbus/qdbusabstractinterface/test/test.pro b/tests/auto/dbus/qdbusabstractinterface/test/test.pro
new file mode 100644
index 0000000000..98bcaa70f5
--- /dev/null
+++ b/tests/auto/dbus/qdbusabstractinterface/test/test.pro
@@ -0,0 +1,13 @@
+load(qttest_p4)
+SOURCES += ../tst_qdbusabstractinterface.cpp ../interface.cpp
+HEADERS += ../interface.h
+
+# These are generated sources
+# To regenerate, see the command-line at the top of the files
+SOURCES += ../pinger.cpp
+HEADERS += ../pinger.h
+
+TARGET = ../tst_qdbusabstractinterface
+
+QT = core
+QT += dbus
diff --git a/tests/auto/dbus/qdbusabstractinterface/tst_qdbusabstractinterface.cpp b/tests/auto/dbus/qdbusabstractinterface/tst_qdbusabstractinterface.cpp
new file mode 100644
index 0000000000..994df058fa
--- /dev/null
+++ b/tests/auto/dbus/qdbusabstractinterface/tst_qdbusabstractinterface.cpp
@@ -0,0 +1,1301 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qcoreapplication.h>
+#include <qdebug.h>
+#include <qsharedpointer.h>
+
+#include <QtTest/QtTest>
+
+#include <QtDBus>
+
+#include "interface.h"
+#include "pinger.h"
+
+static const char serviceName[] = "com.trolltech.autotests.qpinger";
+static const char objectPath[] = "/com/trolltech/qpinger";
+static const char *interfaceName = serviceName;
+
+typedef QSharedPointer<com::trolltech::QtDBus::Pinger> Pinger;
+
+class tst_QDBusAbstractInterface: public QObject
+{
+ Q_OBJECT
+ Interface targetObj;
+
+ Pinger getPinger(QString service = "", const QString &path = "/")
+ {
+ QDBusConnection con = QDBusConnection::sessionBus();
+ if (!con.isConnected())
+ return Pinger();
+ if (service.isEmpty() && !service.isNull())
+ service = con.baseService();
+ return Pinger(new com::trolltech::QtDBus::Pinger(service, path, con));
+ }
+
+ Pinger getPingerPeer(const QString &path = "/")
+ {
+ QDBusConnection con = QDBusConnection("peer");
+ if (!con.isConnected())
+ return Pinger();
+ return Pinger(new com::trolltech::QtDBus::Pinger("", path, con));
+ }
+
+ void resetServer()
+ {
+ QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "reset");
+ QDBusConnection::sessionBus().send(req);
+ }
+
+public:
+ tst_QDBusAbstractInterface();
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ void makeVoidCall();
+ void makeStringCall();
+ void makeComplexCall();
+ void makeMultiOutCall();
+
+ void makeVoidCallPeer();
+ void makeStringCallPeer();
+ void makeComplexCallPeer();
+ void makeMultiOutCallPeer();
+
+ void makeAsyncVoidCall();
+ void makeAsyncStringCall();
+ void makeAsyncComplexCall();
+ void makeAsyncMultiOutCall();
+
+ void makeAsyncVoidCallPeer();
+ void makeAsyncStringCallPeer();
+ void makeAsyncComplexCallPeer();
+ void makeAsyncMultiOutCallPeer();
+
+ void callWithTimeout();
+
+ void stringPropRead();
+ void stringPropWrite();
+ void variantPropRead();
+ void variantPropWrite();
+ void complexPropRead();
+ void complexPropWrite();
+
+ void stringPropReadPeer();
+ void stringPropWritePeer();
+ void variantPropReadPeer();
+ void variantPropWritePeer();
+ void complexPropReadPeer();
+ void complexPropWritePeer();
+
+ void stringPropDirectRead();
+ void stringPropDirectWrite();
+ void variantPropDirectRead();
+ void variantPropDirectWrite();
+ void complexPropDirectRead();
+ void complexPropDirectWrite();
+
+ void stringPropDirectReadPeer();
+ void stringPropDirectWritePeer();
+ void variantPropDirectReadPeer();
+ void variantPropDirectWritePeer();
+ void complexPropDirectReadPeer();
+ void complexPropDirectWritePeer();
+
+ void getVoidSignal_data();
+ void getVoidSignal();
+ void getStringSignal_data();
+ void getStringSignal();
+ void getComplexSignal_data();
+ void getComplexSignal();
+
+ void getVoidSignalPeer_data();
+ void getVoidSignalPeer();
+ void getStringSignalPeer_data();
+ void getStringSignalPeer();
+ void getComplexSignalPeer_data();
+ void getComplexSignalPeer();
+
+ void followSignal();
+
+ void createErrors_data();
+ void createErrors();
+
+ void createErrorsPeer_data();
+ void createErrorsPeer();
+
+ void callErrors_data();
+ void callErrors();
+ void asyncCallErrors_data();
+ void asyncCallErrors();
+
+ void callErrorsPeer_data();
+ void callErrorsPeer();
+ void asyncCallErrorsPeer_data();
+ void asyncCallErrorsPeer();
+
+ void propertyReadErrors_data();
+ void propertyReadErrors();
+ void propertyWriteErrors_data();
+ void propertyWriteErrors();
+ void directPropertyReadErrors_data();
+ void directPropertyReadErrors();
+ void directPropertyWriteErrors_data();
+ void directPropertyWriteErrors();
+
+ void propertyReadErrorsPeer_data();
+ void propertyReadErrorsPeer();
+ void propertyWriteErrorsPeer_data();
+ void propertyWriteErrorsPeer();
+ void directPropertyReadErrorsPeer_data();
+ void directPropertyReadErrorsPeer();
+ void directPropertyWriteErrorsPeer_data();
+ void directPropertyWriteErrorsPeer();
+private:
+ QProcess proc;
+};
+
+class WaitForQPinger: public QObject
+{
+ Q_OBJECT
+public:
+ WaitForQPinger();
+ bool ok();
+public Q_SLOTS:
+ void ownerChange(const QString &name)
+ {
+ if (name == serviceName)
+ loop.quit();
+ }
+
+private:
+ QEventLoop loop;
+};
+
+WaitForQPinger::WaitForQPinger()
+{
+ 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 WaitForQPinger::ok()
+{
+ return QDBusConnection::sessionBus().isConnected() &&
+ QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName);
+}
+
+tst_QDBusAbstractInterface::tst_QDBusAbstractInterface()
+{
+ // register the meta types
+ qDBusRegisterMetaType<RegisteredType>();
+ qRegisterMetaType<UnregisteredType>();
+}
+
+void tst_QDBusAbstractInterface::initTestCase()
+{
+ // enable debugging temporarily:
+ //putenv("QDBUS_DEBUG=1");
+
+ // register the object
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+ con.registerObject("/", &targetObj, QDBusConnection::ExportScriptableContents);
+
+ // start peer server
+ #ifdef Q_OS_WIN
+ proc.start("qpinger");
+ #else
+ proc.start("./qpinger/qpinger");
+ #endif
+ QVERIFY(proc.waitForStarted());
+
+ WaitForQPinger w;
+ QVERIFY(w.ok());
+ //QTest::qWait(2000);
+
+ // get peer server address
+ QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "address");
+ QDBusMessage rpl = con.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 = con.call(req2);
+ QVERIFY(rpl2.type() == QDBusMessage::ReplyMessage);
+ QVERIFY(rpl2.arguments().at(0).toBool());
+}
+
+void tst_QDBusAbstractInterface::cleanupTestCase()
+{
+ proc.close();
+ proc.kill();
+}
+
+void tst_QDBusAbstractInterface::makeVoidCall()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusReply<void> r = p->voidMethod();
+ QVERIFY(r.isValid());
+}
+
+void tst_QDBusAbstractInterface::makeStringCall()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusReply<QString> r = p->stringMethod();
+ QVERIFY(r.isValid());
+ QCOMPARE(r.value(), targetObj.stringMethod());
+}
+
+void tst_QDBusAbstractInterface::makeComplexCall()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusReply<RegisteredType> r = p->complexMethod();
+ QVERIFY(r.isValid());
+ QCOMPARE(r.value(), targetObj.complexMethod());
+}
+
+void tst_QDBusAbstractInterface::makeMultiOutCall()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ int value;
+ QDBusReply<QString> r = p->multiOutMethod(value);
+ QVERIFY(r.isValid());
+
+ int expectedValue;
+ QCOMPARE(r.value(), targetObj.multiOutMethod(expectedValue));
+ QCOMPARE(value, expectedValue);
+}
+
+void tst_QDBusAbstractInterface::makeVoidCallPeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusReply<void> r = p->voidMethod();
+ QVERIFY(r.isValid());
+}
+
+void tst_QDBusAbstractInterface::makeStringCallPeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusReply<QString> r = p->stringMethod();
+ QVERIFY(r.isValid());
+ QCOMPARE(r.value(), targetObj.stringMethod());
+}
+
+void tst_QDBusAbstractInterface::makeComplexCallPeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusReply<RegisteredType> r = p->complexMethod();
+ QVERIFY(r.isValid());
+ QCOMPARE(r.value(), targetObj.complexMethod());
+}
+
+void tst_QDBusAbstractInterface::makeMultiOutCallPeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ int value;
+ QDBusReply<QString> r = p->multiOutMethod(value);
+ QVERIFY(r.isValid());
+
+ int expectedValue;
+ QCOMPARE(r.value(), targetObj.multiOutMethod(expectedValue));
+ QCOMPARE(value, expectedValue);
+}
+
+void tst_QDBusAbstractInterface::makeAsyncVoidCall()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusPendingReply<void> r = p->voidMethod();
+ r.waitForFinished();
+ QVERIFY(r.isValid());
+}
+
+void tst_QDBusAbstractInterface::makeAsyncStringCall()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusPendingReply<QString> r = p->stringMethod();
+ r.waitForFinished();
+ QVERIFY(r.isValid());
+ QCOMPARE(r.value(), targetObj.stringMethod());
+}
+
+void tst_QDBusAbstractInterface::makeAsyncComplexCall()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusPendingReply<RegisteredType> r = p->complexMethod();
+ r.waitForFinished();
+ QVERIFY(r.isValid());
+ QCOMPARE(r.value(), targetObj.complexMethod());
+}
+
+void tst_QDBusAbstractInterface::makeAsyncMultiOutCall()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusPendingReply<QString, int> r = p->multiOutMethod();
+ r.waitForFinished();
+ QVERIFY(r.isValid());
+
+ int expectedValue;
+ QCOMPARE(r.value(), targetObj.multiOutMethod(expectedValue));
+ QCOMPARE(r.argumentAt<1>(), expectedValue);
+}
+
+void tst_QDBusAbstractInterface::makeAsyncVoidCallPeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusPendingReply<void> r = p->voidMethod();
+ r.waitForFinished();
+ QVERIFY(r.isValid());
+}
+void tst_QDBusAbstractInterface::makeAsyncStringCallPeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusMessage reply = p->call(QDBus::BlockWithGui, QLatin1String("voidMethod"));
+ QVERIFY(reply.type() == QDBusMessage::ReplyMessage);
+
+ QDBusPendingReply<QString> r = p->stringMethod();
+ r.waitForFinished();
+ QVERIFY(r.isValid());
+ QCOMPARE(r.value(), targetObj.stringMethod());
+}
+
+void tst_QDBusAbstractInterface::makeAsyncComplexCallPeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusPendingReply<RegisteredType> r = p->complexMethod();
+ r.waitForFinished();
+ QVERIFY(r.isValid());
+ QCOMPARE(r.value(), targetObj.complexMethod());
+}
+
+void tst_QDBusAbstractInterface::makeAsyncMultiOutCallPeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusPendingReply<QString, int> r = p->multiOutMethod();
+ r.waitForFinished();
+ QVERIFY(r.isValid());
+
+ int expectedValue;
+ QCOMPARE(r.value(), targetObj.multiOutMethod(expectedValue));
+ QCOMPARE(r.argumentAt<1>(), expectedValue);
+ QCoreApplication::instance()->processEvents();
+}
+
+static const char server_serviceName[] = "com.trolltech.autotests.dbusserver";
+static const char server_objectPath[] = "/com/trolltech/server";
+static const char server_interfaceName[] = "com.trolltech.QtDBus.Pinger";
+
+class DBusServerThread : public QThread
+{
+public:
+ DBusServerThread() {
+ start();
+ m_ready.acquire();
+ }
+ ~DBusServerThread() {
+ quit();
+ wait();
+ }
+
+ void run()
+ {
+ QDBusConnection con = QDBusConnection::connectToBus(QDBusConnection::SessionBus, "ThreadConnection");
+ if (!con.isConnected())
+ qWarning("Error registering to DBus");
+ if (!con.registerService(server_serviceName))
+ qWarning("Error registering service name");
+ Interface targetObj;
+ con.registerObject(server_objectPath, &targetObj, QDBusConnection::ExportScriptableContents);
+ m_ready.release();
+ exec();
+
+ QDBusConnection::disconnectFromBus( con.name() );
+ }
+private:
+ QSemaphore m_ready;
+};
+
+void tst_QDBusAbstractInterface::callWithTimeout()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY2(con.isConnected(), "Not connected to D-Bus");
+
+ DBusServerThread serverThread;
+
+ QDBusMessage msg = QDBusMessage::createMethodCall(server_serviceName,
+ server_objectPath, server_interfaceName, "sleepMethod");
+ msg << 100;
+
+ {
+ // Call with no timeout -> works
+ QDBusMessage reply = con.call(msg);
+ QCOMPARE((int)reply.type(), (int)QDBusMessage::ReplyMessage);
+ QCOMPARE(reply.arguments().at(0).toInt(), 42);
+ }
+
+ {
+ // Call with 1 sec timeout -> fails
+ QDBusMessage reply = con.call(msg, QDBus::Block, 1);
+ QCOMPARE(reply.type(), QDBusMessage::ErrorMessage);
+ }
+
+ // Now using QDBusInterface
+
+ QDBusInterface iface(server_serviceName, server_objectPath, server_interfaceName, con);
+ {
+ // Call with no timeout
+ QDBusMessage reply = iface.call("sleepMethod", 100);
+ QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
+ QCOMPARE(reply.arguments().at(0).toInt(), 42);
+ }
+ {
+ // Call with 1 sec timeout -> fails
+ iface.setTimeout(1);
+ QDBusMessage reply = iface.call("sleepMethod", 100);
+ QCOMPARE(reply.type(), QDBusMessage::ErrorMessage);
+ }
+
+ // Now using generated code
+ com::trolltech::QtDBus::Pinger p(server_serviceName, server_objectPath, QDBusConnection::sessionBus());
+ {
+ // Call with no timeout
+ QDBusReply<int> reply = p.sleepMethod(100);
+ QVERIFY(reply.isValid());
+ QCOMPARE(int(reply), 42);
+ }
+ {
+ // Call with 1 sec timeout -> fails
+ p.setTimeout(1);
+ QDBusReply<int> reply = p.sleepMethod(100);
+ QVERIFY(!reply.isValid());
+ }
+}
+
+void tst_QDBusAbstractInterface::stringPropRead()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QString expectedValue = targetObj.m_stringProp = "This is a test";
+ QVariant v = p->property("stringProp");
+ QVERIFY(v.isValid());
+ QCOMPARE(v.toString(), expectedValue);
+}
+
+void tst_QDBusAbstractInterface::stringPropWrite()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QString expectedValue = "This is a value";
+ QVERIFY(p->setProperty("stringProp", expectedValue));
+ QCOMPARE(targetObj.m_stringProp, expectedValue);
+}
+
+void tst_QDBusAbstractInterface::variantPropRead()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusVariant expectedValue = targetObj.m_variantProp = QDBusVariant(QVariant(42));
+ QVariant v = p->property("variantProp");
+ QVERIFY(v.isValid());
+ QDBusVariant value = v.value<QDBusVariant>();
+ QCOMPARE(value.variant().userType(), expectedValue.variant().userType());
+ QCOMPARE(value.variant(), expectedValue.variant());
+}
+
+void tst_QDBusAbstractInterface::variantPropWrite()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusVariant expectedValue = QDBusVariant(Q_INT64_C(-47));
+ QVERIFY(p->setProperty("variantProp", qVariantFromValue(expectedValue)));
+ QCOMPARE(targetObj.m_variantProp.variant(), expectedValue.variant());
+}
+
+void tst_QDBusAbstractInterface::complexPropRead()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ RegisteredType expectedValue = targetObj.m_complexProp = RegisteredType("This is a test");
+ QVariant v = p->property("complexProp");
+ QVERIFY(v.userType() == qMetaTypeId<RegisteredType>());
+ QCOMPARE(v.value<RegisteredType>(), targetObj.m_complexProp);
+}
+
+void tst_QDBusAbstractInterface::complexPropWrite()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ RegisteredType expectedValue = RegisteredType("This is a value");
+ QVERIFY(p->setProperty("complexProp", qVariantFromValue(expectedValue)));
+ QCOMPARE(targetObj.m_complexProp, expectedValue);
+}
+
+void tst_QDBusAbstractInterface::stringPropReadPeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+ resetServer();
+
+ QString expectedValue = "This is a test";
+ QVariant v = p->property("stringProp");
+ QVERIFY(v.isValid());
+ QCOMPARE(v.toString(), expectedValue);
+}
+
+void tst_QDBusAbstractInterface::stringPropWritePeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+ resetServer();
+
+ QString expectedValue = "This is a value";
+ QVERIFY(p->setProperty("stringProp", expectedValue));
+ QCOMPARE(targetObj.m_stringProp, expectedValue);
+}
+
+void tst_QDBusAbstractInterface::variantPropReadPeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+ resetServer();
+
+ QDBusVariant expectedValue = QDBusVariant(QVariant(42));
+ QVariant v = p->property("variantProp");
+ QVERIFY(v.isValid());
+ QDBusVariant value = v.value<QDBusVariant>();
+ QCOMPARE(value.variant().userType(), expectedValue.variant().userType());
+ QCOMPARE(value.variant(), expectedValue.variant());
+}
+
+void tst_QDBusAbstractInterface::variantPropWritePeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+ resetServer();
+
+ QDBusVariant expectedValue = QDBusVariant(Q_INT64_C(-47));
+ QVERIFY(p->setProperty("variantProp", qVariantFromValue(expectedValue)));
+ QCOMPARE(targetObj.m_variantProp.variant(), expectedValue.variant());
+}
+
+void tst_QDBusAbstractInterface::complexPropReadPeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+ resetServer();
+
+ RegisteredType expectedValue = RegisteredType("This is a test");
+ QVariant v = p->property("complexProp");
+ QVERIFY(v.userType() == qMetaTypeId<RegisteredType>());
+ QCOMPARE(v.value<RegisteredType>(), expectedValue);
+}
+
+void tst_QDBusAbstractInterface::complexPropWritePeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+ resetServer();
+
+ RegisteredType expectedValue = RegisteredType("This is a value");
+ QVERIFY(p->setProperty("complexProp", qVariantFromValue(expectedValue)));
+ QCOMPARE(targetObj.m_complexProp, expectedValue);
+}
+
+void tst_QDBusAbstractInterface::stringPropDirectRead()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QString expectedValue = targetObj.m_stringProp = "This is a test";
+ QCOMPARE(p->stringProp(), expectedValue);
+}
+
+void tst_QDBusAbstractInterface::stringPropDirectWrite()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QString expectedValue = "This is a value";
+ p->setStringProp(expectedValue);
+ QCOMPARE(targetObj.m_stringProp, expectedValue);
+}
+
+void tst_QDBusAbstractInterface::variantPropDirectRead()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusVariant expectedValue = targetObj.m_variantProp = QDBusVariant(42);
+ QCOMPARE(p->variantProp().variant(), expectedValue.variant());
+}
+
+void tst_QDBusAbstractInterface::variantPropDirectWrite()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusVariant expectedValue = QDBusVariant(Q_INT64_C(-47));
+ p->setVariantProp(expectedValue);
+ QCOMPARE(targetObj.m_variantProp.variant().userType(), expectedValue.variant().userType());
+ QCOMPARE(targetObj.m_variantProp.variant(), expectedValue.variant());
+}
+
+void tst_QDBusAbstractInterface::complexPropDirectRead()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ RegisteredType expectedValue = targetObj.m_complexProp = RegisteredType("This is a test");
+ QCOMPARE(p->complexProp(), targetObj.m_complexProp);
+}
+
+void tst_QDBusAbstractInterface::complexPropDirectWrite()
+{
+ Pinger p = getPinger();
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ RegisteredType expectedValue = RegisteredType("This is a value");
+ p->setComplexProp(expectedValue);
+ QCOMPARE(targetObj.m_complexProp, expectedValue);
+}
+
+void tst_QDBusAbstractInterface::stringPropDirectReadPeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+ resetServer();
+
+ QString expectedValue = "This is a test";
+ QCOMPARE(p->stringProp(), expectedValue);
+}
+
+void tst_QDBusAbstractInterface::stringPropDirectWritePeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+ resetServer();
+
+ QString expectedValue = "This is a value";
+ p->setStringProp(expectedValue);
+ QCOMPARE(targetObj.m_stringProp, expectedValue);
+}
+
+void tst_QDBusAbstractInterface::variantPropDirectReadPeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+ resetServer();
+
+ QDBusVariant expectedValue = QDBusVariant(42);
+ QCOMPARE(p->variantProp().variant(), expectedValue.variant());
+}
+
+void tst_QDBusAbstractInterface::variantPropDirectWritePeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+ resetServer();
+
+ QDBusVariant expectedValue = QDBusVariant(Q_INT64_C(-47));
+ p->setVariantProp(expectedValue);
+ QCOMPARE(targetObj.m_variantProp.variant().userType(), expectedValue.variant().userType());
+ QCOMPARE(targetObj.m_variantProp.variant(), expectedValue.variant());
+}
+
+void tst_QDBusAbstractInterface::complexPropDirectReadPeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+ resetServer();
+
+ RegisteredType expectedValue = RegisteredType("This is a test");
+ QCOMPARE(p->complexProp(), expectedValue);
+}
+
+void tst_QDBusAbstractInterface::complexPropDirectWritePeer()
+{
+ Pinger p = getPingerPeer();
+ QVERIFY2(p, "Not connected to D-Bus");
+ resetServer();
+
+ RegisteredType expectedValue = RegisteredType("This is a value");
+ p->setComplexProp(expectedValue);
+ QCOMPARE(targetObj.m_complexProp, expectedValue);
+}
+
+void tst_QDBusAbstractInterface::getVoidSignal_data()
+{
+ QTest::addColumn<QString>("service");
+ QTest::addColumn<QString>("path");
+
+ QTest::newRow("specific") << QDBusConnection::sessionBus().baseService() << "/";
+ QTest::newRow("service-wildcard") << QString() << "/";
+ QTest::newRow("path-wildcard") << QDBusConnection::sessionBus().baseService() << QString();
+ QTest::newRow("full-wildcard") << QString() << QString();
+}
+
+void tst_QDBusAbstractInterface::getVoidSignal()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we need to connect the signal somewhere in order for D-Bus to enable the rules
+ QTestEventLoop::instance().connect(p.data(), SIGNAL(voidSignal()), SLOT(exitLoop()));
+ QSignalSpy s(p.data(), SIGNAL(voidSignal()));
+
+ emit targetObj.voidSignal();
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QVERIFY(s.size() == 1);
+ QVERIFY(s.at(0).size() == 0);
+}
+
+void tst_QDBusAbstractInterface::getStringSignal_data()
+{
+ getVoidSignal_data();
+}
+
+void tst_QDBusAbstractInterface::getStringSignal()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we need to connect the signal somewhere in order for D-Bus to enable the rules
+ QTestEventLoop::instance().connect(p.data(), SIGNAL(stringSignal(QString)), SLOT(exitLoop()));
+ QSignalSpy s(p.data(), SIGNAL(stringSignal(QString)));
+
+ QString expectedValue = "Good morning";
+ emit targetObj.stringSignal(expectedValue);
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QVERIFY(s.size() == 1);
+ QVERIFY(s[0].size() == 1);
+ QCOMPARE(s[0][0].userType(), int(QVariant::String));
+ QCOMPARE(s[0][0].toString(), expectedValue);
+}
+
+void tst_QDBusAbstractInterface::getComplexSignal_data()
+{
+ getVoidSignal_data();
+}
+
+void tst_QDBusAbstractInterface::getComplexSignal()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we need to connect the signal somewhere in order for D-Bus to enable the rules
+ QTestEventLoop::instance().connect(p.data(), SIGNAL(complexSignal(RegisteredType)), SLOT(exitLoop()));
+ QSignalSpy s(p.data(), SIGNAL(complexSignal(RegisteredType)));
+
+ RegisteredType expectedValue("Good evening");
+ emit targetObj.complexSignal(expectedValue);
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QVERIFY(s.size() == 1);
+ QVERIFY(s[0].size() == 1);
+ QCOMPARE(s[0][0].userType(), qMetaTypeId<RegisteredType>());
+ QCOMPARE(s[0][0].value<RegisteredType>(), expectedValue);
+}
+
+void tst_QDBusAbstractInterface::getVoidSignalPeer_data()
+{
+ QTest::addColumn<QString>("path");
+
+ QTest::newRow("specific") << "/";
+ QTest::newRow("wildcard") << QString();
+}
+
+void tst_QDBusAbstractInterface::getVoidSignalPeer()
+{
+ QFETCH(QString, path);
+ Pinger p = getPingerPeer(path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we need to connect the signal somewhere in order for D-Bus to enable the rules
+ QTestEventLoop::instance().connect(p.data(), SIGNAL(voidSignal()), SLOT(exitLoop()));
+ QSignalSpy s(p.data(), SIGNAL(voidSignal()));
+
+ QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "voidSignal");
+ QVERIFY(QDBusConnection::sessionBus().send(req));
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QVERIFY(s.size() == 1);
+ QVERIFY(s.at(0).size() == 0);
+}
+
+void tst_QDBusAbstractInterface::getStringSignalPeer_data()
+{
+ getVoidSignalPeer_data();
+}
+
+void tst_QDBusAbstractInterface::getStringSignalPeer()
+{
+ QFETCH(QString, path);
+ Pinger p = getPingerPeer(path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we need to connect the signal somewhere in order for D-Bus to enable the rules
+ QTestEventLoop::instance().connect(p.data(), SIGNAL(stringSignal(QString)), SLOT(exitLoop()));
+ QSignalSpy s(p.data(), SIGNAL(stringSignal(QString)));
+
+ QString expectedValue = "Good morning";
+ QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "stringSignal");
+ req << expectedValue;
+ QVERIFY(QDBusConnection::sessionBus().send(req));
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QVERIFY(s.size() == 1);
+ QVERIFY(s[0].size() == 1);
+ QCOMPARE(s[0][0].userType(), int(QVariant::String));
+ QCOMPARE(s[0][0].toString(), expectedValue);
+}
+
+void tst_QDBusAbstractInterface::getComplexSignalPeer_data()
+{
+ getVoidSignalPeer_data();
+}
+
+void tst_QDBusAbstractInterface::getComplexSignalPeer()
+{
+ QFETCH(QString, path);
+ Pinger p = getPingerPeer(path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we need to connect the signal somewhere in order for D-Bus to enable the rules
+ QTestEventLoop::instance().connect(p.data(), SIGNAL(complexSignal(RegisteredType)), SLOT(exitLoop()));
+ QSignalSpy s(p.data(), SIGNAL(complexSignal(RegisteredType)));
+
+ RegisteredType expectedValue("Good evening");
+ QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "complexSignal");
+ req << "Good evening";
+ QVERIFY(QDBusConnection::sessionBus().send(req));
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QVERIFY(s.size() == 1);
+ QVERIFY(s[0].size() == 1);
+ QCOMPARE(s[0][0].userType(), qMetaTypeId<RegisteredType>());
+ QCOMPARE(s[0][0].value<RegisteredType>(), expectedValue);
+}
+
+void tst_QDBusAbstractInterface::followSignal()
+{
+ const QString serviceToFollow = "com.trolltech.tst_qdbusabstractinterface.FollowMe";
+ Pinger p = getPinger(serviceToFollow);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QDBusConnection con = p->connection();
+ QVERIFY(!con.interface()->isServiceRegistered(serviceToFollow));
+ Pinger control = getPinger("");
+
+ // we need to connect the signal somewhere in order for D-Bus to enable the rules
+ QTestEventLoop::instance().connect(p.data(), SIGNAL(voidSignal()), SLOT(exitLoop()));
+ QTestEventLoop::instance().connect(control.data(), SIGNAL(voidSignal()), SLOT(exitLoop()));
+ QSignalSpy s(p.data(), SIGNAL(voidSignal()));
+
+ emit targetObj.voidSignal();
+ QTestEventLoop::instance().enterLoop(200);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ // signal must not have been received because the service isn't registered
+ QVERIFY(s.isEmpty());
+
+ // now register the service
+ QDBusReply<QDBusConnectionInterface::RegisterServiceReply> r =
+ con.interface()->registerService(serviceToFollow, QDBusConnectionInterface::DontQueueService,
+ QDBusConnectionInterface::DontAllowReplacement);
+ QVERIFY(r.isValid() && r.value() == QDBusConnectionInterface::ServiceRegistered);
+ QVERIFY(con.interface()->isServiceRegistered(serviceToFollow));
+ QCoreApplication::instance()->processEvents();
+
+ // emit the signal again:
+ emit targetObj.voidSignal();
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ // now the signal must have been received:
+ QCOMPARE(s.size(), 1);
+ QVERIFY(s.at(0).size() == 0);
+ s.clear();
+
+ // disconnect the signal
+ disconnect(p.data(), SIGNAL(voidSignal()), &QTestEventLoop::instance(), 0);
+
+ // emit the signal again:
+ emit targetObj.voidSignal();
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ // and now it mustn't have been received
+ QVERIFY(s.isEmpty());
+
+ // cleanup:
+ con.interface()->unregisterService(serviceToFollow);
+}
+
+void tst_QDBusAbstractInterface::createErrors_data()
+{
+ QTest::addColumn<QString>("service");
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<QString>("errorName");
+
+ QTest::newRow("invalid-service") << "this isn't valid" << "/" << "com.trolltech.QtDBus.Error.InvalidService";
+ QTest::newRow("invalid-path") << QDBusConnection::sessionBus().baseService() << "this isn't valid"
+ << "com.trolltech.QtDBus.Error.InvalidObjectPath";
+}
+
+void tst_QDBusAbstractInterface::createErrors()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QVERIFY(!p->isValid());
+ QTEST(p->lastError().name(), "errorName");
+}
+
+void tst_QDBusAbstractInterface::createErrorsPeer_data()
+{
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<QString>("errorName");
+
+ QTest::newRow("invalid-path") << "this isn't valid" << "com.trolltech.QtDBus.Error.InvalidObjectPath";
+}
+
+void tst_QDBusAbstractInterface::createErrorsPeer()
+{
+ QFETCH(QString, path);
+ Pinger p = getPingerPeer(path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ QVERIFY(!p->isValid());
+ QTEST(p->lastError().name(), "errorName");
+}
+
+void tst_QDBusAbstractInterface::callErrors_data()
+{
+ createErrors_data();
+ QTest::newRow("service-wildcard") << QString() << "/" << "com.trolltech.QtDBus.Error.InvalidService";
+ QTest::newRow("path-wildcard") << QDBusConnection::sessionBus().baseService() << QString()
+ << "com.trolltech.QtDBus.Error.InvalidObjectPath";
+ QTest::newRow("full-wildcard") << QString() << QString() << "com.trolltech.QtDBus.Error.InvalidService";
+}
+
+void tst_QDBusAbstractInterface::callErrors()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to make this call:
+ QDBusReply<QString> r = p->stringMethod();
+ QVERIFY(!r.isValid());
+ QTEST(r.error().name(), "errorName");
+ QCOMPARE(p->lastError().name(), r.error().name());
+}
+
+void tst_QDBusAbstractInterface::asyncCallErrors_data()
+{
+ callErrors_data();
+}
+
+void tst_QDBusAbstractInterface::asyncCallErrors()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to make this call:
+ QDBusPendingReply<QString> r = p->stringMethod();
+ QVERIFY(r.isError());
+ QTEST(r.error().name(), "errorName");
+ QCOMPARE(p->lastError().name(), r.error().name());
+}
+
+void tst_QDBusAbstractInterface::callErrorsPeer_data()
+{
+ createErrorsPeer_data();
+ QTest::newRow("path-wildcard") << QString() << "com.trolltech.QtDBus.Error.InvalidObjectPath";
+}
+
+void tst_QDBusAbstractInterface::callErrorsPeer()
+{
+ QFETCH(QString, path);
+ Pinger p = getPingerPeer(path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to make this call:
+ QDBusReply<QString> r = p->stringMethod();
+ QVERIFY(!r.isValid());
+ QTEST(r.error().name(), "errorName");
+ QCOMPARE(p->lastError().name(), r.error().name());
+}
+
+void tst_QDBusAbstractInterface::asyncCallErrorsPeer_data()
+{
+ callErrorsPeer_data();
+}
+
+void tst_QDBusAbstractInterface::asyncCallErrorsPeer()
+{
+ QFETCH(QString, path);
+ Pinger p = getPingerPeer(path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to make this call:
+ QDBusPendingReply<QString> r = p->stringMethod();
+ QVERIFY(r.isError());
+ QTEST(r.error().name(), "errorName");
+ QCOMPARE(p->lastError().name(), r.error().name());
+}
+
+void tst_QDBusAbstractInterface::propertyReadErrors_data()
+{
+ callErrors_data();
+}
+
+void tst_QDBusAbstractInterface::propertyReadErrors()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to get this value:
+ QVariant v = p->property("stringProp");
+ QVERIFY(v.isNull());
+ QVERIFY(!v.isValid());
+ QTEST(p->lastError().name(), "errorName");
+}
+
+void tst_QDBusAbstractInterface::propertyWriteErrors_data()
+{
+ callErrors_data();
+}
+
+void tst_QDBusAbstractInterface::propertyWriteErrors()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to get this value:
+ if (p->isValid())
+ QCOMPARE(int(p->lastError().type()), int(QDBusError::NoError));
+ QVERIFY(!p->setProperty("stringProp", ""));
+ QTEST(p->lastError().name(), "errorName");
+}
+
+void tst_QDBusAbstractInterface::directPropertyReadErrors_data()
+{
+ callErrors_data();
+}
+
+void tst_QDBusAbstractInterface::directPropertyReadErrors()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to get this value:
+ QString v = p->stringProp();
+ QVERIFY(v.isNull());
+ QTEST(p->lastError().name(), "errorName");
+}
+
+void tst_QDBusAbstractInterface::directPropertyWriteErrors_data()
+{
+ callErrors_data();
+}
+
+void tst_QDBusAbstractInterface::directPropertyWriteErrors()
+{
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ Pinger p = getPinger(service, path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to get this value:
+ // but there's no direct way of verifying that the setting failed
+ if (p->isValid())
+ QCOMPARE(int(p->lastError().type()), int(QDBusError::NoError));
+ p->setStringProp("");
+ QTEST(p->lastError().name(), "errorName");
+}
+
+void tst_QDBusAbstractInterface::propertyReadErrorsPeer_data()
+{
+ callErrorsPeer_data();
+}
+
+void tst_QDBusAbstractInterface::propertyReadErrorsPeer()
+{
+ QFETCH(QString, path);
+ Pinger p = getPingerPeer(path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to get this value:
+ QVariant v = p->property("stringProp");
+ QVERIFY(v.isNull());
+ QVERIFY(!v.isValid());
+ QTEST(p->lastError().name(), "errorName");
+}
+
+void tst_QDBusAbstractInterface::propertyWriteErrorsPeer_data()
+{
+ callErrorsPeer_data();
+}
+
+void tst_QDBusAbstractInterface::propertyWriteErrorsPeer()
+{
+ QFETCH(QString, path);
+ Pinger p = getPingerPeer(path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to get this value:
+ if (p->isValid())
+ QCOMPARE(int(p->lastError().type()), int(QDBusError::NoError));
+ QVERIFY(!p->setProperty("stringProp", ""));
+ QTEST(p->lastError().name(), "errorName");
+}
+
+void tst_QDBusAbstractInterface::directPropertyReadErrorsPeer_data()
+{
+ callErrorsPeer_data();
+}
+
+void tst_QDBusAbstractInterface::directPropertyReadErrorsPeer()
+{
+ QFETCH(QString, path);
+ Pinger p = getPingerPeer(path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to get this value:
+ QString v = p->stringProp();
+ QVERIFY(v.isNull());
+ QTEST(p->lastError().name(), "errorName");
+}
+
+void tst_QDBusAbstractInterface::directPropertyWriteErrorsPeer_data()
+{
+ callErrorsPeer_data();
+}
+
+void tst_QDBusAbstractInterface::directPropertyWriteErrorsPeer()
+{
+ QFETCH(QString, path);
+ Pinger p = getPingerPeer(path);
+ QVERIFY2(p, "Not connected to D-Bus");
+
+ // we shouldn't be able to get this value:
+ // but there's no direct way of verifying that the setting failed
+ if (p->isValid())
+ QCOMPARE(int(p->lastError().type()), int(QDBusError::NoError));
+ p->setStringProp("");
+ QTEST(p->lastError().name(), "errorName");
+}
+
+QTEST_MAIN(tst_QDBusAbstractInterface)
+#include "tst_qdbusabstractinterface.moc"
diff --git a/tests/auto/dbus/qdbusconnection/.gitignore b/tests/auto/dbus/qdbusconnection/.gitignore
new file mode 100644
index 0000000000..2995d60244
--- /dev/null
+++ b/tests/auto/dbus/qdbusconnection/.gitignore
@@ -0,0 +1 @@
+tst_qdbusconnection
diff --git a/tests/auto/dbus/qdbusconnection/qdbusconnection.pro b/tests/auto/dbus/qdbusconnection/qdbusconnection.pro
new file mode 100644
index 0000000000..d33ab0d95b
--- /dev/null
+++ b/tests/auto/dbus/qdbusconnection/qdbusconnection.pro
@@ -0,0 +1,11 @@
+load(qttest_p4)
+QT = core
+
+contains(QT_CONFIG,dbus): {
+ SOURCES += tst_qdbusconnection.cpp
+ QT += dbus
+} else {
+ SOURCES += ../qdbusmarshall/dummy.cpp
+}
+
+
diff --git a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp
new file mode 100644
index 0000000000..6490bfe973
--- /dev/null
+++ b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp
@@ -0,0 +1,1305 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qcoreapplication.h>
+#include <qdebug.h>
+
+#include <QtTest/QtTest>
+#include <QtDBus/QtDBus>
+
+class BaseObject: public QObject
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "local.BaseObject")
+public:
+ BaseObject(QObject *parent = 0) : QObject(parent) { }
+public slots:
+ void anotherMethod() { }
+};
+
+class MyObject: public BaseObject
+{
+ Q_OBJECT
+public slots:
+ void method(const QDBusMessage &msg);
+
+public:
+ static QString path;
+ int callCount;
+ MyObject(QObject *parent = 0) : BaseObject(parent), callCount(0) {}
+};
+
+void MyObject::method(const QDBusMessage &msg)
+{
+ path = msg.path();
+ ++callCount;
+ //qDebug() << msg;
+}
+
+class tst_QDBusConnection: public QObject
+{
+ Q_OBJECT
+
+ int signalsReceived;
+public slots:
+ void oneSlot() { ++signalsReceived; }
+ void exitLoop() { ++signalsReceived; QTestEventLoop::instance().exitLoop(); }
+ void secondCallWithCallback();
+
+private slots:
+ void noConnection();
+ void connectToBus();
+ void connectToPeer();
+ void connect();
+ void send();
+ void sendWithGui();
+ void sendAsync();
+ void sendSignal();
+
+ void registerObject_data();
+ void registerObject();
+ void registerObjectPeer_data();
+ void registerObjectPeer();
+ void registerObject2();
+ void registerObjectPeer2();
+
+ void registerQObjectChildren();
+ void registerQObjectChildrenPeer();
+
+ void callSelf();
+ void callSelfByAnotherName_data();
+ void callSelfByAnotherName();
+ void multipleInterfacesInQObject();
+
+ void slotsWithLessParameters();
+ void nestedCallWithCallback();
+
+ void serviceRegistrationRaceCondition();
+
+ void registerVirtualObject();
+ void callVirtualObject();
+ void callVirtualObjectLocal();
+
+public:
+ QString serviceName() const { return "com.trolltech.Qt.Autotests.QDBusConnection"; }
+ bool callMethod(const QDBusConnection &conn, const QString &path);
+ bool callMethodPeer(const QDBusConnection &conn, const QString &path);
+};
+
+class QDBusSpy: public QObject
+{
+ Q_OBJECT
+public slots:
+ void handlePing(const QString &str) { args.clear(); args << str; }
+ void asyncReply(const QDBusMessage &msg) { args = msg.arguments(); }
+
+public:
+ QList<QVariant> args;
+};
+
+void tst_QDBusConnection::noConnection()
+{
+ QDBusConnection con = QDBusConnection::connectToBus("unix:path=/dev/null", "testconnection");
+ QVERIFY(!con.isConnected());
+
+ // try sending a message. This should fail
+ QDBusMessage msg = QDBusMessage::createMethodCall("org.kde.selftest", "/org/kde/selftest",
+ "org.kde.selftest", "Ping");
+ msg << QLatin1String("ping");
+
+ QVERIFY(!con.send(msg));
+
+ QDBusSpy spy;
+ QVERIFY(con.callWithCallback(msg, &spy, SLOT(asyncReply)) == 0);
+
+ QDBusMessage reply = con.call(msg);
+ QVERIFY(reply.type() == QDBusMessage::ErrorMessage);
+
+ QDBusReply<void> voidreply(reply);
+ QVERIFY(!voidreply.isValid());
+
+ QDBusConnection::disconnectFromBus("testconnection");
+}
+
+void tst_QDBusConnection::sendSignal()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+
+ QVERIFY(con.isConnected());
+
+ QDBusMessage msg = QDBusMessage::createSignal("/org/kde/selftest", "org.kde.selftest",
+ "Ping");
+ msg << QLatin1String("ping");
+
+ QVERIFY(con.send(msg));
+
+ QTest::qWait(1000);
+}
+
+void tst_QDBusConnection::send()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+
+ QVERIFY(con.isConnected());
+
+ QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.DBus",
+ "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames");
+
+ QDBusMessage reply = con.call(msg);
+
+ QCOMPARE(reply.arguments().count(), 1);
+ QCOMPARE(reply.arguments().at(0).typeName(), "QStringList");
+ QVERIFY(reply.arguments().at(0).toStringList().contains(con.baseService()));
+}
+
+void tst_QDBusConnection::sendWithGui()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+
+ QVERIFY(con.isConnected());
+
+ QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.DBus",
+ "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames");
+
+ QDBusMessage reply = con.call(msg, QDBus::BlockWithGui);
+
+ QCOMPARE(reply.arguments().count(), 1);
+ QCOMPARE(reply.arguments().at(0).typeName(), "QStringList");
+ QVERIFY(reply.arguments().at(0).toStringList().contains(con.baseService()));
+}
+
+void tst_QDBusConnection::sendAsync()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+
+ QDBusSpy spy;
+
+ QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.DBus",
+ "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames");
+ QVERIFY(con.callWithCallback(msg, &spy, SLOT(asyncReply(QDBusMessage))));
+
+ QTest::qWait(1000);
+
+ QCOMPARE(spy.args.value(0).typeName(), "QStringList");
+ QVERIFY(spy.args.at(0).toStringList().contains(con.baseService()));
+}
+
+void tst_QDBusConnection::connect()
+{
+ QDBusSpy spy;
+
+ QDBusConnection con = QDBusConnection::sessionBus();
+
+ con.connect(con.baseService(), "/org/kde/selftest", "org.kde.selftest", "ping", &spy,
+ SLOT(handlePing(QString)));
+
+ QDBusMessage msg = QDBusMessage::createSignal("/org/kde/selftest", "org.kde.selftest",
+ "ping");
+ msg << QLatin1String("ping");
+
+ QVERIFY(con.send(msg));
+
+ QTest::qWait(1000);
+
+ QCOMPARE(spy.args.count(), 1);
+ QCOMPARE(spy.args.at(0).toString(), QString("ping"));
+}
+
+void tst_QDBusConnection::connectToBus()
+{
+ {
+ QDBusConnection con = QDBusConnection::connectToBus(
+ QDBusConnection::SessionBus, "bubu");
+
+ QVERIFY(con.isConnected());
+ QVERIFY(!con.lastError().isValid());
+
+ QDBusConnection con2("foo");
+ QVERIFY(!con2.isConnected());
+ QVERIFY(!con2.lastError().isValid());
+
+ con2 = con;
+ QVERIFY(con.isConnected());
+ QVERIFY(con2.isConnected());
+ QVERIFY(!con.lastError().isValid());
+ QVERIFY(!con2.lastError().isValid());
+ }
+
+ {
+ QDBusConnection con("bubu");
+ QVERIFY(con.isConnected());
+ QVERIFY(!con.lastError().isValid());
+ }
+
+ QDBusConnection::disconnectFromPeer("bubu");
+
+ {
+ QDBusConnection con("bubu");
+ QVERIFY(con.isConnected());
+ QVERIFY(!con.lastError().isValid());
+ }
+
+ QDBusConnection::disconnectFromBus("bubu");
+
+ {
+ QDBusConnection con("bubu");
+ QVERIFY(!con.isConnected());
+ QVERIFY(!con.lastError().isValid());
+ }
+
+ QByteArray address = qgetenv("DBUS_SESSION_BUS_ADDRESS");
+ if (!address.isEmpty()) {
+ QDBusConnection con = QDBusConnection::connectToBus(address, "newconn");
+ QVERIFY(con.isConnected());
+ QVERIFY(!con.lastError().isValid());
+
+ QDBusConnection::disconnectFromBus("newconn");
+ }
+}
+
+void tst_QDBusConnection::connectToPeer()
+{
+ {
+ QDBusConnection con = QDBusConnection::connectToPeer(
+ "", "newconn");
+ QVERIFY(!con.isConnected());
+ QVERIFY(con.lastError().isValid());
+ }
+
+ QDBusServer server("unix:tmpdir=/tmp", 0);
+
+ {
+ QDBusConnection con = QDBusConnection::connectToPeer(
+ "unix:abstract=/tmp/dbus-XXXXXXXXXX,guid=00000000000000000000000000000000", "newconn2");
+ QVERIFY(!con.isConnected());
+ QVERIFY(con.lastError().isValid());
+ }
+
+ {
+ QDBusConnection con = QDBusConnection::connectToPeer(
+ server.address(), "bubu");
+
+ QVERIFY(con.isConnected());
+ QVERIFY(!con.lastError().isValid());
+
+ QDBusConnection con2("foo");
+ QVERIFY(!con2.isConnected());
+ QVERIFY(!con2.lastError().isValid());
+
+ con2 = con;
+ QVERIFY(con.isConnected());
+ QVERIFY(con2.isConnected());
+ QVERIFY(!con.lastError().isValid());
+ QVERIFY(!con2.lastError().isValid());
+ }
+
+ {
+ QDBusConnection con("bubu");
+ QVERIFY(con.isConnected());
+ QVERIFY(!con.lastError().isValid());
+ }
+
+ QDBusConnection::disconnectFromBus("bubu");
+
+ {
+ QDBusConnection con("bubu");
+ QVERIFY(con.isConnected());
+ QVERIFY(!con.lastError().isValid());
+ }
+
+ QDBusConnection::disconnectFromPeer("bubu");
+
+ {
+ QDBusConnection con("bubu");
+ QVERIFY(!con.isConnected());
+ QVERIFY(!con.lastError().isValid());
+ }
+}
+
+void tst_QDBusConnection::registerObject_data()
+{
+ QTest::addColumn<QString>("path");
+
+ QTest::newRow("/") << "/";
+ QTest::newRow("/p1") << "/p1";
+ QTest::newRow("/p2") << "/p2";
+ QTest::newRow("/p1/q") << "/p1/q";
+ QTest::newRow("/p1/q/r") << "/p1/q/r";
+}
+
+void tst_QDBusConnection::registerObject()
+{
+ QFETCH(QString, path);
+
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+
+ //QVERIFY(!callMethod(con, path));
+ {
+ // register one object at root:
+ MyObject obj;
+ QVERIFY(con.registerObject(path, &obj, QDBusConnection::ExportAllSlots));
+ QCOMPARE(con.objectRegisteredAt(path), static_cast<QObject *>(&obj));
+ QVERIFY(callMethod(con, path));
+ QCOMPARE(obj.path, path);
+ }
+ // make sure it's gone
+ QVERIFY(!callMethod(con, path));
+}
+
+class MyServer : public QDBusServer
+{
+ Q_OBJECT
+public:
+ MyServer(QString path, QString addr, QObject* parent) : QDBusServer(addr, parent),
+ m_path(path),
+ m_conn("none")
+ {
+ connect(this, SIGNAL(newConnection(const QDBusConnection&)), SLOT(handleConnection(const QDBusConnection&)));
+ }
+
+ bool registerObject()
+ {
+ if( !m_conn.registerObject(m_path, &m_obj, QDBusConnection::ExportAllSlots) )
+ return false;
+ if(! (m_conn.objectRegisteredAt(m_path) == &m_obj))
+ return false;
+ return true;
+ }
+
+ void unregisterObject()
+ {
+ m_conn.unregisterObject(m_path);
+ }
+
+public slots:
+ void handleConnection(const QDBusConnection& c)
+ {
+ m_conn = c;
+ QVERIFY(isConnected());
+ QVERIFY(m_conn.isConnected());
+ QVERIFY(registerObject());
+ }
+
+private:
+ MyObject m_obj;
+ QString m_path;
+ QDBusConnection m_conn;
+};
+
+
+void tst_QDBusConnection::registerObjectPeer_data()
+{
+ QTest::addColumn<QString>("path");
+
+ QTest::newRow("/") << "/";
+ QTest::newRow("/p1") << "/p1";
+ QTest::newRow("/p2") << "/p2";
+ QTest::newRow("/p1/q") << "/p1/q";
+ QTest::newRow("/p1/q/r") << "/p1/q/r";
+}
+
+void tst_QDBusConnection::registerObjectPeer()
+{
+ QFETCH(QString, path);
+
+ MyServer server(path, "unix:tmpdir=/tmp", 0);
+
+ {
+ QDBusConnection con = QDBusConnection::connectToPeer(server.address(), "foo");
+
+ QCoreApplication::processEvents();
+ QVERIFY(con.isConnected());
+
+ MyObject obj;
+ QVERIFY(callMethodPeer(con, path));
+ QCOMPARE(obj.path, path);
+ }
+
+ {
+ QDBusConnection con("foo");
+ QVERIFY(con.isConnected());
+ QVERIFY(callMethodPeer(con, path));
+ }
+
+ server.unregisterObject();
+
+ {
+ QDBusConnection con("foo");
+ QVERIFY(con.isConnected());
+ QVERIFY(!callMethodPeer(con, path));
+ }
+
+ server.registerObject();
+
+ {
+ QDBusConnection con("foo");
+ QVERIFY(con.isConnected());
+ QVERIFY(callMethodPeer(con, path));
+ }
+
+ QDBusConnection::disconnectFromPeer("foo");
+
+ {
+ QDBusConnection con("foo");
+ QVERIFY(!con.isConnected());
+ QVERIFY(!callMethodPeer(con, path));
+ }
+}
+
+void tst_QDBusConnection::registerObject2()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+
+ // make sure nothing is using our paths:
+ QVERIFY(!callMethod(con, "/"));
+ QVERIFY(!callMethod(con, "/p1"));
+ QVERIFY(!callMethod(con, "/p2"));
+ QVERIFY(!callMethod(con, "/p1/q"));
+ QVERIFY(!callMethod(con, "/p1/q/r"));
+
+ {
+ // register one object at root:
+ MyObject obj;
+ QVERIFY(con.registerObject("/", &obj, QDBusConnection::ExportAllSlots));
+ QVERIFY(callMethod(con, "/"));
+ qDebug() << obj.path;
+ QCOMPARE(obj.path, QString("/"));
+ }
+ // make sure it's gone
+ QVERIFY(!callMethod(con, "/"));
+
+ {
+ // register one at an element:
+ MyObject obj;
+ QVERIFY(con.registerObject("/p1", &obj, QDBusConnection::ExportAllSlots));
+ QVERIFY(!callMethod(con, "/"));
+ QVERIFY(callMethod(con, "/p1"));
+ qDebug() << obj.path;
+ QCOMPARE(obj.path, QString("/p1"));
+
+ // re-register it somewhere else
+ QVERIFY(con.registerObject("/p2", &obj, QDBusConnection::ExportAllSlots));
+ QVERIFY(callMethod(con, "/p1"));
+ QCOMPARE(obj.path, QString("/p1"));
+ QVERIFY(callMethod(con, "/p2"));
+ QCOMPARE(obj.path, QString("/p2"));
+ }
+ // make sure it's gone
+ QVERIFY(!callMethod(con, "/p1"));
+ QVERIFY(!callMethod(con, "/p2"));
+
+ {
+ // register at a deep path
+ MyObject obj;
+ QVERIFY(con.registerObject("/p1/q/r", &obj, QDBusConnection::ExportAllSlots));
+ QVERIFY(!callMethod(con, "/"));
+ QVERIFY(!callMethod(con, "/p1"));
+ QVERIFY(!callMethod(con, "/p1/q"));
+ QVERIFY(callMethod(con, "/p1/q/r"));
+ QCOMPARE(obj.path, QString("/p1/q/r"));
+ }
+ // make sure it's gone
+ QVERIFY(!callMethod(con, "/p1/q/r"));
+
+ {
+ MyObject obj;
+ QVERIFY(con.registerObject("/p1/q2", &obj, QDBusConnection::ExportAllSlots));
+ QVERIFY(callMethod(con, "/p1/q2"));
+ QCOMPARE(obj.path, QString("/p1/q2"));
+
+ // try unregistering
+ con.unregisterObject("/p1/q2");
+ QVERIFY(!callMethod(con, "/p1/q2"));
+
+ // register it again
+ QVERIFY(con.registerObject("/p1/q2", &obj, QDBusConnection::ExportAllSlots));
+ QVERIFY(callMethod(con, "/p1/q2"));
+ QCOMPARE(obj.path, QString("/p1/q2"));
+
+ // now try removing things around it:
+ con.unregisterObject("/p2");
+ QVERIFY(callMethod(con, "/p1/q2")); // unrelated object shouldn't affect
+
+ con.unregisterObject("/p1");
+ QVERIFY(callMethod(con, "/p1/q2")); // unregistering just the parent shouldn't affect it
+
+ con.unregisterObject("/p1/q2/r");
+ QVERIFY(callMethod(con, "/p1/q2")); // unregistering non-existing child shouldn't affect it either
+
+ con.unregisterObject("/p1/q");
+ QVERIFY(callMethod(con, "/p1/q2")); // unregistering sibling (before) shouldn't affect
+
+ con.unregisterObject("/p1/r");
+ QVERIFY(callMethod(con, "/p1/q2")); // unregistering sibling (after) shouldn't affect
+
+ // now remove it:
+ con.unregisterObject("/p1", QDBusConnection::UnregisterTree);
+ QVERIFY(!callMethod(con, "/p1/q2")); // we removed the full tree
+ }
+}
+
+class MyServer2 : public QDBusServer
+{
+ Q_OBJECT
+public:
+ MyServer2(QString addr, QObject* parent) : QDBusServer(addr, parent),
+ m_conn("none")
+ {
+ connect(this, SIGNAL(newConnection(const QDBusConnection&)), SLOT(handleConnection(const QDBusConnection&)));
+ }
+
+ QDBusConnection connection()
+ {
+ return m_conn;
+ }
+
+public slots:
+ void handleConnection(const QDBusConnection& c)
+ {
+ m_conn = c;
+ QVERIFY(isConnected());
+ QVERIFY(m_conn.isConnected());
+ }
+
+private:
+ MyObject m_obj;
+ QDBusConnection m_conn;
+};
+
+void tst_QDBusConnection::registerObjectPeer2()
+{
+ MyServer2 server("unix:tmpdir=/tmp", 0);
+ QDBusConnection con = QDBusConnection::connectToPeer(server.address(), "foo");
+ QCoreApplication::processEvents();
+ QVERIFY(con.isConnected());
+
+ QDBusConnection srv_con = server.connection();
+
+ // make sure nothing is using our paths:
+ QVERIFY(!callMethodPeer(srv_con, "/"));
+ QVERIFY(!callMethodPeer(srv_con, "/p1"));
+ QVERIFY(!callMethodPeer(srv_con, "/p2"));
+ QVERIFY(!callMethodPeer(srv_con, "/p1/q"));
+ QVERIFY(!callMethodPeer(srv_con, "/p1/q/r"));
+
+ {
+ // register one object at root:
+ MyObject obj;
+ QVERIFY(con.registerObject("/", &obj, QDBusConnection::ExportAllSlots));
+ QVERIFY(callMethodPeer(srv_con, "/"));
+ qDebug() << obj.path;
+ QCOMPARE(obj.path, QString("/"));
+ }
+ // make sure it's gone
+ QVERIFY(!callMethodPeer(srv_con, "/"));
+
+ {
+ // register one at an element:
+ MyObject obj;
+ QVERIFY(con.registerObject("/p1", &obj, QDBusConnection::ExportAllSlots));
+ QVERIFY(!callMethodPeer(srv_con, "/"));
+ QVERIFY(callMethodPeer(srv_con, "/p1"));
+ qDebug() << obj.path;
+ QCOMPARE(obj.path, QString("/p1"));
+
+ // re-register it somewhere else
+ QVERIFY(con.registerObject("/p2", &obj, QDBusConnection::ExportAllSlots));
+ QVERIFY(callMethodPeer(srv_con, "/p1"));
+ QCOMPARE(obj.path, QString("/p1"));
+ QVERIFY(callMethodPeer(srv_con, "/p2"));
+ QCOMPARE(obj.path, QString("/p2"));
+ }
+ // make sure it's gone
+ QVERIFY(!callMethodPeer(srv_con, "/p1"));
+ QVERIFY(!callMethodPeer(srv_con, "/p2"));
+
+ {
+ // register at a deep path
+ MyObject obj;
+ QVERIFY(con.registerObject("/p1/q/r", &obj, QDBusConnection::ExportAllSlots));
+ QVERIFY(!callMethodPeer(srv_con, "/"));
+ QVERIFY(!callMethodPeer(srv_con, "/p1"));
+ QVERIFY(!callMethodPeer(srv_con, "/p1/q"));
+ QVERIFY(callMethodPeer(srv_con, "/p1/q/r"));
+ QCOMPARE(obj.path, QString("/p1/q/r"));
+ }
+ // make sure it's gone
+ QVERIFY(!callMethodPeer(srv_con, "/p1/q/r"));
+
+ {
+ MyObject obj;
+ QVERIFY(con.registerObject("/p1/q2", &obj, QDBusConnection::ExportAllSlots));
+ QVERIFY(callMethodPeer(srv_con, "/p1/q2"));
+ QCOMPARE(obj.path, QString("/p1/q2"));
+
+ // try unregistering
+ con.unregisterObject("/p1/q2");
+ QVERIFY(!callMethodPeer(srv_con, "/p1/q2"));
+
+ // register it again
+ QVERIFY(con.registerObject("/p1/q2", &obj, QDBusConnection::ExportAllSlots));
+ QVERIFY(callMethodPeer(srv_con, "/p1/q2"));
+ QCOMPARE(obj.path, QString("/p1/q2"));
+
+ // now try removing things around it:
+ con.unregisterObject("/p2");
+ QVERIFY(callMethodPeer(srv_con, "/p1/q2")); // unrelated object shouldn't affect
+
+ con.unregisterObject("/p1");
+ QVERIFY(callMethodPeer(srv_con, "/p1/q2")); // unregistering just the parent shouldn't affect it
+
+ con.unregisterObject("/p1/q2/r");
+ QVERIFY(callMethodPeer(srv_con, "/p1/q2")); // unregistering non-existing child shouldn't affect it either
+
+ con.unregisterObject("/p1/q");
+ QVERIFY(callMethodPeer(srv_con, "/p1/q2")); // unregistering sibling (before) shouldn't affect
+
+ con.unregisterObject("/p1/r");
+ QVERIFY(callMethodPeer(srv_con, "/p1/q2")); // unregistering sibling (after) shouldn't affect
+
+ // now remove it:
+ con.unregisterObject("/p1", QDBusConnection::UnregisterTree);
+ QVERIFY(!callMethodPeer(srv_con, "/p1/q2")); // we removed the full tree
+ }
+
+ QDBusConnection::disconnectFromPeer("foo");
+}
+
+
+void tst_QDBusConnection::registerQObjectChildren()
+{
+ // make sure no one is there
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(!callMethod(con, "/p1"));
+
+ {
+ MyObject obj, *a, *b, *c, *cc;
+
+ a = new MyObject(&obj);
+ a->setObjectName("a");
+
+ b = new MyObject(&obj);
+ b->setObjectName("b");
+
+ c = new MyObject(&obj);
+ c->setObjectName("c");
+
+ cc = new MyObject(c);
+ cc->setObjectName("cc");
+
+ con.registerObject("/p1", &obj, QDBusConnection::ExportAllSlots |
+ QDBusConnection::ExportChildObjects);
+
+ // make calls
+ QVERIFY(callMethod(con, "/p1"));
+ QCOMPARE(obj.callCount, 1);
+ QVERIFY(callMethod(con, "/p1/a"));
+ QCOMPARE(a->callCount, 1);
+ QVERIFY(callMethod(con, "/p1/b"));
+ QCOMPARE(b->callCount, 1);
+ QVERIFY(callMethod(con, "/p1/c"));
+ QCOMPARE(c->callCount, 1);
+ QVERIFY(callMethod(con, "/p1/c/cc"));
+ QCOMPARE(cc->callCount, 1);
+
+ QVERIFY(!callMethod(con, "/p1/d"));
+ QVERIFY(!callMethod(con, "/p1/c/abc"));
+
+ // pull an object, see if it goes away:
+ delete b;
+ QVERIFY(!callMethod(con, "/p1/b"));
+
+ delete c;
+ QVERIFY(!callMethod(con, "/p1/c"));
+ QVERIFY(!callMethod(con, "/p1/c/cc"));
+ }
+
+ QVERIFY(!callMethod(con, "/p1"));
+ QVERIFY(!callMethod(con, "/p1/a"));
+ QVERIFY(!callMethod(con, "/p1/b"));
+ QVERIFY(!callMethod(con, "/p1/c"));
+ QVERIFY(!callMethod(con, "/p1/c/cc"));
+}
+
+void tst_QDBusConnection::registerQObjectChildrenPeer()
+{
+ MyServer2 server("unix:tmpdir=/tmp", 0);
+ QDBusConnection con = QDBusConnection::connectToPeer(server.address(), "foo");
+ QCoreApplication::processEvents();
+ QVERIFY(con.isConnected());
+
+ QDBusConnection srv_con = server.connection();
+
+ QVERIFY(!callMethodPeer(srv_con, "/p1"));
+
+ {
+ MyObject obj, *a, *b, *c, *cc;
+
+ a = new MyObject(&obj);
+ a->setObjectName("a");
+
+ b = new MyObject(&obj);
+ b->setObjectName("b");
+
+ c = new MyObject(&obj);
+ c->setObjectName("c");
+
+ cc = new MyObject(c);
+ cc->setObjectName("cc");
+
+ con.registerObject("/p1", &obj, QDBusConnection::ExportAllSlots |
+ QDBusConnection::ExportChildObjects);
+
+ // make calls
+ QVERIFY(callMethodPeer(srv_con, "/p1"));
+ QCOMPARE(obj.callCount, 1);
+ QVERIFY(callMethodPeer(srv_con, "/p1/a"));
+ QCOMPARE(a->callCount, 1);
+ QVERIFY(callMethodPeer(srv_con, "/p1/b"));
+ QCOMPARE(b->callCount, 1);
+ QVERIFY(callMethodPeer(srv_con, "/p1/c"));
+ QCOMPARE(c->callCount, 1);
+ QVERIFY(callMethodPeer(srv_con, "/p1/c/cc"));
+ QCOMPARE(cc->callCount, 1);
+
+ QVERIFY(!callMethodPeer(srv_con, "/p1/d"));
+ QVERIFY(!callMethodPeer(srv_con, "/p1/c/abc"));
+
+ // pull an object, see if it goes away:
+ delete b;
+ QVERIFY(!callMethodPeer(srv_con, "/p1/b"));
+
+ delete c;
+ QVERIFY(!callMethodPeer(srv_con, "/p1/c"));
+ QVERIFY(!callMethodPeer(srv_con, "/p1/c/cc"));
+ }
+
+ QVERIFY(!callMethodPeer(srv_con, "/p1"));
+ QVERIFY(!callMethodPeer(srv_con, "/p1/a"));
+ QVERIFY(!callMethodPeer(srv_con, "/p1/b"));
+ QVERIFY(!callMethodPeer(srv_con, "/p1/c"));
+ QVERIFY(!callMethodPeer(srv_con, "/p1/c/cc"));
+
+ QDBusConnection::disconnectFromPeer("foo");
+}
+
+bool tst_QDBusConnection::callMethod(const QDBusConnection &conn, const QString &path)
+{
+ QDBusMessage msg = QDBusMessage::createMethodCall(conn.baseService(), path, "", "method");
+ QDBusMessage reply = conn.call(msg, QDBus::Block/*WithGui*/);
+ if (reply.type() != QDBusMessage::ReplyMessage)
+ return false;
+ if (MyObject::path == path) {
+ QTest::compare_helper(true, "COMPARE()", __FILE__, __LINE__);
+ } else {
+ QTest::compare_helper(false, "Compared values are not the same",
+ QTest::toString(MyObject::path), QTest::toString(path),
+ "MyObject::path", "path", __FILE__, __LINE__);
+ return false;
+ }
+
+ return true;
+}
+
+bool tst_QDBusConnection::callMethodPeer(const QDBusConnection &conn, const QString &path)
+{
+ QDBusMessage msg = QDBusMessage::createMethodCall("", path, "", "method");
+ QDBusMessage reply = conn.call(msg, QDBus::BlockWithGui);
+
+ if (reply.type() != QDBusMessage::ReplyMessage)
+ return false;
+ if (MyObject::path == path) {
+ QTest::compare_helper(true, "COMPARE()", __FILE__, __LINE__);
+ } else {
+ QTest::compare_helper(false, "Compared values are not the same",
+ QTest::toString(MyObject::path), QTest::toString(path),
+ "MyObject::path", "path", __FILE__, __LINE__);
+ return false;
+ }
+
+ return true;
+}
+
+class TestObject : public QObject
+{
+Q_OBJECT
+public:
+ TestObject(QObject *parent = 0) : QObject(parent) {}
+ ~TestObject() {}
+
+ QString func;
+
+public slots:
+ void test0() { func = "test0"; }
+ void test1(int i) { func = "test1 " + QString::number(i); }
+ int test2() { func = "test2"; return 43; }
+ int test3(int i) { func = "test2"; return i + 1; }
+};
+
+void tst_QDBusConnection::callSelf()
+{
+ TestObject testObject;
+ QDBusConnection connection = QDBusConnection::sessionBus();
+ QVERIFY(connection.registerObject("/test", &testObject,
+ QDBusConnection::ExportAllContents));
+ QCOMPARE(connection.objectRegisteredAt("/test"), static_cast<QObject *>(&testObject));
+ QVERIFY(connection.registerService(serviceName()));
+ QDBusInterface interface(serviceName(), "/test");
+ QVERIFY(interface.isValid());
+
+ interface.call(QDBus::Block, "test0");
+ QCOMPARE(testObject.func, QString("test0"));
+ interface.call(QDBus::Block, "test1", 42);
+ QCOMPARE(testObject.func, QString("test1 42"));
+ QDBusMessage reply = interface.call(QDBus::Block, "test2");
+ QCOMPARE(testObject.func, QString("test2"));
+ QCOMPARE(reply.arguments().value(0).toInt(), 43);
+
+ QDBusMessage msg = QDBusMessage::createMethodCall(serviceName(), "/test",
+ QString(), "test3");
+ msg << 44;
+ reply = connection.call(msg);
+ QCOMPARE(reply.arguments().value(0).toInt(), 45);
+}
+
+void tst_QDBusConnection::callSelfByAnotherName_data()
+{
+ QTest::addColumn<int>("registerMethod");
+ QTest::newRow("connection") << 0;
+ QTest::newRow("connection-interface") << 1;
+ QTest::newRow("direct") << 2;
+}
+
+void tst_QDBusConnection::callSelfByAnotherName()
+{
+ static int counter = 0;
+ QString sname = serviceName() + QString::number(counter++);
+
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+
+ TestObject testObject;
+ QVERIFY(con.registerObject("/test", &testObject,
+ QDBusConnection::ExportAllContents));
+ con.connect("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameOwnerChanged",
+ QStringList() << sname << "",
+ QString(), &QTestEventLoop::instance(), SLOT(exitLoop()));
+
+ // register the name
+ QFETCH(int, registerMethod);
+ switch (registerMethod) {
+ case 0:
+ QVERIFY(con.registerService(sname));
+ break;
+
+ case 1:
+ QVERIFY(con.interface()->registerService(sname).value() == QDBusConnectionInterface::ServiceRegistered);
+ break;
+
+ case 2: {
+ // flag is DBUS_NAME_FLAG_DO_NOT_QUEUE = 0x04
+ // reply is DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER = 1
+ QDBusReply<uint> reply = con.interface()->call("RequestName", sname, 4u);
+ QVERIFY(reply.value() == 1);
+ }
+ }
+
+ struct Deregisterer {
+ QDBusConnection con;
+ QString sname;
+ Deregisterer(const QDBusConnection &con, const QString &sname) : con(con), sname(sname) {}
+ ~Deregisterer() { con.interface()->unregisterService(sname); }
+ } deregisterer(con, sname);
+
+ // give the connection a chance to find out that we're good to go
+ QTestEventLoop::instance().enterLoop(2);
+ con.disconnect("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameOwnerChanged",
+ QStringList() << sname << "",
+ QString(), &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ // make the call
+ QDBusMessage msg = QDBusMessage::createMethodCall(sname, "/test",
+ QString(), "test0");
+ QDBusMessage reply = con.call(msg, QDBus::Block, 1000);
+
+ QVERIFY(reply.type() == QDBusMessage::ReplyMessage);
+}
+
+void tst_QDBusConnection::multipleInterfacesInQObject()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(!callMethod(con, "/p1"));
+
+ MyObject obj;
+ con.registerObject("/p1", &obj, QDBusConnection::ExportAllSlots);
+
+ // check if we can call the BaseObject's interface
+ QDBusMessage msg = QDBusMessage::createMethodCall(con.baseService(), "/p1",
+ "local.BaseObject", "anotherMethod");
+ QDBusMessage reply = con.call(msg, QDBus::Block);
+ QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
+ QVERIFY(reply.arguments().count() == 0);
+}
+
+void tst_QDBusConnection::slotsWithLessParameters()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+
+ QDBusMessage signal = QDBusMessage::createSignal("/", "com.trolltech.TestCase",
+ "oneSignal");
+ signal << "one parameter";
+
+ signalsReceived = 0;
+ QVERIFY(con.connect(con.baseService(), signal.path(), signal.interface(),
+ signal.member(), this, SLOT(oneSlot())));
+ QVERIFY(con.send(signal));
+ QTest::qWait(100);
+ QCOMPARE(signalsReceived, 1);
+
+ // disconnect and try with a signature
+ signalsReceived = 0;
+ QVERIFY(con.disconnect(con.baseService(), signal.path(), signal.interface(),
+ signal.member(), this, SLOT(oneSlot())));
+ QVERIFY(con.connect(con.baseService(), signal.path(), signal.interface(),
+ signal.member(), "s", this, SLOT(oneSlot())));
+ QVERIFY(con.send(signal));
+ QTest::qWait(100);
+ QCOMPARE(signalsReceived, 1);
+}
+
+void tst_QDBusConnection::secondCallWithCallback()
+{
+ qDebug("Hello");
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusMessage msg = QDBusMessage::createMethodCall(con.baseService(), "/test", QString(),
+ "test0");
+ con.callWithCallback(msg, this, SLOT(exitLoop()), SLOT(secondCallWithCallback()));
+}
+
+void tst_QDBusConnection::nestedCallWithCallback()
+{
+ TestObject testObject;
+ QDBusConnection connection = QDBusConnection::sessionBus();
+ QVERIFY(connection.registerObject("/test", &testObject,
+ QDBusConnection::ExportAllContents));
+
+ QDBusMessage msg = QDBusMessage::createMethodCall(connection.baseService(), "/test", QString(),
+ "ThisFunctionDoesntExist");
+ signalsReceived = 0;
+
+ connection.callWithCallback(msg, this, SLOT(exitLoop()), SLOT(secondCallWithCallback()), 10);
+ QTestEventLoop::instance().enterLoop(15);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+ QCOMPARE(signalsReceived, 1);
+}
+
+class RaceConditionSignalWaiter : public QObject
+{
+ Q_OBJECT
+public:
+ int count;
+ RaceConditionSignalWaiter() : count (0) {}
+ virtual ~RaceConditionSignalWaiter() {}
+
+public slots:
+ void countUp() { ++count; emit done(); }
+signals:
+ void done();
+};
+
+void tst_QDBusConnection::serviceRegistrationRaceCondition()
+{
+ // There was a race condition in the updating of list of name owners in
+ // QtDBus. When the user connects to a signal coming from a given
+ // service, we must listen for NameOwnerChanged signals relevant to that
+ // name and update when the owner changes. However, it's possible that we
+ // receive in one chunk from the server both the NameOwnerChanged signal
+ // about the service and the signal we're interested in. Since QtDBus
+ // posts events in order to handle the incoming signals, the update
+ // happens too late.
+
+ const QString connectionName = "testConnectionName";
+ const QString serviceName = "org.example.SecondaryName";
+
+ QDBusConnection session = QDBusConnection::sessionBus();
+ QVERIFY(!session.interface()->isServiceRegistered(serviceName));
+
+ // connect to the signal:
+ RaceConditionSignalWaiter recv;
+ session.connect(serviceName, "/", "com.trolltech.TestCase", "oneSignal", &recv, SLOT(countUp()));
+
+ // create a secondary connection and register a name
+ QDBusConnection connection = QDBusConnection::connectToBus(QDBusConnection::SessionBus, connectionName);
+ QDBusConnection::disconnectFromBus(connectionName); // disconnection happens when "connection" goes out of scope
+ QVERIFY(connection.isConnected());
+ QVERIFY(connection.registerService(serviceName));
+
+ // send a signal
+ QDBusMessage msg = QDBusMessage::createSignal("/", "com.trolltech.TestCase", "oneSignal");
+ connection.send(msg);
+
+ // make a blocking call just to be sure that the buffer was flushed
+ msg = QDBusMessage::createMethodCall("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus",
+ "NameHasOwner");
+ msg << connectionName;
+ connection.call(msg); // ignore result
+
+ // Now here's the race condition (more info on task QTBUG-15651):
+ // the bus has most likely queued three signals for us to work on:
+ // 1) NameOwnerChanged for the connection we created above
+ // 2) NameOwnerChanged for the service we registered above
+ // 3) The "oneSignal" signal we sent
+ //
+ // We'll most likely receive all three in one go from the server. We must
+ // update the owner of serviceName before we start processing the
+ // "oneSignal" signal.
+
+ QTestEventLoop::instance().connect(&recv, SIGNAL(done()), SLOT(exitLoop()));
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+ QCOMPARE(recv.count, 1);
+}
+
+class VirtualObject: public QDBusVirtualObject
+{
+ Q_OBJECT
+public:
+ VirtualObject() :success(true) {}
+
+ QString introspect(const QString &path) const
+ {
+ return QString();
+ }
+
+ bool handleMessage(const QDBusMessage &message, const QDBusConnection &connection) {
+ ++callCount;
+ lastMessage = message;
+
+ if (success) {
+ QDBusMessage reply = message.createReply(replyArguments);
+ connection.send(reply);
+ }
+ emit messageReceived(message);
+ return success;
+ }
+signals:
+ void messageReceived(const QDBusMessage &message) const;
+
+public:
+ mutable QDBusMessage lastMessage;
+ QVariantList replyArguments;
+ mutable int callCount;
+ bool success;
+};
+
+
+void tst_QDBusConnection::registerVirtualObject()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+
+ QString path = "/tree/node";
+ QString childPath = "/tree/node/child";
+ QString childChildPath = "/tree/node/child/another";
+
+ {
+ // Register VirtualObject that handles child paths. Unregister by going out of scope.
+ VirtualObject obj;
+ QVERIFY(con.registerVirtualObject(path, &obj, QDBusConnection::SubPath));
+ QCOMPARE(con.objectRegisteredAt(path), static_cast<QObject *>(&obj));
+ QCOMPARE(con.objectRegisteredAt(childPath), static_cast<QObject *>(&obj));
+ QCOMPARE(con.objectRegisteredAt(childChildPath), static_cast<QObject *>(&obj));
+ }
+ QCOMPARE(con.objectRegisteredAt(path), static_cast<QObject *>(0));
+ QCOMPARE(con.objectRegisteredAt(childPath), static_cast<QObject *>(0));
+
+ {
+ // Register VirtualObject that handles child paths. Unregister by calling unregister.
+ VirtualObject obj;
+ QVERIFY(con.registerVirtualObject(path, &obj, QDBusConnection::SubPath));
+ QCOMPARE(con.objectRegisteredAt(path), static_cast<QObject *>(&obj));
+ QCOMPARE(con.objectRegisteredAt(childPath), static_cast<QObject *>(&obj));
+ QCOMPARE(con.objectRegisteredAt(childChildPath), static_cast<QObject *>(&obj));
+ con.unregisterObject(path);
+ QCOMPARE(con.objectRegisteredAt(path), static_cast<QObject *>(0));
+ QCOMPARE(con.objectRegisteredAt(childPath), static_cast<QObject *>(0));
+ }
+
+ {
+ // Single node has no sub path handling.
+ VirtualObject obj;
+ QVERIFY(con.registerVirtualObject(path, &obj, QDBusConnection::SingleNode));
+ QCOMPARE(con.objectRegisteredAt(path), static_cast<QObject *>(&obj));
+ QCOMPARE(con.objectRegisteredAt(childPath), static_cast<QObject *>(0));
+ }
+
+ {
+ // Register VirtualObject that handles child paths. Try to register an object on a child path of that.
+ VirtualObject obj;
+ QVERIFY(con.registerVirtualObject(path, &obj, QDBusConnection::SubPath));
+ QCOMPARE(con.objectRegisteredAt(path), static_cast<QObject *>(&obj));
+
+ QObject objectAtSubPath;
+ QVERIFY(!con.registerObject(path, &objectAtSubPath));
+ QVERIFY(!con.registerObject(childPath, &objectAtSubPath));
+ QCOMPARE(con.objectRegisteredAt(childPath), static_cast<QObject *>(&obj));
+ }
+
+ {
+ // Register object, make sure no SubPath handling object can be registered on a parent path.
+ QObject objectAtSubPath;
+ QVERIFY(con.registerObject(childPath, &objectAtSubPath));
+ QCOMPARE(con.objectRegisteredAt(childPath), static_cast<QObject *>(&objectAtSubPath));
+
+ VirtualObject obj;
+ QVERIFY(!con.registerVirtualObject(path, &obj, QDBusConnection::SubPath));
+ QCOMPARE(con.objectRegisteredAt(path), static_cast<QObject *>(0));
+ }
+ QCOMPARE(con.objectRegisteredAt(path), static_cast<QObject *>(0));
+ QCOMPARE(con.objectRegisteredAt(childPath), static_cast<QObject *>(0));
+ QCOMPARE(con.objectRegisteredAt(childChildPath), static_cast<QObject *>(0));
+}
+
+void tst_QDBusConnection::callVirtualObject()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+
+ QDBusConnection con2 = QDBusConnection::connectToBus(QDBusConnection::SessionBus, "con2");
+
+ QString path = "/tree/node";
+ QString childPath = "/tree/node/child";
+
+ // register one object at root:
+ VirtualObject obj;
+ QVERIFY(con.registerVirtualObject(path, &obj, QDBusConnection::SubPath));
+ obj.callCount = 0;
+ obj.replyArguments << 42 << 47u;
+
+ QObject::connect(&obj, SIGNAL(messageReceived(QDBusMessage)), &QTestEventLoop::instance(), SLOT(exitLoop()));
+
+ QDBusMessage message = QDBusMessage::createMethodCall(con.baseService(), path, QString(), "hello");
+ QDBusPendingCall reply = con2.asyncCall(message);
+
+ QTestEventLoop::instance().enterLoop(5);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(obj.callCount, 1);
+ QCOMPARE(obj.lastMessage.service(), con2.baseService());
+ QCOMPARE(obj.lastMessage.interface(), QString());
+ QCOMPARE(obj.lastMessage.path(), path);
+ reply.waitForFinished();
+ QVERIFY(reply.isValid());
+ QCOMPARE(reply.reply().arguments(), obj.replyArguments);
+
+ // call sub path
+ QDBusMessage childMessage = QDBusMessage::createMethodCall(con.baseService(), childPath, QString(), "helloChild");
+ obj.replyArguments.clear();
+ obj.replyArguments << 99;
+ QDBusPendingCall childReply = con2.asyncCall(childMessage);
+
+ QTestEventLoop::instance().enterLoop(5);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(obj.callCount, 2);
+ QCOMPARE(obj.lastMessage.service(), con2.baseService());
+ QCOMPARE(obj.lastMessage.interface(), QString());
+ QCOMPARE(obj.lastMessage.path(), childPath);
+
+ childReply.waitForFinished();
+ QVERIFY(childReply.isValid());
+ QCOMPARE(childReply.reply().arguments(), obj.replyArguments);
+
+ // let the call fail by having the virtual object return false
+ obj.success = false;
+ QDBusMessage errorMessage = QDBusMessage::createMethodCall(con.baseService(), childPath, QString(), "someFunc");
+ QDBusPendingCall errorReply = con2.asyncCall(errorMessage);
+
+ QTestEventLoop::instance().enterLoop(5);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+ QTest::qWait(100);
+ QVERIFY(errorReply.isError());
+ qDebug() << errorReply.reply().arguments();
+ QCOMPARE(errorReply.reply().errorName(), QString("org.freedesktop.DBus.Error.UnknownObject"));
+
+ QDBusConnection::disconnectFromBus("con2");
+}
+
+void tst_QDBusConnection::callVirtualObjectLocal()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+
+ QString path = "/tree/node";
+ QString childPath = "/tree/node/child";
+
+ // register one object at root:
+ VirtualObject obj;
+ QVERIFY(con.registerVirtualObject(path, &obj, QDBusConnection::SubPath));
+ obj.callCount = 0;
+ obj.replyArguments << 42 << 47u;
+
+ QDBusMessage message = QDBusMessage::createMethodCall(con.baseService(), path, QString(), "hello");
+ QDBusMessage reply = con.call(message, QDBus::Block, 5000);
+ QCOMPARE(obj.callCount, 1);
+ QCOMPARE(obj.lastMessage.service(), con.baseService());
+ QCOMPARE(obj.lastMessage.interface(), QString());
+ QCOMPARE(obj.lastMessage.path(), path);
+ QCOMPARE(obj.replyArguments, reply.arguments());
+
+ obj.replyArguments << QString("alien abduction");
+ QDBusMessage subPathMessage = QDBusMessage::createMethodCall(con.baseService(), childPath, QString(), "hello");
+ QDBusMessage subPathReply = con.call(subPathMessage , QDBus::Block, 5000);
+ QCOMPARE(obj.callCount, 2);
+ QCOMPARE(obj.lastMessage.service(), con.baseService());
+ QCOMPARE(obj.lastMessage.interface(), QString());
+ QCOMPARE(obj.lastMessage.path(), childPath);
+ QCOMPARE(obj.replyArguments, subPathReply.arguments());
+}
+
+QString MyObject::path;
+QTEST_MAIN(tst_QDBusConnection)
+
+#include "tst_qdbusconnection.moc"
+
diff --git a/tests/auto/dbus/qdbusconnection_no_bus/qdbusconnection_no_bus.pro b/tests/auto/dbus/qdbusconnection_no_bus/qdbusconnection_no_bus.pro
new file mode 100644
index 0000000000..86d08ea0d4
--- /dev/null
+++ b/tests/auto/dbus/qdbusconnection_no_bus/qdbusconnection_no_bus.pro
@@ -0,0 +1,9 @@
+load(qttest_p4)
+QT = core
+
+contains(QT_CONFIG,dbus): {
+ SOURCES += tst_qdbusconnection_no_bus.cpp
+ QT += dbus
+} else {
+ SOURCES += ../qdbusmarshall/dummy.cpp
+}
diff --git a/tests/auto/dbus/qdbusconnection_no_bus/tst_qdbusconnection_no_bus.cpp b/tests/auto/dbus/qdbusconnection_no_bus/tst_qdbusconnection_no_bus.cpp
new file mode 100644
index 0000000000..acd27386f5
--- /dev/null
+++ b/tests/auto/dbus/qdbusconnection_no_bus/tst_qdbusconnection_no_bus.cpp
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qcoreapplication.h>
+#include <qdebug.h>
+
+#include <QtTest/QtTest>
+#include <QtDBus/QtDBus>
+
+#include <stdlib.h>
+
+/* This test uses an appless main, to ensure that no D-Bus stuff is implicitly done
+ It also sets the magic "QT_SIMULATE_DBUS_LIBFAIL" env variable, that is only available
+ in developer builds. That env variable simulates a D-Bus library load fail.
+
+ In no case should the QDBus module crash because D-Bus libs couldn't be loaded */
+
+class tst_QDBusConnectionNoBus : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QDBusConnectionNoBus()
+ {
+ ::setenv("DBUS_SESSION_BUS_ADDRESS", "unix:abstract=/tmp/does_not_exist", 1);
+ ::setenv("QT_SIMULATE_DBUS_LIBFAIL", "1", 1);
+ }
+
+private slots:
+ void connectToBus();
+};
+
+
+void tst_QDBusConnectionNoBus::connectToBus()
+{
+ int argc = 0;
+ QCoreApplication app(argc, 0);
+
+ QDBusConnection con = QDBusConnection::sessionBus();
+
+ QVERIFY(true); // if we didn't crash here, the test passed :)
+}
+
+QTEST_APPLESS_MAIN(tst_QDBusConnectionNoBus)
+
+#include "tst_qdbusconnection_no_bus.moc"
+
diff --git a/tests/auto/dbus/qdbuscontext/.gitignore b/tests/auto/dbus/qdbuscontext/.gitignore
new file mode 100644
index 0000000000..64fff94d76
--- /dev/null
+++ b/tests/auto/dbus/qdbuscontext/.gitignore
@@ -0,0 +1 @@
+tst_qdbuscontext
diff --git a/tests/auto/dbus/qdbuscontext/qdbuscontext.pro b/tests/auto/dbus/qdbuscontext/qdbuscontext.pro
new file mode 100644
index 0000000000..ddd340c37e
--- /dev/null
+++ b/tests/auto/dbus/qdbuscontext/qdbuscontext.pro
@@ -0,0 +1,11 @@
+load(qttest_p4)
+QT = core
+
+contains(QT_CONFIG,dbus): {
+ SOURCES += tst_qdbuscontext.cpp
+ QT += dbus
+} else {
+ SOURCES += ../qdbusmarshall/dummy.cpp
+}
+
+
diff --git a/tests/auto/dbus/qdbuscontext/tst_qdbuscontext.cpp b/tests/auto/dbus/qdbuscontext/tst_qdbuscontext.cpp
new file mode 100644
index 0000000000..8041708151
--- /dev/null
+++ b/tests/auto/dbus/qdbuscontext/tst_qdbuscontext.cpp
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtDBus>
+#include <QtTest>
+
+const char errorName[] = "com.trolltech.tst_QDBusContext.Error";
+const char errorMsg[] = "A generic error";
+
+class TestObject: public QObject, protected QDBusContext
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "com.trolltech.tst_QDBusContext.TestObject")
+public:
+ inline TestObject(QObject *parent) : QObject(parent) { }
+public Q_SLOTS:
+ void generateError();
+};
+
+class tst_QDBusContext: public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+ void initTestCase();
+ void sendErrorReply();
+};
+
+void TestObject::generateError()
+{
+ sendErrorReply(errorName, errorMsg);
+}
+
+void tst_QDBusContext::initTestCase()
+{
+ TestObject *obj = new TestObject(this);
+ QVERIFY(QDBusConnection::sessionBus().isConnected());
+ QVERIFY(QDBusConnection::sessionBus().registerObject("/TestObject", obj,
+ QDBusConnection::ExportAllSlots));
+}
+
+void tst_QDBusContext::sendErrorReply()
+{
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), "/TestObject");
+ QVERIFY(iface.isValid());
+
+ QDBusReply<void> reply = iface.call("generateError");
+ QVERIFY(!reply.isValid());
+
+ const QDBusError &error = reply.error();
+ QCOMPARE(error.name(), QString::fromLatin1(errorName));
+ QCOMPARE(error.message(), QString::fromLatin1(errorMsg));
+}
+
+QTEST_MAIN(tst_QDBusContext)
+
+#include "tst_qdbuscontext.moc"
diff --git a/tests/auto/dbus/qdbusinterface/.gitignore b/tests/auto/dbus/qdbusinterface/.gitignore
new file mode 100644
index 0000000000..98313ecf04
--- /dev/null
+++ b/tests/auto/dbus/qdbusinterface/.gitignore
@@ -0,0 +1 @@
+tst_qdbusinterface
diff --git a/tests/auto/dbus/qdbusinterface/myobject.h b/tests/auto/dbus/qdbusinterface/myobject.h
new file mode 100644
index 0000000000..3959823a77
--- /dev/null
+++ b/tests/auto/dbus/qdbusinterface/myobject.h
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MYOBJECT_H
+#define MYOBJECT_H
+
+#include <QtCore/QObject>
+#include <QtDBus/QtDBus>
+
+Q_DECLARE_METATYPE(QVariantList)
+
+class MyObject: public QObject
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "com.trolltech.QtDBus.MyObject")
+ Q_CLASSINFO("D-Bus Introspection", ""
+" <interface name=\"com.trolltech.QtDBus.MyObject\" >\n"
+" <property access=\"readwrite\" type=\"i\" name=\"prop1\" />\n"
+" <property name=\"complexProp\" type=\"ai\" access=\"readwrite\">\n"
+" <annotation name=\"com.trolltech.QtDBus.QtTypeName\" value=\"QList&lt;int&gt;\"/>\n"
+" </property>\n"
+" <signal name=\"somethingHappened\" >\n"
+" <arg direction=\"out\" type=\"s\" />\n"
+" </signal>\n"
+" <method name=\"ping\" >\n"
+" <arg direction=\"in\" type=\"v\" name=\"ping\" />\n"
+" <arg direction=\"out\" type=\"v\" name=\"ping\" />\n"
+" </method>\n"
+" <method name=\"ping_invokable\" >\n"
+" <arg direction=\"in\" type=\"v\" name=\"ping_invokable\" />\n"
+" <arg direction=\"out\" type=\"v\" name=\"ping_invokable\" />\n"
+" </method>\n"
+" <method name=\"ping\" >\n"
+" <arg direction=\"in\" type=\"v\" name=\"ping1\" />\n"
+" <arg direction=\"in\" type=\"v\" name=\"ping2\" />\n"
+" <arg direction=\"out\" type=\"v\" name=\"pong1\" />\n"
+" <arg direction=\"out\" type=\"v\" name=\"pong2\" />\n"
+" </method>\n"
+" <method name=\"ping_invokable\" >\n"
+" <arg direction=\"in\" type=\"v\" name=\"ping1_invokable\" />\n"
+" <arg direction=\"in\" type=\"v\" name=\"ping2_invokable\" />\n"
+" <arg direction=\"out\" type=\"v\" name=\"pong1_invokable\" />\n"
+" <arg direction=\"out\" type=\"v\" name=\"pong2_invokable\" />\n"
+" </method>\n"
+" <method name=\"ping\" >\n"
+" <arg direction=\"in\" type=\"ai\" name=\"ping\" />\n"
+" <arg direction=\"out\" type=\"ai\" name=\"ping\" />\n"
+" <annotation name=\"com.trolltech.QtDBus.QtTypeName.In0\" value=\"QList&lt;int&gt;\"/>\n"
+" <annotation name=\"com.trolltech.QtDBus.QtTypeName.Out0\" value=\"QList&lt;int&gt;\"/>\n"
+" </method>\n"
+" <method name=\"ping_invokable\" >\n"
+" <arg direction=\"in\" type=\"ai\" name=\"ping_invokable\" />\n"
+" <arg direction=\"out\" type=\"ai\" name=\"ping_invokable\" />\n"
+" <annotation name=\"com.trolltech.QtDBus.QtTypeName.In0\" value=\"QList&lt;int&gt;\"/>\n"
+" <annotation name=\"com.trolltech.QtDBus.QtTypeName.Out0\" value=\"QList&lt;int&gt;\"/>\n"
+" </method>\n"
+" </interface>\n"
+ "")
+ Q_PROPERTY(int prop1 READ prop1 WRITE setProp1)
+ Q_PROPERTY(QList<int> complexProp READ complexProp WRITE setComplexProp)
+
+public:
+ static int callCount;
+ static QVariantList callArgs;
+ MyObject()
+ {
+ QObject *subObject = new QObject(this);
+ subObject->setObjectName("subObject");
+ }
+
+ int m_prop1;
+ int prop1() const
+ {
+ ++callCount;
+ return m_prop1;
+ }
+ void setProp1(int value)
+ {
+ ++callCount;
+ m_prop1 = value;
+ }
+
+ QList<int> m_complexProp;
+ QList<int> complexProp() const
+ {
+ ++callCount;
+ return m_complexProp;
+ }
+ void setComplexProp(const QList<int> &value)
+ {
+ ++callCount;
+ m_complexProp = value;
+ }
+
+ Q_INVOKABLE void ping_invokable(QDBusMessage msg)
+ {
+ QDBusConnection sender = QDBusConnection::sender();
+ if (!sender.isConnected())
+ exit(1);
+
+ ++callCount;
+ callArgs = msg.arguments();
+
+ msg.setDelayedReply(true);
+ if (!sender.send(msg.createReply(callArgs)))
+ exit(1);
+ }
+
+public slots:
+
+ void ping(QDBusMessage msg)
+ {
+ QDBusConnection sender = QDBusConnection::sender();
+ if (!sender.isConnected())
+ exit(1);
+
+ ++callCount;
+ callArgs = msg.arguments();
+
+ msg.setDelayedReply(true);
+ if (!sender.send(msg.createReply(callArgs)))
+ exit(1);
+ }
+};
+
+#endif // INTERFACE_H
diff --git a/tests/auto/dbus/qdbusinterface/qdbusinterface.pro b/tests/auto/dbus/qdbusinterface/qdbusinterface.pro
new file mode 100644
index 0000000000..0aca06ceb4
--- /dev/null
+++ b/tests/auto/dbus/qdbusinterface/qdbusinterface.pro
@@ -0,0 +1,11 @@
+load(qttest_p4)
+QT = core
+contains(QT_CONFIG,dbus): {
+ TEMPLATE = subdirs
+ CONFIG += ordered
+ SUBDIRS = qmyserver test
+} else {
+ SOURCES += ../qdbusmarshall/dummy.cpp
+}
+
+
diff --git a/tests/auto/dbus/qdbusinterface/qmyserver/qmyserver.cpp b/tests/auto/dbus/qdbusinterface/qmyserver/qmyserver.cpp
new file mode 100644
index 0000000000..dd15012222
--- /dev/null
+++ b/tests/auto/dbus/qdbusinterface/qmyserver/qmyserver.cpp
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/QtCore>
+#include <QtDBus/QtDBus>
+
+#include "../myobject.h"
+
+static const char serviceName[] = "com.trolltech.autotests.qmyserver";
+static const char objectPath[] = "/com/trolltech/qmyserver";
+//static const char *interfaceName = serviceName;
+
+int MyObject::callCount = 0;
+QVariantList MyObject::callArgs;
+
+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")
+ {
+ connect(this, SIGNAL(newConnection(const QDBusConnection&)), SLOT(handleConnection(const QDBusConnection&)));
+ }
+
+public slots:
+ QString address() const
+ {
+ return QDBusServer::address();
+ }
+
+ bool isConnected() const
+ {
+ return m_conn.isConnected();
+ }
+
+ void emitSignal(const QString &interface, const QString &name, const QString &arg)
+ {
+ QDBusMessage msg = QDBusMessage::createSignal("/", interface, name);
+ msg << arg;
+ m_conn.send(msg);
+ }
+
+ void reset()
+ {
+ MyObject::callCount = 0;
+ obj.m_complexProp.clear();
+ }
+
+ int callCount()
+ {
+ return MyObject::callCount;
+ }
+
+ QVariantList callArgs()
+ {
+ qDebug() << "callArgs" << MyObject::callArgs.count();
+ return MyObject::callArgs;
+ }
+
+ void setProp1(int val)
+ {
+ obj.m_prop1 = val;
+ }
+
+ int prop1()
+ {
+ return obj.m_prop1;
+ }
+
+ void setComplexProp(QList<int> val)
+ {
+ obj.m_complexProp = val;
+ }
+
+ QList<int> complexProp()
+ {
+ return obj.m_complexProp;
+ }
+
+
+private slots:
+ void handleConnection(const QDBusConnection& con)
+ {
+ m_conn = con;
+ m_conn.registerObject("/", &obj, QDBusConnection::ExportAllProperties
+ | QDBusConnection::ExportAllSlots
+ | QDBusConnection::ExportAllInvokables);
+ }
+
+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/dbus/qdbusinterface/qmyserver/qmyserver.pro b/tests/auto/dbus/qdbusinterface/qmyserver/qmyserver.pro
new file mode 100644
index 0000000000..f4fe02c4eb
--- /dev/null
+++ b/tests/auto/dbus/qdbusinterface/qmyserver/qmyserver.pro
@@ -0,0 +1,5 @@
+SOURCES = qmyserver.cpp
+HEADERS = ../myobject.h
+TARGET = qmyserver
+QT += dbus
+QT -= gui
diff --git a/tests/auto/dbus/qdbusinterface/test/test.pro b/tests/auto/dbus/qdbusinterface/test/test.pro
new file mode 100644
index 0000000000..2ef7a89c56
--- /dev/null
+++ b/tests/auto/dbus/qdbusinterface/test/test.pro
@@ -0,0 +1,6 @@
+load(qttest_p4)
+SOURCES += ../tst_qdbusinterface.cpp
+HEADERS += ../myobject.h
+TARGET = ../tst_qdbusinterface
+
+QT = core core-private dbus
diff --git a/tests/auto/dbus/qdbusinterface/tst_qdbusinterface.cpp b/tests/auto/dbus/qdbusinterface/tst_qdbusinterface.cpp
new file mode 100644
index 0000000000..9156818158
--- /dev/null
+++ b/tests/auto/dbus/qdbusinterface/tst_qdbusinterface.cpp
@@ -0,0 +1,1139 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+/* -*- C++ -*-
+ */
+
+#include <qcoreapplication.h>
+#include <qmetatype.h>
+#include <QtTest/QtTest>
+#include <QtCore/qvariant.h>
+#include <QtDBus/QtDBus>
+
+#include "../qdbusmarshall/common.h"
+#include "myobject.h"
+
+#define TEST_INTERFACE_NAME "com.trolltech.QtDBus.MyObject"
+#define TEST_SIGNAL_NAME "somethingHappened"
+
+static const char serviceName[] = "com.trolltech.autotests.qmyserver";
+static const char objectPath[] = "/com/trolltech/qmyserver";
+static const char *interfaceName = serviceName;
+
+int MyObject::callCount = 0;
+QVariantList MyObject::callArgs;
+
+class MyObjectUnknownType: public QObject
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "com.trolltech.QtDBus.MyObject")
+ Q_CLASSINFO("D-Bus Introspection", ""
+" <interface name=\"com.trolltech.QtDBus.MyObjectUnknownTypes\" >\n"
+" <property access=\"readwrite\" type=\"~\" name=\"prop1\" />\n"
+" <signal name=\"somethingHappened\" >\n"
+" <arg direction=\"out\" type=\"~\" />\n"
+" </signal>\n"
+" <method name=\"ping\" >\n"
+" <arg direction=\"in\" type=\"~\" name=\"ping\" />\n"
+" <arg direction=\"out\" type=\"~\" name=\"ping\" />\n"
+" </method>\n"
+" <method name=\"regularMethod\" />\n"
+" </interface>\n"
+ "")
+};
+
+class Spy: public QObject
+{
+ Q_OBJECT
+public:
+ QString received;
+ int count;
+
+ Spy() : count(0)
+ { }
+
+public slots:
+ void spySlot(const QString& arg)
+ {
+ received = arg;
+ ++count;
+ }
+};
+
+class DerivedFromQDBusInterface: public QDBusInterface
+{
+ Q_OBJECT
+public:
+ DerivedFromQDBusInterface()
+ : QDBusInterface("com.example.Test", "/")
+ {}
+
+public slots:
+ void method() {}
+};
+
+// helper function
+void emitSignal(const QString &interface, const QString &name, const QString &arg)
+{
+ QDBusMessage msg = QDBusMessage::createSignal("/", interface, name);
+ msg << arg;
+ QDBusConnection::sessionBus().send(msg);
+
+ QTest::qWait(1000);
+}
+
+void emitSignalPeer(const QString &interface, const QString &name, const QString &arg)
+{
+ QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "emitSignal");
+ req << interface;
+ req << name;
+ req << arg;
+ QDBusConnection::sessionBus().send(req);
+
+ QTest::qWait(1000);
+}
+
+int callCountPeer()
+{
+ QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "callCount");
+ QDBusMessage reply = QDBusConnection::sessionBus().call(req);
+ return reply.arguments().at(0).toInt();
+}
+
+QVariantList callArgsPeer()
+{
+ QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "callArgs");
+ QDBusMessage reply = QDBusConnection::sessionBus().call(req);
+ return qdbus_cast<QVariantList>(reply.arguments().at(0));
+}
+
+void setProp1Peer(int val)
+{
+ QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "setProp1");
+ req << val;
+ QDBusMessage reply = QDBusConnection::sessionBus().call(req);
+}
+
+int prop1Peer()
+{
+ QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "prop1");
+ QDBusMessage reply = QDBusConnection::sessionBus().call(req);
+ return reply.arguments().at(0).toInt();
+}
+
+void setComplexPropPeer(QList<int> val)
+{
+ QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "setComplexProp");
+ req << qVariantFromValue(val);
+ QDBusMessage reply = QDBusConnection::sessionBus().call(req);
+}
+
+QList<int> complexPropPeer()
+{
+ QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "complexProp");
+ QDBusMessage reply = QDBusConnection::sessionBus().call(req);
+ return qdbus_cast<QList<int> >(reply.arguments().at(0));
+}
+
+void resetPeer()
+{
+ QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "reset");
+ QDBusConnection::sessionBus().call(req);
+}
+
+class tst_QDBusInterface: public QObject
+{
+ Q_OBJECT
+ MyObject obj;
+
+public slots:
+ void testServiceOwnerChanged(const QString &service)
+ {
+ if (service == "com.example.Test")
+ QTestEventLoop::instance().exitLoop();
+ }
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ void notConnected();
+ void notValid();
+ void notValidDerived();
+ void invalidAfterServiceOwnerChanged();
+ void introspect();
+ void introspectUnknownTypes();
+ void introspectVirtualObject();
+ void callMethod();
+ void invokeMethod();
+ void invokeMethodWithReturn();
+ void invokeMethodWithMultiReturn();
+ void invokeMethodWithComplexReturn();
+
+ void introspectPeer();
+ void callMethodPeer();
+ void invokeMethodPeer();
+ void invokeMethodWithReturnPeer();
+ void invokeMethodWithMultiReturnPeer();
+ void invokeMethodWithComplexReturnPeer();
+
+ void signal();
+ void signalPeer();
+
+ void propertyRead();
+ void propertyWrite();
+ void complexPropertyRead();
+ void complexPropertyWrite();
+
+ void propertyReadPeer();
+ void propertyWritePeer();
+ void complexPropertyReadPeer();
+ void complexPropertyWritePeer();
+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_QDBusInterface::initTestCase()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+ QTest::qWait(500);
+
+ con.registerObject("/", &obj, QDBusConnection::ExportAllProperties
+ | QDBusConnection::ExportAllSlots
+ | QDBusConnection::ExportAllInvokables);
+
+ // 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 = con.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 = con.call(req2);
+ QVERIFY(rpl2.type() == QDBusMessage::ReplyMessage);
+ QVERIFY(rpl2.arguments().at(0).toBool());
+}
+
+void tst_QDBusInterface::cleanupTestCase()
+{
+ proc.close();
+ proc.kill();
+}
+
+void tst_QDBusInterface::notConnected()
+{
+ QDBusConnection connection("");
+ QVERIFY(!connection.isConnected());
+
+ QDBusInterface interface("org.freedesktop.DBus", "/", "org.freedesktop.DBus",
+ connection);
+
+ QVERIFY(!interface.isValid());
+ QVERIFY(!QMetaObject::invokeMethod(&interface, "ListNames", Qt::DirectConnection));
+}
+
+void tst_QDBusInterface::notValid()
+{
+ QDBusConnection connection("");
+ QVERIFY(!connection.isConnected());
+
+ QDBusInterface interface("com.example.Test", QString(), "org.example.Test",
+ connection);
+
+ QVERIFY(!interface.isValid());
+ QVERIFY(!QMetaObject::invokeMethod(&interface, "ListNames", Qt::DirectConnection));
+}
+
+void tst_QDBusInterface::notValidDerived()
+{
+ DerivedFromQDBusInterface c;
+ QVERIFY(!c.isValid());
+ QMetaObject::invokeMethod(&c, "method", Qt::DirectConnection);
+}
+
+void tst_QDBusInterface::invalidAfterServiceOwnerChanged()
+{
+ // this test is technically the same as tst_QDBusAbstractInterface::followSignal
+ QDBusConnection conn = QDBusConnection::sessionBus();
+ QDBusConnectionInterface *connIface = conn.interface();
+
+ QDBusInterface validInterface(conn.baseService(), "/");
+ QVERIFY(validInterface.isValid());
+ QDBusInterface invalidInterface("com.example.Test", "/");
+ QVERIFY(!invalidInterface.isValid());
+
+ QTestEventLoop::instance().connect(connIface, SIGNAL(serviceOwnerChanged(QString, QString, QString)),
+ SLOT(exitLoop()));
+ QVERIFY(connIface->registerService("com.example.Test") == QDBusConnectionInterface::ServiceRegistered);
+
+ QTestEventLoop::instance().enterLoop(5);
+
+ QVERIFY(!QTestEventLoop::instance().timeout());
+ QVERIFY(invalidInterface.isValid());
+}
+
+void tst_QDBusInterface::introspect()
+{
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ const QMetaObject *mo = iface.metaObject();
+
+ QCOMPARE(mo->methodCount() - mo->methodOffset(), 7);
+ QVERIFY(mo->indexOfSignal(TEST_SIGNAL_NAME "(QString)") != -1);
+
+ QCOMPARE(mo->propertyCount() - mo->propertyOffset(), 2);
+ QVERIFY(mo->indexOfProperty("prop1") != -1);
+ QVERIFY(mo->indexOfProperty("complexProp") != -1);
+}
+
+void tst_QDBusInterface::introspectUnknownTypes()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ MyObjectUnknownType obj;
+ con.registerObject("/unknownTypes", &obj, QDBusConnection::ExportAllContents);
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/unknownTypes"),
+ "com.trolltech.QtDBus.MyObjectUnknownTypes");
+
+ const QMetaObject *mo = iface.metaObject();
+ QVERIFY(mo->indexOfMethod("regularMethod()") != -1); // this is the control
+ QVERIFY(mo->indexOfMethod("somethingHappened(QDBusRawType<0x7e>*)") != -1);
+
+ QVERIFY(mo->indexOfMethod("ping(QDBusRawType<0x7e>*)") != -1);
+ int midx = mo->indexOfMethod("ping(QDBusRawType<0x7e>*)");
+ QCOMPARE(mo->method(midx).typeName(), "QDBusRawType<0x7e>*");
+
+ QVERIFY(mo->indexOfProperty("prop1") != -1);
+ int pidx = mo->indexOfProperty("prop1");
+ QCOMPARE(mo->property(pidx).typeName(), "QDBusRawType<0x7e>*");
+
+
+
+ QDBusMessage message = QDBusMessage::createMethodCall(con.baseService(), "/unknownTypes", "org.freedesktop.DBus.Introspectable", "Introspect");
+ QDBusMessage reply = con.call(message, QDBus::Block, 5000);
+ qDebug() << "REPL: " << reply.arguments();
+
+}
+
+
+class VirtualObject: public QDBusVirtualObject
+{
+ Q_OBJECT
+public:
+ VirtualObject() :success(true) {}
+
+ QString introspect(const QString &path) const {
+ if (path == "/some/path/superNode")
+ return "zitroneneis";
+ if (path == "/some/path/superNode/foo")
+ return " <interface name=\"com.trolltech.QtDBus.VirtualObject\">\n"
+ " <method name=\"klingeling\" />\n"
+ " </interface>\n" ;
+ return QString();
+ }
+
+ bool handleMessage(const QDBusMessage &message, const QDBusConnection &connection) {
+ ++callCount;
+ lastMessage = message;
+
+ if (success) {
+ QDBusMessage reply = message.createReply(replyArguments);
+ connection.send(reply);
+ }
+ emit messageReceived(message);
+ return success;
+ }
+signals:
+ void messageReceived(const QDBusMessage &message) const;
+
+public:
+ mutable QDBusMessage lastMessage;
+ QVariantList replyArguments;
+ mutable int callCount;
+ bool success;
+};
+
+void tst_QDBusInterface::introspectVirtualObject()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+ VirtualObject obj;
+
+ obj.success = false;
+
+ QString path = "/some/path/superNode";
+ QVERIFY(con.registerVirtualObject(path, &obj, QDBusConnection::SubPath));
+
+ QDBusMessage message = QDBusMessage::createMethodCall(con.baseService(), path, "org.freedesktop.DBus.Introspectable", "Introspect");
+ QDBusMessage reply = con.call(message, QDBus::Block, 5000);
+ QVERIFY(reply.arguments().at(0).toString().contains(
+ QRegExp("<node>.*zitroneneis.*<interface name=") ));
+
+ QDBusMessage message2 = QDBusMessage::createMethodCall(con.baseService(), path + "/foo", "org.freedesktop.DBus.Introspectable", "Introspect");
+ QDBusMessage reply2 = con.call(message2, QDBus::Block, 5000);
+ QVERIFY(reply2.arguments().at(0).toString().contains(
+ QRegExp("<node>.*<interface name=\"com.trolltech.QtDBus.VirtualObject\">"
+ ".*<method name=\"klingeling\" />\n"
+ ".*</interface>.*<interface name=") ));
+}
+
+void tst_QDBusInterface::callMethod()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ MyObject::callCount = 0;
+
+ // call a SLOT method
+ QDBusMessage reply = iface.call("ping", qVariantFromValue(QDBusVariant("foo")));
+ QCOMPARE(MyObject::callCount, 1);
+ QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
+
+ // verify what the callee received
+ QCOMPARE(MyObject::callArgs.count(), 1);
+ QVariant v = MyObject::callArgs.at(0);
+ QDBusVariant dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), QString("foo"));
+
+ // verify reply
+ QCOMPARE(reply.arguments().count(), 1);
+ v = reply.arguments().at(0);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), QString("foo"));
+
+ // call an INVOKABLE method
+ reply = iface.call("ping_invokable", qVariantFromValue(QDBusVariant("bar")));
+ QCOMPARE(MyObject::callCount, 2);
+ QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
+
+ // verify what the callee received
+ QCOMPARE(MyObject::callArgs.count(), 1);
+ v = MyObject::callArgs.at(0);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), QString("bar"));
+
+ // verify reply
+ QCOMPARE(reply.arguments().count(), 1);
+ v = reply.arguments().at(0);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), QString("bar"));
+}
+
+void tst_QDBusInterface::invokeMethod()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ MyObject::callCount = 0;
+
+ // make the SLOT call without a return type
+ QDBusVariant arg("foo");
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_ARG(QDBusVariant, arg)));
+ QCOMPARE(MyObject::callCount, 1);
+
+ // verify what the callee received
+ QCOMPARE(MyObject::callArgs.count(), 1);
+ QVariant v = MyObject::callArgs.at(0);
+ QDBusVariant dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), QString("foo"));
+
+ // make the INVOKABLE call without a return type
+ QDBusVariant arg2("bar");
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping_invokable", Q_ARG(QDBusVariant, arg2)));
+ QCOMPARE(MyObject::callCount, 2);
+
+ // verify what the callee received
+ QCOMPARE(MyObject::callArgs.count(), 1);
+ v = MyObject::callArgs.at(0);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), QString("bar"));
+}
+
+void tst_QDBusInterface::invokeMethodWithReturn()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ MyObject::callCount = 0;
+ QDBusVariant retArg;
+
+ // make the SLOT call without a return type
+ QDBusVariant arg("foo");
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_RETURN_ARG(QDBusVariant, retArg), Q_ARG(QDBusVariant, arg)));
+ QCOMPARE(MyObject::callCount, 1);
+
+ // verify what the callee received
+ QCOMPARE(MyObject::callArgs.count(), 1);
+ QVariant v = MyObject::callArgs.at(0);
+ QDBusVariant dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), arg.variant().toString());
+
+ // verify that we got the reply as expected
+ QCOMPARE(retArg.variant(), arg.variant());
+
+ // make the INVOKABLE call without a return type
+ QDBusVariant arg2("bar");
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping_invokable", Q_RETURN_ARG(QDBusVariant, retArg), Q_ARG(QDBusVariant, arg2)));
+ QCOMPARE(MyObject::callCount, 2);
+
+ // verify what the callee received
+ QCOMPARE(MyObject::callArgs.count(), 1);
+ v = MyObject::callArgs.at(0);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), arg2.variant().toString());
+
+ // verify that we got the reply as expected
+ QCOMPARE(retArg.variant(), arg2.variant());
+}
+
+void tst_QDBusInterface::invokeMethodWithMultiReturn()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ MyObject::callCount = 0;
+ QDBusVariant retArg, retArg2;
+
+ // make the SLOT call without a return type
+ QDBusVariant arg("foo"), arg2("bar");
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping",
+ Q_RETURN_ARG(QDBusVariant, retArg),
+ Q_ARG(QDBusVariant, arg),
+ Q_ARG(QDBusVariant, arg2),
+ Q_ARG(QDBusVariant&, retArg2)));
+ QCOMPARE(MyObject::callCount, 1);
+
+ // verify what the callee received
+ QCOMPARE(MyObject::callArgs.count(), 2);
+ QVariant v = MyObject::callArgs.at(0);
+ QDBusVariant dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), arg.variant().toString());
+
+ v = MyObject::callArgs.at(1);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), arg2.variant().toString());
+
+ // verify that we got the replies as expected
+ QCOMPARE(retArg.variant(), arg.variant());
+ QCOMPARE(retArg2.variant(), arg2.variant());
+
+ // make the INVOKABLE call without a return type
+ QDBusVariant arg3("hello"), arg4("world");
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping_invokable",
+ Q_RETURN_ARG(QDBusVariant, retArg),
+ Q_ARG(QDBusVariant, arg3),
+ Q_ARG(QDBusVariant, arg4),
+ Q_ARG(QDBusVariant&, retArg2)));
+ QCOMPARE(MyObject::callCount, 2);
+
+ // verify what the callee received
+ QCOMPARE(MyObject::callArgs.count(), 2);
+ v = MyObject::callArgs.at(0);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), arg3.variant().toString());
+
+ v = MyObject::callArgs.at(1);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), arg4.variant().toString());
+
+ // verify that we got the replies as expected
+ QCOMPARE(retArg.variant(), arg3.variant());
+ QCOMPARE(retArg2.variant(), arg4.variant());
+}
+
+void tst_QDBusInterface::invokeMethodWithComplexReturn()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ MyObject::callCount = 0;
+ QList<int> retArg;
+
+ // make the SLOT call without a return type
+ QList<int> arg = QList<int>() << 42 << -47;
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_RETURN_ARG(QList<int>, retArg), Q_ARG(QList<int>, arg)));
+ QCOMPARE(MyObject::callCount, 1);
+
+ // verify what the callee received
+ QCOMPARE(MyObject::callArgs.count(), 1);
+ QVariant v = MyObject::callArgs.at(0);
+ QCOMPARE(v.userType(), qMetaTypeId<QDBusArgument>());
+ QCOMPARE(qdbus_cast<QList<int> >(v), arg);
+
+ // verify that we got the reply as expected
+ QCOMPARE(retArg, arg);
+
+ // make the INVOKABLE call without a return type
+ QList<int> arg2 = QList<int>() << 24 << -74;
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_RETURN_ARG(QList<int>, retArg), Q_ARG(QList<int>, arg2)));
+ QCOMPARE(MyObject::callCount, 2);
+
+ // verify what the callee received
+ QCOMPARE(MyObject::callArgs.count(), 1);
+ v = MyObject::callArgs.at(0);
+ QCOMPARE(v.userType(), qMetaTypeId<QDBusArgument>());
+ QCOMPARE(qdbus_cast<QList<int> >(v), arg2);
+
+ // verify that we got the reply as expected
+ QCOMPARE(retArg, arg2);
+}
+
+void tst_QDBusInterface::introspectPeer()
+{
+ QDBusConnection con("peer");
+ QDBusInterface iface(QString(), QLatin1String("/"),
+ TEST_INTERFACE_NAME, con);
+
+ const QMetaObject *mo = iface.metaObject();
+
+ QCOMPARE(mo->methodCount() - mo->methodOffset(), 7);
+ QVERIFY(mo->indexOfSignal(TEST_SIGNAL_NAME "(QString)") != -1);
+
+ QCOMPARE(mo->propertyCount() - mo->propertyOffset(), 2);
+ QVERIFY(mo->indexOfProperty("prop1") != -1);
+ QVERIFY(mo->indexOfProperty("complexProp") != -1);
+}
+
+void tst_QDBusInterface::callMethodPeer()
+{
+ QDBusConnection con("peer");
+ QDBusInterface iface(QString(), QLatin1String("/"),
+ TEST_INTERFACE_NAME, con);
+
+ resetPeer();
+
+ // call a SLOT method
+ QDBusMessage reply = iface.call("ping", qVariantFromValue(QDBusVariant("foo")));
+ QCOMPARE(callCountPeer(), 1);
+ QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
+
+ // verify what the callee received
+ QVariantList callArgs = callArgsPeer();
+ QCOMPARE(callArgs.count(), 1);
+ QVariant v = callArgs.at(0);
+ QDBusVariant dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), QString("foo"));
+
+ // verify reply
+ QCOMPARE(reply.arguments().count(), 1);
+ v = reply.arguments().at(0);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), QString("foo"));
+
+ // call an INVOKABLE method
+ reply = iface.call("ping_invokable", qVariantFromValue(QDBusVariant("bar")));
+ QCOMPARE(callCountPeer(), 2);
+ QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
+
+ // verify what the callee received
+ callArgs = callArgsPeer();
+ QCOMPARE(callArgs.count(), 1);
+ v = callArgs.at(0);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), QString("bar"));
+
+ // verify reply
+ QCOMPARE(reply.arguments().count(), 1);
+ v = reply.arguments().at(0);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), QString("bar"));
+}
+
+void tst_QDBusInterface::invokeMethodPeer()
+{
+ QDBusConnection con("peer");
+ QDBusInterface iface(QString(), QLatin1String("/"),
+ TEST_INTERFACE_NAME, con);
+
+ resetPeer();
+
+ // make the SLOT call without a return type
+ QDBusVariant arg("foo");
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_ARG(QDBusVariant, arg)));
+ QCOMPARE(callCountPeer(), 1);
+
+ // verify what the callee received
+ QVariantList callArgs = callArgsPeer();
+ QCOMPARE(callArgs.count(), 1);
+ QVariant v = callArgs.at(0);
+ QDBusVariant dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), QString("foo"));
+
+ // make the INVOKABLE call without a return type
+ QDBusVariant arg2("bar");
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping_invokable", Q_ARG(QDBusVariant, arg2)));
+ QCOMPARE(callCountPeer(), 2);
+
+ // verify what the callee received
+ callArgs = callArgsPeer();
+ QCOMPARE(callArgs.count(), 1);
+ v = callArgs.at(0);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), QString("bar"));
+}
+
+void tst_QDBusInterface::invokeMethodWithReturnPeer()
+{
+ QDBusConnection con("peer");
+ QDBusInterface iface(QString(), QLatin1String("/"),
+ TEST_INTERFACE_NAME, con);
+
+ resetPeer();
+ QDBusVariant retArg;
+
+ // make the SLOT call without a return type
+ QDBusVariant arg("foo");
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_RETURN_ARG(QDBusVariant, retArg), Q_ARG(QDBusVariant, arg)));
+ QCOMPARE(callCountPeer(), 1);
+
+ // verify what the callee received
+ QVariantList callArgs = callArgsPeer();
+ QCOMPARE(callArgs.count(), 1);
+ QVariant v = callArgs.at(0);
+ QDBusVariant dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), arg.variant().toString());
+
+ // verify that we got the reply as expected
+ QCOMPARE(retArg.variant(), arg.variant());
+
+ // make the INVOKABLE call without a return type
+ QDBusVariant arg2("bar");
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping_invokable", Q_RETURN_ARG(QDBusVariant, retArg), Q_ARG(QDBusVariant, arg2)));
+ QCOMPARE(callCountPeer(), 2);
+
+ // verify what the callee received
+ callArgs = callArgsPeer();
+ QCOMPARE(callArgs.count(), 1);
+ v = callArgs.at(0);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), arg2.variant().toString());
+
+ // verify that we got the reply as expected
+ QCOMPARE(retArg.variant(), arg2.variant());
+}
+
+void tst_QDBusInterface::invokeMethodWithMultiReturnPeer()
+{
+ QDBusConnection con("peer");
+ QDBusInterface iface(QString(), QLatin1String("/"),
+ TEST_INTERFACE_NAME, con);
+
+ resetPeer();
+ QDBusVariant retArg, retArg2;
+
+ // make the SLOT call without a return type
+ QDBusVariant arg("foo"), arg2("bar");
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping",
+ Q_RETURN_ARG(QDBusVariant, retArg),
+ Q_ARG(QDBusVariant, arg),
+ Q_ARG(QDBusVariant, arg2),
+ Q_ARG(QDBusVariant&, retArg2)));
+ QCOMPARE(callCountPeer(), 1);
+
+ // verify what the callee received
+ QVariantList callArgs = callArgsPeer();
+ QCOMPARE(callArgs.count(), 2);
+ QVariant v = callArgs.at(0);
+ QDBusVariant dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), arg.variant().toString());
+
+ v = callArgs.at(1);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), arg2.variant().toString());
+
+ // verify that we got the replies as expected
+ QCOMPARE(retArg.variant(), arg.variant());
+ QCOMPARE(retArg2.variant(), arg2.variant());
+
+ // make the INVOKABLE call without a return type
+ QDBusVariant arg3("hello"), arg4("world");
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping_invokable",
+ Q_RETURN_ARG(QDBusVariant, retArg),
+ Q_ARG(QDBusVariant, arg3),
+ Q_ARG(QDBusVariant, arg4),
+ Q_ARG(QDBusVariant&, retArg2)));
+ QCOMPARE(callCountPeer(), 2);
+
+ // verify what the callee received
+ callArgs = callArgsPeer();
+ QCOMPARE(callArgs.count(), 2);
+ v = callArgs.at(0);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), arg3.variant().toString());
+
+ v = callArgs.at(1);
+ dv = qdbus_cast<QDBusVariant>(v);
+ QCOMPARE(dv.variant().type(), QVariant::String);
+ QCOMPARE(dv.variant().toString(), arg4.variant().toString());
+
+ // verify that we got the replies as expected
+ QCOMPARE(retArg.variant(), arg3.variant());
+ QCOMPARE(retArg2.variant(), arg4.variant());
+}
+
+void tst_QDBusInterface::invokeMethodWithComplexReturnPeer()
+{
+ QDBusConnection con("peer");
+ QDBusInterface iface(QString(), QLatin1String("/"),
+ TEST_INTERFACE_NAME, con);
+
+ resetPeer();
+ QList<int> retArg;
+
+ // make the SLOT call without a return type
+ QList<int> arg = QList<int>() << 42 << -47;
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_RETURN_ARG(QList<int>, retArg), Q_ARG(QList<int>, arg)));
+ QCOMPARE(callCountPeer(), 1);
+
+ // verify what the callee received
+ QVariantList callArgs = callArgsPeer();
+ QCOMPARE(callArgs.count(), 1);
+ QVariant v = callArgs.at(0);
+ QCOMPARE(v.userType(), qMetaTypeId<QDBusArgument>());
+ QCOMPARE(qdbus_cast<QList<int> >(v), arg);
+
+ // verify that we got the reply as expected
+ QCOMPARE(retArg, arg);
+
+ // make the INVOKABLE call without a return type
+ QList<int> arg2 = QList<int>() << 24 << -74;
+ QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_RETURN_ARG(QList<int>, retArg), Q_ARG(QList<int>, arg2)));
+ QCOMPARE(callCountPeer(), 2);
+
+ // verify what the callee received
+ callArgs = callArgsPeer();
+ QCOMPARE(callArgs.count(), 1);
+ v = callArgs.at(0);
+ QCOMPARE(v.userType(), qMetaTypeId<QDBusArgument>());
+ QCOMPARE(qdbus_cast<QList<int> >(v), arg2);
+
+ // verify that we got the reply as expected
+ QCOMPARE(retArg, arg2);
+}
+
+void tst_QDBusInterface::signal()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ QString arg = "So long and thanks for all the fish";
+ {
+ Spy spy;
+ spy.connect(&iface, SIGNAL(somethingHappened(QString)), SLOT(spySlot(QString)));
+
+ emitSignal(TEST_INTERFACE_NAME, TEST_SIGNAL_NAME, arg);
+ QCOMPARE(spy.count, 1);
+ QCOMPARE(spy.received, arg);
+ }
+
+ QDBusInterface iface2(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+ {
+ Spy spy;
+ spy.connect(&iface, SIGNAL(somethingHappened(QString)), SLOT(spySlot(QString)));
+ spy.connect(&iface2, SIGNAL(somethingHappened(QString)), SLOT(spySlot(QString)));
+
+ emitSignal(TEST_INTERFACE_NAME, TEST_SIGNAL_NAME, arg);
+ QCOMPARE(spy.count, 2);
+ QCOMPARE(spy.received, arg);
+ }
+
+ {
+ Spy spy, spy2;
+ spy.connect(&iface, SIGNAL(somethingHappened(QString)), SLOT(spySlot(QString)));
+ spy2.connect(&iface2, SIGNAL(somethingHappened(QString)), SLOT(spySlot(QString)));
+
+ emitSignal(TEST_INTERFACE_NAME, TEST_SIGNAL_NAME, arg);
+ QCOMPARE(spy.count, 1);
+ QCOMPARE(spy.received, arg);
+ QCOMPARE(spy2.count, 1);
+ QCOMPARE(spy2.received, arg);
+ }
+}
+
+void tst_QDBusInterface::signalPeer()
+{
+ QDBusConnection con("peer");
+ QDBusInterface iface(QString(), QLatin1String("/"),
+ TEST_INTERFACE_NAME, con);
+
+ QString arg = "So long and thanks for all the fish";
+ {
+ Spy spy;
+ spy.connect(&iface, SIGNAL(somethingHappened(QString)), SLOT(spySlot(QString)));
+
+ emitSignalPeer(TEST_INTERFACE_NAME, TEST_SIGNAL_NAME, arg);
+ QCOMPARE(spy.count, 1);
+ QCOMPARE(spy.received, arg);
+ }
+
+ QDBusInterface iface2(QString(), QLatin1String("/"),
+ TEST_INTERFACE_NAME, con);
+ {
+ Spy spy;
+ spy.connect(&iface, SIGNAL(somethingHappened(QString)), SLOT(spySlot(QString)));
+ spy.connect(&iface2, SIGNAL(somethingHappened(QString)), SLOT(spySlot(QString)));
+
+ emitSignalPeer(TEST_INTERFACE_NAME, TEST_SIGNAL_NAME, arg);
+ QCOMPARE(spy.count, 2);
+ QCOMPARE(spy.received, arg);
+ }
+
+ {
+ Spy spy, spy2;
+ spy.connect(&iface, SIGNAL(somethingHappened(QString)), SLOT(spySlot(QString)));
+ spy2.connect(&iface2, SIGNAL(somethingHappened(QString)), SLOT(spySlot(QString)));
+
+ emitSignalPeer(TEST_INTERFACE_NAME, TEST_SIGNAL_NAME, arg);
+ QCOMPARE(spy.count, 1);
+ QCOMPARE(spy.received, arg);
+ QCOMPARE(spy2.count, 1);
+ QCOMPARE(spy2.received, arg);
+ }
+}
+
+void tst_QDBusInterface::propertyRead()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ int arg = obj.m_prop1 = 42;
+ MyObject::callCount = 0;
+
+ QVariant v = iface.property("prop1");
+ QVERIFY(v.isValid());
+ QCOMPARE(v.userType(), int(QVariant::Int));
+ QCOMPARE(v.toInt(), arg);
+ QCOMPARE(MyObject::callCount, 1);
+}
+
+void tst_QDBusInterface::propertyWrite()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ int arg = 42;
+ obj.m_prop1 = 0;
+ MyObject::callCount = 0;
+
+ QVERIFY(iface.setProperty("prop1", arg));
+ QCOMPARE(MyObject::callCount, 1);
+ QCOMPARE(obj.m_prop1, arg);
+}
+
+void tst_QDBusInterface::complexPropertyRead()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ QList<int> arg = obj.m_complexProp = QList<int>() << 42 << -47;
+ MyObject::callCount = 0;
+
+ QVariant v = iface.property("complexProp");
+ QVERIFY(v.isValid());
+ QCOMPARE(v.userType(), qMetaTypeId<QList<int> >());
+ QCOMPARE(v.value<QList<int> >(), arg);
+ QCOMPARE(MyObject::callCount, 1);
+}
+
+void tst_QDBusInterface::complexPropertyWrite()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+
+ QList<int> arg = QList<int>() << -47 << 42;
+ obj.m_complexProp.clear();
+ MyObject::callCount = 0;
+
+ QVERIFY(iface.setProperty("complexProp", qVariantFromValue(arg)));
+ QCOMPARE(MyObject::callCount, 1);
+ QCOMPARE(obj.m_complexProp, arg);
+}
+
+void tst_QDBusInterface::propertyReadPeer()
+{
+ QDBusConnection con("peer");
+ QDBusInterface iface(QString(), QLatin1String("/"),
+ TEST_INTERFACE_NAME, con);
+
+ resetPeer();
+ int arg = 42;
+ setProp1Peer(42);
+
+ QVariant v = iface.property("prop1");
+ QVERIFY(v.isValid());
+ QCOMPARE(v.userType(), int(QVariant::Int));
+ QCOMPARE(v.toInt(), arg);
+ QCOMPARE(callCountPeer(), 1);
+}
+
+void tst_QDBusInterface::propertyWritePeer()
+{
+ QDBusConnection con("peer");
+ QDBusInterface iface(QString(), QLatin1String("/"),
+ TEST_INTERFACE_NAME, con);
+
+ resetPeer();
+ int arg = 42;
+ setProp1Peer(0);
+
+ QVERIFY(iface.setProperty("prop1", arg));
+ QCOMPARE(callCountPeer(), 1);
+ QCOMPARE(prop1Peer(), arg);
+}
+
+void tst_QDBusInterface::complexPropertyReadPeer()
+{
+ QDBusConnection con("peer");
+ QDBusInterface iface(QString(), QLatin1String("/"),
+ TEST_INTERFACE_NAME, con);
+
+ resetPeer();
+ QList<int> arg = QList<int>() << 42 << -47;
+ setComplexPropPeer(arg);
+
+ QVariant v = iface.property("complexProp");
+ QVERIFY(v.isValid());
+ QCOMPARE(v.userType(), qMetaTypeId<QList<int> >());
+ QCOMPARE(v.value<QList<int> >(), arg);
+ QCOMPARE(callCountPeer(), 1);
+}
+
+void tst_QDBusInterface::complexPropertyWritePeer()
+{
+ QDBusConnection con("peer");
+ QDBusInterface iface(QString(), QLatin1String("/"),
+ TEST_INTERFACE_NAME, con);
+
+ resetPeer();
+ QList<int> arg = QList<int>() << -47 << 42;
+
+ QVERIFY(iface.setProperty("complexProp", qVariantFromValue(arg)));
+ QCOMPARE(callCountPeer(), 1);
+ QCOMPARE(complexPropPeer(), arg);
+}
+
+QTEST_MAIN(tst_QDBusInterface)
+
+#include "tst_qdbusinterface.moc"
diff --git a/tests/auto/dbus/qdbuslocalcalls/.gitignore b/tests/auto/dbus/qdbuslocalcalls/.gitignore
new file mode 100644
index 0000000000..15bdea69c0
--- /dev/null
+++ b/tests/auto/dbus/qdbuslocalcalls/.gitignore
@@ -0,0 +1 @@
+tst_qdbuslocalcalls
diff --git a/tests/auto/dbus/qdbuslocalcalls/qdbuslocalcalls.pro b/tests/auto/dbus/qdbuslocalcalls/qdbuslocalcalls.pro
new file mode 100644
index 0000000000..cef3ddcb28
--- /dev/null
+++ b/tests/auto/dbus/qdbuslocalcalls/qdbuslocalcalls.pro
@@ -0,0 +1,11 @@
+load(qttest_p4)
+QT = core
+
+contains(QT_CONFIG,dbus): {
+ SOURCES += tst_qdbuslocalcalls.cpp
+ QT += dbus
+} else {
+ SOURCES += ../qdbusmarshall/dummy.cpp
+}
+
+
diff --git a/tests/auto/dbus/qdbuslocalcalls/tst_qdbuslocalcalls.cpp b/tests/auto/dbus/qdbuslocalcalls/tst_qdbuslocalcalls.cpp
new file mode 100644
index 0000000000..c89fd7dde4
--- /dev/null
+++ b/tests/auto/dbus/qdbuslocalcalls/tst_qdbuslocalcalls.cpp
@@ -0,0 +1,277 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/QObject>
+#include <QtCore/QVariant>
+#include <QtCore/QList>
+#include <QtCore/QVector>
+#include <QtTest/QtTest>
+#include <QtDBus>
+
+Q_DECLARE_METATYPE(QVariant)
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QVector<int>)
+
+class tst_QDBusLocalCalls: public QObject
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "local.tst_QDBusLocalCalls")
+
+ QDBusConnection conn;
+public:
+ tst_QDBusLocalCalls();
+
+public Q_SLOTS:
+ Q_SCRIPTABLE int echo(int value)
+ { return value; }
+
+ Q_SCRIPTABLE QString echo(const QString &value)
+ { return value; }
+
+ Q_SCRIPTABLE QDBusVariant echo(const QDBusVariant &value)
+ { return value; }
+
+ Q_SCRIPTABLE QVector<int> echo(const QVector<int> &value)
+ { return value; }
+
+ Q_SCRIPTABLE QString echo2(const QStringList &list, QString &out)
+ { out = list[1]; return list[0]; }
+
+ Q_SCRIPTABLE void delayed(const QDBusMessage &msg)
+ { msg.setDelayedReply(true); }
+
+protected Q_SLOTS:
+ void replyReceived(QDBusPendingCallWatcher *watcher);
+
+private Q_SLOTS:
+ void initTestCase();
+ void makeInvalidCalls();
+ void makeCalls_data();
+ void makeCalls();
+ void makeCallsVariant_data();
+ void makeCallsVariant();
+ void makeCallsTwoRets();
+ void makeCallsComplex();
+ void makeDelayedCalls();
+ void asyncReplySignal();
+
+private:
+ QVariantList asyncReplyArgs;
+ QDBusMessage doCall(const QDBusMessage &call);
+};
+
+tst_QDBusLocalCalls::tst_QDBusLocalCalls()
+ : conn(QDBusConnection::sessionBus())
+{
+}
+
+QDBusMessage tst_QDBusLocalCalls::doCall(const QDBusMessage &call)
+{
+ QFETCH_GLOBAL(bool, useAsync);
+ if (useAsync) {
+ QDBusPendingCall ac = conn.asyncCall(call);
+ ac.waitForFinished();
+ return ac.reply();
+ } else {
+ return conn.call(call);
+ }
+}
+
+void tst_QDBusLocalCalls::replyReceived(QDBusPendingCallWatcher *watcher)
+{
+ asyncReplyArgs = watcher->reply().arguments();
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_QDBusLocalCalls::initTestCase()
+{
+ QVERIFY(conn.isConnected());
+ QVERIFY(conn.registerObject("/", this, QDBusConnection::ExportScriptableSlots));
+
+ QTest::addColumn<bool>("useAsync");
+ QTest::newRow("sync") << false;
+ QTest::newRow("async") << true;
+}
+
+void tst_QDBusLocalCalls::makeCalls_data()
+{
+ QTest::addColumn<QVariant>("value");
+ QTest::newRow("int") << QVariant(42);
+ QTest::newRow("string") << QVariant("Hello, world");
+}
+
+void tst_QDBusLocalCalls::makeCallsVariant_data()
+{
+ makeCalls_data();
+}
+
+void tst_QDBusLocalCalls::makeInvalidCalls()
+{
+ {
+ QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(),
+ "/", QString(), "echo");
+ QDBusMessage replyMsg = doCall(callMsg);
+ QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ErrorMessage));
+
+ QDBusError error(replyMsg);
+ QCOMPARE(int(error.type()), int(QDBusError::UnknownMethod));
+ }
+
+ {
+ QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(),
+ "/no_object", QString(), "echo");
+ QDBusMessage replyMsg = doCall(callMsg);
+ QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ErrorMessage));
+
+ QDBusError error(replyMsg);
+ QCOMPARE(int(error.type()), int(QDBusError::UnknownObject));
+ }
+}
+
+void tst_QDBusLocalCalls::makeCalls()
+{
+ QFETCH(QVariant, value);
+ QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(),
+ "/", QString(), "echo");
+ callMsg << value;
+ QDBusMessage replyMsg = doCall(callMsg);
+
+ QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ReplyMessage));
+
+ QVariantList replyArgs = replyMsg.arguments();
+ QCOMPARE(replyArgs.count(), 1);
+ QCOMPARE(replyArgs.at(0), value);
+}
+
+void tst_QDBusLocalCalls::makeCallsVariant()
+{
+ QFETCH(QVariant, value);
+ QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(),
+ "/", QString(), "echo");
+ callMsg << qVariantFromValue(QDBusVariant(value));
+ QDBusMessage replyMsg = doCall(callMsg);
+
+ QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ReplyMessage));
+
+ QVariantList replyArgs = replyMsg.arguments();
+ QCOMPARE(replyArgs.count(), 1);
+
+ const QVariant &reply = replyArgs.at(0);
+ QCOMPARE(reply.userType(), qMetaTypeId<QDBusVariant>());
+ QCOMPARE(qvariant_cast<QDBusVariant>(reply).variant(), value);
+}
+
+void tst_QDBusLocalCalls::makeCallsTwoRets()
+{
+ QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(),
+ "/", QString(), "echo2");
+ callMsg << (QStringList() << "One" << "Two");
+ QDBusMessage replyMsg = doCall(callMsg);
+
+ QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ReplyMessage));
+
+ QVariantList replyArgs = replyMsg.arguments();
+ QCOMPARE(replyArgs.count(), 2);
+ QCOMPARE(replyArgs.at(0).toString(), QString::fromLatin1("One"));
+ QCOMPARE(replyArgs.at(1).toString(), QString::fromLatin1("Two"));
+}
+
+void tst_QDBusLocalCalls::makeCallsComplex()
+{
+ qDBusRegisterMetaType<QList<int> >();
+ qDBusRegisterMetaType<QVector<int> >();
+
+ QList<int> value;
+ value << 1 << -42 << 47;
+ QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(),
+ "/", QString(), "echo");
+ callMsg << qVariantFromValue(value);
+ QDBusMessage replyMsg = doCall(callMsg);
+
+ QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ReplyMessage));
+
+ QVariantList replyArgs = replyMsg.arguments();
+ QCOMPARE(replyArgs.count(), 1);
+ const QVariant &reply = replyArgs.at(0);
+ QCOMPARE(reply.userType(), qMetaTypeId<QDBusArgument>());
+ QCOMPARE(qdbus_cast<QList<int> >(reply), value);
+}
+
+void tst_QDBusLocalCalls::makeDelayedCalls()
+{
+ QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(),
+ "/", QString(), "delayed");
+ QTest::ignoreMessage(QtWarningMsg, "QDBusConnection: cannot call local method 'delayed' at object / (with signature '') on blocking mode");
+ QDBusMessage replyMsg = doCall(callMsg);
+ QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ErrorMessage));
+
+ QDBusError error(replyMsg);
+ QCOMPARE(int(error.type()), int(QDBusError::InternalError));
+}
+
+void tst_QDBusLocalCalls::asyncReplySignal()
+{
+ QFETCH_GLOBAL(bool, useAsync);
+ if (!useAsync)
+ return; // this test only works in async mode
+
+ QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(),
+ "/", QString(), "echo");
+ callMsg << "Hello World";
+ QDBusPendingCall ac = conn.asyncCall(callMsg);
+ if (ac.isFinished())
+ QSKIP("Test ignored: the local-loop async call is already finished", SkipAll);
+
+ QDBusPendingCallWatcher watch(ac);
+ connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
+ SLOT(replyReceived(QDBusPendingCallWatcher*)));
+
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QVERIFY(ac.isFinished());
+ QVERIFY(!ac.isError());
+
+ QVERIFY(!asyncReplyArgs.isEmpty());
+ QCOMPARE(asyncReplyArgs.at(0).toString(), QString("Hello World"));
+}
+
+QTEST_MAIN(tst_QDBusLocalCalls)
+#include "tst_qdbuslocalcalls.moc"
diff --git a/tests/auto/dbus/qdbusmarshall/.gitignore b/tests/auto/dbus/qdbusmarshall/.gitignore
new file mode 100644
index 0000000000..d227388521
--- /dev/null
+++ b/tests/auto/dbus/qdbusmarshall/.gitignore
@@ -0,0 +1,2 @@
+tst_qdbusmarshall
+qpong/qpong
diff --git a/tests/auto/dbus/qdbusmarshall/common.h b/tests/auto/dbus/qdbusmarshall/common.h
new file mode 100644
index 0000000000..35fe5f1bf7
--- /dev/null
+++ b/tests/auto/dbus/qdbusmarshall/common.h
@@ -0,0 +1,755 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <math.h> // isnan
+#include <qvariant.h>
+
+#ifdef Q_OS_UNIX
+# include <private/qcore_unix_p.h>
+
+static bool compareFileDescriptors(int fd1, int fd2)
+{
+ QT_STATBUF st1, st2;
+ if (QT_FSTAT(fd1, &st1) == -1 || QT_FSTAT(fd2, &st2) == -1) {
+ perror("fstat");
+ return false;
+ }
+
+ return (st1.st_dev == st2.st_dev) && (st1.st_ino == st2.st_ino);
+}
+#endif
+
+Q_DECLARE_METATYPE(QVariant)
+Q_DECLARE_METATYPE(QList<bool>)
+Q_DECLARE_METATYPE(QList<short>)
+Q_DECLARE_METATYPE(QList<ushort>)
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QList<uint>)
+Q_DECLARE_METATYPE(QList<qlonglong>)
+Q_DECLARE_METATYPE(QList<qulonglong>)
+Q_DECLARE_METATYPE(QList<double>)
+Q_DECLARE_METATYPE(QList<QDBusVariant>)
+Q_DECLARE_METATYPE(QList<QDateTime>)
+
+Q_DECLARE_METATYPE(QList<QByteArray>)
+Q_DECLARE_METATYPE(QList<QVariantList>)
+Q_DECLARE_METATYPE(QList<QStringList>)
+Q_DECLARE_METATYPE(QList<QList<bool> >)
+Q_DECLARE_METATYPE(QList<QList<short> >)
+Q_DECLARE_METATYPE(QList<QList<ushort> >)
+Q_DECLARE_METATYPE(QList<QList<int> >)
+Q_DECLARE_METATYPE(QList<QList<uint> >)
+Q_DECLARE_METATYPE(QList<QList<qlonglong> >)
+Q_DECLARE_METATYPE(QList<QList<qulonglong> >)
+Q_DECLARE_METATYPE(QList<QList<double> >)
+Q_DECLARE_METATYPE(QList<QList<QDBusObjectPath> >)
+Q_DECLARE_METATYPE(QList<QList<QDBusSignature> >)
+
+typedef QMap<int, QString> IntStringMap;
+typedef QMap<QString, QString> StringStringMap;
+typedef QMap<QDBusObjectPath, QString> ObjectPathStringMap;
+typedef QHash<qlonglong, QDateTime> LLDateTimeMap;
+typedef QHash<QDBusSignature, QString> SignatureStringMap;
+Q_DECLARE_METATYPE(IntStringMap)
+Q_DECLARE_METATYPE(StringStringMap)
+Q_DECLARE_METATYPE(ObjectPathStringMap)
+Q_DECLARE_METATYPE(LLDateTimeMap)
+Q_DECLARE_METATYPE(SignatureStringMap)
+
+static bool compare(const QDBusUnixFileDescriptor &t1, const QDBusUnixFileDescriptor &t2)
+{
+ int fd1 = t1.fileDescriptor();
+ int fd2 = t2.fileDescriptor();
+ if ((fd1 == -1 || fd2 == -1) && fd1 != fd2) {
+ // one is valid, the other isn't
+ return false;
+ }
+
+#ifdef Q_OS_UNIX
+ return compareFileDescriptors(fd1, fd2);
+#else
+ return true;
+#endif
+}
+
+struct MyStruct
+{
+ int i;
+ QString s;
+
+ inline bool operator==(const MyStruct &other) const
+ { return i == other.i && s == other.s; }
+};
+Q_DECLARE_METATYPE(MyStruct)
+
+QDBusArgument &operator<<(QDBusArgument &arg, const MyStruct &ms)
+{
+ arg.beginStructure();
+ arg << ms.i << ms.s;
+ arg.endStructure();
+ return arg;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &arg, MyStruct &ms)
+{
+ arg.beginStructure();
+ arg >> ms.i >> ms.s;
+ arg.endStructure();
+ return arg;
+}
+
+struct MyVariantMapStruct
+{
+ QString s;
+ QVariantMap map;
+
+ inline bool operator==(const MyVariantMapStruct &other) const
+ { return s == other.s && map == other.map; }
+};
+Q_DECLARE_METATYPE(MyVariantMapStruct)
+Q_DECLARE_METATYPE(QList<MyVariantMapStruct>)
+
+QDBusArgument &operator<<(QDBusArgument &arg, const MyVariantMapStruct &ms)
+{
+ arg.beginStructure();
+ arg << ms.s << ms.map;
+ arg.endStructure();
+ return arg;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &arg, MyVariantMapStruct &ms)
+{
+ arg.beginStructure();
+ arg >> ms.s >> ms.map;
+ arg.endStructure();
+ return arg;
+}
+
+struct MyFileDescriptorStruct
+{
+ QDBusUnixFileDescriptor fd;
+
+ inline bool operator==(const MyFileDescriptorStruct &other) const
+ { return compare(fd, other.fd); }
+};
+Q_DECLARE_METATYPE(MyFileDescriptorStruct)
+Q_DECLARE_METATYPE(QList<MyFileDescriptorStruct>)
+
+QDBusArgument &operator<<(QDBusArgument &arg, const MyFileDescriptorStruct &ms)
+{
+ arg.beginStructure();
+ arg << ms.fd;
+ arg.endStructure();
+ return arg;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &arg, MyFileDescriptorStruct &ms)
+{
+ arg.beginStructure();
+ arg >> ms.fd;
+ arg.endStructure();
+ return arg;
+}
+
+
+void commonInit()
+{
+ qDBusRegisterMetaType<QList<QDateTime> >();
+ qDBusRegisterMetaType<QList<QStringList> >();
+ qDBusRegisterMetaType<QList<QByteArray> >();
+ qDBusRegisterMetaType<QList<QList<bool> > >();
+ qDBusRegisterMetaType<QList<QList<short> > >();
+ qDBusRegisterMetaType<QList<QList<ushort> > >();
+ qDBusRegisterMetaType<QList<QList<int> > >();
+ qDBusRegisterMetaType<QList<QList<uint> > >();
+ qDBusRegisterMetaType<QList<QList<qlonglong> > >();
+ qDBusRegisterMetaType<QList<QList<qulonglong> > >();
+ qDBusRegisterMetaType<QList<QList<double> > >();
+ qDBusRegisterMetaType<QList<QList<QDBusObjectPath> > >();
+ qDBusRegisterMetaType<QList<QList<QDBusSignature> > >();
+ qDBusRegisterMetaType<QList<QVariantList> >();
+
+ qDBusRegisterMetaType<QMap<int, QString> >();
+ qDBusRegisterMetaType<QMap<QString, QString> >();
+ qDBusRegisterMetaType<QMap<QDBusObjectPath, QString> >();
+ qDBusRegisterMetaType<QHash<qlonglong, QDateTime> >();
+ qDBusRegisterMetaType<QHash<QDBusSignature, QString> >();
+
+ qDBusRegisterMetaType<MyStruct>();
+ qDBusRegisterMetaType<MyVariantMapStruct>();
+ qDBusRegisterMetaType<QList<MyVariantMapStruct> >();
+ qDBusRegisterMetaType<MyFileDescriptorStruct>();
+ qDBusRegisterMetaType<QList<MyFileDescriptorStruct> >();
+}
+#ifdef USE_PRIVATE_CODE
+#include "private/qdbusintrospection_p.h"
+
+// just to make it easier:
+typedef QDBusIntrospection::Interfaces InterfaceMap;
+typedef QDBusIntrospection::Objects ObjectMap;
+typedef QDBusIntrospection::Arguments ArgumentList;
+typedef QDBusIntrospection::Annotations AnnotationsMap;
+typedef QDBusIntrospection::Methods MethodMap;
+typedef QDBusIntrospection::Signals SignalMap;
+typedef QDBusIntrospection::Properties PropertyMap;
+
+Q_DECLARE_METATYPE(QDBusIntrospection::Method)
+Q_DECLARE_METATYPE(QDBusIntrospection::Signal)
+Q_DECLARE_METATYPE(QDBusIntrospection::Property)
+Q_DECLARE_METATYPE(MethodMap)
+Q_DECLARE_METATYPE(SignalMap)
+Q_DECLARE_METATYPE(PropertyMap)
+
+inline QDBusIntrospection::Argument arg(const char* type, const char *name = 0)
+{
+ QDBusIntrospection::Argument retval;
+ retval.type = QLatin1String(type);
+ retval.name = QLatin1String(name);
+ return retval;
+}
+
+template<typename T>
+inline QMap<QString, T>& operator<<(QMap<QString, T>& map, const T& m)
+{ map.insertMulti(m.name, m); return map; }
+
+inline const char* mapName(const MethodMap&)
+{ return "MethodMap"; }
+
+inline const char* mapName(const SignalMap&)
+{ return "SignalMap"; }
+
+inline const char* mapName(const PropertyMap&)
+{ return "PropertyMap"; }
+
+QString printable(const QDBusIntrospection::Method& m)
+{
+ QString result = "method " + m.name + "(";
+ foreach (QDBusIntrospection::Argument arg, m.inputArgs)
+ result += QString("in %1 %2, ")
+ .arg(arg.type, arg.name);
+ foreach (QDBusIntrospection::Argument arg, m.outputArgs)
+ result += QString("out %1 %2, ")
+ .arg(arg.type, arg.name);
+ AnnotationsMap::const_iterator it = m.annotations.begin();
+ for ( ; it != m.annotations.end(); ++it)
+ result += QString("%1 \"%2\", ").arg(it.key()).arg(it.value());
+
+ result += ")";
+ return result;
+}
+
+QString printable(const QDBusIntrospection::Signal& s)
+{
+ QString result = "signal " + s.name + "(";
+ foreach (QDBusIntrospection::Argument arg, s.outputArgs)
+ result += QString("out %1 %2, ")
+ .arg(arg.type, arg.name);
+ AnnotationsMap::const_iterator it = s.annotations.begin();
+ for ( ; it != s.annotations.end(); ++it)
+ result += QString("%1 \"%2\", ").arg(it.key()).arg(it.value());
+
+ result += ")";
+ return result;
+}
+
+QString printable(const QDBusIntrospection::Property& p)
+{
+ QString result;
+ if (p.access == QDBusIntrospection::Property::Read)
+ result = "property read %1 %2, ";
+ else if (p.access == QDBusIntrospection::Property::Write)
+ result = "property write %1 %2, ";
+ else
+ result = "property readwrite %1 %2, ";
+ result = result.arg(p.type, p.name);
+
+ AnnotationsMap::const_iterator it = p.annotations.begin();
+ for ( ; it != p.annotations.end(); ++it)
+ result += QString("%1 \"%2\", ").arg(it.key()).arg(it.value());
+
+ return result;
+}
+
+template<typename T>
+char* printableMap(const QMap<QString, T>& map)
+{
+ QString contents = "\n";
+ typename QMap<QString, T>::const_iterator it = map.begin();
+ for ( ; it != map.end(); ++it) {
+ if (it.key() != it.value().name)
+ contents += it.value().name + ":";
+ contents += printable(it.value());
+ contents += ";\n";
+ }
+
+ QString result("%1(size = %2): {%3}");
+ return qstrdup(qPrintable(result
+ .arg(mapName(map))
+ .arg(map.size())
+ .arg(contents)));
+}
+
+QT_BEGIN_NAMESPACE
+namespace QTest {
+ template<>
+ inline char* toString(const MethodMap& map)
+ {
+ return printableMap(map);
+ }
+
+ template<>
+ inline char* toString(const SignalMap& map)
+ {
+ return printableMap(map);
+ }
+
+ template<>
+ inline char* toString(const PropertyMap& map)
+ {
+ return printableMap(map);
+ }
+}
+QT_END_NAMESPACE
+
+#endif
+
+//bool compare(const QVariantList &l1, const QVariantList &l2);
+//bool compare(const QVariantMap &m1, const QVariantMap &m2);
+template<typename T>
+bool compare(const T &t1, const T &t2)
+{ return t1 == t2; }
+
+template<>
+bool compare(const QVariant &v1, const QVariant &v2);
+
+bool compare(double d1, double d2)
+{
+ if (isnan(d1) && isnan(d2))
+ return true;
+ return d1 == d2;
+}
+
+template<>
+bool compare(const QString &s1, const QString &s2)
+{
+ if (s1.isEmpty() && s2.isEmpty())
+ return true; // regardless of whether one of them is null
+ return s1 == s2;
+}
+
+template<>
+bool compare(const QByteArray &ba1, const QByteArray &ba2)
+{
+ if (ba1.isEmpty() && ba2.isEmpty())
+ return true; // regardless of whether one of them is null
+ return ba1 == ba2;
+}
+
+template<>
+bool compare(const QDBusVariant &s1, const QDBusVariant &s2)
+{
+ return compare(s1.variant(), s2.variant());
+}
+
+template<typename T>
+bool compare(const QList<T> &l1, const QList<T> &l2)
+{
+ if (l1.count() != l2.count())
+ return false;
+
+ typename QList<T>::ConstIterator it1 = l1.constBegin();
+ typename QList<T>::ConstIterator it2 = l2.constBegin();
+ typename QList<T>::ConstIterator end = l1.constEnd();
+ for ( ; it1 != end; ++it1, ++it2)
+ if (!compare(*it1, *it2))
+ return false;
+ return true;
+}
+
+template<typename Key, typename T>
+bool compare(const QMap<Key, T> &m1, const QMap<Key, T> &m2)
+{
+ if (m1.count() != m2.size())
+ return false;
+ typename QMap<Key, T>::ConstIterator i1 = m1.constBegin();
+ typename QMap<Key, T>::ConstIterator end = m1.constEnd();
+ for ( ; i1 != end; ++i1) {
+ typename QMap<Key, T>::ConstIterator i2 = m2.find(i1.key());
+ if (i2 == m2.constEnd())
+ return false;
+ if (!compare(*i1, *i2))
+ return false;
+ }
+ return true;
+}
+
+template<typename Key, typename T>
+bool compare(const QHash<Key, T> &m1, const QHash<Key, T> &m2)
+{
+ if (m1.count() != m2.size())
+ return false;
+ typename QHash<Key, T>::ConstIterator i1 = m1.constBegin();
+ typename QHash<Key, T>::ConstIterator end = m1.constEnd();
+ for ( ; i1 != end; ++i1) {
+ typename QHash<Key, T>::ConstIterator i2 = m2.find(i1.key());
+ if (i2 == m2.constEnd())
+ return false;
+ if (!compare(*i1, *i2))
+ return false;
+ }
+ return true;
+}
+
+template<typename T>
+inline bool compare(const QDBusArgument &arg, const QVariant &v2, T * = 0)
+{
+ return compare(qdbus_cast<T>(arg), qvariant_cast<T>(v2));
+}
+
+bool compareToArgument(const QDBusArgument &arg, const QVariant &v2)
+{
+ if (arg.currentSignature() != QDBusMetaType::typeToSignature(v2.userType()))
+ return false;
+
+ // try to demarshall the arg according to v2
+ switch (v2.userType())
+ {
+ case QVariant::Bool:
+ return compare<bool>(arg, v2);
+ case QMetaType::UChar:
+ return compare<uchar>(arg, v2);
+ case QMetaType::Short:
+ return compare<short>(arg, v2);
+ case QMetaType::UShort:
+ return compare<ushort>(arg, v2);
+ case QVariant::Int:
+ return compare<int>(arg, v2);
+ case QVariant::UInt:
+ return compare<uint>(arg, v2);
+ case QVariant::LongLong:
+ return compare<qlonglong>(arg, v2);
+ case QVariant::ULongLong:
+ return compare<qulonglong>(arg, v2);
+ case QVariant::Double:
+ return compare<double>(arg, v2);
+ case QVariant::String:
+ return compare<QString>(arg, v2);
+ case QVariant::ByteArray:
+ return compare<QByteArray>(arg, v2);
+ case QVariant::List:
+ return compare<QVariantList>(arg, v2);
+ case QVariant::Map:
+ return compare<QVariantMap>(arg, v2);
+ case QVariant::Point:
+ return compare<QPoint>(arg, v2);
+ case QVariant::PointF:
+ return compare<QPointF>(arg, v2);
+ case QVariant::Size:
+ return compare<QSize>(arg, v2);
+ case QVariant::SizeF:
+ return compare<QSizeF>(arg, v2);
+ case QVariant::Line:
+ return compare<QLine>(arg, v2);
+ case QVariant::LineF:
+ return compare<QLineF>(arg, v2);
+ case QVariant::Rect:
+ return compare<QRect>(arg, v2);
+ case QVariant::RectF:
+ return compare<QRectF>(arg, v2);
+ case QVariant::Date:
+ return compare<QDate>(arg, v2);
+ case QVariant::Time:
+ return compare<QTime>(arg, v2);
+ case QVariant::DateTime:
+ return compare<QDateTime>(arg, v2);
+ default:
+ register int id = v2.userType();
+ if (id == qMetaTypeId<QDBusObjectPath>())
+ return compare<QDBusObjectPath>(arg, v2);
+ else if (id == qMetaTypeId<QDBusSignature>())
+ return compare<QDBusSignature>(arg, v2);
+ else if (id == qMetaTypeId<QDBusVariant>())
+ return compare<QDBusVariant>(arg, v2);
+ else if (id == qMetaTypeId<QList<bool> >())
+ return compare<QList<bool> >(arg, v2);
+ else if (id == qMetaTypeId<QList<short> >())
+ return compare<QList<short> >(arg, v2);
+ else if (id == qMetaTypeId<QList<ushort> >())
+ return compare<QList<ushort> >(arg, v2);
+ else if (id == qMetaTypeId<QList<int> >())
+ return compare<QList<int> >(arg, v2);
+ else if (id == qMetaTypeId<QList<uint> >())
+ return compare<QList<uint> >(arg, v2);
+ else if (id == qMetaTypeId<QList<qlonglong> >())
+ return compare<QList<qlonglong> >(arg, v2);
+ else if (id == qMetaTypeId<QList<qulonglong> >())
+ return compare<QList<qulonglong> >(arg, v2);
+ else if (id == qMetaTypeId<QList<double> >())
+ return compare<QList<double> >(arg, v2);
+ else if (id == qMetaTypeId<QList<QDBusObjectPath> >())
+ return compare<QList<QDBusObjectPath> >(arg, v2);
+ else if (id == qMetaTypeId<QList<QDBusSignature> >())
+ return compare<QList<QDBusSignature> >(arg, v2);
+ else if (id == qMetaTypeId<QList<QDBusUnixFileDescriptor> >())
+ return compare<QList<QDBusUnixFileDescriptor> >(arg, v2);
+ else if (id == qMetaTypeId<QList<QDateTime> >())
+ return compare<QList<QDateTime> >(arg, v2);
+
+ else if (id == qMetaTypeId<QMap<int, QString> >())
+ return compare<QMap<int, QString> >(arg, v2);
+ else if (id == qMetaTypeId<QMap<QString, QString> >())
+ return compare<QMap<QString, QString> >(arg, v2);
+ else if (id == qMetaTypeId<QMap<QDBusObjectPath, QString> >())
+ return compare<QMap<QDBusObjectPath, QString> >(arg, v2);
+ else if (id == qMetaTypeId<QHash<qlonglong, QDateTime> >())
+ return compare<QHash<qlonglong, QDateTime> >(arg, v2);
+ else if (id == qMetaTypeId<QHash<QDBusSignature, QString> >())
+ return compare<QHash<QDBusSignature, QString> >(arg, v2);
+
+ else if (id == qMetaTypeId<QList<QByteArray> >())
+ return compare<QList<QByteArray> >(arg, v2);
+ else if (id == qMetaTypeId<QList<QList<bool> > >())
+ return compare<QList<QList<bool> > >(arg, v2);
+ else if (id == qMetaTypeId<QList<QList<short> > >())
+ return compare<QList<QList<short> > >(arg, v2);
+ else if (id == qMetaTypeId<QList<QList<ushort> > >())
+ return compare<QList<QList<ushort> > >(arg, v2);
+ else if (id == qMetaTypeId<QList<QList<int> > >())
+ return compare<QList<QList<int> > >(arg, v2);
+ else if (id == qMetaTypeId<QList<QList<uint> > >())
+ return compare<QList<QList<uint> > >(arg, v2);
+ else if (id == qMetaTypeId<QList<QList<qlonglong> > >())
+ return compare<QList<QList<qlonglong> > >(arg, v2);
+ else if (id == qMetaTypeId<QList<QList<qulonglong> > >())
+ return compare<QList<QList<qulonglong> > >(arg, v2);
+ else if (id == qMetaTypeId<QList<QList<double> > >())
+ return compare<QList<QList<double> > >(arg, v2);
+ else if (id == qMetaTypeId<QList<QStringList> >())
+ return compare<QList<QStringList> >(arg, v2);
+ else if (id == qMetaTypeId<QList<QVariantList> >())
+ return compare<QList<QVariantList> >(arg, v2);
+
+ else if (id == qMetaTypeId<MyStruct>())
+ return compare<MyStruct>(arg, v2);
+
+ else if (id == qMetaTypeId<MyVariantMapStruct>())
+ return compare<MyVariantMapStruct>(arg, v2);
+ else if (id == qMetaTypeId<QList<MyVariantMapStruct> >())
+ return compare<QList<MyVariantMapStruct> >(arg, v2);
+ else if (id == qMetaTypeId<MyFileDescriptorStruct>())
+ return compare<MyFileDescriptorStruct>(arg, v2);
+ else if (id == qMetaTypeId<QList<MyFileDescriptorStruct> >())
+ return compare<QList<MyFileDescriptorStruct> >(arg, v2);
+ }
+
+ qWarning() << "Unexpected QVariant type" << v2.userType()
+ << QByteArray(QDBusMetaType::typeToSignature(v2.userType()))
+ << QVariant::typeToName(QVariant::Type(v2.userType()));
+ return false;
+}
+
+template<> bool compare(const QVariant &v1, const QVariant &v2)
+{
+ // v1 is the one that came from the network
+ // v2 is the one that we sent
+
+ if (v1.userType() == qMetaTypeId<QDBusArgument>())
+ // this argument has been left un-demarshalled
+ return compareToArgument(qvariant_cast<QDBusArgument>(v1), v2);
+
+ if (v1.userType() != v2.userType())
+ return false;
+
+ int id = v1.userType();
+ if (id == QVariant::List)
+ return compare(v1.toList(), v2.toList());
+
+ else if (id == QVariant::Map)
+ return compare(v1.toMap(), v2.toMap());
+
+ else if (id == QVariant::String)
+ return compare(v1.toString(), v2.toString());
+
+ else if (id == QVariant::ByteArray)
+ return compare(v1.toByteArray(), v2.toByteArray());
+
+ else if (id < int(QVariant::UserType)) // yes, v1.type()
+ // QVariant can compare
+ return v1 == v2;
+
+ else if (id == QMetaType::UChar)
+ return qvariant_cast<uchar>(v1) == qvariant_cast<uchar>(v2);
+
+ else if (id == QMetaType::Short)
+ return qvariant_cast<short>(v1) == qvariant_cast<short>(v2);
+
+ else if (id == QMetaType::UShort)
+ return qvariant_cast<ushort>(v1) == qvariant_cast<ushort>(v2);
+
+ else if (id == qMetaTypeId<QDBusObjectPath>())
+ return qvariant_cast<QDBusObjectPath>(v1).path() == qvariant_cast<QDBusObjectPath>(v2).path();
+
+ else if (id == qMetaTypeId<QDBusSignature>())
+ return qvariant_cast<QDBusSignature>(v1).signature() == qvariant_cast<QDBusSignature>(v2).signature();
+
+ else if (id == qMetaTypeId<QDBusUnixFileDescriptor>())
+ return compare(qvariant_cast<QDBusUnixFileDescriptor>(v1), qvariant_cast<QDBusUnixFileDescriptor>(v2));
+
+ else if (id == qMetaTypeId<QDBusVariant>())
+ return compare(qvariant_cast<QDBusVariant>(v1).variant(), qvariant_cast<QDBusVariant>(v2).variant());
+
+ else if (id == qMetaTypeId<QVariant>())
+ return compare(qvariant_cast<QVariant>(v1), qvariant_cast<QVariant>(v2));
+
+ else if (id == qMetaTypeId<QList<bool> >())
+ return qvariant_cast<QList<bool> >(v1) == qvariant_cast<QList<bool> >(v2);
+
+ else if (id == qMetaTypeId<QList<short> >())
+ return qvariant_cast<QList<short> >(v1) == qvariant_cast<QList<short> >(v2);
+
+ else if (id == qMetaTypeId<QList<ushort> >())
+ return qvariant_cast<QList<ushort> >(v1) == qvariant_cast<QList<ushort> >(v2);
+
+ else if (id == qMetaTypeId<QList<int> >())
+ return qvariant_cast<QList<int> >(v1) == qvariant_cast<QList<int> >(v2);
+
+ else if (id == qMetaTypeId<QList<uint> >())
+ return qvariant_cast<QList<uint> >(v1) == qvariant_cast<QList<uint> >(v2);
+
+ else if (id == qMetaTypeId<QList<qlonglong> >())
+ return qvariant_cast<QList<qlonglong> >(v1) == qvariant_cast<QList<qlonglong> >(v2);
+
+ else if (id == qMetaTypeId<QList<qulonglong> >())
+ return qvariant_cast<QList<qulonglong> >(v2) == qvariant_cast<QList<qulonglong> >(v2);
+
+ else if (id == qMetaTypeId<QList<double> >())
+ return compare(qvariant_cast<QList<double> >(v1), qvariant_cast<QList<double> >(v2));
+
+ else if (id == qMetaTypeId<QVariant>())
+ return compare(qvariant_cast<QVariant>(v1), qvariant_cast<QVariant>(v2));
+
+ else if (id == qMetaTypeId<QList<QList<bool> > >())
+ return qvariant_cast<QList<QList<bool> > >(v1) == qvariant_cast<QList<QList<bool> > >(v2);
+
+ else if (id == qMetaTypeId<QList<QList<short> > >())
+ return qvariant_cast<QList<QList<short> > >(v1) == qvariant_cast<QList<QList<short> > >(v2);
+
+ else if (id == qMetaTypeId<QList<QList<ushort> > >())
+ return qvariant_cast<QList<QList<ushort> > >(v1) == qvariant_cast<QList<QList<ushort> > >(v2);
+
+ else if (id == qMetaTypeId<QList<QList<int> > >())
+ return qvariant_cast<QList<QList<int> > >(v1) == qvariant_cast<QList<QList<int> > >(v2);
+
+ else if (id == qMetaTypeId<QList<QList<uint> > >())
+ return qvariant_cast<QList<QList<uint> > >(v1) == qvariant_cast<QList<QList<uint> > >(v2);
+
+ else if (id == qMetaTypeId<QList<QList<qlonglong> > >())
+ return qvariant_cast<QList<QList<qlonglong> > >(v1) == qvariant_cast<QList<QList<qlonglong> > >(v2);
+
+ else if (id == qMetaTypeId<QList<QList<qulonglong> > >())
+ return qvariant_cast<QList<QList<qulonglong> > >(v1) == qvariant_cast<QList<QList<qulonglong> > >(v2);
+
+ else if (id == qMetaTypeId<QList<QList<double> > >())
+ return compare(qvariant_cast<QList<QList<double> > >(v1), qvariant_cast<QList<QList<double> > >(v2));
+
+ else if (id == qMetaTypeId<QList<QStringList> >())
+ return qvariant_cast<QList<QStringList> >(v1) == qvariant_cast<QList<QStringList> >(v2);
+
+ else if (id == qMetaTypeId<QList<QByteArray> >())
+ return qvariant_cast<QList<QByteArray> >(v1) == qvariant_cast<QList<QByteArray> >(v2);
+
+ else if (id == qMetaTypeId<QList<QVariantList> >())
+ return compare(qvariant_cast<QList<QVariantList> >(v1), qvariant_cast<QList<QVariantList> >(v2));
+
+ else if (id == qMetaTypeId<QMap<int, QString> >())
+ return compare(qvariant_cast<QMap<int, QString> >(v1), qvariant_cast<QMap<int, QString> >(v2));
+
+ else if (id == qMetaTypeId<QMap<QString, QString> >()) // ssmap
+ return compare(qvariant_cast<QMap<QString, QString> >(v1), qvariant_cast<QMap<QString, QString> >(v2));
+
+ else if (id == qMetaTypeId<QMap<QDBusObjectPath, QString> >())
+ return compare(qvariant_cast<QMap<QDBusObjectPath, QString> >(v1), qvariant_cast<QMap<QDBusObjectPath, QString> >(v2));
+
+ else if (id == qMetaTypeId<QHash<qlonglong, QDateTime> >()) // lldtmap
+ return compare(qvariant_cast<QHash<qint64, QDateTime> >(v1), qvariant_cast<QHash<qint64, QDateTime> >(v2));
+
+ else if (id == qMetaTypeId<QHash<QDBusSignature, QString> >())
+ return compare(qvariant_cast<QHash<QDBusSignature, QString> >(v1), qvariant_cast<QHash<QDBusSignature, QString> >(v2));
+
+ else if (id == qMetaTypeId<MyStruct>()) // (is)
+ return qvariant_cast<MyStruct>(v1) == qvariant_cast<MyStruct>(v2);
+
+ else {
+ qWarning() << "Please write a comparison case for type" << v1.typeName();
+ return false; // unknown type
+ }
+}
+
+#if 0
+bool compare(const QVariantList &l1, const QVariantList &l2)
+{
+ if (l1.count() != l2.size())
+ return false;
+ QVariantList::ConstIterator i1 = l1.constBegin();
+ QVariantList::ConstIterator i2 = l2.constBegin();
+ QVariantList::ConstIterator end = l1.constEnd();
+ for ( ; i1 != end; ++i1, ++i2) {
+ if (!compare(*i1, *i2))
+ return false;
+ }
+ return true;
+}
+
+bool compare(const QVariantMap &m1, const QVariantMap &m2)
+{
+ if (m1.count() != m2.size())
+ return false;
+ QVariantMap::ConstIterator i1 = m1.constBegin();
+ QVariantMap::ConstIterator end = m1.constEnd();
+ for ( ; i1 != end; ++i1) {
+ QVariantMap::ConstIterator i2 = m2.find(i1.key());
+ if (i2 == m2.constEnd())
+ return false;
+ if (!compare(*i1, *i2))
+ return false;
+ }
+ return true;
+}
+#endif
diff --git a/tests/auto/dbus/qdbusmarshall/dummy.cpp b/tests/auto/dbus/qdbusmarshall/dummy.cpp
new file mode 100644
index 0000000000..0b403c3585
--- /dev/null
+++ b/tests/auto/dbus/qdbusmarshall/dummy.cpp
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtTest/QtTest>
+
+QTEST_NOOP_MAIN
+
diff --git a/tests/auto/dbus/qdbusmarshall/qdbusmarshall.pro b/tests/auto/dbus/qdbusmarshall/qdbusmarshall.pro
new file mode 100644
index 0000000000..1b6408a2f9
--- /dev/null
+++ b/tests/auto/dbus/qdbusmarshall/qdbusmarshall.pro
@@ -0,0 +1,14 @@
+load(qttest_p4)
+contains(QT_CONFIG,dbus): {
+ TEMPLATE = subdirs
+ CONFIG += ordered
+ SUBDIRS = qpong test
+
+ QT += core-private
+
+ requires(contains(QT_CONFIG,private_tests))
+} else {
+ SOURCES += dummy.cpp
+}
+
+
diff --git a/tests/auto/dbus/qdbusmarshall/qpong/qpong.cpp b/tests/auto/dbus/qdbusmarshall/qpong/qpong.cpp
new file mode 100644
index 0000000000..fce6f59344
--- /dev/null
+++ b/tests/auto/dbus/qdbusmarshall/qpong/qpong.cpp
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/QtCore>
+#include <QtDBus/QtDBus>
+
+static const char serviceName[] = "com.trolltech.autotests.qpong";
+static const char objectPath[] = "/com/trolltech/qpong";
+//static const char *interfaceName = serviceName;
+
+class Pong: public QObject
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "com.trolltech.autotests.qpong")
+public slots:
+
+ void ping(QDBusMessage msg)
+ {
+ msg.setDelayedReply(true);
+ if (!QDBusConnection::sessionBus().send(msg.createReply(msg.arguments())))
+ exit(1);
+ }
+};
+
+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);
+
+ Pong pong;
+ con.registerObject(objectPath, &pong, QDBusConnection::ExportAllSlots);
+
+ printf("ready.\n");
+
+ return app.exec();
+}
+
+#include "qpong.moc"
diff --git a/tests/auto/dbus/qdbusmarshall/qpong/qpong.pro b/tests/auto/dbus/qdbusmarshall/qpong/qpong.pro
new file mode 100644
index 0000000000..5cd9acdc1c
--- /dev/null
+++ b/tests/auto/dbus/qdbusmarshall/qpong/qpong.pro
@@ -0,0 +1,6 @@
+SOURCES = qpong.cpp
+TARGET = qpong
+QT += dbus
+QT -= gui
+
+
diff --git a/tests/auto/dbus/qdbusmarshall/test/test.pro b/tests/auto/dbus/qdbusmarshall/test/test.pro
new file mode 100644
index 0000000000..ba4d99b57d
--- /dev/null
+++ b/tests/auto/dbus/qdbusmarshall/test/test.pro
@@ -0,0 +1,9 @@
+load(qttest_p4)
+SOURCES += ../tst_qdbusmarshall.cpp
+TARGET = ../tst_qdbusmarshall
+
+QT = core
+QT += core-private dbus-private
+
+LIBS += $$QT_LIBS_DBUS
+QMAKE_CXXFLAGS += $$QT_CFLAGS_DBUS
diff --git a/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp b/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp
new file mode 100644
index 0000000000..cca212e278
--- /dev/null
+++ b/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp
@@ -0,0 +1,1172 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/QtCore>
+#include <QtTest/QtTest>
+#include <QtDBus/QtDBus>
+#include <QtDBus/private/qdbusutil_p.h>
+#include <QtDBus/private/qdbusconnection_p.h>
+
+#include "common.h"
+#include <limits>
+
+#include <dbus/dbus.h>
+
+static const char serviceName[] = "com.trolltech.autotests.qpong";
+static const char objectPath[] = "/com/trolltech/qpong";
+static const char *interfaceName = serviceName;
+
+class tst_QDBusMarshall: public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+private slots:
+ void sendBasic_data();
+ void sendBasic();
+
+ void sendVariant_data();
+ void sendVariant();
+
+ void sendArrays_data();
+ void sendArrays();
+
+ void sendArrayOfArrays_data();
+ void sendArrayOfArrays();
+
+ void sendMaps_data();
+ void sendMaps();
+
+ void sendStructs_data();
+ void sendStructs();
+
+ void sendComplex_data();
+ void sendComplex();
+
+ void sendArgument_data();
+ void sendArgument();
+
+ void sendSignalErrors();
+ void sendCallErrors_data();
+ void sendCallErrors();
+
+ void receiveUnknownType_data();
+ void receiveUnknownType();
+
+private:
+ int fileDescriptorForTest();
+
+ QProcess proc;
+ QTemporaryFile tempFile;
+ bool fileDescriptorPassing;
+};
+
+class QDBusMessageSpy: public QObject
+{
+ Q_OBJECT
+public slots:
+ Q_SCRIPTABLE int theSlot(const QDBusMessage &msg)
+ {
+ list << msg;
+ return 42;
+ }
+public:
+ QList<QDBusMessage> list;
+};
+
+struct UnregisteredType { };
+Q_DECLARE_METATYPE(UnregisteredType)
+
+void tst_QDBusMarshall::initTestCase()
+{
+ commonInit();
+ QDBusConnection con = QDBusConnection::sessionBus();
+ fileDescriptorPassing = con.connectionCapabilities() & QDBusConnection::UnixFileDescriptorPassing;
+#ifdef Q_OS_WIN
+ proc.start("qpong");
+#else
+ proc.start("./qpong/qpong");
+#endif
+ if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName)) {
+ QVERIFY(proc.waitForStarted());
+
+ QVERIFY(con.isConnected());
+ con.connect("org.freedesktop.DBus", QString(), "org.freedesktop.DBus", "NameOwnerChanged",
+ QStringList() << serviceName << QString(""), QString(),
+ &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+ QVERIFY(QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName));
+ con.disconnect("org.freedesktop.DBus", QString(), "org.freedesktop.DBus", "NameOwnerChanged",
+ QStringList() << serviceName << QString(""), QString(),
+ &QTestEventLoop::instance(), SLOT(exitLoop()));
+ }
+}
+
+void tst_QDBusMarshall::cleanupTestCase()
+{
+ proc.close();
+ proc.terminate();
+ proc.waitForFinished(200);
+}
+
+int tst_QDBusMarshall::fileDescriptorForTest()
+{
+ if (!tempFile.isOpen()) {
+ tempFile.setFileTemplate(QDir::tempPath() + "/qdbusmarshalltestXXXXXX.tmp");
+ tempFile.open();
+ }
+ return tempFile.handle();
+}
+
+void tst_QDBusMarshall::sendBasic_data()
+{
+ QTest::addColumn<QVariant>("value");
+ QTest::addColumn<QString>("sig");
+ QTest::addColumn<QString>("stringResult");
+
+ // basic types:
+ QTest::newRow("bool") << QVariant(false) << "b" << "false";
+#if 1
+ QTest::newRow("bool2") << QVariant(true) << "b" << "true";
+ QTest::newRow("byte") << qVariantFromValue(uchar(1)) << "y" << "1";
+ QTest::newRow("int16") << qVariantFromValue(short(2)) << "n" << "2";
+ QTest::newRow("uint16") << qVariantFromValue(ushort(3)) << "q" << "3";
+ QTest::newRow("int") << QVariant(1) << "i" << "1";
+ QTest::newRow("uint") << QVariant(2U) << "u" << "2";
+ QTest::newRow("int64") << QVariant(Q_INT64_C(3)) << "x" << "3";
+ QTest::newRow("uint64") << QVariant(Q_UINT64_C(4)) << "t" << "4";
+ QTest::newRow("double") << QVariant(42.5) << "d" << "42.5";
+ QTest::newRow("string") << QVariant("ping") << "s" << "\"ping\"";
+ QTest::newRow("objectpath") << qVariantFromValue(QDBusObjectPath("/org/kde")) << "o" << "[ObjectPath: /org/kde]";
+ QTest::newRow("signature") << qVariantFromValue(QDBusSignature("g")) << "g" << "[Signature: g]";
+ QTest::newRow("emptystring") << QVariant("") << "s" << "\"\"";
+ QTest::newRow("nullstring") << QVariant(QString()) << "s" << "\"\"";
+
+ if (fileDescriptorPassing)
+ QTest::newRow("file-descriptor") << qVariantFromValue(QDBusUnixFileDescriptor(fileDescriptorForTest())) << "h" << "[Unix FD: valid]";
+#endif
+}
+
+void tst_QDBusMarshall::sendVariant_data()
+{
+ sendBasic_data();
+
+ QTest::newRow("variant") << qVariantFromValue(QDBusVariant(1)) << "v" << "[Variant(int): 1]";
+
+ QDBusVariant nested(1);
+ QTest::newRow("variant-variant") << qVariantFromValue(QDBusVariant(qVariantFromValue(nested))) << "v"
+ << "[Variant(QDBusVariant): [Variant(int): 1]]";
+}
+
+void tst_QDBusMarshall::sendArrays_data()
+{
+ QTest::addColumn<QVariant>("value");
+ QTest::addColumn<QString>("sig");
+ QTest::addColumn<QString>("stringResult");
+
+ // arrays
+ QStringList strings;
+ QTest::newRow("emptystringlist") << QVariant(strings) << "as" << "{}";
+ strings << "hello" << "world";
+ QTest::newRow("stringlist") << QVariant(strings) << "as" << "{\"hello\", \"world\"}";
+
+ strings.clear();
+ strings << "" << "" << "";
+ QTest::newRow("list-of-emptystrings") << QVariant(strings) << "as" << "{\"\", \"\", \"\"}";
+
+ strings.clear();
+ strings << QString() << QString() << QString() << QString();
+ QTest::newRow("list-of-nullstrings") << QVariant(strings) << "as" << "{\"\", \"\", \"\", \"\"}";
+
+ QByteArray bytearray;
+ QTest::newRow("nullbytearray") << QVariant(bytearray) << "ay" << "{}";
+ bytearray = ""; // empty, not null
+ QTest::newRow("emptybytearray") << QVariant(bytearray) << "ay" << "{}";
+ bytearray = "foo";
+ QTest::newRow("bytearray") << QVariant(bytearray) << "ay" << "{102, 111, 111}";
+
+ QList<bool> bools;
+ QTest::newRow("emptyboollist") << qVariantFromValue(bools) << "ab" << "[Argument: ab {}]";
+ bools << false << true << false;
+ QTest::newRow("boollist") << qVariantFromValue(bools) << "ab" << "[Argument: ab {false, true, false}]";
+
+ QList<short> shorts;
+ QTest::newRow("emptyshortlist") << qVariantFromValue(shorts) << "an" << "[Argument: an {}]";
+ shorts << 42 << -43 << 44 << 45 << -32768 << 32767;
+ QTest::newRow("shortlist") << qVariantFromValue(shorts) << "an"
+ << "[Argument: an {42, -43, 44, 45, -32768, 32767}]";
+
+ QList<ushort> ushorts;
+ QTest::newRow("emptyushortlist") << qVariantFromValue(ushorts) << "aq" << "[Argument: aq {}]";
+ ushorts << 12u << 13u << 14u << 15 << 65535;
+ QTest::newRow("ushortlist") << qVariantFromValue(ushorts) << "aq" << "[Argument: aq {12, 13, 14, 15, 65535}]";
+
+ QList<int> ints;
+ QTest::newRow("emptyintlist") << qVariantFromValue(ints) << "ai" << "[Argument: ai {}]";
+ ints << 42 << -43 << 44 << 45 << 2147483647 << -2147483647-1;
+ QTest::newRow("intlist") << qVariantFromValue(ints) << "ai" << "[Argument: ai {42, -43, 44, 45, 2147483647, -2147483648}]";
+
+ QList<uint> uints;
+ QTest::newRow("emptyuintlist") << qVariantFromValue(uints) << "au" << "[Argument: au {}]";
+ uints << uint(12) << uint(13) << uint(14) << 4294967295U;
+ QTest::newRow("uintlist") << qVariantFromValue(uints) << "au" << "[Argument: au {12, 13, 14, 4294967295}]";
+
+ QList<qlonglong> llints;
+ QTest::newRow("emptyllintlist") << qVariantFromValue(llints) << "ax" << "[Argument: ax {}]";
+ llints << Q_INT64_C(99) << Q_INT64_C(-100)
+ << Q_INT64_C(-9223372036854775807)-1 << Q_INT64_C(9223372036854775807);
+ QTest::newRow("llintlist") << qVariantFromValue(llints) << "ax"
+ << "[Argument: ax {99, -100, -9223372036854775808, 9223372036854775807}]";
+
+ QList<qulonglong> ullints;
+ QTest::newRow("emptyullintlist") << qVariantFromValue(ullints) << "at" << "[Argument: at {}]";
+ ullints << Q_UINT64_C(66) << Q_UINT64_C(67)
+ << Q_UINT64_C(18446744073709551615);
+ QTest::newRow("ullintlist") << qVariantFromValue(ullints) << "at" << "[Argument: at {66, 67, 18446744073709551615}]";
+
+ QList<double> doubles;
+ QTest::newRow("emptydoublelist") << qVariantFromValue(doubles) << "ad" << "[Argument: ad {}]";
+ doubles << 1.2 << 2.2 << 4.4
+ << -std::numeric_limits<double>::infinity()
+ << std::numeric_limits<double>::infinity()
+ << std::numeric_limits<double>::quiet_NaN();
+ QTest::newRow("doublelist") << qVariantFromValue(doubles) << "ad" << "[Argument: ad {1.2, 2.2, 4.4, -inf, inf, nan}]";
+
+ QList<QDBusObjectPath> objectPaths;
+ QTest::newRow("emptyobjectpathlist") << qVariantFromValue(objectPaths) << "ao" << "[Argument: ao {}]";
+ objectPaths << QDBusObjectPath("/") << QDBusObjectPath("/foo");
+ QTest::newRow("objectpathlist") << qVariantFromValue(objectPaths) << "ao" << "[Argument: ao {[ObjectPath: /], [ObjectPath: /foo]}]";
+
+ if (fileDescriptorPassing) {
+ QList<QDBusUnixFileDescriptor> fileDescriptors;
+ QTest::newRow("emptyfiledescriptorlist") << qVariantFromValue(fileDescriptors) << "ah" << "[Argument: ah {}]";
+ fileDescriptors << QDBusUnixFileDescriptor(fileDescriptorForTest()) << QDBusUnixFileDescriptor(1);
+ QTest::newRow("filedescriptorlist") << qVariantFromValue(fileDescriptors) << "ah" << "[Argument: ah {[Unix FD: valid], [Unix FD: valid]}]";
+ }
+
+ QVariantList variants;
+ QTest::newRow("emptyvariantlist") << QVariant(variants) << "av" << "[Argument: av {}]";
+ variants << QString("Hello") << QByteArray("World") << 42 << -43.0 << 44U << Q_INT64_C(-45)
+ << Q_UINT64_C(46) << true << qVariantFromValue(short(-47))
+ << qVariantFromValue(QDBusSignature("av"))
+ << qVariantFromValue(QDBusVariant(qVariantFromValue(QDBusObjectPath("/"))));
+ QTest::newRow("variantlist") << QVariant(variants) << "av"
+ << "[Argument: av {[Variant(QString): \"Hello\"], [Variant(QByteArray): {87, 111, 114, 108, 100}], [Variant(int): 42], [Variant(double): -43], [Variant(uint): 44], [Variant(qlonglong): -45], [Variant(qulonglong): 46], [Variant(bool): true], [Variant(short): -47], [Variant: [Signature: av]], [Variant: [Variant: [ObjectPath: /]]]}]";
+}
+
+void tst_QDBusMarshall::sendArrayOfArrays_data()
+{
+ QTest::addColumn<QVariant>("value");
+ QTest::addColumn<QString>("sig");
+ QTest::addColumn<QString>("stringResult");
+
+ // arrays:
+ QList<QStringList> strings;
+ QTest::newRow("empty-list-of-stringlist") << qVariantFromValue(strings) << "aas"
+ << "[Argument: aas {}]";
+ strings << QStringList();
+ QTest::newRow("list-of-emptystringlist") << qVariantFromValue(strings) << "aas"
+ << "[Argument: aas {{}}]";
+ strings << (QStringList() << "hello" << "world")
+ << (QStringList() << "hi" << "there")
+ << (QStringList() << QString());
+ QTest::newRow("stringlist") << qVariantFromValue(strings) << "aas"
+ << "[Argument: aas {{}, {\"hello\", \"world\"}, {\"hi\", \"there\"}, {\"\"}}]";
+
+ QList<QByteArray> bytearray;
+ QTest::newRow("empty-list-of-bytearray") << qVariantFromValue(bytearray) << "aay"
+ << "[Argument: aay {}]";
+ bytearray << QByteArray();
+ QTest::newRow("list-of-emptybytearray") << qVariantFromValue(bytearray) << "aay"
+ << "[Argument: aay {{}}]";
+ bytearray << "foo" << "bar" << "baz" << "" << QByteArray();
+ QTest::newRow("bytearray") << qVariantFromValue(bytearray) << "aay"
+ << "[Argument: aay {{}, {102, 111, 111}, {98, 97, 114}, {98, 97, 122}, {}, {}}]";
+
+ QList<QList<bool> > bools;
+ QTest::newRow("empty-list-of-boollist") << qVariantFromValue(bools) << "aab"
+ << "[Argument: aab {}]";
+ bools << QList<bool>();
+ QTest::newRow("list-of-emptyboollist") << qVariantFromValue(bools) << "aab"
+ << "[Argument: aab {[Argument: ab {}]}]";
+ bools << (QList<bool>() << false << true) << (QList<bool>() << false) << (QList<bool>());
+ QTest::newRow("boollist") << qVariantFromValue(bools) << "aab"
+ << "[Argument: aab {[Argument: ab {}], [Argument: ab {false, true}], [Argument: ab {false}], [Argument: ab {}]}]";
+ QList<QList<short> > shorts;
+ QTest::newRow("empty-list-of-shortlist") << qVariantFromValue(shorts) << "aan"
+ << "[Argument: aan {}]";
+ shorts << QList<short>();
+ QTest::newRow("list-of-emptyshortlist") << qVariantFromValue(shorts) << "aan"
+ << "[Argument: aan {[Argument: an {}]}]";
+ shorts << (QList<short>() << 42 << -43 << 44 << 45)
+ << (QList<short>() << -32768 << 32767)
+ << (QList<short>());
+ QTest::newRow("shortlist") << qVariantFromValue(shorts) << "aan"
+ << "[Argument: aan {[Argument: an {}], [Argument: an {42, -43, 44, 45}], [Argument: an {-32768, 32767}], [Argument: an {}]}]";
+
+ QList<QList<ushort> > ushorts;
+ QTest::newRow("empty-list-of-ushortlist") << qVariantFromValue(ushorts) << "aaq"
+ << "[Argument: aaq {}]";
+ ushorts << QList<ushort>();
+ QTest::newRow("list-of-emptyushortlist") << qVariantFromValue(ushorts) << "aaq"
+ << "[Argument: aaq {[Argument: aq {}]}]";
+ ushorts << (QList<ushort>() << 12u << 13u << 14u << 15)
+ << (QList<ushort>() << 65535)
+ << (QList<ushort>());
+ QTest::newRow("ushortlist") << qVariantFromValue(ushorts) << "aaq"
+ << "[Argument: aaq {[Argument: aq {}], [Argument: aq {12, 13, 14, 15}], [Argument: aq {65535}], [Argument: aq {}]}]";
+
+ QList<QList<int> > ints;
+ QTest::newRow("empty-list-of-intlist") << qVariantFromValue(ints) << "aai"
+ << "[Argument: aai {}]";
+ ints << QList<int>();
+ QTest::newRow("list-of-emptyintlist") << qVariantFromValue(ints) << "aai"
+ << "[Argument: aai {[Argument: ai {}]}]";
+ ints << (QList<int>() << 42 << -43 << 44 << 45)
+ << (QList<int>() << 2147483647 << -2147483647-1)
+ << (QList<int>());
+ QTest::newRow("intlist") << qVariantFromValue(ints) << "aai"
+ << "[Argument: aai {[Argument: ai {}], [Argument: ai {42, -43, 44, 45}], [Argument: ai {2147483647, -2147483648}], [Argument: ai {}]}]";
+
+ QList<QList<uint> > uints;
+ QTest::newRow("empty-list-of-uintlist") << qVariantFromValue(uints) << "aau"
+ << "[Argument: aau {}]";
+ uints << QList<uint>();
+ QTest::newRow("list-of-emptyuintlist") << qVariantFromValue(uints) << "aau"
+ << "[Argument: aau {[Argument: au {}]}]";
+ uints << (QList<uint>() << uint(12) << uint(13) << uint(14))
+ << (QList<uint>() << 4294967295U)
+ << (QList<uint>());
+ QTest::newRow("uintlist") << qVariantFromValue(uints) << "aau"
+ << "[Argument: aau {[Argument: au {}], [Argument: au {12, 13, 14}], [Argument: au {4294967295}], [Argument: au {}]}]";
+
+ QList<QList<qlonglong> > llints;
+ QTest::newRow("empty-list-of-llintlist") << qVariantFromValue(llints) << "aax"
+ << "[Argument: aax {}]";
+ llints << QList<qlonglong>();
+ QTest::newRow("list-of-emptyllintlist") << qVariantFromValue(llints) << "aax"
+ << "[Argument: aax {[Argument: ax {}]}]";
+ llints << (QList<qlonglong>() << Q_INT64_C(99) << Q_INT64_C(-100))
+ << (QList<qlonglong>() << Q_INT64_C(-9223372036854775807)-1 << Q_INT64_C(9223372036854775807))
+ << (QList<qlonglong>());
+ QTest::newRow("llintlist") << qVariantFromValue(llints) << "aax"
+ << "[Argument: aax {[Argument: ax {}], [Argument: ax {99, -100}], [Argument: ax {-9223372036854775808, 9223372036854775807}], [Argument: ax {}]}]";
+
+ QList<QList<qulonglong> > ullints;
+ QTest::newRow("empty-list-of-ullintlist") << qVariantFromValue(ullints) << "aat"
+ << "[Argument: aat {}]";
+ ullints << QList<qulonglong>();
+ QTest::newRow("list-of-emptyullintlist") << qVariantFromValue(ullints) << "aat"
+ << "[Argument: aat {[Argument: at {}]}]";
+ ullints << (QList<qulonglong>() << Q_UINT64_C(66) << Q_UINT64_C(67))
+ << (QList<qulonglong>() << Q_UINT64_C(18446744073709551615))
+ << (QList<qulonglong>());
+ QTest::newRow("ullintlist") << qVariantFromValue(ullints) << "aat"
+ << "[Argument: aat {[Argument: at {}], [Argument: at {66, 67}], [Argument: at {18446744073709551615}], [Argument: at {}]}]";
+
+ QList<QList<double> > doubles;
+ QTest::newRow("empty-list-ofdoublelist") << qVariantFromValue(doubles) << "aad"
+ << "[Argument: aad {}]";
+ doubles << QList<double>();
+ QTest::newRow("list-of-emptydoublelist") << qVariantFromValue(doubles) << "aad"
+ << "[Argument: aad {[Argument: ad {}]}]";
+ doubles << (QList<double>() << 1.2 << 2.2 << 4.4)
+ << (QList<double>() << -std::numeric_limits<double>::infinity()
+ << std::numeric_limits<double>::infinity()
+ << std::numeric_limits<double>::quiet_NaN())
+ << (QList<double>());
+ QTest::newRow("doublelist") << qVariantFromValue(doubles) << "aad"
+ << "[Argument: aad {[Argument: ad {}], [Argument: ad {1.2, 2.2, 4.4}], [Argument: ad {-inf, inf, nan}], [Argument: ad {}]}]";
+
+ QList<QVariantList> variants;
+ QTest::newRow("emptyvariantlist") << qVariantFromValue(variants) << "aav"
+ << "[Argument: aav {}]";
+ variants << QVariantList();
+ QTest::newRow("emptyvariantlist") << qVariantFromValue(variants) << "aav"
+ << "[Argument: aav {[Argument: av {}]}]";
+ variants << (QVariantList() << QString("Hello") << QByteArray("World"))
+ << (QVariantList() << 42 << -43.0 << 44U << Q_INT64_C(-45))
+ << (QVariantList() << Q_UINT64_C(46) << true << qVariantFromValue(short(-47)));
+ QTest::newRow("variantlist") << qVariantFromValue(variants) << "aav"
+ << "[Argument: aav {[Argument: av {}], [Argument: av {[Variant(QString): \"Hello\"], [Variant(QByteArray): {87, 111, 114, 108, 100}]}], [Argument: av {[Variant(int): 42], [Variant(double): -43], [Variant(uint): 44], [Variant(qlonglong): -45]}], [Argument: av {[Variant(qulonglong): 46], [Variant(bool): true], [Variant(short): -47]}]}]";
+}
+
+void tst_QDBusMarshall::sendMaps_data()
+{
+ QTest::addColumn<QVariant>("value");
+ QTest::addColumn<QString>("sig");
+ QTest::addColumn<QString>("stringResult");
+
+ QMap<int, QString> ismap;
+ QTest::newRow("empty-is-map") << qVariantFromValue(ismap) << "a{is}"
+ << "[Argument: a{is} {}]";
+ ismap[1] = "a";
+ ismap[2000] = "b";
+ ismap[-47] = "c";
+ QTest::newRow("is-map") << qVariantFromValue(ismap) << "a{is}"
+ << "[Argument: a{is} {-47 = \"c\", 1 = \"a\", 2000 = \"b\"}]";
+
+ QMap<QString, QString> ssmap;
+ QTest::newRow("empty-ss-map") << qVariantFromValue(ssmap) << "a{ss}"
+ << "[Argument: a{ss} {}]";
+ ssmap["a"] = "a";
+ ssmap["c"] = "b";
+ ssmap["b"] = "c";
+ QTest::newRow("ss-map") << qVariantFromValue(ssmap) << "a{ss}"
+ << "[Argument: a{ss} {\"a\" = \"a\", \"b\" = \"c\", \"c\" = \"b\"}]";
+
+ QVariantMap svmap;
+ QTest::newRow("empty-sv-map") << qVariantFromValue(svmap) << "a{sv}"
+ << "[Argument: a{sv} {}]";
+ svmap["a"] = 1;
+ svmap["c"] = "b";
+ svmap["b"] = QByteArray("c");
+ svmap["d"] = 42U;
+ svmap["e"] = qVariantFromValue(short(-47));
+ svmap["f"] = qVariantFromValue(QDBusVariant(0));
+ QTest::newRow("sv-map1") << qVariantFromValue(svmap) << "a{sv}"
+ << "[Argument: a{sv} {\"a\" = [Variant(int): 1], \"b\" = [Variant(QByteArray): {99}], \"c\" = [Variant(QString): \"b\"], \"d\" = [Variant(uint): 42], \"e\" = [Variant(short): -47], \"f\" = [Variant: [Variant(int): 0]]}]";
+
+ QMap<QDBusObjectPath, QString> osmap;
+ QTest::newRow("empty-os-map") << qVariantFromValue(osmap) << "a{os}"
+ << "[Argument: a{os} {}]";
+ osmap[QDBusObjectPath("/")] = "root";
+ osmap[QDBusObjectPath("/foo")] = "foo";
+ osmap[QDBusObjectPath("/bar/baz")] = "bar and baz";
+ QTest::newRow("os-map") << qVariantFromValue(osmap) << "a{os}"
+ << "[Argument: a{os} {[ObjectPath: /] = \"root\", [ObjectPath: /bar/baz] = \"bar and baz\", [ObjectPath: /foo] = \"foo\"}]";
+
+ QHash<QDBusSignature, QString> gsmap;
+ QTest::newRow("empty-gs-map") << qVariantFromValue(gsmap) << "a{gs}"
+ << "[Argument: a{gs} {}]";
+ gsmap[QDBusSignature("i")] = "int32";
+ gsmap[QDBusSignature("s")] = "string";
+ gsmap[QDBusSignature("a{gs}")] = "array of dict_entry of (signature, string)";
+ QTest::newRow("gs-map") << qVariantFromValue(gsmap) << "a{gs}"
+ << "[Argument: a{gs} {[Signature: a{gs}] = \"array of dict_entry of (signature, string)\", [Signature: i] = \"int32\", [Signature: s] = \"string\"}]";
+
+ if (fileDescriptorPassing) {
+ svmap["zzfiledescriptor"] = qVariantFromValue(QDBusUnixFileDescriptor(fileDescriptorForTest()));
+ QTest::newRow("sv-map1-fd") << qVariantFromValue(svmap) << "a{sv}"
+ << "[Argument: a{sv} {\"a\" = [Variant(int): 1], \"b\" = [Variant(QByteArray): {99}], \"c\" = [Variant(QString): \"b\"], \"d\" = [Variant(uint): 42], \"e\" = [Variant(short): -47], \"f\" = [Variant: [Variant(int): 0]], \"zzfiledescriptor\" = [Variant(QDBusUnixFileDescriptor): [Unix FD: valid]]}]";
+ }
+
+ svmap.clear();
+ svmap["ismap"] = qVariantFromValue(ismap);
+ svmap["ssmap"] = qVariantFromValue(ssmap);
+ svmap["osmap"] = qVariantFromValue(osmap);
+ svmap["gsmap"] = qVariantFromValue(gsmap);
+ QTest::newRow("sv-map2") << qVariantFromValue(svmap) << "a{sv}"
+ << "[Argument: a{sv} {\"gsmap\" = [Variant: [Argument: a{gs} {[Signature: a{gs}] = \"array of dict_entry of (signature, string)\", [Signature: i] = \"int32\", [Signature: s] = \"string\"}]], \"ismap\" = [Variant: [Argument: a{is} {-47 = \"c\", 1 = \"a\", 2000 = \"b\"}]], \"osmap\" = [Variant: [Argument: a{os} {[ObjectPath: /] = \"root\", [ObjectPath: /bar/baz] = \"bar and baz\", [ObjectPath: /foo] = \"foo\"}]], \"ssmap\" = [Variant: [Argument: a{ss} {\"a\" = \"a\", \"b\" = \"c\", \"c\" = \"b\"}]]}]";
+}
+
+void tst_QDBusMarshall::sendStructs_data()
+{
+ QTest::addColumn<QVariant>("value");
+ QTest::addColumn<QString>("sig");
+ QTest::addColumn<QString>("stringResult");
+
+ QTest::newRow("point") << QVariant(QPoint(1, 2)) << "(ii)" << "[Argument: (ii) 1, 2]";
+ QTest::newRow("pointf") << QVariant(QPointF(1.5, -1.5)) << "(dd)" << "[Argument: (dd) 1.5, -1.5]";
+
+ QTest::newRow("size") << QVariant(QSize(1, 2)) << "(ii)" << "[Argument: (ii) 1, 2]";
+ QTest::newRow("sizef") << QVariant(QSizeF(1.5, 1.5)) << "(dd)" << "[Argument: (dd) 1.5, 1.5]";
+
+ QTest::newRow("rect") << QVariant(QRect(1, 2, 3, 4)) << "(iiii)" << "[Argument: (iiii) 1, 2, 3, 4]";
+ QTest::newRow("rectf") << QVariant(QRectF(0.5, 0.5, 1.5, 1.5)) << "(dddd)" << "[Argument: (dddd) 0.5, 0.5, 1.5, 1.5]";
+
+ QTest::newRow("line") << QVariant(QLine(1, 2, 3, 4)) << "((ii)(ii))"
+ << "[Argument: ((ii)(ii)) [Argument: (ii) 1, 2], [Argument: (ii) 3, 4]]";
+ QTest::newRow("linef") << QVariant(QLineF(0.5, 0.5, 1.5, 1.5)) << "((dd)(dd))"
+ << "[Argument: ((dd)(dd)) [Argument: (dd) 0.5, 0.5], [Argument: (dd) 1.5, 1.5]]";
+
+ QDate date(2006, 6, 18);
+ QTime time(12, 25, 00); // the date I wrote this test on :-)
+ QTest::newRow("date") << QVariant(date) << "(iii)" << "[Argument: (iii) 2006, 6, 18]";
+ QTest::newRow("time") << QVariant(time) << "(iiii)" << "[Argument: (iiii) 12, 25, 0, 0]";
+ QTest::newRow("datetime") << QVariant(QDateTime(date, time)) << "((iii)(iiii)i)"
+ << "[Argument: ((iii)(iiii)i) [Argument: (iii) 2006, 6, 18], [Argument: (iiii) 12, 25, 0, 0], 0]";
+
+ MyStruct ms = { 1, "Hello, World" };
+ QTest::newRow("int-string") << qVariantFromValue(ms) << "(is)" << "[Argument: (is) 1, \"Hello, World\"]";
+
+ MyVariantMapStruct mvms = { "Hello, World", QVariantMap() };
+ QTest::newRow("string-variantmap") << qVariantFromValue(mvms) << "(sa{sv})" << "[Argument: (sa{sv}) \"Hello, World\", [Argument: a{sv} {}]]";
+
+ // use only basic types, otherwise comparison will fail
+ mvms.map["int"] = 42;
+ mvms.map["uint"] = 42u;
+ mvms.map["short"] = qVariantFromValue<short>(-47);
+ mvms.map["bytearray"] = QByteArray("Hello, world");
+ QTest::newRow("string-variantmap2") << qVariantFromValue(mvms) << "(sa{sv})" << "[Argument: (sa{sv}) \"Hello, World\", [Argument: a{sv} {\"bytearray\" = [Variant(QByteArray): {72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100}], \"int\" = [Variant(int): 42], \"short\" = [Variant(short): -47], \"uint\" = [Variant(uint): 42]}]]";
+
+ QList<MyVariantMapStruct> list;
+ QTest::newRow("empty-list-of-string-variantmap") << qVariantFromValue(list) << "a(sa{sv})" << "[Argument: a(sa{sv}) {}]";
+ list << mvms;
+ QTest::newRow("list-of-string-variantmap") << qVariantFromValue(list) << "a(sa{sv})" << "[Argument: a(sa{sv}) {[Argument: (sa{sv}) \"Hello, World\", [Argument: a{sv} {\"bytearray\" = [Variant(QByteArray): {72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100}], \"int\" = [Variant(int): 42], \"short\" = [Variant(short): -47], \"uint\" = [Variant(uint): 42]}]]}]";
+
+ if (fileDescriptorPassing) {
+ MyFileDescriptorStruct fds;
+ fds.fd = QDBusUnixFileDescriptor(fileDescriptorForTest());
+ QTest::newRow("fdstruct") << qVariantFromValue(fds) << "(h)" << "[Argument: (h) [Unix FD: valid]]";
+
+ QList<MyFileDescriptorStruct> fdlist;
+ QTest::newRow("empty-list-of-fdstruct") << qVariantFromValue(fdlist) << "a(h)" << "[Argument: a(h) {}]";
+
+ fdlist << fds;
+ QTest::newRow("list-of-fdstruct") << qVariantFromValue(fdlist) << "a(h)" << "[Argument: a(h) {[Argument: (h) [Unix FD: valid]]}]";
+ }
+}
+
+void tst_QDBusMarshall::sendComplex_data()
+{
+ QTest::addColumn<QVariant>("value");
+ QTest::addColumn<QString>("sig");
+ QTest::addColumn<QString>("stringResult");
+
+ QList<QDateTime> dtlist;
+ QTest::newRow("empty-datetimelist") << qVariantFromValue(dtlist) << "a((iii)(iiii)i)"
+ << "[Argument: a((iii)(iiii)i) {}]";
+ dtlist << QDateTime();
+ QTest::newRow("list-of-emptydatetime") << qVariantFromValue(dtlist) << "a((iii)(iiii)i)"
+ << "[Argument: a((iii)(iiii)i) {[Argument: ((iii)(iiii)i) [Argument: (iii) 0, 0, 0], [Argument: (iiii) -1, -1, -1, -1], 0]}]";
+ dtlist << QDateTime(QDate(1977, 9, 13), QTime(0, 0, 0))
+ << QDateTime(QDate(2006, 6, 18), QTime(13, 14, 0));
+ QTest::newRow("datetimelist") << qVariantFromValue(dtlist) << "a((iii)(iiii)i)"
+ << "[Argument: a((iii)(iiii)i) {[Argument: ((iii)(iiii)i) [Argument: (iii) 0, 0, 0], [Argument: (iiii) -1, -1, -1, -1], 0], [Argument: ((iii)(iiii)i) [Argument: (iii) 1977, 9, 13], [Argument: (iiii) 0, 0, 0, 0], 0], [Argument: ((iii)(iiii)i) [Argument: (iii) 2006, 6, 18], [Argument: (iiii) 13, 14, 0, 0], 0]}]";
+
+ QHash<qlonglong, QDateTime> lldtmap;
+ QTest::newRow("empty-lldtmap") << qVariantFromValue(lldtmap) << "a{x((iii)(iiii)i)}"
+ << "[Argument: a{x((iii)(iiii)i)} {}]";
+ lldtmap[0] = QDateTime();
+ lldtmap[1] = QDateTime(QDate(1970, 1, 1), QTime(0, 0, 1), Qt::UTC);
+ lldtmap[1150629776] = QDateTime(QDate(2006, 6, 18), QTime(11, 22, 56), Qt::UTC);
+ QTest::newRow("lldtmap") << qVariantFromValue(lldtmap) << "a{x((iii)(iiii)i)}"
+ << "[Argument: a{x((iii)(iiii)i)} {0 = [Argument: ((iii)(iiii)i) [Argument: (iii) 0, 0, 0], [Argument: (iiii) -1, -1, -1, -1], 0], 1 = [Argument: ((iii)(iiii)i) [Argument: (iii) 1970, 1, 1], [Argument: (iiii) 0, 0, 1, 0], 1], 1150629776 = [Argument: ((iii)(iiii)i) [Argument: (iii) 2006, 6, 18], [Argument: (iiii) 11, 22, 56, 0], 1]}]";
+
+
+ QMap<int, QString> ismap;
+ ismap[1] = "a";
+ ismap[2000] = "b";
+ ismap[-47] = "c";
+
+ QMap<QString, QString> ssmap;
+ ssmap["a"] = "a";
+ ssmap["c"] = "b";
+ ssmap["b"] = "c";
+
+ QHash<QDBusSignature, QString> gsmap;
+ gsmap[QDBusSignature("i")] = "int32";
+ gsmap[QDBusSignature("s")] = "string";
+ gsmap[QDBusSignature("a{gs}")] = "array of dict_entry of (signature, string)";
+
+ QVariantMap svmap;
+ svmap["a"] = 1;
+ svmap["c"] = "b";
+ svmap["b"] = QByteArray("c");
+ svmap["d"] = 42U;
+ svmap["e"] = qVariantFromValue(short(-47));
+ svmap["f"] = qVariantFromValue(QDBusVariant(0));
+ svmap["date"] = QDate(1977, 1, 1);
+ svmap["time"] = QTime(8, 58, 0);
+ svmap["datetime"] = QDateTime(QDate(13, 9, 2008), QTime(8, 59, 31));
+ svmap["pointf"] = QPointF(0.5, -0.5);
+ svmap["ismap"] = qVariantFromValue(ismap);
+ svmap["ssmap"] = qVariantFromValue(ssmap);
+ svmap["gsmap"] = qVariantFromValue(gsmap);
+ svmap["dtlist"] = qVariantFromValue(dtlist);
+ svmap["lldtmap"] = qVariantFromValue(lldtmap);
+ QTest::newRow("sv-map") << qVariantFromValue(svmap) << "a{sv}"
+ << "[Argument: a{sv} {\"a\" = [Variant(int): 1], \"b\" = [Variant(QByteArray): {99}], \"c\" = [Variant(QString): \"b\"], \"d\" = [Variant(uint): 42], \"date\" = [Variant: [Argument: (iii) 1977, 1, 1]], \"datetime\" = [Variant: [Argument: ((iii)(iiii)i) [Argument: (iii) 0, 0, 0], [Argument: (iiii) 8, 59, 31, 0], 0]], \"dtlist\" = [Variant: [Argument: a((iii)(iiii)i) {[Argument: ((iii)(iiii)i) [Argument: (iii) 0, 0, 0], [Argument: (iiii) -1, -1, -1, -1], 0], [Argument: ((iii)(iiii)i) [Argument: (iii) 1977, 9, 13], [Argument: (iiii) 0, 0, 0, 0], 0], [Argument: ((iii)(iiii)i) [Argument: (iii) 2006, 6, 18], [Argument: (iiii) 13, 14, 0, 0], 0]}]], \"e\" = [Variant(short): -47], \"f\" = [Variant: [Variant(int): 0]], \"gsmap\" = [Variant: [Argument: a{gs} {[Signature: a{gs}] = \"array of dict_entry of (signature, string)\", [Signature: i] = \"int32\", [Signature: s] = \"string\"}]], \"ismap\" = [Variant: [Argument: a{is} {-47 = \"c\", 1 = \"a\", 2000 = \"b\"}]], \"lldtmap\" = [Variant: [Argument: a{x((iii)(iiii)i)} {0 = [Argument: ((iii)(iiii)i) [Argument: (iii) 0, 0, 0], [Argument: (iiii) -1, -1, -1, -1], 0], 1 = [Argument: ((iii)(iiii)i) [Argument: (iii) 1970, 1, 1], [Argument: (iiii) 0, 0, 1, 0], 1], 1150629776 = [Argument: ((iii)(iiii)i) [Argument: (iii) 2006, 6, 18], [Argument: (iiii) 11, 22, 56, 0], 1]}]], \"pointf\" = [Variant: [Argument: (dd) 0.5, -0.5]], \"ssmap\" = [Variant: [Argument: a{ss} {\"a\" = \"a\", \"b\" = \"c\", \"c\" = \"b\"}]], \"time\" = [Variant: [Argument: (iiii) 8, 58, 0, 0]]}]";
+}
+
+void tst_QDBusMarshall::sendArgument_data()
+{
+ QTest::addColumn<QVariant>("value");
+ QTest::addColumn<QString>("sig");
+ QTest::addColumn<int>("classification");
+
+ QDBusArgument();
+ QDBusArgument arg;
+
+ arg = QDBusArgument();
+ arg << true;
+ QTest::newRow("bool") << qVariantFromValue(arg) << "b" << int(QDBusArgument::BasicType);;
+
+ arg = QDBusArgument();
+ arg << false;
+ QTest::newRow("bool2") << qVariantFromValue(arg) << "b" << int(QDBusArgument::BasicType);
+
+ arg = QDBusArgument();
+ arg << uchar(1);
+ QTest::newRow("byte") << qVariantFromValue(arg) << "y" << int(QDBusArgument::BasicType);
+
+ arg = QDBusArgument();
+ arg << short(2);
+ QTest::newRow("int16") << qVariantFromValue(arg) << "n" << int(QDBusArgument::BasicType);
+
+ arg = QDBusArgument();
+ arg << ushort(3);
+ QTest::newRow("uint16") << qVariantFromValue(arg) << "q" << int(QDBusArgument::BasicType);
+
+ arg = QDBusArgument();
+ arg << 1;
+ QTest::newRow("int32") << qVariantFromValue(arg) << "i" << int(QDBusArgument::BasicType);
+
+ arg = QDBusArgument();
+ arg << 2U;
+ QTest::newRow("uint32") << qVariantFromValue(arg) << "u" << int(QDBusArgument::BasicType);
+
+ arg = QDBusArgument();
+ arg << Q_INT64_C(3);
+ QTest::newRow("int64") << qVariantFromValue(arg) << "x" << int(QDBusArgument::BasicType);
+
+ arg = QDBusArgument();
+ arg << Q_UINT64_C(4);
+ QTest::newRow("uint64") << qVariantFromValue(arg) << "t" << int(QDBusArgument::BasicType);
+
+ arg = QDBusArgument();
+ arg << 42.5;
+ QTest::newRow("double") << qVariantFromValue(arg) << "d" << int(QDBusArgument::BasicType);
+
+ arg = QDBusArgument();
+ arg << QLatin1String("ping");
+ QTest::newRow("string") << qVariantFromValue(arg) << "s" << int(QDBusArgument::BasicType);
+
+ arg = QDBusArgument();
+ arg << QDBusObjectPath("/org/kde");
+ QTest::newRow("objectpath") << qVariantFromValue(arg) << "o" << int(QDBusArgument::BasicType);
+
+ arg = QDBusArgument();
+ arg << QDBusSignature("g");
+ QTest::newRow("signature") << qVariantFromValue(arg) << "g" << int(QDBusArgument::BasicType);
+
+ arg = QDBusArgument();
+ arg << QLatin1String("");
+ QTest::newRow("emptystring") << qVariantFromValue(arg) << "s" << int(QDBusArgument::BasicType);
+
+ arg = QDBusArgument();
+ arg << QString();
+ QTest::newRow("nullstring") << qVariantFromValue(arg) << "s" << int(QDBusArgument::BasicType);
+
+ if (fileDescriptorPassing) {
+ arg = QDBusArgument();
+ arg << QDBusUnixFileDescriptor(fileDescriptorForTest());
+ QTest::newRow("filedescriptor") << qVariantFromValue(arg) << "h" << int(QDBusArgument::BasicType);
+ }
+
+ arg = QDBusArgument();
+ arg << QDBusVariant(1);
+ QTest::newRow("variant") << qVariantFromValue(arg) << "v" << int(QDBusArgument::VariantType);
+
+ arg = QDBusArgument();
+ arg << QDBusVariant(qVariantFromValue(QDBusVariant(1)));
+ QTest::newRow("variant-variant") << qVariantFromValue(arg) << "v" << int(QDBusArgument::VariantType);
+
+ arg = QDBusArgument();
+ arg.beginArray(QVariant::Int);
+ arg << 1 << 2 << 3 << -4;
+ arg.endArray();
+ QTest::newRow("array-of-int") << qVariantFromValue(arg) << "ai" << int(QDBusArgument::ArrayType);
+
+ arg = QDBusArgument();
+ arg.beginMap(QVariant::Int, QVariant::UInt);
+ arg.beginMapEntry();
+ arg << 1 << 2U;
+ arg.endMapEntry();
+ arg.beginMapEntry();
+ arg << 3 << 4U;
+ arg.endMapEntry();
+ arg.endMap();
+ QTest::newRow("map") << qVariantFromValue(arg) << "a{iu}" << int(QDBusArgument::MapType);
+
+ arg = QDBusArgument();
+ arg.beginStructure();
+ arg << 1 << 2U << short(-3) << ushort(4) << 5.0 << false;
+ arg.endStructure();
+ QTest::newRow("structure") << qVariantFromValue(arg) << "(iunqdb)" << int(QDBusArgument::StructureType);
+
+#if 0
+ // this is now unsupported
+ arg << 1 << 2U << short(-3) << ushort(4) << 5.0 << false;
+ QTest::newRow("many-args") << qVariantFromValue(arg) << "(iunqdb)iunqdb";
+#endif
+}
+
+void tst_QDBusMarshall::sendBasic()
+{
+ QFETCH(QVariant, value);
+ QFETCH(QString, stringResult);
+
+ QDBusConnection con = QDBusConnection::sessionBus();
+
+ QVERIFY(con.isConnected());
+
+ QDBusMessage msg = QDBusMessage::createMethodCall(serviceName,
+ objectPath, interfaceName, "ping");
+ msg << value;
+
+ QDBusMessage reply = con.call(msg);
+ QVERIFY2(reply.type() == QDBusMessage::ReplyMessage,
+ qPrintable(reply.errorName() + ": " + reply.errorMessage()));
+ //qDebug() << reply;
+
+ QCOMPARE(reply.arguments().count(), msg.arguments().count());
+ QTEST(reply.signature(), "sig");
+ for (int i = 0; i < reply.arguments().count(); ++i) {
+ QVERIFY(compare(reply.arguments().at(i), msg.arguments().at(i)));
+ //printf("\n! %s\n* %s\n", qPrintable(qDBusArgumentToString(reply.arguments().at(i))), qPrintable(stringResult));
+ QCOMPARE(QDBusUtil::argumentToString(reply.arguments().at(i)), stringResult);
+ }
+}
+
+void tst_QDBusMarshall::sendVariant()
+{
+ QFETCH(QVariant, value);
+
+ QDBusConnection con = QDBusConnection::sessionBus();
+
+ QVERIFY(con.isConnected());
+
+ QDBusMessage msg = QDBusMessage::createMethodCall(serviceName,
+ objectPath, interfaceName, "ping");
+ msg << qVariantFromValue(QDBusVariant(value));
+
+ QDBusMessage reply = con.call(msg);
+ // qDebug() << reply;
+
+ QCOMPARE(reply.arguments().count(), msg.arguments().count());
+ QCOMPARE(reply.signature(), QString("v"));
+ for (int i = 0; i < reply.arguments().count(); ++i)
+ QVERIFY(compare(reply.arguments().at(i), msg.arguments().at(i)));
+}
+
+void tst_QDBusMarshall::sendArrays()
+{
+ sendBasic();
+}
+
+void tst_QDBusMarshall::sendArrayOfArrays()
+{
+ sendBasic();
+}
+
+void tst_QDBusMarshall::sendMaps()
+{
+ sendBasic();
+}
+
+void tst_QDBusMarshall::sendStructs()
+{
+ sendBasic();
+}
+
+void tst_QDBusMarshall::sendComplex()
+{
+ sendBasic();
+}
+
+void tst_QDBusMarshall::sendArgument()
+{
+ QFETCH(QVariant, value);
+ QFETCH(QString, sig);
+
+ QDBusConnection con = QDBusConnection::sessionBus();
+
+ QVERIFY(con.isConnected());
+
+ QDBusMessage msg = QDBusMessage::createMethodCall(serviceName, objectPath,
+ interfaceName, "ping");
+ msg << value;
+
+ QDBusMessage reply = con.call(msg);
+
+// QCOMPARE(reply.arguments().count(), msg.arguments().count());
+ QCOMPARE(reply.signature(), sig);
+// for (int i = 0; i < reply.arguments().count(); ++i)
+// QVERIFY(compare(reply.arguments().at(i), msg.arguments().at(i)));
+
+ // do it again inside a STRUCT now
+ QDBusArgument sendArg;
+ sendArg.beginStructure();
+ sendArg.appendVariant(value);
+ sendArg.endStructure();
+ msg.setArguments(QVariantList() << qVariantFromValue(sendArg));
+ reply = con.call(msg);
+
+ QCOMPARE(reply.signature(), QString("(%1)").arg(sig));
+ QCOMPARE(reply.arguments().at(0).userType(), qMetaTypeId<QDBusArgument>());
+
+ const QDBusArgument arg = qvariant_cast<QDBusArgument>(reply.arguments().at(0));
+ QCOMPARE(int(arg.currentType()), int(QDBusArgument::StructureType));
+
+ arg.beginStructure();
+ QVERIFY(!arg.atEnd());
+ QCOMPARE(arg.currentSignature(), sig);
+ QTEST(int(arg.currentType()), "classification");
+
+ QVariant extracted = arg.asVariant();
+ QVERIFY(arg.atEnd());
+
+ arg.endStructure();
+ QVERIFY(arg.atEnd());
+ QCOMPARE(arg.currentType(), QDBusArgument::UnknownType);
+
+ if (value.type() != QVariant::UserType)
+ QCOMPARE(extracted, value);
+}
+
+void tst_QDBusMarshall::sendSignalErrors()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+
+ QVERIFY(con.isConnected());
+ QDBusMessage msg = QDBusMessage::createSignal("/foo", "local.interfaceName",
+ "signalName");
+ msg << qVariantFromValue(QDBusObjectPath());
+
+ QTest::ignoreMessage(QtWarningMsg, "QDBusConnection: error: could not send signal path \"/foo\" interface \"local.interfaceName\" member \"signalName\": Marshalling failed: Invalid object path passed in arguments");
+ QVERIFY(!con.send(msg));
+
+ msg.setArguments(QVariantList());
+ QDBusObjectPath path;
+
+ QTest::ignoreMessage(QtWarningMsg, "QDBusObjectPath: invalid path \"abc\"");
+ path.setPath("abc");
+ msg << qVariantFromValue(path);
+
+ QTest::ignoreMessage(QtWarningMsg, "QDBusConnection: error: could not send signal path \"/foo\" interface \"local.interfaceName\" member \"signalName\": Marshalling failed: Invalid object path passed in arguments");
+ QVERIFY(!con.send(msg));
+
+ QDBusSignature sig;
+ msg.setArguments(QVariantList() << qVariantFromValue(sig));
+ QTest::ignoreMessage(QtWarningMsg, "QDBusConnection: error: could not send signal path \"/foo\" interface \"local.interfaceName\" member \"signalName\": Marshalling failed: Invalid signature passed in arguments");
+ QVERIFY(!con.send(msg));
+
+ QTest::ignoreMessage(QtWarningMsg, "QDBusSignature: invalid signature \"a\"");
+ sig.setSignature("a");
+ msg.setArguments(QVariantList());
+ msg << qVariantFromValue(sig);
+ QTest::ignoreMessage(QtWarningMsg, "QDBusConnection: error: could not send signal path \"/foo\" interface \"local.interfaceName\" member \"signalName\": Marshalling failed: Invalid signature passed in arguments");
+ QVERIFY(!con.send(msg));
+}
+
+void tst_QDBusMarshall::sendCallErrors_data()
+{
+ QTest::addColumn<QString>("service");
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<QString>("interface");
+ QTest::addColumn<QString>("method");
+ QTest::addColumn<QVariantList>("arguments");
+ QTest::addColumn<QString>("errorName");
+ QTest::addColumn<QString>("errorMsg");
+ QTest::addColumn<QString>("ignoreMsg");
+
+ // this error comes from the bus server
+ QTest::newRow("empty-service") << "" << objectPath << interfaceName << "ping" << QVariantList()
+ << "org.freedesktop.DBus.Error.UnknownMethod"
+ << "Method \"ping\" with signature \"\" on interface \"com.trolltech.autotests.qpong\" doesn't exist\n" << (const char*)0;
+
+ QTest::newRow("invalid-service") << "this isn't valid" << objectPath << interfaceName << "ping" << QVariantList()
+ << "com.trolltech.QtDBus.Error.InvalidService"
+ << "Invalid service name: this isn't valid" << "";
+
+ QTest::newRow("empty-path") << serviceName << "" << interfaceName << "ping" << QVariantList()
+ << "com.trolltech.QtDBus.Error.InvalidObjectPath"
+ << "Object path cannot be empty" << "";
+ QTest::newRow("invalid-path") << serviceName << "//" << interfaceName << "ping" << QVariantList()
+ << "com.trolltech.QtDBus.Error.InvalidObjectPath"
+ << "Invalid object path: //" << "";
+
+ // empty interfaces are valid
+ QTest::newRow("invalid-interface") << serviceName << objectPath << "this isn't valid" << "ping" << QVariantList()
+ << "com.trolltech.QtDBus.Error.InvalidInterface"
+ << "Invalid interface class: this isn't valid" << "";
+
+ QTest::newRow("empty-method") << serviceName << objectPath << interfaceName << "" << QVariantList()
+ << "com.trolltech.QtDBus.Error.InvalidMember"
+ << "method name cannot be empty" << "";
+ QTest::newRow("invalid-method") << serviceName << objectPath << interfaceName << "this isn't valid" << QVariantList()
+ << "com.trolltech.QtDBus.Error.InvalidMember"
+ << "Invalid method name: this isn't valid" << "";
+
+ QTest::newRow("invalid-variant1") << serviceName << objectPath << interfaceName << "ping"
+ << (QVariantList() << QVariant())
+ << "org.freedesktop.DBus.Error.Failed"
+ << "Marshalling failed: Variant containing QVariant::Invalid passed in arguments"
+ << "QDBusMarshaller: cannot add an invalid QVariant";
+ QTest::newRow("invalid-variant1") << serviceName << objectPath << interfaceName << "ping"
+ << (QVariantList() << qVariantFromValue(QDBusVariant()))
+ << "org.freedesktop.DBus.Error.Failed"
+ << "Marshalling failed: Variant containing QVariant::Invalid passed in arguments"
+ << "QDBusMarshaller: cannot add a null QDBusVariant";
+
+ QTest::newRow("builtin-unregistered") << serviceName << objectPath << interfaceName << "ping"
+ << (QVariantList() << QLocale::c())
+ << "org.freedesktop.DBus.Error.Failed"
+ << "Marshalling failed: Unregistered type QLocale passed in arguments"
+ << "QDBusMarshaller: type `QLocale' (18) is not registered with D-BUS. Use qDBusRegisterMetaType to register it";
+
+ // this type is known to the meta type system, but not registered with D-Bus
+ qRegisterMetaType<UnregisteredType>();
+ QTest::newRow("extra-unregistered") << serviceName << objectPath << interfaceName << "ping"
+ << (QVariantList() << qVariantFromValue(UnregisteredType()))
+ << "org.freedesktop.DBus.Error.Failed"
+ << "Marshalling failed: Unregistered type UnregisteredType passed in arguments"
+ << QString("QDBusMarshaller: type `UnregisteredType' (%1) is not registered with D-BUS. Use qDBusRegisterMetaType to register it")
+ .arg(qMetaTypeId<UnregisteredType>());
+
+ QTest::newRow("invalid-object-path-arg") << serviceName << objectPath << interfaceName << "ping"
+ << (QVariantList() << qVariantFromValue(QDBusObjectPath()))
+ << "org.freedesktop.DBus.Error.Failed"
+ << "Marshalling failed: Invalid object path passed in arguments"
+ << "";
+
+ QTest::newRow("invalid-signature-arg") << serviceName << objectPath << interfaceName << "ping"
+ << (QVariantList() << qVariantFromValue(QDBusSignature()))
+ << "org.freedesktop.DBus.Error.Failed"
+ << "Marshalling failed: Invalid signature passed in arguments"
+ << "";
+
+ // invalid file descriptor
+ if (fileDescriptorPassing) {
+ QTest::newRow("invalid-file-descriptor") << serviceName << objectPath << interfaceName << "ping"
+ << (QVariantList() << qVariantFromValue(QDBusUnixFileDescriptor(-1)))
+ << "org.freedesktop.DBus.Error.Failed"
+ << "Marshalling failed: Invalid file descriptor passed in arguments"
+ << "";
+ }
+}
+
+void tst_QDBusMarshall::sendCallErrors()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+
+ QFETCH(QString, service);
+ QFETCH(QString, path);
+ QFETCH(QString, interface);
+ QFETCH(QString, method);
+ QFETCH(QVariantList, arguments);
+ QFETCH(QString, errorMsg);
+
+ QFETCH(QString, ignoreMsg);
+ if (!ignoreMsg.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg, ignoreMsg.toLatin1());
+ if (!ignoreMsg.isNull())
+ QTest::ignoreMessage(QtWarningMsg,
+ QString("QDBusConnection: error: could not send message to service \"%1\" path \"%2\" interface \"%3\" member \"%4\": %5")
+ .arg(service, path, interface, method, errorMsg)
+ .toLatin1());
+
+ QDBusMessage msg = QDBusMessage::createMethodCall(service, path, interface, method);
+ msg.setArguments(arguments);
+
+ QDBusMessage reply = con.call(msg, QDBus::Block);
+ QCOMPARE(reply.type(), QDBusMessage::ErrorMessage);
+ QTEST(reply.errorName(), "errorName");
+ QCOMPARE(reply.errorMessage(), errorMsg);
+}
+
+void tst_QDBusMarshall::receiveUnknownType_data()
+{
+ QTest::addColumn<int>("receivedTypeId");
+ QTest::newRow("in-call") << qMetaTypeId<void*>();
+ QTest::newRow("type-variant") << qMetaTypeId<QDBusVariant>();
+ QTest::newRow("type-array") << qMetaTypeId<QDBusArgument>();
+ QTest::newRow("type-struct") << qMetaTypeId<QDBusArgument>();
+ QTest::newRow("type-naked") << qMetaTypeId<void *>();
+}
+
+struct DisconnectRawDBus {
+ static void cleanup(DBusConnection *connection)
+ {
+ if (!connection)
+ return;
+ dbus_connection_close(connection);
+ dbus_connection_unref(connection);
+ }
+};
+template <typename T, void (*unref)(T *)> struct GenericUnref
+{
+ static void cleanup(T *type)
+ {
+ if (!type) return;
+ unref(type);
+ }
+};
+
+// use these scoped types to avoid memory leaks if QVERIFY or QCOMPARE fails
+typedef QScopedPointer<DBusConnection, DisconnectRawDBus> ScopedDBusConnection;
+typedef QScopedPointer<DBusMessage, GenericUnref<DBusMessage, dbus_message_unref> > ScopedDBusMessage;
+typedef QScopedPointer<DBusPendingCall, GenericUnref<DBusPendingCall, dbus_pending_call_unref> > ScopedDBusPendingCall;
+
+template <typename T> struct SetResetValue
+{
+ const T oldValue;
+ T &value;
+public:
+ SetResetValue(T &v, T newValue) : oldValue(v), value(v)
+ {
+ value = newValue;
+ }
+ ~SetResetValue()
+ {
+ value = oldValue;
+ }
+};
+
+void tst_QDBusMarshall::receiveUnknownType()
+{
+#ifndef DBUS_TYPE_UNIX_FD
+ QSKIP("Your system's D-Bus library is too old for this test", SkipAll);
+#else
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+
+ // this needs to be implemented in raw
+ // open a new connection to the bus daemon
+ DBusError error;
+ dbus_error_init(&error);
+ ScopedDBusConnection rawcon(dbus_bus_get_private(DBUS_BUS_SESSION, &error));
+ QVERIFY2(rawcon.data(), error.name);
+
+ // check if this bus supports passing file descriptors
+ if (!dbus_connection_can_send_type(rawcon.data(), DBUS_TYPE_UNIX_FD))
+ QSKIP("Your session bus does not allow sending Unix file descriptors", SkipAll);
+
+ // make sure this QDBusConnection won't handle Unix file descriptors
+ QDBusConnection::ConnectionCapabilities &capabRef = QDBusConnectionPrivate::d(con)->capabilities;
+ SetResetValue<QDBusConnection::ConnectionCapabilities> resetter(capabRef, capabRef & ~QDBusConnection::UnixFileDescriptorPassing);
+
+ if (qstrcmp(QTest::currentDataTag(), "in-call") == 0) {
+ // create a call back to us containing a file descriptor
+ QDBusMessageSpy spy;
+ con.registerObject("/spyObject", &spy, QDBusConnection::ExportAllSlots);
+ ScopedDBusMessage msg(dbus_message_new_method_call(con.baseService().toLatin1(), "/spyObject", NULL, "theSlot"));
+
+ int fd = fileno(stdout);
+ dbus_message_append_args(msg.data(), DBUS_TYPE_UNIX_FD, &fd, DBUS_TYPE_INVALID);
+
+ // try to send to us
+ DBusPendingCall *pending_ptr;
+ dbus_connection_send_with_reply(rawcon.data(), msg.data(), &pending_ptr, 1000);
+ ScopedDBusPendingCall pending(pending_ptr);
+
+ // check that it got sent
+ while (dbus_connection_dispatch(rawcon.data()) == DBUS_DISPATCH_DATA_REMAINS)
+ ;
+
+ // now spin our event loop. We don't catch this call, so let's get the reply
+ QEventLoop loop;
+ QTimer::singleShot(200, &loop, SLOT(quit()));
+ loop.exec();
+
+ // now try to receive the reply
+ dbus_pending_call_block(pending.data());
+
+ // check that the spy received what it was supposed to receive
+ QCOMPARE(spy.list.size(), 1);
+ QCOMPARE(spy.list.at(0).arguments().size(), 1);
+ QFETCH(int, receivedTypeId);
+ QCOMPARE(spy.list.at(0).arguments().at(0).userType(), receivedTypeId);
+
+ msg.reset(dbus_pending_call_steal_reply(pending.data()));
+ QVERIFY(msg);
+ QCOMPARE(dbus_message_get_type(msg.data()), DBUS_MESSAGE_TYPE_METHOD_RETURN);
+ QCOMPARE(dbus_message_get_signature(msg.data()), DBUS_TYPE_INT32_AS_STRING);
+
+ int retval;
+ QVERIFY(dbus_message_get_args(msg.data(), &error, DBUS_TYPE_INT32, &retval, DBUS_TYPE_INVALID));
+ QCOMPARE(retval, 42);
+ } else {
+ // create a signal that we'll emit
+ static const char signalName[] = "signalName";
+ static const char interfaceName[] = "local.interface.name";
+ ScopedDBusMessage msg(dbus_message_new_signal("/", interfaceName, signalName));
+ con.connect(dbus_bus_get_unique_name(rawcon.data()), QString(), interfaceName, signalName, &QTestEventLoop::instance(), SLOT(exitLoop()));
+
+ QDBusMessageSpy spy;
+ con.connect(dbus_bus_get_unique_name(rawcon.data()), QString(), interfaceName, signalName, &spy, SLOT(theSlot(QDBusMessage)));
+
+ DBusMessageIter iter;
+ dbus_message_iter_init_append(msg.data(), &iter);
+ int fd = fileno(stdout);
+
+ if (qstrcmp(QTest::currentDataTag(), "type-naked") == 0) {
+ // send naked
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_UNIX_FD, &fd);
+ } else {
+ DBusMessageIter subiter;
+ if (qstrcmp(QTest::currentDataTag(), "type-variant") == 0)
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, DBUS_TYPE_UNIX_FD_AS_STRING, &subiter);
+ else if (qstrcmp(QTest::currentDataTag(), "type-array") == 0)
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_UNIX_FD_AS_STRING, &subiter);
+ else if (qstrcmp(QTest::currentDataTag(), "type-struct") == 0)
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, 0, &subiter);
+ dbus_message_iter_append_basic(&subiter, DBUS_TYPE_UNIX_FD, &fd);
+ dbus_message_iter_close_container(&iter, &subiter);
+ }
+
+ // send it
+ dbus_connection_send(rawcon.data(), msg.data(), 0);
+
+ // check that it got sent
+ while (dbus_connection_dispatch(rawcon.data()) == DBUS_DISPATCH_DATA_REMAINS)
+ ;
+
+ // now let's see what happens
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+ QCOMPARE(spy.list.size(), 1);
+ QCOMPARE(spy.list.at(0).arguments().count(), 1);
+ QFETCH(int, receivedTypeId);
+ //qDebug() << spy.list.at(0).arguments().at(0).typeName();
+ QCOMPARE(spy.list.at(0).arguments().at(0).userType(), receivedTypeId);
+ }
+#endif
+}
+
+QTEST_MAIN(tst_QDBusMarshall)
+#include "tst_qdbusmarshall.moc"
diff --git a/tests/auto/dbus/qdbusmetaobject/.gitignore b/tests/auto/dbus/qdbusmetaobject/.gitignore
new file mode 100644
index 0000000000..6696c0def7
--- /dev/null
+++ b/tests/auto/dbus/qdbusmetaobject/.gitignore
@@ -0,0 +1 @@
+tst_qdbusmetaobject
diff --git a/tests/auto/dbus/qdbusmetaobject/qdbusmetaobject.pro b/tests/auto/dbus/qdbusmetaobject/qdbusmetaobject.pro
new file mode 100644
index 0000000000..fa59c06c8e
--- /dev/null
+++ b/tests/auto/dbus/qdbusmetaobject/qdbusmetaobject.pro
@@ -0,0 +1,10 @@
+load(qttest_p4)
+QT = core
+contains(QT_CONFIG,dbus): {
+ SOURCES += tst_qdbusmetaobject.cpp
+ QT += dbus dbus-private
+} else {
+ SOURCES += ../qdbusmarshall/dummy.cpp
+}
+
+
diff --git a/tests/auto/dbus/qdbusmetaobject/tst_qdbusmetaobject.cpp b/tests/auto/dbus/qdbusmetaobject/tst_qdbusmetaobject.cpp
new file mode 100644
index 0000000000..7711e819a0
--- /dev/null
+++ b/tests/auto/dbus/qdbusmetaobject/tst_qdbusmetaobject.cpp
@@ -0,0 +1,688 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qcoreapplication.h>
+#include <qmetatype.h>
+#include <QtTest/QtTest>
+
+#include <QtDBus/QtDBus>
+#include <private/qdbusmetaobject_p.h>
+
+class tst_QDBusMetaObject: public QObject
+{
+ Q_OBJECT
+
+ QHash<QString, QDBusMetaObject *> map;
+public slots:
+ void init();
+
+private slots:
+ void initTestCase();
+ void types_data();
+ void types();
+ void methods_data();
+ void methods();
+ void _signals_data();
+ void _signals();
+ void properties_data();
+ void properties();
+};
+
+typedef QPair<QString,QString> StringPair;
+
+struct Struct1 { }; // (s)
+struct Struct4 // (ssa(ss)sayasx)
+{
+ QString m1;
+ QString m2;
+ QList<StringPair> m3;
+ QString m4;
+ QByteArray m5;
+ QStringList m6;
+ qlonglong m7;
+};
+
+Q_DECLARE_METATYPE(Struct1)
+Q_DECLARE_METATYPE(Struct4)
+Q_DECLARE_METATYPE(StringPair)
+
+Q_DECLARE_METATYPE(QList<Struct1>)
+Q_DECLARE_METATYPE(QList<Struct4>)
+
+Q_DECLARE_METATYPE(const QMetaObject*)
+
+QT_BEGIN_NAMESPACE
+QDBusArgument &operator<<(QDBusArgument &arg, const Struct1 &)
+{
+ arg.beginStructure();
+ arg << QString();
+ arg.endStructure();
+ return arg;
+}
+
+QDBusArgument &operator<<(QDBusArgument &arg, const StringPair &s)
+{
+ arg.beginStructure();
+ arg << s.first << s.second;
+ arg.endStructure();
+ return arg;
+}
+
+QDBusArgument &operator<<(QDBusArgument &arg, const Struct4 &s)
+{
+ arg.beginStructure();
+ arg << s.m1 << s.m2 << s.m3 << s.m4 << s.m5 << s.m6 << s.m7;
+ arg.endStructure();
+ return arg;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &arg, Struct1 &)
+{ return arg; }
+const QDBusArgument &operator>>(const QDBusArgument &arg, Struct4 &)
+{ return arg; }
+const QDBusArgument &operator>>(const QDBusArgument &arg, StringPair &)
+{ return arg; }
+QT_END_NAMESPACE
+
+void tst_QDBusMetaObject::initTestCase()
+{
+ qDBusRegisterMetaType<Struct1>();
+ qDBusRegisterMetaType<Struct4>();
+ qDBusRegisterMetaType<StringPair>();
+
+ qDBusRegisterMetaType<QList<Struct1> >();
+ qDBusRegisterMetaType<QList<Struct4> >();
+}
+
+void tst_QDBusMetaObject::init()
+{
+ qDeleteAll(map);
+ map.clear();
+}
+
+// test classes
+class TypesTest1: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(uchar);
+};
+const char TypesTest1_xml[] =
+ "<signal name=\"signal\"><arg type=\"y\"/></signal>";
+
+class TypesTest2: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(bool);
+};
+const char TypesTest2_xml[] =
+ "<signal name=\"signal\"><arg type=\"b\"/></signal>";
+
+class TypesTest3: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(short);
+};
+const char TypesTest3_xml[] =
+ "<signal name=\"signal\"><arg type=\"n\"/></signal>";
+
+class TypesTest4: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(ushort);
+};
+const char TypesTest4_xml[] =
+ "<signal name=\"signal\"><arg type=\"q\"/></signal>";
+
+class TypesTest5: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(int);
+};
+const char TypesTest5_xml[] =
+ "<signal name=\"signal\"><arg type=\"i\"/></signal>";
+
+class TypesTest6: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(uint);
+};
+const char TypesTest6_xml[] =
+ "<signal name=\"signal\"><arg type=\"u\"/></signal>";
+
+class TypesTest7: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(qlonglong);
+};
+const char TypesTest7_xml[] =
+ "<signal name=\"signal\"><arg type=\"x\"/></signal>";
+
+class TypesTest8: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(qulonglong);
+};
+const char TypesTest8_xml[] =
+ "<signal name=\"signal\"><arg type=\"t\"/></signal>";
+
+class TypesTest9: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(double);
+};
+const char TypesTest9_xml[] =
+ "<signal name=\"signal\"><arg type=\"d\"/></signal>";
+
+class TypesTest10: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(QString);
+};
+const char TypesTest10_xml[] =
+ "<signal name=\"signal\"><arg type=\"s\"/></signal>";
+
+class TypesTest11: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(QDBusObjectPath);
+};
+const char TypesTest11_xml[] =
+ "<signal name=\"signal\"><arg type=\"o\"/></signal>";
+
+class TypesTest12: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(QDBusSignature);
+};
+const char TypesTest12_xml[] =
+ "<signal name=\"signal\"><arg type=\"g\"/></signal>";
+
+class TypesTest13: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(QDBusVariant);
+};
+const char TypesTest13_xml[] =
+ "<signal name=\"signal\"><arg type=\"v\"/></signal>";
+
+class TypesTest14: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(QStringList);
+};
+const char TypesTest14_xml[] =
+ "<signal name=\"signal\"><arg type=\"as\"/></signal>";
+
+class TypesTest15: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(QByteArray);
+};
+const char TypesTest15_xml[] =
+ "<signal name=\"signal\"><arg type=\"ay\"/></signal>";
+
+class TypesTest16: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(StringPair);
+};
+const char TypesTest16_xml[] =
+ "<signal name=\"signal\"><arg type=\"(ss)\"/>"
+ "<annotation name=\"com.trolltech.QtDBus.QtTypeName.Out0\" value=\"StringPair\"></signal>";
+
+class TypesTest17: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(Struct1);
+};
+const char TypesTest17_xml[] =
+ "<signal name=\"signal\"><arg type=\"(s)\"/>"
+ "<annotation name=\"com.trolltech.QtDBus.QtTypeName.Out0\" value=\"Struct1\"></signal>";
+
+class TypesTest18: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(Struct4);
+};
+const char TypesTest18_xml[] =
+ "<signal name=\"signal\"><arg type=\"(ssa(ss)sayasx)\"/>"
+ "<annotation name=\"com.trolltech.QtDBus.QtTypeName.Out0\" value=\"Struct4\"></signal>";
+
+class TypesTest19: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(QVariantList);
+};
+const char TypesTest19_xml[] =
+ "<signal name=\"signal\"><arg type=\"av\"/>"
+ "<annotation name=\"com.trolltech.QtDBus.QtTypeName.Out0\" value=\"QVariantList\"></signal>";
+
+class TypesTest20: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(QVariantMap);
+};
+const char TypesTest20_xml[] =
+ "<signal name=\"signal\"><arg type=\"a{sv}\"/>"
+ "<annotation name=\"com.trolltech.QtDBus.QtTypeName.Out0\" value=\"QVariantMap\"></signal>";
+
+void tst_QDBusMetaObject::types_data()
+{
+ QTest::addColumn<const QMetaObject *>("metaobject");
+ QTest::addColumn<QString>("xml");
+
+ QTest::newRow("byte") << &TypesTest1::staticMetaObject << QString(TypesTest1_xml);
+ QTest::newRow("bool") << &TypesTest2::staticMetaObject << QString(TypesTest2_xml);
+ QTest::newRow("short") << &TypesTest3::staticMetaObject << QString(TypesTest3_xml);
+ QTest::newRow("ushort") << &TypesTest4::staticMetaObject << QString(TypesTest4_xml);
+ QTest::newRow("int") << &TypesTest5::staticMetaObject << QString(TypesTest5_xml);
+ QTest::newRow("uint") << &TypesTest6::staticMetaObject << QString(TypesTest6_xml);
+ QTest::newRow("qlonglong") << &TypesTest7::staticMetaObject << QString(TypesTest7_xml);
+ QTest::newRow("qulonglong") << &TypesTest8::staticMetaObject << QString(TypesTest8_xml);
+ QTest::newRow("double") << &TypesTest9::staticMetaObject << QString(TypesTest9_xml);
+ QTest::newRow("QString") << &TypesTest10::staticMetaObject << QString(TypesTest10_xml);
+ QTest::newRow("QDBusObjectPath") << &TypesTest11::staticMetaObject << QString(TypesTest11_xml);
+ QTest::newRow("QDBusSignature") << &TypesTest12::staticMetaObject << QString(TypesTest12_xml);
+ QTest::newRow("QDBusVariant") << &TypesTest13::staticMetaObject << QString(TypesTest13_xml);
+ QTest::newRow("QStringList") << &TypesTest14::staticMetaObject << QString(TypesTest14_xml);
+ QTest::newRow("QByteArray") << &TypesTest15::staticMetaObject << QString(TypesTest15_xml);
+ QTest::newRow("StringPair") << &TypesTest16::staticMetaObject << QString(TypesTest16_xml);
+ QTest::newRow("Struct1") << &TypesTest17::staticMetaObject << QString(TypesTest17_xml);
+ QTest::newRow("Struct4") << &TypesTest18::staticMetaObject << QString(TypesTest18_xml);
+ QTest::newRow("QVariantList") << &TypesTest19::staticMetaObject << QString(TypesTest19_xml);
+ QTest::newRow("QVariantMap") << &TypesTest20::staticMetaObject << QString(TypesTest20_xml);
+}
+
+void tst_QDBusMetaObject::types()
+{
+ QFETCH(const QMetaObject*, metaobject);
+ QFETCH(QString, xml);
+
+ // add the rest of the XML tags
+ xml = QString("<node><interface name=\"local.Interface\">%1</interface></node>")
+ .arg(xml);
+
+ QDBusError error;
+
+ QMetaObject *result = QDBusMetaObject::createMetaObject("local.Interface", xml,
+ map, error);
+ QVERIFY2(result, qPrintable(error.message()));
+
+ QCOMPARE(result->enumeratorCount(), 0);
+ QCOMPARE(result->classInfoCount(), 0);
+
+ // compare the meta objects
+ QCOMPARE(result->methodCount() - result->methodOffset(),
+ metaobject->methodCount() - metaobject->methodOffset());
+ QCOMPARE(result->propertyCount() - result->propertyOffset(),
+ metaobject->propertyCount() - metaobject->propertyOffset());
+
+ for (int i = metaobject->methodOffset(); i < metaobject->methodCount(); ++i) {
+ QMetaMethod expected = metaobject->method(i);
+
+ int methodIdx = result->indexOfMethod(expected.signature());
+ QVERIFY(methodIdx != -1);
+ QMetaMethod constructed = result->method(methodIdx);
+
+ QCOMPARE(int(constructed.access()), int(expected.access()));
+ QCOMPARE(int(constructed.methodType()), int(expected.methodType()));
+ QCOMPARE(constructed.parameterNames(), expected.parameterNames());
+ QCOMPARE(constructed.parameterTypes(), expected.parameterTypes());
+ QCOMPARE(constructed.tag(), expected.tag());
+ QCOMPARE(constructed.typeName(), expected.typeName());
+ }
+
+ for (int i = metaobject->propertyOffset(); i < metaobject->propertyCount(); ++i) {
+ QMetaProperty expected = metaobject->property(i);
+
+ int propIdx = result->indexOfProperty(expected.name());
+ QVERIFY(propIdx != -1);
+ QMetaProperty constructed = result->property(propIdx);
+
+ QCOMPARE(constructed.isDesignable(), expected.isDesignable());
+ QCOMPARE(constructed.isEditable(), expected.isEditable());
+ QCOMPARE(constructed.isEnumType(), expected.isEnumType());
+ QCOMPARE(constructed.isFlagType(), expected.isFlagType());
+ QCOMPARE(constructed.isReadable(), expected.isReadable());
+ QCOMPARE(constructed.isResettable(), expected.isResettable());
+ QCOMPARE(constructed.isScriptable(), expected.isScriptable());
+ QCOMPARE(constructed.isStored(), expected.isStored());
+ QCOMPARE(constructed.isUser(), expected.isUser());
+ QCOMPARE(constructed.isWritable(), expected.isWritable());
+ QCOMPARE(constructed.typeName(), expected.typeName());
+ }
+}
+
+class MethodTest1: public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void method() { }
+};
+const char MethodTest1_xml[] =
+ "<method name=\"method\" />";
+
+class MethodTest2: public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void method(int) { }
+};
+const char MethodTest2_xml[] =
+ "<method name=\"method\"><arg direction=\"in\" type=\"i\"/></method>";
+
+class MethodTest3: public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void method(int input0) { Q_UNUSED(input0); }
+};
+const char MethodTest3_xml[] =
+ "<method name=\"method\"><arg direction=\"in\" type=\"i\" name=\"input0\"/></method>";
+
+class MethodTest4: public QObject
+{
+ Q_OBJECT
+
+public slots:
+ int method() { return 0; }
+};
+const char MethodTest4_xml[] =
+ "<method name=\"method\"><arg direction=\"out\" type=\"i\"/></method>";
+const char MethodTest4_xml2[] =
+ "<method name=\"method\"><arg direction=\"out\" type=\"i\" name=\"thisShouldNeverBeSeen\"/></method>";
+
+class MethodTest5: public QObject
+{
+ Q_OBJECT
+
+public slots:
+ int method(int input0) { return input0; }
+};
+const char MethodTest5_xml[] =
+ "<method name=\"method\">"
+ "<arg direction=\"in\" type=\"i\" name=\"input0\"/>"
+ "<arg direction=\"out\" type=\"i\"/>"
+ "</method>";
+
+class MethodTest6: public QObject
+{
+ Q_OBJECT
+
+public slots:
+ int method(int input0, int input1) { Q_UNUSED(input0); return input1; }
+};
+const char MethodTest6_xml[] =
+ "<method name=\"method\">"
+ "<arg direction=\"in\" type=\"i\" name=\"input0\"/>"
+ "<arg direction=\"out\" type=\"i\"/>"
+ "<arg direction=\"in\" type=\"i\" name=\"input1\"/>"
+ "</method>";
+
+class MethodTest7: public QObject
+{
+ Q_OBJECT
+
+public slots:
+ int method(int input0, int input1, int &output1) { output1 = input1; return input0; }
+};
+const char MethodTest7_xml[] =
+ "<method name=\"method\">"
+ "<arg direction=\"in\" type=\"i\" name=\"input0\"/>"
+ "<arg direction=\"in\" type=\"i\" name=\"input1\"/>"
+ "<arg direction=\"out\" type=\"i\"/>"
+ "<arg direction=\"out\" type=\"i\" name=\"output1\"/>"
+ "</method>";
+
+class MethodTest8: public QObject
+{
+ Q_OBJECT
+
+public slots:
+ int method(int input0, int input1, int &output1, int &output2) { output1 = output2 = input1; return input0; }
+};
+const char MethodTest8_xml[] =
+ "<method name=\"method\">"
+ "<arg direction=\"in\" type=\"i\" name=\"input0\"/>"
+ "<arg direction=\"in\" type=\"i\" name=\"input1\"/>"
+ "<arg direction=\"out\" type=\"i\"/>"
+ "<arg direction=\"out\" type=\"i\" name=\"output1\"/>"
+ "<arg direction=\"out\" type=\"i\" name=\"output2\"/>"
+ "</method>";
+
+class MethodTest9: public QObject
+{
+ Q_OBJECT
+
+public slots:
+ Q_NOREPLY void method(int) { }
+};
+const char MethodTest9_xml[] =
+ "<method name=\"method\">"
+ "<arg direction=\"in\" type=\"i\"/>"
+ "<annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>"
+ "</method>";
+
+void tst_QDBusMetaObject::methods_data()
+{
+ QTest::addColumn<const QMetaObject *>("metaobject");
+ QTest::addColumn<QString>("xml");
+
+ QTest::newRow("void-void") << &MethodTest1::staticMetaObject << QString(MethodTest1_xml);
+ QTest::newRow("void-int") << &MethodTest2::staticMetaObject << QString(MethodTest2_xml);
+ QTest::newRow("void-int-with-name") << &MethodTest3::staticMetaObject << QString(MethodTest3_xml);
+ QTest::newRow("int-void") << &MethodTest4::staticMetaObject << QString(MethodTest4_xml);
+ QTest::newRow("int-void2") << &MethodTest4::staticMetaObject << QString(MethodTest4_xml2);
+ QTest::newRow("int-int") << &MethodTest5::staticMetaObject << QString(MethodTest5_xml);
+ QTest::newRow("int-int,int") << &MethodTest6::staticMetaObject << QString(MethodTest6_xml);
+ QTest::newRow("int,int-int,int") << &MethodTest7::staticMetaObject << QString(MethodTest7_xml);
+ QTest::newRow("int,int,int-int,int") << &MethodTest8::staticMetaObject << QString(MethodTest8_xml);
+ QTest::newRow("Q_ASYNC") << &MethodTest9::staticMetaObject << QString(MethodTest9_xml);
+}
+
+void tst_QDBusMetaObject::methods()
+{
+ types();
+}
+
+class SignalTest1: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal();
+};
+const char SignalTest1_xml[] =
+ "<signal name=\"signal\" />";
+
+class SignalTest2: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(int);
+};
+const char SignalTest2_xml[] =
+ "<signal name=\"signal\"><arg type=\"i\"/></signal>";
+
+class SignalTest3: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(int output0);
+};
+const char SignalTest3_xml[] =
+ "<signal name=\"signal\"><arg type=\"i\" name=\"output0\"/></signal>";
+
+class SignalTest4: public QObject
+{
+ Q_OBJECT
+
+signals:
+ void signal(int output0, int);
+};
+const char SignalTest4_xml[] =
+ "<signal name=\"signal\"><arg type=\"i\" name=\"output0\"/><arg type=\"i\"/></signal>";
+
+void tst_QDBusMetaObject::_signals_data()
+{
+ QTest::addColumn<const QMetaObject *>("metaobject");
+ QTest::addColumn<QString>("xml");
+
+ QTest::newRow("empty") << &SignalTest1::staticMetaObject << QString(SignalTest1_xml);
+ QTest::newRow("int") << &SignalTest2::staticMetaObject << QString(SignalTest2_xml);
+ QTest::newRow("int output0") << &SignalTest3::staticMetaObject << QString(SignalTest3_xml);
+ QTest::newRow("int output0,int") << &SignalTest4::staticMetaObject << QString(SignalTest4_xml);
+}
+
+void tst_QDBusMetaObject::_signals()
+{
+ types();
+}
+
+class PropertyTest1: public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int property READ property)
+public:
+ int property() { return 0; }
+ void setProperty(int) { }
+};
+const char PropertyTest1_xml[] =
+ "<property name=\"property\" type=\"i\" access=\"read\"/>";
+
+class PropertyTest2: public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int property READ property WRITE setProperty)
+public:
+ int property() { return 0; }
+ void setProperty(int) { }
+};
+const char PropertyTest2_xml[] =
+ "<property name=\"property\" type=\"i\" access=\"readwrite\"/>";
+
+class PropertyTest3: public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int property WRITE setProperty)
+public:
+ int property() { return 0; }
+ void setProperty(int) { }
+};
+const char PropertyTest3_xml[] =
+ "<property name=\"property\" type=\"i\" access=\"write\"/>";
+
+class PropertyTest4: public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(Struct1 property WRITE setProperty)
+public:
+ Struct1 property() { return Struct1(); }
+ void setProperty(Struct1) { }
+};
+const char PropertyTest4_xml[] =
+ "<property name=\"property\" type=\"(s)\" access=\"write\">"
+ "<annotation name=\"com.trolltech.QtDBus.QtTypeName\" value=\"Struct1\"/>"
+ "</property>";
+
+void tst_QDBusMetaObject::properties_data()
+{
+ QTest::addColumn<const QMetaObject *>("metaobject");
+ QTest::addColumn<QString>("xml");
+
+ QTest::newRow("read") << &PropertyTest1::staticMetaObject << QString(PropertyTest1_xml);
+ QTest::newRow("readwrite") << &PropertyTest2::staticMetaObject << QString(PropertyTest2_xml);
+ QTest::newRow("write") << &PropertyTest3::staticMetaObject << QString(PropertyTest3_xml);
+ QTest::newRow("customtype") << &PropertyTest4::staticMetaObject << QString(PropertyTest4_xml);
+}
+
+void tst_QDBusMetaObject::properties()
+{
+ types();
+}
+
+
+QTEST_MAIN(tst_QDBusMetaObject)
+#include "tst_qdbusmetaobject.moc"
diff --git a/tests/auto/dbus/qdbusmetatype/.gitignore b/tests/auto/dbus/qdbusmetatype/.gitignore
new file mode 100644
index 0000000000..75de5c26cf
--- /dev/null
+++ b/tests/auto/dbus/qdbusmetatype/.gitignore
@@ -0,0 +1 @@
+tst_qdbusmetatype
diff --git a/tests/auto/dbus/qdbusmetatype/qdbusmetatype.pro b/tests/auto/dbus/qdbusmetatype/qdbusmetatype.pro
new file mode 100644
index 0000000000..da8fbec01a
--- /dev/null
+++ b/tests/auto/dbus/qdbusmetatype/qdbusmetatype.pro
@@ -0,0 +1,10 @@
+load(qttest_p4)
+QT = core
+contains(QT_CONFIG,dbus): {
+ SOURCES += tst_qdbusmetatype.cpp
+ QT += dbus
+} else {
+ SOURCES += ../qdbusmarshall/dummy.cpp
+}
+
+
diff --git a/tests/auto/dbus/qdbusmetatype/tst_qdbusmetatype.cpp b/tests/auto/dbus/qdbusmetatype/tst_qdbusmetatype.cpp
new file mode 100644
index 0000000000..7e1f651a1b
--- /dev/null
+++ b/tests/auto/dbus/qdbusmetatype/tst_qdbusmetatype.cpp
@@ -0,0 +1,383 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qcoreapplication.h>
+#include <qmetatype.h>
+#include <QtTest/QtTest>
+
+#include <QtDBus/QtDBus>
+
+class tst_QDBusMetaType: public QObject
+{
+ Q_OBJECT
+public:
+ int intStringMap;
+ int stringStringMap;
+ int stringStruct1Map;
+
+private slots:
+ void initTestCase();
+ void staticTypes_data();
+ void staticTypes();
+ void dynamicTypes_data();
+ void dynamicTypes();
+ void invalidTypes_data();
+ void invalidTypes();
+};
+
+typedef QPair<QString,QString> StringPair;
+
+struct Struct1 { }; // (s)
+struct Struct2 { }; // (sos)
+struct Struct3 { }; // (sas)
+struct Struct4 // (ssa(ss)sayasx)
+{
+ QString m1;
+ QString m2;
+ QList<StringPair> m3;
+ QString m4;
+ QByteArray m5;
+ QStringList m6;
+ qlonglong m7;
+};
+
+struct Invalid0 { }; // empty
+struct Invalid1 { }; // s
+struct Invalid2 { }; // o
+struct Invalid3 { }; // as
+struct Invalid4 { }; // ay
+struct Invalid5 { }; // ii
+struct Invalid6 { }; // <invalid>
+struct Invalid7 { }; // (<invalid>)
+
+Q_DECLARE_METATYPE(Struct1)
+Q_DECLARE_METATYPE(Struct2)
+Q_DECLARE_METATYPE(Struct3)
+Q_DECLARE_METATYPE(Struct4)
+Q_DECLARE_METATYPE(StringPair)
+
+Q_DECLARE_METATYPE(QList<Struct1>)
+Q_DECLARE_METATYPE(QList<Struct2>)
+Q_DECLARE_METATYPE(QList<Struct3>)
+Q_DECLARE_METATYPE(QList<Struct4>)
+
+Q_DECLARE_METATYPE(Invalid0)
+Q_DECLARE_METATYPE(Invalid1)
+Q_DECLARE_METATYPE(Invalid2)
+Q_DECLARE_METATYPE(Invalid3)
+Q_DECLARE_METATYPE(Invalid4)
+Q_DECLARE_METATYPE(Invalid5)
+Q_DECLARE_METATYPE(Invalid6)
+Q_DECLARE_METATYPE(Invalid7)
+
+Q_DECLARE_METATYPE(QList<Invalid0>)
+
+typedef QMap<int, QString> IntStringMap;
+typedef QMap<QString, QString> StringStringMap;
+typedef QMap<QString, Struct1> StringStruct1Map;
+Q_DECLARE_METATYPE(IntStringMap)
+Q_DECLARE_METATYPE(StringStringMap)
+Q_DECLARE_METATYPE(StringStruct1Map)
+
+Q_DECLARE_METATYPE(QVariant::Type)
+
+QT_BEGIN_NAMESPACE
+QDBusArgument &operator<<(QDBusArgument &arg, const Struct1 &)
+{
+ arg.beginStructure();
+ arg << QString();
+ arg.endStructure();
+ return arg;
+}
+
+QDBusArgument &operator<<(QDBusArgument &arg, const Struct2 &)
+{
+ arg.beginStructure();
+ arg << QString() << QDBusObjectPath() << QString();
+ arg.endStructure();
+ return arg;
+}
+
+QDBusArgument &operator<<(QDBusArgument &arg, const Struct3 &)
+{
+ arg.beginStructure();
+ arg << QString() << QStringList();
+ arg.endStructure();
+ return arg;
+}
+
+QDBusArgument &operator<<(QDBusArgument &arg, const StringPair &s)
+{
+ arg.beginStructure();
+ arg << s.first << s.second;
+ arg.endStructure();
+ return arg;
+}
+
+QDBusArgument &operator<<(QDBusArgument &arg, const Struct4 &s)
+{
+ arg.beginStructure();
+ arg << s.m1 << s.m2 << s.m3 << s.m4 << s.m5 << s.m6 << s.m7;
+ arg.endStructure();
+ return arg;
+}
+
+QDBusArgument &operator<<(QDBusArgument &arg, const Invalid0 &)
+{
+ return arg;
+}
+
+QDBusArgument &operator<<(QDBusArgument &arg, const Invalid1 &)
+{
+ arg << QString();
+ return arg;
+}
+
+QDBusArgument &operator<<(QDBusArgument &arg, const Invalid2 &)
+{
+ arg << QDBusObjectPath();
+ return arg;
+}
+
+QDBusArgument &operator<<(QDBusArgument &arg, const Invalid3 &)
+{
+ arg << QStringList();
+ return arg;
+}
+
+QDBusArgument &operator<<(QDBusArgument &arg, const Invalid4 &)
+{
+ arg << QByteArray();
+ return arg;
+}
+
+QDBusArgument &operator<<(QDBusArgument &arg, const Invalid5 &)
+{
+ arg << 1 << 2;
+ return arg;
+}
+
+// no Invalid6
+
+QDBusArgument &operator<<(QDBusArgument &arg, const Invalid7 &)
+{
+ arg.beginStructure();
+ arg << Invalid0();
+ arg.endStructure();
+ return arg;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &arg, Struct1 &)
+{ return arg; }
+const QDBusArgument &operator>>(const QDBusArgument &arg, Struct2 &)
+{ return arg; }
+const QDBusArgument &operator>>(const QDBusArgument &arg, Struct3 &)
+{ return arg; }
+const QDBusArgument &operator>>(const QDBusArgument &arg, Struct4 &)
+{ return arg; }
+const QDBusArgument &operator>>(const QDBusArgument &arg, StringPair &)
+{ return arg; }
+const QDBusArgument &operator>>(const QDBusArgument &arg, Invalid0 &)
+{ return arg; }
+const QDBusArgument &operator>>(const QDBusArgument &arg, Invalid1 &)
+{ return arg; }
+const QDBusArgument &operator>>(const QDBusArgument &arg, Invalid2 &)
+{ return arg; }
+const QDBusArgument &operator>>(const QDBusArgument &arg, Invalid3 &)
+{ return arg; }
+const QDBusArgument &operator>>(const QDBusArgument &arg, Invalid4 &)
+{ return arg; }
+const QDBusArgument &operator>>(const QDBusArgument &arg, Invalid5 &)
+{ return arg; }
+const QDBusArgument &operator>>(const QDBusArgument &arg, Invalid6 &)
+{ return arg; }
+const QDBusArgument &operator>>(const QDBusArgument &arg, Invalid7 &)
+{ return arg; }
+QT_END_NAMESPACE
+
+void tst_QDBusMetaType::initTestCase()
+{
+ qDBusRegisterMetaType<Struct1>();
+ qDBusRegisterMetaType<Struct2>();
+ qDBusRegisterMetaType<Struct3>();
+ qDBusRegisterMetaType<Struct4>();
+ qDBusRegisterMetaType<StringPair>();
+
+ qDBusRegisterMetaType<QList<Struct1> >();
+ qDBusRegisterMetaType<QList<Struct2> >();
+ qDBusRegisterMetaType<QList<Struct3> >();
+ qDBusRegisterMetaType<QList<Struct4> >();
+
+ qDBusRegisterMetaType<Invalid0>();
+ qDBusRegisterMetaType<Invalid1>();
+ qDBusRegisterMetaType<Invalid2>();
+ qDBusRegisterMetaType<Invalid3>();
+ qDBusRegisterMetaType<Invalid4>();
+ qDBusRegisterMetaType<Invalid5>();
+ // don't register Invalid6
+ qDBusRegisterMetaType<Invalid7>();
+
+ qDBusRegisterMetaType<QList<Invalid0> >();
+
+ intStringMap = qDBusRegisterMetaType<QMap<int, QString> >();
+ stringStringMap = qDBusRegisterMetaType<QMap<QString, QString> >();
+ stringStruct1Map = qDBusRegisterMetaType<QMap<QString, Struct1> >();
+}
+
+void tst_QDBusMetaType::staticTypes_data()
+{
+ QTest::addColumn<QVariant::Type>("typeId");
+ QTest::addColumn<QString>("signature");
+
+ QTest::newRow("uchar") << QVariant::Type(QMetaType::UChar) << "y";
+ QTest::newRow("bool") << QVariant::Bool << "b";
+ QTest::newRow("short") << QVariant::Type(QMetaType::Short) << "n";
+ QTest::newRow("ushort") << QVariant::Type(QMetaType::UShort) << "q";
+ QTest::newRow("int") << QVariant::Int << "i";
+ QTest::newRow("uint") << QVariant::UInt << "u";
+ QTest::newRow("qlonglong") << QVariant::LongLong << "x";
+ QTest::newRow("qulonglong") << QVariant::ULongLong << "t";
+ QTest::newRow("double") << QVariant::Double << "d";
+ QTest::newRow("QString") << QVariant::String << "s";
+ QTest::newRow("QDBusObjectPath") << QVariant::Type(qMetaTypeId<QDBusObjectPath>()) << "o";
+ QTest::newRow("QDBusSignature") << QVariant::Type(qMetaTypeId<QDBusSignature>()) << "g";
+ QTest::newRow("QDBusVariant") << QVariant::Type(qMetaTypeId<QDBusVariant>()) << "v";
+
+ QTest::newRow("QByteArray") << QVariant::ByteArray << "ay";
+ QTest::newRow("QStringList") << QVariant::StringList << "as";
+}
+
+void tst_QDBusMetaType::dynamicTypes_data()
+{
+ QTest::addColumn<QVariant::Type>("typeId");
+ QTest::addColumn<QString>("signature");
+
+ QTest::newRow("QVariantList") << QVariant::List << "av";
+ QTest::newRow("QVariantMap") << QVariant::Map << "a{sv}";
+ QTest::newRow("QDate") << QVariant::Date << "(iii)";
+ QTest::newRow("QTime") << QVariant::Time << "(iiii)";
+ QTest::newRow("QDateTime") << QVariant::DateTime << "((iii)(iiii)i)";
+ QTest::newRow("QRect") << QVariant::Rect << "(iiii)";
+ QTest::newRow("QRectF") << QVariant::RectF << "(dddd)";
+ QTest::newRow("QSize") << QVariant::Size << "(ii)";
+ QTest::newRow("QSizeF") << QVariant::SizeF << "(dd)";
+ QTest::newRow("QPoint") << QVariant::Point << "(ii)";
+ QTest::newRow("QPointF") << QVariant::PointF << "(dd)";
+ QTest::newRow("QLine") << QVariant::Line << "((ii)(ii))";
+ QTest::newRow("QLineF") << QVariant::LineF << "((dd)(dd))";
+
+ QTest::newRow("Struct1") << QVariant::Type(qMetaTypeId<Struct1>()) << "(s)";
+ QTest::newRow("QList<Struct1>") << QVariant::Type(qMetaTypeId<QList<Struct1> >()) << "a(s)";
+
+ QTest::newRow("Struct2") << QVariant::Type(qMetaTypeId<Struct2>()) << "(sos)";
+ QTest::newRow("QList<Struct2>") << QVariant::Type(qMetaTypeId<QList<Struct2> >()) << "a(sos)";
+
+ QTest::newRow("QList<Struct3>") << QVariant::Type(qMetaTypeId<QList<Struct3> >()) << "a(sas)";
+ QTest::newRow("Struct3") << QVariant::Type(qMetaTypeId<Struct3>()) << "(sas)";
+
+ QTest::newRow("Struct4") << QVariant::Type(qMetaTypeId<Struct4>()) << "(ssa(ss)sayasx)";
+ QTest::newRow("QList<Struct4>") << QVariant::Type(qMetaTypeId<QList<Struct4> >()) << "a(ssa(ss)sayasx)";
+
+ QTest::newRow("QMap<int,QString>") << QVariant::Type(intStringMap) << "a{is}";
+ QTest::newRow("QMap<QString,QString>") << QVariant::Type(stringStringMap) << "a{ss}";
+ QTest::newRow("QMap<QString,Struct1>") << QVariant::Type(stringStruct1Map) << "a{s(s)}";
+}
+
+void tst_QDBusMetaType::staticTypes()
+{
+ QFETCH(QVariant::Type, typeId);
+
+ QString result = QDBusMetaType::typeToSignature(typeId);
+ QTEST(result, "signature");
+}
+
+void tst_QDBusMetaType::dynamicTypes()
+{
+ // same test
+ staticTypes();
+}
+
+void tst_QDBusMetaType::invalidTypes_data()
+{
+ QTest::addColumn<QVariant::Type>("typeId");
+ QTest::addColumn<QString>("signature");
+
+ QTest::newRow("Invalid0") << QVariant::Type(qMetaTypeId<Invalid0>()) << "";
+ QTest::newRow("Invalid1") << QVariant::Type(qMetaTypeId<Invalid1>()) << "";
+ QTest::newRow("Invalid2") << QVariant::Type(qMetaTypeId<Invalid2>()) << "";
+ QTest::newRow("Invalid3") << QVariant::Type(qMetaTypeId<Invalid3>()) << "";
+ QTest::newRow("Invalid4") << QVariant::Type(qMetaTypeId<Invalid4>()) << "";
+ QTest::newRow("Invalid5") << QVariant::Type(qMetaTypeId<Invalid5>()) << "";
+ QTest::newRow("Invalid6") << QVariant::Type(qMetaTypeId<Invalid6>()) << "";
+ QTest::newRow("Invalid7") << QVariant::Type(qMetaTypeId<Invalid7>()) << "";
+
+ QTest::newRow("QList<Invalid0>") << QVariant::Type(qMetaTypeId<QList<Invalid0> >()) << "";
+
+ QTest::newRow("long") << QVariant::Type(QMetaType::Long) << "";
+ QTest::newRow("void*") << QVariant::Type(QMetaType::VoidStar) << "";
+}
+
+void tst_QDBusMetaType::invalidTypes()
+{
+ // same test
+ if (qstrcmp(QTest::currentDataTag(), "Invalid0") == 0)
+ QTest::ignoreMessage(QtWarningMsg, "QDBusMarshaller: type `Invalid0' produces invalid D-BUS signature `<empty>' (Did you forget to call beginStructure() ?)");
+ else if (qstrcmp(QTest::currentDataTag(), "Invalid1") == 0)
+ QTest::ignoreMessage(QtWarningMsg, "QDBusMarshaller: type `Invalid1' attempts to redefine basic D-BUS type 's' (QString) (Did you forget to call beginStructure() ?)");
+ else if (qstrcmp(QTest::currentDataTag(), "Invalid2") == 0)
+ QTest::ignoreMessage(QtWarningMsg, "QDBusMarshaller: type `Invalid2' attempts to redefine basic D-BUS type 'o' (QDBusObjectPath) (Did you forget to call beginStructure() ?)");
+ else if (qstrcmp(QTest::currentDataTag(), "Invalid3") == 0)
+ QTest::ignoreMessage(QtWarningMsg, "QDBusMarshaller: type `Invalid3' attempts to redefine basic D-BUS type 'as' (QStringList) (Did you forget to call beginStructure() ?)");
+ else if (qstrcmp(QTest::currentDataTag(), "Invalid4") == 0)
+ QTest::ignoreMessage(QtWarningMsg, "QDBusMarshaller: type `Invalid4' attempts to redefine basic D-BUS type 'ay' (QByteArray) (Did you forget to call beginStructure() ?)");
+ else if (qstrcmp(QTest::currentDataTag(), "Invalid5") == 0)
+ QTest::ignoreMessage(QtWarningMsg, "QDBusMarshaller: type `Invalid5' produces invalid D-BUS signature `ii' (Did you forget to call beginStructure() ?)");
+ else if (qstrcmp(QTest::currentDataTag(), "Invalid7") == 0)
+ QTest::ignoreMessage(QtWarningMsg, "QDBusMarshaller: type `Invalid7' produces invalid D-BUS signature `()' (Did you forget to call beginStructure() ?)");
+ else if (qstrcmp(QTest::currentDataTag(), "QList<Invalid0>") == 0)
+ QTest::ignoreMessage(QtWarningMsg, "QDBusMarshaller: type `QList<Invalid0>' produces invalid D-BUS signature `a' (Did you forget to call beginStructure() ?)");
+
+ staticTypes();
+ staticTypes(); // run twice: the error messages should be printed once only
+}
+
+QTEST_MAIN(tst_QDBusMetaType)
+
+#include "tst_qdbusmetatype.moc"
diff --git a/tests/auto/dbus/qdbuspendingcall/.gitignore b/tests/auto/dbus/qdbuspendingcall/.gitignore
new file mode 100644
index 0000000000..a216d5804a
--- /dev/null
+++ b/tests/auto/dbus/qdbuspendingcall/.gitignore
@@ -0,0 +1 @@
+tst_qdbuspendingcall
diff --git a/tests/auto/dbus/qdbuspendingcall/qdbuspendingcall.pro b/tests/auto/dbus/qdbuspendingcall/qdbuspendingcall.pro
new file mode 100644
index 0000000000..74708c8103
--- /dev/null
+++ b/tests/auto/dbus/qdbuspendingcall/qdbuspendingcall.pro
@@ -0,0 +1,6 @@
+load(qttest_p4)
+requires(contains(QT_CONFIG, dbus))
+QT = core dbus
+SOURCES += tst_qdbuspendingcall.cpp
+
+CONFIG+=insignificant_test
diff --git a/tests/auto/dbus/qdbuspendingcall/tst_qdbuspendingcall.cpp b/tests/auto/dbus/qdbuspendingcall/tst_qdbuspendingcall.cpp
new file mode 100644
index 0000000000..7bdf9c561b
--- /dev/null
+++ b/tests/auto/dbus/qdbuspendingcall/tst_qdbuspendingcall.cpp
@@ -0,0 +1,556 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/QObject>
+#include <QtCore/QVariant>
+#include <QtCore/QList>
+#include <QtCore/QThread>
+#include <QtCore/QVector>
+#include <QtTest/QtTest>
+#ifndef QT_NO_DBUS
+#include <QtDBus>
+
+#define TEST_INTERFACE_NAME "com.trolltech.QtDBus.MyObject"
+
+class MyObject : public QDBusAbstractAdaptor
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "com.trolltech.QtDBus.MyObject")
+
+public:
+ MyObject(QObject* parent =0)
+ : QDBusAbstractAdaptor(parent)
+ {}
+
+public slots:
+ QStringList returnFoo() const
+ { return QStringList() << QString::fromLatin1("foo"); }
+
+ void returnError(const QDBusMessage &msg) const
+ {
+ msg.setDelayedReply(true);
+ QDBusConnection::sessionBus().send(msg.createErrorReply("dbuspendingcall_error", ""));
+ }
+};
+
+class tst_QDBusPendingCall: public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QDBusPendingCall();
+
+public Q_SLOTS:
+ void callback(const QStringList &list);
+ void errorCallback(const QDBusError &error);
+ void finished(QDBusPendingCallWatcher *call);
+ void makeCall();
+
+private Q_SLOTS:
+ void initTestCase();
+ void waitForFinished();
+ void waitForFinished_error();
+// void setReplyCallback();
+ void watcher();
+ void watcher_error();
+ void watcher_waitForFinished();
+ void watcher_waitForFinished_threaded();
+ void watcher_waitForFinished_alreadyFinished();
+ void watcher_waitForFinished_alreadyFinished_eventLoop();
+ void watcher_waitForFinished_error();
+ void callInsideWaitForFinished();
+
+ void callWithCallback_localLoop();
+ void callWithCallback_localLoop_errorReply();
+
+private:
+ QDBusPendingCall sendMessage();
+ QDBusPendingCall sendError();
+
+ QDBusConnection conn;
+
+ enum { CallbackCalled, ErrorCallbackCalled, FinishCalled, MakeCallCalled };
+ int slotCalled;
+ int callCount;
+ QStringList callbackArgument;
+ QDBusError errorArgument;
+ QDBusPendingCallWatcher *watchArgument;
+ MyObject *obj;
+};
+
+tst_QDBusPendingCall::tst_QDBusPendingCall()
+ : conn(QDBusConnection::sessionBus())
+ , obj(new MyObject(this))
+{
+}
+
+void tst_QDBusPendingCall::finished(QDBusPendingCallWatcher *call)
+{
+ slotCalled = FinishCalled;
+ ++callCount;
+ watchArgument = call;
+ if (QThread::currentThread() == thread())
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_QDBusPendingCall::callback(const QStringList &list)
+{
+ slotCalled = CallbackCalled;
+ ++callCount;
+ callbackArgument = list;
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_QDBusPendingCall::errorCallback(const QDBusError &error)
+{
+ slotCalled = ErrorCallbackCalled;
+ ++callCount;
+ errorArgument = error;
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_QDBusPendingCall::makeCall()
+{
+ // make an external call to D-Bus to make sure we haven't left any locks
+ slotCalled = MakeCallCalled;
+ ++callCount;
+
+ sendMessage().waitForFinished();
+}
+
+void tst_QDBusPendingCall::initTestCase()
+{
+ QVERIFY(conn.isConnected());
+ QVERIFY(conn.registerObject("/", this));
+}
+
+QDBusPendingCall tst_QDBusPendingCall::sendMessage()
+{
+ QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.DBus",
+ "/",
+ "org.freedesktop.DBus",
+ "ListNames");
+ return conn.asyncCall(msg);
+}
+
+QDBusPendingCall tst_QDBusPendingCall::sendError()
+{
+ QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.DBus",
+ "/",
+ "org.freedesktop.DBus",
+ "ThisNameWontExist");
+ return conn.asyncCall(msg);
+}
+
+void tst_QDBusPendingCall::waitForFinished()
+{
+ QDBusPendingCall ac = sendMessage();
+ QVERIFY(!ac.isFinished());
+ QVERIFY(!ac.isError());
+ QVERIFY(ac.reply().type() == QDBusMessage::InvalidMessage);
+
+ ac.waitForFinished();
+ QVERIFY(ac.isFinished());
+ QVERIFY(!ac.isError());
+
+ const QDBusMessage reply = ac.reply();
+ QVERIFY(reply.type() == QDBusMessage::ReplyMessage);
+ QCOMPARE(reply.signature(), QString("as"));
+
+ const QVariantList args = ac.reply().arguments();
+ QCOMPARE(args.count(), 1);
+
+ const QVariant &arg = args.at(0);
+ QCOMPARE(arg.type(), QVariant::StringList);
+ QVERIFY(arg.toStringList().contains(conn.baseService()));
+}
+
+void tst_QDBusPendingCall::waitForFinished_error()
+{
+ QDBusPendingCall ac = sendError();
+ QVERIFY(!ac.isFinished());
+ QVERIFY(!ac.isError());
+ QVERIFY(ac.reply().type() == QDBusMessage::InvalidMessage);
+
+ ac.waitForFinished();
+ QVERIFY(ac.isFinished());
+ QVERIFY(ac.isError());
+
+ QDBusError error = ac.error();
+ QVERIFY(error.isValid());
+ QCOMPARE(error.name(), QString("org.freedesktop.DBus.Error.UnknownMethod"));
+ QCOMPARE(error.type(), QDBusError::UnknownMethod);
+}
+
+void tst_QDBusPendingCall::callWithCallback_localLoop()
+{
+ // Verify that a callback actually gets called when the call is dispatched locally.
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+ QVERIFY(iface.isValid());
+
+ QVERIFY(iface.callWithCallback("returnFoo", QVariantList(), this, SLOT(callback(QStringList))));
+
+ // May be called synchronously or asynchronously...
+ if (callbackArgument != (QStringList() << QString::fromLatin1("foo"))) {
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+ }
+
+ QCOMPARE(callbackArgument, QStringList() << QString::fromLatin1("foo"));
+}
+
+void tst_QDBusPendingCall::callWithCallback_localLoop_errorReply()
+{
+ // Verify that an error callback actually gets called when the call is
+ // dispatched locally and the called method returns an error
+
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
+ TEST_INTERFACE_NAME);
+ QVERIFY(iface.isValid());
+
+ callbackArgument.clear();
+
+ QVERIFY(iface.callWithCallback("returnError", QVariantList(), this,
+ SLOT(callback(QStringList)), SLOT(errorCallback(QDBusError))));
+
+ // May be called synchronously or asynchronously...
+ if (errorArgument.name() != "dbuspendingcall_error") {
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+ }
+
+ QCOMPARE(errorArgument.name(), QString::fromLatin1("dbuspendingcall_error"));
+ QVERIFY(callbackArgument.isEmpty());
+}
+
+#if 0
+// This function was removed from the public API
+void tst_QDBusPendingCall::setReplyCallback()
+{
+ QDBusPendingCall ac = sendMessage();
+ QVERIFY(!ac.isFinished());
+ QVERIFY(!ac.isError());
+ QVERIFY(ac.reply().type() == QDBusMessage::InvalidMessage);
+
+ callCount = 0;
+ callbackArgument.clear();
+ QVERIFY(ac.setReplyCallback(this, SLOT(callback(const QStringList &))));
+ QVERIFY(callCount == 0);
+ QVERIFY(callbackArgument.isEmpty());
+
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QVERIFY(ac.isFinished());
+ QVERIFY(!ac.isError());
+
+ QCOMPARE(callCount, 1);
+ QCOMPARE(slotCalled, (int)CallbackCalled);
+ QVERIFY(!callbackArgument.isEmpty());
+ QVERIFY(callbackArgument.contains(conn.baseService()));
+
+ const QVariantList args = ac.reply().arguments();
+ QVERIFY(!args.isEmpty());
+ QCOMPARE(args.at(0).toStringList(), callbackArgument);
+}
+#endif
+
+void tst_QDBusPendingCall::watcher()
+{
+ QDBusPendingCall ac = sendMessage();
+ QVERIFY(!ac.isFinished());
+ QVERIFY(!ac.isError());
+ QVERIFY(ac.reply().type() == QDBusMessage::InvalidMessage);
+
+ callCount = 0;
+ watchArgument = 0;
+
+ QDBusPendingCallWatcher watch(ac);
+ connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
+ SLOT(finished(QDBusPendingCallWatcher*)));
+
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QVERIFY(ac.isFinished());
+ QVERIFY(!ac.isError());
+
+ QCOMPARE(callCount, 1);
+ QCOMPARE(slotCalled, (int)FinishCalled);
+ QCOMPARE(watchArgument, &watch);
+ QVERIFY(!watch.isError());
+
+ const QVariantList args2 = ac.reply().arguments();
+ QVERIFY(!args2.isEmpty());
+ QVERIFY(args2.at(0).toStringList().contains(conn.baseService()));
+}
+
+void tst_QDBusPendingCall::watcher_error()
+{
+ QDBusPendingCall ac = sendError();
+ QVERIFY(!ac.isFinished());
+ QVERIFY(!ac.isError());
+ QVERIFY(ac.reply().type() == QDBusMessage::InvalidMessage);
+
+ callCount = 0;
+ watchArgument = 0;
+
+ QDBusPendingCallWatcher watch(ac);
+ connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
+ SLOT(finished(QDBusPendingCallWatcher*)));
+
+ QTestEventLoop::instance().enterLoop(2);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QVERIFY(ac.isFinished());
+ QVERIFY(ac.isError());
+
+ QCOMPARE(callCount, 1);
+ QCOMPARE(slotCalled, (int)FinishCalled);
+ QCOMPARE(watchArgument, &watch);
+
+ QVERIFY(watch.isError());
+ QVERIFY(watch.error().isValid());
+}
+
+void tst_QDBusPendingCall::watcher_waitForFinished()
+{
+ QDBusPendingCall ac = sendMessage();
+ QVERIFY(!ac.isFinished());
+ QVERIFY(!ac.isError());
+ QVERIFY(ac.reply().type() == QDBusMessage::InvalidMessage);
+
+ callCount = 0;
+ watchArgument = 0;
+
+ QDBusPendingCallWatcher watch(ac);
+ connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
+ SLOT(finished(QDBusPendingCallWatcher*)));
+
+ watch.waitForFinished();
+
+ QVERIFY(ac.isFinished());
+ QVERIFY(!ac.isError());
+
+ QCOMPARE(callCount, 1);
+ QCOMPARE(slotCalled, (int)FinishCalled);
+ QCOMPARE(watchArgument, &watch);
+ QVERIFY(!watch.isError());
+
+ const QVariantList args2 = ac.reply().arguments();
+ QVERIFY(!args2.isEmpty());
+ QVERIFY(args2.at(0).toStringList().contains(conn.baseService()));
+}
+
+void tst_QDBusPendingCall::watcher_waitForFinished_threaded()
+{
+ callCount = 0;
+ watchArgument = 0;
+ slotCalled = 0;
+
+ class WorkerThread: public QThread {
+ public:
+ tst_QDBusPendingCall *tst;
+ WorkerThread(tst_QDBusPendingCall *tst) : tst(tst) {}
+ void run()
+ {
+ QDBusPendingCall ac = tst->sendMessage();
+// QVERIFY(!ac.isFinished());
+// QVERIFY(!ac.isError());
+// QVERIFY(ac.reply().type() == QDBusMessage::InvalidMessage);
+
+ QDBusPendingCallWatcher watch(ac);
+ tst->connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
+ SLOT(finished(QDBusPendingCallWatcher*)), Qt::DirectConnection);
+
+ QTest::qSleep(100); // don't process events in this thread
+
+// QVERIFY(!ac.isFinished());
+// QVERIFY(!ac.isError());
+// QVERIFY(ac.reply().type() == QDBusMessage::InvalidMessage);
+ QCOMPARE(tst->callCount, 0);
+ QCOMPARE(tst->slotCalled, 0);
+
+ watch.waitForFinished();
+ QVERIFY(ac.isFinished());
+ QVERIFY(!ac.isError());
+
+ QCOMPARE(tst->callCount, 1);
+ QCOMPARE(tst->slotCalled, (int)FinishCalled);
+ QCOMPARE(tst->watchArgument, &watch);
+ QVERIFY(!watch.isError());
+
+ const QVariantList args2 = ac.reply().arguments();
+ QVERIFY(!args2.isEmpty());
+ QVERIFY(args2.at(0).toStringList().contains(tst->conn.baseService()));
+ }
+ } thread(this);
+ QTestEventLoop::instance().connect(&thread, SIGNAL(finished()), SLOT(exitLoop()));
+ thread.start();
+ QTestEventLoop::instance().enterLoop(10);
+ QVERIFY(!thread.isRunning());
+ QVERIFY(!QTestEventLoop::instance().timeout());
+}
+
+void tst_QDBusPendingCall::watcher_waitForFinished_alreadyFinished()
+{
+ QDBusPendingCall ac = sendMessage();
+ QVERIFY(!ac.isFinished());
+ QVERIFY(!ac.isError());
+ QVERIFY(ac.reply().type() == QDBusMessage::InvalidMessage);
+
+ ac.waitForFinished();
+ QVERIFY(ac.isFinished());
+ QVERIFY(!ac.isError());
+
+ callCount = 0;
+ watchArgument = 0;
+
+ // create a watcher on an already-finished reply
+ QDBusPendingCallWatcher watch(ac);
+ connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
+ SLOT(finished(QDBusPendingCallWatcher*)));
+
+ watch.waitForFinished();
+
+ QVERIFY(ac.isFinished());
+ QVERIFY(!ac.isError());
+
+ QCOMPARE(callCount, 1);
+ QCOMPARE(slotCalled, (int)FinishCalled);
+ QCOMPARE(watchArgument, &watch);
+ QVERIFY(!watch.isError());
+
+ const QVariantList args2 = ac.reply().arguments();
+ QVERIFY(!args2.isEmpty());
+ QVERIFY(args2.at(0).toStringList().contains(conn.baseService()));
+}
+
+void tst_QDBusPendingCall::watcher_waitForFinished_alreadyFinished_eventLoop()
+{
+ QDBusPendingCall ac = sendMessage();
+ QVERIFY(!ac.isFinished());
+ QVERIFY(!ac.isError());
+ QVERIFY(ac.reply().type() == QDBusMessage::InvalidMessage);
+
+ ac.waitForFinished();
+ QVERIFY(ac.isFinished());
+ QVERIFY(!ac.isError());
+
+ callCount = 0;
+ watchArgument = 0;
+
+ // create a watcher on an already-finished reply
+ QDBusPendingCallWatcher watch(ac);
+ connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
+ SLOT(finished(QDBusPendingCallWatcher*)));
+ connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
+ &QTestEventLoop::instance(), SLOT(exitLoop()));
+
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QVERIFY(ac.isFinished());
+ QVERIFY(!ac.isError());
+
+ QCOMPARE(callCount, 1);
+ QCOMPARE(slotCalled, (int)FinishCalled);
+ QCOMPARE(watchArgument, &watch);
+ QVERIFY(!watch.isError());
+
+ const QVariantList args2 = ac.reply().arguments();
+ QVERIFY(!args2.isEmpty());
+ QVERIFY(args2.at(0).toStringList().contains(conn.baseService()));
+}
+
+void tst_QDBusPendingCall::watcher_waitForFinished_error()
+{
+ QDBusPendingCall ac = sendError();
+ QVERIFY(!ac.isFinished());
+ QVERIFY(!ac.isError());
+ QVERIFY(ac.reply().type() == QDBusMessage::InvalidMessage);
+
+ callCount = 0;
+ watchArgument = 0;
+
+ QDBusPendingCallWatcher watch(ac);
+ connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
+ SLOT(finished(QDBusPendingCallWatcher*)));
+
+ watch.waitForFinished();
+
+ QVERIFY(ac.isFinished());
+ QVERIFY(ac.isError());
+
+ QCOMPARE(callCount, 1);
+ QCOMPARE(slotCalled, (int)FinishCalled);
+ QCOMPARE(watchArgument, &watch);
+
+ QVERIFY(watch.isError());
+ QVERIFY(watch.error().isValid());
+}
+
+void tst_QDBusPendingCall::callInsideWaitForFinished()
+{
+ QDBusPendingCall ac = sendMessage();
+ QDBusPendingCallWatcher watch(ac);
+
+ callCount = 0;
+
+ connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
+ SLOT(makeCall()));
+
+ watch.waitForFinished();
+
+ QCOMPARE(callCount, 1);
+ QCOMPARE(slotCalled, (int)MakeCallCalled);
+ QVERIFY(!watch.isError());
+
+ const QVariantList args2 = ac.reply().arguments();
+ QVERIFY(!args2.isEmpty());
+ QVERIFY(args2.at(0).toStringList().contains(conn.baseService()));
+}
+
+QTEST_MAIN(tst_QDBusPendingCall)
+#include "tst_qdbuspendingcall.moc"
+#else
+QTEST_NOOP_MAIN
+#endif
diff --git a/tests/auto/dbus/qdbuspendingreply/.gitignore b/tests/auto/dbus/qdbuspendingreply/.gitignore
new file mode 100644
index 0000000000..d2537acca6
--- /dev/null
+++ b/tests/auto/dbus/qdbuspendingreply/.gitignore
@@ -0,0 +1 @@
+tst_qdbuspendingreply
diff --git a/tests/auto/dbus/qdbuspendingreply/qdbuspendingreply.pro b/tests/auto/dbus/qdbuspendingreply/qdbuspendingreply.pro
new file mode 100644
index 0000000000..c649e4aaf5
--- /dev/null
+++ b/tests/auto/dbus/qdbuspendingreply/qdbuspendingreply.pro
@@ -0,0 +1,4 @@
+load(qttest_p4)
+requires(contains(QT_CONFIG, dbus))
+QT = core dbus
+SOURCES += tst_qdbuspendingreply.cpp
diff --git a/tests/auto/dbus/qdbuspendingreply/tst_qdbuspendingreply.cpp b/tests/auto/dbus/qdbuspendingreply/tst_qdbuspendingreply.cpp
new file mode 100644
index 0000000000..18177181fb
--- /dev/null
+++ b/tests/auto/dbus/qdbuspendingreply/tst_qdbuspendingreply.cpp
@@ -0,0 +1,597 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/QObject>
+#include <QtCore/QVariant>
+#include <QtCore/QList>
+#include <QtCore/QVector>
+#include <QtTest/QtTest>
+#ifndef QT_NO_DBUS
+#include <QtDBus>
+
+typedef QMap<int,QString> IntStringMap;
+Q_DECLARE_METATYPE(IntStringMap)
+
+struct MyStruct
+{
+ int i;
+ QString s;
+
+ MyStruct() : i(1), s("String") { }
+ bool operator==(const MyStruct &other) const
+ { return i == other.i && s == other.s; }
+};
+Q_DECLARE_METATYPE(MyStruct)
+
+QDBusArgument &operator<<(QDBusArgument &arg, const MyStruct &ms)
+{
+ arg.beginStructure();
+ arg << ms.i << ms.s;
+ arg.endStructure();
+ return arg;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &arg, MyStruct &ms)
+{
+ arg.beginStructure();
+ arg >> ms.i >> ms.s;
+ arg.endStructure();
+ return arg;
+}
+
+class TypesInterface;
+class tst_QDBusPendingReply: public QObject
+{
+ Q_OBJECT
+ QDBusInterface *iface;
+ TypesInterface *adaptor;
+public:
+ tst_QDBusPendingReply();
+
+private slots:
+ void initTestCase()
+ {
+ qDBusRegisterMetaType<IntStringMap>();
+ qDBusRegisterMetaType<MyStruct>();
+ }
+
+ void init();
+ void unconnected();
+ void simpleTypes();
+ void complexTypes();
+ void wrongTypes();
+ void multipleTypes();
+
+ void synchronousSimpleTypes();
+
+ void errors();
+};
+
+class TypesInterface: public QDBusAbstractAdaptor
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "com.trolltech.Qt.Autotests.TypesInterface")
+public:
+ TypesInterface(QObject *parent)
+ : QDBusAbstractAdaptor(parent)
+ { }
+
+public slots:
+ void retrieveVoid()
+ { }
+
+ bool retrieveBool()
+ {
+ return true;
+ }
+
+ uchar retrieveUChar()
+ {
+ return 'A';
+ }
+
+ short retrieveShort()
+ {
+ return -47;
+ }
+
+ ushort retrieveUShort()
+ {
+ return 42U;
+ }
+
+ int retrieveInt()
+ {
+ return -470000;
+ }
+
+ void retrieveIntInt(int &i1, int &i2)
+ {
+ i1 = -424242;
+ i2 = 434343;
+ }
+
+ uint retrieveUInt()
+ {
+ return 42424242;
+ }
+
+ qlonglong retrieveLongLong()
+ {
+ return -(Q_INT64_C(1) << 32);
+ }
+
+ qulonglong retrieveULongLong()
+ {
+ return Q_INT64_C(1) << 32;
+ }
+
+ double retrieveDouble()
+ {
+ return 1.5;
+ }
+
+ QString retrieveString()
+ {
+ return "This string you should see";
+ }
+
+ QDBusObjectPath retrieveObjectPath()
+ {
+ return QDBusObjectPath("/");
+ }
+
+ QDBusSignature retrieveSignature()
+ {
+ return QDBusSignature("g");
+ }
+
+ QDBusVariant retrieveVariant()
+ {
+ return QDBusVariant(retrieveString());
+ }
+
+ QStringList retrieveStringList()
+ {
+ return QStringList() << "one" << "two";
+ }
+
+ QByteArray retrieveByteArray()
+ {
+ return "Hello, World";
+ }
+
+ QVariantList retrieveList()
+ {
+ return QVariantList() << retrieveInt() << retrieveString()
+ << retrieveByteArray();
+ }
+
+ QVariantMap retrieveMap()
+ {
+ QVariantMap map;
+ map["one"] = 1;
+ map["two"] = 2U;
+ map["string"] = retrieveString();
+ map["stringlist"] = retrieveStringList();
+ return map;
+ }
+
+ IntStringMap retrieveIntStringMap()
+ {
+ IntStringMap map;
+ map[1] = "1";
+ map[2] = "2";
+ map[-1231456] = "foo";
+ return map;
+ }
+
+ MyStruct retrieveStruct()
+ {
+ return MyStruct();
+ }
+
+ void sendError(const QDBusMessage &msg)
+ {
+ msg.setDelayedReply(true);
+ QDBusConnection::sessionBus()
+ .send(msg.createErrorReply("local.AnErrorName", "You've got an error!"));
+ }
+};
+
+tst_QDBusPendingReply::tst_QDBusPendingReply()
+{
+ adaptor = new TypesInterface(this);
+ QDBusConnection::sessionBus().registerObject("/", this);
+
+ iface = new QDBusInterface(QDBusConnection::sessionBus().baseService(), "/",
+ "com.trolltech.Qt.Autotests.TypesInterface",
+ QDBusConnection::sessionBus(),
+ this);
+}
+
+void tst_QDBusPendingReply::init()
+{
+ QVERIFY(iface);
+ QVERIFY(iface->isValid());
+}
+
+void tst_QDBusPendingReply::unconnected()
+{
+ QDBusConnection con("invalid stored connection");
+ QVERIFY(!con.isConnected());
+ QDBusInterface iface("doesnt.matter", "/", "doesnt.matter", con);
+ QVERIFY(!iface.isValid());
+
+ QDBusPendingReply<> rvoid = iface.asyncCall("ReloadConfig");
+ QVERIFY(rvoid.isFinished());
+ QVERIFY(!rvoid.isValid());
+ QVERIFY(rvoid.isError());
+ rvoid.waitForFinished();
+ QVERIFY(!rvoid.isValid());
+ QVERIFY(rvoid.isError());
+
+ QDBusPendingReply<QString> rstring = iface.asyncCall("GetId");
+ QVERIFY(rstring.isFinished());
+ QVERIFY(!rstring.isValid());
+ QVERIFY(rstring.isError());
+ rstring.waitForFinished();
+ QVERIFY(!rstring.isValid());
+ QVERIFY(rstring.isError());
+}
+
+void tst_QDBusPendingReply::simpleTypes()
+{
+ QDBusPendingReply<> rvoid = iface->asyncCall("retrieveVoid");
+ rvoid.waitForFinished();
+ QVERIFY(rvoid.isFinished());
+ QVERIFY(!rvoid.isError());
+
+ QDBusPendingReply<bool> rbool = iface->asyncCall("retrieveBool");
+ rbool.waitForFinished();
+ QVERIFY(rbool.isFinished());
+ QCOMPARE(rbool.argumentAt<0>(), adaptor->retrieveBool());
+
+ QDBusPendingReply<uchar> ruchar = iface->asyncCall("retrieveUChar");
+ ruchar.waitForFinished();
+ QVERIFY(ruchar.isFinished());
+ QCOMPARE(ruchar.argumentAt<0>(), adaptor->retrieveUChar());
+
+ QDBusPendingReply<short> rshort = iface->asyncCall("retrieveShort");
+ rshort.waitForFinished();
+ QVERIFY(rshort.isFinished());
+ QCOMPARE(rshort.argumentAt<0>(), adaptor->retrieveShort());
+
+ QDBusPendingReply<ushort> rushort = iface->asyncCall("retrieveUShort");
+ rushort.waitForFinished();
+ QVERIFY(rushort.isFinished());
+ QCOMPARE(rushort.argumentAt<0>(), adaptor->retrieveUShort());
+
+ QDBusPendingReply<int> rint = iface->asyncCall("retrieveInt");
+ rint.waitForFinished();
+ QVERIFY(rint.isFinished());
+ QCOMPARE(rint.argumentAt<0>(), adaptor->retrieveInt());
+
+ QDBusPendingReply<uint> ruint = iface->asyncCall("retrieveUInt");
+ ruint.waitForFinished();
+ QVERIFY(ruint.isFinished());
+ QCOMPARE(ruint.argumentAt<0>(), adaptor->retrieveUInt());
+
+ QDBusPendingReply<qlonglong> rqlonglong = iface->asyncCall("retrieveLongLong");
+ rqlonglong.waitForFinished();
+ QVERIFY(rqlonglong.isFinished());
+ QCOMPARE(rqlonglong.argumentAt<0>(), adaptor->retrieveLongLong());
+
+ QDBusPendingReply<qulonglong> rqulonglong = iface->asyncCall("retrieveULongLong");
+ rqulonglong.waitForFinished();
+ QVERIFY(rqulonglong.isFinished());
+ QCOMPARE(rqulonglong.argumentAt<0>(), adaptor->retrieveULongLong());
+
+ QDBusPendingReply<double> rdouble = iface->asyncCall("retrieveDouble");
+ rdouble.waitForFinished();
+ QVERIFY(rdouble.isFinished());
+ QCOMPARE(rdouble.argumentAt<0>(), adaptor->retrieveDouble());
+
+ QDBusPendingReply<QString> rstring = iface->asyncCall("retrieveString");
+ rstring.waitForFinished();
+ QVERIFY(rstring.isFinished());
+ QCOMPARE(rstring.argumentAt<0>(), adaptor->retrieveString());
+
+ QDBusPendingReply<QDBusObjectPath> robjectpath = iface->asyncCall("retrieveObjectPath");
+ robjectpath.waitForFinished();
+ QVERIFY(robjectpath.isFinished());
+ QCOMPARE(robjectpath.argumentAt<0>().path(), adaptor->retrieveObjectPath().path());
+
+ QDBusPendingReply<QDBusSignature> rsignature = iface->asyncCall("retrieveSignature");
+ rsignature.waitForFinished();
+ QVERIFY(rsignature.isFinished());
+ QCOMPARE(rsignature.argumentAt<0>().signature(), adaptor->retrieveSignature().signature());
+
+ QDBusPendingReply<QDBusVariant> rdbusvariant = iface->asyncCall("retrieveVariant");
+ rdbusvariant.waitForFinished();
+ QVERIFY(rdbusvariant.isFinished());
+ QCOMPARE(rdbusvariant.argumentAt<0>().variant(), adaptor->retrieveVariant().variant());
+
+ QDBusPendingReply<QVariant> rvariant = iface->asyncCall("retrieveVariant");
+ rvariant.waitForFinished();
+ QVERIFY(rvariant.isFinished());
+ QCOMPARE(rvariant.argumentAt<0>(), adaptor->retrieveVariant().variant());
+
+ QDBusPendingReply<QByteArray> rbytearray = iface->asyncCall("retrieveByteArray");
+ rbytearray.waitForFinished();
+ QVERIFY(rbytearray.isFinished());
+ QCOMPARE(rbytearray.argumentAt<0>(), adaptor->retrieveByteArray());
+
+ QDBusPendingReply<QStringList> rstringlist = iface->asyncCall("retrieveStringList");
+ rstringlist.waitForFinished();
+ QVERIFY(rstringlist.isFinished());
+ QCOMPARE(rstringlist.argumentAt<0>(), adaptor->retrieveStringList());
+}
+
+void tst_QDBusPendingReply::complexTypes()
+{
+ QDBusPendingReply<QVariantList> rlist = iface->asyncCall("retrieveList");
+ rlist.waitForFinished();
+ QVERIFY(rlist.isFinished());
+ QCOMPARE(rlist.argumentAt<0>(), adaptor->retrieveList());
+
+ QDBusPendingReply<QVariantMap> rmap = iface->asyncCall("retrieveMap");
+ rmap.waitForFinished();
+ QVERIFY(rmap.isFinished());
+ QCOMPARE(rmap.argumentAt<0>(), adaptor->retrieveMap());
+
+ QDBusPendingReply<IntStringMap> rismap = iface->asyncCall("retrieveIntStringMap");
+ rismap.waitForFinished();
+ QVERIFY(rismap.isFinished());
+ QCOMPARE(rismap.argumentAt<0>(), adaptor->retrieveIntStringMap());
+
+ QDBusPendingReply<MyStruct> rstruct = iface->asyncCall("retrieveStruct");
+ rstruct.waitForFinished();
+ QVERIFY(rstruct.isFinished());
+ QCOMPARE(rstruct.argumentAt<0>(), adaptor->retrieveStruct());
+}
+
+#define VERIFY_WRONG_TYPE(error) \
+ QVERIFY(error.isValid()); \
+ QCOMPARE(error.type(), QDBusError::InvalidSignature)
+
+void tst_QDBusPendingReply::wrongTypes()
+{
+ QDBusError error;
+
+ QDBusPendingReply<bool> rbool = iface->asyncCall("retrieveInt");
+ rbool.waitForFinished();
+ QVERIFY(rbool.isFinished());
+ QVERIFY(rbool.isError());
+ error = rbool.error();
+ VERIFY_WRONG_TYPE(error);
+
+ rbool = iface->asyncCall("retrieveShort");
+ rbool.waitForFinished();
+ QVERIFY(rbool.isFinished());
+ QVERIFY(rbool.isError());
+ error = rbool.error();
+ VERIFY_WRONG_TYPE(error);
+
+ rbool = iface->asyncCall("retrieveStruct");
+ rbool.waitForFinished();
+ QVERIFY(rbool.isFinished());
+ QVERIFY(rbool.isError());
+ error = rbool.error();
+ VERIFY_WRONG_TYPE(error);
+
+ QDBusPendingReply<short> rshort = iface->asyncCall("retrieveInt");
+ rshort.waitForFinished();
+ QVERIFY(rshort.isFinished());
+ QVERIFY(rshort.isError());
+ error = rshort.error();
+ VERIFY_WRONG_TYPE(error);
+
+ rshort = iface->asyncCall("retrieveBool");
+ rshort.waitForFinished();
+ QVERIFY(rshort.isFinished());
+ QVERIFY(rshort.isError());
+ error = rshort.error();
+ VERIFY_WRONG_TYPE(error);
+
+ rshort = iface->asyncCall("retrieveStruct");
+ rshort.waitForFinished();
+ QVERIFY(rshort.isFinished());
+ QVERIFY(rshort.isError());
+ error = rshort.error();
+ VERIFY_WRONG_TYPE(error);
+
+ QDBusPendingReply<MyStruct> rstruct = iface->asyncCall("retrieveInt");
+ rstruct.waitForFinished();
+ QVERIFY(rstruct.isFinished());
+ QVERIFY(rstruct.isError());
+ error = rstruct.error();
+ VERIFY_WRONG_TYPE(error);
+
+ rstruct = iface->asyncCall("retrieveShort");
+ rstruct.waitForFinished();
+ QVERIFY(rstruct.isFinished());
+ QVERIFY(rstruct.isError());
+ error = rstruct.error();
+ VERIFY_WRONG_TYPE(error);
+
+ rstruct = iface->asyncCall("retrieveIntStringMap");
+ rstruct.waitForFinished();
+ QVERIFY(rstruct.isFinished());
+ QVERIFY(rstruct.isError());
+ error = rstruct.error();
+ VERIFY_WRONG_TYPE(error);
+}
+
+void tst_QDBusPendingReply::multipleTypes()
+{
+ QDBusPendingReply<int, int> rintint = iface->asyncCall("retrieveIntInt");
+ rintint.waitForFinished();
+ QVERIFY(rintint.isFinished());
+ QVERIFY(!rintint.isError());
+
+ int i1, i2;
+ adaptor->retrieveIntInt(i1, i2);
+ QCOMPARE(rintint.argumentAt<0>(), i1);
+ QCOMPARE(rintint.argumentAt<1>(), i2);
+}
+
+void tst_QDBusPendingReply::synchronousSimpleTypes()
+{
+ QDBusPendingReply<bool> rbool = iface->call("retrieveBool");
+ rbool.waitForFinished();
+ QVERIFY(rbool.isFinished());
+ QCOMPARE(rbool.argumentAt<0>(), adaptor->retrieveBool());
+
+ QDBusPendingReply<uchar> ruchar = iface->call("retrieveUChar");
+ ruchar.waitForFinished();
+ QVERIFY(ruchar.isFinished());
+ QCOMPARE(ruchar.argumentAt<0>(), adaptor->retrieveUChar());
+
+ QDBusPendingReply<short> rshort = iface->call("retrieveShort");
+ rshort.waitForFinished();
+ QVERIFY(rshort.isFinished());
+ QCOMPARE(rshort.argumentAt<0>(), adaptor->retrieveShort());
+
+ QDBusPendingReply<ushort> rushort = iface->call("retrieveUShort");
+ rushort.waitForFinished();
+ QVERIFY(rushort.isFinished());
+ QCOMPARE(rushort.argumentAt<0>(), adaptor->retrieveUShort());
+
+ QDBusPendingReply<int> rint = iface->call("retrieveInt");
+ rint.waitForFinished();
+ QVERIFY(rint.isFinished());
+ QCOMPARE(rint.argumentAt<0>(), adaptor->retrieveInt());
+
+ QDBusPendingReply<uint> ruint = iface->call("retrieveUInt");
+ ruint.waitForFinished();
+ QVERIFY(ruint.isFinished());
+ QCOMPARE(ruint.argumentAt<0>(), adaptor->retrieveUInt());
+
+ QDBusPendingReply<qlonglong> rqlonglong = iface->call("retrieveLongLong");
+ rqlonglong.waitForFinished();
+ QVERIFY(rqlonglong.isFinished());
+ QCOMPARE(rqlonglong.argumentAt<0>(), adaptor->retrieveLongLong());
+
+ QDBusPendingReply<qulonglong> rqulonglong = iface->call("retrieveULongLong");
+ rqulonglong.waitForFinished();
+ QVERIFY(rqulonglong.isFinished());
+ QCOMPARE(rqulonglong.argumentAt<0>(), adaptor->retrieveULongLong());
+
+ QDBusPendingReply<double> rdouble = iface->call("retrieveDouble");
+ rdouble.waitForFinished();
+ QVERIFY(rdouble.isFinished());
+ QCOMPARE(rdouble.argumentAt<0>(), adaptor->retrieveDouble());
+
+ QDBusPendingReply<QString> rstring = iface->call("retrieveString");
+ rstring.waitForFinished();
+ QVERIFY(rstring.isFinished());
+ QCOMPARE(rstring.argumentAt<0>(), adaptor->retrieveString());
+
+ QDBusPendingReply<QDBusObjectPath> robjectpath = iface->call("retrieveObjectPath");
+ robjectpath.waitForFinished();
+ QVERIFY(robjectpath.isFinished());
+ QCOMPARE(robjectpath.argumentAt<0>().path(), adaptor->retrieveObjectPath().path());
+
+ QDBusPendingReply<QDBusSignature> rsignature = iface->call("retrieveSignature");
+ rsignature.waitForFinished();
+ QVERIFY(rsignature.isFinished());
+ QCOMPARE(rsignature.argumentAt<0>().signature(), adaptor->retrieveSignature().signature());
+
+ QDBusPendingReply<QDBusVariant> rdbusvariant = iface->call("retrieveVariant");
+ rdbusvariant.waitForFinished();
+ QVERIFY(rdbusvariant.isFinished());
+ QCOMPARE(rdbusvariant.argumentAt<0>().variant(), adaptor->retrieveVariant().variant());
+
+ QDBusPendingReply<QByteArray> rbytearray = iface->call("retrieveByteArray");
+ rbytearray.waitForFinished();
+ QVERIFY(rbytearray.isFinished());
+ QCOMPARE(rbytearray.argumentAt<0>(), adaptor->retrieveByteArray());
+
+ QDBusPendingReply<QStringList> rstringlist = iface->call("retrieveStringList");
+ rstringlist.waitForFinished();
+ QVERIFY(rstringlist.isFinished());
+ QCOMPARE(rstringlist.argumentAt<0>(), adaptor->retrieveStringList());
+}
+
+#define VERIFY_ERROR(error) \
+ QVERIFY(error.isValid()); \
+ QCOMPARE(error.name(), QString("local.AnErrorName")); \
+ QCOMPARE(error.type(), QDBusError::Other)
+
+void tst_QDBusPendingReply::errors()
+{
+ QDBusError error;
+
+ QDBusPendingReply<> rvoid = iface->asyncCall("sendError");
+ rvoid.waitForFinished();
+ QVERIFY(rvoid.isFinished());
+ QVERIFY(rvoid.isError());
+ error = rvoid.error();
+ VERIFY_ERROR(error);
+
+ QDBusPendingReply<int> rint = iface->asyncCall("sendError");
+ rint.waitForFinished();
+ QVERIFY(rint.isFinished());
+ QVERIFY(rint.isError());
+ error = rint.error();
+ VERIFY_ERROR(error);
+
+ QDBusPendingReply<int,int> rintint = iface->asyncCall("sendError");
+ rintint.waitForFinished();
+ QVERIFY(rintint.isFinished());
+ QVERIFY(rintint.isError());
+ error = rintint.error();
+ VERIFY_ERROR(error);
+
+ QDBusPendingReply<QString> rstring = iface->asyncCall("sendError");
+ rstring.waitForFinished();
+ QVERIFY(rstring.isFinished());
+ QVERIFY(rstring.isError());
+ error = rstring.error();
+ VERIFY_ERROR(error);
+}
+
+QTEST_MAIN(tst_QDBusPendingReply)
+
+#include "tst_qdbuspendingreply.moc"
+#else
+QTEST_NOOP_MAIN
+#endif
diff --git a/tests/auto/dbus/qdbusreply/.gitignore b/tests/auto/dbus/qdbusreply/.gitignore
new file mode 100644
index 0000000000..886db18592
--- /dev/null
+++ b/tests/auto/dbus/qdbusreply/.gitignore
@@ -0,0 +1 @@
+tst_qdbusreply
diff --git a/tests/auto/dbus/qdbusreply/qdbusreply.pro b/tests/auto/dbus/qdbusreply/qdbusreply.pro
new file mode 100644
index 0000000000..c96116c0ab
--- /dev/null
+++ b/tests/auto/dbus/qdbusreply/qdbusreply.pro
@@ -0,0 +1,10 @@
+load(qttest_p4)
+QT = core
+contains(QT_CONFIG,dbus): {
+ SOURCES += tst_qdbusreply.cpp
+ QT += dbus
+} else {
+ SOURCES += ../qdbusmarshall/dummy.cpp
+}
+
+
diff --git a/tests/auto/dbus/qdbusreply/tst_qdbusreply.cpp b/tests/auto/dbus/qdbusreply/tst_qdbusreply.cpp
new file mode 100644
index 0000000000..8d18657c56
--- /dev/null
+++ b/tests/auto/dbus/qdbusreply/tst_qdbusreply.cpp
@@ -0,0 +1,377 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qcoreapplication.h>
+#include <qdebug.h>
+#include <qvariant.h>
+
+#include <QtTest/QtTest>
+
+#include <QtDBus>
+
+typedef QMap<int,QString> IntStringMap;
+Q_DECLARE_METATYPE(IntStringMap)
+
+struct MyStruct
+{
+ int i;
+ QString s;
+
+ MyStruct() : i(1), s("String") { }
+ bool operator==(const MyStruct &other) const
+ { return i == other.i && s == other.s; }
+};
+Q_DECLARE_METATYPE(MyStruct)
+
+QDBusArgument &operator<<(QDBusArgument &arg, const MyStruct &ms)
+{
+ arg.beginStructure();
+ arg << ms.i << ms.s;
+ arg.endStructure();
+ return arg;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &arg, MyStruct &ms)
+{
+ arg.beginStructure();
+ arg >> ms.i >> ms.s;
+ arg.endStructure();
+ return arg;
+}
+
+class TypesInterface;
+class tst_QDBusReply: public QObject
+{
+ Q_OBJECT
+ QDBusInterface *iface;
+ TypesInterface *adaptor;
+public:
+ tst_QDBusReply();
+
+private slots:
+ void initTestCase()
+ {
+ qDBusRegisterMetaType<IntStringMap>();
+ qDBusRegisterMetaType<MyStruct>();
+ }
+
+ void init();
+ void unconnected();
+ void simpleTypes();
+ void complexTypes();
+ void wrongTypes();
+};
+
+class TypesInterface: public QDBusAbstractAdaptor
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "com.trolltech.Qt.Autotests.TypesInterface")
+public:
+ TypesInterface(QObject *parent)
+ : QDBusAbstractAdaptor(parent)
+ { }
+
+public slots:
+ bool retrieveBool()
+ {
+ return true;
+ }
+
+ uchar retrieveUChar()
+ {
+ return 'A';
+ }
+
+ short retrieveShort()
+ {
+ return -47;
+ }
+
+ ushort retrieveUShort()
+ {
+ return 42U;
+ }
+
+ int retrieveInt()
+ {
+ return -470000;
+ }
+
+ uint retrieveUInt()
+ {
+ return 42424242;
+ }
+
+ qlonglong retrieveLongLong()
+ {
+ return -(Q_INT64_C(1) << 32);
+ }
+
+ qulonglong retrieveULongLong()
+ {
+ return Q_INT64_C(1) << 32;
+ }
+
+ double retrieveDouble()
+ {
+ return 1.5;
+ }
+
+ QString retrieveString()
+ {
+ return "This string you should see";
+ }
+
+ QDBusObjectPath retrieveObjectPath()
+ {
+ return QDBusObjectPath("/");
+ }
+
+ QDBusSignature retrieveSignature()
+ {
+ return QDBusSignature("g");
+ }
+
+ QDBusVariant retrieveVariant()
+ {
+ return QDBusVariant(retrieveString());
+ }
+
+ QStringList retrieveStringList()
+ {
+ return QStringList() << "one" << "two";
+ }
+
+ QByteArray retrieveByteArray()
+ {
+ return "Hello, World";
+ }
+
+ QVariantList retrieveList()
+ {
+ return QVariantList() << retrieveInt() << retrieveString()
+ << retrieveByteArray();
+ }
+
+ QList<QDBusObjectPath> retrieveObjectPathList()
+ {
+ return QList<QDBusObjectPath>() << QDBusObjectPath("/") << QDBusObjectPath("/foo");
+ }
+
+ QVariantMap retrieveMap()
+ {
+ QVariantMap map;
+ map["one"] = 1;
+ map["two"] = 2U;
+ map["string"] = retrieveString();
+ map["stringlist"] = retrieveStringList();
+ return map;
+ }
+
+ IntStringMap retrieveIntStringMap()
+ {
+ IntStringMap map;
+ map[1] = "1";
+ map[2] = "2";
+ map[-1231456] = "foo";
+ return map;
+ }
+
+ MyStruct retrieveStruct()
+ {
+ return MyStruct();
+ }
+};
+
+tst_QDBusReply::tst_QDBusReply()
+{
+ adaptor = new TypesInterface(this);
+ QDBusConnection::sessionBus().registerObject("/", this);
+
+ iface = new QDBusInterface(QDBusConnection::sessionBus().baseService(), "/",
+ "com.trolltech.Qt.Autotests.TypesInterface",
+ QDBusConnection::sessionBus(),
+ this);
+}
+
+void tst_QDBusReply::init()
+{
+ QVERIFY(iface);
+ QVERIFY(iface->isValid());
+}
+
+void tst_QDBusReply::unconnected()
+{
+ QDBusConnection con("invalid stored connection");
+ QVERIFY(!con.isConnected());
+ QDBusInterface iface("doesnt.matter", "/", "doesnt.matter", con);
+ QVERIFY(!iface.isValid());
+
+ QDBusReply<void> rvoid = iface.asyncCall("ReloadConfig");
+ QVERIFY(!rvoid.isValid());
+
+ QDBusReply<QString> rstring = iface.asyncCall("GetId");
+ QVERIFY(!rstring.isValid());
+ QVERIFY(rstring.value().isEmpty());
+}
+
+void tst_QDBusReply::simpleTypes()
+{
+ QDBusReply<bool> rbool = iface->call(QDBus::BlockWithGui, "retrieveBool");
+ QVERIFY(rbool.isValid());
+ QCOMPARE(rbool.value(), adaptor->retrieveBool());
+
+ QDBusReply<uchar> ruchar = iface->call(QDBus::BlockWithGui, "retrieveUChar");
+ QVERIFY(ruchar.isValid());
+ QCOMPARE(ruchar.value(), adaptor->retrieveUChar());
+
+ QDBusReply<short> rshort = iface->call(QDBus::BlockWithGui, "retrieveShort");
+ QVERIFY(rshort.isValid());
+ QCOMPARE(rshort.value(), adaptor->retrieveShort());
+
+ QDBusReply<ushort> rushort = iface->call(QDBus::BlockWithGui, "retrieveUShort");
+ QVERIFY(rushort.isValid());
+ QCOMPARE(rushort.value(), adaptor->retrieveUShort());
+
+ QDBusReply<int> rint = iface->call(QDBus::BlockWithGui, "retrieveInt");
+ QVERIFY(rint.isValid());
+ QCOMPARE(rint.value(), adaptor->retrieveInt());
+
+ QDBusReply<uint> ruint = iface->call(QDBus::BlockWithGui, "retrieveUInt");
+ QVERIFY(ruint.isValid());
+ QCOMPARE(ruint.value(), adaptor->retrieveUInt());
+
+ QDBusReply<qlonglong> rqlonglong = iface->call(QDBus::BlockWithGui, "retrieveLongLong");
+ QVERIFY(rqlonglong.isValid());
+ QCOMPARE(rqlonglong.value(), adaptor->retrieveLongLong());
+
+ QDBusReply<qulonglong> rqulonglong = iface->call(QDBus::BlockWithGui, "retrieveULongLong");
+ QVERIFY(rqulonglong.isValid());
+ QCOMPARE(rqulonglong.value(), adaptor->retrieveULongLong());
+
+ QDBusReply<double> rdouble = iface->call(QDBus::BlockWithGui, "retrieveDouble");
+ QVERIFY(rdouble.isValid());
+ QCOMPARE(rdouble.value(), adaptor->retrieveDouble());
+
+ QDBusReply<QString> rstring = iface->call(QDBus::BlockWithGui, "retrieveString");
+ QVERIFY(rstring.isValid());
+ QCOMPARE(rstring.value(), adaptor->retrieveString());
+
+ QDBusReply<QDBusObjectPath> robjectpath = iface->call(QDBus::BlockWithGui, "retrieveObjectPath");
+ QVERIFY(robjectpath.isValid());
+ QCOMPARE(robjectpath.value().path(), adaptor->retrieveObjectPath().path());
+
+ QDBusReply<QDBusSignature> rsignature = iface->call(QDBus::BlockWithGui, "retrieveSignature");
+ QVERIFY(rsignature.isValid());
+ QCOMPARE(rsignature.value().signature(), adaptor->retrieveSignature().signature());
+
+ QDBusReply<QDBusVariant> rdbusvariant = iface->call(QDBus::BlockWithGui, "retrieveVariant");
+ QVERIFY(rdbusvariant.isValid());
+ QCOMPARE(rdbusvariant.value().variant(), adaptor->retrieveVariant().variant());
+
+ QDBusReply<QVariant> rvariant = iface->call(QDBus::BlockWithGui, "retrieveVariant");
+ QVERIFY(rvariant.isValid());
+ QCOMPARE(rvariant.value(), adaptor->retrieveVariant().variant());
+
+ QDBusReply<QByteArray> rbytearray = iface->call(QDBus::BlockWithGui, "retrieveByteArray");
+ QVERIFY(rbytearray.isValid());
+ QCOMPARE(rbytearray.value(), adaptor->retrieveByteArray());
+
+ QDBusReply<QStringList> rstringlist = iface->call(QDBus::BlockWithGui, "retrieveStringList");
+ QVERIFY(rstringlist.isValid());
+ QCOMPARE(rstringlist.value(), adaptor->retrieveStringList());
+}
+
+void tst_QDBusReply::complexTypes()
+{
+ QDBusReply<QVariantList> rlist = iface->call(QDBus::BlockWithGui, "retrieveList");
+ QVERIFY(rlist.isValid());
+ QCOMPARE(rlist.value(), adaptor->retrieveList());
+
+ QDBusReply<QList<QDBusObjectPath> > rolist = iface->call(QDBus::BlockWithGui, "retrieveObjectPathList");
+ QVERIFY(rolist.isValid());
+ QCOMPARE(rolist.value(), adaptor->retrieveObjectPathList());
+
+ QDBusReply<QVariantMap> rmap = iface->call(QDBus::BlockWithGui, "retrieveMap");
+ QVERIFY(rmap.isValid());
+ QCOMPARE(rmap.value(), adaptor->retrieveMap());
+
+ QDBusReply<IntStringMap> rismap = iface->call(QDBus::BlockWithGui, "retrieveIntStringMap");
+ QVERIFY(rismap.isValid());
+ QCOMPARE(rismap.value(), adaptor->retrieveIntStringMap());
+
+ QDBusReply<MyStruct> rstruct = iface->call(QDBus::BlockWithGui, "retrieveStruct");
+ QVERIFY(rstruct.isValid());
+ QCOMPARE(rstruct.value(), adaptor->retrieveStruct());
+}
+
+void tst_QDBusReply::wrongTypes()
+{
+ QDBusReply<bool> rbool = iface->call(QDBus::BlockWithGui, "retrieveInt");
+ QVERIFY(!rbool.isValid());
+
+ rbool = iface->call(QDBus::BlockWithGui, "retrieveShort");
+ QVERIFY(!rbool.isValid());
+
+ rbool = iface->call(QDBus::BlockWithGui, "retrieveStruct");
+ QVERIFY(!rbool.isValid());
+
+ QDBusReply<short> rshort = iface->call(QDBus::BlockWithGui, "retrieveInt");
+ QVERIFY(!rshort.isValid());
+
+ rshort = iface->call(QDBus::BlockWithGui, "retrieveBool");
+ QVERIFY(!rshort.isValid());
+
+ rshort = iface->call(QDBus::BlockWithGui, "retrieveStruct");
+ QVERIFY(!rshort.isValid());
+
+ QDBusReply<MyStruct> rstruct = iface->call(QDBus::BlockWithGui, "retrieveInt");
+ QVERIFY(!rstruct.isValid());
+
+ rstruct = iface->call(QDBus::BlockWithGui, "retrieveShort");
+ QVERIFY(!rstruct.isValid());
+
+ rstruct = iface->call(QDBus::BlockWithGui, "retrieveIntStringMap");
+ QVERIFY(!rstruct.isValid());
+}
+
+QTEST_MAIN(tst_QDBusReply)
+
+#include "tst_qdbusreply.moc"
diff --git a/tests/auto/dbus/qdbusservicewatcher/qdbusservicewatcher.pro b/tests/auto/dbus/qdbusservicewatcher/qdbusservicewatcher.pro
new file mode 100644
index 0000000000..4970f16863
--- /dev/null
+++ b/tests/auto/dbus/qdbusservicewatcher/qdbusservicewatcher.pro
@@ -0,0 +1,8 @@
+load(qttest_p4)
+QT = core
+contains(QT_CONFIG,dbus): {
+ SOURCES += tst_qdbusservicewatcher.cpp
+ QT += dbus
+} else {
+ SOURCES += ../qdbusmarshall/dummy.cpp
+}
diff --git a/tests/auto/dbus/qdbusservicewatcher/tst_qdbusservicewatcher.cpp b/tests/auto/dbus/qdbusservicewatcher/tst_qdbusservicewatcher.cpp
new file mode 100644
index 0000000000..99aeefa8ee
--- /dev/null
+++ b/tests/auto/dbus/qdbusservicewatcher/tst_qdbusservicewatcher.cpp
@@ -0,0 +1,275 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtDBus/QDBusServiceWatcher>
+#include <QtDBus>
+#include <QtTest>
+
+class tst_QDBusServiceWatcher: public QObject
+{
+ Q_OBJECT
+ QString serviceName;
+ int testCounter;
+public:
+ tst_QDBusServiceWatcher();
+
+private slots:
+ void initTestCase();
+ void init();
+
+ void watchForCreation();
+ void watchForDisappearance();
+ void watchForOwnerChange();
+ void modeChange();
+};
+
+tst_QDBusServiceWatcher::tst_QDBusServiceWatcher()
+ : testCounter(0)
+{
+}
+
+void tst_QDBusServiceWatcher::initTestCase()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+}
+
+void tst_QDBusServiceWatcher::init()
+{
+ // change the service name from test to test
+ serviceName = "com.example.TestService" + QString::number(testCounter++);
+}
+
+void tst_QDBusServiceWatcher::watchForCreation()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+
+ QDBusServiceWatcher watcher(serviceName, con, QDBusServiceWatcher::WatchForRegistration);
+
+ QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString)));
+ QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString)));
+ QSignalSpy spyO(&watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)));
+ QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceRegistered(QString)), SLOT(exitLoop()));
+
+ // register a name
+ QVERIFY(con.registerService(serviceName));
+
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(spyR.count(), 1);
+ QCOMPARE(spyR.at(0).at(0).toString(), serviceName);
+
+ QCOMPARE(spyU.count(), 0);
+
+ QCOMPARE(spyO.count(), 1);
+ QCOMPARE(spyO.at(0).at(0).toString(), serviceName);
+ QVERIFY(spyO.at(0).at(1).toString().isEmpty());
+ QCOMPARE(spyO.at(0).at(2).toString(), con.baseService());
+
+ spyR.clear();
+ spyU.clear();
+ spyO.clear();
+
+ // unregister it:
+ con.unregisterService(serviceName);
+
+ // and register again
+ QVERIFY(con.registerService(serviceName));
+
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(spyR.count(), 1);
+ QCOMPARE(spyR.at(0).at(0).toString(), serviceName);
+
+ QCOMPARE(spyU.count(), 0);
+
+ QCOMPARE(spyO.count(), 1);
+ QCOMPARE(spyO.at(0).at(0).toString(), serviceName);
+ QVERIFY(spyO.at(0).at(1).toString().isEmpty());
+ QCOMPARE(spyO.at(0).at(2).toString(), con.baseService());
+}
+
+void tst_QDBusServiceWatcher::watchForDisappearance()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+
+ QDBusServiceWatcher watcher(serviceName, con, QDBusServiceWatcher::WatchForUnregistration);
+ watcher.setObjectName("watcher for disappearance");
+
+ QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString)));
+ QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString)));
+ QSignalSpy spyO(&watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)));
+ QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceUnregistered(QString)), SLOT(exitLoop()));
+
+ // register a name
+ QVERIFY(con.registerService(serviceName));
+
+ // unregister it:
+ con.unregisterService(serviceName);
+
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(spyR.count(), 0);
+
+ QCOMPARE(spyU.count(), 1);
+ QCOMPARE(spyU.at(0).at(0).toString(), serviceName);
+
+ QCOMPARE(spyO.count(), 1);
+ QCOMPARE(spyO.at(0).at(0).toString(), serviceName);
+ QCOMPARE(spyO.at(0).at(1).toString(), con.baseService());
+ QVERIFY(spyO.at(0).at(2).toString().isEmpty());
+}
+
+void tst_QDBusServiceWatcher::watchForOwnerChange()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+
+ QDBusServiceWatcher watcher(serviceName, con, QDBusServiceWatcher::WatchForOwnerChange);
+
+ QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString)));
+ QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString)));
+ QSignalSpy spyO(&watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)));
+ QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceRegistered(QString)), SLOT(exitLoop()));
+
+ // register a name
+ QVERIFY(con.registerService(serviceName));
+
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(spyR.count(), 1);
+ QCOMPARE(spyR.at(0).at(0).toString(), serviceName);
+
+ QCOMPARE(spyU.count(), 0);
+
+ QCOMPARE(spyO.count(), 1);
+ QCOMPARE(spyO.at(0).at(0).toString(), serviceName);
+ QVERIFY(spyO.at(0).at(1).toString().isEmpty());
+ QCOMPARE(spyO.at(0).at(2).toString(), con.baseService());
+
+ spyR.clear();
+ spyU.clear();
+ spyO.clear();
+
+ // unregister it:
+ con.unregisterService(serviceName);
+
+ // and register again
+ QVERIFY(con.registerService(serviceName));
+
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(spyR.count(), 1);
+ QCOMPARE(spyR.at(0).at(0).toString(), serviceName);
+
+ QCOMPARE(spyU.count(), 1);
+ QCOMPARE(spyU.at(0).at(0).toString(), serviceName);
+
+ QCOMPARE(spyO.count(), 2);
+ QCOMPARE(spyO.at(0).at(0).toString(), serviceName);
+ QCOMPARE(spyO.at(0).at(1).toString(), con.baseService());
+ QVERIFY(spyO.at(0).at(2).toString().isEmpty());
+ QCOMPARE(spyO.at(1).at(0).toString(), serviceName);
+ QVERIFY(spyO.at(1).at(1).toString().isEmpty());
+ QCOMPARE(spyO.at(1).at(2).toString(), con.baseService());
+}
+
+void tst_QDBusServiceWatcher::modeChange()
+{
+ QDBusConnection con = QDBusConnection::sessionBus();
+ QVERIFY(con.isConnected());
+
+ QDBusServiceWatcher watcher(serviceName, con, QDBusServiceWatcher::WatchForRegistration);
+
+ QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString)));
+ QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString)));
+ QSignalSpy spyO(&watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)));
+ QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceRegistered(QString)), SLOT(exitLoop()));
+
+ // register a name
+ QVERIFY(con.registerService(serviceName));
+
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(spyR.count(), 1);
+ QCOMPARE(spyR.at(0).at(0).toString(), serviceName);
+
+ QCOMPARE(spyU.count(), 0);
+
+ QCOMPARE(spyO.count(), 1);
+ QCOMPARE(spyO.at(0).at(0).toString(), serviceName);
+ QVERIFY(spyO.at(0).at(1).toString().isEmpty());
+ QCOMPARE(spyO.at(0).at(2).toString(), con.baseService());
+
+ spyR.clear();
+ spyU.clear();
+ spyO.clear();
+
+ watcher.setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
+
+ // unregister it:
+ con.unregisterService(serviceName);
+
+ QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceUnregistered(QString)), SLOT(exitLoop()));
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(spyR.count(), 0);
+
+ QCOMPARE(spyU.count(), 1);
+ QCOMPARE(spyU.at(0).at(0).toString(), serviceName);
+
+ QCOMPARE(spyO.count(), 1);
+ QCOMPARE(spyO.at(0).at(0).toString(), serviceName);
+ QCOMPARE(spyO.at(0).at(1).toString(), con.baseService());
+ QVERIFY(spyO.at(0).at(2).toString().isEmpty());
+}
+
+QTEST_MAIN(tst_QDBusServiceWatcher)
+#include "tst_qdbusservicewatcher.moc"
diff --git a/tests/auto/dbus/qdbusthreading/.gitignore b/tests/auto/dbus/qdbusthreading/.gitignore
new file mode 100644
index 0000000000..70c71f3ab7
--- /dev/null
+++ b/tests/auto/dbus/qdbusthreading/.gitignore
@@ -0,0 +1 @@
+tst_qdbusthreading
diff --git a/tests/auto/dbus/qdbusthreading/qdbusthreading.pro b/tests/auto/dbus/qdbusthreading/qdbusthreading.pro
new file mode 100644
index 0000000000..e239e9861e
--- /dev/null
+++ b/tests/auto/dbus/qdbusthreading/qdbusthreading.pro
@@ -0,0 +1,11 @@
+load(qttest_p4)
+QT = core
+
+contains(QT_CONFIG,dbus): {
+ SOURCES += tst_qdbusthreading.cpp
+ QT += dbus
+} else {
+ SOURCES += ../qdbusmarshall/dummy.cpp
+}
+
+
diff --git a/tests/auto/dbus/qdbusthreading/tst_qdbusthreading.cpp b/tests/auto/dbus/qdbusthreading/tst_qdbusthreading.cpp
new file mode 100644
index 0000000000..e37e4c3ae7
--- /dev/null
+++ b/tests/auto/dbus/qdbusthreading/tst_qdbusthreading.cpp
@@ -0,0 +1,613 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtTest>
+#include <QtDBus>
+#include <QtCore/QVarLengthArray>
+#include <QtCore/QThread>
+#include <QtCore/QObject>
+#include <QtCore/QSemaphore>
+#include <QtCore/QMutex>
+#include <QtCore/QWaitCondition>
+#include <QtCore/QMap>
+
+class Thread : public QThread
+{
+ Q_OBJECT
+ static int counter;
+public:
+ Thread(bool automatic = true);
+ void run();
+
+ using QThread::exec;
+};
+int Thread::counter;
+
+class tst_QDBusThreading : public QObject
+{
+ Q_OBJECT
+ static tst_QDBusThreading *_self;
+ QAtomicInt threadJoinCount;
+ QSemaphore threadJoin;
+public:
+ QSemaphore sem1, sem2;
+ volatile bool success;
+ QEventLoop *loop;
+ enum FunctionSpy {
+ NoMethod = 0,
+ Adaptor_method,
+ Object_method
+ } functionSpy;
+
+ QThread *threadSpy;
+ int signalSpy;
+
+ tst_QDBusThreading();
+ static inline tst_QDBusThreading *self() { return _self; }
+
+ void joinThreads();
+ bool waitForSignal(QObject *obj, const char *signal, int delay = 1);
+
+public Q_SLOTS:
+ void cleanup();
+ void signalSpySlot() { ++signalSpy; }
+ void threadStarted() { threadJoinCount.ref(); }
+ void threadFinished() { threadJoin.release(); }
+
+ void dyingThread_thread();
+ void lastInstanceInOtherThread_thread();
+ void concurrentCreation_thread();
+ void disconnectAnothersConnection_thread();
+ void accessMainsConnection_thread();
+ void accessOthersConnection_thread();
+ void registerObjectInOtherThread_thread();
+ void registerAdaptorInOtherThread_thread();
+ void callbackInMainThread_thread();
+ void callbackInAuxThread_thread();
+ void callbackInAnotherAuxThread_thread();
+
+private Q_SLOTS:
+ void initTestCase();
+ void dyingThread();
+ void lastInstanceInOtherThread();
+ void concurrentCreation();
+ void disconnectAnothersConnection();
+ void accessMainsConnection();
+ void accessOthersConnection();
+ void registerObjectInOtherThread();
+ void registerAdaptorInOtherThread();
+ void callbackInMainThread();
+ void callbackInAuxThread();
+ void callbackInAnotherAuxThread();
+};
+tst_QDBusThreading *tst_QDBusThreading::_self;
+
+class Adaptor : public QDBusAbstractAdaptor
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "local.Adaptor")
+public:
+ Adaptor(QObject *parent)
+ : QDBusAbstractAdaptor(parent)
+ {
+ }
+
+public Q_SLOTS:
+ void method()
+ {
+ tst_QDBusThreading::self()->functionSpy = tst_QDBusThreading::Adaptor_method;
+ tst_QDBusThreading::self()->threadSpy = QThread::currentThread();
+ emit signal();
+ }
+
+Q_SIGNALS:
+ void signal();
+};
+
+class Object : public QObject
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "local.Object")
+public:
+ Object(bool useAdaptor)
+ {
+ if (useAdaptor)
+ new Adaptor(this);
+ }
+
+ ~Object()
+ {
+ QMetaObject::invokeMethod(QThread::currentThread(), "quit", Qt::QueuedConnection);
+ }
+
+public Q_SLOTS:
+ void method()
+ {
+ tst_QDBusThreading::self()->functionSpy = tst_QDBusThreading::Object_method;
+ tst_QDBusThreading::self()->threadSpy = QThread::currentThread();
+ emit signal();
+ deleteLater();
+ }
+
+Q_SIGNALS:
+ void signal();
+};
+
+#if 0
+typedef void (*qdbusThreadDebugFunc)(int, int, QDBusConnectionPrivate *);
+QDBUS_EXPORT void qdbusDefaultThreadDebug(int, int, QDBusConnectionPrivate *);
+extern QDBUS_EXPORT qdbusThreadDebugFunc qdbusThreadDebug;
+
+static void threadDebug(int action, int condition, QDBusConnectionPrivate *p)
+{
+ qdbusDefaultThreadDebug(action, condition, p);
+}
+#endif
+
+Thread::Thread(bool automatic)
+{
+ setObjectName(QString::fromLatin1("Aux thread %1").arg(++counter));
+ connect(this, SIGNAL(started()), tst_QDBusThreading::self(), SLOT(threadStarted()));
+ connect(this, SIGNAL(finished()), tst_QDBusThreading::self(), SLOT(threadFinished()),
+ Qt::DirectConnection);
+ connect(this, SIGNAL(finished()), this, SLOT(deleteLater()), Qt::DirectConnection);
+ if (automatic)
+ start();
+}
+
+void Thread::run()
+{
+ QVarLengthArray<char, 56> name;
+ name.append(QTest::currentTestFunction(), qstrlen(QTest::currentTestFunction()));
+ name.append("_thread", sizeof "_thread");
+ QMetaObject::invokeMethod(tst_QDBusThreading::self(), name.constData(), Qt::DirectConnection);
+}
+
+static const char myConnectionName[] = "connection";
+
+tst_QDBusThreading::tst_QDBusThreading()
+ : loop(0), functionSpy(NoMethod), threadSpy(0)
+{
+ _self = this;
+ QCoreApplication::instance()->thread()->setObjectName("Main thread");
+}
+
+void tst_QDBusThreading::joinThreads()
+{
+ threadJoin.acquire(threadJoinCount);
+ threadJoinCount = 0;
+}
+
+bool tst_QDBusThreading::waitForSignal(QObject *obj, const char *signal, int delay)
+{
+ QObject::connect(obj, signal, &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QPointer<QObject> safe = obj;
+
+ QTestEventLoop::instance().enterLoop(delay);
+ if (!safe.isNull())
+ QObject::disconnect(safe, signal, &QTestEventLoop::instance(), SLOT(exitLoop()));
+ return QTestEventLoop::instance().timeout();
+}
+
+void tst_QDBusThreading::cleanup()
+{
+ joinThreads();
+
+ if (sem1.available())
+ sem1.acquire(sem1.available());
+ if (sem2.available())
+ sem2.acquire(sem2.available());
+
+ if (QDBusConnection(myConnectionName).isConnected())
+ QDBusConnection::disconnectFromBus(myConnectionName);
+
+ delete loop;
+ loop = 0;
+
+ QTest::qWait(500);
+}
+
+void tst_QDBusThreading::initTestCase()
+{
+}
+
+void tst_QDBusThreading::dyingThread_thread()
+{
+ QDBusConnection::connectToBus(QDBusConnection::SessionBus, myConnectionName);
+}
+
+void tst_QDBusThreading::dyingThread()
+{
+ Thread *th = new Thread(false);
+ QTestEventLoop::instance().connect(th, SIGNAL(destroyed(QObject*)), SLOT(exitLoop()));
+ th->start();
+
+ QTestEventLoop::instance().enterLoop(10);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QDBusConnection con(myConnectionName);
+ QDBusConnection::disconnectFromBus(myConnectionName);
+
+ QVERIFY(con.isConnected());
+ QDBusReply<QStringList> reply = con.interface()->registeredServiceNames();
+ QVERIFY(reply.isValid());
+ QVERIFY(!reply.value().isEmpty());
+ QVERIFY(reply.value().contains(con.baseService()));
+
+ con.interface()->callWithCallback("ListNames", QVariantList(),
+ &QTestEventLoop::instance(), SLOT(exitLoop()));
+
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+}
+
+void tst_QDBusThreading::lastInstanceInOtherThread_thread()
+{
+ QDBusConnection con(myConnectionName);
+ QVERIFY(con.isConnected());
+
+ QDBusConnection::disconnectFromBus(myConnectionName);
+
+ // con is being destroyed in the wrong thread
+}
+
+void tst_QDBusThreading::lastInstanceInOtherThread()
+{
+ Thread *th = new Thread(false);
+ // create the connection:
+ QDBusConnection::connectToBus(QDBusConnection::SessionBus, myConnectionName);
+
+ th->start();
+ th->wait();
+}
+
+void tst_QDBusThreading::concurrentCreation_thread()
+{
+ sem1.acquire();
+ QDBusConnection con = QDBusConnection::connectToBus(QDBusConnection::SessionBus,
+ myConnectionName);
+ sem2.release();
+}
+
+void tst_QDBusThreading::concurrentCreation()
+{
+ Thread *th = new Thread;
+
+ {
+ sem1.release();
+ QDBusConnection con = QDBusConnection::connectToBus(QDBusConnection::SessionBus,
+ myConnectionName);
+ QVERIFY(con.isConnected());
+ sem2.acquire();
+ }
+ waitForSignal(th, SIGNAL(finished()));
+ QDBusConnection::disconnectFromBus(myConnectionName);
+
+ QVERIFY(!QDBusConnection(myConnectionName).isConnected());
+}
+
+void tst_QDBusThreading::disconnectAnothersConnection_thread()
+{
+ QDBusConnection con = QDBusConnection::connectToBus(QDBusConnection::SessionBus,
+ myConnectionName);
+ sem2.release();
+}
+
+void tst_QDBusThreading::disconnectAnothersConnection()
+{
+ new Thread;
+ sem2.acquire();
+
+ QVERIFY(QDBusConnection(myConnectionName).isConnected());
+ QDBusConnection::disconnectFromBus(myConnectionName);
+}
+
+void tst_QDBusThreading::accessMainsConnection_thread()
+{
+ sem1.acquire();
+ QDBusConnection con = QDBusConnection::sessionBus();
+ con.interface()->registeredServiceNames();
+ sem2.release();
+}
+
+void tst_QDBusThreading::accessMainsConnection()
+{
+ QVERIFY(QDBusConnection::sessionBus().isConnected());
+
+ new Thread;
+ sem1.release();
+ sem2.acquire();
+};
+
+void tst_QDBusThreading::accessOthersConnection_thread()
+{
+ QDBusConnection::connectToBus(QDBusConnection::SessionBus, myConnectionName);
+ sem2.release();
+
+ // wait for main thread to be done
+ sem1.acquire();
+ QDBusConnection::disconnectFromBus(myConnectionName);
+ sem2.release();
+}
+
+void tst_QDBusThreading::accessOthersConnection()
+{
+ new Thread;
+
+ // wait for the connection to be created
+ sem2.acquire();
+
+ {
+ QDBusConnection con(myConnectionName);
+ QVERIFY(con.isConnected());
+ QVERIFY(con.baseService() != QDBusConnection::sessionBus().baseService());
+
+ QDBusReply<QStringList> reply = con.interface()->registeredServiceNames();
+ if (!reply.isValid())
+ qDebug() << reply.error().name() << reply.error().message();
+ QVERIFY(reply.isValid());
+ QVERIFY(!reply.value().isEmpty());
+ QVERIFY(reply.value().contains(con.baseService()));
+ QVERIFY(reply.value().contains(QDBusConnection::sessionBus().baseService()));
+ }
+
+ // tell it to destroy:
+ sem1.release();
+ sem2.acquire();
+
+ QDBusConnection con(myConnectionName);
+ QVERIFY(!con.isConnected());
+}
+
+void tst_QDBusThreading::registerObjectInOtherThread_thread()
+{
+ {
+ Object *obj = new Object(false);
+ QDBusConnection::sessionBus().registerObject("/", obj, QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals);
+
+ sem2.release();
+ static_cast<Thread *>(QThread::currentThread())->exec();
+ }
+
+ sem2.release();
+}
+
+void tst_QDBusThreading::registerObjectInOtherThread()
+{
+ QVERIFY(QDBusConnection::sessionBus().isConnected());
+ QThread *th = new Thread;
+ sem2.acquire();
+
+ signalSpy = 0;
+
+ QDBusInterface iface(QDBusConnection::sessionBus().baseService(), "/", "local.Object");
+ QVERIFY(iface.isValid());
+
+ connect(&iface, SIGNAL(signal()), SLOT(signalSpySlot()));
+
+ QTest::qWait(100);
+ QCOMPARE(signalSpy, 0);
+
+ functionSpy = NoMethod;
+ threadSpy = 0;
+ QDBusReply<void> reply = iface.call("method");
+ QVERIFY(reply.isValid());
+ QCOMPARE(functionSpy, Object_method);
+ QCOMPARE(threadSpy, th);
+
+ QTest::qWait(100);
+ QCOMPARE(signalSpy, 1);
+
+ sem2.acquire(); // the object is gone
+ functionSpy = NoMethod;
+ threadSpy = 0;
+ reply = iface.call("method");
+ QVERIFY(!reply.isValid());
+ QCOMPARE(functionSpy, NoMethod);
+ QCOMPARE(threadSpy, (QThread*)0);
+}
+
+void tst_QDBusThreading::registerAdaptorInOtherThread_thread()
+{
+ {
+ Object *obj = new Object(true);
+ QDBusConnection::sessionBus().registerObject("/", obj, QDBusConnection::ExportAdaptors |
+ QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals);
+
+ sem2.release();
+ static_cast<Thread *>(QThread::currentThread())->exec();
+ }
+
+ sem2.release();
+}
+
+void tst_QDBusThreading::registerAdaptorInOtherThread()
+{
+ QVERIFY(QDBusConnection::sessionBus().isConnected());
+ QThread *th = new Thread;
+ sem2.acquire();
+
+ QDBusInterface object(QDBusConnection::sessionBus().baseService(), "/", "local.Object");
+ QDBusInterface adaptor(QDBusConnection::sessionBus().baseService(), "/", "local.Adaptor");
+ QVERIFY(object.isValid());
+ QVERIFY(adaptor.isValid());
+
+ signalSpy = 0;
+ connect(&adaptor, SIGNAL(signal()), SLOT(signalSpySlot()));
+ QCOMPARE(signalSpy, 0);
+
+ functionSpy = NoMethod;
+ threadSpy = 0;
+ QDBusReply<void> reply = adaptor.call("method");
+ QVERIFY(reply.isValid());
+ QCOMPARE(functionSpy, Adaptor_method);
+ QCOMPARE(threadSpy, th);
+
+ QTest::qWait(100);
+ QCOMPARE(signalSpy, 1);
+
+ functionSpy = NoMethod;
+ threadSpy = 0;
+ reply = object.call("method");
+ QVERIFY(reply.isValid());
+ QCOMPARE(functionSpy, Object_method);
+ QCOMPARE(threadSpy, th);
+
+ QTest::qWait(100);
+ QCOMPARE(signalSpy, 1);
+
+ sem2.acquire(); // the object is gone
+ functionSpy = NoMethod;
+ threadSpy = 0;
+ reply = adaptor.call("method");
+ QVERIFY(!reply.isValid());
+ QCOMPARE(functionSpy, NoMethod);
+ QCOMPARE(threadSpy, (QThread*)0);
+ reply = object.call("method");
+ QVERIFY(!reply.isValid());
+ QCOMPARE(functionSpy, NoMethod);
+ QCOMPARE(threadSpy, (QThread*)0);
+}
+
+void tst_QDBusThreading::callbackInMainThread_thread()
+{
+ QDBusConnection::connectToBus(QDBusConnection::SessionBus, myConnectionName);
+ sem2.release();
+
+ static_cast<Thread *>(QThread::currentThread())->exec();
+ QDBusConnection::disconnectFromBus(myConnectionName);
+}
+
+void tst_QDBusThreading::callbackInMainThread()
+{
+ Thread *th = new Thread;
+
+ // wait for it to be connected
+ sem2.acquire();
+
+ QDBusConnection con(myConnectionName);
+ con.interface()->callWithCallback("ListNames", QVariantList(),
+ &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QTestEventLoop::instance().enterLoop(10);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QMetaObject::invokeMethod(th, "quit");
+ waitForSignal(th, SIGNAL(finished()));
+}
+
+void tst_QDBusThreading::callbackInAuxThread_thread()
+{
+ QDBusConnection con(QDBusConnection::sessionBus());
+ QTestEventLoop ownLoop;
+ con.interface()->callWithCallback("ListNames", QVariantList(),
+ &ownLoop, SLOT(exitLoop()));
+ ownLoop.enterLoop(10);
+ loop->exit(ownLoop.timeout() ? 1 : 0);
+}
+
+void tst_QDBusThreading::callbackInAuxThread()
+{
+ QVERIFY(QDBusConnection::sessionBus().isConnected());
+
+ loop = new QEventLoop;
+
+ new Thread;
+ QCOMPARE(loop->exec(), 0);
+}
+
+void tst_QDBusThreading::callbackInAnotherAuxThread_thread()
+{
+ sem1.acquire();
+ if (!loop) {
+ // first thread
+ // create the connection and just wait
+ QDBusConnection con = QDBusConnection::connectToBus(QDBusConnection::SessionBus, myConnectionName);
+ loop = new QEventLoop;
+
+ // tell the main thread we have created the loop and connection
+ sem2.release();
+
+ // wait for the main thread to connect its signal
+ sem1.acquire();
+ success = loop->exec() == 0;
+ sem2.release();
+
+ // clean up
+ QDBusConnection::disconnectFromBus(myConnectionName);
+ } else {
+ // second thread
+ // try waiting for a message
+ QDBusConnection con(myConnectionName);
+ QTestEventLoop ownLoop;
+ con.interface()->callWithCallback("ListNames", QVariantList(),
+ &ownLoop, SLOT(exitLoop()));
+ ownLoop.enterLoop(1);
+ loop->exit(ownLoop.timeout() ? 1 : 0);
+ }
+}
+
+void tst_QDBusThreading::callbackInAnotherAuxThread()
+{
+ // create first thread
+ success = false;
+ new Thread;
+
+ // wait for the event loop
+ sem1.release();
+ sem2.acquire();
+ QVERIFY(loop);
+
+ // create the second thread
+ new Thread;
+ sem1.release(2);
+
+ // wait for loop thread to finish executing:
+ sem2.acquire();
+
+ QVERIFY(success);
+}
+
+// Next tests:
+// - unexport an object at the moment the call is being delivered
+// - delete an object at the moment the call is being delivered
+// - keep a global-static QDBusConnection for a thread-created connection
+
+QTEST_MAIN(tst_QDBusThreading)
+#include "tst_qdbusthreading.moc"
diff --git a/tests/auto/dbus/qdbustype/qdbustype.pro b/tests/auto/dbus/qdbustype/qdbustype.pro
new file mode 100644
index 0000000000..9b6808b562
--- /dev/null
+++ b/tests/auto/dbus/qdbustype/qdbustype.pro
@@ -0,0 +1,10 @@
+load(qttest_p4)
+QT = core core-private
+contains(QT_CONFIG,dbus): {
+ SOURCES += tst_qdbustype.cpp
+ QT += dbus dbus-private
+ QMAKE_CXXFLAGS += $$QT_CFLAGS_DBUS
+ LIBS_PRIVATE += $$QT_LIBS_DBUS
+} else {
+ SOURCES += ../qdbusmarshall/dummy.cpp
+}
diff --git a/tests/auto/dbus/qdbustype/tst_qdbustype.cpp b/tests/auto/dbus/qdbustype/tst_qdbustype.cpp
new file mode 100644
index 0000000000..5c46b4684a
--- /dev/null
+++ b/tests/auto/dbus/qdbustype/tst_qdbustype.cpp
@@ -0,0 +1,273 @@
+/****************************************************************************
+**
+** 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 FOO module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtCore/QCoreApplication>
+
+#include <QtDBus/private/qdbusutil_p.h>
+
+#include <dbus/dbus.h>
+
+class tst_QDBusType : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void isValidFixedType_data();
+ void isValidFixedType();
+ void isValidBasicType_data();
+ void isValidBasicType();
+ void isValidSingleSignature_data();
+ void isValidSingleSignature();
+ void isValidArray_data();
+ void isValidArray();
+ void isValidSignature_data();
+ void isValidSignature();
+};
+
+enum { Invalid = false, Valid = true };
+
+static void addColumns()
+{
+ // All tests use these two columns only
+ QTest::addColumn<QString>("data");
+ QTest::addColumn<bool>("result");
+ QTest::addColumn<bool>("isValid");
+}
+
+// ---- type adds ---
+static void addFixedTypes()
+{
+ QTest::newRow("bool") << DBUS_TYPE_BOOLEAN_AS_STRING << true << true;
+ QTest::newRow("byte") << DBUS_TYPE_BYTE_AS_STRING << true << true;
+ QTest::newRow("int16") << DBUS_TYPE_INT16_AS_STRING << true << true;
+ QTest::newRow("uint16") << DBUS_TYPE_UINT16_AS_STRING << true << true;
+ QTest::newRow("int32") << DBUS_TYPE_INT32_AS_STRING << true << true;
+ QTest::newRow("uint32") << DBUS_TYPE_UINT32_AS_STRING << true << true;
+ QTest::newRow("int64") << DBUS_TYPE_INT64_AS_STRING << true << true;
+ QTest::newRow("uint64") << DBUS_TYPE_UINT64_AS_STRING << true << true;
+ QTest::newRow("double") << DBUS_TYPE_DOUBLE_AS_STRING << true << true;
+#ifdef DBUS_TYPE_UNIX_FD_AS_STRING
+ QTest::newRow("unixfd") << DBUS_TYPE_UNIX_FD_AS_STRING << true << true;
+#endif
+}
+
+static void addInvalidSingleLetterTypes()
+{
+ QChar nulString[] = { 0 };
+ QTest::newRow("nul") << QString(nulString, 1) << false << false;
+ QTest::newRow("tilde") << "~" << false << false;
+ QTest::newRow("struct-begin") << "(" << false << false;
+ QTest::newRow("struct-end") << ")" << false << false;
+ QTest::newRow("dict-entry-begin") << "{" << false << false;
+ QTest::newRow("dict-entry-end") << "}" << false << false;
+ QTest::newRow("array-no-element") << "a" << false << false;
+}
+
+static void addBasicTypes(bool basicsAreValid)
+{
+ addFixedTypes();
+ QTest::newRow("string") << DBUS_TYPE_STRING_AS_STRING << basicsAreValid << true;
+ QTest::newRow("object-path") << DBUS_TYPE_OBJECT_PATH_AS_STRING << basicsAreValid << true;
+ QTest::newRow("signature") << DBUS_TYPE_SIGNATURE_AS_STRING << basicsAreValid << true;
+}
+
+static void addVariant(bool variantIsValid)
+{
+ QTest::newRow("variant") << "v" << variantIsValid << true;
+}
+
+static void addSingleSignatures()
+{
+ addBasicTypes(Valid);
+ addVariant(Valid);
+ QTest::newRow("struct-1") << "(y)" << true;
+ QTest::newRow("struct-2") << "(yy)" << true;
+ QTest::newRow("struct-3") << "(yyv)" << true;
+
+ QTest::newRow("struct-nested-1") << "((y))" << true;
+ QTest::newRow("struct-nested-2") << "((yy))" << true;
+ QTest::newRow("struct-nested-3") << "(y(y))" << true;
+ QTest::newRow("struct-nested-4") << "((y)y)" << true;
+ QTest::newRow("struct-nested-5") << "(y(y)y)" << true;
+ QTest::newRow("struct-nested-6") << "((y)(y))" << true;
+
+ QTest::newRow("array-1") << "as" << true;
+ QTest::newRow("struct-array-1") << "(as)" << true;
+ QTest::newRow("struct-array-2") << "(yas)" << true;
+ QTest::newRow("struct-array-3") << "(asy)" << true;
+ QTest::newRow("struct-array-4") << "(yasy)" << true;
+
+ QTest::newRow("dict-1") << "a{sy}" << true;
+ QTest::newRow("dict-2") << "a{sv}" << true;
+ QTest::newRow("dict-struct-1") << "a{s(y)}" << true;
+ QTest::newRow("dict-struct-2") << "a{s(yyyy)}" << true;
+ QTest::newRow("dict-struct-array") << "a{s(ay)}" << true;
+ QTest::newRow("dict-array") << "a{sas}" << true;
+ QTest::newRow("dict-array-struct") << "a{sa(y)}" << true;
+
+ addInvalidSingleLetterTypes();
+ QTest::newRow("naked-dict-empty") << "{}" << false;
+ QTest::newRow("naked-dict-missing-value") << "{i}" << false;
+
+ QTest::newRow("dict-empty") << "a{}" << false;
+ QTest::newRow("dict-missing-value") << "a{i}" << false;
+ QTest::newRow("dict-non-basic-key") << "a{vi}" << false;
+ QTest::newRow("dict-struct-key") << "a{(y)y}" << false;
+ QTest::newRow("dict-missing-close") << "a{sv" << false;
+ QTest::newRow("dict-mismatched-close") << "a{sv)" << false;
+ QTest::newRow("dict-missing-value-close") << "a{s" << false;
+
+ QTest::newRow("empty-struct") << "()" << false;
+ QTest::newRow("struct-missing-close") << "(s" << false;
+ QTest::newRow("struct-nested-missing-close-1") << "((s)" << false;
+ QTest::newRow("struct-nested-missing-close-2") << "((s" << false;
+
+ QTest::newRow("struct-ending-array-no-element") << "(a)" << false;
+}
+
+static void addNakedDictEntry()
+{
+ QTest::newRow("naked-dict-entry") << "{sv}" << false;
+}
+
+// ---- tests ----
+
+void tst_QDBusType::isValidFixedType_data()
+{
+ addColumns();
+ addFixedTypes();
+ addBasicTypes(Invalid);
+ addVariant(Invalid);
+ addInvalidSingleLetterTypes();
+}
+
+void tst_QDBusType::isValidFixedType()
+{
+ QFETCH(QString, data);
+ QFETCH(bool, result);
+ QFETCH(bool, isValid);
+ QVERIFY2(data.length() == 1, "Test is malformed, this function must test only one-letter types");
+ QVERIFY(isValid || (!isValid && !result));
+
+ int type = data.at(0).unicode();
+ if (isValid)
+ QCOMPARE(bool(dbus_type_is_fixed(type)), result);
+ QCOMPARE(QDBusUtil::isValidFixedType(type), result);
+}
+
+void tst_QDBusType::isValidBasicType_data()
+{
+ addColumns();
+ addBasicTypes(Valid);
+ addVariant(Invalid);
+ addInvalidSingleLetterTypes();
+}
+
+void tst_QDBusType::isValidBasicType()
+{
+ QFETCH(QString, data);
+ QFETCH(bool, result);
+ QFETCH(bool, isValid);
+ QVERIFY2(data.length() == 1, "Test is malformed, this function must test only one-letter types");
+ QVERIFY(isValid || (!isValid && !result));
+
+ int type = data.at(0).unicode();
+ if (isValid)
+ QCOMPARE(bool(dbus_type_is_basic(type)), result);
+ QCOMPARE(QDBusUtil::isValidBasicType(type), result);
+}
+
+void tst_QDBusType::isValidSingleSignature_data()
+{
+ addColumns();
+ addSingleSignatures();
+ addNakedDictEntry();
+}
+
+void tst_QDBusType::isValidSingleSignature()
+{
+ QFETCH(QString, data);
+ QFETCH(bool, result);
+
+ QCOMPARE(bool(dbus_signature_validate_single(data.toLatin1(), 0)), result);
+ QCOMPARE(QDBusUtil::isValidSingleSignature(data), result);
+}
+
+void tst_QDBusType::isValidArray_data()
+{
+ addColumns();
+ addSingleSignatures();
+}
+
+void tst_QDBusType::isValidArray()
+{
+ QFETCH(QString, data);
+ QFETCH(bool, result);
+
+ data.prepend("a");
+ QCOMPARE(bool(dbus_signature_validate_single(data.toLatin1(), 0)), result);
+ QCOMPARE(QDBusUtil::isValidSingleSignature(data), result);
+
+ data.prepend("a");
+ QCOMPARE(bool(dbus_signature_validate_single(data.toLatin1(), 0)), result);
+ QCOMPARE(QDBusUtil::isValidSingleSignature(data), result);
+}
+
+void tst_QDBusType::isValidSignature_data()
+{
+ isValidSingleSignature_data();
+}
+
+void tst_QDBusType::isValidSignature()
+{
+ QFETCH(QString, data);
+ QFETCH(bool, result);
+
+ data.append(data);
+ if (data.at(0).unicode())
+ QCOMPARE(bool(dbus_signature_validate(data.toLatin1(), 0)), result);
+ QCOMPARE(QDBusUtil::isValidSignature(data), result);
+}
+
+QTEST_MAIN(tst_QDBusType)
+
+#include "tst_qdbustype.moc"
diff --git a/tests/auto/dbus/qdbusxmlparser/.gitignore b/tests/auto/dbus/qdbusxmlparser/.gitignore
new file mode 100644
index 0000000000..e6a1cd4700
--- /dev/null
+++ b/tests/auto/dbus/qdbusxmlparser/.gitignore
@@ -0,0 +1 @@
+tst_qdbusxmlparser
diff --git a/tests/auto/dbus/qdbusxmlparser/qdbusxmlparser.pro b/tests/auto/dbus/qdbusxmlparser/qdbusxmlparser.pro
new file mode 100644
index 0000000000..0ac0d9e198
--- /dev/null
+++ b/tests/auto/dbus/qdbusxmlparser/qdbusxmlparser.pro
@@ -0,0 +1,10 @@
+load(qttest_p4)
+QT = core core-private
+contains(QT_CONFIG,dbus): {
+ SOURCES += tst_qdbusxmlparser.cpp
+ QT += dbus dbus-private
+} else {
+ SOURCES += ../qdbusmarshall/dummy.cpp
+}
+
+
diff --git a/tests/auto/dbus/qdbusxmlparser/tst_qdbusxmlparser.cpp b/tests/auto/dbus/qdbusxmlparser/tst_qdbusxmlparser.cpp
new file mode 100644
index 0000000000..e0f03307f3
--- /dev/null
+++ b/tests/auto/dbus/qdbusxmlparser/tst_qdbusxmlparser.cpp
@@ -0,0 +1,600 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+/* -*- C++ -*-
+ */
+#include <qcoreapplication.h>
+#include <qmetatype.h>
+#include <QtTest/QtTest>
+#include <QtDBus/QtDBus>
+
+#define USE_PRIVATE_CODE
+#include "../qdbusmarshall/common.h"
+
+class tst_QDBusXmlParser: public QObject
+{
+ Q_OBJECT
+
+private:
+ void parsing_common(const QString&);
+
+private slots:
+ void parsing_data();
+ void parsing();
+ void parsingWithDoctype_data();
+ void parsingWithDoctype();
+
+ void objectWithContent_data();
+ void objectWithContent();
+
+ void methods_data();
+ void methods();
+ void signals__data();
+ void signals_();
+ void properties_data();
+ void properties();
+};
+
+void tst_QDBusXmlParser::parsing_data()
+{
+ QTest::addColumn<QString>("xmlData");
+ QTest::addColumn<int>("interfaceCount");
+ QTest::addColumn<int>("objectCount");
+
+ QTest::newRow("null") << QString() << 0 << 0;
+ QTest::newRow("empty") << QString("") << 0 << 0;
+
+ QTest::newRow("junk") << "<junk/>" << 0 << 0;
+ QTest::newRow("interface-inside-junk") << "<junk><interface name=\"iface.iface1\" /></junk>"
+ << 0 << 0;
+ QTest::newRow("object-inside-junk") << "<junk><node name=\"obj1\" /></junk>"
+ << 0 << 0;
+
+ QTest::newRow("zero-interfaces") << "<node/>" << 0 << 0;
+ QTest::newRow("one-interface") << "<node><interface name=\"iface.iface1\" /></node>" << 1 << 0;
+
+
+ QTest::newRow("two-interfaces") << "<node><interface name=\"iface.iface1\" />"
+ "<interface name=\"iface.iface2\"></node>"
+ << 2 << 0;
+
+
+ QTest::newRow("one-object") << "<node><node name=\"obj1\"/></node>" << 0 << 1;
+ QTest::newRow("two-objects") << "<node><node name=\"obj1\"/><node name=\"obj2\"></node>" << 0 << 2;
+
+ QTest::newRow("i1o1") << "<node><interface name=\"iface.iface1\"><node name=\"obj1\"></node>" << 1 << 1;
+
+}
+
+void tst_QDBusXmlParser::parsing_common(const QString &xmlData)
+{
+ QDBusIntrospection::ObjectTree obj =
+ QDBusIntrospection::parseObjectTree(xmlData, "local.testing", "/");
+ QFETCH(int, interfaceCount);
+ QFETCH(int, objectCount);
+ QCOMPARE(obj.interfaces.count(), interfaceCount);
+ QCOMPARE(obj.childObjects.count(), objectCount);
+
+ // also verify the naming
+ int i = 0;
+ foreach (QString name, obj.interfaces)
+ QCOMPARE(name, QString("iface.iface%1").arg(++i));
+
+ i = 0;
+ foreach (QString name, obj.childObjects)
+ QCOMPARE(name, QString("obj%1").arg(++i));
+}
+
+void tst_QDBusXmlParser::parsing()
+{
+ QFETCH(QString, xmlData);
+
+ parsing_common(xmlData);
+}
+
+void tst_QDBusXmlParser::parsingWithDoctype_data()
+{
+ parsing_data();
+}
+
+void tst_QDBusXmlParser::parsingWithDoctype()
+{
+ QString docType = "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
+ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n";
+ QFETCH(QString, xmlData);
+
+ parsing_common(docType + xmlData);
+}
+
+void tst_QDBusXmlParser::objectWithContent_data()
+{
+ QTest::addColumn<QString>("xmlData");
+ QTest::addColumn<QString>("probedObject");
+ QTest::addColumn<int>("interfaceCount");
+ QTest::addColumn<int>("objectCount");
+
+ QTest::newRow("zero") << "<node><node name=\"obj\"/></node>" << "obj" << 0 << 0;
+
+ QString xmlData = "<node><node name=\"obj\">"
+ "<interface name=\"iface.iface1\" />"
+ "</node></node>";
+ QTest::newRow("one-interface") << xmlData << "obj" << 1 << 0;
+ QTest::newRow("one-interface2") << xmlData << "obj2" << 0 << 0;
+
+ xmlData = "<node><node name=\"obj\">"
+ "<interface name=\"iface.iface1\" />"
+ "<interface name=\"iface.iface2\" />"
+ "</node></node>";
+ QTest::newRow("two-interfaces") << xmlData << "obj" << 2 << 0;
+ QTest::newRow("two-interfaces2") << xmlData << "obj2" << 0 << 0;
+
+ xmlData = "<node><node name=\"obj\">"
+ "<interface name=\"iface.iface1\" />"
+ "<interface name=\"iface.iface2\" />"
+ "</node><node name=\"obj2\">"
+ "<interface name=\"iface.iface1\" />"
+ "</node></node>";
+ QTest::newRow("two-nodes-two-interfaces") << xmlData << "obj" << 2 << 0;
+ QTest::newRow("two-nodes-one-interface") << xmlData << "obj2" << 1 << 0;
+
+ xmlData = "<node><node name=\"obj\">"
+ "<node name=\"obj1\" />"
+ "</node></node>";
+ QTest::newRow("one-object") << xmlData << "obj" << 0 << 1;
+ QTest::newRow("one-object2") << xmlData << "obj2" << 0 << 0;
+
+ xmlData = "<node><node name=\"obj\">"
+ "<node name=\"obj1\" />"
+ "<node name=\"obj2\" />"
+ "</node></node>";
+ QTest::newRow("two-objects") << xmlData << "obj" << 0 << 2;
+ QTest::newRow("two-objects2") << xmlData << "obj2" << 0 << 0;
+
+ xmlData = "<node><node name=\"obj\">"
+ "<node name=\"obj1\" />"
+ "<node name=\"obj2\" />"
+ "</node><node name=\"obj2\">"
+ "<node name=\"obj1\" />"
+ "</node></node>";
+ QTest::newRow("two-nodes-two-objects") << xmlData << "obj" << 0 << 2;
+ QTest::newRow("two-nodes-one-object") << xmlData << "obj2" << 0 << 1;
+}
+
+void tst_QDBusXmlParser::objectWithContent()
+{
+ QFETCH(QString, xmlData);
+ QFETCH(QString, probedObject);
+
+ QDBusIntrospection::ObjectTree tree =
+ QDBusIntrospection::parseObjectTree(xmlData, "local.testing", "/");
+
+ const ObjectMap &om = tree.childObjectData;
+
+ if (om.contains(probedObject)) {
+ const QSharedDataPointer<QDBusIntrospection::ObjectTree>& obj = om.value(probedObject);
+ QVERIFY(obj != 0);
+
+ QFETCH(int, interfaceCount);
+ QFETCH(int, objectCount);
+
+ QCOMPARE(obj->interfaces.count(), interfaceCount);
+ QCOMPARE(obj->childObjects.count(), objectCount);
+
+ // verify the object names
+ int i = 0;
+ foreach (QString name, obj->interfaces)
+ QCOMPARE(name, QString("iface.iface%1").arg(++i));
+
+ i = 0;
+ foreach (QString name, obj->childObjects)
+ QCOMPARE(name, QString("obj%1").arg(++i));
+ }
+}
+
+void tst_QDBusXmlParser::methods_data()
+{
+ QTest::addColumn<QString>("xmlDataFragment");
+ QTest::addColumn<MethodMap>("methodMap");
+
+ MethodMap map;
+ QTest::newRow("no-methods") << QString() << map;
+
+ // one method without arguments
+ QDBusIntrospection::Method method;
+ method.name = "Foo";
+ map << method;
+ QTest::newRow("one-method") << "<method name=\"Foo\"/>" << map;
+
+ // add another method without arguments
+ method.name = "Bar";
+ map << method;
+ QTest::newRow("two-methods") << "<method name=\"Foo\"/>"
+ "<method name=\"Bar\"/>"
+ << map;
+
+ // invert the order of the XML declaration
+ QTest::newRow("two-methods-inverse") << "<method name=\"Bar\"/>"
+ "<method name=\"Foo\"/>"
+ << map;
+
+ // add a third, with annotations
+ method.name = "Baz";
+ method.annotations.insert("foo.testing", "nothing to see here");
+ map << method;
+ QTest::newRow("method-with-annotation") <<
+ "<method name=\"Foo\"/>"
+ "<method name=\"Bar\"/>"
+ "<method name=\"Baz\"><annotation name=\"foo.testing\" value=\"nothing to see here\"></method>"
+ << map;
+
+ // arguments
+ map.clear();
+ method.annotations.clear();
+
+ method.name = "Method";
+ method.inputArgs << arg("s");
+ map << method;
+ QTest::newRow("one-in") <<
+ "<method name=\"Method\">"
+ "<arg type=\"s\" direction=\"in\"/>"
+ "</method>" << map;
+
+ // two arguments
+ method.inputArgs << arg("v");
+ map.clear();
+ map << method;
+ QTest::newRow("two-in") <<
+ "<method name=\"Method\">"
+ "<arg type=\"s\" direction=\"in\"/>"
+ "<arg type=\"v\" direction=\"in\"/>"
+ "</method>" << map;
+
+ // one invalid arg
+ method.inputArgs << arg("~", "invalid");
+ map.clear();
+ map << method;
+ QTest::newRow("two-in-one-invalid") <<
+ "<method name=\"Method\">"
+ "<arg type=\"s\" direction=\"in\"/>"
+ "<arg type=\"v\" direction=\"in\"/>"
+ "<arg type=\"~\" name=\"invalid\" direction=\"in\"/>"
+ "</method>" << map;
+
+ // one out argument
+ method.inputArgs.clear();
+ method.outputArgs << arg("s");
+ map.clear();
+ map << method;
+ QTest::newRow("one-out") <<
+ "<method name=\"Method\">"
+ "<arg type=\"s\" direction=\"out\"/>"
+ "</method>" << map;
+
+ // two in and one out
+ method.inputArgs << arg("s") << arg("v");
+ map.clear();
+ map << method;
+ QTest::newRow("two-in-one-out") <<
+ "<method name=\"Method\">"
+ "<arg type=\"s\" direction=\"in\"/>"
+ "<arg type=\"v\" direction=\"in\"/>"
+ "<arg type=\"s\" direction=\"out\"/>"
+ "</method>" << map;
+
+ // let's try an arg with name
+ method.outputArgs.clear();
+ method.inputArgs.clear();
+ method.inputArgs << arg("s", "foo");
+ map.clear();
+ map << method;
+ QTest::newRow("one-in-with-name") <<
+ "<method name=\"Method\">"
+ "<arg type=\"s\" name=\"foo\" direction=\"in\"/>"
+ "</method>" << map;
+
+ // two args with name
+ method.inputArgs << arg("i", "bar");
+ map.clear();
+ map << method;
+ QTest::newRow("two-in-with-name") <<
+ "<method name=\"Method\">"
+ "<arg type=\"s\" name=\"foo\" direction=\"in\"/>"
+ "<arg type=\"i\" name=\"bar\" direction=\"in\"/>"
+ "</method>" << map;
+
+ // one complex
+ map.clear();
+ method = QDBusIntrospection::Method();
+
+ // Method1(in STRING arg1, in BYTE arg2, out ARRAY of STRING)
+ method.inputArgs << arg("s", "arg1") << arg("y", "arg2");
+ method.outputArgs << arg("as");
+ method.name = "Method1";
+ map << method;
+
+ // Method2(in ARRAY of DICT_ENTRY of (STRING,VARIANT) variantMap, in UINT32 index,
+ // out STRING key, out VARIANT value)
+ // with annotation "foo.equivalent":"QVariantMap"
+ method = QDBusIntrospection::Method();
+ method.inputArgs << arg("a{sv}", "variantMap") << arg("u", "index");
+ method.outputArgs << arg("s", "key") << arg("v", "value");
+ method.annotations.insert("foo.equivalent", "QVariantMap");
+ method.name = "Method2";
+ map << method;
+
+ QTest::newRow("complex") <<
+ "<method name=\"Method1\">"
+ "<arg name=\"arg1\" type=\"s\" direction=\"in\"/>"
+ "<arg name=\"arg2\" type=\"y\" direction=\"in\"/>"
+ "<arg type=\"as\" direction=\"out\"/>"
+ "</method>"
+ "<method name=\"Method2\">"
+ "<arg name=\"variantMap\" type=\"a{sv}\" direction=\"in\"/>"
+ "<arg name=\"index\" type=\"u\" direction=\"in\"/>"
+ "<arg name=\"key\" type=\"s\" direction=\"out\"/>"
+ "<arg name=\"value\" type=\"v\" direction=\"out\"/>"
+ "<annotation name=\"foo.equivalent\" value=\"QVariantMap\"/>"
+ "</method>" << map;
+}
+
+void tst_QDBusXmlParser::methods()
+{
+ QString xmlHeader = "<node>"
+ "<interface name=\"iface.iface1\">",
+ xmlFooter = "</interface>"
+ "</node>";
+
+ QFETCH(QString, xmlDataFragment);
+
+ QDBusIntrospection::Interface iface =
+ QDBusIntrospection::parseInterface(xmlHeader + xmlDataFragment + xmlFooter);
+
+ QCOMPARE(iface.name, QString("iface.iface1"));
+
+ QFETCH(MethodMap, methodMap);
+ MethodMap parsedMap = iface.methods;
+
+ QCOMPARE(parsedMap.count(), methodMap.count());
+ QCOMPARE(parsedMap, methodMap);
+}
+
+void tst_QDBusXmlParser::signals__data()
+{
+ QTest::addColumn<QString>("xmlDataFragment");
+ QTest::addColumn<SignalMap>("signalMap");
+
+ SignalMap map;
+ QTest::newRow("no-signals") << QString() << map;
+
+ // one signal without arguments
+ QDBusIntrospection::Signal signal;
+ signal.name = "Foo";
+ map << signal;
+ QTest::newRow("one-signal") << "<signal name=\"Foo\"/>" << map;
+
+ // add another signal without arguments
+ signal.name = "Bar";
+ map << signal;
+ QTest::newRow("two-signals") << "<signal name=\"Foo\"/>"
+ "<signal name=\"Bar\"/>"
+ << map;
+
+ // invert the order of the XML declaration
+ QTest::newRow("two-signals-inverse") << "<signal name=\"Bar\"/>"
+ "<signal name=\"Foo\"/>"
+ << map;
+
+ // add a third, with annotations
+ signal.name = "Baz";
+ signal.annotations.insert("foo.testing", "nothing to see here");
+ map << signal;
+ QTest::newRow("signal-with-annotation") <<
+ "<signal name=\"Foo\"/>"
+ "<signal name=\"Bar\"/>"
+ "<signal name=\"Baz\"><annotation name=\"foo.testing\" value=\"nothing to see here\"></signal>"
+ << map;
+
+ // one out argument
+ map.clear();
+ signal.annotations.clear();
+ signal.outputArgs << arg("s");
+ signal.name = "Signal";
+ map.clear();
+ map << signal;
+ QTest::newRow("one-out") <<
+ "<signal name=\"Signal\">"
+ "<arg type=\"s\" direction=\"out\"/>"
+ "</signal>" << map;
+
+ // without saying which direction it is
+ QTest::newRow("one-out-no-direction") <<
+ "<signal name=\"Signal\">"
+ "<arg type=\"s\"/>"
+ "</signal>" << map;
+
+ // two args with name
+ signal.outputArgs << arg("i", "bar");
+ map.clear();
+ map << signal;
+ QTest::newRow("two-out-with-name") <<
+ "<signal name=\"Signal\">"
+ "<arg type=\"s\" direction=\"out\"/>"
+ "<arg type=\"i\" name=\"bar\"/>"
+ "</signal>" << map;
+
+ // one complex
+ map.clear();
+ signal = QDBusIntrospection::Signal();
+
+ // Signal1(out ARRAY of STRING)
+ signal.outputArgs << arg("as");
+ signal.name = "Signal1";
+ map << signal;
+
+ // Signal2(out STRING key, out VARIANT value)
+ // with annotation "foo.equivalent":"QVariantMap"
+ signal = QDBusIntrospection::Signal();
+ signal.outputArgs << arg("s", "key") << arg("v", "value");
+ signal.annotations.insert("foo.equivalent", "QVariantMap");
+ signal.name = "Signal2";
+ map << signal;
+
+ QTest::newRow("complex") <<
+ "<signal name=\"Signal1\">"
+ "<arg type=\"as\" direction=\"out\"/>"
+ "</signal>"
+ "<signal name=\"Signal2\">"
+ "<arg name=\"key\" type=\"s\" direction=\"out\"/>"
+ "<arg name=\"value\" type=\"v\" direction=\"out\"/>"
+ "<annotation name=\"foo.equivalent\" value=\"QVariantMap\"/>"
+ "</signal>" << map;
+}
+
+void tst_QDBusXmlParser::signals_()
+{
+ QString xmlHeader = "<node>"
+ "<interface name=\"iface.iface1\">",
+ xmlFooter = "</interface>"
+ "</node>";
+
+ QFETCH(QString, xmlDataFragment);
+
+ QDBusIntrospection::Interface iface =
+ QDBusIntrospection::parseInterface(xmlHeader + xmlDataFragment + xmlFooter);
+
+ QCOMPARE(iface.name, QString("iface.iface1"));
+
+ QFETCH(SignalMap, signalMap);
+ SignalMap parsedMap = iface.signals_;
+
+ QCOMPARE(signalMap.count(), parsedMap.count());
+ QCOMPARE(signalMap, parsedMap);
+}
+
+void tst_QDBusXmlParser::properties_data()
+{
+ QTest::addColumn<QString>("xmlDataFragment");
+ QTest::addColumn<PropertyMap>("propertyMap");
+
+ PropertyMap map;
+ QTest::newRow("no-signals") << QString() << map;
+
+ // one readable signal
+ QDBusIntrospection::Property prop;
+ prop.name = "foo";
+ prop.type = "s";
+ prop.access = QDBusIntrospection::Property::Read;
+ map << prop;
+ QTest::newRow("one-readable") << "<property name=\"foo\" type=\"s\" access=\"read\"/>" << map;
+
+ // one writable signal
+ prop.access = QDBusIntrospection::Property::Write;
+ map.clear();
+ map << prop;
+ QTest::newRow("one-writable") << "<property name=\"foo\" type=\"s\" access=\"write\"/>" << map;
+
+ // one read- & writable signal
+ prop.access = QDBusIntrospection::Property::ReadWrite;
+ map.clear();
+ map << prop;
+ QTest::newRow("one-read-writable") << "<property name=\"foo\" type=\"s\" access=\"readwrite\"/>"
+ << map;
+
+ // two, mixed properties
+ prop.name = "bar";
+ prop.type = "i";
+ prop.access = QDBusIntrospection::Property::Read;
+ map << prop;
+ QTest::newRow("two") <<
+ "<property name=\"foo\" type=\"s\" access=\"readwrite\"/>"
+ "<property name=\"bar\" type=\"i\" access=\"read\"/>" << map;
+
+ // invert the order of the declaration
+ QTest::newRow("two") <<
+ "<property name=\"bar\" type=\"i\" access=\"read\"/>"
+ "<property name=\"foo\" type=\"s\" access=\"readwrite\"/>" << map;
+
+ // add a third with annotations
+ prop.name = "baz";
+ prop.type = "as";
+ prop.access = QDBusIntrospection::Property::Write;
+ prop.annotations.insert("foo.annotation", "Hello, World");
+ prop.annotations.insert("foo.annotation2", "Goodbye, World");
+ map << prop;
+ QTest::newRow("complex") <<
+ "<property name=\"bar\" type=\"i\" access=\"read\"/>"
+ "<property name=\"baz\" type=\"as\" access=\"write\">"
+ "<annotation name=\"foo.annotation\" value=\"Hello, World\" />"
+ "<annotation name=\"foo.annotation2\" value=\"Goodbye, World\" />"
+ "<property name=\"foo\" type=\"s\" access=\"readwrite\"/>" << map;
+
+ // and now change the order
+ QTest::newRow("complex2") <<
+ "<property name=\"baz\" type=\"as\" access=\"write\">"
+ "<annotation name=\"foo.annotation2\" value=\"Goodbye, World\" />"
+ "<annotation name=\"foo.annotation\" value=\"Hello, World\" />"
+ "<property name=\"bar\" type=\"i\" access=\"read\"/>"
+ "<property name=\"foo\" type=\"s\" access=\"readwrite\"/>" << map;
+}
+
+void tst_QDBusXmlParser::properties()
+{
+ QString xmlHeader = "<node>"
+ "<interface name=\"iface.iface1\">",
+ xmlFooter = "</interface>"
+ "</node>";
+
+ QFETCH(QString, xmlDataFragment);
+
+ QDBusIntrospection::Interface iface =
+ QDBusIntrospection::parseInterface(xmlHeader + xmlDataFragment + xmlFooter);
+
+ QCOMPARE(iface.name, QString("iface.iface1"));
+
+ QFETCH(PropertyMap, propertyMap);
+ PropertyMap parsedMap = iface.properties;
+
+ QCOMPARE(propertyMap.count(), parsedMap.count());
+ QCOMPARE(propertyMap, parsedMap);
+}
+
+QTEST_MAIN(tst_QDBusXmlParser)
+
+#include "tst_qdbusxmlparser.moc"