qt6windows7/tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp
2023-11-01 18:02:52 +01:00

1896 lines
63 KiB
C++

// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QDebug>
#include <QCoreApplication>
#include <QProcess>
#include <QTimer>
#include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusConnectionInterface>
#include "../qdbusmarshall/common.h"
#include "myobject.h"
static const char serviceName[] = "org.qtproject.autotests.qmyserver";
static const char objectPath[] = "/org/qtproject/qmyserver";
static const char *interfaceName = serviceName;
const char *slotSpy;
QString valueSpy;
QT_BEGIN_NAMESPACE
namespace QTest {
char *toString(QDBusMessage::MessageType t)
{
switch (t)
{
case QDBusMessage::InvalidMessage:
return qstrdup("InvalidMessage");
case QDBusMessage::MethodCallMessage:
return qstrdup("MethodCallMessage");
case QDBusMessage::ReplyMessage:
return qstrdup("ReplyMessage");
case QDBusMessage::ErrorMessage:
return qstrdup("ErrorMessage");
case QDBusMessage::SignalMessage:
return qstrdup("SignalMessage");
default:
return 0;
}
}
}
QT_END_NAMESPACE
class TypesInterface: public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "local.TypesInterface")
public:
TypesInterface(QObject *parent)
: QDBusAbstractAdaptor(parent)
{ }
union
{
bool b;
uchar uc;
short s;
ushort us;
int i;
uint ui;
qlonglong ll;
qulonglong ull;
double d;
} dataSpy;
QVariant variantSpy;
QString stringSpy;
QVariantList listSpy;
QStringList stringlistSpy;
QByteArray bytearraySpy;
QVariantMap mapSpy;
StringStringMap ssmapSpy;
LLDateTimeMap lldtmapSpy;
MyStruct structSpy;
public slots:
void methodBool(bool b)
{
slotSpy = "void TypesInterface::methodBool(bool)";
dataSpy.b = b;
}
void methodUChar(uchar uc)
{
slotSpy = "void TypesInterface::methodUChar(uchar)";
dataSpy.uc = uc;
}
void methodShort(short s)
{
slotSpy = "void TypesInterface::methodShort(short)";
dataSpy.s = s;
}
void methodUShort(ushort us)
{
slotSpy = "void TypesInterface::methodUShort(ushort)";
dataSpy.us = us;
}
void methodInt(int i)
{
slotSpy = "void TypesInterface::methodInt(int)";
dataSpy.i = i;
}
void methodUInt(uint ui)
{
slotSpy = "void TypesInterface::methodUInt(uint)";
dataSpy.ui = ui;
}
void methodLongLong(qlonglong ll)
{
slotSpy = "void TypesInterface::methodLongLong(qlonglong)";
dataSpy.ll = ll;
}
void methodULongLong(qulonglong ull)
{
slotSpy = "void TypesInterface::methodULongLong(qulonglong)";
dataSpy.ull = ull;
}
void methodDouble(double d)
{
slotSpy = "void TypesInterface::methodDouble(double)";
dataSpy.d = d;
}
void methodString(const QString &s)
{
slotSpy = "void TypesInterface::methodString(const QString &)";
stringSpy = s;
}
void methodObjectPath(const QDBusObjectPath &op)
{
slotSpy = "void TypesInterface::methodObjectPath(const QDBusObjectPath &)";
stringSpy = op.path();
}
void methodSignature(const QDBusSignature &s)
{
slotSpy = "void TypesInterface::methodSignature(const QDBusSignature &)";
stringSpy = s.signature();
}
void methodVariant(const QDBusVariant &v)
{
slotSpy = "void TypesInterface::methodVariant(const QDBusVariant &)";
variantSpy = v.variant();
}
void methodList(const QVariantList &l)
{
slotSpy = "void TypesInterface::methodList(const QVariantList &)";
listSpy = l;
}
void methodStringList(const QStringList &sl)
{
slotSpy = "void TypesInterface::methodStringList(const QStringList &)";
stringlistSpy = sl;
}
void methodByteArray(const QByteArray &ba)
{
slotSpy = "void TypesInterface::methodByteArray(const QByteArray &)";
bytearraySpy = ba;
}
void methodMap(const QVariantMap &m)
{
slotSpy = "void TypesInterface::methodMap(const QVariantMap &)";
mapSpy = m;
}
void methodSSMap(const StringStringMap &ssmap)
{
slotSpy = "void TypesInterface::methodSSMap(const StringStringMap &)";
ssmapSpy = ssmap;
}
void methodLLDateTimeMap(const LLDateTimeMap &lldtmap)
{
slotSpy = "void TypesInterface::methodLLDateTimeMap(const LLDateTimeMap &)";
lldtmapSpy = lldtmap;
}
void methodStruct(const MyStruct &s)
{
slotSpy = "void TypesInterface::methodStruct(const MyStruct &)";
structSpy = s;
}
bool retrieveBool()
{
return dataSpy.b;
}
uchar retrieveUChar()
{
return dataSpy.uc;
}
short retrieveShort()
{
return dataSpy.s;
}
ushort retrieveUShort()
{
return dataSpy.us;
}
int retrieveInt()
{
return dataSpy.i;
}
uint retrieveUInt()
{
return dataSpy.ui;
}
qlonglong retrieveLongLong()
{
return dataSpy.ll;
}
qulonglong retrieveULongLong()
{
return dataSpy.ull;
}
double retrieveDouble()
{
return dataSpy.d;
}
QString retrieveString()
{
return stringSpy;
}
QDBusObjectPath retrieveObjectPath()
{
return QDBusObjectPath(stringSpy);
}
QDBusSignature retrieveSignature()
{
return QDBusSignature(stringSpy);
}
QDBusVariant retrieveVariant()
{
return QDBusVariant(variantSpy);
}
QVariantList retrieveList()
{
return listSpy;
}
QStringList retrieveStringList()
{
return stringlistSpy;
}
QByteArray retrieveByteArray()
{
return bytearraySpy;
}
QVariantMap retrieveMap()
{
return mapSpy;
}
StringStringMap retrieveSSMap()
{
return ssmapSpy;
}
LLDateTimeMap retrieveLLDateTimeMap()
{
return lldtmapSpy;
}
MyStruct retrieveStruct()
{
return structSpy;
}
};
void newMyObjectPeer(int nInterfaces = 4)
{
QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "newMyObject");
req << nInterfaces;
QDBusMessage reply = QDBusConnection::sessionBus().call(req);
}
void registerMyObjectPeer(const QString & path, QDBusConnection::RegisterOptions options = QDBusConnection::ExportAdaptors)
{
QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "registerMyObject");
req << path;
req << (int)options;
QDBusMessage reply = QDBusConnection::sessionBus().call(req);
}
void syncPeer()
{
static int counter = 0;
QString reqId = QString::number(++counter);
// wait for the sync signal with the right ID
QEventLoop loop;
QDBusConnection con("peer");
con.connect(QString(), objectPath, interfaceName, "syncReceived",
QStringList() << reqId, QString(), &loop, SLOT(quit()));
QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "requestSync");
req << reqId;
QDBusConnection::sessionBus().send(req);
loop.exec();
}
void emitSignalPeer(const QString &interface, const QString &name, const QVariant &parameter)
{
if (parameter.isValid())
{
QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "emitSignal");
req << interface;
req << name;
req << QVariant::fromValue(QDBusVariant(parameter));
QDBusConnection::sessionBus().send(req);
}
else
{
QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "emitSignal2");
req << interface;
req << name;
QDBusConnection::sessionBus().send(req);
}
}
QString slotSpyPeer()
{
QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "slotSpyServer");
QDBusMessage reply = QDBusConnection::sessionBus().call(req);
return reply.arguments().at(0).toString();
}
QString valueSpyPeer()
{
QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "valueSpyServer");
QDBusMessage reply = QDBusConnection::sessionBus().call(req);
return reply.arguments().at(0).toString();
}
void clearValueSpyPeer()
{
QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "clearValueSpy");
QDBusMessage reply = QDBusConnection::sessionBus().call(req);
}
class tst_QDBusAbstractAdaptor: public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void cleanupTestCase();
void methodCalls_data();
void methodCalls();
void methodCallScriptable();
void signalEmissions_data();
void signalEmissions();
void sameSignalDifferentPaths();
void sameObjectDifferentPaths();
void scriptableSignalOrNot();
void overloadedSignalEmission_data();
void overloadedSignalEmission();
void readProperties();
void readPropertiesInvalidInterface();
void readPropertiesEmptyInterface_data();
void readPropertiesEmptyInterface();
void readAllProperties();
void readAllPropertiesInvalidInterface();
void readAllPropertiesEmptyInterface_data();
void readAllPropertiesEmptyInterface();
void writeProperties();
void methodCallsPeer_data();
void methodCallsPeer();
void methodCallScriptablePeer();
void signalEmissionsPeer_data();
void signalEmissionsPeer();
void sameSignalDifferentPathsPeer();
void sameObjectDifferentPathsPeer();
void scriptableSignalOrNotPeer();
void overloadedSignalEmissionPeer_data();
void overloadedSignalEmissionPeer();
void readPropertiesPeer();
void readPropertiesInvalidInterfacePeer();
void readPropertiesEmptyInterfacePeer_data();
void readPropertiesEmptyInterfacePeer();
void readAllPropertiesPeer();
void readAllPropertiesInvalidInterfacePeer();
void readAllPropertiesEmptyInterfacePeer_data();
void readAllPropertiesEmptyInterfacePeer();
void writePropertiesPeer();
void typeMatching_data();
void typeMatching();
void methodWithMoreThanOneReturnValue();
void methodWithMoreThanOneReturnValuePeer();
private:
QProcess proc;
};
class WaitForQMyServer: public QObject
{
Q_OBJECT
public:
WaitForQMyServer();
bool ok();
public Q_SLOTS:
void ownerChange(const QString &name)
{
if (name == serviceName)
loop.quit();
}
private:
QEventLoop loop;
};
WaitForQMyServer::WaitForQMyServer()
{
QDBusConnection con = QDBusConnection::sessionBus();
if (!ok()) {
connect(con.interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)),
SLOT(ownerChange(QString)));
QTimer::singleShot(2000, &loop, SLOT(quit()));
loop.exec();
}
}
bool WaitForQMyServer::ok()
{
return QDBusConnection::sessionBus().isConnected() &&
QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName);
}
void tst_QDBusAbstractAdaptor::initTestCase()
{
commonInit();
// start peer server
#ifdef Q_OS_WIN
# define EXE ".exe"
#else
# define EXE ""
#endif
proc.setProcessChannelMode(QProcess::ForwardedErrorChannel);
proc.start(QFINDTESTDATA("qmyserver/qmyserver" EXE));
QVERIFY2(proc.waitForStarted(), qPrintable(proc.errorString()));
QVERIFY(proc.waitForReadyRead());
WaitForQMyServer w;
QVERIFY(w.ok());
// get peer server address
QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "address");
QDBusMessage rpl = QDBusConnection::sessionBus().call(req);
QCOMPARE(rpl.type(), QDBusMessage::ReplyMessage);
QString address = rpl.arguments().at(0).toString();
// connect to peer server
QDBusConnection peercon = QDBusConnection::connectToPeer(address, "peer");
QVERIFY(peercon.isConnected());
QDBusMessage req2 = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "waitForConnected");
QDBusMessage rpl2 = QDBusConnection::sessionBus().call(req2);
QVERIFY2(rpl2.type() == QDBusMessage::ReplyMessage, rpl2.errorMessage().toLatin1());
}
void tst_QDBusAbstractAdaptor::cleanupTestCase()
{
QDBusMessage msg = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "quit");
QDBusConnection::sessionBus().call(msg);
proc.waitForFinished(200);
proc.close();
}
void tst_QDBusAbstractAdaptor::methodCalls_data()
{
QTest::addColumn<int>("nInterfaces");
QTest::newRow("0") << 0;
QTest::newRow("1") << 1;
QTest::newRow("2") << 2;
QTest::newRow("3") << 3;
QTest::newRow("4") << 4;
}
void tst_QDBusAbstractAdaptor::methodCalls()
{
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
//QDBusInterface emptycon.baseService(), "/", QString());
{
// must fail: no object
QDBusInterface if1(con.baseService(), "/", "local.Interface1", con);
QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage);
}
QFETCH(int, nInterfaces);
MyObject obj(nInterfaces);
con.registerObject("/", &obj);
QDBusInterface if1(con.baseService(), "/", "local.Interface1", con);
QDBusInterface if2(con.baseService(), "/", "local.Interface2", con);
QDBusInterface if3(con.baseService(), "/", "local.Interface3", con);
QDBusInterface if4(con.baseService(), "/", "local.Interface4", con);
// must fail: no such method
QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage);
if (!nInterfaces--)
return;
if (!nInterfaces--)
return;
// simple call: one such method exists
QCOMPARE(if2.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpy, "void Interface2::method()");
if (!nInterfaces--)
return;
// multiple methods in multiple interfaces, no name overlap
QCOMPARE(if1.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ErrorMessage);
QCOMPARE(if1.call(QDBus::BlockWithGui, "methodInt").type(), QDBusMessage::ErrorMessage);
QCOMPARE(if1.call(QDBus::BlockWithGui, "methodString").type(), QDBusMessage::ErrorMessage);
QCOMPARE(if2.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ErrorMessage);
QCOMPARE(if2.call(QDBus::BlockWithGui, "methodInt").type(), QDBusMessage::ErrorMessage);
QCOMPARE(if2.call(QDBus::BlockWithGui, "methodString").type(), QDBusMessage::ErrorMessage);
QCOMPARE(if3.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpy, "void Interface3::methodVoid()");
QCOMPARE(if3.call(QDBus::BlockWithGui, "methodInt", 42).type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpy, "void Interface3::methodInt(int)");
QCOMPARE(if3.call(QDBus::BlockWithGui, "methodString", QString("")).type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpy, "void Interface3::methodString(QString)");
if (!nInterfaces--)
return;
// method overloading: different interfaces
QCOMPARE(if4.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpy, "void Interface4::method()");
// method overloading: different parameters
QCOMPARE(if4.call(QDBus::BlockWithGui, "method.i", 42).type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpy, "void Interface4::method(int)");
QCOMPARE(if4.call(QDBus::BlockWithGui, "method.s", QString()).type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpy, "void Interface4::method(QString)");
}
void tst_QDBusAbstractAdaptor::methodCallScriptable()
{
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
MyObject obj(2);
con.registerObject("/", &obj);
QDBusInterface if2(con.baseService(), "/", "local.Interface2", con);
QCOMPARE(if2.call(QDBus::BlockWithGui,"scriptableMethod").type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpy, "void Interface2::scriptableMethod()");
}
static void emitSignal(MyObject *obj, const QString &iface, const QString &name,
const QVariant &parameter)
{
if (iface.endsWith('2'))
obj->if2->emitSignal(name, parameter);
else if (iface.endsWith('3'))
obj->if3->emitSignal(name, parameter);
else if (iface.endsWith('4'))
obj->if4->emitSignal(name, parameter);
else
obj->emitSignal(name, parameter);
}
void tst_QDBusAbstractAdaptor::signalEmissions_data()
{
QTest::addColumn<QString>("interface");
QTest::addColumn<QString>("name");
QTest::addColumn<QString>("signature");
QTest::addColumn<QVariant>("parameter");
QTest::newRow("Interface2.signal") << "local.Interface2" << "signal" << QString() << QVariant();
QTest::newRow("Interface3.signalVoid") << "local.Interface3" << "signalVoid" << QString() << QVariant();
QTest::newRow("Interface3.signalInt") << "local.Interface3" << "signalInt" << "i" << QVariant(1);
QTest::newRow("Interface3.signalString") << "local.Interface3" << "signalString" << "s" << QVariant("foo");
QTest::newRow("MyObject.scriptableSignalVoid") << "local.MyObject" << "scriptableSignalVoid" << QString() << QVariant();
QTest::newRow("MyObject.scriptableSignalInt") << "local.MyObject" << "scriptableSignalInt" << "i" << QVariant(1);
QTest::newRow("MyObject.nySignalString") << "local.MyObject" << "scriptableSignalString" << "s" << QVariant("foo");
}
void tst_QDBusAbstractAdaptor::signalEmissions()
{
QFETCH(QString, interface);
QFETCH(QString, name);
QFETCH(QVariant, parameter);
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
con.registerService("org.qtproject.tst_QDBusAbstractAdaptor");
MyObject obj(3);
con.registerObject("/", &obj, QDBusConnection::ExportAdaptors
| QDBusConnection::ExportScriptableSignals);
// connect all signals and emit only one
{
QDBusSignalSpy spy;
con.connect(con.baseService(), "/", "local.Interface2", "signal",
&spy, SLOT(slot(QDBusMessage)));
con.connect(con.baseService(), "/", "local.Interface3", "signalVoid",
&spy, SLOT(slot(QDBusMessage)));
con.connect(con.baseService(), "/", "local.Interface3", "signalInt",
&spy, SLOT(slot(QDBusMessage)));
con.connect(con.baseService(), "/", "local.Interface3", "signalString",
&spy, SLOT(slot(QDBusMessage)));
con.connect(con.baseService(), "/", "local.MyObject", "scriptableSignalVoid",
&spy, SLOT(slot(QDBusMessage)));
con.connect(con.baseService(), "/", "local.MyObject", "scriptableSignalInt",
&spy, SLOT(slot(QDBusMessage)));
con.connect(con.baseService(), "/", "local.MyObject", "scriptableSignalString",
&spy, SLOT(slot(QDBusMessage)));
emitSignal(&obj, interface, name, parameter);
QTRY_COMPARE(spy.count, 1);
QCOMPARE(spy.interface, interface);
QCOMPARE(spy.name, name);
QTEST(spy.signature, "signature");
QCOMPARE(spy.value, parameter);
}
// connect one signal and emit them all
{
QDBusSignalSpy spy;
con.connect(con.baseService(), "/", interface, name, &spy, SLOT(slot(QDBusMessage)));
emitSignal(&obj, "local.Interface2", "signal", QVariant());
emitSignal(&obj, "local.Interface3", "signalVoid", QVariant());
emitSignal(&obj, "local.Interface3", "signalInt", QVariant(1));
emitSignal(&obj, "local.Interface3", "signalString", QVariant("foo"));
emitSignal(&obj, "local.MyObject", "scriptableSignalVoid", QVariant());
emitSignal(&obj, "local.MyObject", "scriptableSignalInt", QVariant(1));
emitSignal(&obj, "local.MyObject", "scriptableSignalString", QVariant("foo"));
QTRY_COMPARE(spy.count, 1);
QCOMPARE(spy.interface, interface);
QCOMPARE(spy.name, name);
QTEST(spy.signature, "signature");
QCOMPARE(spy.value, parameter);
}
}
void tst_QDBusAbstractAdaptor::sameSignalDifferentPaths()
{
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
MyObject obj(2);
con.registerObject("/p1",&obj);
con.registerObject("/p2",&obj);
QDBusSignalSpy spy;
con.connect(con.baseService(), "/p1", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage)));
obj.if2->emitSignal(QString(), QVariant());
QTRY_COMPARE(spy.count, 1);
QCOMPARE(spy.interface, QString("local.Interface2"));
QCOMPARE(spy.name, QString("signal"));
QVERIFY(spy.signature.isEmpty());
// now connect the other one
spy.count = 0;
con.connect(con.baseService(), "/p2", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage)));
obj.if2->emitSignal(QString(), QVariant());
QTRY_COMPARE(spy.count, 2);
}
void tst_QDBusAbstractAdaptor::sameObjectDifferentPaths()
{
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
MyObject obj(2);
con.registerObject("/p1",&obj);
con.registerObject("/p2",&obj, { }); // don't export anything
QDBusSignalSpy spy;
con.connect(con.baseService(), "/p1", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage)));
con.connect(con.baseService(), "/p2", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage)));
obj.if2->emitSignal(QString(), QVariant());
QTRY_COMPARE(spy.count, 1);
QCOMPARE(spy.interface, QString("local.Interface2"));
QCOMPARE(spy.name, QString("signal"));
QVERIFY(spy.signature.isEmpty());
}
void tst_QDBusAbstractAdaptor::scriptableSignalOrNot()
{
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
{
MyObject obj(0);
con.registerObject("/p1",&obj, QDBusConnection::ExportScriptableSignals);
con.registerObject("/p2",&obj, { }); // don't export anything
QDBusSignalSpy spy;
con.connect(con.baseService(), "/p1", "local.MyObject", "scriptableSignalVoid", &spy, SLOT(slot(QDBusMessage)));
con.connect(con.baseService(), "/p2", "local.MyObject", "scriptableSignalVoid", &spy, SLOT(slot(QDBusMessage)));
con.connect(con.baseService(), "/p1", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage)));
con.connect(con.baseService(), "/p2", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage)));
obj.emitSignal("scriptableSignalVoid", QVariant());
obj.emitSignal("nonScriptableSignalVoid", QVariant());
QTRY_COMPARE(spy.count, 1); // only /p1 must have emitted
QCOMPARE(spy.interface, QString("local.MyObject"));
QCOMPARE(spy.name, QString("scriptableSignalVoid"));
QCOMPARE(spy.path, QString("/p1"));
QVERIFY(spy.signature.isEmpty());
}
{
MyObject obj(0);
con.registerObject("/p1",&obj, QDBusConnection::ExportScriptableSignals);
con.registerObject("/p2",&obj, QDBusConnection::ExportScriptableSignals
| QDBusConnection::ExportNonScriptableSignals);
QDBusSignalSpy spy;
con.connect(con.baseService(), "/p1", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage)));
con.connect(con.baseService(), "/p2", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage)));
obj.emitSignal("nonScriptableSignalVoid", QVariant());
QTRY_COMPARE(spy.count, 1); // only /p2 must have emitted now
QCOMPARE(spy.interface, QString("local.MyObject"));
QCOMPARE(spy.name, QString("nonScriptableSignalVoid"));
QCOMPARE(spy.path, QString("/p2"));
QVERIFY(spy.signature.isEmpty());
}
{
QDBusSignalSpy spy;
con.connect(con.baseService(), "/p1", "local.MyObject", "destroyed", &spy, SLOT(slot(QDBusMessage)));
con.connect(con.baseService(), "/p2", "local.MyObject", "destroyed", &spy, SLOT(slot(QDBusMessage)));
{
MyObject obj(0);
con.registerObject("/p1",&obj, QDBusConnection::ExportScriptableSignals);
con.registerObject("/p2",&obj, QDBusConnection::ExportScriptableSignals
| QDBusConnection::ExportNonScriptableSignals);
} // <--- QObject emits the destroyed(QObject*) signal at this point
QTest::qWait(200);
QCOMPARE(spy.count, 0);
}
}
void tst_QDBusAbstractAdaptor::overloadedSignalEmission_data()
{
QTest::addColumn<QString>("signature");
QTest::addColumn<QVariant>("parameter");
QTest::newRow("void") << QString("") << QVariant();
QTest::newRow("int") << "i" << QVariant(1);
QTest::newRow("string") << "s" << QVariant("foo");
}
void tst_QDBusAbstractAdaptor::overloadedSignalEmission()
{
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
MyObject obj;
con.registerObject("/", &obj);
QString interface = "local.Interface4";
QString name = "signal";
QFETCH(QVariant, parameter);
//QDBusInterface *if4 = new QDBusInterface(con.baseService(), "/", interface, con);
// connect all signals and emit only one
{
QDBusSignalSpy spy;
con.connect(con.baseService(), "/", "local.Interface4", "signal", "",
&spy, SLOT(slot(QDBusMessage)));
con.connect(con.baseService(), "/", "local.Interface4", "signal", "i",
&spy, SLOT(slot(QDBusMessage)));
con.connect(con.baseService(), "/", "local.Interface4", "signal", "s",
&spy, SLOT(slot(QDBusMessage)));
emitSignal(&obj, interface, name, parameter);
QTRY_COMPARE(spy.count, 1);
QCOMPARE(spy.interface, interface);
QCOMPARE(spy.name, name);
QTEST(spy.signature, "signature");
QCOMPARE(spy.value, parameter);
}
QFETCH(QString, signature);
// connect one signal and emit them all
{
QDBusSignalSpy spy;
con.connect(con.baseService(), "/", interface, name, signature, &spy, SLOT(slot(QDBusMessage)));
emitSignal(&obj, "local.Interface4", "signal", QVariant());
emitSignal(&obj, "local.Interface4", "signal", QVariant(1));
emitSignal(&obj, "local.Interface4", "signal", QVariant("foo"));
QTRY_COMPARE(spy.count, 1);
QCOMPARE(spy.interface, interface);
QCOMPARE(spy.name, name);
QTEST(spy.signature, "signature");
QCOMPARE(spy.value, parameter);
}
}
void tst_QDBusAbstractAdaptor::readProperties()
{
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
MyObject obj;
con.registerObject("/", &obj);
QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con);
for (int i = 2; i <= 4; ++i) {
QString name = QString("Interface%1").arg(i);
for (int j = 1; j <= 2; ++j) {
QString propname = QString("prop%1").arg(j);
QDBusReply<QVariant> reply =
properties.call(QDBus::BlockWithGui, "Get", "local." + name, propname);
QVariant value = reply;
QCOMPARE(value.userType(), int(QMetaType::QString));
QCOMPARE(value.toString(), QString("QString %1::%2() const").arg(name, propname));
}
}
}
void tst_QDBusAbstractAdaptor::readPropertiesInvalidInterface()
{
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
MyObject obj;
con.registerObject("/", &obj);
QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con);
// test an invalid interface:
QDBusReply<QVariant> reply = properties.call(QDBus::BlockWithGui, "Get", "local.DoesntExist", "prop1");
QVERIFY(!reply.isValid());
}
void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterface_data()
{
QTest::addColumn<QVariantMap>("expectedProperties");
QTest::addColumn<bool>("existing");
QVariantMap expectedProperties;
expectedProperties["prop1"] = QVariant();
expectedProperties["prop2"] = QVariant();
expectedProperties["interface3prop"] = "QString Interface3::interface3prop() const";
expectedProperties["interface4prop"] = "QString Interface4::interface4prop() const";
QTest::newRow("existing") << expectedProperties << true;
expectedProperties.clear();
expectedProperties["prop5"] = QVariant();
expectedProperties["foobar"] = QVariant();
QTest::newRow("non-existing") << expectedProperties << false;
}
void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterface()
{
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
MyObject obj;
con.registerObject("/", &obj);
QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con);
QFETCH(QVariantMap, expectedProperties);
QFETCH(bool, existing);
QVariantMap::ConstIterator it = expectedProperties.constBegin();
for ( ; it != expectedProperties.constEnd(); ++it) {
QDBusReply<QVariant> reply = properties.call(QDBus::BlockWithGui, "Get", "", it.key());
if (existing) {
QVERIFY2(reply.isValid(), qPrintable(it.key()));
} else {
QVERIFY2(!reply.isValid(), qPrintable(it.key()));
continue;
}
QCOMPARE(reply.value().userType(), int(QMetaType::QString));
if (it.value().isValid())
QCOMPARE(reply.value().toString(), it.value().toString());
}
}
void tst_QDBusAbstractAdaptor::readAllProperties()
{
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
MyObject obj;
con.registerObject("/", &obj);
QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con);
for (int i = 2; i <= 4; ++i) {
QString name = QString("Interface%1").arg(i);
QDBusReply<QVariantMap> reply =
properties.call(QDBus::BlockWithGui, "GetAll", "local." + name);
for (int j = 1; j <= 2; ++j) {
QString propname = QString("prop%1").arg(j);
QVERIFY2(reply.value().contains(propname),
qPrintable(propname + " on " + name));
QVariant value = reply.value().value(propname);
QCOMPARE(value.userType(), int(QMetaType::QString));
QCOMPARE(value.toString(), QString("QString %1::%2() const").arg(name, propname));
}
}
}
void tst_QDBusAbstractAdaptor::readAllPropertiesInvalidInterface()
{
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
MyObject obj;
con.registerObject("/", &obj);
QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con);
// test an invalid interface:
QDBusReply<QVariantMap> reply = properties.call(QDBus::BlockWithGui, "GetAll", "local.DoesntExist");
QVERIFY(!reply.isValid());
}
void tst_QDBusAbstractAdaptor::readAllPropertiesEmptyInterface_data()
{
readPropertiesEmptyInterface_data();
}
void tst_QDBusAbstractAdaptor::readAllPropertiesEmptyInterface()
{
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
MyObject obj;
con.registerObject("/", &obj);
QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con);
QDBusReply<QVariantMap> reply = properties.call(QDBus::BlockWithGui, "GetAll", "");
QVERIFY(reply.isValid());
QVariantMap allprops = reply;
QFETCH(QVariantMap, expectedProperties);
QFETCH(bool, existing);
QVariantMap::ConstIterator it = expectedProperties.constBegin();
if (existing) {
for ( ; it != expectedProperties.constEnd(); ++it) {
QVERIFY2(allprops.contains(it.key()), qPrintable(it.key()));
QVariant propvalue = allprops.value(it.key());
QVERIFY2(!propvalue.isNull(), qPrintable(it.key()));
QVERIFY2(propvalue.isValid(), qPrintable(it.key()));
QString stringvalue = propvalue.toString();
QVERIFY2(!stringvalue.isEmpty(), qPrintable(it.key()));
if (it.value().isValid())
QCOMPARE(stringvalue, it.value().toString());
// remove this property from the map
allprops.remove(it.key());
}
QVERIFY2(allprops.isEmpty(),
qPrintable(QStringList(allprops.keys()).join(' ')));
} else {
for ( ; it != expectedProperties.constEnd(); ++it)
QVERIFY2(!allprops.contains(it.key()), qPrintable(it.key()));
}
}
void tst_QDBusAbstractAdaptor::writeProperties()
{
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
MyObject obj;
con.registerObject("/", &obj);
QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con);
for (int i = 2; i <= 4; ++i) {
QString name = QString("Interface%1").arg(i);
valueSpy.clear();
properties.call(QDBus::BlockWithGui, "Set", "local." + name, QString("prop1"),
QVariant::fromValue(QDBusVariant(name)));
QVERIFY(valueSpy.isEmpty()); // call mustn't have succeeded
properties.call(QDBus::BlockWithGui, "Set", "local." + name, QString("prop2"),
QVariant::fromValue(QDBusVariant(name)));
QCOMPARE(valueSpy, name);
QCOMPARE(QString(slotSpy), QString("void %1::setProp2(const QString &)").arg(name));
}
}
void tst_QDBusAbstractAdaptor::methodCallsPeer_data()
{
methodCalls_data();
}
void tst_QDBusAbstractAdaptor::methodCallsPeer()
{
QSKIP("Test is currently too flaky (QTBUG-66223)");
if (QSysInfo::productType().compare("opensuse", Qt::CaseInsensitive) == 0
&& QSysInfo::productVersion() == QLatin1String("42.1")
&& qgetenv("QTEST_ENVIRONMENT").split(' ').contains("ci")) {
QSKIP("This test is occasionally hanging in the CI");
}
QDBusConnection con("peer");
QVERIFY(con.isConnected());
{
// must fail: no object
QDBusInterface if1(QString(), "/", "local.Interface1", con);
QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage);
}
QFETCH(int, nInterfaces);
newMyObjectPeer(nInterfaces);
registerMyObjectPeer("/");
QDBusInterface if1(QString(), "/", "local.Interface1", con);
QDBusInterface if2(QString(), "/", "local.Interface2", con);
QDBusInterface if3(QString(), "/", "local.Interface3", con);
QDBusInterface if4(QString(), "/", "local.Interface4", con);
// must fail: no such method
QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage);
if (!nInterfaces--)
return;
if (!nInterfaces--)
return;
// simple call: one such method exists
QCOMPARE(if2.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpyPeer(), QStringLiteral("void Interface2::method()"));
if (!nInterfaces--)
return;
// multiple methods in multiple interfaces, no name overlap
QCOMPARE(if1.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ErrorMessage);
QCOMPARE(if1.call(QDBus::BlockWithGui, "methodInt").type(), QDBusMessage::ErrorMessage);
QCOMPARE(if1.call(QDBus::BlockWithGui, "methodString").type(), QDBusMessage::ErrorMessage);
QCOMPARE(if2.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ErrorMessage);
QCOMPARE(if2.call(QDBus::BlockWithGui, "methodInt").type(), QDBusMessage::ErrorMessage);
QCOMPARE(if2.call(QDBus::BlockWithGui, "methodString").type(), QDBusMessage::ErrorMessage);
QCOMPARE(if3.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpyPeer(), QStringLiteral("void Interface3::methodVoid()"));
QCOMPARE(if3.call(QDBus::BlockWithGui, "methodInt", 42).type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpyPeer(), QStringLiteral("void Interface3::methodInt(int)"));
QCOMPARE(if3.call(QDBus::BlockWithGui, "methodString", QString("")).type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpyPeer(), QStringLiteral("void Interface3::methodString(QString)"));
if (!nInterfaces--)
return;
// method overloading: different interfaces
QCOMPARE(if4.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpyPeer(), QStringLiteral("void Interface4::method()"));
// method overloading: different parameters
QCOMPARE(if4.call(QDBus::BlockWithGui, "method.i", 42).type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpyPeer(), QStringLiteral("void Interface4::method(int)"));
QCOMPARE(if4.call(QDBus::BlockWithGui, "method.s", QString()).type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpyPeer(), QStringLiteral("void Interface4::method(QString)"));
}
void tst_QDBusAbstractAdaptor::methodCallScriptablePeer()
{
QSKIP("Test is currently too flaky (QTBUG-66223)");
QDBusConnection con("peer");
QVERIFY(con.isConnected());
newMyObjectPeer(2);
registerMyObjectPeer("/");
QDBusInterface if2(QString(), "/", "local.Interface2", con);
QCOMPARE(if2.call(QDBus::BlockWithGui,"scriptableMethod").type(), QDBusMessage::ReplyMessage);
QCOMPARE(slotSpyPeer(), QStringLiteral("void Interface2::scriptableMethod()"));
}
void tst_QDBusAbstractAdaptor::signalEmissionsPeer_data()
{
signalEmissions_data();
}
void tst_QDBusAbstractAdaptor::signalEmissionsPeer()
{
QSKIP("Test is currently too flaky (QTBUG-66223)");
QFETCH(QString, interface);
QFETCH(QString, name);
QFETCH(QVariant, parameter);
QDBusConnection con("peer");
QVERIFY(con.isConnected());
newMyObjectPeer(3);
registerMyObjectPeer("/", QDBusConnection::ExportAdaptors
| QDBusConnection::ExportScriptableSignals);
// connect all signals and emit only one
{
syncPeer();
QDBusSignalSpy spy;
con.connect(QString(), "/", "local.Interface2", "signal",
&spy, SLOT(slot(QDBusMessage)));
con.connect(QString(), "/", "local.Interface3", "signalVoid",
&spy, SLOT(slot(QDBusMessage)));
con.connect(QString(), "/", "local.Interface3", "signalInt",
&spy, SLOT(slot(QDBusMessage)));
con.connect(QString(), "/", "local.Interface3", "signalString",
&spy, SLOT(slot(QDBusMessage)));
con.connect(QString(), "/", "local.MyObject", "scriptableSignalVoid",
&spy, SLOT(slot(QDBusMessage)));
con.connect(QString(), "/", "local.MyObject", "scriptableSignalInt",
&spy, SLOT(slot(QDBusMessage)));
con.connect(QString(), "/", "local.MyObject", "scriptableSignalString",
&spy, SLOT(slot(QDBusMessage)));
emitSignalPeer(interface, name, parameter);
QTRY_COMPARE(spy.count, 1);
QCOMPARE(spy.interface, interface);
QCOMPARE(spy.name, name);
QTEST(spy.signature, "signature");
QCOMPARE(spy.value, parameter);
}
// connect one signal and emit them all
{
syncPeer();
QDBusSignalSpy spy;
con.connect(QString(), "/", interface, name, &spy, SLOT(slot(QDBusMessage)));
emitSignalPeer("local.Interface2", "signal", QVariant());
emitSignalPeer("local.Interface3", "signalVoid", QVariant());
emitSignalPeer("local.Interface3", "signalInt", QVariant(1));
emitSignalPeer("local.Interface3", "signalString", QVariant("foo"));
emitSignalPeer("local.MyObject", "scriptableSignalVoid", QVariant());
emitSignalPeer("local.MyObject", "scriptableSignalInt", QVariant(1));
emitSignalPeer("local.MyObject", "scriptableSignalString", QVariant("foo"));
QTRY_COMPARE(spy.count, 1);
QCOMPARE(spy.interface, interface);
QCOMPARE(spy.name, name);
QTEST(spy.signature, "signature");
QCOMPARE(spy.value, parameter);
}
}
void tst_QDBusAbstractAdaptor::sameSignalDifferentPathsPeer()
{
QSKIP("Test is currently too flaky (QTBUG-66223)");
QDBusConnection con("peer");
QVERIFY(con.isConnected());
newMyObjectPeer(2);
registerMyObjectPeer("/p1");
registerMyObjectPeer("/p2");
syncPeer();
QDBusSignalSpy spy;
con.connect(QString(), "/p1", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage)));
emitSignalPeer("local.Interface2", QString(), QVariant());
QTRY_COMPARE(spy.count, 1);
QCOMPARE(spy.interface, QString("local.Interface2"));
QCOMPARE(spy.name, QString("signal"));
QVERIFY(spy.signature.isEmpty());
// now connect the other one
spy.count = 0;
con.connect(QString(), "/p2", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage)));
emitSignalPeer("local.Interface2", QString(), QVariant());
QTRY_COMPARE(spy.count, 2);
}
void tst_QDBusAbstractAdaptor::sameObjectDifferentPathsPeer()
{
QSKIP("Test is currently too flaky (QTBUG-66223)");
QDBusConnection con("peer");
QVERIFY(con.isConnected());
newMyObjectPeer(2);
registerMyObjectPeer("/p1");
registerMyObjectPeer("/p2", { }); // don't export anything
syncPeer();
QDBusSignalSpy spy;
con.connect(QString(), "/p1", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage)));
con.connect(QString(), "/p2", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage)));
emitSignalPeer("local.Interface2", QString(), QVariant());
QTRY_COMPARE(spy.count, 1);
QCOMPARE(spy.interface, QString("local.Interface2"));
QCOMPARE(spy.name, QString("signal"));
QVERIFY(spy.signature.isEmpty());
}
void tst_QDBusAbstractAdaptor::scriptableSignalOrNotPeer()
{
QSKIP("Test is currently too flaky (QTBUG-66223)");
QDBusConnection con("peer");;
QVERIFY(con.isConnected());
{
newMyObjectPeer(0);
registerMyObjectPeer("/p1", QDBusConnection::ExportScriptableSignals);
registerMyObjectPeer("/p2", { }); // don't export anything
syncPeer();
QDBusSignalSpy spy;
con.connect(QString(), "/p1", "local.MyObject", "scriptableSignalVoid", &spy, SLOT(slot(QDBusMessage)));
con.connect(QString(), "/p2", "local.MyObject", "scriptableSignalVoid", &spy, SLOT(slot(QDBusMessage)));
con.connect(QString(), "/p1", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage)));
con.connect(QString(), "/p2", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage)));
emitSignalPeer("local.MyObject", "scriptableSignalVoid", QVariant());
emitSignalPeer("local.MyObject", "nonScriptableSignalVoid", QVariant());
QTRY_COMPARE(spy.count, 1); // only /p1 must have emitted
QCOMPARE(spy.interface, QString("local.MyObject"));
QCOMPARE(spy.name, QString("scriptableSignalVoid"));
QCOMPARE(spy.path, QString("/p1"));
QVERIFY(spy.signature.isEmpty());
}
{
newMyObjectPeer(0);
registerMyObjectPeer("/p1", QDBusConnection::ExportScriptableSignals);
registerMyObjectPeer("/p2", QDBusConnection::ExportScriptableSignals
| QDBusConnection::ExportNonScriptableSignals);
syncPeer();
QDBusSignalSpy spy;
con.connect(QString(), "/p1", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage)));
con.connect(QString(), "/p2", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage)));
emitSignalPeer("local.MyObject", "nonScriptableSignalVoid", QVariant());
QTRY_COMPARE(spy.count, 1); // only /p2 must have emitted now
QCOMPARE(spy.interface, QString("local.MyObject"));
QCOMPARE(spy.name, QString("nonScriptableSignalVoid"));
QCOMPARE(spy.path, QString("/p2"));
QVERIFY(spy.signature.isEmpty());
}
{
QDBusSignalSpy spy;
con.connect(QString(), "/p1", "local.MyObject", "destroyed", &spy, SLOT(slot(QDBusMessage)));
con.connect(QString(), "/p2", "local.MyObject", "destroyed", &spy, SLOT(slot(QDBusMessage)));
{
newMyObjectPeer(0);
registerMyObjectPeer("/p1", QDBusConnection::ExportScriptableSignals);
registerMyObjectPeer("/p2", QDBusConnection::ExportScriptableSignals
| QDBusConnection::ExportNonScriptableSignals);
} // <--- QObject emits the destroyed(QObject*) signal at this point
QTest::qWait(200);
QCOMPARE(spy.count, 0);
}
}
void tst_QDBusAbstractAdaptor::overloadedSignalEmissionPeer_data()
{
overloadedSignalEmission_data();
}
void tst_QDBusAbstractAdaptor::overloadedSignalEmissionPeer()
{
QSKIP("Test is currently too flaky (QTBUG-66223)");
QDBusConnection con("peer");
QVERIFY(con.isConnected());
newMyObjectPeer();
registerMyObjectPeer("/");
QString interface = "local.Interface4";
QString name = "signal";
QFETCH(QVariant, parameter);
//QDBusInterface *if4 = new QDBusInterface(QString(), "/", interface, con);
// connect all signals and emit only one
{
syncPeer();
QDBusSignalSpy spy;
con.connect(QString(), "/", "local.Interface4", "signal", "",
&spy, SLOT(slot(QDBusMessage)));
con.connect(QString(), "/", "local.Interface4", "signal", "i",
&spy, SLOT(slot(QDBusMessage)));
con.connect(QString(), "/", "local.Interface4", "signal", "s",
&spy, SLOT(slot(QDBusMessage)));
emitSignalPeer(interface, name, parameter);
QTRY_COMPARE(spy.count, 1);
QCOMPARE(spy.interface, interface);
QCOMPARE(spy.name, name);
QTEST(spy.signature, "signature");
QCOMPARE(spy.value, parameter);
}
QFETCH(QString, signature);
// connect one signal and emit them all
{
syncPeer();
QDBusSignalSpy spy;
con.connect(QString(), "/", interface, name, signature, &spy, SLOT(slot(QDBusMessage)));
emitSignalPeer("local.Interface4", "signal", QVariant());
emitSignalPeer("local.Interface4", "signal", QVariant(1));
emitSignalPeer("local.Interface4", "signal", QVariant("foo"));
QTRY_COMPARE(spy.count, 1);
QCOMPARE(spy.interface, interface);
QCOMPARE(spy.name, name);
QTEST(spy.signature, "signature");
QCOMPARE(spy.value, parameter);
}
}
void tst_QDBusAbstractAdaptor::readPropertiesPeer()
{
QSKIP("Test is currently too flaky (QTBUG-66223)");
QDBusConnection con("peer");
QVERIFY(con.isConnected());
newMyObjectPeer();
registerMyObjectPeer("/");
QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con);
for (int i = 2; i <= 4; ++i) {
QString name = QString("Interface%1").arg(i);
for (int j = 1; j <= 2; ++j) {
QString propname = QString("prop%1").arg(j);
QDBusReply<QVariant> reply =
properties.call(QDBus::BlockWithGui, "Get", "local." + name, propname);
QVariant value = reply;
QCOMPARE(value.userType(), int(QMetaType::QString));
QCOMPARE(value.toString(), QString("QString %1::%2() const").arg(name, propname));
}
}
}
void tst_QDBusAbstractAdaptor::readPropertiesInvalidInterfacePeer()
{
QSKIP("Test is currently too flaky (QTBUG-66223)");
QDBusConnection con("peer");
QVERIFY(con.isConnected());
newMyObjectPeer();
registerMyObjectPeer("/");
QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con);
// test an invalid interface:
QDBusReply<QVariant> reply = properties.call(QDBus::BlockWithGui, "Get", "local.DoesntExist", "prop1");
QVERIFY(!reply.isValid());
}
void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterfacePeer_data()
{
readPropertiesEmptyInterface_data();
}
void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterfacePeer()
{
QSKIP("Test is currently too flaky (QTBUG-66223)");
QDBusConnection con("peer");
QVERIFY(con.isConnected());
newMyObjectPeer();
registerMyObjectPeer("/");
QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con);
QFETCH(QVariantMap, expectedProperties);
QFETCH(bool, existing);
QVariantMap::ConstIterator it = expectedProperties.constBegin();
for ( ; it != expectedProperties.constEnd(); ++it) {
QDBusReply<QVariant> reply = properties.call(QDBus::BlockWithGui, "Get", "", it.key());
if (existing) {
QVERIFY2(reply.isValid(), qPrintable(it.key()));
} else {
QVERIFY2(!reply.isValid(), qPrintable(it.key()));
continue;
}
QCOMPARE(int(reply.value().userType()), int(QMetaType::QString));
if (it.value().isValid())
QCOMPARE(reply.value().toString(), it.value().toString());
}
}
void tst_QDBusAbstractAdaptor::readAllPropertiesPeer()
{
QSKIP("Test is currently too flaky (QTBUG-66223)");
QDBusConnection con("peer");
QVERIFY(con.isConnected());
newMyObjectPeer();
registerMyObjectPeer("/");
QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con);
for (int i = 2; i <= 4; ++i) {
QString name = QString("Interface%1").arg(i);
QDBusReply<QVariantMap> reply =
properties.call(QDBus::BlockWithGui, "GetAll", "local." + name);
for (int j = 1; j <= 2; ++j) {
QString propname = QString("prop%1").arg(j);
QVERIFY2(reply.value().contains(propname),
qPrintable(propname + " on " + name));
QVariant value = reply.value().value(propname);
QCOMPARE(value.userType(), int(QMetaType::QString));
QCOMPARE(value.toString(), QString("QString %1::%2() const").arg(name, propname));
}
}
}
void tst_QDBusAbstractAdaptor::readAllPropertiesInvalidInterfacePeer()
{
QSKIP("Test is currently too flaky (QTBUG-66223)");
QDBusConnection con("peer");
QVERIFY(con.isConnected());
newMyObjectPeer();
registerMyObjectPeer("/");
QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con);
// test an invalid interface:
QDBusReply<QVariantMap> reply = properties.call(QDBus::BlockWithGui, "GetAll", "local.DoesntExist");
QVERIFY(!reply.isValid());
}
void tst_QDBusAbstractAdaptor::readAllPropertiesEmptyInterfacePeer_data()
{
readAllPropertiesEmptyInterface_data();
}
void tst_QDBusAbstractAdaptor::readAllPropertiesEmptyInterfacePeer()
{
QDBusConnection con("peer");
QVERIFY(con.isConnected());
newMyObjectPeer();
registerMyObjectPeer("/");
QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con);
QDBusReply<QVariantMap> reply = properties.call(QDBus::BlockWithGui, "GetAll", "");
QVERIFY(reply.isValid());
QVariantMap allprops = reply;
QFETCH(QVariantMap, expectedProperties);
QFETCH(bool, existing);
QVariantMap::ConstIterator it = expectedProperties.constBegin();
if (existing) {
for ( ; it != expectedProperties.constEnd(); ++it) {
QVERIFY2(allprops.contains(it.key()), qPrintable(it.key()));
QVariant propvalue = allprops.value(it.key());
QVERIFY2(!propvalue.isNull(), qPrintable(it.key()));
QVERIFY2(propvalue.isValid(), qPrintable(it.key()));
QString stringvalue = propvalue.toString();
QVERIFY2(!stringvalue.isEmpty(), qPrintable(it.key()));
if (it.value().isValid())
QCOMPARE(stringvalue, it.value().toString());
// remove this property from the map
allprops.remove(it.key());
}
QVERIFY2(allprops.isEmpty(),
qPrintable(QStringList(allprops.keys()).join(' ')));
} else {
for ( ; it != expectedProperties.constEnd(); ++it)
QVERIFY2(!allprops.contains(it.key()), qPrintable(it.key()));
}
}
void tst_QDBusAbstractAdaptor::writePropertiesPeer()
{
QSKIP("Test is currently too flaky (QTBUG-66223)");
QDBusConnection con("peer");
QVERIFY(con.isConnected());
newMyObjectPeer();
registerMyObjectPeer("/");
QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con);
for (int i = 2; i <= 4; ++i) {
QString name = QString("Interface%1").arg(i);
clearValueSpyPeer();
properties.call(QDBus::BlockWithGui, "Set", "local." + name, QString("prop1"),
QVariant::fromValue(QDBusVariant(name)));
QVERIFY(valueSpyPeer().isEmpty()); // call mustn't have succeeded
properties.call(QDBus::BlockWithGui, "Set", "local." + name, QString("prop2"),
QVariant::fromValue(QDBusVariant(name)));
QCOMPARE(valueSpyPeer(), name);
QCOMPARE(QString(slotSpyPeer()), QString("void %1::setProp2(const QString &)").arg(name));
}
}
#if 0
void tst_QDBusAbstractAdaptor::adaptorIntrospection_data()
{
methodCalls_data();
}
void tst_QDBusAbstractAdaptor::adaptorIntrospection()
{
QDBusConnection con = QDBus::sessionBus();
QVERIFY(con.isConnected());
QObject obj;
con.registerObject("/", &obj);
QFETCH(int, nInterfaces);
switch (nInterfaces)
{
case 4:
new Interface4(&obj);
case 3:
new Interface3(&obj);
case 2:
new Interface2(&obj);
case 1:
new Interface1(&obj);
}
QDBusObject dobj = con.findObject(con.baseService(), "/");
QVERIFY(dobj.isValid());
QString xml = dobj.introspect();
QVERIFY(!xml.isEmpty());
QStringList interfaces = dobj.interfaces();
QCOMPARE(interfaces.count(), nInterfaces + 2);
switch (nInterfaces)
{
case 4: {
QVERIFY(interfaces.contains("local.Interface4"));
QDBusInterface iface(dobj, "local.Interface4");
QCOMPARE(iface.methodData(), Interface4::methodData);
QCOMPARE(iface.signalData(), Interface4::signalData);
QCOMPARE(iface.propertyData(), Interface4::propertyData);
}
case 3: {
QVERIFY(interfaces.contains("local.Interface3"));
QDBusInterface iface(dobj, "local.Interface3");
QCOMPARE(iface.methodData(), Interface3::methodData);
QCOMPARE(iface.signalData(), Interface3::signalData);
QCOMPARE(iface.propertyData(), Interface3::propertyData);
}
case 2: {
QVERIFY(interfaces.contains("local.Interface2"));
QDBusInterface iface(dobj, "local.Interface2");
QCOMPARE(iface.methodData(), Interface2::methodData);
QCOMPARE(iface.signalData(), Interface2::signalData);
QCOMPARE(iface.propertyData(), Interface2::propertyData);
}
case 1: {
QVERIFY(interfaces.contains("local.Interface1"));
QDBusInterface iface(dobj, "local.Interface1");
QCOMPARE(iface.methodData(), Interface1::methodData);
QCOMPARE(iface.signalData(), Interface1::signalData);
QCOMPARE(iface.propertyData(), Interface1::propertyData);
}
}
}
void tst_QDBusAbstractAdaptor::objectTreeIntrospection()
{
QDBusConnection con = QDBus::sessionBus();
QVERIFY(con.isConnected());
{
QDBusObject dobj = con.findObject(con.baseService(), "/");
QString xml = dobj.introspect();
QDBusIntrospection::Object tree =
QDBusIntrospection::parseObject(xml);
QVERIFY(tree.childObjects.isEmpty());
}
QObject root;
con.registerObject("/", &root);
{
QDBusObject dobj = con.findObject(con.baseService(), "/");
QString xml = dobj.introspect();
QDBusIntrospection::Object tree =
QDBusIntrospection::parseObject(xml);
QVERIFY(tree.childObjects.isEmpty());
}
QObject p1;
con.registerObject("/p1", &p1);
{
QDBusObject dobj = con.findObject(con.baseService(), "/");
QString xml = dobj.introspect();
QDBusIntrospection::Object tree =
QDBusIntrospection::parseObject(xml);
QVERIFY(tree.childObjects.contains("p1"));
}
con.unregisterObject("/");
{
QDBusObject dobj = con.findObject(con.baseService(), "/");
QString xml = dobj.introspect();
QDBusIntrospection::Object tree =
QDBusIntrospection::parseObject(xml);
QVERIFY(tree.childObjects.contains("p1"));
}
con.registerObject("/p1/q/r", &root);
{
QDBusObject dobj = con.findObject(con.baseService(), "/p1");
QString xml = dobj.introspect();
QDBusIntrospection::Object tree =
QDBusIntrospection::parseObject(xml);
QVERIFY(tree.childObjects.contains("q"));
}
{
QDBusObject dobj = con.findObject(con.baseService(), "/p1/q");
QString xml = dobj.introspect();
QDBusIntrospection::Object tree =
QDBusIntrospection::parseObject(xml);
QVERIFY(tree.childObjects.contains("r"));
}
con.unregisterObject("/p1", QDBusConnection::UnregisterTree);
{
QDBusObject dobj = con.findObject(con.baseService(), "/");
QString xml = dobj.introspect();
QDBusIntrospection::Object tree =
QDBusIntrospection::parseObject(xml);
QVERIFY(tree.childObjects.isEmpty());
}
QObject p2;
con.registerObject("/p2", &p2, QDBusConnection::ExportChildObjects);
{
QDBusObject dobj = con.findObject(con.baseService(), "/");
QString xml = dobj.introspect();
QDBusIntrospection::Object tree =
QDBusIntrospection::parseObject(xml);
QVERIFY(!tree.childObjects.contains("p1"));
QVERIFY(tree.childObjects.contains("p2"));
}
QObject q;
q.setParent(&p2);
{
QDBusObject dobj = con.findObject(con.baseService(), "/p2");
QString xml = dobj.introspect();
QDBusIntrospection::Object tree =
QDBusIntrospection::parseObject(xml);
QVERIFY(!tree.childObjects.contains("q"));
}
q.setObjectName("q");
{
QDBusObject dobj = con.findObject(con.baseService(), "/p2");
QString xml = dobj.introspect();
QDBusIntrospection::Object tree =
QDBusIntrospection::parseObject(xml);
QVERIFY(tree.childObjects.contains("q"));
}
q.setParent(0);
{
QDBusObject dobj = con.findObject(con.baseService(), "/p2");
QString xml = dobj.introspect();
QDBusIntrospection::Object tree =
QDBusIntrospection::parseObject(xml);
QVERIFY(!tree.childObjects.contains("q"));
}
}
#endif
void tst_QDBusAbstractAdaptor::typeMatching_data()
{
QTest::addColumn<QString>("basename");
QTest::addColumn<QString>("signature");
QTest::addColumn<QVariant>("value");
QTest::newRow("bool") << "Bool" << "b" << QVariant(true);
QTest::newRow("byte") << "UChar" << "y" << QVariant::fromValue(uchar(42));
QTest::newRow("short") << "Short" << "n" << QVariant::fromValue(short(-43));
QTest::newRow("ushort") << "UShort" << "q" << QVariant::fromValue(ushort(44));
QTest::newRow("int") << "Int" << "i" << QVariant(42);
QTest::newRow("uint") << "UInt" << "u" << QVariant(42U);
QTest::newRow("qlonglong") << "LongLong" << "x" << QVariant(Q_INT64_C(42));
QTest::newRow("qulonglong") << "ULongLong" << "t" << QVariant(Q_UINT64_C(42));
QTest::newRow("double") << "Double" << "d" << QVariant(2.5);
QTest::newRow("string") << "String" << "s" << QVariant("Hello, World!");
QTest::newRow("variant") << "Variant" << "v" << QVariant::fromValue(QDBusVariant("Hello again!"));
QTest::newRow("list") << "List" << "av" << QVariant(QVariantList()
<< 42
<< QString("foo")
<< QByteArray("bar")
<< QVariant::fromValue(QDBusVariant(QString("baz"))));
QTest::newRow("stringlist") << "StringList" << "as" << QVariant(QStringList() << "Hello" << "world");
QTest::newRow("bytearray") << "ByteArray" << "ay" << QVariant(QByteArray("foo"));
QVariantMap map;
map["one"] = 1; // int
map["The answer to life, the Universe and everything"] = 42u; // uint
map["In the beginning..."] = QString("There was nothing"); // string
map["but Unix came and said"] = QByteArray("\"Hello, World\""); // bytearray
map["two"] = QVariant::fromValue(short(2)); // short
QTest::newRow("map") << "Map" << "a{sv}" << QVariant(map);
StringStringMap ssmap;
ssmap["a"] = "A";
ssmap["A"] = "a";
QTest::newRow("ssmap") << "SSMap" << "a{ss}" << QVariant::fromValue(ssmap);
LLDateTimeMap lldtmap;
lldtmap[-1] = QDateTime();
QDateTime now = QDateTime::currentDateTime();
lldtmap[now.toSecsSinceEpoch()] = now; // array of struct of int64 and struct of 3 ints and struct of 4 ints and int
QTest::newRow("lldtmap") << "LLDateTimeMap" << "a{x((iii)(iiii)i)}" << QVariant::fromValue(lldtmap);
MyStruct s;
s.i = 42;
s.s = "A value";
QTest::newRow("struct") << "Struct" << "(is)" << QVariant::fromValue(s);
}
void tst_QDBusAbstractAdaptor::typeMatching()
{
QObject obj;
new TypesInterface(&obj);
QDBusConnection con = QDBusConnection::sessionBus();
con.registerObject("/types", &obj);
QFETCH(QString, basename);
QFETCH(QString, signature);
QFETCH(QVariant, value);
QDBusMessage reply;
QDBusInterface iface(con.baseService(), "/types", "local.TypesInterface", con);
reply = iface.callWithArgumentList(QDBus::BlockWithGui, "method" + basename,
QVariantList() << value);
QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
reply = iface.call(QDBus::BlockWithGui, "retrieve" + basename);
QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
QCOMPARE(reply.arguments().size(), 1);
QVERIFY(compare(reply.arguments().at(0), value));
}
void tst_QDBusAbstractAdaptor::methodWithMoreThanOneReturnValue()
{
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
MyObject obj;
con.registerObject("/", &obj);
QString testString = "This is a test string.";
QDBusInterface remote(con.baseService(), "/", "local.Interface3", con);
QDBusMessage reply = remote.call(QDBus::BlockWithGui, "methodStringString", testString);
QCOMPARE(reply.arguments().size(), 2);
QDBusReply<int> intreply = reply;
QVERIFY(intreply.isValid());
QCOMPARE(intreply.value(), 42);
QCOMPARE(reply.arguments().at(1).userType(), int(QMetaType::QString));
QCOMPARE(qdbus_cast<QString>(reply.arguments().at(1)), testString);
}
void tst_QDBusAbstractAdaptor::methodWithMoreThanOneReturnValuePeer()
{
QSKIP("Test is currently too flaky (QTBUG-66223)");
QDBusConnection con("peer");
QVERIFY(con.isConnected());
newMyObjectPeer();
registerMyObjectPeer("/");
QString testString = "This is a test string.";
QDBusInterface remote(QString(), "/", "local.Interface3", con);
QDBusMessage reply = remote.call(QDBus::BlockWithGui, "methodStringString", testString);
QCOMPARE(reply.arguments().size(), 2);
QDBusReply<int> intreply = reply;
QVERIFY(intreply.isValid());
QCOMPARE(intreply.value(), 42);
QCOMPARE(reply.arguments().at(1).userType(), int(QMetaType::QString));
QCOMPARE(qdbus_cast<QString>(reply.arguments().at(1)), testString);
}
QTEST_MAIN(tst_QDBusAbstractAdaptor)
#include "tst_qdbusabstractadaptor.moc"