tests/auto/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/auto/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,1443 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qcoreapplication.h>
+#include <qdebug.h>
+
+#include <QtTest/QtTest>
+
+#include <QtDBus>
+
+#include "../qdbusmarshall/common.h"
+
+const char *slotSpy;
+QString valueSpy;
+
+QT_BEGIN_NAMESPACE
+namespace QTest {
+    char *toString(QDBusMessage::MessageType t)
+    {
+        switch (t)
+        {
+        case QDBusMessage::InvalidMessage:
+            return qstrdup("InvalidMessage");
+        case QDBusMessage::MethodCallMessage:
+            return qstrdup("MethodCallMessage");
+        case QDBusMessage::ReplyMessage:
+            return qstrdup("ReplyMessage");
+        case QDBusMessage::ErrorMessage:
+            return qstrdup("ErrorMessage");
+        case QDBusMessage::SignalMessage:
+            return qstrdup("SignalMessage");
+        default:
+            return 0;
+        }
+    }
+}
+QT_END_NAMESPACE
+
+class tst_QDBusAbstractAdaptor: public QObject
+{
+    Q_OBJECT
+
+private slots:
+    void initTestCase() { commonInit(); }
+    void methodCalls_data();
+    void methodCalls();
+    void methodCallScriptable();
+    void signalEmissions_data();
+    void signalEmissions();
+    void sameSignalDifferentPaths();
+    void sameObjectDifferentPaths();
+    void scriptableSignalOrNot();
+    void overloadedSignalEmission_data();
+    void overloadedSignalEmission();
+    void readProperties();
+    void readPropertiesInvalidInterface();
+    void readPropertiesEmptyInterface_data();
+    void readPropertiesEmptyInterface();
+    void readAllProperties();
+    void readAllPropertiesInvalidInterface();
+    void readAllPropertiesEmptyInterface_data();
+    void readAllPropertiesEmptyInterface();
+    void writeProperties();
+
+    void typeMatching_data();
+    void typeMatching();
+
+    void methodWithMoreThanOneReturnValue();
+};
+
+class QDBusSignalSpy: public QObject
+{
+    Q_OBJECT
+
+public slots:
+    void slot(const QDBusMessage &msg)
+    {
+        ++count;
+        interface = msg.interface();
+        name = msg.member();
+        signature = msg.signature();
+        path = msg.path();
+        value.clear();
+        if (msg.arguments().count())
+            value = msg.arguments().at(0);
+    }
+
+public:
+    QDBusSignalSpy() : count(0) { }
+
+    int count;
+    QString interface;
+    QString name;
+    QString signature;
+    QString path;
+    QVariant value;
+};
+
+class Interface1: public QDBusAbstractAdaptor
+{
+    Q_OBJECT
+    Q_CLASSINFO("D-Bus Interface", "local.Interface1")
+public:
+    Interface1(QObject *parent) : QDBusAbstractAdaptor(parent)
+    { }
+};
+
+class Interface2: public QDBusAbstractAdaptor
+{
+    Q_OBJECT
+    Q_CLASSINFO("D-Bus Interface", "local.Interface2")
+    Q_PROPERTY(QString prop1 READ prop1)
+    Q_PROPERTY(QString prop2 READ prop2 WRITE setProp2 SCRIPTABLE true)
+    Q_PROPERTY(QUrl nonDBusProperty READ nonDBusProperty)
+public:
+    Interface2(QObject *parent) : QDBusAbstractAdaptor(parent)
+    { setAutoRelaySignals(true); }
+
+    QString prop1() const
+    { return QLatin1String("QString Interface2::prop1() const"); }
+
+    QString prop2() const
+    { return QLatin1String("QString Interface2::prop2() const"); }
+
+    void setProp2(const QString &value)
+    {
+        slotSpy = "void Interface2::setProp2(const QString &)";
+        valueSpy = value;
+    }
+
+    QUrl nonDBusProperty() const
+    { return QUrl(); }
+
+    void emitSignal(const QString &, const QVariant &)
+    { emit signal(); }
+
+public slots:
+    void method()
+    {
+        slotSpy = "void Interface2::method()";
+    }
+
+    Q_SCRIPTABLE void scriptableMethod()
+    {
+        slotSpy = "void Interface2::scriptableMethod()";
+    }
+
+signals:
+    void signal();
+};
+
+class Interface3: public QDBusAbstractAdaptor
+{
+    Q_OBJECT
+    Q_CLASSINFO("D-Bus Interface", "local.Interface3")
+    Q_PROPERTY(QString prop1 READ prop1)
+    Q_PROPERTY(QString prop2 READ prop2 WRITE setProp2)
+    Q_PROPERTY(QString interface3prop READ interface3prop)
+public:
+    Interface3(QObject *parent) : QDBusAbstractAdaptor(parent)
+    { setAutoRelaySignals(true); }
+
+    QString prop1() const
+    { return QLatin1String("QString Interface3::prop1() const"); }
+
+    QString prop2() const
+    { return QLatin1String("QString Interface3::prop2() const"); }
+
+    void setProp2(const QString &value)
+    {
+        slotSpy = "void Interface3::setProp2(const QString &)";
+        valueSpy = value;
+    }
+
+    QString interface3prop() const
+    { return QLatin1String("QString Interface3::interface3prop() const"); }
+
+    void emitSignal(const QString &name, const QVariant &value)
+    {
+        if (name == "signalVoid")
+            emit signalVoid();
+        else if (name == "signalInt")
+            emit signalInt(value.toInt());
+        else if (name == "signalString")
+            emit signalString(value.toString());
+    }
+
+public slots:
+    void methodVoid() { slotSpy = "void Interface3::methodVoid()"; }
+    void methodInt(int) { slotSpy = "void Interface3::methodInt(int)"; }
+    void methodString(QString) { slotSpy = "void Interface3::methodString(QString)"; }
+
+    int methodStringString(const QString &s, QString &out)
+    {
+        slotSpy = "int Interface3::methodStringString(const QString &, QString &)";
+        out = s;
+        return 42;
+    }
+
+signals:
+    void signalVoid();
+    void signalInt(int);
+    void signalString(const QString &);
+};
+
+class Interface4: public QDBusAbstractAdaptor
+{
+    Q_OBJECT
+    Q_CLASSINFO("D-Bus Interface", "local.Interface4")
+    Q_PROPERTY(QString prop1 READ prop1)
+    Q_PROPERTY(QString prop2 READ prop2 WRITE setProp2)
+    Q_PROPERTY(QString interface4prop READ interface4prop)
+public:
+    Interface4(QObject *parent) : QDBusAbstractAdaptor(parent)
+    { setAutoRelaySignals(true); }
+
+    QString prop1() const
+    { return QLatin1String("QString Interface4::prop1() const"); }
+
+    QString prop2() const
+    { return QLatin1String("QString Interface4::prop2() const"); }
+
+    QString interface4prop() const
+    { return QLatin1String("QString Interface4::interface4prop() const"); }
+
+    void setProp2(const QString &value)
+    {
+        slotSpy = "void Interface4::setProp2(const QString &)";
+        valueSpy = value;
+    }
+
+    void emitSignal(const QString &, const QVariant &value)
+    {
+        switch (value.type())
+        {
+        case QVariant::Invalid:
+            emit signal();
+            break;
+        case QVariant::Int:
+            emit signal(value.toInt());
+            break;
+        case QVariant::String:
+            emit signal(value.toString());
+            break;
+        default:
+            break;
+        }
+    }
+
+public slots:
+    void method() { slotSpy = "void Interface4::method()"; }
+    void method(int) { slotSpy = "void Interface4::method(int)"; }
+    void method(QString) { slotSpy = "void Interface4::method(QString)"; }
+
+signals:
+    void signal();
+    void signal(int);
+    void signal(const QString &);
+};
+
+class MyObject: public QObject
+{
+    Q_OBJECT
+    Q_CLASSINFO("D-Bus Interface", "local.MyObject")
+public:
+    Interface1 *if1;
+    Interface2 *if2;
+    Interface3 *if3;
+    Interface4 *if4;
+
+    MyObject(int n = 4)
+        : if1(0), if2(0), if3(0), if4(0)
+    {
+        switch (n)
+        {
+        case 4:
+            if4 = new Interface4(this);
+        case 3:
+            if3 = new Interface3(this);
+        case 2:
+            if2 = new Interface2(this);
+        case 1:
+            if1 = new Interface1(this);
+        }
+    }
+
+    void emitSignal(const QString &name, const QVariant &value)
+    {
+        if (name == "scriptableSignalVoid")
+            emit scriptableSignalVoid();
+        else if (name == "scriptableSignalInt")
+            emit scriptableSignalInt(value.toInt());
+        else if (name == "scriptableSignalString")
+            emit scriptableSignalString(value.toString());
+        else if (name == "nonScriptableSignalVoid")
+            emit nonScriptableSignalVoid();
+    }
+
+signals:
+    Q_SCRIPTABLE void scriptableSignalVoid();
+    Q_SCRIPTABLE void scriptableSignalInt(int);
+    Q_SCRIPTABLE void scriptableSignalString(QString);
+    void nonScriptableSignalVoid();
+};
+
+class TypesInterface: public QDBusAbstractAdaptor
+{
+    Q_OBJECT
+    Q_CLASSINFO("D-Bus Interface", "local.TypesInterface")
+public:
+    TypesInterface(QObject *parent)
+        : QDBusAbstractAdaptor(parent)
+    { }
+
+    union
+    {
+        bool b;
+        uchar uc;
+        short s;
+        ushort us;
+        int i;
+        uint ui;
+        qlonglong ll;
+        qulonglong ull;
+        double d;
+    } dataSpy;
+    QVariant variantSpy;
+    QString stringSpy;
+    QVariantList listSpy;
+    QStringList stringlistSpy;
+    QByteArray bytearraySpy;
+    QVariantMap mapSpy;
+    StringStringMap ssmapSpy;
+    LLDateTimeMap lldtmapSpy;
+    MyStruct structSpy;
+
+public slots:
+    void methodBool(bool b)
+    {
+        slotSpy = "void TypesInterface::methodBool(bool)";
+        dataSpy.b = b;
+    }
+
+    void methodUChar(uchar uc)
+    {
+        slotSpy = "void TypesInterface::methodUChar(uchar)";
+        dataSpy.uc = uc;
+    }
+
+    void methodShort(short s)
+    {
+        slotSpy = "void TypesInterface::methodShort(short)";
+        dataSpy.s = s;
+    }
+
+    void methodUShort(ushort us)
+    {
+        slotSpy = "void TypesInterface::methodUShort(ushort)";
+        dataSpy.us = us;
+    }
+
+    void methodInt(int i)
+    {
+        slotSpy = "void TypesInterface::methodInt(int)";
+        dataSpy.i = i;
+    }
+
+    void methodUInt(uint ui)
+    {
+        slotSpy = "void TypesInterface::methodUInt(uint)";
+        dataSpy.ui = ui;
+    }
+
+    void methodLongLong(qlonglong ll)
+    {
+        slotSpy = "void TypesInterface::methodLongLong(qlonglong)";
+        dataSpy.ll = ll;
+    }
+
+    void methodULongLong(qulonglong ull)
+    {
+        slotSpy = "void TypesInterface::methodULongLong(qulonglong)";
+        dataSpy.ull = ull;
+    }
+
+    void methodDouble(double d)
+    {
+        slotSpy = "void TypesInterface::methodDouble(double)";
+        dataSpy.d = d;
+    }
+
+    void methodString(const QString &s)
+    {
+        slotSpy = "void TypesInterface::methodString(const QString &)";
+        stringSpy = s;
+    }
+
+    void methodObjectPath(const QDBusObjectPath &op)
+    {
+        slotSpy = "void TypesInterface::methodObjectPath(const QDBusObjectPath &)";
+        stringSpy = op.path();
+    }
+
+    void methodSignature(const QDBusSignature &s)
+    {
+        slotSpy = "void TypesInterface::methodSignature(const QDBusSignature &)";
+        stringSpy = s.signature();
+    }
+
+    void methodVariant(const QDBusVariant &v)
+    {
+        slotSpy = "void TypesInterface::methodVariant(const QDBusVariant &)";
+        variantSpy = v.variant();
+    }
+
+    void methodList(const QVariantList &l)
+    {
+        slotSpy = "void TypesInterface::methodList(const QVariantList &)";
+        listSpy = l;
+    }
+
+    void methodStringList(const QStringList &sl)
+    {
+        slotSpy = "void TypesInterface::methodStringList(const QStringList &)";
+        stringlistSpy = sl;
+    }
+
+    void methodByteArray(const QByteArray &ba)
+    {
+        slotSpy = "void TypesInterface::methodByteArray(const QByteArray &)";
+        bytearraySpy = ba;
+    }
+
+    void methodMap(const QVariantMap &m)
+    {
+        slotSpy = "void TypesInterface::methodMap(const QVariantMap &)";
+        mapSpy = m;
+    }
+
+    void methodSSMap(const StringStringMap &ssmap)
+    {
+        slotSpy = "void TypesInterface::methodSSMap(const StringStringMap &)";
+        ssmapSpy = ssmap;
+    }
+
+    void methodLLDateTimeMap(const LLDateTimeMap &lldtmap)
+    {
+        slotSpy = "void TypesInterface::methodLLDateTimeMap(const LLDateTimeMap &)";
+        lldtmapSpy = lldtmap;
+    }
+
+    void methodStruct(const MyStruct &s)
+    {
+        slotSpy = "void TypesInterface::methodStruct(const MyStruct &)";
+        structSpy = s;
+    }
+
+    bool retrieveBool()
+    {
+        return dataSpy.b;
+    }
+
+    uchar retrieveUChar()
+    {
+        return dataSpy.uc;
+    }
+
+    short retrieveShort()
+    {
+        return dataSpy.s;
+    }
+
+    ushort retrieveUShort()
+    {
+        return dataSpy.us;
+    }
+
+    int retrieveInt()
+    {
+        return dataSpy.i;
+    }
+
+    uint retrieveUInt()
+    {
+        return dataSpy.ui;
+    }
+
+    qlonglong retrieveLongLong()
+    {
+        return dataSpy.ll;
+    }
+
+    qulonglong retrieveULongLong()
+    {
+        return dataSpy.ull;
+    }
+
+    double retrieveDouble()
+    {
+        return dataSpy.d;
+    }
+
+    QString retrieveString()
+    {
+        return stringSpy;
+    }
+
+    QDBusObjectPath retrieveObjectPath()
+    {
+        return QDBusObjectPath(stringSpy);
+    }
+
+    QDBusSignature retrieveSignature()
+    {
+        return QDBusSignature(stringSpy);
+    }
+
+    QDBusVariant retrieveVariant()
+    {
+        return QDBusVariant(variantSpy);
+    }
+
+    QVariantList retrieveList()
+    {
+        return listSpy;
+    }
+
+    QStringList retrieveStringList()
+    {
+        return stringlistSpy;
+    }
+
+    QByteArray retrieveByteArray()
+    {
+        return bytearraySpy;
+    }
+
+    QVariantMap retrieveMap()
+    {
+        return mapSpy;
+    }
+
+    StringStringMap retrieveSSMap()
+    {
+        return ssmapSpy;
+    }
+
+    LLDateTimeMap retrieveLLDateTimeMap()
+    {
+        return lldtmapSpy;
+    }
+
+    MyStruct retrieveStruct()
+    {
+        return structSpy;
+    }
+};
+
+void tst_QDBusAbstractAdaptor::methodCalls_data()
+{
+    QTest::addColumn<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));
+    }
+}
+
+#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);
+}
+
+QTEST_MAIN(tst_QDBusAbstractAdaptor)
+
+#include "tst_qdbusabstractadaptor.moc"