* 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.
This commit is contained in:
Thiago Macieira 2006-06-11 12:18:23 +00:00
parent 3b50a8c9fe
commit fd5ac15ebc
11 changed files with 744 additions and 132 deletions

View file

@ -1,3 +1,10 @@
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.

View 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 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)

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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;
}

View file

@ -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(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("methodVoid").type(), QDBusMessage::ReplyMessage);
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);

View file

@ -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;
}

View file

@ -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()) {

View file

@ -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"

View file

@ -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"