350a64196f
Use QTRY_COMPARE instead of a wait followed by QCOMPARE. Unless the condition doesn't change and the wait provides the opportunity for things to go wrong. Task-number: QTBUG-63992 Change-Id: I13474a45f1f4df9d77a418729a5748235ae0dd1a Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> Reviewed-by: Gatis Paeglis <gatis.paeglis@qt.io>
1919 lines
64 KiB
C++
1919 lines
64 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
** Copyright (C) 2016 Intel Corporation.
|
|
** Contact: https://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the test suite of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 3 as published by the Free Software
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
** included in the packaging of this file. Please review the following
|
|
** information to ensure the GNU General Public License requirements will
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
#include <qcoreapplication.h>
|
|
#include <qdebug.h>
|
|
|
|
#include <QtTest/QtTest>
|
|
|
|
#include <QtDBus>
|
|
|
|
#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 ¶meter)
|
|
{
|
|
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 ¶meter)
|
|
{
|
|
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, 0); // 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, 0); // 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(QVariant::String));
|
|
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(int(reply.value().type()), int(QVariant::String));
|
|
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(QVariant::String));
|
|
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", 0); // 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", 0); // 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(QVariant::String));
|
|
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().type()), int(QVariant::String));
|
|
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(QVariant::String));
|
|
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().count(), 1);
|
|
|
|
const QVariant &retval = reply.arguments().at(0);
|
|
QVERIFY(compare(retval, 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().count(), 2);
|
|
|
|
QDBusReply<int> intreply = reply;
|
|
QVERIFY(intreply.isValid());
|
|
QCOMPARE(intreply.value(), 42);
|
|
|
|
QCOMPARE(reply.arguments().at(1).userType(), int(QVariant::String));
|
|
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().count(), 2);
|
|
|
|
QDBusReply<int> intreply = reply;
|
|
QVERIFY(intreply.isValid());
|
|
QCOMPARE(intreply.value(), 42);
|
|
|
|
QCOMPARE(reply.arguments().at(1).userType(), int(QVariant::String));
|
|
QCOMPARE(qdbus_cast<QString>(reply.arguments().at(1)), testString);
|
|
}
|
|
|
|
QTEST_MAIN(tst_QDBusAbstractAdaptor)
|
|
|
|
#include "tst_qdbusabstractadaptor.moc"
|