diff options
| author | Thiago Macieira <thiago@kde.org> | 2006-06-11 12:18:23 +0000 | 
|---|---|---|
| committer | Thiago Macieira <thiago@kde.org> | 2006-06-11 12:18:23 +0000 | 
| commit | fd5ac15ebc643635e436b64cf1e656284380b1a5 (patch) | |
| tree | f1630dd4f97b5f56c61150ee2a0186831d81c256 | |
| parent | 3b50a8c9fe65839b79f8df988aee6124abd4f0c4 (diff) | |
	* test/qt/*: Update the testcases, including testing the new
        functionality of sending null QByteArray and QString over the
        bus. Add new headertest test and restore the old
        qdbusxmlparser test.
| -rw-r--r-- | ChangeLog | 7 | ||||
| -rw-r--r-- | test/qt/Makefile.am | 19 | ||||
| -rw-r--r-- | test/qt/common.h | 24 | ||||
| -rw-r--r-- | test/qt/qpong.cpp | 12 | ||||
| -rw-r--r-- | test/qt/tst_hal.cpp | 1 | ||||
| -rw-r--r-- | test/qt/tst_headertest.cpp | 16 | ||||
| -rw-r--r-- | test/qt/tst_qdbusabstractadaptor.cpp | 78 | ||||
| -rw-r--r-- | test/qt/tst_qdbusconnection.cpp | 2 | ||||
| -rw-r--r-- | test/qt/tst_qdbusinterface.cpp | 87 | ||||
| -rw-r--r-- | test/qt/tst_qdbusmarshall.cpp (renamed from test/qt/ping.cpp) | 54 | ||||
| -rw-r--r-- | test/qt/tst_qdbusxmlparser.cpp | 578 | 
11 files changed, 745 insertions, 133 deletions
@@ -1,5 +1,12 @@  2006-06-11  Thiago Macieira <thiago.macieira@trolltech.com> +	* test/qt/*: Update the testcases, including testing the new +        functionality of sending null QByteArray and QString over the +        bus. Add new headertest test and restore the old +        qdbusxmlparser test. + +2006-06-11  Thiago Macieira <thiago.macieira@trolltech.com> +  	* qt/tools/dbuscpp2xml.cpp: Compile on Windows.  	* qt/tools/dbusidl2cpp.cpp: Add missing newline. diff --git a/test/qt/Makefile.am b/test/qt/Makefile.am index f7a8efa9..8ebd3323 100644 --- a/test/qt/Makefile.am +++ b/test/qt/Makefile.am @@ -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 qpong ping qdbusinterface qdbusabstractadaptor hal +TEST_BINARIES = tst_headertest tst_qdbusxmlparser tst_qdbusconnection qpong tst_qdbusmarshall tst_qdbusinterface tst_qdbusabstractadaptor tst_hal  TESTS=  else  TEST_BINARIES= @@ -11,14 +11,17 @@ endif  noinst_PROGRAMS= $(TEST_BINARIES)  qpong_SOURCES= qpong.cpp -ping_SOURCES= ping.cpp -qdbusconnection_SOURCES= tst_qdbusconnection.cpp -qdbusinterface_SOURCES= tst_qdbusinterface.cpp -qdbusabstractadaptor_SOURCES= tst_qdbusabstractadaptor.cpp common.h -hal_SOURCES = tst_hal.cpp +tst_headertest_SOURCES = tst_headertest.cpp +tst_qdbusconnection_SOURCES = tst_qdbusconnection.cpp +tst_qdbusxmlparser_SOURCES = tst_qdbusxmlparser.cpp +tst_qdbusmarshall_SOURCES = tst_qdbusmarshall.cpp +tst_qdbusinterface_SOURCES = tst_qdbusinterface.cpp +tst_qdbusabstractadaptor_SOURCES = tst_qdbusabstractadaptor.cpp common.h +tst_hal_SOURCES = tst_hal.cpp  qpong.o: qpong.moc -ping.o: ping.moc +tst_qdbusxmlparser.o: tst_qdbusxmlparser.moc +tst_qdbusmarshall.o: tst_qdbusmarshall.moc  tst_qdbusconnection.o: tst_qdbusconnection.moc  tst_qdbusinterface.o: tst_qdbusinterface.moc  tst_qdbusabstractadaptor.o: tst_qdbusabstractadaptor.moc @@ -27,7 +30,7 @@ tst_hal.o: tst_hal.moc  %.moc: %.cpp  	$(QT_MOC) $< > $@ -TEST_LIBS=$(DBUS_QTESTLIB_LIBS) $(top_builddir)/qt/libdbus-qt4-1.la +TEST_LIBS=$(DBUS_QTESTLIB_LIBS) $(top_builddir)/qt/src/libdbus-qt4-1.la  LDADD=$(TEST_LIBS) diff --git a/test/qt/common.h b/test/qt/common.h index 943d3d95..58beae4e 100644 --- a/test/qt/common.h +++ b/test/qt/common.h @@ -9,8 +9,8 @@ Q_DECLARE_METATYPE(QList<uint>)  Q_DECLARE_METATYPE(QList<qlonglong>)  Q_DECLARE_METATYPE(QList<qulonglong>)  Q_DECLARE_METATYPE(QList<double>) -#if 0 -#include "../qdbusintrospection_p.h" +#ifdef USE_PRIVATE_CODE +#include "../../qt/src/qdbusintrospection_p.h"  // just to make it easier:  typedef QDBusIntrospection::Interfaces InterfaceMap; @@ -157,6 +157,20 @@ bool compare(const QList<double> &l1, const QList<double> &l2)      return true;  } +bool compare(const QString &s1, const QString &s2) +{ +    if (s1.isEmpty() && s2.isEmpty()) +        return true;            // regardless of whether one of them is null +    return s1 == s2; +} + +bool compare(const QByteArray &ba1, const QByteArray &ba2) +{ +    if (ba1.isEmpty() && ba2.isEmpty()) +        return true;            // regardless of whether one of them is null +    return ba1 == ba2; +} +  bool compare(const QVariant &v1, const QVariant &v2)  {      if (v1.userType() != v2.userType()) @@ -169,6 +183,12 @@ bool compare(const QVariant &v1, const QVariant &v2)      else if (id == QVariant::Map)          return compare(v1.toMap(), v2.toMap()); +    else if (id == QVariant::String) +        return compare(v1.toString(), v2.toString()); + +    else if (id == QVariant::ByteArray) +        return compare(v1.toByteArray(), v2.toByteArray()); +      else if (id < int(QVariant::UserType)) // yes, v1.type()          // QVariant can compare          return v1 == v2; diff --git a/test/qt/qpong.cpp b/test/qt/qpong.cpp index 4a3e9763..cad04eb6 100644 --- a/test/qt/qpong.cpp +++ b/test/qt/qpong.cpp @@ -1,6 +1,5 @@  #include <QtCore/QtCore>  #include <dbus/qdbus.h> -#include <dbus/dbus.h>  class Pong: public QObject  { @@ -22,13 +21,10 @@ int main(int argc, char *argv[])      QCoreApplication app(argc, argv);      QDBusConnection &con = QDBus::sessionBus(); -    QDBusMessage msg = QDBusMessage::methodCall(DBUS_SERVICE_DBUS, -                                                DBUS_PATH_DBUS, -                                                DBUS_INTERFACE_DBUS, -                                                "RequestName"); -    msg << "org.kde.selftest" << 0U; -    msg = con.sendWithReply(msg); -    if (msg.type() != QDBusMessage::ReplyMessage) +    if (!con.isConnected()) +        exit(1); + +    if (con.busService()->requestName("org.kde.selftest", QDBusBusService::DoNotQueueName).isError())          exit(2);      Pong pong; diff --git a/test/qt/tst_hal.cpp b/test/qt/tst_hal.cpp index f98eb98a..a69daf2f 100644 --- a/test/qt/tst_hal.cpp +++ b/test/qt/tst_hal.cpp @@ -2,7 +2,6 @@  #include <qdebug.h>  #include <QtTest/QtTest> -#define DBUS_API_SUBJECT_TO_CHANGE  #include <dbus/qdbus.h>  class tst_Hal: public QObject diff --git a/test/qt/tst_headertest.cpp b/test/qt/tst_headertest.cpp new file mode 100644 index 00000000..eb90c555 --- /dev/null +++ b/test/qt/tst_headertest.cpp @@ -0,0 +1,16 @@ +#define QT_NO_KEYWORDS +#define signals Choke! +#define slots Choke! +#define emit Choke! +#define foreach Choke! +#define forever Choke! + +#define QT_NO_CAST_FROM_ASCII +#define QT_NO_CAST_TO_ASCII + +#include <dbus/qdbus.h> + +int main(int, char **) +{ +    return 0; +} diff --git a/test/qt/tst_qdbusabstractadaptor.cpp b/test/qt/tst_qdbusabstractadaptor.cpp index ec3f0470..d47c5436 100644 --- a/test/qt/tst_qdbusabstractadaptor.cpp +++ b/test/qt/tst_qdbusabstractadaptor.cpp @@ -7,6 +7,10 @@  #include "common.h" +#ifdef Q_CC_MSVC +#define __PRETTY_FUNCTION__ __FUNCDNAME__ +#endif +  const char *slotSpy;  QString valueSpy; @@ -79,7 +83,7 @@ public:  class Interface1: public QDBusAbstractAdaptor  {      Q_OBJECT -    Q_CLASSINFO("D-Bus Interface", "local.Interface1"); +    Q_CLASSINFO("D-Bus Interface", "local.Interface1")  public:      Interface1(QObject *parent) : QDBusAbstractAdaptor(parent)      { } @@ -88,9 +92,9 @@ public:  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); +    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); } @@ -117,9 +121,9 @@ signals:  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_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); } @@ -157,9 +161,9 @@ signals:  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_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); } @@ -452,51 +456,51 @@ void tst_QDBusAbstractAdaptor::methodCalls()      // must fail: no object      //QCOMPARE(empty->call("method").type(), QDBusMessage::ErrorMessage); -    QCOMPARE(if1->call("method").type(), QDBusMessage::ErrorMessage); +    QCOMPARE(if1->call(QDBusInterface::UseEventLoop, "method").type(), QDBusMessage::ErrorMessage);      QFETCH(int, nInterfaces);      MyObject obj(nInterfaces);      con.registerObject("/", &obj);      // must fail: no such method -    QCOMPARE(if1->call("method").type(), QDBusMessage::ErrorMessage); +    QCOMPARE(if1->call(QDBusInterface::UseEventLoop, "method").type(), QDBusMessage::ErrorMessage);      if (!nInterfaces--)          return;      if (!nInterfaces--)          return;      // simple call: one such method exists -    QCOMPARE(if2->call("method").type(), QDBusMessage::ReplyMessage); +    QCOMPARE(if2->call(QDBusInterface::UseEventLoop, "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(if1->call(QDBusInterface::UseEventLoop, "methodVoid").type(), QDBusMessage::ErrorMessage); +    QCOMPARE(if1->call(QDBusInterface::UseEventLoop, "methodInt").type(), QDBusMessage::ErrorMessage); +    QCOMPARE(if1->call(QDBusInterface::UseEventLoop, "methodString").type(), QDBusMessage::ErrorMessage); +    QCOMPARE(if2->call(QDBusInterface::UseEventLoop, "methodVoid").type(), QDBusMessage::ErrorMessage); +    QCOMPARE(if2->call(QDBusInterface::UseEventLoop, "methodInt").type(), QDBusMessage::ErrorMessage); +    QCOMPARE(if2->call(QDBusInterface::UseEventLoop, "methodString").type(), QDBusMessage::ErrorMessage); + +    QCOMPARE(if3->call(QDBusInterface::UseEventLoop, "methodVoid").type(), QDBusMessage::ReplyMessage);      QCOMPARE(slotSpy, "void Interface3::methodVoid()"); -    QCOMPARE(if3->call("methodInt", 42).type(), QDBusMessage::ReplyMessage); +    QCOMPARE(if3->call(QDBusInterface::UseEventLoop, "methodInt", 42).type(), QDBusMessage::ReplyMessage);      QCOMPARE(slotSpy, "void Interface3::methodInt(int)"); -    QCOMPARE(if3->call("methodString", QString("")).type(), QDBusMessage::ReplyMessage); +    QCOMPARE(if3->call(QDBusInterface::UseEventLoop, "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(if4->call(QDBusInterface::UseEventLoop, "method").type(), QDBusMessage::ReplyMessage);      QCOMPARE(slotSpy, "void Interface4::method()");      // method overloading: different parameters -    QCOMPARE(if4->call("method.i", 42).type(), QDBusMessage::ReplyMessage); +    QCOMPARE(if4->call(QDBusInterface::UseEventLoop, "method.i", 42).type(), QDBusMessage::ReplyMessage);      QCOMPARE(slotSpy, "void Interface4::method(int)"); -    QCOMPARE(if4->call("method.s", QString()).type(), QDBusMessage::ReplyMessage); +    QCOMPARE(if4->call(QDBusInterface::UseEventLoop, "method.s", QString()).type(), QDBusMessage::ReplyMessage);      QCOMPARE(slotSpy, "void Interface4::method(QString)");  } @@ -679,18 +683,19 @@ void tst_QDBusAbstractAdaptor::readProperties()      MyObject obj;      con.registerObject("/", &obj); +    QDBusInterfacePtr properties(con, con.baseService(), "/", "org.freedesktop.DBus.Properties");      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); -            QVariant value = iface->property(propname.toLatin1()); +            QDBusReply<QVariant> reply = +                properties->call(QDBusInterface::UseEventLoop, "Get", "local." + name, propname); +            QVariant value = reply;              QCOMPARE(value.userType(), int(QVariant::String));              QCOMPARE(value.toString(), QString("QString %1::%2() const").arg(name, propname));          } -        iface->deleteLater();      }  } @@ -702,21 +707,21 @@ void tst_QDBusAbstractAdaptor::writeProperties()      MyObject obj;      con.registerObject("/", &obj); +    QDBusInterfacePtr properties(con, con.baseService(), "/", "org.freedesktop.DBus.Properties");      for (int i = 2; i <= 4; ++i) {          QString name = QString("Interface%1").arg(i); -        QDBusInterface *iface = con.findInterface(con.baseService(), "/", "local." + name);          QVariant value(name);          valueSpy.clear(); -        iface->setProperty("prop1", value); +        properties->call(QDBusInterface::UseEventLoop, "Set", "local." + name, QString("prop1"), +                         value);          QVERIFY(valueSpy.isEmpty()); // call mustn't have succeeded -        iface->setProperty("prop2", value); +        properties->call(QDBusInterface::UseEventLoop, "Set", "local." + name, QString("prop2"), +                         value);          QCOMPARE(valueSpy, name);          QCOMPARE(QString(slotSpy), QString("void %1::setProp2(const QString&)").arg(name)); - -        iface->deleteLater();      }  } @@ -964,10 +969,11 @@ void tst_QDBusAbstractAdaptor::typeMatching()      QDBusMessage reply;      QDBusInterface *iface = con.findInterface(con.baseService(), "/types", "local.TypesInterface"); -    reply = iface->callWithArgs("method" + basename + '.' + signature, QVariantList() << value); +    reply = iface->callWithArgs("method" + basename + '.' + signature, QVariantList() << value, +                                QDBusInterface::UseEventLoop);      QCOMPARE(reply.type(), QDBusMessage::ReplyMessage); -    reply = iface->call("retrieve" + basename); +    reply = iface->call(QDBusInterface::UseEventLoop, "retrieve" + basename);      QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);      QCOMPARE(reply.count(), 1); diff --git a/test/qt/tst_qdbusconnection.cpp b/test/qt/tst_qdbusconnection.cpp index 224a02c6..a887cd93 100644 --- a/test/qt/tst_qdbusconnection.cpp +++ b/test/qt/tst_qdbusconnection.cpp @@ -246,7 +246,7 @@ void tst_QDBusConnection::registerObject()  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); +    QDBusMessage reply = conn.sendWithReply(msg, QDBusConnection::UseEventLoop);      return reply.type() == QDBusMessage::ReplyMessage;  }     diff --git a/test/qt/tst_qdbusinterface.cpp b/test/qt/tst_qdbusinterface.cpp index 46dde97a..a63b8e0b 100644 --- a/test/qt/tst_qdbusinterface.cpp +++ b/test/qt/tst_qdbusinterface.cpp @@ -34,63 +34,33 @@ Q_DECLARE_METATYPE(QVariantList)  #define TEST_INTERFACE_NAME "com.trolltech.QtDBus.MyObject"  #define TEST_SIGNAL_NAME "somethingHappened" -const char introspectionData[] = -    "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" -    "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n" -    "<node>" - -    "<interface name=\"org.freedesktop.DBus.Introspectable\">" -    "<method name=\"Introspect\">" -    "<arg name=\"data\" direction=\"out\" type=\"s\"/>" -    "</method>" -    "</interface>" - -    "<interface name=\"" TEST_INTERFACE_NAME "\">" -    "<method name=\"ping\">" -    "<arg name=\"ping\" direction=\"in\"  type=\"v\"/>" -    "<arg name=\"pong\" direction=\"out\" type=\"v\"/>" -    "</method>" -    "<method name=\"ping\">" -    "<arg name=\"ping1\" direction=\"in\"  type=\"v\"/>" -    "<arg name=\"ping2\" direction=\"in\"  type=\"v\"/>" -    "<arg name=\"pong1\" direction=\"out\" type=\"v\"/>" -    "<arg name=\"pong2\" direction=\"out\" type=\"v\"/>" -    "</method>" -    "<signal name=\"" TEST_SIGNAL_NAME "\">" -    "<arg type=\"s\"/>" -    "</signal>" -    "<property name=\"prop1\" access=\"readwrite\" type=\"i\" />" -    "</interface>" -    "<node name=\"subObject\"/>" -    "</node>"; - -class IntrospectionAdaptor: public QDBusAbstractAdaptor -{ -    Q_OBJECT -    Q_CLASSINFO("D-Bus Interface", "org.freedesktop.DBus.Introspectable") -public: -    IntrospectionAdaptor(QObject *parent) -        : QDBusAbstractAdaptor(parent) -    { } -         -public slots: - -    void Introspect(const QDBusMessage &msg) -    { -        QDBusMessage reply = QDBusMessage::methodReply(msg); -        reply << ::introspectionData; -        if (!msg.connection().send(reply)) -            exit(1); -    } -};     -  class MyObject: public QObject  {      Q_OBJECT +    Q_CLASSINFO("D-Bus Interface", "com.trolltech.QtDBus.MyObject") +    Q_CLASSINFO("D-Bus Introspection", "" +"  <interface name=\"com.trolltech.QtDBus.MyObject\" >\n" +"    <property access=\"readwrite\" type=\"i\" name=\"prop1\" />\n" +"    <signal name=\"somethingHappened\" >\n" +"      <arg direction=\"out\" type=\"s\" />\n" +"    </signal>\n" +"    <method name=\"ping\" >\n" +"      <arg direction=\"in\" type=\"v\" name=\"ping\" />\n" +"      <arg direction=\"out\" type=\"v\" name=\"ping\" />\n" +"    </method>\n" +"    <method name=\"ping\" >\n" +"      <arg direction=\"in\" type=\"v\" name=\"ping1\" />\n" +"      <arg direction=\"in\" type=\"v\" name=\"ping2\" />\n" +"      <arg direction=\"out\" type=\"v\" name=\"pong1\" />\n" +"      <arg direction=\"out\" type=\"v\" name=\"pong2\" />\n" +"    </method>\n" +"  </interface>\n" +        "")  public:      MyObject()      { -        new IntrospectionAdaptor(this); +        QObject *subObject = new QObject(this); +        subObject->setObjectName("subObject");      }  public slots: @@ -152,7 +122,8 @@ void tst_QDBusInterface::initTestCase()      QDBusConnection &con = QDBus::sessionBus();      QVERIFY(con.isConnected()); -    con.registerObject("/", &obj, QDBusConnection::ExportAdaptors | QDBusConnection::ExportSlots); +    con.registerObject("/", &obj, QDBusConnection::ExportAdaptors | QDBusConnection::ExportSlots | +                       QDBusConnection::ExportChildObjects);  }  void tst_QDBusInterface::call_data() @@ -241,7 +212,7 @@ void tst_QDBusInterface::call()      QDBusMessage reply;      // try first callWithArgs: -    reply = iface->callWithArgs(method, input); +    reply = iface->callWithArgs(method, input, QDBusInterface::UseEventLoop);      QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);      if (!output.isEmpty()) { @@ -251,20 +222,20 @@ void tst_QDBusInterface::call()      // try the template methods      if (input.isEmpty()) -        reply = iface->call(method); +        reply = iface->call(QDBusInterface::UseEventLoop, method);      else if (input.count() == 1)          switch (input.at(0).type())          {          case QVariant::Int: -            reply = iface->call(method, input.at(0).toInt()); +            reply = iface->call(QDBusInterface::UseEventLoop, method, input.at(0).toInt());              break;          case QVariant::UInt: -            reply = iface->call(method, input.at(0).toUInt()); +            reply = iface->call(QDBusInterface::UseEventLoop, method, input.at(0).toUInt());              break;          case QVariant::String: -            reply = iface->call(method, input.at(0).toString()); +            reply = iface->call(QDBusInterface::UseEventLoop, method, input.at(0).toString());              break;          default: @@ -272,7 +243,7 @@ void tst_QDBusInterface::call()              break;          }      else -        reply = iface->call(method, input.at(0).toString(), input.at(1).toString()); +        reply = iface->call(QDBusInterface::UseEventLoop, method, input.at(0).toString(), input.at(1).toString());      QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);      if (!output.isEmpty()) { diff --git a/test/qt/ping.cpp b/test/qt/tst_qdbusmarshall.cpp index 1cdbfca5..306f7b6a 100644 --- a/test/qt/ping.cpp +++ b/test/qt/tst_qdbusmarshall.cpp @@ -3,8 +3,9 @@  #include <dbus/qdbus.h>  #include "common.h" +#include <limits> -class Ping: public QObject +class tst_QDBusMarshall: public QObject  {      Q_OBJECT @@ -35,19 +36,20 @@ private:      QProcess proc;  }; -void Ping::initTestCase() +void tst_QDBusMarshall::initTestCase()  {      proc.start("./qpong");      QVERIFY(proc.waitForStarted());      QTest::qWait(2000);  } -void Ping::cleanupTestCase() +void tst_QDBusMarshall::cleanupTestCase()  {      proc.close(); +    proc.kill();  } -void Ping::sendBasic_data() +void tst_QDBusMarshall::sendBasic_data()  {      QTest::addColumn<QVariant>("value");      QTest::addColumn<QString>("sig"); @@ -65,9 +67,10 @@ void Ping::sendBasic_data()      QTest::newRow("double") << QVariant(42.5) << "d";      QTest::newRow("string") << QVariant("ping") << "s";      QTest::newRow("emptystring") << QVariant("") << "s"; +    QTest::newRow("nullstring") << QVariant(QString()) << "s";  } -void Ping::sendVariant_data() +void tst_QDBusMarshall::sendVariant_data()  {      sendBasic_data(); @@ -80,7 +83,7 @@ void Ping::sendVariant_data()      QTest::newRow("variant-variant") << nested2 << "v";  } -void Ping::sendArrays_data() +void tst_QDBusMarshall::sendArrays_data()  {      QTest::addColumn<QVariant>("value");      QTest::addColumn<QString>("sig"); @@ -91,10 +94,24 @@ void Ping::sendArrays_data()      strings << "hello" << "world";      QTest::newRow("stringlist") << QVariant(strings) << "as"; -    QByteArray bytearray("");   // empty, not null +    strings.clear(); +    strings << "" << "" << ""; +    QTest::newRow("list-of-emptystrings") << QVariant(strings) << "as"; + +    strings.clear(); +    strings << QString() << QString() << QString() << QString(); +    QTest::newRow("list-of-nullstrings") << QVariant(strings) << "as"; + +    QByteArray bytearray; +    QTest::newRow("nullbytearray") << QVariant(bytearray) << "ay"; +    bytearray = "";             // empty, not null      QTest::newRow("emptybytearray") << QVariant(bytearray) << "ay";      bytearray = "foo";      QTest::newRow("bytearray") << QVariant(bytearray) << "ay"; +    bytearray.clear(); +    for (int i = 0; i < 4096; ++i) +        bytearray += QByteArray(1024, char(i)); +    QTest::newRow("hugebytearray") << QVariant(bytearray) << "ay";      QList<bool> bools;       QTest::newRow("emptyboollist") << qVariantFromValue(bools) << "ab"; @@ -152,12 +169,12 @@ void Ping::sendArrays_data()      QTest::newRow("variantlist") << QVariant(variants) << "av";  } -void Ping::sendArrayOfArrays_data() +void tst_QDBusMarshall::sendArrayOfArrays_data()  {      sendArrays_data();  } -void Ping::sendStringMap_data() +void tst_QDBusMarshall::sendStringMap_data()  {      sendBasic_data(); @@ -172,12 +189,12 @@ void Ping::sendStringMap_data()      sendArrays_data();  } -void Ping::sendStringMapOfMap_data() +void tst_QDBusMarshall::sendStringMapOfMap_data()  {      sendStringMap_data();  } -void Ping::sendBasic() +void tst_QDBusMarshall::sendBasic()  {      QFETCH(QVariant, value); @@ -198,7 +215,7 @@ void Ping::sendBasic()          QVERIFY(compare(reply.at(i), msg.at(i)));  } -void Ping::sendVariant() +void tst_QDBusMarshall::sendVariant()  {      QFETCH(QVariant, value);      QVariant tmp = value; @@ -221,7 +238,7 @@ void Ping::sendVariant()          QVERIFY(compare(reply.at(i), msg.at(i)));  } -void Ping::sendArrays() +void tst_QDBusMarshall::sendArrays()  {      QFETCH(QVariant, value); @@ -242,7 +259,7 @@ void Ping::sendArrays()          QVERIFY(compare(reply.at(i), msg.at(i)));  } -void Ping::sendArrayOfArrays() +void tst_QDBusMarshall::sendArrayOfArrays()  {      QFETCH(QVariant, value); @@ -264,7 +281,7 @@ void Ping::sendArrayOfArrays()          QVERIFY(compare(reply.at(i), msg.at(i)));  } -void Ping::sendStringMap() +void tst_QDBusMarshall::sendStringMap()  {      QFETCH(QVariant, value); @@ -290,7 +307,7 @@ void Ping::sendStringMap()          QVERIFY(compare(reply.at(i), msg.at(i)));  } -void Ping::sendStringMapOfMap() +void tst_QDBusMarshall::sendStringMapOfMap()  {      QFETCH(QVariant, value); @@ -316,11 +333,10 @@ void Ping::sendStringMapOfMap()      QFETCH(QString, sig);      QCOMPARE(reply.signature(), "a{sa{s" + sig + "}}"); -    QEXPECT_FAIL("", "libdbus returns an empty set for un unknown reason", Abort);      for (int i = 0; i < reply.count(); ++i)          QVERIFY(compare(reply.at(i), msg.at(i)));  } -QTEST_MAIN(Ping) -#include "ping.moc" +QTEST_MAIN(tst_QDBusMarshall) +#include "tst_qdbusmarshall.moc" diff --git a/test/qt/tst_qdbusxmlparser.cpp b/test/qt/tst_qdbusxmlparser.cpp new file mode 100644 index 00000000..bf1ddec5 --- /dev/null +++ b/test/qt/tst_qdbusxmlparser.cpp @@ -0,0 +1,578 @@ +/* -*- C++ -*- + * + * Copyright (C) 2006 Trolltech AS. All rights reserved. + *    Author: Thiago Macieira <thiago.macieira@trolltech.com> + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include <qcoreapplication.h> +#include <qmetatype.h> +#include <QtTest/QtTest> + +#include <dbus/qdbus.h> + +#define USE_PRIVATE_CODE +#include "common.h" + +class tst_QDBusXmlParser: public QObject +{ +    Q_OBJECT + +private: +    void parsing_common(const QString&); + +private slots: +    void parsing_data(); +    void parsing(); +    void parsingWithDoctype_data(); +    void parsingWithDoctype(); + +    void objectWithContent_data(); +    void objectWithContent(); + +    void methods_data(); +    void methods(); +    void signals__data(); +    void signals_(); +    void properties_data(); +    void properties(); +}; + +void tst_QDBusXmlParser::parsing_data() +{ +    QTest::addColumn<QString>("xmlData"); +    QTest::addColumn<int>("interfaceCount"); +    QTest::addColumn<int>("objectCount"); + +    QTest::newRow("null") << QString() << 0 << 0; +    QTest::newRow("empty") << QString("") << 0 << 0; +     +    QTest::newRow("junk") << "<junk/>" << 0 << 0; +    QTest::newRow("interface-inside-junk") << "<junk><interface name=\"iface.iface1\" /></junk>" +                                           << 0 << 0; +    QTest::newRow("object-inside-junk") << "<junk><node name=\"obj1\" /></junk>" +                                        << 0 << 0; + +    QTest::newRow("zero-interfaces") << "<node/>" << 0 << 0; +    QTest::newRow("one-interface") << "<node><interface name=\"iface.iface1\" /></node>" << 1 << 0; + +     +    QTest::newRow("two-interfaces") << "<node><interface name=\"iface.iface1\" />" +                                       "<interface name=\"iface.iface2\"></node>" +                                    << 2 << 0;         + + +    QTest::newRow("one-object") << "<node><node name=\"obj1\"/></node>" << 0 << 1; +    QTest::newRow("two-objects") << "<node><node name=\"obj1\"/><node name=\"obj2\"></node>" << 0 << 2; + +    QTest::newRow("i1o1") << "<node><interface name=\"iface.iface1\"><node name=\"obj1\"></node>" << 1 << 1; + +} + +void tst_QDBusXmlParser::parsing_common(const QString &xmlData) +{ +    QDBusIntrospection::ObjectTree obj = +        QDBusIntrospection::parseObjectTree(xmlData, "local.testing", "/"); +    QFETCH(int, interfaceCount); +    QFETCH(int, objectCount); +    QCOMPARE(obj.interfaces.count(), interfaceCount); +    QCOMPARE(obj.childObjects.count(), objectCount); + +    // also verify the naming +    int i = 0; +    foreach (QString name, obj.interfaces) +        QCOMPARE(name, QString("iface.iface%1").arg(++i)); + +    i = 0; +    foreach (QString name, obj.childObjects) +        QCOMPARE(name, QString("obj%1").arg(++i)); +} + +void tst_QDBusXmlParser::parsing() +{ +    QFETCH(QString, xmlData); + +    parsing_common(xmlData); +} + +void tst_QDBusXmlParser::parsingWithDoctype_data() +{ +    parsing_data(); +} + +void tst_QDBusXmlParser::parsingWithDoctype() +{ +    QString docType = "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" +                      "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"; +    QFETCH(QString, xmlData); + +    parsing_common(docType + xmlData); +}     + +void tst_QDBusXmlParser::objectWithContent_data() +{ +    QTest::addColumn<QString>("xmlData"); +    QTest::addColumn<QString>("probedObject"); +    QTest::addColumn<int>("interfaceCount"); +    QTest::addColumn<int>("objectCount"); + +    QTest::newRow("zero") << "<node><node name=\"obj\"/></node>" << "obj" << 0 << 0; + +    QString xmlData = "<node><node name=\"obj\">" +                      "<interface name=\"iface.iface1\" />" +                      "</node></node>"; +    QTest::newRow("one-interface") << xmlData << "obj" << 1 << 0; +    QTest::newRow("one-interface2") << xmlData << "obj2" << 0 << 0; + +    xmlData = "<node><node name=\"obj\">" +              "<interface name=\"iface.iface1\" />" +              "<interface name=\"iface.iface2\" />" +              "</node></node>"; +    QTest::newRow("two-interfaces") << xmlData << "obj" << 2 << 0; +    QTest::newRow("two-interfaces2") << xmlData << "obj2" << 0 << 0; + +    xmlData = "<node><node name=\"obj\">" +              "<interface name=\"iface.iface1\" />" +              "<interface name=\"iface.iface2\" />" +              "</node><node name=\"obj2\">" +              "<interface name=\"iface.iface1\" />" +              "</node></node>"; +    QTest::newRow("two-nodes-two-interfaces") << xmlData << "obj" << 2 << 0; +    QTest::newRow("two-nodes-one-interface") << xmlData << "obj2" << 1 << 0; + +    xmlData = "<node><node name=\"obj\">" +              "<node name=\"obj1\" />" +              "</node></node>"; +    QTest::newRow("one-object") << xmlData << "obj" << 0 << 1; +    QTest::newRow("one-object2") << xmlData << "obj2" << 0 << 0; + +    xmlData = "<node><node name=\"obj\">" +              "<node name=\"obj1\" />" +              "<node name=\"obj2\" />" +              "</node></node>"; +    QTest::newRow("two-objects") << xmlData << "obj" << 0 << 2; +    QTest::newRow("two-objects2") << xmlData << "obj2" << 0 << 0; + +    xmlData = "<node><node name=\"obj\">" +              "<node name=\"obj1\" />" +              "<node name=\"obj2\" />" +              "</node><node name=\"obj2\">" +              "<node name=\"obj1\" />" +              "</node></node>"; +    QTest::newRow("two-nodes-two-objects") << xmlData << "obj" << 0 << 2; +    QTest::newRow("two-nodes-one-object") << xmlData << "obj2" << 0 << 1; +} + +void tst_QDBusXmlParser::objectWithContent() +{ +    QFETCH(QString, xmlData); +    QFETCH(QString, probedObject); + +    QDBusIntrospection::ObjectTree tree = +        QDBusIntrospection::parseObjectTree(xmlData, "local.testing", "/"); + +    const ObjectMap &om = tree.childObjectData; + +    if (om.contains(probedObject)) { +        const QSharedDataPointer<QDBusIntrospection::ObjectTree>& obj = om.value(probedObject); +        QVERIFY(obj != 0); +     +        QFETCH(int, interfaceCount); +        QFETCH(int, objectCount); + +        QCOMPARE(obj->interfaces.count(), interfaceCount); +        QCOMPARE(obj->childObjects.count(), objectCount); + +        // verify the object names +        int i = 0; +        foreach (QString name, obj->interfaces) +            QCOMPARE(name, QString("iface.iface%1").arg(++i)); + +        i = 0; +        foreach (QString name, obj->childObjects) +            QCOMPARE(name, QString("obj%1").arg(++i)); +    } +} + +void tst_QDBusXmlParser::methods_data() +{ +    QTest::addColumn<QString>("xmlDataFragment"); +    QTest::addColumn<MethodMap>("methodMap"); + +    MethodMap map; +    QTest::newRow("no-methods") << QString() << map; + +    // one method without arguments +    QDBusIntrospection::Method method; +    method.name = "Foo"; +    map << method; +    QTest::newRow("one-method") << "<method name=\"Foo\"/>" << map; + +    // add another method without arguments +    method.name = "Bar"; +    map << method; +    QTest::newRow("two-methods") << "<method name=\"Foo\"/>" +                                    "<method name=\"Bar\"/>" +                                 << map; + +    // invert the order of the XML declaration +    QTest::newRow("two-methods-inverse") << "<method name=\"Bar\"/>" +                                            "<method name=\"Foo\"/>" +                                         << map; + +    // add a third, with annotations +    method.name = "Baz"; +    method.annotations.insert("foo.testing", "nothing to see here"); +    map << method; +    QTest::newRow("method-with-annotation") << +        "<method name=\"Foo\"/>" +        "<method name=\"Bar\"/>" +        "<method name=\"Baz\"><annotation name=\"foo.testing\" value=\"nothing to see here\"></method>" +                                            << map; + +    // arguments +    map.clear(); +    method.annotations.clear(); + +    method.name = "Method"; +    method.inputArgs << arg("s"); +    map << method; +    QTest::newRow("one-in") << +        "<method name=\"Method\">" +        "<arg type=\"s\" direction=\"in\"/>" +        "</method>" << map; + +    // two arguments +    method.inputArgs << arg("v"); +    map.clear(); +    map << method; +    QTest::newRow("two-in") << +        "<method name=\"Method\">" +        "<arg type=\"s\" direction=\"in\"/>" +        "<arg type=\"v\" direction=\"in\"/>" +        "</method>" << map; + +    // one invalid arg +    QTest::newRow("two-in-one-invalid") << +        "<method name=\"Method\">" +        "<arg type=\"s\" direction=\"in\"/>" +        "<arg type=\"~\" name=\"invalid\" direction=\"in\"/>" // this line should be ignored +        "<arg type=\"v\" direction=\"in\"/>" +        "</method>" << map; + +    // one out argument +    method.inputArgs.clear(); +    method.outputArgs << arg("s"); +    map.clear(); +    map << method; +    QTest::newRow("one-out") << +        "<method name=\"Method\">" +        "<arg type=\"s\" direction=\"out\"/>" +        "</method>" << map; + +    // two in and one out +    method.inputArgs << arg("s") << arg("v"); +    map.clear(); +    map << method; +    QTest::newRow("two-in-one-out") << +        "<method name=\"Method\">" +        "<arg type=\"s\" direction=\"in\"/>" +        "<arg type=\"v\" direction=\"in\"/>" +        "<arg type=\"s\" direction=\"out\"/>" +        "</method>" << map; + +    // let's try an arg with name +    method.outputArgs.clear(); +    method.inputArgs.clear(); +    method.inputArgs << arg("s", "foo"); +    map.clear(); +    map << method; +    QTest::newRow("one-in-with-name") << +        "<method name=\"Method\">" +        "<arg type=\"s\" name=\"foo\" direction=\"in\"/>" +        "</method>" << map; + +    // two args with name +    method.inputArgs << arg("i", "bar"); +    map.clear(); +    map << method; +    QTest::newRow("two-in-with-name") << +        "<method name=\"Method\">" +        "<arg type=\"s\" name=\"foo\" direction=\"in\"/>" +        "<arg type=\"i\" name=\"bar\" direction=\"in\"/>" +        "</method>" << map; + +    // one complex +    map.clear(); +    method = QDBusIntrospection::Method(); + +    // Method1(in STRING arg1, in BYTE arg2, out ARRAY of STRING) +    method.inputArgs << arg("s", "arg1") << arg("y", "arg2"); +    method.outputArgs << arg("as"); +    method.name = "Method1"; +    map << method; + +    // Method2(in ARRAY of DICT_ENTRY of (STRING,VARIANT) variantMap, in UINT32 index, +    //         out STRING key, out VARIANT value) +    // with annotation "foo.equivalent":"QVariantMap" +    method = QDBusIntrospection::Method(); +    method.inputArgs << arg("a{sv}", "variantMap") << arg("u", "index"); +    method.outputArgs << arg("s", "key") << arg("v", "value"); +    method.annotations.insert("foo.equivalent", "QVariantMap"); +    method.name = "Method2"; +    map << method; + +    QTest::newRow("complex") << +        "<method name=\"Method1\">" +        "<arg name=\"arg1\" type=\"s\" direction=\"in\"/>" +        "<arg name=\"arg2\" type=\"y\" direction=\"in\"/>" +        "<arg type=\"as\" direction=\"out\"/>" +        "</method>" +        "<method name=\"Method2\">" +        "<arg name=\"variantMap\" type=\"a{sv}\" direction=\"in\"/>" +        "<arg name=\"index\" type=\"u\" direction=\"in\"/>" +        "<arg name=\"key\" type=\"s\" direction=\"out\"/>" +        "<arg name=\"value\" type=\"v\" direction=\"out\"/>" +        "<annotation name=\"foo.equivalent\" value=\"QVariantMap\"/>" +        "</method>" << map; +} + +void tst_QDBusXmlParser::methods() +{ +    QString xmlHeader = "<node>" +                        "<interface name=\"iface.iface1\">", +            xmlFooter = "</interface>" +                        "</node>"; + +    QFETCH(QString, xmlDataFragment); + +    QDBusIntrospection::Interface iface = +        QDBusIntrospection::parseInterface(xmlHeader + xmlDataFragment + xmlFooter); + +    QCOMPARE(iface.name, QString("iface.iface1")); + +    QFETCH(MethodMap, methodMap); +    MethodMap parsedMap = iface.methods; + +    QCOMPARE(methodMap.count(), parsedMap.count()); +    QCOMPARE(methodMap, parsedMap); +}              + +void tst_QDBusXmlParser::signals__data() +{ +    QTest::addColumn<QString>("xmlDataFragment"); +    QTest::addColumn<SignalMap>("signalMap"); + +    SignalMap map; +    QTest::newRow("no-signals") << QString() << map; + +    // one signal without arguments +    QDBusIntrospection::Signal signal; +    signal.name = "Foo"; +    map << signal; +    QTest::newRow("one-signal") << "<signal name=\"Foo\"/>" << map; + +    // add another signal without arguments +    signal.name = "Bar"; +    map << signal; +    QTest::newRow("two-signals") << "<signal name=\"Foo\"/>" +                                    "<signal name=\"Bar\"/>" +                                 << map; + +    // invert the order of the XML declaration +    QTest::newRow("two-signals-inverse") << "<signal name=\"Bar\"/>" +                                            "<signal name=\"Foo\"/>" +                                         << map; + +    // add a third, with annotations +    signal.name = "Baz"; +    signal.annotations.insert("foo.testing", "nothing to see here"); +    map << signal; +    QTest::newRow("signal-with-annotation") << +        "<signal name=\"Foo\"/>" +        "<signal name=\"Bar\"/>" +        "<signal name=\"Baz\"><annotation name=\"foo.testing\" value=\"nothing to see here\"></signal>" +                                            << map; + +    // one out argument +    map.clear(); +    signal.annotations.clear(); +    signal.outputArgs << arg("s"); +    signal.name = "Signal"; +    map.clear(); +    map << signal; +    QTest::newRow("one-out") << +        "<signal name=\"Signal\">" +        "<arg type=\"s\" direction=\"out\"/>" +        "</signal>" << map; + +    // without saying which direction it is +    QTest::newRow("one-out-no-direction") << +        "<signal name=\"Signal\">" +        "<arg type=\"s\"/>" +        "</signal>" << map;     + +    // two args with name +    signal.outputArgs << arg("i", "bar"); +    map.clear(); +    map << signal; +    QTest::newRow("two-out-with-name") << +        "<signal name=\"Signal\">" +        "<arg type=\"s\" direction=\"out\"/>" +        "<arg type=\"i\" name=\"bar\"/>" +        "</signal>" << map; + +    // one complex +    map.clear(); +    signal = QDBusIntrospection::Signal(); + +    // Signal1(out ARRAY of STRING) +    signal.outputArgs << arg("as"); +    signal.name = "Signal1"; +    map << signal; + +    // Signal2(out STRING key, out VARIANT value) +    // with annotation "foo.equivalent":"QVariantMap" +    signal = QDBusIntrospection::Signal(); +    signal.outputArgs << arg("s", "key") << arg("v", "value"); +    signal.annotations.insert("foo.equivalent", "QVariantMap"); +    signal.name = "Signal2"; +    map << signal; + +    QTest::newRow("complex") << +        "<signal name=\"Signal1\">" +        "<arg type=\"as\" direction=\"out\"/>" +        "</signal>" +        "<signal name=\"Signal2\">" +        "<arg name=\"key\" type=\"s\" direction=\"out\"/>" +        "<arg name=\"value\" type=\"v\" direction=\"out\"/>" +        "<annotation name=\"foo.equivalent\" value=\"QVariantMap\"/>" +        "</signal>" << map; +} + +void tst_QDBusXmlParser::signals_() +{ +    QString xmlHeader = "<node>" +                        "<interface name=\"iface.iface1\">", +            xmlFooter = "</interface>" +                        "</node>"; + +    QFETCH(QString, xmlDataFragment); + +    QDBusIntrospection::Interface iface = +        QDBusIntrospection::parseInterface(xmlHeader + xmlDataFragment + xmlFooter); + +    QCOMPARE(iface.name, QString("iface.iface1")); + +    QFETCH(SignalMap, signalMap); +    SignalMap parsedMap = iface.signals_; + +    QCOMPARE(signalMap.count(), parsedMap.count()); +    QCOMPARE(signalMap, parsedMap); +} + +void tst_QDBusXmlParser::properties_data() +{ +    QTest::addColumn<QString>("xmlDataFragment"); +    QTest::addColumn<PropertyMap>("propertyMap"); + +    PropertyMap map; +    QTest::newRow("no-signals") << QString() << map; + +    // one readable signal +    QDBusIntrospection::Property prop; +    prop.name = "foo"; +    prop.type = "s"; +    prop.access = QDBusIntrospection::Property::Read; +    map << prop; +    QTest::newRow("one-readable") << "<property name=\"foo\" type=\"s\" access=\"read\"/>" << map; + +    // one writable signal +    prop.access = QDBusIntrospection::Property::Write; +    map.clear(); +    map << prop; +    QTest::newRow("one-writable") << "<property name=\"foo\" type=\"s\" access=\"write\"/>" << map; + +    // one read- & writable signal +    prop.access = QDBusIntrospection::Property::ReadWrite; +    map.clear(); +    map << prop; +    QTest::newRow("one-read-writable") << "<property name=\"foo\" type=\"s\" access=\"readwrite\"/>" +                                       << map; + +    // two, mixed properties +    prop.name = "bar"; +    prop.type = "i"; +    prop.access = QDBusIntrospection::Property::Read; +    map << prop; +    QTest::newRow("two") << +        "<property name=\"foo\" type=\"s\" access=\"readwrite\"/>" +        "<property name=\"bar\" type=\"i\" access=\"read\"/>" << map; + +    // invert the order of the declaration +    QTest::newRow("two") << +        "<property name=\"bar\" type=\"i\" access=\"read\"/>" +        "<property name=\"foo\" type=\"s\" access=\"readwrite\"/>" << map; + +    // add a third with annotations +    prop.name = "baz"; +    prop.type = "as"; +    prop.access = QDBusIntrospection::Property::Write; +    prop.annotations.insert("foo.annotation", "Hello, World"); +    prop.annotations.insert("foo.annotation2", "Goodbye, World"); +    map << prop; +    QTest::newRow("complex") << +        "<property name=\"bar\" type=\"i\" access=\"read\"/>" +        "<property name=\"baz\" type=\"as\" access=\"write\">" +        "<annotation name=\"foo.annotation\" value=\"Hello, World\" />" +        "<annotation name=\"foo.annotation2\" value=\"Goodbye, World\" />" +        "<property name=\"foo\" type=\"s\" access=\"readwrite\"/>" << map; + +    // and now change the order +    QTest::newRow("complex2") << +        "<property name=\"baz\" type=\"as\" access=\"write\">" +        "<annotation name=\"foo.annotation2\" value=\"Goodbye, World\" />" +        "<annotation name=\"foo.annotation\" value=\"Hello, World\" />" +        "<property name=\"bar\" type=\"i\" access=\"read\"/>" +        "<property name=\"foo\" type=\"s\" access=\"readwrite\"/>" << map; +} + +void tst_QDBusXmlParser::properties() +{ +    QString xmlHeader = "<node>" +                        "<interface name=\"iface.iface1\">", +            xmlFooter = "</interface>" +                        "</node>"; + +    QFETCH(QString, xmlDataFragment); + +    QDBusIntrospection::Interface iface = +        QDBusIntrospection::parseInterface(xmlHeader + xmlDataFragment + xmlFooter); + +    QCOMPARE(iface.name, QString("iface.iface1")); + +    QFETCH(PropertyMap, propertyMap); +    PropertyMap parsedMap = iface.properties; + +    QCOMPARE(propertyMap.count(), parsedMap.count()); +    QCOMPARE(propertyMap, parsedMap); +} + +QTEST_MAIN(tst_QDBusXmlParser) + +#include "tst_qdbusxmlparser.moc"  | 
