2006-03-06 Thiago Macieira <thiago.macieira@trolltech.com>
authorThiago Macieira <thiago@kde.org>
Mon, 6 Mar 2006 14:30:52 +0000 (14:30 +0000)
committerThiago Macieira <thiago@kde.org>
Mon, 6 Mar 2006 14:30:52 +0000 (14:30 +0000)
* test/qt/*: Update the self-tests.

12 files changed:
ChangeLog
test/qt/Makefile.am
test/qt/common.h [new file with mode: 0644]
test/qt/ping.cpp [new file with mode: 0644]
test/qt/qpong.cpp [new file with mode: 0644]
test/qt/tst_hal.cpp
test/qt/tst_qdbusabstractadaptor.cpp [new file with mode: 0644]
test/qt/tst_qdbusconnection.cpp
test/qt/tst_qdbusinterface.cpp
test/qt/tst_qdbusobject.cpp
test/qt/tst_qdbustype.cpp
test/qt/tst_qdbusxmlparser.cpp

index c380e0a..86dea3a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2006-03-06  Thiago Macieira  <thiago.macieira@trolltech.com>
 
+       * test/qt/*: Update the self-tests.
+
+2006-03-06  Thiago Macieira  <thiago.macieira@trolltech.com>
+
        * qt/*: 
        * dbus/qdbus.h: Sync with KDE Subversion revision 516237. This
        represents the first feature-complete version of the Qt4
index 77f86d8..94283eb 100644 (file)
@@ -1,7 +1,7 @@
 INCLUDES=-I$(top_srcdir) -I$(top_srcdir)/qt $(DBUS_CLIENT_CFLAGS) $(DBUS_QT_CFLAGS) $(DBUS_QTESTLIB_CFLAGS) -DDBUS_COMPILATION
 
 if DBUS_BUILD_TESTS
-TEST_BINARIES=qdbusconnection qdbusobject qdbusinterface qdbustype qdbusxmlparser hal
+TEST_BINARIES=qdbustype qdbusxmlparser qdbusconnection qpong ping qdbusobject qdbusinterface qdbusabstractadaptor hal
 TESTS=
 else
 TEST_BINARIES=
@@ -11,18 +11,24 @@ endif
 
 noinst_PROGRAMS= $(TEST_BINARIES)
 
+qpong_SOURCES= qpong.cpp
+ping_SOURCES= ping.cpp
 qdbusconnection_SOURCES= tst_qdbusconnection.cpp
 qdbusobject_SOURCES= tst_qdbusobject.cpp
 qdbusinterface_SOURCES= tst_qdbusinterface.cpp
 qdbustype_SOURCES= tst_qdbustype.cpp
-qdbusxmlparser_SOURCES= tst_qdbusxmlparser.cpp
+qdbusxmlparser_SOURCES= tst_qdbusxmlparser.cpp common.h
+qdbusabstractadaptor_SOURCES= tst_qdbusabstractadaptor.cpp common.h
 hal_SOURCES = tst_hal.cpp
 
+qpong.o: qpong.moc
+ping.o: ping.moc
 tst_qdbusconnection.o: tst_qdbusconnection.moc
 tst_qdbusobject.o: tst_qdbusobject.moc
 tst_qdbusinterface.o: tst_qdbusinterface.moc
 tst_qdbustype.o: tst_qdbustype.moc
 tst_qdbusxmlparser.o: tst_qdbusxmlparser.moc
+tst_qdbusabstractadaptor.o: tst_qdbusabstractadaptor.moc
 tst_hal.o: tst_hal.moc
 
 %.moc: %.cpp
diff --git a/test/qt/common.h b/test/qt/common.h
new file mode 100644 (file)
index 0000000..e3c78bd
--- /dev/null
@@ -0,0 +1,127 @@
+// 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 = QDBusType(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.toString(QDBusType::ConventionalNames))
+        .arg(arg.name);
+    foreach (QDBusIntrospection::Argument arg, m.outputArgs)
+        result += QString("out %1 %2, ")
+        .arg(arg.type.toString(QDBusType::ConventionalNames))
+        .arg(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.toString(QDBusType::ConventionalNames))
+        .arg(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.toString(QDBusType::ConventionalNames)).arg(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)));
+}
+
+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);
+    }
+}
diff --git a/test/qt/ping.cpp b/test/qt/ping.cpp
new file mode 100644 (file)
index 0000000..1777a80
--- /dev/null
@@ -0,0 +1,123 @@
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <QtCore/QtCore>
+#include <QtTest/QtTest>
+#include <dbus/qdbus.h>
+
+class Ping: public QObject
+{
+    Q_OBJECT
+
+public slots:
+    void initTestCase();
+    void cleanupTestCase();
+
+private slots:
+    void sendPing_data();
+    void sendPing();
+
+private:
+    QProcess proc;
+};
+
+void Ping::initTestCase()
+{
+    proc.start("./qpong");
+    QVERIFY(proc.waitForStarted());
+    QTest::qWait(2000);
+}
+
+void Ping::cleanupTestCase()
+{
+    proc.close();
+}
+
+Q_DECLARE_METATYPE(QVariant)
+
+void Ping::sendPing_data()
+{
+    QTest::addColumn<QVariant>("value");
+
+    QTest::newRow("string") << QVariant("ping");
+    QTest::newRow("int") << QVariant(1);
+    QTest::newRow("double") << QVariant(42.5);
+
+    QStringList strings;
+    strings << "hello" << "world";
+    QTest::newRow("stringlist") << QVariant(strings);
+
+    QList<QVariant> ints;
+    ints << 42 << -43 << 44 << 45;
+    QTest::newRow("intlist") << QVariant(ints);
+
+    QList<QVariant> uints;
+    uints << uint(12) << uint(13) << uint(14);
+    QTest::newRow("uintlist") << QVariant(uints);
+
+    QList<QVariant> llints;
+    llints << Q_INT64_C(99) << Q_INT64_C(-100);
+    QTest::newRow("llintlist") << QVariant(llints);
+
+    QList<QVariant> ullints;
+    ullints << Q_UINT64_C(66) << Q_UINT64_C(67);
+    QTest::newRow("ullintlist") << QVariant(ullints);
+
+    QList<QVariant> doubles;
+    doubles << 1.2 << 2.2 << 4.4;
+    QTest::newRow("doublelist") << QVariant(doubles);
+
+    QList<QVariant> stackedInts;
+    stackedInts << 4 << ints << 5;
+    QTest::newRow("stackedInts") << QVariant(stackedInts);
+
+    QList<QVariant> stackedUInts;
+    stackedUInts << uint(3) << uints << uint(4);
+    QTest::newRow("stackedUInts") << QVariant(stackedUInts);
+
+    QList<QVariant> stackedLlints;
+    stackedLlints << Q_INT64_C(49) << llints << Q_INT64_C(-160);
+    QTest::newRow("stackedLlintlist") << QVariant(stackedLlints);
+
+    QList<QVariant> stackedUllints;
+    stackedUllints << Q_UINT64_C(56) << ullints << Q_UINT64_C(57);
+    QTest::newRow("stackedullintlist") << QVariant(stackedUllints);
+
+    QList<QVariant> stackedDoubles;
+    stackedDoubles << 6.2 << doubles << 6.4;
+    QTest::newRow("stackedDoublelist") << QVariant(stackedDoubles);
+
+    QMap<QString, QVariant> map;
+    map["foo"] = "bar";
+    map["kde"] = "great";
+    QTest::newRow("map") << QVariant(map);
+    
+    QList<QVariant> byteArrays;
+    byteArrays << QByteArray("test1") << QByteArray("t2");
+    QTest::newRow("bytearray") << QVariant(byteArrays);
+    
+    QList<QVariant> lists;
+    lists << QVariant(byteArrays) << QVariant(byteArrays);
+    QTest::newRow("listoflists") << QVariant(lists);
+}
+
+void Ping::sendPing()
+{
+    QFETCH(QVariant, value);
+
+    QDBusConnection &con = QDBus::sessionBus();
+
+    QVERIFY(con.isConnected());
+
+    QDBusMessage msg = QDBusMessage::methodCall("org.kde.selftest",
+            "/org/kde/selftest", "org.kde.selftest", "ping");
+    msg << value;
+
+    QDBusMessage reply = con.sendWithReply(msg);
+ //   qDebug() << reply;
+
+    QCOMPARE(reply.count(), msg.count());
+    for (int i = 0; i < reply.count(); ++i)
+        QCOMPARE(reply.at(i), msg.at(i));
+}
+
+QTEST_MAIN(Ping)
+#include "ping.moc"
diff --git a/test/qt/qpong.cpp b/test/qt/qpong.cpp
new file mode 100644 (file)
index 0000000..38e5c78
--- /dev/null
@@ -0,0 +1,35 @@
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <QtCore/QtCore>
+#include <dbus/qdbus.h>
+
+class Pong: public QObject
+{
+    Q_OBJECT
+public slots:
+
+    void ping(const QDBusMessage &msg)
+    {
+        QDBusMessage reply = QDBusMessage::methodReply(msg);
+        reply << static_cast<QList<QVariant> >(msg);
+        if (!msg.connection().send(reply))
+            exit(1);
+    }
+};
+
+int main(int argc, char *argv[])
+{
+    QCoreApplication app(argc, argv);
+
+    QDBusConnection &con = QDBus::sessionBus();
+    if (!con.requestName("org.kde.selftest"))
+        exit(2);
+
+    Pong pong;
+    con.registerObject("/org/kde/selftest", &pong, QDBusConnection::ExportSlots);
+
+    printf("ready.\n");
+
+    return app.exec();
+}
+
+#include "qpong.moc"
index 36389c2..57c9b46 100644 (file)
@@ -2,6 +2,7 @@
 #include <qdebug.h>
 
 #include <QtTest/QtTest>
+#define DBUS_API_SUBJECT_TO_CHANGE
 #include <dbus/qdbus.h>
 
 class tst_Hal: public QObject
@@ -18,9 +19,9 @@ class Spy: public QObject
     Q_OBJECT
 public:
     int count;
-    QDBusConnection conn;
+    QDBusConnection &conn;
 
-    Spy(QDBusConnection c) : count(0), conn(c)
+    Spy(QDBusConnection &c) : count(0), conn(c)
     { }
 
 public slots:
@@ -40,7 +41,7 @@ public slots:
 
 void tst_Hal::getDevices()
 {
-    QDBusConnection con = QDBusConnection::addConnection(QDBusConnection::SystemBus);
+    QDBusConnection &con = QDBus::systemBus();
     QVERIFY(con.isConnected());
 
     QDBusMessage msg = QDBusMessage::methodCall("org.freedesktop.Hal",
@@ -49,12 +50,13 @@ void tst_Hal::getDevices()
 
     QDBusMessage reply = con.sendWithReply(msg);
     QVERIFY(!reply.isEmpty());
+    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);
     qDebug() << reply;
 }
 
 void tst_Hal::lock()
 {
-    QDBusConnection con = QDBusConnection::addConnection(QDBusConnection::SystemBus);
+    QDBusConnection &con = QDBus::systemBus();
     QVERIFY(con.isConnected());
 
     Spy spy( con );
@@ -68,6 +70,7 @@ void tst_Hal::lock()
     msg << "No reason...";
 
     QDBusMessage reply = con.sendWithReply(msg);
+    QTest::qWait(200);
     qDebug() << reply;
     QCOMPARE(spy.count, 3);
     QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
diff --git a/test/qt/tst_qdbusabstractadaptor.cpp b/test/qt/tst_qdbusabstractadaptor.cpp
new file mode 100644 (file)
index 0000000..5c1c609
--- /dev/null
@@ -0,0 +1,792 @@
+#include <qcoreapplication.h>
+#include <qdebug.h>
+
+#include <QtTest/QtTest>
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/qdbus.h>
+
+#include "common.h"
+
+Q_DECLARE_METATYPE(QVariant)
+
+const char *slotSpy;
+QString propSpy;
+
+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;
+        }
+    }
+}
+
+class tst_QDBusAbstractAdaptor: public QObject
+{
+    Q_OBJECT
+
+private slots:
+    void initTestCase();
+
+    void methodCalls_data();
+    void methodCalls();
+    void signalEmissions_data();
+    void signalEmissions();
+    void sameSignalDifferentPaths();
+    void overloadedSignalEmission_data();
+    void overloadedSignalEmission();
+    void readProperties();
+    void writeProperties();
+    void adaptorIntrospection_data();
+    void adaptorIntrospection();
+    void objectTreeIntrospection();
+};
+
+class QDBusSignalSpy: public QObject
+{
+    Q_OBJECT
+
+public slots:
+    void slot(const QDBusMessage &msg)
+    {
+        ++count;
+        interface = msg.interface();
+        name = msg.name();
+        signature = msg.signature();
+        value.clear();
+        if (msg.count())
+            value = msg.at(0);
+    }
+
+public:
+    QDBusSignalSpy() : count(0) { }
+
+    int count;
+    QString interface;
+    QString name;
+    QString signature;
+    QVariant value;
+};
+
+class Interface1: public QDBusAbstractAdaptor
+{
+    Q_OBJECT
+    Q_CLASSINFO("D-Bus Interface", "local.Interface1");
+public:
+    Interface1(QObject *parent) : QDBusAbstractAdaptor(parent)
+    { }
+
+    static QDBusIntrospection::Methods methodData;
+    static QDBusIntrospection::Signals signalData;
+    static QDBusIntrospection::Properties propertyData;
+};
+
+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);
+public:
+    Interface2(QObject *parent) : QDBusAbstractAdaptor(parent)
+    { setAutoRelaySignals(true); }
+
+    QString prop1() const
+    { return __PRETTY_FUNCTION__; }
+
+    QString prop2() const
+    { return __PRETTY_FUNCTION__; }
+
+    void setProp2(const QString &value)
+    { slotSpy = __PRETTY_FUNCTION__; propSpy = value; }
+
+    void emitSignal(const QString &, const QVariant &)
+    { emit signal(); }
+
+public slots:
+    void method() { slotSpy = __PRETTY_FUNCTION__; }
+
+signals:
+    void signal();
+
+public:
+    static QDBusIntrospection::Methods methodData;
+    static QDBusIntrospection::Signals signalData;
+    static QDBusIntrospection::Properties propertyData;    
+};
+
+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);
+public:
+    Interface3(QObject *parent) : QDBusAbstractAdaptor(parent)
+    { setAutoRelaySignals(true); }
+
+    QString prop1() const
+    { return __PRETTY_FUNCTION__; }
+
+    QString prop2() const
+    { return __PRETTY_FUNCTION__; }
+
+    void setProp2(const QString &value)
+    { slotSpy = __PRETTY_FUNCTION__; propSpy = value; }
+
+    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 = __PRETTY_FUNCTION__; }
+    void methodInt(int) { slotSpy = __PRETTY_FUNCTION__; }
+    void methodString(QString) { slotSpy = __PRETTY_FUNCTION__; }
+
+signals:
+    void signalVoid();
+    void signalInt(int);
+    void signalString(const QString &);
+
+public:
+    static QDBusIntrospection::Methods methodData;
+    static QDBusIntrospection::Signals signalData;
+    static QDBusIntrospection::Properties propertyData;    
+};
+
+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);
+public:
+    Interface4(QObject *parent) : QDBusAbstractAdaptor(parent)
+    { setAutoRelaySignals(true); }
+
+    QString prop1() const
+    { return __PRETTY_FUNCTION__; }
+
+    QString prop2() const
+    { return __PRETTY_FUNCTION__; }
+
+    void setProp2(const QString &value)
+    { slotSpy = __PRETTY_FUNCTION__; propSpy = 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 = __PRETTY_FUNCTION__; }
+    void method(int) { slotSpy = __PRETTY_FUNCTION__; }
+    void method(QString) { slotSpy = __PRETTY_FUNCTION__; }
+
+signals:
+    void signal();
+    void signal(int);
+    void signal(const QString &);
+
+public:
+    static QDBusIntrospection::Methods methodData;
+    static QDBusIntrospection::Signals signalData;
+    static QDBusIntrospection::Properties propertyData;    
+};
+
+
+QDBusIntrospection::Methods Interface1::methodData;
+QDBusIntrospection::Signals Interface1::signalData;
+QDBusIntrospection::Properties Interface1::propertyData;    
+QDBusIntrospection::Methods Interface2::methodData;
+QDBusIntrospection::Signals Interface2::signalData;
+QDBusIntrospection::Properties Interface2::propertyData;    
+QDBusIntrospection::Methods Interface3::methodData;
+QDBusIntrospection::Signals Interface3::signalData;
+QDBusIntrospection::Properties Interface3::propertyData;    
+QDBusIntrospection::Methods Interface4::methodData;
+QDBusIntrospection::Signals Interface4::signalData;
+QDBusIntrospection::Properties Interface4::propertyData;
+
+void tst_QDBusAbstractAdaptor::initTestCase()
+{
+    QDBusIntrospection::Method method;
+    method.name = "Method";
+    Interface2::methodData << method;
+    Interface4::methodData << method;
+    method.inputArgs << arg("i");
+    Interface4::methodData << method;
+    method.inputArgs.clear();
+    method.inputArgs << arg("s");
+    Interface4::methodData << method;
+
+    method.name = "MethodVoid";
+    method.inputArgs.clear();
+    Interface3::methodData << method;
+    method.name = "MethodInt";
+    method.inputArgs << arg("i");
+    Interface3::methodData << method;
+    method.name = "MethodString";
+    method.inputArgs.clear();
+    method.inputArgs << arg("s");
+    Interface3::methodData << method;
+
+    QDBusIntrospection::Signal signal;
+    signal.name = "Signal";
+    Interface2::signalData << signal;
+    Interface4::signalData << signal;
+    signal.outputArgs << arg("i");
+    Interface4::signalData << signal;
+    signal.outputArgs.clear();
+    signal.outputArgs << arg("s");
+    Interface4::signalData << signal;
+
+    signal.name = "SignalVoid";
+    signal.outputArgs.clear();
+    Interface3::signalData << signal;
+    signal.name = "SignalInt";
+    signal.outputArgs << arg("i");
+    Interface3::signalData << signal;
+    signal.name = "SignalString";
+    signal.outputArgs.clear();
+    signal.outputArgs << arg("s");
+    Interface3::signalData << signal;
+
+    QDBusIntrospection::Property prop;
+    prop.name = "Prop1";
+    prop.type = QDBusType('s');
+    prop.access = QDBusIntrospection::Property::Read;
+    Interface2::propertyData << prop;
+    Interface3::propertyData << prop;
+    Interface4::propertyData << prop;
+    prop.name = "Prop2";
+    prop.access = QDBusIntrospection::Property::ReadWrite;
+    Interface2::propertyData << prop;
+    Interface3::propertyData << prop;
+    Interface4::propertyData << prop;
+}
+
+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 = QDBus::sessionBus();
+    QVERIFY(con.isConnected());
+
+    QDBusObject dobj = con.findObject(con.baseService(), "/");
+    QVERIFY(dobj.isValid());
+
+    //QDBusInterface empty(dobj, QString());
+    QDBusInterface if1(dobj, "local.Interface1");
+    QDBusInterface if2(dobj, "local.Interface2");
+    QDBusInterface if3(dobj, "local.Interface3");
+    QDBusInterface if4(dobj, "local.Interface4");
+
+    // must fail: no object
+    //QCOMPARE(empty.call("method").type(), QDBusMessage::ErrorMessage);
+    QCOMPARE(if1.call("method").type(), QDBusMessage::ErrorMessage);
+
+    QObject obj;
+    con.registerObject("/", &obj);
+
+    QFETCH(int, nInterfaces);
+    switch (nInterfaces)
+    {
+    case 4:
+        new Interface4(&obj);
+    case 3:
+        new Interface3(&obj);
+    case 2:
+        new Interface2(&obj);
+    case 1:
+        new Interface1(&obj);
+    }
+
+    // must fail: no such method
+    QCOMPARE(if1.call("method").type(), QDBusMessage::ErrorMessage);
+    if (!nInterfaces--)
+        return;
+    if (!nInterfaces--)
+        return;
+
+    // simple call: one such method exists
+    QCOMPARE(if2.call("method").type(), QDBusMessage::ReplyMessage);
+    QCOMPARE(slotSpy, "void Interface2::method()");
+    if (!nInterfaces--)
+        return;
+
+    // multiple methods in multiple interfaces, no name overlap
+    QCOMPARE(if1.call("methodVoid").type(), QDBusMessage::ErrorMessage);
+    QCOMPARE(if1.call("methodInt").type(), QDBusMessage::ErrorMessage);
+    QCOMPARE(if1.call("methodString").type(), QDBusMessage::ErrorMessage);
+    QCOMPARE(if2.call("methodVoid").type(), QDBusMessage::ErrorMessage);
+    QCOMPARE(if2.call("methodInt").type(), QDBusMessage::ErrorMessage);
+    QCOMPARE(if2.call("methodString").type(), QDBusMessage::ErrorMessage);
+
+    QCOMPARE(if3.call("methodVoid").type(), QDBusMessage::ReplyMessage);
+    QCOMPARE(slotSpy, "void Interface3::methodVoid()");
+    QCOMPARE(if3.call("methodInt", 42).type(), QDBusMessage::ReplyMessage);
+    QCOMPARE(slotSpy, "void Interface3::methodInt(int)");
+    QCOMPARE(if3.call("methodString", QString("")).type(), QDBusMessage::ReplyMessage);
+    QCOMPARE(slotSpy, "void Interface3::methodString(QString)");
+
+    if (!nInterfaces--)
+        return;
+
+    // method overloading: different interfaces
+    QCOMPARE(if4.call("method").type(), QDBusMessage::ReplyMessage);
+    QCOMPARE(slotSpy, "void Interface4::method()");
+
+    // method overloading: different parameters
+    QCOMPARE(if4.call("method.i", 42).type(), QDBusMessage::ReplyMessage);
+    QCOMPARE(slotSpy, "void Interface4::method(int)");
+    QCOMPARE(if4.call("method.s", QString()).type(), QDBusMessage::ReplyMessage);
+    QCOMPARE(slotSpy, "void Interface4::method(QString)");
+    
+}
+
+static void emitSignal(QDBusConnection &con, const QString &iface, const QString &name,
+                       const QVariant &parameter)
+{
+    QObject obj;
+    Interface2 *if2 = new Interface2(&obj);
+    Interface3 *if3 = new Interface3(&obj);
+    Interface4 *if4 = new Interface4(&obj);
+    con.registerObject("/",&obj);
+
+    if (iface.endsWith('2'))
+        if2->emitSignal(name, parameter);
+    else if (iface.endsWith('3'))
+        if3->emitSignal(name, parameter);
+    else if (iface.endsWith('4'))
+        if4->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");
+}
+
+void tst_QDBusAbstractAdaptor::signalEmissions()
+{
+    QFETCH(QString, interface);
+    QFETCH(QString, name);
+    QFETCH(QVariant, parameter);
+
+    QDBusConnection &con = QDBus::sessionBus();
+    QVERIFY(con.isConnected());
+
+    QDBusObject dobj = con.findObject(con.baseService(), "/");
+    QVERIFY(dobj.isValid());
+
+    //QDBusInterface empty(dobj, QString());
+    QDBusInterface if2(dobj, "local.Interface2");
+    QDBusInterface if3(dobj, "local.Interface3");
+
+    // connect all signals and emit only one
+    {
+        QDBusSignalSpy spy;
+        if2.connect("signal", &spy, SLOT(slot(QDBusMessage)));
+        if3.connect("signalVoid", &spy, SLOT(slot(QDBusMessage)));
+        if3.connect("signalInt", &spy, SLOT(slot(QDBusMessage)));
+        if3.connect("signalString", &spy, SLOT(slot(QDBusMessage)));
+        
+        emitSignal(con, 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(con, "local.Interface2", "signal", QVariant());
+        emitSignal(con, "local.Interface3", "signalVoid", QVariant());
+        emitSignal(con, "local.Interface3", "signalInt", QVariant(1));
+        emitSignal(con, "local.Interface3", "signalString", 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 = QDBus::sessionBus();
+    QVERIFY(con.isConnected());
+
+    QObject obj;
+    Interface2 *if2 = new Interface2(&obj);
+
+    con.registerObject("/p1",&obj);
+    con.registerObject("/p2",&obj);
+
+    QDBusSignalSpy spy;
+    con.connect(con.baseService(), "/p1", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage)));
+    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)));
+    if2->emitSignal(QString(), QVariant());
+    QTest::qWait(200);
+    
+    QCOMPARE(spy.count, 2);
+}
+
+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 = QDBus::sessionBus();
+    QVERIFY(con.isConnected());
+
+    QString interface = "local.Interface4";
+    QString name = "signal";
+    QFETCH(QVariant, parameter);
+    QDBusInterface if4 = con.findInterface(con.baseService(), "/", interface);
+    
+    // connect all signals and emit only one
+    {
+        QDBusSignalSpy spy;
+        if4.connect("signal.", &spy, SLOT(slot(QDBusMessage)));
+        if4.connect("signal.i", &spy, SLOT(slot(QDBusMessage)));
+        if4.connect("signal.s", &spy, SLOT(slot(QDBusMessage)));
+        
+        emitSignal(con, 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(con, "local.Interface4", "signal", QVariant());
+        emitSignal(con, "local.Interface4", "signal", QVariant(1));
+        emitSignal(con, "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 = QDBus::sessionBus();
+    QVERIFY(con.isConnected());
+
+    QObject obj;
+    new Interface2(&obj);
+    new Interface3(&obj);
+    new Interface4(&obj);
+    con.registerObject("/", &obj);
+
+    for (int i = 2; i <= 4; ++i) {
+        QString name = QString("Interface%1").arg(i);
+        QDBusInterface iface = con.findInterface(con.baseService(), "/", "local." + name);
+
+        for (int j = 1; j <= 2; ++j) {
+            QString propname = QString("prop%1").arg(j);
+            QDBusVariant value = iface.property(propname);
+
+            QVERIFY(value.type == QDBusType('s'));
+            QVERIFY(value.value.type() == QVariant::String);
+            QCOMPARE(value.value.toString(), QString("QString %1::%2() const").arg(name, propname));
+        }
+    }
+}
+
+void tst_QDBusAbstractAdaptor::writeProperties()
+{
+    QDBusConnection &con = QDBus::sessionBus();
+    QVERIFY(con.isConnected());
+
+    QObject obj;
+    new Interface2(&obj);
+    new Interface3(&obj);
+    new Interface4(&obj);
+    con.registerObject("/", &obj);
+
+    for (int i = 2; i <= 4; ++i) {
+        QString name = QString("Interface%1").arg(i);
+        QDBusInterface iface = con.findInterface(con.baseService(), "/", "local." + name);
+
+        QDBusVariant value(name);
+
+        propSpy.clear();
+        iface.setProperty("prop1", value);
+        QVERIFY(propSpy.isEmpty()); // call mustn't have succeeded
+
+        iface.setProperty("prop2", value);
+        QCOMPARE(propSpy, name);
+        QCOMPARE(QString(slotSpy), QString("void %1::setProp2(const QString&)").arg(name));
+    }
+}
+
+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"));
+    }
+}    
+
+QTEST_MAIN(tst_QDBusAbstractAdaptor)
+
+#include "tst_qdbusabstractadaptor.moc"
index c3b15a2..52fb9ff 100644 (file)
@@ -3,15 +3,26 @@
 
 #include <QtTest/QtTest>
 
+#define DBUS_API_SUBJECT_TO_CHANGE
 #include <dbus/qdbus.h>
 
+class MyObject: public QObject
+{
+    Q_OBJECT
+public slots:
+    void method(const QDBusMessage &msg) { serial = msg.serialNumber(); path = msg.path(); }
+
+public:
+    int serial;
+    QString path;
+    MyObject() : serial(0) { }
+};
+
 class tst_QDBusConnection: public QObject
 {
     Q_OBJECT
 
 private slots:
-    void init();
-    void cleanupTestCase();
     void addConnection();
     void connect();
     void send();
@@ -23,6 +34,11 @@ private slots:
     void getNameOwner();
     void releaseName_data();
     void releaseName();
+
+    void registerObject();
+
+public:
+    bool callMethod(const QDBusConnection &conn, const QString &path);
 };
 
 class QDBusSpy: public QObject
@@ -37,25 +53,9 @@ public:
     int serial;
 };
 
-void tst_QDBusConnection::init()
-{
-    if (qstrcmp(QTest::currentTestFunction(), "addConnection") == 0)
-        return;
-
-    QDBusConnection::addConnection(QDBusConnection::SessionBus);
-    QVERIFY(QDBusConnection().isConnected());
-}
-
-void tst_QDBusConnection::cleanupTestCase()
-{
-    QDBusConnection::closeConnection();
-
-    QVERIFY(!QDBusConnection().isConnected());
-}
-
 void tst_QDBusConnection::sendSignal()
 {
-    QDBusConnection con;
+    QDBusConnection &con = QDBus::sessionBus();
 
     QVERIFY(con.isConnected());
 
@@ -70,7 +70,7 @@ void tst_QDBusConnection::sendSignal()
 
 void tst_QDBusConnection::send()
 {
-    QDBusConnection con;
+    QDBusConnection &con = QDBus::sessionBus();
 
     QVERIFY(con.isConnected());
 
@@ -86,7 +86,7 @@ void tst_QDBusConnection::send()
 
 void tst_QDBusConnection::sendAsync()
 {
-    QDBusConnection con;
+    QDBusConnection &con = QDBus::sessionBus();
     QVERIFY(con.isConnected());
 
     QDBusSpy spy;
@@ -107,7 +107,7 @@ void tst_QDBusConnection::connect()
 {
     QDBusSpy spy;
 
-    QDBusConnection con;
+    QDBusConnection &con = QDBus::sessionBus();
 
     con.connect(con.baseService(), "/org/kde/selftest", "org.kde.selftest", "ping", &spy,
                  SLOT(handlePing(QString)));
@@ -133,7 +133,7 @@ void tst_QDBusConnection::addConnection()
         QVERIFY(con.isConnected());
         QVERIFY(!con.lastError().isValid());
 
-        QDBusConnection con2;
+        QDBusConnection con2("foo");
         QVERIFY(!con2.isConnected());
         QVERIFY(!con2.lastError().isValid());
 
@@ -157,26 +157,6 @@ void tst_QDBusConnection::addConnection()
         QVERIFY(!con.isConnected());
         QVERIFY(!con.lastError().isValid());
     }
-
-    {
-        {
-            QDBusConnection con = QDBusConnection::addConnection(
-                    QDBusConnection::SessionBus);
-            QVERIFY(con.isConnected());
-        }
-
-        {
-            QDBusConnection con;
-            QVERIFY(con.isConnected());
-            QDBusConnection::closeConnection();
-            QVERIFY(con.isConnected());
-        }
-
-        {
-            QDBusConnection con;
-            QVERIFY(!con.isConnected());
-        }
-    }
 }
 
 void tst_QDBusConnection::requestName_data()
@@ -197,7 +177,7 @@ void tst_QDBusConnection::requestName_data()
 
 void tst_QDBusConnection::requestName()
 {
-    QDBusConnection con;
+    QDBusConnection &con = QDBus::sessionBus();
 
     QVERIFY(con.isConnected());
     
@@ -224,7 +204,7 @@ void tst_QDBusConnection::getNameOwner_data()
 
     QTest::newRow("bus") << "org.freedesktop.DBus" << "org.freedesktop.DBus";
 
-    QString base = QDBusConnection().baseService();
+    QString base = QDBus::sessionBus().baseService();
     QTest::newRow("address") << base << base;
     QTest::newRow("self") << "com.trolltech.QtDBUS.tst_qdbusconnection" << base;
 }
@@ -234,7 +214,7 @@ void tst_QDBusConnection::getNameOwner()
     QFETCH(QString, name);
     QFETCH(QString, expectedResult);
 
-    QDBusConnection con;
+    QDBusConnection &con = QDBus::sessionBus();
     QVERIFY(con.isConnected());
 
     QString result = con.getNameOwner(name);
@@ -249,7 +229,7 @@ void tst_QDBusConnection::releaseName_data()
 
 void tst_QDBusConnection::releaseName()
 {
-    QDBusConnection con;
+    QDBusConnection &con = QDBus::sessionBus();
 
     QVERIFY(con.isConnected());
     
@@ -260,6 +240,105 @@ void tst_QDBusConnection::releaseName()
     bool result = con.releaseName(requestedName);
 
     QCOMPARE(result, expectedResult);
+}
+
+void tst_QDBusConnection::registerObject()
+{
+    QDBusConnection &con = QDBus::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::ExportSlots));
+        QVERIFY(callMethod(con, "/"));
+        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::ExportSlots));
+        QVERIFY(!callMethod(con, "/"));
+        QVERIFY(callMethod(con, "/p1"));
+        QCOMPARE(obj.path, QString("/p1"));
+
+        // re-register it somewhere else
+        QVERIFY(con.registerObject("/p2", &obj, QDBusConnection::ExportSlots));
+        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::ExportSlots));
+        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::ExportSlots));
+        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::ExportSlots));
+        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
+    }
+}
+
+bool tst_QDBusConnection::callMethod(const QDBusConnection &conn, const QString &path)
+{
+    QDBusMessage msg = QDBusMessage::methodCall(conn.baseService(), path, "local.any", "method");
+    QDBusMessage reply = conn.sendWithReply(msg);
+
+    return reply.type() == QDBusMessage::ReplyMessage;
 }    
 
 QTEST_MAIN(tst_QDBusConnection)
index 599b6c0..a7f8c70 100644 (file)
@@ -20,6 +20,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  */
+#define DBUS_API_SUBJECT_TO_CHANGE 1
 #include <qcoreapplication.h>
 #include <qmetatype.h>
 #include <QtTest/QtTest>
