diff options
Diffstat (limited to 'test')
-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 |
10 files changed, 738 insertions, 133 deletions
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" |