@@ -63,26 +64,42 @@ const char introspectionData[] =
     "<node name=\"subObject\"/>"
     "</node>";
 
-class MyObject: public QObject
+class IntrospectionAdaptor: public QDBusAbstractAdaptor
 {
     Q_OBJECT
+    Q_CLASSINFO("D-Bus Interface", "org.freedesktop.DBus.Introspectable")
+public:
+    IntrospectionAdaptor(QObject *parent)
+        : QDBusAbstractAdaptor(parent)
+    { }
+        
 public slots:
 
-    void ping(const QDBusMessage &msg)
+    void Introspect(const QDBusMessage &msg)
     {
-        QDBusConnection con = QDBusConnection::addConnection(QDBusConnection::SessionBus);
         QDBusMessage reply = QDBusMessage::methodReply(msg);
-        reply << static_cast<QList<QVariant> >(msg);
-        if (!con.send(reply))
+        reply << ::introspectionData;
+        if (!msg.connection().send(reply))
             exit(1);
     }
+};    
 
-    void Introspect(const QDBusMessage &msg)
+class MyObject: public QObject
+{
+    Q_OBJECT
+public:
+    MyObject()
+    {
+        new IntrospectionAdaptor(this);
+    }
+
+public slots:
+
+    void ping(const QDBusMessage &msg)
     {
-        QDBusConnection con = QDBusConnection::addConnection(QDBusConnection::SessionBus);
         QDBusMessage reply = QDBusMessage::methodReply(msg);
-        reply << ::introspectionData;
-        if (!con.send(reply))
+        reply << static_cast<QList<QVariant> >(msg);
+        if (!msg.connection().send(reply))
             exit(1);
     }
 };
@@ -110,7 +127,7 @@ void emitSignal(const QString &interface, const QString &name, const QString &ar
 {
     QDBusMessage msg = QDBusMessage::signal("/", interface, name);
     msg << arg;
-    QDBusConnection().send(msg);
+    QDBus::sessionBus().send(msg);
 
     QTest::qWait(200);
 }
@@ -121,7 +138,6 @@ class tst_QDBusInterface: public QObject
     MyObject obj;
 private slots:
     void initTestCase();
-    void cleanupTestCase();
 
     void call_data();
     void call();
@@ -134,18 +150,11 @@ private slots:
 
 void tst_QDBusInterface::initTestCase()
 {
-    QDBusConnection con = QDBusConnection::addConnection(QDBusConnection::SessionBus);
+    QDBusConnection &con = QDBus::sessionBus();
     QVERIFY(con.isConnected());
     QVERIFY(con.requestName( TEST_SERVICE_NAME ));
 
-    con.registerObject("/", "org.freedesktop.DBus.Introspectable", &obj);
-    con.registerObject("/", TEST_INTERFACE_NAME, &obj);
-}
-
-void tst_QDBusInterface::cleanupTestCase()
-{
-    QDBusConnection::closeConnection();
-    QVERIFY(!QDBusConnection().isConnected());
+    con.registerObject("/", &obj, QDBusConnection::ExportAdaptors | QDBusConnection::ExportSlots);
 }
 
 void tst_QDBusInterface::call_data()
@@ -209,9 +218,9 @@ void tst_QDBusInterface::call_data()
 
 void tst_QDBusInterface::call()
 {
-    QDBusConnection con;
-    QDBusInterface iface(con, con.baseService(), QLatin1String("/"),
-                         TEST_INTERFACE_NAME);
+    QDBusConnection &con = QDBus::sessionBus();
+    QDBusInterface iface = con.findInterface(con.baseService(), QLatin1String("/"),
+                                             TEST_INTERFACE_NAME);
 
     QFETCH(QString, method);
     QFETCH(QVariantList, input);
@@ -262,16 +271,16 @@ void tst_QDBusInterface::call()
 void tst_QDBusInterface::introspect_data()
 {
     QTest::addColumn<QString>("service");
-    QTest::newRow("base") << QDBusConnection().baseService();
+    QTest::newRow("base") << QDBus::sessionBus().baseService();
     QTest::newRow("name") << TEST_SERVICE_NAME;
 }
 
 void tst_QDBusInterface::introspect()
 {
     QFETCH(QString, service);
-    QDBusConnection con;
-    QDBusInterface iface(con, service, QLatin1String("/"),
-                         TEST_INTERFACE_NAME);
+    QDBusConnection &con = QDBus::sessionBus();
+    QDBusInterface iface = con.findInterface(service, QLatin1String("/"),
+                                             TEST_INTERFACE_NAME);
 
     QDBusIntrospection::Methods mm = iface.methodData();
     QVERIFY(mm.count() == 2);
@@ -287,9 +296,9 @@ void tst_QDBusInterface::introspect()
 
 void tst_QDBusInterface::signal()
 {
-    QDBusConnection con;
-    QDBusInterface iface(con, con.baseService(), QLatin1String("/"),
-                         TEST_INTERFACE_NAME);
+    QDBusConnection &con = QDBus::sessionBus();
+    QDBusInterface iface = con.findInterface(con.baseService(), QLatin1String("/"),
+                                             TEST_INTERFACE_NAME);
 
     QString signalName = TEST_SIGNAL_NAME;
 
index 24d5077..904e98b 100644 (file)
@@ -20,6 +20,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  */
+#define DBUS_API_SUBJECT_TO_CHANGE 1
 #include <qcoreapplication.h>
 #include <qmetatype.h>
 #include <QtTest/QtTest>
@@ -46,26 +47,42 @@ const char introspectionData[] =
     "<node name=\"subObject\"/>"
     "</node>";
 
-class MyObject: public QObject
+class IntrospectionAdaptor: public QDBusAbstractAdaptor
 {
     Q_OBJECT
+    Q_CLASSINFO("D-Bus Interface", "org.freedesktop.DBus.Introspectable")
+public:
+    IntrospectionAdaptor(QObject *parent)
+        : QDBusAbstractAdaptor(parent)
+    { }
+        
 public slots:
 
-    void ping(const QDBusMessage &msg)
+    void Introspect(const QDBusMessage &msg)
     {
-        QDBusConnection con = QDBusConnection::addConnection(QDBusConnection::SessionBus);
         QDBusMessage reply = QDBusMessage::methodReply(msg);
-        reply << static_cast<QList<QVariant> >(msg);
-        if (!con.send(reply))
+        reply << ::introspectionData;
+        if (!msg.connection().send(reply))
             exit(1);
     }
+};    
 
-    void Introspect(const QDBusMessage &msg)
+class MyObject: public QObject
+{
+    Q_OBJECT
+public:
+    MyObject()
+    {
+        new IntrospectionAdaptor(this);
+    }
+
+public slots:
+
+    void ping(const QDBusMessage &msg)
     {
-        QDBusConnection con = QDBusConnection::addConnection(QDBusConnection::SessionBus);
         QDBusMessage reply = QDBusMessage::methodReply(msg);
-        reply << ::introspectionData;
-        if (!con.send(reply))
+        reply << static_cast<QList<QVariant> >(msg);
+        if (!msg.connection().send(reply))
             exit(1);
     }
 };
@@ -77,7 +94,6 @@ class tst_QDBusObject: public QObject
 
 private slots:
     void initTestCase();        // connect to D-Bus
-    void cleanupTestCase();     // disconnect from D-Bus
 
     void construction_data();
     void construction();
@@ -88,18 +104,11 @@ private slots:
 
 void tst_QDBusObject::initTestCase()
 {
-    QDBusConnection con = QDBusConnection::addConnection(QDBusConnection::SessionBus);
+    QDBusConnection &con = QDBus::sessionBus();
     QVERIFY(con.isConnected());
     QVERIFY(con.requestName("com.trolltech.tst_qdbusobject"));
 
-    con.registerObject("/", "org.freedesktop.DBus.Introspectable", &obj);
-    con.registerObject("/", "com.trolltech.tst_qdbusobject.MyObject", &obj);
-}
-
-void tst_QDBusObject::cleanupTestCase()
-{
-    QDBusConnection::closeConnection();
-    QVERIFY(!QDBusConnection().isConnected());
+    con.registerObject("/", &obj, QDBusConnection::ExportAdaptors | QDBusConnection::ExportSlots);
 }
 
 void tst_QDBusObject::construction_data()
@@ -128,14 +137,14 @@ void tst_QDBusObject::construction_data()
 
 void tst_QDBusObject::construction()
 {
-    QDBusConnection con;        // default
+    QDBusConnection &con = QDBus::sessionBus();
 
     QFETCH(QString, service);
     QFETCH(QString, path);
     QFETCH(bool, isValid);
     //QFETCH(bool, exists);
 
-    QDBusObject o(con, service, path);
+    QDBusObject o = con.findObject(service, path);
     QCOMPARE(o.isValid(), isValid);
 
     if (isValid) {
@@ -164,7 +173,7 @@ void tst_QDBusObject::introspection_data()
     interfaces << "org.freedesktop.DBus" << DBUS_INTERFACE_INTROSPECTABLE;
     QTest::newRow("server") << "org.freedesktop.DBus" << "/" << interfaces;
 
-    QDBusConnection con;
+    QDBusConnection &con = QDBus::sessionBus();
     interfaces.clear();
     interfaces << "com.trolltech.tst_qdbusobject.MyObject" << DBUS_INTERFACE_INTROSPECTABLE;    
 
@@ -174,12 +183,12 @@ void tst_QDBusObject::introspection_data()
 
 void tst_QDBusObject::introspection()
 {
-    QDBusConnection con;
+    QDBusConnection &con = QDBus::sessionBus();
 
     QFETCH(QString, service);
     QFETCH(QString, path);
 
-    QDBusObject o(con, service, path);
+    QDBusObject o = con.findObject(service, path);
 
     if (!o.isValid())
         QVERIFY(o.introspect().isEmpty());
index 124e60c..9520ae6 100644 (file)
@@ -20,6 +20,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  */
+#define DBUS_API_SUBJECT_TO_CHANGE 1
 #include <qcoreapplication.h>
 #include <QtTest/QtTest>
 
index c7337c3..d908570 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  */
+#define DBUS_API_SUBJECT_TO_CHANGE 1
 #include <qcoreapplication.h>
 #include <qmetatype.h>
 #include <QtTest/QtTest>
 
 #include <dbus/qdbus.h>
 
+#include "common.h"
+
 class tst_QDBusXmlParser: public QObject
 {
     Q_OBJECT
@@ -50,140 +53,6 @@ private slots:
     void properties();
 };
 
-// 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 = QDBusType(type);
-    retval.name = QLatin1String(name);
-    return retval;
-}
-
-template<typename T>
-inline QMap<QString, T>& operator<<(QMap<QString, T>& map, const T& m)
-{ map.insert(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 = m.name + "(";
-    foreach (QDBusIntrospection::Argument arg, m.inputArgs)
-        result += QString("in %1 %2, ")
-        .arg(arg.type.toString(QDBusType::ConventionalNames))
-        .arg(arg.name);
-    foreach (QDBusIntrospection::Argument arg, m.outputArgs)
-        result += QString("out %1 %2, ")
-        .arg(arg.type.toString(QDBusType::ConventionalNames))
-        .arg(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());
-
-    if (result.length() > 1)
-        result.truncate(result.length() - 2);
-    result += ")";
-    return result;
-}    
-
-QString printable(const QDBusIntrospection::Signal& s)
-{
-    QString result = s.name + "(";
-    foreach (QDBusIntrospection::Argument arg, s.outputArgs)
-        result += QString("out %1 %2, ")
-        .arg(arg.type.toString(QDBusType::ConventionalNames))
-        .arg(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());
-
-    if (result.length() > 1)
-        result.truncate(result.length() - 2);
-    result += ")";
-    return result;
-}    
-
-QString printable(const QDBusIntrospection::Property& p)
-{
-    QString result;
-    if (p.access == QDBusIntrospection::Property::Read)
-        result = "read %1 %2, ";
-    else if (p.access == QDBusIntrospection::Property::Write)
-        result = "write %1 %2, ";
-    else
-        result = "readwrite %1 %2, ";
-    result = result.arg(p.type.toString(QDBusType::ConventionalNames)).arg(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());
-
-    if (result.length() > 1)
-        result.truncate(result.length() - 2);
-    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)));
-}
-
-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);
-    }
-}
-
 void tst_QDBusXmlParser::parsing_data()
 {
     QTest::addColumn<QString>("xmlData");