qt 6.5.1 original

This commit is contained in:
kleuter
2023-10-29 23:33:08 +01:00
parent 71d22ab6b0
commit 85d238dfda
21202 changed files with 5499099 additions and 0 deletions

View File

@ -0,0 +1,30 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(qdbusconnection_delayed)
add_subdirectory(qdbusconnection)
add_subdirectory(qdbusconnection_no_app)
add_subdirectory(qdbusconnection_no_bus)
add_subdirectory(qdbusconnection_no_libdbus)
add_subdirectory(qdbusconnection_spyhook)
add_subdirectory(qdbuscontext)
add_subdirectory(qdbuslocalcalls)
add_subdirectory(qdbusmetaobject)
add_subdirectory(qdbusmetatype)
add_subdirectory(qdbuspendingcall)
add_subdirectory(qdbuspendingreply)
add_subdirectory(qdbusreply)
add_subdirectory(qdbusservicewatcher)
add_subdirectory(qdbustype)
add_subdirectory(qdbusthreading)
if(QT_FEATURE_process)
add_subdirectory(qdbusabstractadaptor)
add_subdirectory(qdbusabstractinterface)
add_subdirectory(qdbusinterface)
endif()
if(QT_FEATURE_private_tests AND QT_FEATURE_process)
add_subdirectory(qdbusmarshall)
endif()
if(TARGET Qt::Xml)
add_subdirectory(qdbusxmlparser)
endif()

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(qmyserver)
qt_internal_add_test(tst_qdbusabstractadaptor
SOURCES
myobject.h
tst_qdbusabstractadaptor.cpp
LIBRARIES
Qt::CorePrivate
Qt::DBus
)
add_dependencies(tst_qdbusabstractadaptor qmyserver)

View File

@ -0,0 +1,254 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>
#include <QVariant>
#include <QUrl>
#include <QDBusMessage>
#include <QDBusAbstractAdaptor>
extern const char *slotSpy;
extern QString valueSpy;
class QDBusSignalSpy: public QObject
{
Q_OBJECT
public slots:
void slot(const QDBusMessage &msg)
{
++count;
interface = msg.interface();
name = msg.member();
signature = msg.signature();
path = msg.path();
value.clear();
if (msg.arguments().size())
value = msg.arguments().at(0);
}
public:
QDBusSignalSpy() : count(0) { }
int count;
QString interface;
QString name;
QString signature;
QString path;
QVariant value;
};
class Interface1: public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "local.Interface1")
public:
Interface1(QObject *parent) : QDBusAbstractAdaptor(parent)
{ }
};
class Interface2: public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "local.Interface2")
Q_PROPERTY(QString prop1 READ prop1)
Q_PROPERTY(QString prop2 READ prop2 WRITE setProp2 SCRIPTABLE true)
Q_PROPERTY(QUrl nonDBusProperty READ nonDBusProperty)
public:
Interface2(QObject *parent) : QDBusAbstractAdaptor(parent)
{ setAutoRelaySignals(true); }
QString prop1() const
{ return QLatin1String("QString Interface2::prop1() const"); }
QString prop2() const
{ return QLatin1String("QString Interface2::prop2() const"); }
void setProp2(const QString &value)
{
slotSpy = "void Interface2::setProp2(const QString &)";
valueSpy = value;
}
QUrl nonDBusProperty() const
{ return QUrl(); }
void emitSignal(const QString &, const QVariant &)
{ emit signal(); }
public slots:
void method()
{
slotSpy = "void Interface2::method()";
}
Q_SCRIPTABLE void scriptableMethod()
{
slotSpy = "void Interface2::scriptableMethod()";
}
signals:
void signal();
};
class Interface3: public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "local.Interface3")
Q_PROPERTY(QString prop1 READ prop1)
Q_PROPERTY(QString prop2 READ prop2 WRITE setProp2)
Q_PROPERTY(QString interface3prop READ interface3prop)
public:
Interface3(QObject *parent) : QDBusAbstractAdaptor(parent)
{ setAutoRelaySignals(true); }
QString prop1() const
{ return QLatin1String("QString Interface3::prop1() const"); }
QString prop2() const
{ return QLatin1String("QString Interface3::prop2() const"); }
void setProp2(const QString &value)
{
slotSpy = "void Interface3::setProp2(const QString &)";
valueSpy = value;
}
QString interface3prop() const
{ return QLatin1String("QString Interface3::interface3prop() const"); }
void emitSignal(const QString &name, const QVariant &value)
{
if (name == "signalVoid")
emit signalVoid();
else if (name == "signalInt")
emit signalInt(value.toInt());
else if (name == "signalString")
emit signalString(value.toString());
}
public slots:
void methodVoid() { slotSpy = "void Interface3::methodVoid()"; }
void methodInt(int) { slotSpy = "void Interface3::methodInt(int)"; }
void methodString(QString) { slotSpy = "void Interface3::methodString(QString)"; }
int methodStringString(const QString &s, QString &out)
{
slotSpy = "int Interface3::methodStringString(const QString &, QString &)";
out = s;
return 42;
}
signals:
void signalVoid();
void signalInt(int);
void signalString(const QString &);
};
class Interface4: public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "local.Interface4")
Q_PROPERTY(QString prop1 READ prop1)
Q_PROPERTY(QString prop2 READ prop2 WRITE setProp2)
Q_PROPERTY(QString interface4prop READ interface4prop)
public:
Interface4(QObject *parent) : QDBusAbstractAdaptor(parent)
{ setAutoRelaySignals(true); }
QString prop1() const
{ return QLatin1String("QString Interface4::prop1() const"); }
QString prop2() const
{ return QLatin1String("QString Interface4::prop2() const"); }
QString interface4prop() const
{ return QLatin1String("QString Interface4::interface4prop() const"); }
void setProp2(const QString &value)
{
slotSpy = "void Interface4::setProp2(const QString &)";
valueSpy = value;
}
void emitSignal(const QString &, const QVariant &value)
{
switch (value.metaType().id())
{
case QMetaType::UnknownType:
emit signal();
break;
case QMetaType::Int:
emit signal(value.toInt());
break;
case QMetaType::QString:
emit signal(value.toString());
break;
default:
break;
}
}
public slots:
void method() { slotSpy = "void Interface4::method()"; }
void method(int) { slotSpy = "void Interface4::method(int)"; }
void method(QString) { slotSpy = "void Interface4::method(QString)"; }
signals:
void signal();
void signal(int);
void signal(const QString &);
};
class MyObject: public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "local.MyObject")
public:
Interface1 *if1;
Interface2 *if2;
Interface3 *if3;
Interface4 *if4;
MyObject(int n = 4)
: if1(0), if2(0), if3(0), if4(0)
{
switch (n)
{
case 4:
if4 = new Interface4(this);
Q_FALLTHROUGH();
case 3:
if3 = new Interface3(this);
Q_FALLTHROUGH();
case 2:
if2 = new Interface2(this);
Q_FALLTHROUGH();
case 1:
if1 = new Interface1(this);
}
}
void emitSignal(const QString &name, const QVariant &value)
{
if (name == "scriptableSignalVoid")
emit scriptableSignalVoid();
else if (name == "scriptableSignalInt")
emit scriptableSignalInt(value.toInt());
else if (name == "scriptableSignalString")
emit scriptableSignalString(value.toString());
else if (name == "nonScriptableSignalVoid")
emit nonScriptableSignalVoid();
}
signals:
Q_SCRIPTABLE void scriptableSignalVoid();
Q_SCRIPTABLE void scriptableSignalInt(int);
Q_SCRIPTABLE void scriptableSignalString(QString);
void nonScriptableSignalVoid();
};
#endif // MYOBJECT_H

View File

@ -0,0 +1,16 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## qmyserver Binary:
#####################################################################
qt_internal_add_executable(qmyserver
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
NO_INSTALL
SOURCES
../myobject.h
qmyserver.cpp
LIBRARIES
Qt::DBus
)

View File

@ -0,0 +1,166 @@
// 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 <QCoreApplication>
#include <QDBusServer>
#include <QDBusContext>
#include <QDBusConnection>
#include <QDBusVariant>
#include <QDBusServer>
#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;
Q_DECLARE_METATYPE(QDBusConnection::RegisterOptions)
class MyServer : public QDBusServer, protected QDBusContext
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.qtproject.autotests.qmyserver")
public:
MyServer(QObject* parent = nullptr)
: QDBusServer(parent),
m_conn("none"),
obj(NULL)
{
connect(this, SIGNAL(newConnection(QDBusConnection)), SLOT(handleConnection(QDBusConnection)));
}
~MyServer()
{
if (obj)
obj->deleteLater();
}
public slots:
QString address() const
{
if (!QDBusServer::isConnected())
sendErrorReply(QDBusServer::lastError().name(), QDBusServer::lastError().message());
return QDBusServer::address();
}
void waitForConnected()
{
if (callPendingReply.type() != QDBusMessage::InvalidMessage) {
sendErrorReply(QDBusError::NotSupported, "One call already pending!");
return;
}
if (m_conn.isConnected())
return;
// not connected, we'll reply later
setDelayedReply(true);
callPendingReply = message();
}
Q_NOREPLY void requestSync(const QString &seq)
{
emit syncReceived(seq);
}
void emitSignal(const QString& interface, const QString& name, const QDBusVariant& parameter)
{
if (interface.endsWith('2'))
obj->if2->emitSignal(name, parameter.variant());
else if (interface.endsWith('3'))
obj->if3->emitSignal(name, parameter.variant());
else if (interface.endsWith('4'))
obj->if4->emitSignal(name, parameter.variant());
else
obj->emitSignal(name, parameter.variant());
}
void emitSignal2(const QString& interface, const QString& name)
{
if (interface.endsWith('2'))
obj->if2->emitSignal(name, QVariant());
else if (interface.endsWith('3'))
obj->if3->emitSignal(name, QVariant());
else if (interface.endsWith('4'))
obj->if4->emitSignal(name, QVariant());
else
obj->emitSignal(name, QVariant());
}
void newMyObject(int nInterfaces = 4)
{
if (obj)
obj->deleteLater();
obj = new MyObject(nInterfaces);
}
void registerMyObject(const QString & path, int options)
{
m_conn.registerObject(path, obj, (QDBusConnection::RegisterOptions)options);
}
QString slotSpyServer()
{
return QLatin1String(slotSpy);
}
QString valueSpyServer()
{
return valueSpy;
}
void clearValueSpy()
{
valueSpy.clear();
}
void quit()
{
qApp->quit();
}
signals:
Q_SCRIPTABLE void syncReceived(const QString &sequence);
private slots:
void handleConnection(QDBusConnection con)
{
m_conn = con;
con.registerObject(objectPath, this, QDBusConnection::ExportScriptableSignals);
if (callPendingReply.type() != QDBusMessage::InvalidMessage) {
QDBusConnection::sessionBus().send(callPendingReply.createReply());
callPendingReply = QDBusMessage();
}
}
private:
QDBusConnection m_conn;
QDBusMessage callPendingReply;
MyObject* obj;
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QDBusConnection con = QDBusConnection::sessionBus();
if (!con.isConnected())
exit(1);
if (!con.registerService(serviceName))
exit(2);
MyServer server;
con.registerObject(objectPath, &server, QDBusConnection::ExportAllSlots);
printf("ready.\n");
fflush(stdout);
return app.exec();
}
#include "qmyserver.moc"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(qpinger)
qt_internal_add_test(tst_qdbusabstractinterface
SOURCES
interface.cpp
tst_qdbusabstractinterface.cpp
LIBRARIES
Qt::Core
Qt::DBus
)
qt_internal_extend_target(tst_qdbusabstractinterface
DBUS_INTERFACE_SOURCES
org.qtproject.QtDBus.Pinger.xml
DBUS_INTERFACE_BASENAME
pinger_interface
DBUS_INTERFACE_FLAGS
-i interface.h
)

View File

@ -0,0 +1,24 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "interface.h"
#include <QThread>
Interface::Interface()
{
}
// Export the sleep function
// TODO QT5: remove this class, QThread::msleep is now public
class FriendlySleepyThread : public QThread {
public:
using QThread::msleep;
};
int Interface::sleepMethod(int msec)
{
FriendlySleepyThread::msleep(msec);
return 42;
}
#include "moc_interface.cpp"

View File

@ -0,0 +1,78 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef INTERFACE_H
#define INTERFACE_H
#include <QObject>
#include <QHash>
#include <QDBusArgument>
struct RegisteredType
{
inline RegisteredType(const QString &str = QString()) : s(str) {}
inline bool operator==(const RegisteredType &other) const { return s == other.s; }
QString s;
};
Q_DECLARE_METATYPE(RegisteredType)
inline QDBusArgument &operator<<(QDBusArgument &s, const RegisteredType &data)
{
s.beginStructure();
s << data.s;
s.endStructure();
return s;
}
inline const QDBusArgument &operator>>(const QDBusArgument &s, RegisteredType &data)
{
s.beginStructure();
s >> data.s;
s.endStructure();
return s;
}
struct UnregisteredType
{
QString s;
};
Q_DECLARE_METATYPE(UnregisteredType)
class Interface: public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.qtproject.QtDBus.Pinger")
Q_PROPERTY(QString stringProp READ stringProp WRITE setStringProp SCRIPTABLE true)
Q_PROPERTY(QDBusVariant variantProp READ variantProp WRITE setVariantProp SCRIPTABLE true)
Q_PROPERTY(RegisteredType complexProp READ complexProp WRITE setComplexProp SCRIPTABLE true)
friend class tst_QDBusAbstractInterface;
friend class PingerServer;
QString m_stringProp;
QDBusVariant m_variantProp;
RegisteredType m_complexProp;
public:
Interface();
QString stringProp() const { return m_stringProp; }
void setStringProp(const QString &s) { m_stringProp = s; }
QDBusVariant variantProp() const { return m_variantProp; }
void setVariantProp(const QDBusVariant &v) { m_variantProp = v; }
RegisteredType complexProp() const { return m_complexProp; }
void setComplexProp(const RegisteredType &r) { m_complexProp = r; }
public slots:
Q_SCRIPTABLE void voidMethod() {}
Q_SCRIPTABLE int sleepMethod(int);
Q_SCRIPTABLE QString stringMethod() { return "Hello, world"; }
Q_SCRIPTABLE RegisteredType complexMethod(const QVariantHash &vars) { return RegisteredType(vars.value("arg1").toString()); }
Q_SCRIPTABLE QString multiOutMethod(int &value) { value = 42; return "Hello, world"; }
signals:
Q_SCRIPTABLE void voidSignal();
Q_SCRIPTABLE void stringSignal(const QString &);
Q_SCRIPTABLE void complexSignal(RegisteredType);
};
#endif // INTERFACE_H

View File

@ -0,0 +1,36 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.qtproject.QtDBus.Pinger">
<property name="stringProp" type="s" access="readwrite"/>
<property name="variantProp" type="v" access="readwrite"/>
<property name="complexProp" type="(s)" access="readwrite">
<annotation name="org.qtproject.QtDBus.QtTypeName" value="RegisteredType"/>
</property>
<signal name="voidSignal"/>
<signal name="stringSignal">
<arg type="s" name="string-data"/>
</signal>
<signal name="complexSignal">
<arg name="" type="(s)"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="RegisteredType"/>
</signal>
<method name="voidMethod" />
<method name="sleepMethod">
<arg type="i" />
<arg type="i" direction="out"/>
</method>
<method name="stringMethod">
<arg type="s" direction="out"/>
</method>
<method name="complexMethod">
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QHash&lt;QString,QVariant&gt;"/>
<arg type='a{sv}' name='platform_data' direction='in'/>
<arg type="(s)" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="RegisteredType"/>
</method>
<method name="multiOutMethod">
<arg type="s" direction="out"/>
<arg type="i" direction="out"/>
</method>
</interface>
</node>

View File

@ -0,0 +1,8 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbusabstractinterface Test:
#####################################################################
# this test can not be generated here. It needs to be set up in the
# parent directory

View File

@ -0,0 +1,16 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## qpinger Binary:
#####################################################################
qt_internal_add_executable(qpinger
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
NO_INSTALL
SOURCES
../interface.cpp ../interface.h
qpinger.cpp
LIBRARIES
Qt::DBus
)

View File

@ -0,0 +1,122 @@
// 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 <QCoreApplication>
#include <QDBusServer>
#include <QDBusContext>
#include <QDBusMetaType>
#include <QDBusConnection>
#include <QDBusMessage>
#include "../interface.h"
static const char serviceName[] = "org.qtproject.autotests.qpinger";
static const char objectPath[] = "/org/qtproject/qpinger";
//static const char *interfaceName = serviceName;
class PingerServer : public QDBusServer, protected QDBusContext
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.qtproject.autotests.qpinger")
public:
PingerServer(QObject *parent = nullptr)
: QDBusServer(parent),
m_conn("none")
{
connect(this, SIGNAL(newConnection(QDBusConnection)), SLOT(handleConnection(QDBusConnection)));
reset();
}
public slots:
QString address() const
{
if (!QDBusServer::isConnected())
sendErrorReply(QDBusServer::lastError().name(), QDBusServer::lastError().message());
return QDBusServer::address();
}
void waitForConnected()
{
if (callPendingReply.type() != QDBusMessage::InvalidMessage) {
sendErrorReply(QDBusError::NotSupported, "One call already pending!");
return;
}
if (m_conn.isConnected())
return;
// not connected, we'll reply later
setDelayedReply(true);
callPendingReply = message();
}
void reset()
{
targetObj.m_stringProp = "This is a test";
targetObj.m_variantProp = QDBusVariant(QVariant(42));
targetObj.m_complexProp = RegisteredType("This is a test");
}
void voidSignal()
{
emit targetObj.voidSignal();
}
void stringSignal(const QString& value)
{
emit targetObj.stringSignal(value);
}
void complexSignal(const QString& value)
{
RegisteredType reg(value);
emit targetObj.complexSignal(reg);
}
void quit()
{
qApp->quit();
}
private slots:
void handleConnection(const QDBusConnection& con)
{
m_conn = con;
m_conn.registerObject("/", &targetObj, QDBusConnection::ExportScriptableContents);
if (callPendingReply.type() != QDBusMessage::InvalidMessage) {
QDBusConnection::sessionBus().send(callPendingReply.createReply());
callPendingReply = QDBusMessage();
}
}
private:
Interface targetObj;
QDBusConnection m_conn;
QDBusMessage callPendingReply;
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
// register the meta types
qDBusRegisterMetaType<RegisteredType>();
qRegisterMetaType<UnregisteredType>();
QDBusConnection con = QDBusConnection::sessionBus();
if (!con.isConnected())
exit(1);
if (!con.registerService(serviceName))
exit(2);
PingerServer server;
con.registerObject(objectPath, &server, QDBusConnection::ExportAllSlots);
printf("ready.\n");
fflush(stdout);
return app.exec();
}
#include "qpinger.moc"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbusconnection Test:
#####################################################################
qt_internal_add_test(tst_qdbusconnection
SOURCES
tst_qdbusconnection.cpp tst_qdbusconnection.h
LIBRARIES
Qt::DBus
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,280 @@
// 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
#ifndef TST_QDBUSCONNECTION_H
#define TST_QDBUSCONNECTION_H
#include <QObject>
#include <QTest>
#include <QTestEventLoop>
#include <QDBusMessage>
#include <QDBusConnection>
#include <QDBusServer>
#include <QDBusVirtualObject>
class BaseObject: public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "local.BaseObject")
public:
BaseObject(QObject *parent = nullptr) : QObject(parent) { }
public slots:
void anotherMethod() { }
};
class MyObject: public BaseObject
{
Q_OBJECT
public slots:
void method(const QDBusMessage &msg);
public:
static QString path;
int callCount;
MyObject(QObject *parent = nullptr) : BaseObject(parent), callCount(0) {}
};
class MyObjectWithoutInterface: public QObject
{
Q_OBJECT
public slots:
void method(const QDBusMessage &msg);
public:
static QString path;
static QString interface;
int callCount;
MyObjectWithoutInterface(QObject *parent = nullptr) : QObject(parent), callCount(0) {}
};
class SignalReceiver : public QObject
{
Q_OBJECT
public:
QString argumentReceived;
int signalsReceived;
SignalReceiver() : signalsReceived(0) {}
public slots:
void oneSlot(const QString &arg) { ++signalsReceived; argumentReceived = arg;}
void oneSlot() { ++signalsReceived; }
void exitLoop() { ++signalsReceived; QTestEventLoop::instance().exitLoop(); }
void secondCallWithCallback();
};
class tst_QDBusConnection: public QObject
{
Q_OBJECT
public:
static int hookCallCount;
tst_QDBusConnection();
public slots:
void init();
void cleanup();
private slots:
void noConnection();
void connectToBus();
void connectToPeer();
void connect();
void send();
void sendWithGui();
void sendAsync();
void sendSignal();
void sendSignalToName();
void sendSignalToOtherName();
void registerObject_data();
void registerObject();
void registerObjectWithInterface_data();
void registerObjectWithInterface();
void registerObjectPeer_data();
void registerObjectPeer();
void registerObject2();
void registerObjectPeer2();
void registerQObjectChildren();
void registerQObjectChildrenPeer();
void callSelf();
void callSelfByAnotherName_data();
void callSelfByAnotherName();
void multipleInterfacesInQObject();
void connectSignal();
void slotsWithLessParameters();
void nestedCallWithCallback();
void serviceRegistrationRaceCondition();
void registerVirtualObject();
void callVirtualObject();
void callVirtualObjectLocal();
void pendingCallWhenDisconnected();
public:
QString serviceName() const { return "org.qtproject.Qt.Autotests.QDBusConnection"; }
bool callMethod(const QDBusConnection &conn, const QString &path);
bool callMethod(const QDBusConnection &conn, const QString &path, const QString &interface);
bool callMethodPeer(const QDBusConnection &conn, const QString &path);
};
class QDBusSpy: public QObject
{
Q_OBJECT
public slots:
void handlePing(const QString &str) { args.clear(); args << str; }
void asyncReply(const QDBusMessage &msg) { args = msg.arguments(); }
public:
QList<QVariant> args;
};
class MyServer : public QDBusServer
{
Q_OBJECT
public:
MyServer(QString path) : m_path(path), m_connections()
{
connect(this, SIGNAL(newConnection(QDBusConnection)), SLOT(handleConnection(QDBusConnection)));
}
bool registerObject(const QDBusConnection& c)
{
QDBusConnection conn(c);
if (!conn.registerObject(m_path, &m_obj, QDBusConnection::ExportAllSlots))
return false;
if (!(conn.objectRegisteredAt(m_path) == &m_obj))
return false;
return true;
}
bool registerObject()
{
Q_FOREACH (const QString &name, m_connections) {
if (!registerObject(QDBusConnection(name)))
return false;
}
return true;
}
void unregisterObject()
{
Q_FOREACH (const QString &name, m_connections) {
QDBusConnection c(name);
c.unregisterObject(m_path);
}
}
public slots:
void handleConnection(const QDBusConnection& c)
{
m_connections << c.name();
QVERIFY(isConnected());
QVERIFY(c.isConnected());
QVERIFY(registerObject(c));
QTestEventLoop::instance().exitLoop();
}
private:
MyObject m_obj;
QString m_path;
QStringList m_connections;
};
class MyServer2 : public QDBusServer
{
Q_OBJECT
public:
MyServer2() : m_conn("none")
{
connect(this, SIGNAL(newConnection(QDBusConnection)), SLOT(handleConnection(QDBusConnection)));
}
QDBusConnection connection()
{
return m_conn;
}
public slots:
void handleConnection(const QDBusConnection& c)
{
m_conn = c;
QVERIFY(isConnected());
QVERIFY(m_conn.isConnected());
QTestEventLoop::instance().exitLoop();
}
private:
MyObject m_obj;
QDBusConnection m_conn;
};
class TestObject : public QObject
{
Q_OBJECT
public:
TestObject(QObject *parent = nullptr) : QObject(parent) {}
~TestObject() {}
QString func;
public slots:
void test0() { func = "test0"; }
void test1(int i) { func = "test1 " + QString::number(i); }
int test2() { func = "test2"; return 43; }
int test3(int i) { func = "test2"; return i + 1; }
};
class RaceConditionSignalWaiter : public QObject
{
Q_OBJECT
public:
int count;
RaceConditionSignalWaiter() : count (0) {}
virtual ~RaceConditionSignalWaiter() {}
public slots:
void countUp() { ++count; emit done(); }
signals:
void done();
};
class VirtualObject: public QDBusVirtualObject
{
Q_OBJECT
public:
VirtualObject() :success(true) {}
QString introspect(const QString & /* path */) const override
{
return QString();
}
bool handleMessage(const QDBusMessage &message, const QDBusConnection &connection) override {
++callCount;
lastMessage = message;
if (success) {
QDBusMessage reply = message.createReply(replyArguments);
connection.send(reply);
}
emit messageReceived(message);
return success;
}
signals:
void messageReceived(const QDBusMessage &message) const;
public:
mutable QDBusMessage lastMessage;
QVariantList replyArguments;
mutable int callCount;
bool success;
};
#endif // TST_QDBUSCONNECTION_H

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbusconnection_delayed Test:
#####################################################################
qt_internal_add_test(tst_qdbusconnection_delayed
SOURCES
tst_qdbusconnection_delayed.cpp
LIBRARIES
Qt::DBus
)

View File

@ -0,0 +1,85 @@
// 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 <QTestEventLoop>
#include <QDBusConnection>
#include <QDBusConnectionInterface>
#ifdef Q_OS_WIN
# include <process.h>
# define getpid _getpid
#else
# include <sys/types.h>
# include <unistd.h>
#endif
class tst_QDBusConnection_Delayed : public QObject
{
Q_OBJECT
private slots:
void delayedMessages();
};
class Foo : public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.qtproject.tst_qdbusconnection_delayed.Foo")
public slots:
int bar() { return 42; }
};
static bool executedOnce = false;
void tst_QDBusConnection_Delayed::delayedMessages()
{
if (executedOnce)
QSKIP("This test can only be executed once");
executedOnce = true;
int argc = 1;
char *argv[] = { const_cast<char *>("tst_qdbusconnection_delayed"), 0 };
QCoreApplication app(argc, argv);
QDBusConnection session = QDBusConnection::sessionBus();
QVERIFY(session.isConnected());
QVERIFY(!session.baseService().isEmpty());
QDBusConnection other = QDBusConnection::connectToBus(QDBusConnection::SessionBus, "other");
QVERIFY(other.isConnected());
QVERIFY(!other.baseService().isEmpty());
// make a method call: those should work even if delivery is disabled
QVERIFY(session.interface()->isServiceRegistered(other.baseService()));
// acquire a name in the main session bus connection: the effect is immediate
QString name = "org.qtproject.tst_qdbusconnection_delayed-" +
QString::number(getpid());
QVERIFY(session.registerService(name));
QVERIFY(other.interface()->isServiceRegistered(name));
// make an asynchronous call to a yet-unregistered object
QDBusPendingCallWatcher pending(other.asyncCall(QDBusMessage::createMethodCall(name, "/foo", QString(), "bar")));
// sleep the main thread without running the event loop;
// the call must not be delivered
QTest::qSleep(1000);
QVERIFY(!pending.isFinished());
// now register the object
Foo foo;
session.registerObject("/foo", &foo, QDBusConnection::ExportAllSlots);
connect(&pending, &QDBusPendingCallWatcher::finished,
&QTestEventLoop::instance(), &QTestEventLoop::exitLoop);
QTestEventLoop::instance().enterLoop(2);
QVERIFY(!QTestEventLoop::instance().timeout());
QVERIFY(pending.isFinished());
QVERIFY2(!pending.isError(), pending.error().name().toLatin1());
QVERIFY(!pending.reply().arguments().isEmpty());
QCOMPARE(pending.reply().arguments().at(0), QVariant(42));
}
QTEST_APPLESS_MAIN(tst_QDBusConnection_Delayed)
#include "tst_qdbusconnection_delayed.moc"

View File

@ -0,0 +1,16 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbusconnection_no_app Test:
#####################################################################
qt_internal_add_test(tst_qdbusconnection_no_app
SOURCES
../qdbusconnection/tst_qdbusconnection.h
tst_qdbusconnection_no_app.cpp
DEFINES
tst_QDBusConnection=tst_QDBusConnection_NoApplication
LIBRARIES
Qt::DBus
)

View File

@ -0,0 +1,7 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// Ugly hack, look away
#include "../qdbusconnection/tst_qdbusconnection.cpp"
QTEST_APPLESS_MAIN(tst_QDBusConnection_NoApplication)

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbusconnection_no_bus Test:
#####################################################################
qt_internal_add_test(tst_qdbusconnection_no_bus
SOURCES
tst_qdbusconnection_no_bus.cpp
LIBRARIES
Qt::DBus
)

View File

@ -0,0 +1,48 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QDebug>
#include <QCoreApplication>
#include <QDBusConnection>
#include <stdlib.h>
/* This test uses an appless main, to ensure that no D-Bus stuff is implicitly done
It also sets the magic "QT_SIMULATE_DBUS_LIBFAIL" env variable, that is only available
in developer builds. That env variable simulates a D-Bus library load fail.
In no case should the QDBus module crash because D-Bus libs couldn't be loaded */
class tst_QDBusConnectionNoBus : public QObject
{
Q_OBJECT
public:
tst_QDBusConnectionNoBus()
{
qputenv("DBUS_SESSION_BUS_ADDRESS", "unix:abstract=/tmp/does_not_exist");
#ifdef SIMULATE_LOAD_FAIL
qputenv("QT_SIMULATE_DBUS_LIBFAIL", "1");
#endif
}
private slots:
void connectToBus();
};
void tst_QDBusConnectionNoBus::connectToBus()
{
int argc = 0;
QCoreApplication app(argc, 0);
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(!con.isConnected()); // if we didn't crash here, the test passed :)
}
QTEST_APPLESS_MAIN(tst_QDBusConnectionNoBus)
#include "tst_qdbusconnection_no_bus.moc"

View File

@ -0,0 +1,16 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbusconnection_no_libdbus Test:
#####################################################################
qt_internal_add_test(tst_qdbusconnection_no_libdbus
SOURCES
../qdbusconnection_no_bus/tst_qdbusconnection_no_bus.cpp
DEFINES
SIMULATE_LOAD_FAIL
tst_QDBusConnectionNoBus=tst_QDBusConnectionNoLibDBus1
LIBRARIES
Qt::DBus
)

View File

@ -0,0 +1,48 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <qcoreapplication.h>
#include <qdebug.h>
#include <QTest>
#include <stdlib.h>
/* This test uses an appless main, to ensure that no D-Bus stuff is implicitly done
It also sets the magic "QT_SIMULATE_DBUS_LIBFAIL" env variable, that is only available
in developer builds. That env variable simulates a D-Bus library load fail.
In no case should the QDBus module crash because D-Bus libs couldn't be loaded */
class tst_QDBusConnectionNoBus : public QObject
{
Q_OBJECT
public:
tst_QDBusConnectionNoBus()
{
qputenv("DBUS_SESSION_BUS_ADDRESS", "unix:abstract=/tmp/does_not_exist");
#ifdef SIMULATE_LOAD_FAIL
qputenv("QT_SIMULATE_DBUS_LIBFAIL", "1");
#endif
}
private slots:
void connectToBus();
};
void tst_QDBusConnectionNoBus::connectToBus()
{
int argc = 0;
QCoreApplication app(argc, 0);
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(!con.isConnected()); // if we didn't crash here, the test passed :)
}
QTEST_APPLESS_MAIN(tst_QDBusConnectionNoBus)
#include "tst_qdbusconnection_no_libdbus.moc"

View File

@ -0,0 +1,16 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbusconnection_spyhook Test:
#####################################################################
qt_internal_add_test(tst_qdbusconnection_spyhook
SOURCES
../qdbusconnection/tst_qdbusconnection.h
tst_qdbusconnection_spyhook.cpp
DEFINES
tst_QDBusConnection=tst_QDBusConnection_SpyHook
LIBRARIES
Qt::DBus
)

View File

@ -0,0 +1,27 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtDBus/QDBusMessage>
#define HAS_HOOKSETUPFUNCTION 1
static void hookSetupFunction();
// Ugly hack, look away
#include "../qdbusconnection/tst_qdbusconnection.cpp"
QT_BEGIN_NAMESPACE
extern Q_DBUS_EXPORT void qDBusAddSpyHook(void (*Hook)(const QDBusMessage&));
QT_END_NAMESPACE
static void hookFunction(const QDBusMessage &)
{
// qDebug() << "hook called";
++tst_QDBusConnection::hookCallCount;
}
static void hookSetupFunction()
{
QT_PREPEND_NAMESPACE(qDBusAddSpyHook)(hookFunction);
}
QTEST_MAIN(tst_QDBusConnection_SpyHook)

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbuscontext Test:
#####################################################################
qt_internal_add_test(tst_qdbuscontext
SOURCES
tst_qdbuscontext.cpp
LIBRARIES
Qt::DBus
)

View File

@ -0,0 +1,59 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QDBusContext>
#include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusReply>
const char errorName[] = "org.qtproject.tst_QDBusContext.Error";
const char errorMsg[] = "A generic error";
class TestObject: public QObject, protected QDBusContext
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.qtproject.tst_QDBusContext.TestObject")
public:
inline TestObject(QObject *parent) : QObject(parent) { }
public Q_SLOTS:
void generateError();
};
class tst_QDBusContext: public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void sendErrorReply();
};
void TestObject::generateError()
{
sendErrorReply(errorName, errorMsg);
}
void tst_QDBusContext::initTestCase()
{
TestObject *obj = new TestObject(this);
QVERIFY(QDBusConnection::sessionBus().isConnected());
QVERIFY(QDBusConnection::sessionBus().registerObject("/TestObject", obj,
QDBusConnection::ExportAllSlots));
}
void tst_QDBusContext::sendErrorReply()
{
QDBusInterface iface(QDBusConnection::sessionBus().baseService(), "/TestObject");
QVERIFY(iface.isValid());
QDBusReply<void> reply = iface.call("generateError");
QVERIFY(!reply.isValid());
const QDBusError &error = reply.error();
QCOMPARE(error.name(), QString::fromLatin1(errorName));
QCOMPARE(error.message(), QString::fromLatin1(errorMsg));
}
QTEST_MAIN(tst_QDBusContext)
#include "tst_qdbuscontext.moc"

View File

@ -0,0 +1,38 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(qmyserver)
#####################################################################
## ../tst_qdbusinterface Test:
#####################################################################
qt_internal_add_test(tst_qdbusinterface
SOURCES
myobject.h
tst_qdbusinterface.cpp
LIBRARIES
Qt::CorePrivate
Qt::DBusPrivate
LIBRARIES
Qt::Core
Qt::DBus
)
## Scopes:
#####################################################################
qt_internal_extend_target(tst_qdbusinterface CONDITION QT_FEATURE_dbus_linked
DEFINES
QT_LINKED_LIBDBUS
LIBRARIES
dbus-1
)
qt_internal_extend_target(tst_qdbusinterface CONDITION NOT QT_FEATURE_dbus_linked
SOURCES
../../../../src/dbus/qdbus_symbols.cpp
)
add_dependencies(tst_qdbusinterface qmyserver_qdbusinterface)

View File

@ -0,0 +1,120 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>
#include <QDBusMessage>
#include <QDBusContext>
#include <QDBusConnection>
class MyObject: public QObject, protected QDBusContext
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.qtproject.QtDBus.MyObject")
Q_CLASSINFO("D-Bus Introspection", ""
" <interface name=\"org.qtproject.QtDBus.MyObject\" >\n"
" <property access=\"readwrite\" type=\"i\" name=\"prop1\" />\n"
" <property name=\"complexProp\" type=\"ai\" access=\"readwrite\">\n"
" <annotation name=\"org.qtproject.QtDBus.QtTypeName\" value=\"QList&lt;int&gt;\"/>\n"
" </property>\n"
" <signal name=\"somethingHappened\" >\n"
" <arg direction=\"out\" type=\"s\" />\n"
" </signal>\n"
" <method name=\"ping\" >\n"
" <arg direction=\"in\" type=\"v\" name=\"ping\" />\n"
" <arg direction=\"out\" type=\"v\" name=\"ping\" />\n"
" </method>\n"
" <method name=\"ping_invokable\" >\n"
" <arg direction=\"in\" type=\"v\" name=\"ping_invokable\" />\n"
" <arg direction=\"out\" type=\"v\" name=\"ping_invokable\" />\n"
" </method>\n"
" <method name=\"ping\" >\n"
" <arg direction=\"in\" type=\"v\" name=\"ping1\" />\n"
" <arg direction=\"in\" type=\"v\" name=\"ping2\" />\n"
" <arg direction=\"out\" type=\"v\" name=\"pong1\" />\n"
" <arg direction=\"out\" type=\"v\" name=\"pong2\" />\n"
" </method>\n"
" <method name=\"ping_invokable\" >\n"
" <arg direction=\"in\" type=\"v\" name=\"ping1_invokable\" />\n"
" <arg direction=\"in\" type=\"v\" name=\"ping2_invokable\" />\n"
" <arg direction=\"out\" type=\"v\" name=\"pong1_invokable\" />\n"
" <arg direction=\"out\" type=\"v\" name=\"pong2_invokable\" />\n"
" </method>\n"
" <method name=\"ping\" >\n"
" <arg direction=\"in\" type=\"ai\" name=\"ping\" />\n"
" <arg direction=\"out\" type=\"ai\" name=\"ping\" />\n"
" <annotation name=\"org.qtproject.QtDBus.QtTypeName.In0\" value=\"QList&lt;int&gt;\"/>\n"
" <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QList&lt;int&gt;\"/>\n"
" </method>\n"
" <method name=\"ping_invokable\" >\n"
" <arg direction=\"in\" type=\"ai\" name=\"ping_invokable\" />\n"
" <arg direction=\"out\" type=\"ai\" name=\"ping_invokable\" />\n"
" <annotation name=\"org.qtproject.QtDBus.QtTypeName.In0\" value=\"QList&lt;int&gt;\"/>\n"
" <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QList&lt;int&gt;\"/>\n"
" </method>\n"
" </interface>\n"
"")
Q_PROPERTY(int prop1 READ prop1 WRITE setProp1)
Q_PROPERTY(QList<int> complexProp READ complexProp WRITE setComplexProp)
public:
static int callCount;
static QVariantList callArgs;
MyObject()
{
QObject *subObject = new QObject(this);
subObject->setObjectName("subObject");
}
int m_prop1;
int prop1() const
{
++callCount;
return m_prop1;
}
void setProp1(int value)
{
++callCount;
m_prop1 = value;
}
QList<int> m_complexProp;
QList<int> complexProp() const
{
++callCount;
return m_complexProp;
}
void setComplexProp(const QList<int> &value)
{
++callCount;
m_complexProp = value;
}
Q_INVOKABLE void ping_invokable(QDBusMessage msg)
{
Q_ASSERT(QDBusContext::calledFromDBus());
++callCount;
callArgs = msg.arguments();
msg.setDelayedReply(true);
if (!QDBusContext::connection().send(msg.createReply(callArgs)))
exit(1);
}
public slots:
void ping(QDBusMessage msg)
{
Q_ASSERT(QDBusContext::calledFromDBus());
++callCount;
callArgs = msg.arguments();
msg.setDelayedReply(true);
if (!QDBusContext::connection().send(msg.createReply(callArgs)))
exit(1);
}
};
#endif // INTERFACE_H

View File

@ -0,0 +1,16 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## qmyserver_qdbusinterface Binary:
#####################################################################
qt_internal_add_executable(qmyserver_qdbusinterface
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
NO_INSTALL
SOURCES
../myobject.h
qmyserver.cpp
LIBRARIES
Qt::DBus
)

View File

@ -0,0 +1,148 @@
// 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 <QCoreApplication>
#include <QDBusServer>
#include "../myobject.h"
static const char serviceName[] = "org.qtproject.autotests.qmyserver";
static const char objectPath[] = "/org/qtproject/qmyserver";
//static const char *interfaceName = serviceName;
int MyObject::callCount = 0;
QVariantList MyObject::callArgs;
class MyServer : public QDBusServer, protected QDBusContext
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.qtproject.autotests.qmyserver")
public:
MyServer(QObject *parent = nullptr)
: QDBusServer(parent),
m_conn("none")
{
connect(this, SIGNAL(newConnection(QDBusConnection)), SLOT(handleConnection(QDBusConnection)));
}
public slots:
QString address() const
{
if (!QDBusServer::isConnected())
sendErrorReply(QDBusServer::lastError().name(), QDBusServer::lastError().message());
return QDBusServer::address();
}
void waitForConnected()
{
if (callPendingReply.type() != QDBusMessage::InvalidMessage) {
sendErrorReply(QDBusError::NotSupported, "One call already pending!");
return;
}
if (m_conn.isConnected())
return;
// not connected, we'll reply later
setDelayedReply(true);
callPendingReply = message();
}
void emitSignal(const QString &interface, const QString &name, const QString &arg)
{
QDBusMessage msg = QDBusMessage::createSignal("/", interface, name);
msg << arg;
m_conn.send(msg);
}
void reset()
{
MyObject::callCount = 0;
obj.m_complexProp.clear();
}
int callCount()
{
return MyObject::callCount;
}
QVariantList callArgs()
{
return MyObject::callArgs;
}
void setProp1(int val)
{
obj.m_prop1 = val;
}
int prop1()
{
return obj.m_prop1;
}
void setComplexProp(QList<int> val)
{
obj.m_complexProp = val;
}
QList<int> complexProp()
{
return obj.m_complexProp;
}
bool interactiveAuthorization()
{
if (message().isInteractiveAuthorizationAllowed())
return true;
sendErrorReply(QStringLiteral("org.freedesktop.DBus.Error.InteractiveAuthorizationRequired"),
QStringLiteral("Interactive authentication required."));
return false;
}
void quit()
{
qApp->quit();
}
private slots:
void handleConnection(const QDBusConnection& con)
{
m_conn = con;
m_conn.registerObject("/", &obj, QDBusConnection::ExportAllProperties
| QDBusConnection::ExportAllSlots
| QDBusConnection::ExportAllInvokables);
if (callPendingReply.type() != QDBusMessage::InvalidMessage) {
QDBusConnection::sessionBus().send(callPendingReply.createReply());
callPendingReply = QDBusMessage();
}
}
private:
QDBusConnection m_conn;
QDBusMessage callPendingReply;
MyObject obj;
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QDBusConnection con = QDBusConnection::sessionBus();
if (!con.isConnected())
exit(1);
if (!con.registerService(serviceName))
exit(2);
MyServer server;
con.registerObject(objectPath, &server, QDBusConnection::ExportAllSlots);
printf("ready.\n");
fflush(stdout);
return app.exec();
}
#include "qmyserver.moc"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbuslocalcalls Test:
#####################################################################
qt_internal_add_test(tst_qdbuslocalcalls
SOURCES
tst_qdbuslocalcalls.cpp
LIBRARIES
Qt::DBus
)

View File

@ -0,0 +1,238 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QTestEventLoop>
#include <QObject>
#include <QVariant>
#include <QList>
#include <QDBusConnection>
#include <QDBusVariant>
#include <QDBusPendingCallWatcher>
#include <QDBusMetaType>
class tst_QDBusLocalCalls: public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "local.tst_QDBusLocalCalls")
QDBusConnection conn;
public:
tst_QDBusLocalCalls();
public Q_SLOTS:
Q_SCRIPTABLE int echo(int value)
{ return value; }
Q_SCRIPTABLE QString echo(const QString &value)
{ return value; }
Q_SCRIPTABLE QDBusVariant echo(const QDBusVariant &value)
{ return value; }
Q_SCRIPTABLE QList<int> echo(const QList<int> &value) { return value; }
Q_SCRIPTABLE QString echo2(const QStringList &list, QString &out)
{ out = list[1]; return list[0]; }
Q_SCRIPTABLE void delayed(const QDBusMessage &msg)
{ msg.setDelayedReply(true); }
protected Q_SLOTS:
void replyReceived(QDBusPendingCallWatcher *watcher);
private Q_SLOTS:
void initTestCase();
void makeInvalidCalls();
void makeCalls_data();
void makeCalls();
void makeCallsVariant_data();
void makeCallsVariant();
void makeCallsTwoRets();
void makeCallsComplex();
void makeDelayedCalls();
void asyncReplySignal();
private:
QVariantList asyncReplyArgs;
QDBusMessage doCall(const QDBusMessage &call);
};
tst_QDBusLocalCalls::tst_QDBusLocalCalls()
: conn(QDBusConnection::sessionBus())
{
}
QDBusMessage tst_QDBusLocalCalls::doCall(const QDBusMessage &call)
{
QFETCH_GLOBAL(bool, useAsync);
if (useAsync) {
QDBusPendingCall ac = conn.asyncCall(call);
ac.waitForFinished();
return ac.reply();
} else {
return conn.call(call);
}
}
void tst_QDBusLocalCalls::replyReceived(QDBusPendingCallWatcher *watcher)
{
asyncReplyArgs = watcher->reply().arguments();
QTestEventLoop::instance().exitLoop();
}
void tst_QDBusLocalCalls::initTestCase()
{
QVERIFY(conn.isConnected());
QVERIFY(conn.registerObject("/", this, QDBusConnection::ExportScriptableSlots));
QTest::addColumn<bool>("useAsync");
QTest::newRow("sync") << false;
QTest::newRow("async") << true;
}
void tst_QDBusLocalCalls::makeCalls_data()
{
QTest::addColumn<QVariant>("value");
QTest::newRow("int") << QVariant(42);
QTest::newRow("string") << QVariant("Hello, world");
}
void tst_QDBusLocalCalls::makeCallsVariant_data()
{
makeCalls_data();
}
void tst_QDBusLocalCalls::makeInvalidCalls()
{
{
QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(),
"/", QString(), "echo");
QDBusMessage replyMsg = doCall(callMsg);
QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ErrorMessage));
QDBusError error(replyMsg);
QCOMPARE(int(error.type()), int(QDBusError::UnknownMethod));
}
{
QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(),
"/no_object", QString(), "echo");
QDBusMessage replyMsg = doCall(callMsg);
QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ErrorMessage));
QDBusError error(replyMsg);
QCOMPARE(int(error.type()), int(QDBusError::UnknownObject));
}
}
void tst_QDBusLocalCalls::makeCalls()
{
QFETCH(QVariant, value);
QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(),
"/", QString(), "echo");
callMsg << value;
QDBusMessage replyMsg = doCall(callMsg);
QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ReplyMessage));
QVariantList replyArgs = replyMsg.arguments();
QCOMPARE(replyArgs.size(), 1);
QCOMPARE(replyArgs.at(0), value);
}
void tst_QDBusLocalCalls::makeCallsVariant()
{
QFETCH(QVariant, value);
QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(),
"/", QString(), "echo");
callMsg << QVariant::fromValue(QDBusVariant(value));
QDBusMessage replyMsg = doCall(callMsg);
QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ReplyMessage));
QVariantList replyArgs = replyMsg.arguments();
QCOMPARE(replyArgs.size(), 1);
const QVariant &reply = replyArgs.at(0);
QCOMPARE(reply.userType(), qMetaTypeId<QDBusVariant>());
QCOMPARE(qvariant_cast<QDBusVariant>(reply).variant(), value);
}
void tst_QDBusLocalCalls::makeCallsTwoRets()
{
QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(),
"/", QString(), "echo2");
callMsg << (QStringList() << "One" << "Two");
QDBusMessage replyMsg = doCall(callMsg);
QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ReplyMessage));
QVariantList replyArgs = replyMsg.arguments();
QCOMPARE(replyArgs.size(), 2);
QCOMPARE(replyArgs.at(0).toString(), QString::fromLatin1("One"));
QCOMPARE(replyArgs.at(1).toString(), QString::fromLatin1("Two"));
}
void tst_QDBusLocalCalls::makeCallsComplex()
{
qDBusRegisterMetaType<QList<int> >();
qDBusRegisterMetaType<QList<int>>();
QList<int> value;
value << 1 << -42 << 47;
QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(),
"/", QString(), "echo");
callMsg << QVariant::fromValue(value);
QDBusMessage replyMsg = doCall(callMsg);
QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ReplyMessage));
QVariantList replyArgs = replyMsg.arguments();
QCOMPARE(replyArgs.size(), 1);
const QVariant &reply = replyArgs.at(0);
QCOMPARE(reply.userType(), qMetaTypeId<QDBusArgument>());
QCOMPARE(qdbus_cast<QList<int> >(reply), value);
}
void tst_QDBusLocalCalls::makeDelayedCalls()
{
QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(),
"/", QString(), "delayed");
QTest::ignoreMessage(QtWarningMsg, "QDBusConnection: cannot call local method 'delayed' at object / (with signature '') on blocking mode");
QDBusMessage replyMsg = doCall(callMsg);
QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ErrorMessage));
QDBusError error(replyMsg);
QCOMPARE(int(error.type()), int(QDBusError::InternalError));
}
void tst_QDBusLocalCalls::asyncReplySignal()
{
QFETCH_GLOBAL(bool, useAsync);
if (!useAsync)
return; // this test only works in async mode
QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(),
"/", QString(), "echo");
callMsg << "Hello World";
QDBusPendingCall ac = conn.asyncCall(callMsg);
if (ac.isFinished())
QSKIP("Test ignored: the local-loop async call is already finished");
QDBusPendingCallWatcher watch(ac);
connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
SLOT(replyReceived(QDBusPendingCallWatcher*)));
QTestEventLoop::instance().enterLoop(2);
QVERIFY(!QTestEventLoop::instance().timeout());
QVERIFY(ac.isFinished());
QVERIFY(!ac.isError());
QVERIFY(!asyncReplyArgs.isEmpty());
QCOMPARE(asyncReplyArgs.at(0).toString(), QString("Hello World"));
}
QTEST_MAIN(tst_QDBusLocalCalls)
#include "tst_qdbuslocalcalls.moc"

View File

@ -0,0 +1,8 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
if(NOT QT_FEATURE_private_tests)
return()
endif()
add_subdirectory(qpong)
add_subdirectory(qdbusmarshall)

View File

@ -0,0 +1,649 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtGlobal>
#include <QMap>
#include <QString>
#include <QVariant>
#include <QDateTime>
#include <QLine>
#include <QDBusObjectPath>
#include <QDBusSignature>
#include <QDBusUnixFileDescriptor>
#include <QDBusArgument>
#include <QDBusMetaType>
#ifdef Q_OS_UNIX
# include <private/qcore_unix_p.h>
static bool compareFileDescriptors(int fd1, int fd2)
{
QT_STATBUF st1, st2;
if (QT_FSTAT(fd1, &st1) == -1 || QT_FSTAT(fd2, &st2) == -1) {
perror("fstat");
return false;
}
return (st1.st_dev == st2.st_dev) && (st1.st_ino == st2.st_ino);
}
#endif
typedef QMap<int, QString> IntStringMap;
typedef QMap<QString, QString> StringStringMap;
typedef QMap<QDBusObjectPath, QString> ObjectPathStringMap;
typedef QMap<qlonglong, QDateTime> LLDateTimeMap;
typedef QMap<QDBusSignature, QString> SignatureStringMap;
Q_DECLARE_METATYPE(StringStringMap)
Q_DECLARE_METATYPE(LLDateTimeMap)
static bool compare(const QDBusUnixFileDescriptor &t1, const QDBusUnixFileDescriptor &t2)
{
int fd1 = t1.fileDescriptor();
int fd2 = t2.fileDescriptor();
if ((fd1 == -1 || fd2 == -1) && fd1 != fd2) {
// one is valid, the other isn't
return false;
}
#ifdef Q_OS_UNIX
return compareFileDescriptors(fd1, fd2);
#else
return true;
#endif
}
struct MyStruct
{
int i;
QString s;
inline bool operator==(const MyStruct &other) const
{ return i == other.i && s == other.s; }
};
Q_DECLARE_METATYPE(MyStruct)
QDBusArgument &operator<<(QDBusArgument &arg, const MyStruct &ms)
{
arg.beginStructure();
arg << ms.i << ms.s;
arg.endStructure();
return arg;
}
const QDBusArgument &operator>>(const QDBusArgument &arg, MyStruct &ms)
{
arg.beginStructure();
arg >> ms.i >> ms.s;
arg.endStructure();
return arg;
}
struct MyVariantMapStruct
{
QString s;
QVariantMap map;
inline bool operator==(const MyVariantMapStruct &other) const
{ return s == other.s && map == other.map; }
};
Q_DECLARE_METATYPE(MyVariantMapStruct)
QDBusArgument &operator<<(QDBusArgument &arg, const MyVariantMapStruct &ms)
{
arg.beginStructure();
arg << ms.s << ms.map;
arg.endStructure();
return arg;
}
const QDBusArgument &operator>>(const QDBusArgument &arg, MyVariantMapStruct &ms)
{
arg.beginStructure();
arg >> ms.s >> ms.map;
arg.endStructure();
return arg;
}
struct MyFileDescriptorStruct
{
QDBusUnixFileDescriptor fd;
inline bool operator==(const MyFileDescriptorStruct &other) const
{ return compare(fd, other.fd); }
};
Q_DECLARE_METATYPE(MyFileDescriptorStruct)
QDBusArgument &operator<<(QDBusArgument &arg, const MyFileDescriptorStruct &ms)
{
arg.beginStructure();
arg << ms.fd;
arg.endStructure();
return arg;
}
const QDBusArgument &operator>>(const QDBusArgument &arg, MyFileDescriptorStruct &ms)
{
arg.beginStructure();
arg >> ms.fd;
arg.endStructure();
return arg;
}
void commonInit()
{
qDBusRegisterMetaType<QList<QDateTime> >();
qDBusRegisterMetaType<QList<QStringList> >();
qDBusRegisterMetaType<QList<QByteArray> >();
qDBusRegisterMetaType<QList<QList<bool> > >();
qDBusRegisterMetaType<QList<QList<short> > >();
qDBusRegisterMetaType<QList<QList<ushort> > >();
qDBusRegisterMetaType<QList<QList<int> > >();
qDBusRegisterMetaType<QList<QList<uint> > >();
qDBusRegisterMetaType<QList<QList<qlonglong> > >();
qDBusRegisterMetaType<QList<QList<qulonglong> > >();
qDBusRegisterMetaType<QList<QList<double> > >();
qDBusRegisterMetaType<QList<QList<QDBusObjectPath> > >();
qDBusRegisterMetaType<QList<QList<QDBusSignature> > >();
qDBusRegisterMetaType<QList<QVariantList> >();
qDBusRegisterMetaType<QMap<int, QString> >();
qDBusRegisterMetaType<QMap<QString, QString> >();
qDBusRegisterMetaType<QMap<QDBusObjectPath, QString> >();
qDBusRegisterMetaType<QMap<qlonglong, QDateTime> >();
qDBusRegisterMetaType<QMap<QDBusSignature, QString> >();
qDBusRegisterMetaType<MyStruct>();
qDBusRegisterMetaType<MyVariantMapStruct>();
qDBusRegisterMetaType<QList<MyVariantMapStruct> >();
qDBusRegisterMetaType<MyFileDescriptorStruct>();
qDBusRegisterMetaType<QList<MyFileDescriptorStruct> >();
}
#ifdef USE_PRIVATE_CODE
#include "private/qdbusintrospection_p.h"
// just to make it easier:
typedef QDBusIntrospection::Interfaces InterfaceMap;
typedef QDBusIntrospection::Objects ObjectMap;
typedef QDBusIntrospection::Arguments ArgumentList;
typedef QDBusIntrospection::Annotations AnnotationsMap;
typedef QDBusIntrospection::Methods MethodMap;
typedef QDBusIntrospection::Signals SignalMap;
typedef QDBusIntrospection::Properties PropertyMap;
Q_DECLARE_METATYPE(QDBusIntrospection::Method)
Q_DECLARE_METATYPE(QDBusIntrospection::Signal)
Q_DECLARE_METATYPE(QDBusIntrospection::Property)
Q_DECLARE_METATYPE(MethodMap)
Q_DECLARE_METATYPE(SignalMap)
Q_DECLARE_METATYPE(PropertyMap)
inline QDBusIntrospection::Argument arg(const char* type, const char *name = 0)
{
QDBusIntrospection::Argument retval;
retval.type = QLatin1String(type);
retval.name = QLatin1String(name);
return retval;
}
template<typename T>
inline QMap<QString, T>& operator<<(QMap<QString, T>& map, const T& m)
{ map.insert(m.name, m); return map; }
template<typename T>
inline QMultiMap<QString, T>& operator<<(QMultiMap<QString, T>& map, const T& m)
{ map.insert(m.name, m); return map; }
inline const char* mapName(const MethodMap&)
{ return "MethodMap"; }
inline const char* mapName(const SignalMap&)
{ return "SignalMap"; }
inline const char* mapName(const PropertyMap&)
{ return "PropertyMap"; }
QString printable(const QDBusIntrospection::Method& m)
{
QString result = "method " + m.name + "(";
foreach (QDBusIntrospection::Argument arg, m.inputArgs)
result += QString("in %1 %2, ")
.arg(arg.type, arg.name);
foreach (QDBusIntrospection::Argument arg, m.outputArgs)
result += QString("out %1 %2, ")
.arg(arg.type, arg.name);
AnnotationsMap::const_iterator it = m.annotations.begin();
for ( ; it != m.annotations.end(); ++it)
result += QString("%1 \"%2\", ").arg(it.key()).arg(it.value());
result += ")";
return result;
}
QString printable(const QDBusIntrospection::Signal& s)
{
QString result = "signal " + s.name + "(";
foreach (QDBusIntrospection::Argument arg, s.outputArgs)
result += QString("out %1 %2, ")
.arg(arg.type, arg.name);
AnnotationsMap::const_iterator it = s.annotations.begin();
for ( ; it != s.annotations.end(); ++it)
result += QString("%1 \"%2\", ").arg(it.key()).arg(it.value());
result += ")";
return result;
}
QString printable(const QDBusIntrospection::Property& p)
{
QString result;
if (p.access == QDBusIntrospection::Property::Read)
result = "property read %1 %2, ";
else if (p.access == QDBusIntrospection::Property::Write)
result = "property write %1 %2, ";
else
result = "property readwrite %1 %2, ";
result = result.arg(p.type, p.name);
AnnotationsMap::const_iterator it = p.annotations.begin();
for ( ; it != p.annotations.end(); ++it)
result += QString("%1 \"%2\", ").arg(it.key()).arg(it.value());
return result;
}
template<typename Map>
char* printableMap(const Map& map)
{
QString contents = "\n";
auto it = map.begin();
for ( ; it != map.end(); ++it) {
if (it.key() != it.value().name)
contents += it.value().name + ":";
contents += printable(it.value());
contents += ";\n";
}
QString result("%1(size = %2): {%3}");
return qstrdup(qPrintable(result
.arg(mapName(map))
.arg(map.size())
.arg(contents)));
}
QT_BEGIN_NAMESPACE
namespace QTest {
template<>
inline char* toString(const MethodMap& map)
{
return printableMap(map);
}
template<>
inline char* toString(const SignalMap& map)
{
return printableMap(map);
}
template<>
inline char* toString(const PropertyMap& map)
{
return printableMap(map);
}
}
QT_END_NAMESPACE
#endif
template<typename T>
bool compare(const T &t1, const T &t2)
{ return t1 == t2; }
template<>
bool compare(const QVariant &v1, const QVariant &v2);
bool compare(double d1, double d2)
{
if (qIsNaN(d1) && qIsNaN(d2))
return true;
return d1 == d2;
}
template<>
bool compare(const QString &s1, const QString &s2)
{
if (s1.isEmpty() && s2.isEmpty())
return true; // regardless of whether one of them is null
return s1 == s2;
}
template<>
bool compare(const QByteArray &ba1, const QByteArray &ba2)
{
if (ba1.isEmpty() && ba2.isEmpty())
return true; // regardless of whether one of them is null
return ba1 == ba2;
}
template<>
bool compare(const QDBusVariant &s1, const QDBusVariant &s2)
{
return compare(s1.variant(), s2.variant());
}
template<typename T>
bool compare(const QList<T> &l1, const QList<T> &l2)
{
if (l1.size() != l2.size())
return false;
typename QList<T>::ConstIterator it1 = l1.constBegin();
typename QList<T>::ConstIterator it2 = l2.constBegin();
typename QList<T>::ConstIterator end = l1.constEnd();
for ( ; it1 != end; ++it1, ++it2)
if (!compare(*it1, *it2))
return false;
return true;
}
template<typename Key, typename T>
bool compare(const QMap<Key, T> &m1, const QMap<Key, T> &m2)
{
if (m1.size() != m2.size())
return false;
typename QMap<Key, T>::ConstIterator i1 = m1.constBegin();
typename QMap<Key, T>::ConstIterator end = m1.constEnd();
for ( ; i1 != end; ++i1) {
typename QMap<Key, T>::ConstIterator i2 = m2.find(i1.key());
if (i2 == m2.constEnd())
return false;
if (!compare(*i1, *i2))
return false;
}
return true;
}
template<typename T>
inline bool compare(const QDBusArgument &arg, const QVariant &v2, T * = 0)
{
return compare(qdbus_cast<T>(arg), qvariant_cast<T>(v2));
}
bool compareToArgument(const QDBusArgument &arg, const QVariant &v2)
{
if (arg.currentSignature() != QDBusMetaType::typeToSignature(v2.metaType()))
return false;
// try to demarshall the arg according to v2
switch (v2.userType())
{
case QMetaType::Bool:
return compare<bool>(arg, v2);
case QMetaType::UChar:
return compare<uchar>(arg, v2);
case QMetaType::Short:
return compare<short>(arg, v2);
case QMetaType::UShort:
return compare<ushort>(arg, v2);
case QMetaType::Int:
return compare<int>(arg, v2);
case QMetaType::UInt:
return compare<uint>(arg, v2);
case QMetaType::LongLong:
return compare<qlonglong>(arg, v2);
case QMetaType::ULongLong:
return compare<qulonglong>(arg, v2);
case QMetaType::Double:
return compare<double>(arg, v2);
case QMetaType::QString:
return compare<QString>(arg, v2);
case QMetaType::QByteArray:
return compare<QByteArray>(arg, v2);
case QMetaType::QVariantList:
return compare<QVariantList>(arg, v2);
case QMetaType::QVariantMap:
return compare<QVariantMap>(arg, v2);
case QMetaType::QPoint:
return compare<QPoint>(arg, v2);
case QMetaType::QPointF:
return compare<QPointF>(arg, v2);
case QMetaType::QSize:
return compare<QSize>(arg, v2);
case QMetaType::QSizeF:
return compare<QSizeF>(arg, v2);
case QMetaType::QLine:
return compare<QLine>(arg, v2);
case QMetaType::QLineF:
return compare<QLineF>(arg, v2);
case QMetaType::QRect:
return compare<QRect>(arg, v2);
case QMetaType::QRectF:
return compare<QRectF>(arg, v2);
case QMetaType::QDate:
return compare<QDate>(arg, v2);
case QMetaType::QTime:
return compare<QTime>(arg, v2);
case QMetaType::QDateTime:
return compare<QDateTime>(arg, v2);
default:
int id = v2.userType();
if (id == qMetaTypeId<QDBusObjectPath>())
return compare<QDBusObjectPath>(arg, v2);
else if (id == qMetaTypeId<QDBusSignature>())
return compare<QDBusSignature>(arg, v2);
else if (id == qMetaTypeId<QDBusVariant>())
return compare<QDBusVariant>(arg, v2);
else if (id == qMetaTypeId<QList<bool> >())
return compare<QList<bool> >(arg, v2);
else if (id == qMetaTypeId<QList<short> >())
return compare<QList<short> >(arg, v2);
else if (id == qMetaTypeId<QList<ushort> >())
return compare<QList<ushort> >(arg, v2);
else if (id == qMetaTypeId<QList<int> >())
return compare<QList<int> >(arg, v2);
else if (id == qMetaTypeId<QList<uint> >())
return compare<QList<uint> >(arg, v2);
else if (id == qMetaTypeId<QList<qlonglong> >())
return compare<QList<qlonglong> >(arg, v2);
else if (id == qMetaTypeId<QList<qulonglong> >())
return compare<QList<qulonglong> >(arg, v2);
else if (id == qMetaTypeId<QList<double> >())
return compare<QList<double> >(arg, v2);
else if (id == qMetaTypeId<QList<QDBusObjectPath> >())
return compare<QList<QDBusObjectPath> >(arg, v2);
else if (id == qMetaTypeId<QList<QDBusSignature> >())
return compare<QList<QDBusSignature> >(arg, v2);
else if (id == qMetaTypeId<QList<QDBusUnixFileDescriptor> >())
return compare<QList<QDBusUnixFileDescriptor> >(arg, v2);
else if (id == qMetaTypeId<QList<QDateTime> >())
return compare<QList<QDateTime> >(arg, v2);
else if (id == qMetaTypeId<QMap<int, QString> >())
return compare<QMap<int, QString> >(arg, v2);
else if (id == qMetaTypeId<QMap<QString, QString> >())
return compare<QMap<QString, QString> >(arg, v2);
else if (id == qMetaTypeId<QMap<QDBusObjectPath, QString> >())
return compare<QMap<QDBusObjectPath, QString> >(arg, v2);
else if (id == qMetaTypeId<QMap<qlonglong, QDateTime> >())
return compare<QMap<qlonglong, QDateTime> >(arg, v2);
else if (id == qMetaTypeId<QMap<QDBusSignature, QString> >())
return compare<QMap<QDBusSignature, QString> >(arg, v2);
else if (id == qMetaTypeId<QList<QByteArray> >())
return compare<QList<QByteArray> >(arg, v2);
else if (id == qMetaTypeId<QList<QList<bool> > >())
return compare<QList<QList<bool> > >(arg, v2);
else if (id == qMetaTypeId<QList<QList<short> > >())
return compare<QList<QList<short> > >(arg, v2);
else if (id == qMetaTypeId<QList<QList<ushort> > >())
return compare<QList<QList<ushort> > >(arg, v2);
else if (id == qMetaTypeId<QList<QList<int> > >())
return compare<QList<QList<int> > >(arg, v2);
else if (id == qMetaTypeId<QList<QList<uint> > >())
return compare<QList<QList<uint> > >(arg, v2);
else if (id == qMetaTypeId<QList<QList<qlonglong> > >())
return compare<QList<QList<qlonglong> > >(arg, v2);
else if (id == qMetaTypeId<QList<QList<qulonglong> > >())
return compare<QList<QList<qulonglong> > >(arg, v2);
else if (id == qMetaTypeId<QList<QList<double> > >())
return compare<QList<QList<double> > >(arg, v2);
else if (id == qMetaTypeId<QList<QStringList> >())
return compare<QList<QStringList> >(arg, v2);
else if (id == qMetaTypeId<QList<QVariantList> >())
return compare<QList<QVariantList> >(arg, v2);
else if (id == qMetaTypeId<MyStruct>())
return compare<MyStruct>(arg, v2);
else if (id == qMetaTypeId<MyVariantMapStruct>())
return compare<MyVariantMapStruct>(arg, v2);
else if (id == qMetaTypeId<QList<MyVariantMapStruct> >())
return compare<QList<MyVariantMapStruct> >(arg, v2);
else if (id == qMetaTypeId<MyFileDescriptorStruct>())
return compare<MyFileDescriptorStruct>(arg, v2);
else if (id == qMetaTypeId<QList<MyFileDescriptorStruct> >())
return compare<QList<MyFileDescriptorStruct> >(arg, v2);
}
qWarning() << "Unexpected QVariant type" << v2.userType()
<< QByteArray(QDBusMetaType::typeToSignature(v2.metaType()))
<< v2.metaType().name();
return false;
}
template<> bool compare(const QVariant &v1, const QVariant &v2)
{
// v1 is the one that came from the network
// v2 is the one that we sent
if (v1.metaType() == QMetaType::fromType<QDBusArgument>())
// this argument has been left un-demarshalled
return compareToArgument(qvariant_cast<QDBusArgument>(v1), v2);
if (v1.userType() != v2.userType())
return false;
int id = v1.userType();
if (id == QMetaType::QVariantList)
return compare(v1.toList(), v2.toList());
else if (id == QMetaType::QVariantMap)
return compare(v1.toMap(), v2.toMap());
else if (id == QMetaType::QString)
return compare(v1.toString(), v2.toString());
else if (id == QMetaType::QByteArray)
return compare(v1.toByteArray(), v2.toByteArray());
else if (id == QMetaType::UChar)
return qvariant_cast<uchar>(v1) == qvariant_cast<uchar>(v2);
else if (id == QMetaType::Short)
return qvariant_cast<short>(v1) == qvariant_cast<short>(v2);
else if (id == QMetaType::UShort)
return qvariant_cast<ushort>(v1) == qvariant_cast<ushort>(v2);
else if (id == qMetaTypeId<QDBusObjectPath>())
return qvariant_cast<QDBusObjectPath>(v1).path() == qvariant_cast<QDBusObjectPath>(v2).path();
else if (id == qMetaTypeId<QDBusSignature>())
return qvariant_cast<QDBusSignature>(v1).signature() == qvariant_cast<QDBusSignature>(v2).signature();
else if (id == qMetaTypeId<QDBusUnixFileDescriptor>())
return compare(qvariant_cast<QDBusUnixFileDescriptor>(v1), qvariant_cast<QDBusUnixFileDescriptor>(v2));
else if (id == qMetaTypeId<QDBusVariant>())
return compare(qvariant_cast<QDBusVariant>(v1).variant(), qvariant_cast<QDBusVariant>(v2).variant());
else if (id == qMetaTypeId<QVariant>())
return compare(qvariant_cast<QVariant>(v1), qvariant_cast<QVariant>(v2));
else if (id == qMetaTypeId<QList<bool> >())
return qvariant_cast<QList<bool> >(v1) == qvariant_cast<QList<bool> >(v2);
else if (id == qMetaTypeId<QList<short> >())
return qvariant_cast<QList<short> >(v1) == qvariant_cast<QList<short> >(v2);
else if (id == qMetaTypeId<QList<ushort> >())
return qvariant_cast<QList<ushort> >(v1) == qvariant_cast<QList<ushort> >(v2);
else if (id == qMetaTypeId<QList<int> >())
return qvariant_cast<QList<int> >(v1) == qvariant_cast<QList<int> >(v2);
else if (id == qMetaTypeId<QList<uint> >())
return qvariant_cast<QList<uint> >(v1) == qvariant_cast<QList<uint> >(v2);
else if (id == qMetaTypeId<QList<qlonglong> >())
return qvariant_cast<QList<qlonglong> >(v1) == qvariant_cast<QList<qlonglong> >(v2);
else if (id == qMetaTypeId<QList<qulonglong> >())
return qvariant_cast<QList<qulonglong> >(v2) == qvariant_cast<QList<qulonglong> >(v2);
else if (id == qMetaTypeId<QList<double> >())
return compare(qvariant_cast<QList<double> >(v1), qvariant_cast<QList<double> >(v2));
else if (id == qMetaTypeId<QVariant>())
return compare(qvariant_cast<QVariant>(v1), qvariant_cast<QVariant>(v2));
else if (id == qMetaTypeId<QList<QList<bool> > >())
return qvariant_cast<QList<QList<bool> > >(v1) == qvariant_cast<QList<QList<bool> > >(v2);
else if (id == qMetaTypeId<QList<QList<short> > >())
return qvariant_cast<QList<QList<short> > >(v1) == qvariant_cast<QList<QList<short> > >(v2);
else if (id == qMetaTypeId<QList<QList<ushort> > >())
return qvariant_cast<QList<QList<ushort> > >(v1) == qvariant_cast<QList<QList<ushort> > >(v2);
else if (id == qMetaTypeId<QList<QList<int> > >())
return qvariant_cast<QList<QList<int> > >(v1) == qvariant_cast<QList<QList<int> > >(v2);
else if (id == qMetaTypeId<QList<QList<uint> > >())
return qvariant_cast<QList<QList<uint> > >(v1) == qvariant_cast<QList<QList<uint> > >(v2);
else if (id == qMetaTypeId<QList<QList<qlonglong> > >())
return qvariant_cast<QList<QList<qlonglong> > >(v1) == qvariant_cast<QList<QList<qlonglong> > >(v2);
else if (id == qMetaTypeId<QList<QList<qulonglong> > >())
return qvariant_cast<QList<QList<qulonglong> > >(v1) == qvariant_cast<QList<QList<qulonglong> > >(v2);
else if (id == qMetaTypeId<QList<QList<double> > >())
return compare(qvariant_cast<QList<QList<double> > >(v1), qvariant_cast<QList<QList<double> > >(v2));
else if (id == qMetaTypeId<QList<QStringList> >())
return qvariant_cast<QList<QStringList> >(v1) == qvariant_cast<QList<QStringList> >(v2);
else if (id == qMetaTypeId<QList<QByteArray> >())
return qvariant_cast<QList<QByteArray> >(v1) == qvariant_cast<QList<QByteArray> >(v2);
else if (id == qMetaTypeId<QList<QVariantList> >())
return compare(qvariant_cast<QList<QVariantList> >(v1), qvariant_cast<QList<QVariantList> >(v2));
else if (id == qMetaTypeId<QMap<int, QString> >())
return compare(qvariant_cast<QMap<int, QString> >(v1), qvariant_cast<QMap<int, QString> >(v2));
else if (id == qMetaTypeId<QMap<QString, QString> >()) // ssmap
return compare(qvariant_cast<QMap<QString, QString> >(v1), qvariant_cast<QMap<QString, QString> >(v2));
else if (id == qMetaTypeId<QMap<QDBusObjectPath, QString> >())
return compare(qvariant_cast<QMap<QDBusObjectPath, QString> >(v1), qvariant_cast<QMap<QDBusObjectPath, QString> >(v2));
else if (id == qMetaTypeId<QMap<qlonglong, QDateTime> >()) // lldtmap
return compare(qvariant_cast<QMap<qint64, QDateTime> >(v1), qvariant_cast<QMap<qint64, QDateTime> >(v2));
else if (id == qMetaTypeId<QMap<QDBusSignature, QString> >())
return compare(qvariant_cast<QMap<QDBusSignature, QString> >(v1), qvariant_cast<QMap<QDBusSignature, QString> >(v2));
else if (id == qMetaTypeId<MyStruct>()) // (is)
return qvariant_cast<MyStruct>(v1) == qvariant_cast<MyStruct>(v2);
else if (id < int(QMetaType::User)) // yes, v1.type()
// QVariant can compare
return v1 == v2;
else {
qWarning() << "Please write a comparison case for type" << v1.typeName();
return false; // unknown type
}
}

View File

@ -0,0 +1,32 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbusmarshall Test:
#####################################################################
qt_internal_add_test(tst_qdbusmarshall
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../"
SOURCES
../tst_qdbusmarshall.cpp
LIBRARIES
Qt::CorePrivate
Qt::DBusPrivate
)
## Scopes:
#####################################################################
# This test case interacts with dbus code directly via the private
# headers. The include path is also not exposed via Qt:DBus.
qt_internal_extend_target(tst_qdbusmarshall CONDITION QT_FEATURE_dbus_linked
DEFINES
QT_LINKED_LIBDBUS
LIBRARIES
dbus-1
)
qt_internal_extend_target(tst_qdbusmarshall CONDITION NOT QT_FEATURE_dbus_linked
SOURCES
../../../../../src/dbus/qdbus_symbols.cpp
)

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## qpong Binary:
#####################################################################
qt_internal_add_executable(qpong
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
SOURCES
qpong.cpp
LIBRARIES
Qt::DBus
)

View File

@ -0,0 +1,51 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QCoreApplication>
#include <QDBusMessage>
#include <QDBusConnection>
static const char serviceName[] = "org.qtproject.autotests.qpong";
static const char objectPath[] = "/org/qtproject/qpong";
//static const char *interfaceName = serviceName;
class Pong: public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.qtproject.autotests.qpong")
public slots:
void ping(QDBusMessage msg)
{
msg.setDelayedReply(true);
if (!QDBusConnection::sessionBus().send(msg.createReply(msg.arguments())))
exit(1);
}
void quit()
{
qApp->quit();
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QDBusConnection con = QDBusConnection::sessionBus();
if (!con.isConnected())
exit(1);
if (!con.registerService(serviceName))
exit(2);
Pong pong;
con.registerObject(objectPath, &pong, QDBusConnection::ExportAllSlots);
printf("ready.\n");
fflush(stdout);
return app.exec();
}
#include "qpong.moc"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbusmetaobject Test:
#####################################################################
qt_internal_add_test(tst_qdbusmetaobject
SOURCES
tst_qdbusmetaobject.cpp
LIBRARIES
Qt::DBusPrivate
)

View File

@ -0,0 +1,877 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QCoreApplication>
#include <QMetaType>
#include <QDBusArgument>
#include <QDBusMetaType>
#include <QDBusError>
#include <QDBusUnixFileDescriptor>
#include <private/qdbusmetaobject_p.h>
class tst_QDBusMetaObject: public QObject
{
Q_OBJECT
QHash<QString, QDBusMetaObject *> map;
public slots:
void init();
private slots:
void initTestCase();
void types_data();
void types();
void methods_data();
void methods();
void _signals_data();
void _signals();
void properties_data();
void properties();
};
typedef QPair<QString,QString> StringPair;
struct Struct1 { }; // (s)
struct Struct4 // (ssa(ss)sayasx)
{
QString m1;
QString m2;
QList<StringPair> m3;
QString m4;
QByteArray m5;
QStringList m6;
qlonglong m7;
};
Q_DECLARE_METATYPE(Struct1)
Q_DECLARE_METATYPE(Struct4)
Q_DECLARE_METATYPE(StringPair)
Q_DECLARE_METATYPE(const QMetaObject*)
QT_BEGIN_NAMESPACE
QDBusArgument &operator<<(QDBusArgument &arg, const Struct1 &)
{
arg.beginStructure();
arg << QString();
arg.endStructure();
return arg;
}
QDBusArgument &operator<<(QDBusArgument &arg, const StringPair &s)
{
arg.beginStructure();
arg << s.first << s.second;
arg.endStructure();
return arg;
}
QDBusArgument &operator<<(QDBusArgument &arg, const Struct4 &s)
{
arg.beginStructure();
arg << s.m1 << s.m2 << s.m3 << s.m4 << s.m5 << s.m6 << s.m7;
arg.endStructure();
return arg;
}
const QDBusArgument &operator>>(const QDBusArgument &arg, Struct1 &)
{ return arg; }
const QDBusArgument &operator>>(const QDBusArgument &arg, Struct4 &)
{ return arg; }
const QDBusArgument &operator>>(const QDBusArgument &arg, StringPair &)
{ return arg; }
QT_END_NAMESPACE
void tst_QDBusMetaObject::initTestCase()
{
qDBusRegisterMetaType<Struct1>();
qDBusRegisterMetaType<Struct4>();
qDBusRegisterMetaType<StringPair>();
qDBusRegisterMetaType<QList<Struct1> >();
qDBusRegisterMetaType<QList<Struct4> >();
}
void tst_QDBusMetaObject::init()
{
qDeleteAll(map);
map.clear();
}
// test classes
class TypesTest1: public QObject
{
Q_OBJECT
signals:
void signal(uchar);
};
const char TypesTest1_xml[] =
"<signal name=\"signal\"><arg type=\"y\"/></signal>";
class TypesTest2: public QObject
{
Q_OBJECT
signals:
void signal(bool);
};
const char TypesTest2_xml[] =
"<signal name=\"signal\"><arg type=\"b\"/></signal>";
class TypesTest3: public QObject
{
Q_OBJECT
signals:
void signal(short);
};
const char TypesTest3_xml[] =
"<signal name=\"signal\"><arg type=\"n\"/></signal>";
class TypesTest4: public QObject
{
Q_OBJECT
signals:
void signal(ushort);
};
const char TypesTest4_xml[] =
"<signal name=\"signal\"><arg type=\"q\"/></signal>";
class TypesTest5: public QObject
{
Q_OBJECT
signals:
void signal(int);
};
const char TypesTest5_xml[] =
"<signal name=\"signal\"><arg type=\"i\"/></signal>";
class TypesTest6: public QObject
{
Q_OBJECT
signals:
void signal(uint);
};
const char TypesTest6_xml[] =
"<signal name=\"signal\"><arg type=\"u\"/></signal>";
class TypesTest7: public QObject
{
Q_OBJECT
signals:
void signal(qlonglong);
};
const char TypesTest7_xml[] =
"<signal name=\"signal\"><arg type=\"x\"/></signal>";
class TypesTest8: public QObject
{
Q_OBJECT
signals:
void signal(qulonglong);
};
const char TypesTest8_xml[] =
"<signal name=\"signal\"><arg type=\"t\"/></signal>";
class TypesTest9: public QObject
{
Q_OBJECT
signals:
void signal(double);
};
const char TypesTest9_xml[] =
"<signal name=\"signal\"><arg type=\"d\"/></signal>";
class TypesTest10: public QObject
{
Q_OBJECT
signals:
void signal(QString);
};
const char TypesTest10_xml[] =
"<signal name=\"signal\"><arg type=\"s\"/></signal>";
class TypesTest11: public QObject
{
Q_OBJECT
signals:
void signal(QDBusObjectPath);
};
const char TypesTest11_xml[] =
"<signal name=\"signal\"><arg type=\"o\"/></signal>";
class TypesTest12: public QObject
{
Q_OBJECT
signals:
void signal(QDBusSignature);
};
const char TypesTest12_xml[] =
"<signal name=\"signal\"><arg type=\"g\"/></signal>";
class TypesTest13: public QObject
{
Q_OBJECT
signals:
void signal(QDBusVariant);
};
const char TypesTest13_xml[] =
"<signal name=\"signal\"><arg type=\"v\"/></signal>";
class TypesTest14: public QObject
{
Q_OBJECT
signals:
void signal(QStringList);
};
const char TypesTest14_xml[] =
"<signal name=\"signal\"><arg type=\"as\"/></signal>";
class TypesTest15: public QObject
{
Q_OBJECT
signals:
void signal(QByteArray);
};
const char TypesTest15_xml[] =
"<signal name=\"signal\"><arg type=\"ay\"/></signal>";
class TypesTest16: public QObject
{
Q_OBJECT
signals:
void signal(StringPair);
};
const char TypesTest16_xml[] =
"<signal name=\"signal\"><arg type=\"(ss)\"/>"
"<annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"StringPair\"></signal>";
class TypesTest17: public QObject
{
Q_OBJECT
signals:
void signal(Struct1);
};
const char TypesTest17_xml[] =
"<signal name=\"signal\"><arg type=\"(s)\"/>"
"<annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"Struct1\"></signal>";
class TypesTest18: public QObject
{
Q_OBJECT
signals:
void signal(Struct4);
};
const char TypesTest18_xml[] =
"<signal name=\"signal\"><arg type=\"(ssa(ss)sayasx)\"/>"
"<annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"Struct4\"></signal>";
class TypesTest19: public QObject
{
Q_OBJECT
signals:
void signal(QVariantList);
};
const char TypesTest19_xml[] =
"<signal name=\"signal\"><arg type=\"av\"/>"
"<annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QVariantList\"></signal>";
class TypesTest20: public QObject
{
Q_OBJECT
signals:
void signal(QVariantMap);
};
const char TypesTest20_xml[] =
"<signal name=\"signal\"><arg type=\"a{sv}\"/>"
"<annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QVariantMap\"></signal>";
const char TypesTest20_oldxml[] =
"<signal name=\"signal\"><arg type=\"a{sv}\"/>"
"<annotation name=\"com.trolltech.QtDBus.QtTypeName.Out0\" value=\"QVariantMap\"></signal>";
void tst_QDBusMetaObject::types_data()
{
QTest::addColumn<const QMetaObject *>("metaobject");
QTest::addColumn<QString>("xml");
QTest::newRow("byte") << &TypesTest1::staticMetaObject << QString(TypesTest1_xml);
QTest::newRow("bool") << &TypesTest2::staticMetaObject << QString(TypesTest2_xml);
QTest::newRow("short") << &TypesTest3::staticMetaObject << QString(TypesTest3_xml);
QTest::newRow("ushort") << &TypesTest4::staticMetaObject << QString(TypesTest4_xml);
QTest::newRow("int") << &TypesTest5::staticMetaObject << QString(TypesTest5_xml);
QTest::newRow("uint") << &TypesTest6::staticMetaObject << QString(TypesTest6_xml);
QTest::newRow("qlonglong") << &TypesTest7::staticMetaObject << QString(TypesTest7_xml);
QTest::newRow("qulonglong") << &TypesTest8::staticMetaObject << QString(TypesTest8_xml);
QTest::newRow("double") << &TypesTest9::staticMetaObject << QString(TypesTest9_xml);
QTest::newRow("QString") << &TypesTest10::staticMetaObject << QString(TypesTest10_xml);
QTest::newRow("QDBusObjectPath") << &TypesTest11::staticMetaObject << QString(TypesTest11_xml);
QTest::newRow("QDBusSignature") << &TypesTest12::staticMetaObject << QString(TypesTest12_xml);
QTest::newRow("QDBusVariant") << &TypesTest13::staticMetaObject << QString(TypesTest13_xml);
QTest::newRow("QStringList") << &TypesTest14::staticMetaObject << QString(TypesTest14_xml);
QTest::newRow("QByteArray") << &TypesTest15::staticMetaObject << QString(TypesTest15_xml);
QTest::newRow("StringPair") << &TypesTest16::staticMetaObject << QString(TypesTest16_xml);
QTest::newRow("Struct1") << &TypesTest17::staticMetaObject << QString(TypesTest17_xml);
QTest::newRow("Struct4") << &TypesTest18::staticMetaObject << QString(TypesTest18_xml);
QTest::newRow("QVariantList") << &TypesTest19::staticMetaObject << QString(TypesTest19_xml);
QTest::newRow("QVariantMap") << &TypesTest20::staticMetaObject << QString(TypesTest20_xml);
QTest::newRow("QVariantMap-oldannotation") << &TypesTest20::staticMetaObject << QString(TypesTest20_oldxml);
}
void tst_QDBusMetaObject::types()
{
QFETCH(const QMetaObject*, metaobject);
QFETCH(QString, xml);
// add the rest of the XML tags
xml = QString("<node><interface name=\"local.Interface\">%1</interface></node>")
.arg(xml);
QDBusError error;
const QScopedPointer<QDBusMetaObject> result(QDBusMetaObject::createMetaObject("local.Interface", xml, map, error));
QVERIFY2(result, qPrintable(error.message()));
QCOMPARE(result->enumeratorCount(), 0);
QCOMPARE(result->classInfoCount(), 0);
// compare the meta objects
QCOMPARE(result->methodCount() - result->methodOffset(),
metaobject->methodCount() - metaobject->methodOffset());
QCOMPARE(result->propertyCount() - result->propertyOffset(),
metaobject->propertyCount() - metaobject->propertyOffset());
for (int i = metaobject->methodOffset(); i < metaobject->methodCount(); ++i) {
QMetaMethod expected = metaobject->method(i);
int methodIdx = result->indexOfMethod(expected.methodSignature().constData());
QVERIFY(methodIdx != -1);
QMetaMethod constructed = result->method(methodIdx);
QCOMPARE(int(constructed.access()), int(expected.access()));
QCOMPARE(int(constructed.methodType()), int(expected.methodType()));
QCOMPARE(constructed.name(), expected.name());
QCOMPARE(constructed.parameterCount(), expected.parameterCount());
QCOMPARE(constructed.parameterNames(), expected.parameterNames());
for (int j = 0; j < constructed.parameterCount(); ++j)
QCOMPARE(constructed.parameterType(j), expected.parameterType(j));
QCOMPARE(constructed.tag(), expected.tag());
QCOMPARE(constructed.typeName(), expected.typeName());
QCOMPARE(constructed.returnType(), expected.returnType());
}
for (int i = metaobject->propertyOffset(); i < metaobject->propertyCount(); ++i) {
QMetaProperty expected = metaobject->property(i);
int propIdx = result->indexOfProperty(expected.name());
QVERIFY(propIdx != -1);
QMetaProperty constructed = result->property(propIdx);
QCOMPARE(constructed.isDesignable(), expected.isDesignable());
QCOMPARE(constructed.isEnumType(), expected.isEnumType());
QCOMPARE(constructed.isFlagType(), expected.isFlagType());
QCOMPARE(constructed.isReadable(), expected.isReadable());
QCOMPARE(constructed.isResettable(), expected.isResettable());
QCOMPARE(constructed.isScriptable(), expected.isScriptable());
QCOMPARE(constructed.isStored(), expected.isStored());
QCOMPARE(constructed.isUser(), expected.isUser());
QCOMPARE(constructed.isWritable(), expected.isWritable());
QCOMPARE(constructed.typeName(), expected.typeName());
QCOMPARE(constructed.metaType(), expected.metaType());
QCOMPARE(constructed.userType(), expected.userType());
}
}
class MethodTest1: public QObject
{
Q_OBJECT
public slots:
void method() { }
};
const char MethodTest1_xml[] =
"<method name=\"method\" />";
class MethodTest2: public QObject
{
Q_OBJECT
public slots:
void method(int) { }
};
const char MethodTest2_xml[] =
"<method name=\"method\"><arg direction=\"in\" type=\"i\"/></method>";
class MethodTest3: public QObject
{
Q_OBJECT
public slots:
void method(int input0) { Q_UNUSED(input0); }
};
const char MethodTest3_xml[] =
"<method name=\"method\"><arg direction=\"in\" type=\"i\" name=\"input0\"/></method>";
class MethodTest4: public QObject
{
Q_OBJECT
public slots:
int method() { return 0; }
};
const char MethodTest4_xml[] =
"<method name=\"method\"><arg direction=\"out\" type=\"i\"/></method>";
const char MethodTest4_xml2[] =
"<method name=\"method\"><arg direction=\"out\" type=\"i\" name=\"thisShouldNeverBeSeen\"/></method>";
class MethodTest5: public QObject
{
Q_OBJECT
public slots:
int method(int input0) { return input0; }
};
const char MethodTest5_xml[] =
"<method name=\"method\">"
"<arg direction=\"in\" type=\"i\" name=\"input0\"/>"
"<arg direction=\"out\" type=\"i\"/>"
"</method>";
class MethodTest6: public QObject
{
Q_OBJECT
public slots:
int method(int input0, int input1) { Q_UNUSED(input0); return input1; }
};
const char MethodTest6_xml[] =
"<method name=\"method\">"
"<arg direction=\"in\" type=\"i\" name=\"input0\"/>"
"<arg direction=\"out\" type=\"i\"/>"
"<arg direction=\"in\" type=\"i\" name=\"input1\"/>"
"</method>";
class MethodTest7: public QObject
{
Q_OBJECT
public slots:
int method(int input0, int input1, int &output1) { output1 = input1; return input0; }
};
const char MethodTest7_xml[] =
"<method name=\"method\">"
"<arg direction=\"in\" type=\"i\" name=\"input0\"/>"
"<arg direction=\"in\" type=\"i\" name=\"input1\"/>"
"<arg direction=\"out\" type=\"i\"/>"
"<arg direction=\"out\" type=\"i\" name=\"output1\"/>"
"</method>";
class MethodTest8: public QObject
{
Q_OBJECT
public slots:
int method(int input0, int input1, int &output1, int &output2) { output1 = output2 = input1; return input0; }
};
const char MethodTest8_xml[] =
"<method name=\"method\">"
"<arg direction=\"in\" type=\"i\" name=\"input0\"/>"
"<arg direction=\"in\" type=\"i\" name=\"input1\"/>"
"<arg direction=\"out\" type=\"i\"/>"
"<arg direction=\"out\" type=\"i\" name=\"output1\"/>"
"<arg direction=\"out\" type=\"i\" name=\"output2\"/>"
"</method>";
class MethodTest9: public QObject
{
Q_OBJECT
public slots:
Q_NOREPLY void method(int) { }
};
const char MethodTest9_xml[] =
"<method name=\"method\">"
"<arg direction=\"in\" type=\"i\"/>"
"<annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>"
"</method>";
void tst_QDBusMetaObject::methods_data()
{
QTest::addColumn<const QMetaObject *>("metaobject");
QTest::addColumn<QString>("xml");
QTest::newRow("void-void") << &MethodTest1::staticMetaObject << QString(MethodTest1_xml);
QTest::newRow("void-int") << &MethodTest2::staticMetaObject << QString(MethodTest2_xml);
QTest::newRow("void-int-with-name") << &MethodTest3::staticMetaObject << QString(MethodTest3_xml);
QTest::newRow("int-void") << &MethodTest4::staticMetaObject << QString(MethodTest4_xml);
QTest::newRow("int-void2") << &MethodTest4::staticMetaObject << QString(MethodTest4_xml2);
QTest::newRow("int-int") << &MethodTest5::staticMetaObject << QString(MethodTest5_xml);
QTest::newRow("int-int,int") << &MethodTest6::staticMetaObject << QString(MethodTest6_xml);
QTest::newRow("int,int-int,int") << &MethodTest7::staticMetaObject << QString(MethodTest7_xml);
QTest::newRow("int,int,int-int,int") << &MethodTest8::staticMetaObject << QString(MethodTest8_xml);
QTest::newRow("Q_ASYNC") << &MethodTest9::staticMetaObject << QString(MethodTest9_xml);
}
void tst_QDBusMetaObject::methods()
{
types();
}
class SignalTest1: public QObject
{
Q_OBJECT
signals:
void signal();
};
const char SignalTest1_xml[] =
"<signal name=\"signal\" />";
class SignalTest2: public QObject
{
Q_OBJECT
signals:
void signal(int);
};
const char SignalTest2_xml[] =
"<signal name=\"signal\"><arg type=\"i\"/></signal>";
class SignalTest3: public QObject
{
Q_OBJECT
signals:
void signal(int output0);
};
const char SignalTest3_xml[] =
"<signal name=\"signal\"><arg type=\"i\" name=\"output0\"/></signal>";
class SignalTest4: public QObject
{
Q_OBJECT
signals:
void signal(int output0, int);
};
const char SignalTest4_xml[] =
"<signal name=\"signal\"><arg type=\"i\" name=\"output0\"/><arg type=\"i\"/></signal>";
void tst_QDBusMetaObject::_signals_data()
{
QTest::addColumn<const QMetaObject *>("metaobject");
QTest::addColumn<QString>("xml");
QTest::newRow("empty") << &SignalTest1::staticMetaObject << QString(SignalTest1_xml);
QTest::newRow("int") << &SignalTest2::staticMetaObject << QString(SignalTest2_xml);
QTest::newRow("int output0") << &SignalTest3::staticMetaObject << QString(SignalTest3_xml);
QTest::newRow("int output0,int") << &SignalTest4::staticMetaObject << QString(SignalTest4_xml);
}
void tst_QDBusMetaObject::_signals()
{
types();
}
class PropertyTest1: public QObject
{
Q_OBJECT
Q_PROPERTY(int property READ property)
public:
int property() { return 0; }
void setProperty(int) { }
};
const char PropertyTest1_xml[] =
"<property name=\"property\" type=\"i\" access=\"read\"/>";
class PropertyTest2: public QObject
{
Q_OBJECT
Q_PROPERTY(int property READ property WRITE setProperty)
public:
int property() { return 0; }
void setProperty(int) { }
};
const char PropertyTest2_xml[] =
"<property name=\"property\" type=\"i\" access=\"readwrite\"/>";
class PropertyTest3: public QObject
{
Q_OBJECT
Q_PROPERTY(int property WRITE setProperty)
public:
int property() { return 0; }
void setProperty(int) { }
};
const char PropertyTest3_xml[] =
"<property name=\"property\" type=\"i\" access=\"write\"/>";
class PropertyTest4: public QObject
{
Q_OBJECT
Q_PROPERTY(Struct1 property WRITE setProperty)
public:
Struct1 property() { return Struct1(); }
void setProperty(Struct1) { }
};
const char PropertyTest4_xml[] =
"<property name=\"property\" type=\"(s)\" access=\"write\">"
"<annotation name=\"org.qtproject.QtDBus.QtTypeName\" value=\"Struct1\"/>"
"</property>";
class PropertyTest_b: public QObject
{
Q_OBJECT
Q_PROPERTY(bool property READ property WRITE setProperty)
public:
bool property() { return false; }
void setProperty(bool) { }
};
const char PropertyTest_b_xml[] =
"<property name=\"property\" type=\"b\" access=\"readwrite\"/>";
class PropertyTest_y: public QObject
{
Q_OBJECT
Q_PROPERTY(uchar property READ property WRITE setProperty)
public:
uchar property() { return 0; }
void setProperty(uchar) { }
};
const char PropertyTest_y_xml[] =
"<property name=\"property\" type=\"y\" access=\"readwrite\"/>";
class PropertyTest_n: public QObject
{
Q_OBJECT
Q_PROPERTY(short property READ property WRITE setProperty)
public:
short property() { return 0; }
void setProperty(short) { }
};
const char PropertyTest_n_xml[] =
"<property name=\"property\" type=\"n\" access=\"readwrite\"/>";
class PropertyTest_q: public QObject
{
Q_OBJECT
Q_PROPERTY(ushort property READ property WRITE setProperty)
public:
ushort property() { return 0; }
void setProperty(ushort) { }
};
const char PropertyTest_q_xml[] =
"<property name=\"property\" type=\"q\" access=\"readwrite\"/>";
class PropertyTest_u: public QObject
{
Q_OBJECT
Q_PROPERTY(uint property READ property WRITE setProperty)
public:
uint property() { return 0; }
void setProperty(uint) { }
};
const char PropertyTest_u_xml[] =
"<property name=\"property\" type=\"u\" access=\"readwrite\"/>";
class PropertyTest_x: public QObject
{
Q_OBJECT
Q_PROPERTY(qlonglong property READ property WRITE setProperty)
public:
qlonglong property() { return 0; }
void setProperty(qlonglong) { }
};
const char PropertyTest_x_xml[] =
"<property name=\"property\" type=\"x\" access=\"readwrite\"/>";
class PropertyTest_t: public QObject
{
Q_OBJECT
Q_PROPERTY(qulonglong property READ property WRITE setProperty)
public:
qulonglong property() { return 0; }
void setProperty(qulonglong) { }
};
const char PropertyTest_t_xml[] =
"<property name=\"property\" type=\"t\" access=\"readwrite\"/>";
class PropertyTest_d: public QObject
{
Q_OBJECT
Q_PROPERTY(double property READ property WRITE setProperty)
public:
double property() { return 0; }
void setProperty(double) { }
};
const char PropertyTest_d_xml[] =
"<property name=\"property\" type=\"d\" access=\"readwrite\"/>";
class PropertyTest_s: public QObject
{
Q_OBJECT
Q_PROPERTY(QString property READ property WRITE setProperty)
public:
QString property() { return QString(); }
void setProperty(QString) { }
};
const char PropertyTest_s_xml[] =
"<property name=\"property\" type=\"s\" access=\"readwrite\"/>";
class PropertyTest_v: public QObject
{
Q_OBJECT
Q_PROPERTY(QDBusVariant property READ property WRITE setProperty)
public:
QDBusVariant property() { return QDBusVariant(); }
void setProperty(QDBusVariant) { }
};
const char PropertyTest_v_xml[] =
"<property name=\"property\" type=\"v\" access=\"readwrite\"/>";
class PropertyTest_o: public QObject
{
Q_OBJECT
Q_PROPERTY(QDBusObjectPath property READ property WRITE setProperty)
public:
QDBusObjectPath property() { return QDBusObjectPath(); }
void setProperty(QDBusObjectPath) { }
};
const char PropertyTest_o_xml[] =
"<property name=\"property\" type=\"o\" access=\"readwrite\"/>";
class PropertyTest_g: public QObject
{
Q_OBJECT
Q_PROPERTY(QDBusSignature property READ property WRITE setProperty)
public:
QDBusSignature property() { return QDBusSignature(); }
void setProperty(QDBusSignature) { }
};
const char PropertyTest_g_xml[] =
"<property name=\"property\" type=\"g\" access=\"readwrite\"/>";
class PropertyTest_h: public QObject
{
Q_OBJECT
Q_PROPERTY(QDBusUnixFileDescriptor property READ property WRITE setProperty)
public:
QDBusUnixFileDescriptor property() { return QDBusUnixFileDescriptor(); }
void setProperty(QDBusUnixFileDescriptor) { }
};
const char PropertyTest_h_xml[] =
"<property name=\"property\" type=\"h\" access=\"readwrite\"/>";
class PropertyTest_ay: public QObject
{
Q_OBJECT
Q_PROPERTY(QByteArray property READ property WRITE setProperty)
public:
QByteArray property() { return QByteArray(); }
void setProperty(QByteArray) { }
};
const char PropertyTest_ay_xml[] =
"<property name=\"property\" type=\"ay\" access=\"readwrite\"/>";
class PropertyTest_as: public QObject
{
Q_OBJECT
Q_PROPERTY(QStringList property READ property WRITE setProperty)
public:
QStringList property() { return QStringList(); }
void setProperty(QStringList) { }
};
const char PropertyTest_as_xml[] =
"<property name=\"property\" type=\"as\" access=\"readwrite\"/>";
class PropertyTest_av: public QObject
{
Q_OBJECT
Q_PROPERTY(QVariantList property READ property WRITE setProperty)
public:
QVariantList property() { return QVariantList(); }
void setProperty(QVariantList) { }
};
const char PropertyTest_av_xml[] =
"<property name=\"property\" type=\"av\" access=\"readwrite\"/>";
class PropertyTest_ao: public QObject
{
Q_OBJECT
Q_PROPERTY(QList<QDBusObjectPath> property READ property WRITE setProperty)
public:
QList<QDBusObjectPath> property() { return QList<QDBusObjectPath>(); }
void setProperty(QList<QDBusObjectPath>) { }
};
const char PropertyTest_ao_xml[] =
"<property name=\"property\" type=\"ao\" access=\"readwrite\"/>";
class PropertyTest_ag: public QObject
{
Q_OBJECT
Q_PROPERTY(QList<QDBusSignature> property READ property WRITE setProperty)
public:
QList<QDBusSignature> property() { return QList<QDBusSignature>(); }
void setProperty(QList<QDBusSignature>) { }
};
const char PropertyTest_ag_xml[] =
"<property name=\"property\" type=\"ag\" access=\"readwrite\"/>";
void tst_QDBusMetaObject::properties_data()
{
QTest::addColumn<const QMetaObject *>("metaobject");
QTest::addColumn<QString>("xml");
QTest::newRow("read") << &PropertyTest1::staticMetaObject << QString(PropertyTest1_xml);
QTest::newRow("readwrite") << &PropertyTest2::staticMetaObject << QString(PropertyTest2_xml);
QTest::newRow("write") << &PropertyTest3::staticMetaObject << QString(PropertyTest3_xml);
QTest::newRow("customtype") << &PropertyTest4::staticMetaObject << QString(PropertyTest4_xml);
QTest::newRow("bool") << &PropertyTest_b::staticMetaObject << QString(PropertyTest_b_xml);
QTest::newRow("byte") << &PropertyTest_y::staticMetaObject << QString(PropertyTest_y_xml);
QTest::newRow("short") << &PropertyTest_n::staticMetaObject << QString(PropertyTest_n_xml);
QTest::newRow("ushort") << &PropertyTest_q::staticMetaObject << QString(PropertyTest_q_xml);
QTest::newRow("uint") << &PropertyTest_u::staticMetaObject << QString(PropertyTest_u_xml);
QTest::newRow("qlonglong") << &PropertyTest_x::staticMetaObject << QString(PropertyTest_x_xml);
QTest::newRow("qulonglong") << &PropertyTest_t::staticMetaObject << QString(PropertyTest_t_xml);
QTest::newRow("double") << &PropertyTest_d::staticMetaObject << QString(PropertyTest_d_xml);
QTest::newRow("QString") << &PropertyTest_s::staticMetaObject << QString(PropertyTest_s_xml);
QTest::newRow("QDBusVariant") << &PropertyTest_v::staticMetaObject << QString(PropertyTest_v_xml);
QTest::newRow("QDBusObjectPath") << &PropertyTest_o::staticMetaObject << QString(PropertyTest_o_xml);
QTest::newRow("QDBusSignature") << &PropertyTest_g::staticMetaObject << QString(PropertyTest_g_xml);
QTest::newRow("QDBusUnixFileDescriptor") << &PropertyTest_h::staticMetaObject << QString(PropertyTest_h_xml);
QTest::newRow("QByteArray") << &PropertyTest_ay::staticMetaObject << QString(PropertyTest_ay_xml);
QTest::newRow("QStringList") << &PropertyTest_as::staticMetaObject << QString(PropertyTest_as_xml);
QTest::newRow("QVariantList") << &PropertyTest_av::staticMetaObject << QString(PropertyTest_av_xml);
QTest::newRow("QList<QDBusObjectPath>") << &PropertyTest_ao::staticMetaObject << QString(PropertyTest_ao_xml);
QTest::newRow("QList<QDBusSignature>") << &PropertyTest_ag::staticMetaObject << QString(PropertyTest_ag_xml);
}
void tst_QDBusMetaObject::properties()
{
types();
}
QTEST_MAIN(tst_QDBusMetaObject)
#include "tst_qdbusmetaobject.moc"

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbusmetatype Test:
#####################################################################
qt_internal_add_test(tst_qdbusmetatype
SOURCES
tst_qdbusmetatype.cpp
LIBRARIES
Qt::DBus
)

View File

@ -0,0 +1,399 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QCoreApplication>
#include <QMetaType>
#include <QDBusArgument>
#include <QDBusMetaType>
class tst_QDBusMetaType: public QObject
{
Q_OBJECT
public:
int intStringMap;
int stringStringMap;
int stringStruct1Map;
private slots:
void initTestCase();
void staticTypes_data();
void staticTypes();
void dynamicTypes_data();
void dynamicTypes();
void invalidTypes_data();
void invalidTypes();
};
typedef QPair<QString,QString> StringPair;
struct Struct1 { }; // (s)
struct Struct2 { }; // (sos)
struct Struct3 { }; // (sas)
struct Struct4 // (ssa(ss)sayasx)
{
QString m1;
QString m2;
QList<StringPair> m3;
QString m4;
QByteArray m5;
QStringList m6;
qlonglong m7;
};
struct Struct5 // a{sa{sv}} - non-standard outer struct is used as a local
{ // container, see marshalling operator below.
QVariantMap m1;
QVariantMap m2;
QVariantMap m3;
};
struct Struct6 // av - non-standard outer struct is used as a local container,
{ // see marshalling operator below.
QVariant v1;
QVariant v2;
QVariant v3;
};
struct Invalid0 { }; // empty
struct Invalid1 { }; // s
struct Invalid2 { }; // o
struct Invalid3 { }; // as
struct Invalid4 { }; // ay
struct Invalid5 { }; // ii
struct Invalid6 { }; // <invalid>
struct Invalid7 { }; // (<invalid>)
Q_DECLARE_METATYPE(Struct1)
Q_DECLARE_METATYPE(Struct2)
Q_DECLARE_METATYPE(Struct3)
Q_DECLARE_METATYPE(Struct4)
Q_DECLARE_METATYPE(StringPair)
Q_DECLARE_METATYPE(Struct5)
Q_DECLARE_METATYPE(Struct6)
Q_DECLARE_METATYPE(Invalid0)
Q_DECLARE_METATYPE(Invalid1)
Q_DECLARE_METATYPE(Invalid2)
Q_DECLARE_METATYPE(Invalid3)
Q_DECLARE_METATYPE(Invalid4)
Q_DECLARE_METATYPE(Invalid5)
Q_DECLARE_METATYPE(Invalid6)
Q_DECLARE_METATYPE(Invalid7)
typedef QMap<int, QString> IntStringMap;
typedef QMap<QString, QString> StringStringMap;
typedef QMap<QString, Struct1> StringStruct1Map;
QT_BEGIN_NAMESPACE
QDBusArgument &operator<<(QDBusArgument &arg, const Struct1 &)
{
arg.beginStructure();
arg << QString();
arg.endStructure();
return arg;
}
QDBusArgument &operator<<(QDBusArgument &arg, const Struct2 &)
{
arg.beginStructure();
arg << QString() << QDBusObjectPath() << QString();
arg.endStructure();
return arg;
}
QDBusArgument &operator<<(QDBusArgument &arg, const Struct3 &)
{
arg.beginStructure();
arg << QString() << QStringList();
arg.endStructure();
return arg;
}
QDBusArgument &operator<<(QDBusArgument &arg, const StringPair &s)
{
arg.beginStructure();
arg << s.first << s.second;
arg.endStructure();
return arg;
}
QDBusArgument &operator<<(QDBusArgument &arg, const Struct4 &s)
{
arg.beginStructure();
arg << s.m1 << s.m2 << s.m3 << s.m4 << s.m5 << s.m6 << s.m7;
arg.endStructure();
return arg;
}
QDBusArgument &operator<<(QDBusArgument &arg, const Struct5 &s)
{
arg.beginMap(qMetaTypeId<QString>(), qMetaTypeId<QVariantMap>());
arg.beginMapEntry();
arg << QStringLiteral("map1") << s.m1;
arg.endMapEntry();
arg.beginMapEntry();
arg << QStringLiteral("map2") << s.m2;
arg.endMapEntry();
arg.beginMapEntry();
arg << QStringLiteral("map3") << s.m3;
arg.endMapEntry();
arg.endMap();
return arg;
}
QDBusArgument &operator<<(QDBusArgument &arg, const Struct6 &s)
{
arg.beginArray(qMetaTypeId<QDBusVariant>());
arg << QDBusVariant(s.v1) << QDBusVariant(s.v2) << QDBusVariant(s.v3);
arg.endArray();
return arg;
}
QDBusArgument &operator<<(QDBusArgument &arg, const Invalid0 &)
{
return arg;
}
QDBusArgument &operator<<(QDBusArgument &arg, const Invalid1 &)
{
arg << QString();
return arg;
}
QDBusArgument &operator<<(QDBusArgument &arg, const Invalid2 &)
{
arg << QDBusObjectPath();
return arg;
}
QDBusArgument &operator<<(QDBusArgument &arg, const Invalid3 &)
{
arg << QStringList();
return arg;
}
QDBusArgument &operator<<(QDBusArgument &arg, const Invalid4 &)
{
arg << QByteArray();
return arg;
}
QDBusArgument &operator<<(QDBusArgument &arg, const Invalid5 &)
{
arg << 1 << 2;
return arg;
}
// no Invalid6
QDBusArgument &operator<<(QDBusArgument &arg, const Invalid7 &)
{
arg.beginStructure();
arg << Invalid0();
arg.endStructure();
return arg;
}
const QDBusArgument &operator>>(const QDBusArgument &arg, Struct1 &)
{ return arg; }
const QDBusArgument &operator>>(const QDBusArgument &arg, Struct2 &)
{ return arg; }
const QDBusArgument &operator>>(const QDBusArgument &arg, Struct3 &)
{ return arg; }
const QDBusArgument &operator>>(const QDBusArgument &arg, Struct4 &)
{ return arg; }
const QDBusArgument &operator>>(const QDBusArgument &arg, Struct5 &)
{ return arg; }
const QDBusArgument &operator>>(const QDBusArgument &arg, Struct6 &)
{ return arg; }
const QDBusArgument &operator>>(const QDBusArgument &arg, StringPair &)
{ return arg; }
const QDBusArgument &operator>>(const QDBusArgument &arg, Invalid0 &)
{ return arg; }
const QDBusArgument &operator>>(const QDBusArgument &arg, Invalid1 &)
{ return arg; }
const QDBusArgument &operator>>(const QDBusArgument &arg, Invalid2 &)
{ return arg; }
const QDBusArgument &operator>>(const QDBusArgument &arg, Invalid3 &)
{ return arg; }
const QDBusArgument &operator>>(const QDBusArgument &arg, Invalid4 &)
{ return arg; }
const QDBusArgument &operator>>(const QDBusArgument &arg, Invalid5 &)
{ return arg; }
const QDBusArgument &operator>>(const QDBusArgument &arg, Invalid6 &)
{ return arg; }
const QDBusArgument &operator>>(const QDBusArgument &arg, Invalid7 &)
{ return arg; }
QT_END_NAMESPACE
void tst_QDBusMetaType::initTestCase()
{
qDBusRegisterMetaType<Struct1>();
qDBusRegisterMetaType<Struct2>();
qDBusRegisterMetaType<Struct3>();
qDBusRegisterMetaType<Struct4>();
qDBusRegisterMetaType<Struct5>();
qDBusRegisterMetaType<Struct6>();
qDBusRegisterMetaType<StringPair>();
qDBusRegisterMetaType<QList<Struct1> >();
qDBusRegisterMetaType<QList<Struct2> >();
qDBusRegisterMetaType<QList<Struct3> >();
qDBusRegisterMetaType<QList<Struct4> >();
#ifdef Q_CC_GNU_ONLY
// GCC has a defect/extension (depending on your point of view) that allows
// a template class with defaulted template parameters to match a Template
// Template Parameter (TTP) with fewer template arguments. The call below
// tries to use the template<template <typename> class Container, ...>
// template functions qdbusargument.h
qDBusRegisterMetaType<std::vector<Struct1> >();
#endif
qDBusRegisterMetaType<Invalid0>();
qDBusRegisterMetaType<Invalid1>();
qDBusRegisterMetaType<Invalid2>();
qDBusRegisterMetaType<Invalid3>();
qDBusRegisterMetaType<Invalid4>();
qDBusRegisterMetaType<Invalid5>();
// don't register Invalid6
qDBusRegisterMetaType<Invalid7>();
qDBusRegisterMetaType<QList<Invalid0> >();
intStringMap = qDBusRegisterMetaType<QMap<int, QString> >().id();
stringStringMap = qDBusRegisterMetaType<QMap<QString, QString> >().id();
stringStruct1Map = qDBusRegisterMetaType<QMap<QString, Struct1> >().id();
}
void tst_QDBusMetaType::staticTypes_data()
{
QTest::addColumn<int>("typeId");
QTest::addColumn<QString>("signature");
QTest::newRow("uchar") << int(QMetaType::UChar) << "y";
QTest::newRow("bool") << int(QMetaType::Bool) << "b";
QTest::newRow("short") << int(QMetaType::Short) << "n";
QTest::newRow("ushort") << int(QMetaType::UShort) << "q";
QTest::newRow("int") << int(QMetaType::Int) << "i";
QTest::newRow("uint") << int(QMetaType::UInt) << "u";
QTest::newRow("qlonglong") << int(QMetaType::LongLong) << "x";
QTest::newRow("qulonglong") << int(QMetaType::ULongLong) << "t";
QTest::newRow("double") << int(QMetaType::Double) << "d";
QTest::newRow("QString") << int(QMetaType::QString) << "s";
QTest::newRow("QDBusObjectPath") << qMetaTypeId<QDBusObjectPath>() << "o";
QTest::newRow("QDBusSignature") << qMetaTypeId<QDBusSignature>() << "g";
QTest::newRow("QDBusVariant") << qMetaTypeId<QDBusVariant>() << "v";
QTest::newRow("QByteArray") << int(QMetaType::QByteArray) << "ay";
QTest::newRow("QStringList") << int(QMetaType::QStringList) << "as";
}
void tst_QDBusMetaType::dynamicTypes_data()
{
QTest::addColumn<int>("typeId");
QTest::addColumn<QString>("signature");
QTest::newRow("QVariantList") << int(QMetaType::QVariantList) << "av";
QTest::newRow("QVariantMap") << int(QMetaType::QVariantMap) << "a{sv}";
QTest::newRow("QDate") << int(QMetaType::QDate) << "(iii)";
QTest::newRow("QTime") << int(QMetaType::QTime) << "(iiii)";
QTest::newRow("QDateTime") << int(QMetaType::QDateTime) << "((iii)(iiii)i)";
QTest::newRow("QRect") << int(QMetaType::QRect) << "(iiii)";
QTest::newRow("QRectF") << int(QMetaType::QRectF) << "(dddd)";
QTest::newRow("QSize") << int(QMetaType::QSize) << "(ii)";
QTest::newRow("QSizeF") << int(QMetaType::QSizeF) << "(dd)";
QTest::newRow("QPoint") << int(QMetaType::QPoint) << "(ii)";
QTest::newRow("QPointF") << int(QMetaType::QPointF) << "(dd)";
QTest::newRow("QLine") << int(QMetaType::QLine) << "((ii)(ii))";
QTest::newRow("QLineF") << int(QMetaType::QLineF) << "((dd)(dd))";
QTest::newRow("Struct1") << qMetaTypeId<Struct1>() << "(s)";
QTest::newRow("QList<Struct1>") << qMetaTypeId<QList<Struct1> >() << "a(s)";
#ifdef Q_CC_GNU_ONLY
QTest::newRow("std::vector<Struct1>") << qMetaTypeId<std::vector<Struct1> >() << "a(s)";
#endif
QTest::newRow("Struct2") << qMetaTypeId<Struct2>() << "(sos)";
QTest::newRow("QList<Struct2>") << qMetaTypeId<QList<Struct2>>() << "a(sos)";
QTest::newRow("QList<Struct3>") << qMetaTypeId<QList<Struct3>>() << "a(sas)";
QTest::newRow("Struct3") << qMetaTypeId<Struct3>() << "(sas)";
QTest::newRow("Struct4") << qMetaTypeId<Struct4>() << "(ssa(ss)sayasx)";
QTest::newRow("QList<Struct4>") << qMetaTypeId<QList<Struct4>>() << "a(ssa(ss)sayasx)";
QTest::newRow("Struct5") << qMetaTypeId<Struct5>() << "a{sa{sv}}";
QTest::newRow("Struct6") << qMetaTypeId<Struct6>() << "av";
QTest::newRow("QMap<int,QString>") << intStringMap << "a{is}";
QTest::newRow("QMap<QString,QString>") << stringStringMap << "a{ss}";
QTest::newRow("QMap<QString,Struct1>") << stringStruct1Map << "a{s(s)}";
}
void tst_QDBusMetaType::staticTypes()
{
QFETCH(int, typeId);
QString result = QDBusMetaType::typeToSignature(QMetaType(typeId));
QTEST(result, "signature");
}
void tst_QDBusMetaType::dynamicTypes()
{
// same test
staticTypes();
}
void tst_QDBusMetaType::invalidTypes_data()
{
QTest::addColumn<int>("typeId");
QTest::addColumn<QString>("signature");
QTest::newRow("Invalid0") << qMetaTypeId<Invalid0>() << "";
QTest::newRow("Invalid1") << qMetaTypeId<Invalid1>() << "";
QTest::newRow("Invalid2") << qMetaTypeId<Invalid2>() << "";
QTest::newRow("Invalid3") << qMetaTypeId<Invalid3>() << "";
QTest::newRow("Invalid4") << qMetaTypeId<Invalid4>() << "";
QTest::newRow("Invalid5") << qMetaTypeId<Invalid5>() << "";
QTest::newRow("Invalid6") << qMetaTypeId<Invalid6>() << "";
QTest::newRow("Invalid7") << qMetaTypeId<Invalid7>() << "";
QTest::newRow("QList<Invalid0>") << qMetaTypeId<QList<Invalid0>>() << "";
QTest::newRow("long") << int(QMetaType::Long) << "";
QTest::newRow("void*") << int(QMetaType::VoidStar) << "";
}
void tst_QDBusMetaType::invalidTypes()
{
// same test
if (qstrcmp(QTest::currentDataTag(), "Invalid0") == 0)
QTest::ignoreMessage(QtWarningMsg, "QDBusMarshaller: type 'Invalid0' produces invalid D-BUS signature '<empty>' (Did you forget to call beginStructure() ?)");
else if (qstrcmp(QTest::currentDataTag(), "Invalid1") == 0)
QTest::ignoreMessage(QtWarningMsg, "QDBusMarshaller: type 'Invalid1' attempts to redefine basic D-BUS type 's' (QString) (Did you forget to call beginStructure() ?)");
else if (qstrcmp(QTest::currentDataTag(), "Invalid2") == 0)
QTest::ignoreMessage(QtWarningMsg, "QDBusMarshaller: type 'Invalid2' attempts to redefine basic D-BUS type 'o' (QDBusObjectPath) (Did you forget to call beginStructure() ?)");
else if (qstrcmp(QTest::currentDataTag(), "Invalid3") == 0)
QTest::ignoreMessage(QtWarningMsg, "QDBusMarshaller: type 'Invalid3' attempts to redefine basic D-BUS type 'as' (QStringList) (Did you forget to call beginStructure() ?)");
else if (qstrcmp(QTest::currentDataTag(), "Invalid4") == 0)
QTest::ignoreMessage(QtWarningMsg, "QDBusMarshaller: type 'Invalid4' attempts to redefine basic D-BUS type 'ay' (QByteArray) (Did you forget to call beginStructure() ?)");
else if (qstrcmp(QTest::currentDataTag(), "Invalid5") == 0)
QTest::ignoreMessage(QtWarningMsg, "QDBusMarshaller: type 'Invalid5' produces invalid D-BUS signature 'ii' (Did you forget to call beginStructure() ?)");
else if (qstrcmp(QTest::currentDataTag(), "Invalid7") == 0)
QTest::ignoreMessage(QtWarningMsg, "QDBusMarshaller: type 'Invalid7' produces invalid D-BUS signature '()' (Did you forget to call beginStructure() ?)");
else if (qstrcmp(QTest::currentDataTag(), "QList<Invalid0>") == 0)
QTest::ignoreMessage(QtWarningMsg, "QDBusMarshaller: type 'QList<Invalid0>' produces invalid D-BUS signature 'a' (Did you forget to call beginStructure() ?)");
staticTypes();
staticTypes(); // run twice: the error messages should be printed once only
}
QTEST_MAIN(tst_QDBusMetaType)
#include "tst_qdbusmetatype.moc"

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbuspendingcall Test:
#####################################################################
qt_internal_add_test(tst_qdbuspendingcall
SOURCES
tst_qdbuspendingcall.cpp
LIBRARIES
Qt::DBus
)

View File

@ -0,0 +1,455 @@
// 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 <QTestEventLoop>
#include <QObject>
#include <QVariant>
#include <QList>
#include <QThread>
#include <QDBusAbstractAdaptor>
#include <QDBusMessage>
#include <QDBusConnection>
#include <QDBusPendingCallWatcher>
#include <QDBusInterface>
#define TEST_INTERFACE_NAME "org.qtproject.QtDBus.MyObject"
class MyObject : public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.qtproject.QtDBus.MyObject")
public:
MyObject(QObject* parent =0)
: QDBusAbstractAdaptor(parent)
{}
public slots:
QStringList returnFoo() const
{ return QStringList() << QString::fromLatin1("foo"); }
void returnError(const QDBusMessage &msg) const
{
msg.setDelayedReply(true);
QDBusConnection::sessionBus().send(msg.createErrorReply("dbuspendingcall_error", ""));
}
};
class tst_QDBusPendingCall: public QObject
{
Q_OBJECT
public:
tst_QDBusPendingCall();
public Q_SLOTS:
void callback(const QStringList &list);
void errorCallback(const QDBusError &error);
void finished(QDBusPendingCallWatcher *call);
void makeCall();
private Q_SLOTS:
void initTestCase();
void waitForFinished();
void waitForFinished_error();
void watcher();
void watcher_error();
void watcher_waitForFinished();
void watcher_waitForFinished_threaded();
void watcher_waitForFinished_alreadyFinished();
void watcher_waitForFinished_alreadyFinished_eventLoop();
void watcher_waitForFinished_error();
void callInsideWaitForFinished();
void callWithCallback_localLoop();
void callWithCallback_localLoop_errorReply();
private:
QDBusPendingCall sendMessage();
QDBusPendingCall sendError();
QDBusConnection conn;
enum { CallbackCalled, ErrorCallbackCalled, FinishCalled, MakeCallCalled };
int slotCalled;
int callCount;
QStringList callbackArgument;
QDBusError errorArgument;
QDBusPendingCallWatcher *watchArgument;
MyObject *obj;
};
tst_QDBusPendingCall::tst_QDBusPendingCall()
: conn(QDBusConnection::sessionBus())
, obj(new MyObject(this))
{
}
void tst_QDBusPendingCall::finished(QDBusPendingCallWatcher *call)
{
slotCalled = FinishCalled;
++callCount;
watchArgument = call;
if (QThread::currentThread() == thread())
QTestEventLoop::instance().exitLoop();
}
void tst_QDBusPendingCall::callback(const QStringList &list)
{
slotCalled = CallbackCalled;
++callCount;
callbackArgument = list;
QTestEventLoop::instance().exitLoop();
}
void tst_QDBusPendingCall::errorCallback(const QDBusError &error)
{
slotCalled = ErrorCallbackCalled;
++callCount;
errorArgument = error;
QTestEventLoop::instance().exitLoop();
}
void tst_QDBusPendingCall::makeCall()
{
// make an external call to D-Bus to make sure we haven't left any locks
slotCalled = MakeCallCalled;
++callCount;
sendMessage().waitForFinished();
}
void tst_QDBusPendingCall::initTestCase()
{
QVERIFY(conn.isConnected());
QVERIFY(conn.registerObject("/", this));
}
QDBusPendingCall tst_QDBusPendingCall::sendMessage()
{
QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.DBus",
"/",
"org.freedesktop.DBus",
"ListNames");
return conn.asyncCall(msg);
}
QDBusPendingCall tst_QDBusPendingCall::sendError()
{
QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.DBus",
"/",
"org.freedesktop.DBus",
"ThisNameWontExist");
return conn.asyncCall(msg);
}
void tst_QDBusPendingCall::waitForFinished()
{
QDBusPendingCall ac = sendMessage();
ac.waitForFinished();
QVERIFY(ac.isFinished());
QVERIFY(!ac.isError());
const QDBusMessage reply = ac.reply();
QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
QCOMPARE(reply.signature(), QString("as"));
const QVariantList args = ac.reply().arguments();
QCOMPARE(args.size(), 1);
const QVariant &arg = args.at(0);
QCOMPARE(arg.userType(), QMetaType::QStringList);
QVERIFY(arg.toStringList().contains(conn.baseService()));
}
void tst_QDBusPendingCall::waitForFinished_error()
{
QDBusPendingCall ac = sendError();
ac.waitForFinished();
QVERIFY(ac.isFinished());
QVERIFY(ac.isError());
QDBusError error = ac.error();
QVERIFY(error.isValid());
QCOMPARE(error.name(), QString("org.freedesktop.DBus.Error.UnknownMethod"));
QCOMPARE(error.type(), QDBusError::UnknownMethod);
}
void tst_QDBusPendingCall::callWithCallback_localLoop()
{
// Verify that a callback actually gets called when the call is dispatched locally.
QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
TEST_INTERFACE_NAME);
QVERIFY(iface.isValid());
QVERIFY(iface.callWithCallback("returnFoo", QVariantList(), this, SLOT(callback(QStringList))));
// May be called synchronously or asynchronously...
if (callbackArgument != (QStringList() << QString::fromLatin1("foo"))) {
QTestEventLoop::instance().enterLoop(2);
QVERIFY(!QTestEventLoop::instance().timeout());
}
QCOMPARE(callbackArgument, QStringList() << QString::fromLatin1("foo"));
}
void tst_QDBusPendingCall::callWithCallback_localLoop_errorReply()
{
// Verify that an error callback actually gets called when the call is
// dispatched locally and the called method returns an error
QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
TEST_INTERFACE_NAME);
QVERIFY(iface.isValid());
callbackArgument.clear();
QVERIFY(iface.callWithCallback("returnError", QVariantList(), this,
SLOT(callback(QStringList)), SLOT(errorCallback(QDBusError))));
// May be called synchronously or asynchronously...
if (errorArgument.name() != "dbuspendingcall_error") {
QTestEventLoop::instance().enterLoop(2);
QVERIFY(!QTestEventLoop::instance().timeout());
}
QCOMPARE(errorArgument.name(), QString::fromLatin1("dbuspendingcall_error"));
QVERIFY(callbackArgument.isEmpty());
}
void tst_QDBusPendingCall::watcher()
{
QDBusPendingCall ac = sendMessage();
callCount = 0;
watchArgument = 0;
QDBusPendingCallWatcher watch(ac);
connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
SLOT(finished(QDBusPendingCallWatcher*)));
QTestEventLoop::instance().enterLoop(2);
QVERIFY(!QTestEventLoop::instance().timeout());
QVERIFY(ac.isFinished());
QVERIFY(!ac.isError());
QCOMPARE(callCount, 1);
QCOMPARE(slotCalled, (int)FinishCalled);
QCOMPARE(watchArgument, &watch);
QVERIFY(!watch.isError());
const QVariantList args2 = ac.reply().arguments();
QVERIFY(!args2.isEmpty());
QVERIFY(args2.at(0).toStringList().contains(conn.baseService()));
}
void tst_QDBusPendingCall::watcher_error()
{
QDBusPendingCall ac = sendError();
callCount = 0;
watchArgument = 0;
QDBusPendingCallWatcher watch(ac);
connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
SLOT(finished(QDBusPendingCallWatcher*)));
QTestEventLoop::instance().enterLoop(2);
QVERIFY(!QTestEventLoop::instance().timeout());
QVERIFY(ac.isFinished());
QVERIFY(ac.isError());
QCOMPARE(callCount, 1);
QCOMPARE(slotCalled, (int)FinishCalled);
QCOMPARE(watchArgument, &watch);
QVERIFY(watch.isError());
QVERIFY(watch.error().isValid());
}
void tst_QDBusPendingCall::watcher_waitForFinished()
{
QDBusPendingCall ac = sendMessage();
callCount = 0;
watchArgument = 0;
QDBusPendingCallWatcher watch(ac);
connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
SLOT(finished(QDBusPendingCallWatcher*)));
watch.waitForFinished();
QVERIFY(ac.isFinished());
QVERIFY(!ac.isError());
QCOMPARE(callCount, 1);
QCOMPARE(slotCalled, (int)FinishCalled);
QCOMPARE(watchArgument, &watch);
QVERIFY(!watch.isError());
const QVariantList args2 = ac.reply().arguments();
QVERIFY(!args2.isEmpty());
QVERIFY(args2.at(0).toStringList().contains(conn.baseService()));
}
void tst_QDBusPendingCall::watcher_waitForFinished_threaded()
{
callCount = 0;
watchArgument = 0;
slotCalled = 0;
class WorkerThread: public QThread {
public:
tst_QDBusPendingCall *tst;
WorkerThread(tst_QDBusPendingCall *tst) : tst(tst) {}
void run() override
{
QDBusPendingCall ac = tst->sendMessage();
// QVERIFY(!ac.isFinished());
// QVERIFY(!ac.isError());
// QCOMPARE(ac.reply().type(), QDBusMessage::InvalidMessage);
QDBusPendingCallWatcher watch(ac);
tst->connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
SLOT(finished(QDBusPendingCallWatcher*)), Qt::DirectConnection);
QTest::qSleep(100); // don't process events in this thread
// QVERIFY(!ac.isFinished());
// QVERIFY(!ac.isError());
// QCOMPARE(ac.reply().type(), QDBusMessage::InvalidMessage);
QCOMPARE(tst->callCount, 0);
QCOMPARE(tst->slotCalled, 0);
watch.waitForFinished();
QVERIFY(ac.isFinished());
QVERIFY(!ac.isError());
QCOMPARE(tst->callCount, 1);
QCOMPARE(tst->slotCalled, (int)FinishCalled);
QCOMPARE(tst->watchArgument, &watch);
QVERIFY(!watch.isError());
const QVariantList args2 = ac.reply().arguments();
QVERIFY(!args2.isEmpty());
QVERIFY(args2.at(0).toStringList().contains(tst->conn.baseService()));
}
} thread(this);
QTestEventLoop::instance().connect(&thread, SIGNAL(finished()), SLOT(exitLoop()));
thread.start();
QTestEventLoop::instance().enterLoop(10);
QVERIFY(thread.wait(3000));
QVERIFY(!QTestEventLoop::instance().timeout());
}
void tst_QDBusPendingCall::watcher_waitForFinished_alreadyFinished()
{
QDBusPendingCall ac = sendMessage();
ac.waitForFinished();
QVERIFY(ac.isFinished());
QVERIFY(!ac.isError());
callCount = 0;
watchArgument = 0;
// create a watcher on an already-finished reply
QDBusPendingCallWatcher watch(ac);
connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
SLOT(finished(QDBusPendingCallWatcher*)));
watch.waitForFinished();
QVERIFY(ac.isFinished());
QVERIFY(!ac.isError());
QCOMPARE(callCount, 1);
QCOMPARE(slotCalled, (int)FinishCalled);
QCOMPARE(watchArgument, &watch);
QVERIFY(!watch.isError());
const QVariantList args2 = ac.reply().arguments();
QVERIFY(!args2.isEmpty());
QVERIFY(args2.at(0).toStringList().contains(conn.baseService()));
}
void tst_QDBusPendingCall::watcher_waitForFinished_alreadyFinished_eventLoop()
{
QDBusPendingCall ac = sendMessage();
ac.waitForFinished();
QVERIFY(ac.isFinished());
QVERIFY(!ac.isError());
callCount = 0;
watchArgument = 0;
// create a watcher on an already-finished reply
QDBusPendingCallWatcher watch(ac);
connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
SLOT(finished(QDBusPendingCallWatcher*)));
connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
&QTestEventLoop::instance(), SLOT(exitLoop()));
QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout());
QVERIFY(ac.isFinished());
QVERIFY(!ac.isError());
QCOMPARE(callCount, 1);
QCOMPARE(slotCalled, (int)FinishCalled);
QCOMPARE(watchArgument, &watch);
QVERIFY(!watch.isError());
const QVariantList args2 = ac.reply().arguments();
QVERIFY(!args2.isEmpty());
QVERIFY(args2.at(0).toStringList().contains(conn.baseService()));
}
void tst_QDBusPendingCall::watcher_waitForFinished_error()
{
QDBusPendingCall ac = sendError();
callCount = 0;
watchArgument = 0;
QDBusPendingCallWatcher watch(ac);
connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
SLOT(finished(QDBusPendingCallWatcher*)));
watch.waitForFinished();
QVERIFY(ac.isFinished());
QVERIFY(ac.isError());
QCOMPARE(callCount, 1);
QCOMPARE(slotCalled, (int)FinishCalled);
QCOMPARE(watchArgument, &watch);
QVERIFY(watch.isError());
QVERIFY(watch.error().isValid());
}
void tst_QDBusPendingCall::callInsideWaitForFinished()
{
QDBusPendingCall ac = sendMessage();
QDBusPendingCallWatcher watch(ac);
callCount = 0;
connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
SLOT(makeCall()));
watch.waitForFinished();
QCOMPARE(callCount, 1);
QCOMPARE(slotCalled, (int)MakeCallCalled);
QVERIFY(!watch.isError());
const QVariantList args2 = ac.reply().arguments();
QVERIFY(!args2.isEmpty());
QVERIFY(args2.at(0).toStringList().contains(conn.baseService()));
}
QTEST_MAIN(tst_QDBusPendingCall)
#include "tst_qdbuspendingcall.moc"

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbuspendingreply Test:
#####################################################################
qt_internal_add_test(tst_qdbuspendingreply
SOURCES
tst_qdbuspendingreply.cpp
LIBRARIES
Qt::DBus
)

View File

@ -0,0 +1,566 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QObject>
#include <QVariant>
#include <QList>
#include <QDBusArgument>
#include <QDBusInterface>
#include <QDBusMetaType>
#include <QDBusAbstractAdaptor>
#include <QDBusPendingReply>
typedef QMap<int,QString> IntStringMap;
Q_DECLARE_METATYPE(IntStringMap)
struct MyStruct
{
int i;
QString s;
MyStruct() : i(1), s("String") { }
bool operator==(const MyStruct &other) const
{ return i == other.i && s == other.s; }
};
Q_DECLARE_METATYPE(MyStruct)
QDBusArgument &operator<<(QDBusArgument &arg, const MyStruct &ms)
{
arg.beginStructure();
arg << ms.i << ms.s;
arg.endStructure();
return arg;
}
const QDBusArgument &operator>>(const QDBusArgument &arg, MyStruct &ms)
{
arg.beginStructure();
arg >> ms.i >> ms.s;
arg.endStructure();
return arg;
}
class TypesInterface;
class tst_QDBusPendingReply: public QObject
{
Q_OBJECT
QDBusInterface *iface;
TypesInterface *adaptor;
public:
tst_QDBusPendingReply();
private slots:
void initTestCase()
{
qDBusRegisterMetaType<IntStringMap>();
qDBusRegisterMetaType<MyStruct>();
}
void init();
void unconnected();
void simpleTypes();
void complexTypes();
void wrongTypes();
void multipleTypes();
void synchronousSimpleTypes();
void errors();
};
class TypesInterface: public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.qtproject.Qt.Autotests.TypesInterface")
public:
TypesInterface(QObject *parent)
: QDBusAbstractAdaptor(parent)
{ }
public slots:
void retrieveVoid()
{ }
bool retrieveBool()
{
return true;
}
uchar retrieveUChar()
{
return 'A';
}
short retrieveShort()
{
return -47;
}
ushort retrieveUShort()
{
return 42U;
}
int retrieveInt()
{
return -470000;
}
void retrieveIntInt(int &i1, int &i2)
{
i1 = -424242;
i2 = 434343;
}
uint retrieveUInt()
{
return 42424242;
}
qlonglong retrieveLongLong()
{
return -(Q_INT64_C(1) << 32);
}
qulonglong retrieveULongLong()
{
return Q_INT64_C(1) << 32;
}
double retrieveDouble()
{
return 1.5;
}
QString retrieveString()
{
return "This string you should see";
}
QDBusObjectPath retrieveObjectPath()
{
return QDBusObjectPath("/");
}
QDBusSignature retrieveSignature()
{
return QDBusSignature("g");
}
QDBusVariant retrieveVariant()
{
return QDBusVariant(retrieveString());
}
QStringList retrieveStringList()
{
return QStringList() << "one" << "two";
}
QByteArray retrieveByteArray()
{
return "Hello, World";
}
QVariantList retrieveList()
{
return QVariantList() << retrieveInt() << retrieveString()
<< retrieveByteArray();
}
QVariantMap retrieveMap()
{
QVariantMap map;
map["one"] = 1;
map["two"] = 2U;
map["string"] = retrieveString();
map["stringlist"] = retrieveStringList();
return map;
}
IntStringMap retrieveIntStringMap()
{
IntStringMap map;
map[1] = "1";
map[2] = "2";
map[-1231456] = "foo";
return map;
}
MyStruct retrieveStruct()
{
return MyStruct();
}
void sendError(const QDBusMessage &msg)
{
msg.setDelayedReply(true);
QDBusConnection::sessionBus()
.send(msg.createErrorReply("local.AnErrorName", "You've got an error!"));
}
};
tst_QDBusPendingReply::tst_QDBusPendingReply()
{
adaptor = new TypesInterface(this);
QDBusConnection::sessionBus().registerObject("/", this);
iface = new QDBusInterface(QDBusConnection::sessionBus().baseService(), "/",
"org.qtproject.Qt.Autotests.TypesInterface",
QDBusConnection::sessionBus(),
this);
}
void tst_QDBusPendingReply::init()
{
QVERIFY(iface);
QVERIFY(iface->isValid());
}
void tst_QDBusPendingReply::unconnected()
{
QDBusConnection con("invalid stored connection");
QVERIFY(!con.isConnected());
QDBusInterface iface("doesnt.matter", "/", "doesnt.matter", con);
QVERIFY(!iface.isValid());
QDBusPendingReply<> rvoid = iface.asyncCall("ReloadConfig");
QVERIFY(rvoid.isFinished());
QVERIFY(!rvoid.isValid());
QVERIFY(rvoid.isError());
rvoid.waitForFinished();
QVERIFY(!rvoid.isValid());
QVERIFY(rvoid.isError());
QDBusPendingReply<QString> rstring = iface.asyncCall("GetId");
QVERIFY(rstring.isFinished());
QVERIFY(!rstring.isValid());
QVERIFY(rstring.isError());
rstring.waitForFinished();
QVERIFY(!rstring.isValid());
QVERIFY(rstring.isError());
}
void tst_QDBusPendingReply::simpleTypes()
{
QDBusPendingReply<> rvoid = iface->asyncCall("retrieveVoid");
rvoid.waitForFinished();
QVERIFY(rvoid.isFinished());
QVERIFY(!rvoid.isError());
QDBusPendingReply<bool> rbool = iface->asyncCall("retrieveBool");
rbool.waitForFinished();
QVERIFY(rbool.isFinished());
QCOMPARE(rbool.argumentAt<0>(), adaptor->retrieveBool());
QDBusPendingReply<uchar> ruchar = iface->asyncCall("retrieveUChar");
ruchar.waitForFinished();
QVERIFY(ruchar.isFinished());
QCOMPARE(ruchar.argumentAt<0>(), adaptor->retrieveUChar());
QDBusPendingReply<short> rshort = iface->asyncCall("retrieveShort");
rshort.waitForFinished();
QVERIFY(rshort.isFinished());
QCOMPARE(rshort.argumentAt<0>(), adaptor->retrieveShort());
QDBusPendingReply<ushort> rushort = iface->asyncCall("retrieveUShort");
rushort.waitForFinished();
QVERIFY(rushort.isFinished());
QCOMPARE(rushort.argumentAt<0>(), adaptor->retrieveUShort());
QDBusPendingReply<int> rint = iface->asyncCall("retrieveInt");
rint.waitForFinished();
QVERIFY(rint.isFinished());
QCOMPARE(rint.argumentAt<0>(), adaptor->retrieveInt());
QDBusPendingReply<uint> ruint = iface->asyncCall("retrieveUInt");
ruint.waitForFinished();
QVERIFY(ruint.isFinished());
QCOMPARE(ruint.argumentAt<0>(), adaptor->retrieveUInt());
QDBusPendingReply<qlonglong> rqlonglong = iface->asyncCall("retrieveLongLong");
rqlonglong.waitForFinished();
QVERIFY(rqlonglong.isFinished());
QCOMPARE(rqlonglong.argumentAt<0>(), adaptor->retrieveLongLong());
QDBusPendingReply<qulonglong> rqulonglong = iface->asyncCall("retrieveULongLong");
rqulonglong.waitForFinished();
QVERIFY(rqulonglong.isFinished());
QCOMPARE(rqulonglong.argumentAt<0>(), adaptor->retrieveULongLong());
QDBusPendingReply<double> rdouble = iface->asyncCall("retrieveDouble");
rdouble.waitForFinished();
QVERIFY(rdouble.isFinished());
QCOMPARE(rdouble.argumentAt<0>(), adaptor->retrieveDouble());
QDBusPendingReply<QString> rstring = iface->asyncCall("retrieveString");
rstring.waitForFinished();
QVERIFY(rstring.isFinished());
QCOMPARE(rstring.argumentAt<0>(), adaptor->retrieveString());
QDBusPendingReply<QDBusObjectPath> robjectpath = iface->asyncCall("retrieveObjectPath");
robjectpath.waitForFinished();
QVERIFY(robjectpath.isFinished());
QCOMPARE(robjectpath.argumentAt<0>().path(), adaptor->retrieveObjectPath().path());
QDBusPendingReply<QDBusSignature> rsignature = iface->asyncCall("retrieveSignature");
rsignature.waitForFinished();
QVERIFY(rsignature.isFinished());
QCOMPARE(rsignature.argumentAt<0>().signature(), adaptor->retrieveSignature().signature());
QDBusPendingReply<QDBusVariant> rdbusvariant = iface->asyncCall("retrieveVariant");
rdbusvariant.waitForFinished();
QVERIFY(rdbusvariant.isFinished());
QCOMPARE(rdbusvariant.argumentAt<0>().variant(), adaptor->retrieveVariant().variant());
QDBusPendingReply<QVariant> rvariant = iface->asyncCall("retrieveVariant");
rvariant.waitForFinished();
QVERIFY(rvariant.isFinished());
QCOMPARE(rvariant.argumentAt<0>(), adaptor->retrieveVariant().variant());
QDBusPendingReply<QByteArray> rbytearray = iface->asyncCall("retrieveByteArray");
rbytearray.waitForFinished();
QVERIFY(rbytearray.isFinished());
QCOMPARE(rbytearray.argumentAt<0>(), adaptor->retrieveByteArray());
QDBusPendingReply<QStringList> rstringlist = iface->asyncCall("retrieveStringList");
rstringlist.waitForFinished();
QVERIFY(rstringlist.isFinished());
QCOMPARE(rstringlist.argumentAt<0>(), adaptor->retrieveStringList());
}
void tst_QDBusPendingReply::complexTypes()
{
QDBusPendingReply<QVariantList> rlist = iface->asyncCall("retrieveList");
rlist.waitForFinished();
QVERIFY(rlist.isFinished());
QCOMPARE(rlist.argumentAt<0>(), adaptor->retrieveList());
QDBusPendingReply<QVariantMap> rmap = iface->asyncCall("retrieveMap");
rmap.waitForFinished();
QVERIFY(rmap.isFinished());
QCOMPARE(rmap.argumentAt<0>(), adaptor->retrieveMap());
QDBusPendingReply<IntStringMap> rismap = iface->asyncCall("retrieveIntStringMap");
rismap.waitForFinished();
QVERIFY(rismap.isFinished());
QCOMPARE(rismap.argumentAt<0>(), adaptor->retrieveIntStringMap());
QDBusPendingReply<MyStruct> rstruct = iface->asyncCall("retrieveStruct");
rstruct.waitForFinished();
QVERIFY(rstruct.isFinished());
QCOMPARE(rstruct.argumentAt<0>(), adaptor->retrieveStruct());
}
#define VERIFY_WRONG_TYPE(error) \
QVERIFY(error.isValid()); \
QCOMPARE(error.type(), QDBusError::InvalidSignature)
void tst_QDBusPendingReply::wrongTypes()
{
QDBusError error;
QDBusPendingReply<bool> rbool = iface->asyncCall("retrieveInt");
rbool.waitForFinished();
QVERIFY(rbool.isFinished());
QVERIFY(rbool.isError());
error = rbool.error();
VERIFY_WRONG_TYPE(error);
rbool = iface->asyncCall("retrieveShort");
rbool.waitForFinished();
QVERIFY(rbool.isFinished());
QVERIFY(rbool.isError());
error = rbool.error();
VERIFY_WRONG_TYPE(error);
rbool = iface->asyncCall("retrieveStruct");
rbool.waitForFinished();
QVERIFY(rbool.isFinished());
QVERIFY(rbool.isError());
error = rbool.error();
VERIFY_WRONG_TYPE(error);
QDBusPendingReply<short> rshort = iface->asyncCall("retrieveInt");
rshort.waitForFinished();
QVERIFY(rshort.isFinished());
QVERIFY(rshort.isError());
error = rshort.error();
VERIFY_WRONG_TYPE(error);
rshort = iface->asyncCall("retrieveBool");
rshort.waitForFinished();
QVERIFY(rshort.isFinished());
QVERIFY(rshort.isError());
error = rshort.error();
VERIFY_WRONG_TYPE(error);
rshort = iface->asyncCall("retrieveStruct");
rshort.waitForFinished();
QVERIFY(rshort.isFinished());
QVERIFY(rshort.isError());
error = rshort.error();
VERIFY_WRONG_TYPE(error);
QDBusPendingReply<MyStruct> rstruct = iface->asyncCall("retrieveInt");
rstruct.waitForFinished();
QVERIFY(rstruct.isFinished());
QVERIFY(rstruct.isError());
error = rstruct.error();
VERIFY_WRONG_TYPE(error);
rstruct = iface->asyncCall("retrieveShort");
rstruct.waitForFinished();
QVERIFY(rstruct.isFinished());
QVERIFY(rstruct.isError());
error = rstruct.error();
VERIFY_WRONG_TYPE(error);
rstruct = iface->asyncCall("retrieveIntStringMap");
rstruct.waitForFinished();
QVERIFY(rstruct.isFinished());
QVERIFY(rstruct.isError());
error = rstruct.error();
VERIFY_WRONG_TYPE(error);
}
void tst_QDBusPendingReply::multipleTypes()
{
QDBusPendingReply<int, int> rintint = iface->asyncCall("retrieveIntInt");
rintint.waitForFinished();
QVERIFY(rintint.isFinished());
QVERIFY(!rintint.isError());
int i1, i2;
adaptor->retrieveIntInt(i1, i2);
QCOMPARE(rintint.argumentAt<0>(), i1);
QCOMPARE(rintint.argumentAt<1>(), i2);
}
void tst_QDBusPendingReply::synchronousSimpleTypes()
{
QDBusPendingReply<bool> rbool(iface->call("retrieveBool"));
rbool.waitForFinished();
QVERIFY(rbool.isFinished());
QCOMPARE(rbool.argumentAt<0>(), adaptor->retrieveBool());
QDBusPendingReply<uchar> ruchar(iface->call("retrieveUChar"));
ruchar.waitForFinished();
QVERIFY(ruchar.isFinished());
QCOMPARE(ruchar.argumentAt<0>(), adaptor->retrieveUChar());
QDBusPendingReply<short> rshort(iface->call("retrieveShort"));
rshort.waitForFinished();
QVERIFY(rshort.isFinished());
QCOMPARE(rshort.argumentAt<0>(), adaptor->retrieveShort());
QDBusPendingReply<ushort> rushort(iface->call("retrieveUShort"));
rushort.waitForFinished();
QVERIFY(rushort.isFinished());
QCOMPARE(rushort.argumentAt<0>(), adaptor->retrieveUShort());
QDBusPendingReply<int> rint(iface->call("retrieveInt"));
rint.waitForFinished();
QVERIFY(rint.isFinished());
QCOMPARE(rint.argumentAt<0>(), adaptor->retrieveInt());
QDBusPendingReply<uint> ruint(iface->call("retrieveUInt"));
ruint.waitForFinished();
QVERIFY(ruint.isFinished());
QCOMPARE(ruint.argumentAt<0>(), adaptor->retrieveUInt());
QDBusPendingReply<qlonglong> rqlonglong(iface->call("retrieveLongLong"));
rqlonglong.waitForFinished();
QVERIFY(rqlonglong.isFinished());
QCOMPARE(rqlonglong.argumentAt<0>(), adaptor->retrieveLongLong());
QDBusPendingReply<qulonglong> rqulonglong(iface->call("retrieveULongLong"));
rqulonglong.waitForFinished();
QVERIFY(rqulonglong.isFinished());
QCOMPARE(rqulonglong.argumentAt<0>(), adaptor->retrieveULongLong());
QDBusPendingReply<double> rdouble(iface->call("retrieveDouble"));
rdouble.waitForFinished();
QVERIFY(rdouble.isFinished());
QCOMPARE(rdouble.argumentAt<0>(), adaptor->retrieveDouble());
QDBusPendingReply<QString> rstring(iface->call("retrieveString"));
rstring.waitForFinished();
QVERIFY(rstring.isFinished());
QCOMPARE(rstring.argumentAt<0>(), adaptor->retrieveString());
QDBusPendingReply<QDBusObjectPath> robjectpath(iface->call("retrieveObjectPath"));
robjectpath.waitForFinished();
QVERIFY(robjectpath.isFinished());
QCOMPARE(robjectpath.argumentAt<0>().path(), adaptor->retrieveObjectPath().path());
QDBusPendingReply<QDBusSignature> rsignature(iface->call("retrieveSignature"));
rsignature.waitForFinished();
QVERIFY(rsignature.isFinished());
QCOMPARE(rsignature.argumentAt<0>().signature(), adaptor->retrieveSignature().signature());
QDBusPendingReply<QDBusVariant> rdbusvariant(iface->call("retrieveVariant"));
rdbusvariant.waitForFinished();
QVERIFY(rdbusvariant.isFinished());
QCOMPARE(rdbusvariant.argumentAt<0>().variant(), adaptor->retrieveVariant().variant());
QDBusPendingReply<QByteArray> rbytearray(iface->call("retrieveByteArray"));
rbytearray.waitForFinished();
QVERIFY(rbytearray.isFinished());
QCOMPARE(rbytearray.argumentAt<0>(), adaptor->retrieveByteArray());
QDBusPendingReply<QStringList> rstringlist(iface->call("retrieveStringList"));
rstringlist.waitForFinished();
QVERIFY(rstringlist.isFinished());
QCOMPARE(rstringlist.argumentAt<0>(), adaptor->retrieveStringList());
}
#define VERIFY_ERROR(error) \
QVERIFY(error.isValid()); \
QCOMPARE(error.name(), QString("local.AnErrorName")); \
QCOMPARE(error.type(), QDBusError::Other)
void tst_QDBusPendingReply::errors()
{
QDBusError error;
QDBusPendingReply<> rvoid(iface->asyncCall("sendError"));
rvoid.waitForFinished();
QVERIFY(rvoid.isFinished());
QVERIFY(rvoid.isError());
error = rvoid.error();
VERIFY_ERROR(error);
QDBusPendingReply<int> rint(iface->asyncCall("sendError"));
rint.waitForFinished();
QVERIFY(rint.isFinished());
QVERIFY(rint.isError());
error = rint.error();
VERIFY_ERROR(error);
int dummyint = rint;
QCOMPARE(dummyint, int());
QDBusPendingReply<int,int> rintint(iface->asyncCall("sendError"));
rintint.waitForFinished();
QVERIFY(rintint.isFinished());
QVERIFY(rintint.isError());
error = rintint.error();
VERIFY_ERROR(error);
dummyint = rintint;
QCOMPARE(dummyint, int());
QCOMPARE(rintint.argumentAt<1>(), int());
QDBusPendingReply<QString> rstring(iface->asyncCall("sendError"));
rstring.waitForFinished();
QVERIFY(rstring.isFinished());
QVERIFY(rstring.isError());
error = rstring.error();
VERIFY_ERROR(error);
QString dummystring = rstring;
QCOMPARE(dummystring, QString());
}
QTEST_MAIN(tst_QDBusPendingReply)
#include "tst_qdbuspendingreply.moc"

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbusreply Test:
#####################################################################
qt_internal_add_test(tst_qdbusreply
SOURCES
tst_qdbusreply.cpp
LIBRARIES
Qt::DBus
)

View File

@ -0,0 +1,367 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QDebug>
#include <QCoreApplication>
#include <QVariant>
#include <QDBusArgument>
#include <QDBusInterface>
#include <QDBusMetaType>
#include <QDBusAbstractAdaptor>
#include <QDBusReply>
typedef QMap<int,QString> IntStringMap;
Q_DECLARE_METATYPE(IntStringMap)
struct MyStruct
{
int i;
QString s;
MyStruct() : i(1), s("String") { }
bool operator==(const MyStruct &other) const
{ return i == other.i && s == other.s; }
};
Q_DECLARE_METATYPE(MyStruct)
QDBusArgument &operator<<(QDBusArgument &arg, const MyStruct &ms)
{
arg.beginStructure();
arg << ms.i << ms.s;
arg.endStructure();
return arg;
}
const QDBusArgument &operator>>(const QDBusArgument &arg, MyStruct &ms)
{
arg.beginStructure();
arg >> ms.i >> ms.s;
arg.endStructure();
return arg;
}
class TypesInterface;
class tst_QDBusReply: public QObject
{
Q_OBJECT
QDBusInterface *iface;
TypesInterface *adaptor;
public:
tst_QDBusReply();
private slots:
void initTestCase()
{
qDBusRegisterMetaType<IntStringMap>();
qDBusRegisterMetaType<MyStruct>();
}
void init();
void unconnected();
void simpleTypes();
void complexTypes();
void wrongTypes();
void error();
};
class TypesInterface: public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.qtproject.Qt.Autotests.TypesInterface")
public:
TypesInterface(QObject *parent)
: QDBusAbstractAdaptor(parent)
{ }
public slots:
bool retrieveBool()
{
return true;
}
uchar retrieveUChar()
{
return 'A';
}
short retrieveShort()
{
return -47;
}
ushort retrieveUShort()
{
return 42U;
}
int retrieveInt()
{
return -470000;
}
uint retrieveUInt()
{
return 42424242;
}
qlonglong retrieveLongLong()
{
return -(Q_INT64_C(1) << 32);
}
qulonglong retrieveULongLong()
{
return Q_INT64_C(1) << 32;
}
double retrieveDouble()
{
return 1.5;
}
QString retrieveString()
{
return "This string you should see";
}
QDBusObjectPath retrieveObjectPath()
{
return QDBusObjectPath("/");
}
QDBusSignature retrieveSignature()
{
return QDBusSignature("g");
}
QDBusVariant retrieveVariant()
{
return QDBusVariant(retrieveString());
}
QStringList retrieveStringList()
{
return QStringList() << "one" << "two";
}
QByteArray retrieveByteArray()
{
return "Hello, World";
}
QVariantList retrieveList()
{
return QVariantList() << retrieveInt() << retrieveString()
<< retrieveByteArray();
}
QList<QDBusObjectPath> retrieveObjectPathList()
{
return QList<QDBusObjectPath>() << QDBusObjectPath("/") << QDBusObjectPath("/foo");
}
QVariantMap retrieveMap()
{
QVariantMap map;
map["one"] = 1;
map["two"] = 2U;
map["string"] = retrieveString();
map["stringlist"] = retrieveStringList();
return map;
}
IntStringMap retrieveIntStringMap()
{
IntStringMap map;
map[1] = "1";
map[2] = "2";
map[-1231456] = "foo";
return map;
}
MyStruct retrieveStruct()
{
return MyStruct();
}
};
tst_QDBusReply::tst_QDBusReply()
{
adaptor = new TypesInterface(this);
QDBusConnection::sessionBus().registerObject("/", this);
iface = new QDBusInterface(QDBusConnection::sessionBus().baseService(), "/",
"org.qtproject.Qt.Autotests.TypesInterface",
QDBusConnection::sessionBus(),
this);
}
void tst_QDBusReply::init()
{
QVERIFY(iface);
QVERIFY(iface->isValid());
}
void tst_QDBusReply::unconnected()
{
QDBusConnection con("invalid stored connection");
QVERIFY(!con.isConnected());
QDBusInterface iface("doesnt.matter", "/", "doesnt.matter", con);
QVERIFY(!iface.isValid());
QDBusReply<void> rvoid = iface.asyncCall("ReloadConfig");
QVERIFY(!rvoid.isValid());
QDBusReply<QString> rstring = iface.asyncCall("GetId");
QVERIFY(!rstring.isValid());
QVERIFY(rstring.value().isEmpty());
}
void tst_QDBusReply::simpleTypes()
{
QDBusReply<bool> rbool = iface->call(QDBus::BlockWithGui, "retrieveBool");
QVERIFY(rbool.isValid());
QCOMPARE(rbool.value(), adaptor->retrieveBool());
QDBusReply<uchar> ruchar = iface->call(QDBus::BlockWithGui, "retrieveUChar");
QVERIFY(ruchar.isValid());
QCOMPARE(ruchar.value(), adaptor->retrieveUChar());
QDBusReply<short> rshort = iface->call(QDBus::BlockWithGui, "retrieveShort");
QVERIFY(rshort.isValid());
QCOMPARE(rshort.value(), adaptor->retrieveShort());
QDBusReply<ushort> rushort = iface->call(QDBus::BlockWithGui, "retrieveUShort");
QVERIFY(rushort.isValid());
QCOMPARE(rushort.value(), adaptor->retrieveUShort());
QDBusReply<int> rint = iface->call(QDBus::BlockWithGui, "retrieveInt");
QVERIFY(rint.isValid());
QCOMPARE(rint.value(), adaptor->retrieveInt());
QDBusReply<uint> ruint = iface->call(QDBus::BlockWithGui, "retrieveUInt");
QVERIFY(ruint.isValid());
QCOMPARE(ruint.value(), adaptor->retrieveUInt());
QDBusReply<qlonglong> rqlonglong = iface->call(QDBus::BlockWithGui, "retrieveLongLong");
QVERIFY(rqlonglong.isValid());
QCOMPARE(rqlonglong.value(), adaptor->retrieveLongLong());
QDBusReply<qulonglong> rqulonglong = iface->call(QDBus::BlockWithGui, "retrieveULongLong");
QVERIFY(rqulonglong.isValid());
QCOMPARE(rqulonglong.value(), adaptor->retrieveULongLong());
QDBusReply<double> rdouble = iface->call(QDBus::BlockWithGui, "retrieveDouble");
QVERIFY(rdouble.isValid());
QCOMPARE(rdouble.value(), adaptor->retrieveDouble());
QDBusReply<QString> rstring = iface->call(QDBus::BlockWithGui, "retrieveString");
QVERIFY(rstring.isValid());
QCOMPARE(rstring.value(), adaptor->retrieveString());
QDBusReply<QDBusObjectPath> robjectpath = iface->call(QDBus::BlockWithGui, "retrieveObjectPath");
QVERIFY(robjectpath.isValid());
QCOMPARE(robjectpath.value().path(), adaptor->retrieveObjectPath().path());
QDBusReply<QDBusSignature> rsignature = iface->call(QDBus::BlockWithGui, "retrieveSignature");
QVERIFY(rsignature.isValid());
QCOMPARE(rsignature.value().signature(), adaptor->retrieveSignature().signature());
QDBusReply<QDBusVariant> rdbusvariant = iface->call(QDBus::BlockWithGui, "retrieveVariant");
QVERIFY(rdbusvariant.isValid());
QCOMPARE(rdbusvariant.value().variant(), adaptor->retrieveVariant().variant());
QDBusReply<QVariant> rvariant = iface->call(QDBus::BlockWithGui, "retrieveVariant");
QVERIFY(rvariant.isValid());
QCOMPARE(rvariant.value(), adaptor->retrieveVariant().variant());
QDBusReply<QByteArray> rbytearray = iface->call(QDBus::BlockWithGui, "retrieveByteArray");
QVERIFY(rbytearray.isValid());
QCOMPARE(rbytearray.value(), adaptor->retrieveByteArray());
QDBusReply<QStringList> rstringlist = iface->call(QDBus::BlockWithGui, "retrieveStringList");
QVERIFY(rstringlist.isValid());
QCOMPARE(rstringlist.value(), adaptor->retrieveStringList());
}
void tst_QDBusReply::complexTypes()
{
QDBusReply<QVariantList> rlist = iface->call(QDBus::BlockWithGui, "retrieveList");
QVERIFY(rlist.isValid());
QCOMPARE(rlist.value(), adaptor->retrieveList());
QDBusReply<QList<QDBusObjectPath> > rolist = iface->call(QDBus::BlockWithGui, "retrieveObjectPathList");
QVERIFY(rolist.isValid());
QCOMPARE(rolist.value(), adaptor->retrieveObjectPathList());
QDBusReply<QVariantMap> rmap = iface->call(QDBus::BlockWithGui, "retrieveMap");
QVERIFY(rmap.isValid());
QCOMPARE(rmap.value(), adaptor->retrieveMap());
QDBusReply<IntStringMap> rismap = iface->call(QDBus::BlockWithGui, "retrieveIntStringMap");
QVERIFY(rismap.isValid());
QCOMPARE(rismap.value(), adaptor->retrieveIntStringMap());
QDBusReply<MyStruct> rstruct = iface->call(QDBus::BlockWithGui, "retrieveStruct");
QVERIFY(rstruct.isValid());
QCOMPARE(rstruct.value(), adaptor->retrieveStruct());
}
void tst_QDBusReply::wrongTypes()
{
QDBusReply<bool> rbool = iface->call(QDBus::BlockWithGui, "retrieveInt");
QVERIFY(!rbool.isValid());
rbool = iface->call(QDBus::BlockWithGui, "retrieveShort");
QVERIFY(!rbool.isValid());
rbool = iface->call(QDBus::BlockWithGui, "retrieveStruct");
QVERIFY(!rbool.isValid());
QDBusReply<short> rshort = iface->call(QDBus::BlockWithGui, "retrieveInt");
QVERIFY(!rshort.isValid());
rshort = iface->call(QDBus::BlockWithGui, "retrieveBool");
QVERIFY(!rshort.isValid());
rshort = iface->call(QDBus::BlockWithGui, "retrieveStruct");
QVERIFY(!rshort.isValid());
QDBusReply<MyStruct> rstruct = iface->call(QDBus::BlockWithGui, "retrieveInt");
QVERIFY(!rstruct.isValid());
rstruct = iface->call(QDBus::BlockWithGui, "retrieveShort");
QVERIFY(!rstruct.isValid());
rstruct = iface->call(QDBus::BlockWithGui, "retrieveIntStringMap");
QVERIFY(!rstruct.isValid());
}
void tst_QDBusReply::error()
{
{
// Wrong type
QDBusReply<bool> result = iface->call(QDBus::BlockWithGui, "retrieveInt");
QVERIFY(result.error().isValid());
}
{
// Wrong type, const version
const QDBusReply<bool> result = iface->call(QDBus::BlockWithGui, "retrieveInt");
QVERIFY(result.error().isValid());
}
{
// Ok type
QDBusReply<void> result = iface->call(QDBus::BlockWithGui, "retrieveInt");
QVERIFY(!result.error().isValid());
}
{
// Ok type, const version
const QDBusReply<void> result = iface->call(QDBus::BlockWithGui, "retrieveInt");
QVERIFY(!result.error().isValid());
}
}
QTEST_MAIN(tst_QDBusReply)
#include "tst_qdbusreply.moc"

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbusservicewatcher Test:
#####################################################################
qt_internal_add_test(tst_qdbusservicewatcher
SOURCES
tst_qdbusservicewatcher.cpp
LIBRARIES
Qt::DBus
Qt::TestPrivate
)

View File

@ -0,0 +1,478 @@
// 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 <QtTest/private/qpropertytesthelper_p.h>
#include <QSignalSpy>
#include <QTestEventLoop>
#include <QDBusConnection>
#include <QDBusServiceWatcher>
class tst_QDBusServiceWatcher: public QObject
{
Q_OBJECT
int testCounter;
public:
tst_QDBusServiceWatcher();
private slots:
void initTestCase();
void watchForCreation_data();
void watchForCreation();
void watchForDisappearance_data();
void watchForDisappearance();
void watchForDisappearanceUniqueConnection();
void watchForOwnerChange_data();
void watchForOwnerChange();
void modeChange_data();
void modeChange();
void disconnectedConnection();
void setConnection_data();
void setConnection();
void bindings();
void bindingsAutomated();
private:
QString generateServiceName();
};
tst_QDBusServiceWatcher::tst_QDBusServiceWatcher()
: testCounter(0)
{
}
void tst_QDBusServiceWatcher::initTestCase()
{
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
}
QString tst_QDBusServiceWatcher::generateServiceName() {
return "com.example.TestService" + QString::number(testCounter++);
}
void tst_QDBusServiceWatcher::watchForCreation_data()
{
QTest::addColumn<QString>("watchedName");
QTest::addColumn<QString>("registeredName");
//com.example.TestService5 matches com.example.TestService5
QString name = generateServiceName();
QTest::newRow("normal") << name << name;
//com.example* matches com.example.TestService5
name = generateServiceName();
QTest::newRow("wildcard") << "com.example*" << name;
//com.example.TestService5* matches com.example.TestService5
name = generateServiceName();
QTest::newRow("wildcard_exact") << name+"*" << name;
//com.example.TestService5* matches com.example.TestService5.Foo
name = generateServiceName();
QTest::newRow("wildcard_subdomain") << name+"*" << name + ".Foo";
//com.example.TestService5* matches com.example.TestService5.Foo.Bar
name = generateServiceName();
QTest::newRow("wildcard_subsubdomain") << name+"*" << name + ".Foo.Bar";
}
void tst_QDBusServiceWatcher::watchForCreation()
{
QFETCH(QString, watchedName);
QFETCH(QString, registeredName);
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
QDBusServiceWatcher watcher(watchedName, con, QDBusServiceWatcher::WatchForRegistration);
QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString)));
QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString)));
QSignalSpy spyO(&watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)));
QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceRegistered(QString)), SLOT(exitLoop()));
// register a name
QVERIFY(con.registerService(registeredName));
QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(spyR.size(), 1);
QCOMPARE(spyR.at(0).at(0).toString(), registeredName);
QCOMPARE(spyU.size(), 0);
QCOMPARE(spyO.size(), 1);
QCOMPARE(spyO.at(0).at(0).toString(), registeredName);
QVERIFY(spyO.at(0).at(1).toString().isEmpty());
QCOMPARE(spyO.at(0).at(2).toString(), con.baseService());
spyR.clear();
spyU.clear();
spyO.clear();
// unregister it:
con.unregisterService(registeredName);
// and register again
QVERIFY(con.registerService(registeredName));
QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(spyR.size(), 1);
QCOMPARE(spyR.at(0).at(0).toString(), registeredName);
QCOMPARE(spyU.size(), 0);
QCOMPARE(spyO.size(), 1);
QCOMPARE(spyO.at(0).at(0).toString(), registeredName);
QVERIFY(spyO.at(0).at(1).toString().isEmpty());
QCOMPARE(spyO.at(0).at(2).toString(), con.baseService());
}
void tst_QDBusServiceWatcher::watchForDisappearance_data()
{
tst_QDBusServiceWatcher::watchForCreation_data();
}
void tst_QDBusServiceWatcher::watchForDisappearance()
{
QFETCH(QString, watchedName);
QFETCH(QString, registeredName);
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
QDBusServiceWatcher watcher(watchedName, con, QDBusServiceWatcher::WatchForUnregistration);
watcher.setObjectName("watcher for disappearance");
QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString)));
QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString)));
QSignalSpy spyO(&watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)));
QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceUnregistered(QString)), SLOT(exitLoop()));
// register a name
QVERIFY(con.registerService(registeredName));
// unregister it:
con.unregisterService(registeredName);
QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(spyR.size(), 0);
QCOMPARE(spyU.size(), 1);
QCOMPARE(spyU.at(0).at(0).toString(), registeredName);
QCOMPARE(spyO.size(), 1);
QCOMPARE(spyO.at(0).at(0).toString(), registeredName);
QCOMPARE(spyO.at(0).at(1).toString(), con.baseService());
QVERIFY(spyO.at(0).at(2).toString().isEmpty());
}
void tst_QDBusServiceWatcher::watchForDisappearanceUniqueConnection()
{
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
// second connection
QString watchedName = QDBusConnection::connectToBus(QDBusConnection::SessionBus, "session2").baseService();
QVERIFY(!watchedName.isEmpty());
QDBusServiceWatcher watcher(watchedName, con, QDBusServiceWatcher::WatchForUnregistration);
watcher.setObjectName("watcher for disappearance");
QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString)));
QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString)));
QSignalSpy spyO(&watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)));
QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceUnregistered(QString)), SLOT(exitLoop()));
// unregister it:
QDBusConnection::disconnectFromBus("session2");
QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(spyR.size(), 0);
QCOMPARE(spyU.size(), 1);
QCOMPARE(spyU.at(0).at(0).toString(), watchedName);
QCOMPARE(spyO.size(), 1);
QCOMPARE(spyO.at(0).at(0).toString(), watchedName);
QCOMPARE(spyO.at(0).at(1).toString(), watchedName);
QVERIFY(spyO.at(0).at(2).toString().isEmpty());
}
void tst_QDBusServiceWatcher::watchForOwnerChange_data()
{
watchForCreation_data();
}
void tst_QDBusServiceWatcher::watchForOwnerChange()
{
QFETCH(QString, watchedName);
QFETCH(QString, registeredName);
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
QDBusServiceWatcher watcher(watchedName, con, QDBusServiceWatcher::WatchForOwnerChange);
QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString)));
QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString)));
QSignalSpy spyO(&watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)));
QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceRegistered(QString)), SLOT(exitLoop()));
// register a name
QVERIFY(con.registerService(registeredName));
QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(spyR.size(), 1);
QCOMPARE(spyR.at(0).at(0).toString(), registeredName);
QCOMPARE(spyU.size(), 0);
QCOMPARE(spyO.size(), 1);
QCOMPARE(spyO.at(0).at(0).toString(), registeredName);
QVERIFY(spyO.at(0).at(1).toString().isEmpty());
QCOMPARE(spyO.at(0).at(2).toString(), con.baseService());
spyR.clear();
spyU.clear();
spyO.clear();
// unregister it:
con.unregisterService(registeredName);
// and register again
QVERIFY(con.registerService(registeredName));
QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(spyR.size(), 1);
QCOMPARE(spyR.at(0).at(0).toString(), registeredName);
QCOMPARE(spyU.size(), 1);
QCOMPARE(spyU.at(0).at(0).toString(), registeredName);
QCOMPARE(spyO.size(), 2);
QCOMPARE(spyO.at(0).at(0).toString(), registeredName);
QCOMPARE(spyO.at(0).at(1).toString(), con.baseService());
QVERIFY(spyO.at(0).at(2).toString().isEmpty());
QCOMPARE(spyO.at(1).at(0).toString(), registeredName);
QVERIFY(spyO.at(1).at(1).toString().isEmpty());
QCOMPARE(spyO.at(1).at(2).toString(), con.baseService());
}
void tst_QDBusServiceWatcher::modeChange_data()
{
watchForCreation_data();
}
void tst_QDBusServiceWatcher::modeChange()
{
QFETCH(QString, watchedName);
QFETCH(QString, registeredName);
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
QDBusServiceWatcher watcher(watchedName, con, QDBusServiceWatcher::WatchForRegistration);
QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString)));
QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString)));
QSignalSpy spyO(&watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)));
QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceRegistered(QString)), SLOT(exitLoop()));
// register a name
QVERIFY(con.registerService(registeredName));
QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(spyR.size(), 1);
QCOMPARE(spyR.at(0).at(0).toString(), registeredName);
QCOMPARE(spyU.size(), 0);
QCOMPARE(spyO.size(), 1);
QCOMPARE(spyO.at(0).at(0).toString(), registeredName);
QVERIFY(spyO.at(0).at(1).toString().isEmpty());
QCOMPARE(spyO.at(0).at(2).toString(), con.baseService());
spyR.clear();
spyU.clear();
spyO.clear();
watcher.setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
// unregister it:
con.unregisterService(registeredName);
QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceUnregistered(QString)), SLOT(exitLoop()));
QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(spyR.size(), 0);
QCOMPARE(spyU.size(), 1);
QCOMPARE(spyU.at(0).at(0).toString(), registeredName);
QCOMPARE(spyO.size(), 1);
QCOMPARE(spyO.at(0).at(0).toString(), registeredName);
QCOMPARE(spyO.at(0).at(1).toString(), con.baseService());
QVERIFY(spyO.at(0).at(2).toString().isEmpty());
}
void tst_QDBusServiceWatcher::disconnectedConnection()
{
QDBusConnection con("");
QVERIFY(!con.isConnected());
QDBusServiceWatcher watcher(generateServiceName(), con, QDBusServiceWatcher::WatchForRegistration);
watcher.addWatchedService("com.example.somethingelse");
watcher.addWatchedService("org.freedesktop.DBus");
watcher.setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
watcher.setWatchMode(QDBusServiceWatcher::WatchForOwnerChange);
watcher.setWatchedServices(QStringList());
}
void tst_QDBusServiceWatcher::setConnection_data()
{
QTest::addColumn<QString>("serviceName");
QTest::newRow("normal") << generateServiceName();
}
void tst_QDBusServiceWatcher::setConnection()
{
QFETCH(QString, serviceName);
// begin with a disconnected connection
QDBusConnection con("");
QVERIFY(!con.isConnected());
QDBusServiceWatcher watcher(serviceName, con, QDBusServiceWatcher::WatchForRegistration);
QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString)));
QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString)));
QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), SLOT(exitLoop()));
// move to the session bus
con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
watcher.setConnection(con);
// register a name
QVERIFY(con.registerService(serviceName));
QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(spyR.size(), 1);
QCOMPARE(spyR.at(0).at(0).toString(), serviceName);
QCOMPARE(spyU.size(), 0);
// is the system bus available?
if (!QDBusConnection::systemBus().isConnected())
return;
// connect to the system bus and ask to watch that base service
QString watchedName = QDBusConnection::connectToBus(QDBusConnection::SystemBus, "system2").baseService();
watcher.setWatchedServices(QStringList() << watchedName);
watcher.setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
// move to the system bus
watcher.setConnection(QDBusConnection::systemBus());
spyR.clear();
spyU.clear();
QDBusConnection::disconnectFromBus("system2");
QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(spyR.size(), 0);
QCOMPARE(spyU.size(), 1);
QCOMPARE(spyU.at(0).at(0).toString(), watchedName);
}
void tst_QDBusServiceWatcher::bindings()
{
QString serviceName("normal");
QDBusConnection con("");
QVERIFY(!con.isConnected());
QDBusServiceWatcher watcher(serviceName, con, QDBusServiceWatcher::WatchForRegistration);
QProperty<QDBusServiceWatcher::WatchMode> follower;
int notificationCounter = 0;
auto connection = follower.subscribe([&]() { notificationCounter++; });
QCOMPARE(notificationCounter, 1);
follower.setBinding([&]() { return watcher.watchMode(); });
QCOMPARE(follower.value(), QDBusServiceWatcher::WatchForRegistration);
QCOMPARE(notificationCounter, 2);
watcher.setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
QCOMPARE(follower.value(), QDBusServiceWatcher::WatchForUnregistration);
QCOMPARE(notificationCounter, 3);
QProperty<QDBusServiceWatcher::WatchMode> leader(QDBusServiceWatcher::WatchForRegistration);
watcher.bindableWatchMode().setBinding([&]() { return leader.value(); });
QCOMPARE(follower.value(), QDBusServiceWatcher::WatchForRegistration);
QCOMPARE(notificationCounter, 4);
leader = QDBusServiceWatcher::WatchForUnregistration;
QCOMPARE(follower.value(), QDBusServiceWatcher::WatchForUnregistration);
QCOMPARE(notificationCounter, 5);
// check that setting a value breaks the binding
watcher.setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
QCOMPARE(notificationCounter, 5);
leader = QDBusServiceWatcher::WatchForRegistration;
QCOMPARE(follower.value(), QDBusServiceWatcher::WatchForUnregistration);
// check that setting the same value again does not trigger notification
watcher.setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
QCOMPARE(notificationCounter, 5);
}
void tst_QDBusServiceWatcher::bindingsAutomated()
{
QString serviceName("normal");
QDBusConnection con("");
QVERIFY(!con.isConnected());
QDBusServiceWatcher watcher(serviceName, con, QDBusServiceWatcher::WatchForRegistration);
QTestPrivate::testReadWritePropertyBasics<QDBusServiceWatcher, QStringList>(
watcher,
QStringList() << "foo" << "bar",
QStringList() << "bar" << "foo",
"watchedServices");
if (QTest::currentTestFailed()) {
qDebug("Failed property test for QDBusServiceWatcher::watchedServices");
return;
}
QTestPrivate::testReadWritePropertyBasics<QDBusServiceWatcher,
QFlags<QDBusServiceWatcher::WatchModeFlag>>(
watcher, QDBusServiceWatcher::WatchForUnregistration,
QDBusServiceWatcher::WatchForRegistration, "watchMode");
if (QTest::currentTestFailed()) {
qDebug("Failed property test for QDBusServiceWatcher::watchMode");
return;
}
}
QTEST_MAIN(tst_QDBusServiceWatcher)
#include "tst_qdbusservicewatcher.moc"

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbusthreading Test:
#####################################################################
qt_internal_add_test(tst_qdbusthreading
SOURCES
tst_qdbusthreading.cpp
LIBRARIES
Qt::DBus
)

View File

@ -0,0 +1,574 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QTestEventLoop>
#include <QVarLengthArray>
#include <QThread>
#include <QObject>
#include <QSemaphore>
#include <QMutex>
#include <QWaitCondition>
#include <QMap>
#include <QDBusAbstractAdaptor>
#include <QDBusConnection>
#include <QDBusReply>
#include <QDBusConnectionInterface>
#include <QDBusInterface>
class Thread : public QThread
{
Q_OBJECT
static int counter;
public:
Thread(bool automatic = true);
void run() override;
using QThread::exec;
};
int Thread::counter;
class tst_QDBusThreading : public QObject
{
Q_OBJECT
static tst_QDBusThreading *_self;
QAtomicInt threadJoinCount;
QSemaphore threadJoin;
public:
QSemaphore sem1, sem2;
volatile bool success;
QEventLoop *loop;
enum FunctionSpy {
NoMethod = 0,
Adaptor_method,
Object_method
} functionSpy;
QThread *threadSpy;
int signalSpy;
tst_QDBusThreading();
static inline tst_QDBusThreading *self() { return _self; }
void joinThreads();
bool waitForSignal(QObject *obj, const char *signal, int delay = 1);
public Q_SLOTS:
void cleanup();
void signalSpySlot() { ++signalSpy; }
void threadStarted() { threadJoinCount.ref(); }
void threadFinished() { threadJoin.release(); }
void dyingThread_thread();
void lastInstanceInOtherThread_thread();
void concurrentCreation_thread();
void disconnectAnothersConnection_thread();
void accessMainsConnection_thread();
void accessOthersConnection_thread();
void registerObjectInOtherThread_thread();
void registerAdaptorInOtherThread_thread();
void callbackInMainThread_thread();
void callbackInAuxThread_thread();
void callbackInAnotherAuxThread_thread();
private Q_SLOTS:
void dyingThread();
void lastInstanceInOtherThread();
void concurrentCreation();
void disconnectAnothersConnection();
void accessMainsConnection();
void accessOthersConnection();
void registerObjectInOtherThread();
void registerAdaptorInOtherThread();
void callbackInMainThread();
void callbackInAuxThread();
void callbackInAnotherAuxThread();
};
tst_QDBusThreading *tst_QDBusThreading::_self;
class Adaptor : public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "local.Adaptor")
public:
Adaptor(QObject *parent)
: QDBusAbstractAdaptor(parent)
{
}
public Q_SLOTS:
void method()
{
tst_QDBusThreading::self()->functionSpy = tst_QDBusThreading::Adaptor_method;
tst_QDBusThreading::self()->threadSpy = QThread::currentThread();
emit signal();
}
Q_SIGNALS:
void signal();
};
class Object : public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "local.Object")
public:
Object(bool useAdaptor)
{
if (useAdaptor)
new Adaptor(this);
}
~Object()
{
QMetaObject::invokeMethod(QThread::currentThread(), "quit", Qt::QueuedConnection);
}
public Q_SLOTS:
void method()
{
tst_QDBusThreading::self()->functionSpy = tst_QDBusThreading::Object_method;
tst_QDBusThreading::self()->threadSpy = QThread::currentThread();
emit signal();
deleteLater();
}
Q_SIGNALS:
void signal();
};
#if 0
typedef void (*qdbusThreadDebugFunc)(int, int, QDBusConnectionPrivate *);
QDBUS_EXPORT void qdbusDefaultThreadDebug(int, int, QDBusConnectionPrivate *);
extern QDBUS_EXPORT qdbusThreadDebugFunc qdbusThreadDebug;
static void threadDebug(int action, int condition, QDBusConnectionPrivate *p)
{
qdbusDefaultThreadDebug(action, condition, p);
}
#endif
Thread::Thread(bool automatic)
{
setObjectName(QString::fromLatin1("Aux thread %1").arg(++counter));
connect(this, SIGNAL(started()), tst_QDBusThreading::self(), SLOT(threadStarted()));
connect(this, SIGNAL(finished()), tst_QDBusThreading::self(), SLOT(threadFinished()),
Qt::DirectConnection);
connect(this, SIGNAL(finished()), this, SLOT(deleteLater()), Qt::DirectConnection);
if (automatic)
start();
}
void Thread::run()
{
QVarLengthArray<char, 56> name;
name.append(QTest::currentTestFunction(), qstrlen(QTest::currentTestFunction()));
name.append("_thread", sizeof "_thread");
QMetaObject::invokeMethod(tst_QDBusThreading::self(), name.constData(), Qt::DirectConnection);
}
static const char myConnectionName[] = "connection";
tst_QDBusThreading::tst_QDBusThreading()
: loop(0), functionSpy(NoMethod), threadSpy(0)
{
_self = this;
QCoreApplication::instance()->thread()->setObjectName("Main thread");
}
void tst_QDBusThreading::joinThreads()
{
threadJoin.acquire(threadJoinCount.loadRelaxed());
threadJoinCount.storeRelaxed(0);
}
bool tst_QDBusThreading::waitForSignal(QObject *obj, const char *signal, int delay)
{
QObject::connect(obj, signal, &QTestEventLoop::instance(), SLOT(exitLoop()));
QPointer<QObject> safe = obj;
QTestEventLoop::instance().enterLoop(delay);
if (!safe.isNull())
QObject::disconnect(safe, signal, &QTestEventLoop::instance(), SLOT(exitLoop()));
return QTestEventLoop::instance().timeout();
}
void tst_QDBusThreading::cleanup()
{
joinThreads();
if (sem1.available())
sem1.acquire(sem1.available());
if (sem2.available())
sem2.acquire(sem2.available());
if (QDBusConnection(myConnectionName).isConnected())
QDBusConnection::disconnectFromBus(myConnectionName);
delete loop;
loop = 0;
QTest::qWait(500);
}
void tst_QDBusThreading::dyingThread_thread()
{
QDBusConnection::connectToBus(QDBusConnection::SessionBus, myConnectionName);
}
void tst_QDBusThreading::dyingThread()
{
Thread *th = new Thread(false);
QTestEventLoop::instance().connect(th, SIGNAL(destroyed(QObject*)), SLOT(exitLoop()));
th->start();
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
QDBusConnection con(myConnectionName);
QDBusConnection::disconnectFromBus(myConnectionName);
QVERIFY(con.isConnected());
QDBusReply<QStringList> reply = con.interface()->registeredServiceNames();
QVERIFY(reply.isValid());
QVERIFY(!reply.value().isEmpty());
QVERIFY(reply.value().contains(con.baseService()));
con.interface()->callWithCallback("ListNames", QVariantList(),
&QTestEventLoop::instance(), SLOT(exitLoop()));
QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout());
}
void tst_QDBusThreading::lastInstanceInOtherThread_thread()
{
QDBusConnection con(myConnectionName);
QVERIFY(con.isConnected());
QDBusConnection::disconnectFromBus(myConnectionName);
// con is being destroyed in the wrong thread
}
void tst_QDBusThreading::lastInstanceInOtherThread()
{
Thread *th = new Thread(false);
// create the connection:
QDBusConnection::connectToBus(QDBusConnection::SessionBus, myConnectionName);
th->start();
th->wait();
}
void tst_QDBusThreading::concurrentCreation_thread()
{
sem1.acquire();
QDBusConnection con = QDBusConnection::connectToBus(QDBusConnection::SessionBus,
myConnectionName);
sem2.release();
}
void tst_QDBusThreading::concurrentCreation()
{
Thread *th = new Thread;
{
sem1.release();
QDBusConnection con = QDBusConnection::connectToBus(QDBusConnection::SessionBus,
myConnectionName);
QVERIFY(con.isConnected());
sem2.acquire();
}
waitForSignal(th, SIGNAL(finished()));
QDBusConnection::disconnectFromBus(myConnectionName);
QVERIFY(!QDBusConnection(myConnectionName).isConnected());
}
void tst_QDBusThreading::disconnectAnothersConnection_thread()
{
QDBusConnection con = QDBusConnection::connectToBus(QDBusConnection::SessionBus,
myConnectionName);
sem2.release();
}
void tst_QDBusThreading::disconnectAnothersConnection()
{
new Thread;
sem2.acquire();
QVERIFY(QDBusConnection(myConnectionName).isConnected());
QDBusConnection::disconnectFromBus(myConnectionName);
}
void tst_QDBusThreading::accessMainsConnection_thread()
{
sem1.acquire();
QDBusConnection con = QDBusConnection::sessionBus();
con.interface()->registeredServiceNames();
sem2.release();
}
void tst_QDBusThreading::accessMainsConnection()
{
QVERIFY(QDBusConnection::sessionBus().isConnected());
new Thread;
sem1.release();
sem2.acquire();
};
void tst_QDBusThreading::accessOthersConnection_thread()
{
QDBusConnection::connectToBus(QDBusConnection::SessionBus, myConnectionName);
sem2.release();
// wait for main thread to be done
sem1.acquire();
QDBusConnection::disconnectFromBus(myConnectionName);
sem2.release();
}
void tst_QDBusThreading::accessOthersConnection()
{
new Thread;
// wait for the connection to be created
sem2.acquire();
{
QDBusConnection con(myConnectionName);
QVERIFY(con.isConnected());
QVERIFY(con.baseService() != QDBusConnection::sessionBus().baseService());
QDBusReply<QStringList> reply = con.interface()->registeredServiceNames();
if (!reply.isValid())
qDebug() << reply.error().name() << reply.error().message();
QVERIFY(reply.isValid());
QVERIFY(!reply.value().isEmpty());
QVERIFY(reply.value().contains(con.baseService()));
QVERIFY(reply.value().contains(QDBusConnection::sessionBus().baseService()));
}
// tell it to destroy:
sem1.release();
sem2.acquire();
QDBusConnection con(myConnectionName);
QVERIFY(!con.isConnected());
}
void tst_QDBusThreading::registerObjectInOtherThread_thread()
{
{
Object *obj = new Object(false);
QDBusConnection::sessionBus().registerObject("/", obj, QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals);
sem2.release();
static_cast<Thread *>(QThread::currentThread())->exec();
}
sem2.release();
}
void tst_QDBusThreading::registerObjectInOtherThread()
{
QVERIFY(QDBusConnection::sessionBus().isConnected());
QThread *th = new Thread;
sem2.acquire();
signalSpy = 0;
QDBusInterface iface(QDBusConnection::sessionBus().baseService(), "/", "local.Object");
QVERIFY(iface.isValid());
connect(&iface, SIGNAL(signal()), SLOT(signalSpySlot()));
QTest::qWait(100);
QCOMPARE(signalSpy, 0);
functionSpy = NoMethod;
threadSpy = 0;
QDBusReply<void> reply = iface.call("method");
QVERIFY(reply.isValid());
QCOMPARE(functionSpy, Object_method);
QCOMPARE(threadSpy, th);
QTRY_COMPARE(signalSpy, 1);
sem2.acquire(); // the object is gone
functionSpy = NoMethod;
threadSpy = 0;
reply = iface.call("method");
QVERIFY(!reply.isValid());
QCOMPARE(functionSpy, NoMethod);
QCOMPARE(threadSpy, (QThread*)0);
}
void tst_QDBusThreading::registerAdaptorInOtherThread_thread()
{
{
Object *obj = new Object(true);
QDBusConnection::sessionBus().registerObject("/", obj, QDBusConnection::ExportAdaptors |
QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals);
sem2.release();
static_cast<Thread *>(QThread::currentThread())->exec();
}
sem2.release();
}
void tst_QDBusThreading::registerAdaptorInOtherThread()
{
QVERIFY(QDBusConnection::sessionBus().isConnected());
QThread *th = new Thread;
sem2.acquire();
QDBusInterface object(QDBusConnection::sessionBus().baseService(), "/", "local.Object");
QDBusInterface adaptor(QDBusConnection::sessionBus().baseService(), "/", "local.Adaptor");
QVERIFY(object.isValid());
QVERIFY(adaptor.isValid());
signalSpy = 0;
connect(&adaptor, SIGNAL(signal()), SLOT(signalSpySlot()));
QCOMPARE(signalSpy, 0);
functionSpy = NoMethod;
threadSpy = 0;
QDBusReply<void> reply = adaptor.call("method");
QVERIFY(reply.isValid());
QCOMPARE(functionSpy, Adaptor_method);
QCOMPARE(threadSpy, th);
QTRY_COMPARE(signalSpy, 1);
functionSpy = NoMethod;
threadSpy = 0;
reply = object.call("method");
QVERIFY(reply.isValid());
QCOMPARE(functionSpy, Object_method);
QCOMPARE(threadSpy, th);
QTest::qWait(100);
QCOMPARE(signalSpy, 1);
sem2.acquire(); // the object is gone
functionSpy = NoMethod;
threadSpy = 0;
reply = adaptor.call("method");
QVERIFY(!reply.isValid());
QCOMPARE(functionSpy, NoMethod);
QCOMPARE(threadSpy, (QThread*)0);
reply = object.call("method");
QVERIFY(!reply.isValid());
QCOMPARE(functionSpy, NoMethod);
QCOMPARE(threadSpy, (QThread*)0);
}
void tst_QDBusThreading::callbackInMainThread_thread()
{
QDBusConnection::connectToBus(QDBusConnection::SessionBus, myConnectionName);
sem2.release();
static_cast<Thread *>(QThread::currentThread())->exec();
QDBusConnection::disconnectFromBus(myConnectionName);
}
void tst_QDBusThreading::callbackInMainThread()
{
Thread *th = new Thread;
// wait for it to be connected
sem2.acquire();
QDBusConnection con(myConnectionName);
con.interface()->callWithCallback("ListNames", QVariantList(),
&QTestEventLoop::instance(), SLOT(exitLoop()));
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
QMetaObject::invokeMethod(th, "quit");
waitForSignal(th, SIGNAL(finished()));
}
void tst_QDBusThreading::callbackInAuxThread_thread()
{
QDBusConnection con(QDBusConnection::sessionBus());
QTestEventLoop ownLoop;
con.interface()->callWithCallback("ListNames", QVariantList(),
&ownLoop, SLOT(exitLoop()));
ownLoop.enterLoop(10);
loop->exit(ownLoop.timeout() ? 1 : 0);
}
void tst_QDBusThreading::callbackInAuxThread()
{
QVERIFY(QDBusConnection::sessionBus().isConnected());
loop = new QEventLoop;
new Thread;
QCOMPARE(loop->exec(), 0);
}
void tst_QDBusThreading::callbackInAnotherAuxThread_thread()
{
sem1.acquire();
if (!loop) {
// first thread
// create the connection and just wait
QDBusConnection con = QDBusConnection::connectToBus(QDBusConnection::SessionBus, myConnectionName);
loop = new QEventLoop;
// tell the main thread we have created the loop and connection
sem2.release();
// wait for the main thread to connect its signal
sem1.acquire();
success = loop->exec() == 0;
sem2.release();
// clean up
QDBusConnection::disconnectFromBus(myConnectionName);
} else {
// second thread
// try waiting for a message
QDBusConnection con(myConnectionName);
QTestEventLoop ownLoop;
con.interface()->callWithCallback("ListNames", QVariantList(),
&ownLoop, SLOT(exitLoop()));
ownLoop.enterLoop(1);
loop->exit(ownLoop.timeout() ? 1 : 0);
}
}
void tst_QDBusThreading::callbackInAnotherAuxThread()
{
// create first thread
success = false;
new Thread;
// wait for the event loop
sem1.release();
sem2.acquire();
QVERIFY(loop);
// create the second thread
new Thread;
sem1.release(2);
// wait for loop thread to finish executing:
sem2.acquire();
QVERIFY(success);
}
// Next tests:
// - unexport an object at the moment the call is being delivered
// - delete an object at the moment the call is being delivered
// - keep a global-static QDBusConnection for a thread-created connection
QTEST_MAIN(tst_QDBusThreading)
#include "tst_qdbusthreading.moc"

View File

@ -0,0 +1,29 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbustype Test:
#####################################################################
qt_internal_add_test(tst_qdbustype
SOURCES
tst_qdbustype.cpp
LIBRARIES
Qt::CorePrivate
Qt::DBusPrivate
)
## Scopes:
#####################################################################
qt_internal_extend_target(tst_qdbustype CONDITION QT_FEATURE_dbus_linked
DEFINES
QT_LINKED_LIBDBUS
LIBRARIES
dbus-1
)
qt_internal_extend_target(tst_qdbustype CONDITION NOT QT_FEATURE_dbus_linked
SOURCES
../../../../src/dbus/qdbus_symbols.cpp
)

View File

@ -0,0 +1,260 @@
// 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 <QtCore/QCoreApplication>
#include <QtDBus/private/qdbusutil_p.h>
#include <QtDBus/private/qdbus_symbols_p.h>
DEFINEFUNC(dbus_bool_t, dbus_signature_validate, (const char *signature,
DBusError *error),
(signature, error), return)
DEFINEFUNC(dbus_bool_t, dbus_signature_validate_single, (const char *signature,
DBusError *error),
(signature, error), return)
DEFINEFUNC(dbus_bool_t, dbus_type_is_basic, (int typecode),
(typecode), return)
DEFINEFUNC(dbus_bool_t, dbus_type_is_fixed, (int typecode),
(typecode), return)
class tst_QDBusType : public QObject
{
Q_OBJECT
private Q_SLOTS:
void isValidFixedType_data();
void isValidFixedType();
void isValidBasicType_data();
void isValidBasicType();
void isValidSingleSignature_data();
void isValidSingleSignature();
void isValidArray_data();
void isValidArray();
void isValidSignature_data();
void isValidSignature();
};
enum { Invalid = false, Valid = true };
static void addColumns()
{
// All tests use these two columns only
QTest::addColumn<QString>("data");
QTest::addColumn<bool>("result");
QTest::addColumn<bool>("isValid");
}
// ---- type adds ---
static void addFixedTypes()
{
QTest::newRow("bool") << DBUS_TYPE_BOOLEAN_AS_STRING << true << true;
QTest::newRow("byte") << DBUS_TYPE_BYTE_AS_STRING << true << true;
QTest::newRow("int16") << DBUS_TYPE_INT16_AS_STRING << true << true;
QTest::newRow("uint16") << DBUS_TYPE_UINT16_AS_STRING << true << true;
QTest::newRow("int32") << DBUS_TYPE_INT32_AS_STRING << true << true;
QTest::newRow("uint32") << DBUS_TYPE_UINT32_AS_STRING << true << true;
QTest::newRow("int64") << DBUS_TYPE_INT64_AS_STRING << true << true;
QTest::newRow("uint64") << DBUS_TYPE_UINT64_AS_STRING << true << true;
QTest::newRow("double") << DBUS_TYPE_DOUBLE_AS_STRING << true << true;
#ifdef DBUS_TYPE_UNIX_FD_AS_STRING
# ifndef QT_LINKED_LIBDBUS
// We have got the macro from dbus_minimal_p.h, so we need to check if
// the library recognizes this as valid type first.
// The following function was added for Unix FD support, so if it is
// present, so is support for Unix FDs.
# if QT_CONFIG(library)
bool supportsUnixFds = qdbus_resolve_conditionally("dbus_connection_can_send_type");
# else
bool supportsUnixFds = false;
# endif
# else
bool supportsUnixFds = true;
# endif
if (supportsUnixFds)
QTest::newRow("unixfd") << DBUS_TYPE_UNIX_FD_AS_STRING << true << true;
#endif
}
static void addInvalidSingleLetterTypes()
{
QChar nulString[] = { '\0' };
QTest::newRow("nul") << QString(nulString, 1) << false << false;
QTest::newRow("tilde") << "~" << false << false;
QTest::newRow("struct-begin") << "(" << false << false;
QTest::newRow("struct-end") << ")" << false << false;
QTest::newRow("dict-entry-begin") << "{" << false << false;
QTest::newRow("dict-entry-end") << "}" << false << false;
QTest::newRow("array-no-element") << "a" << false << false;
}
static void addBasicTypes(bool basicsAreValid)
{
addFixedTypes();
QTest::newRow("string") << DBUS_TYPE_STRING_AS_STRING << basicsAreValid << true;
QTest::newRow("object-path") << DBUS_TYPE_OBJECT_PATH_AS_STRING << basicsAreValid << true;
QTest::newRow("signature") << DBUS_TYPE_SIGNATURE_AS_STRING << basicsAreValid << true;
}
static void addVariant(bool variantIsValid)
{
QTest::newRow("variant") << "v" << variantIsValid << true;
}
static void addSingleSignatures()
{
addBasicTypes(Valid);
addVariant(Valid);
QTest::newRow("struct-1") << "(y)" << true;
QTest::newRow("struct-2") << "(yy)" << true;
QTest::newRow("struct-3") << "(yyv)" << true;
QTest::newRow("struct-nested-1") << "((y))" << true;
QTest::newRow("struct-nested-2") << "((yy))" << true;
QTest::newRow("struct-nested-3") << "(y(y))" << true;
QTest::newRow("struct-nested-4") << "((y)y)" << true;
QTest::newRow("struct-nested-5") << "(y(y)y)" << true;
QTest::newRow("struct-nested-6") << "((y)(y))" << true;
QTest::newRow("array-1") << "as" << true;
QTest::newRow("struct-array-1") << "(as)" << true;
QTest::newRow("struct-array-2") << "(yas)" << true;
QTest::newRow("struct-array-3") << "(asy)" << true;
QTest::newRow("struct-array-4") << "(yasy)" << true;
QTest::newRow("dict-1") << "a{sy}" << true;
QTest::newRow("dict-2") << "a{sv}" << true;
QTest::newRow("dict-struct-1") << "a{s(y)}" << true;
QTest::newRow("dict-struct-2") << "a{s(yyyy)}" << true;
QTest::newRow("dict-struct-array") << "a{s(ay)}" << true;
QTest::newRow("dict-array") << "a{sas}" << true;
QTest::newRow("dict-array-struct") << "a{sa(y)}" << true;
addInvalidSingleLetterTypes();
QTest::newRow("naked-dict-empty") << "{}" << false;
QTest::newRow("naked-dict-missing-value") << "{i}" << false;
QTest::newRow("dict-empty") << "a{}" << false;
QTest::newRow("dict-missing-value") << "a{i}" << false;
QTest::newRow("dict-non-basic-key") << "a{vi}" << false;
QTest::newRow("dict-struct-key") << "a{(y)y}" << false;
QTest::newRow("dict-missing-close") << "a{sv" << false;
QTest::newRow("dict-mismatched-close") << "a{sv)" << false;
QTest::newRow("dict-missing-value-close") << "a{s" << false;
QTest::newRow("empty-struct") << "()" << false;
QTest::newRow("struct-missing-close") << "(s" << false;
QTest::newRow("struct-nested-missing-close-1") << "((s)" << false;
QTest::newRow("struct-nested-missing-close-2") << "((s" << false;
QTest::newRow("struct-ending-array-no-element") << "(a)" << false;
}
static void addNakedDictEntry()
{
QTest::newRow("naked-dict-entry") << "{sv}" << false;
}
// ---- tests ----
void tst_QDBusType::isValidFixedType_data()
{
addColumns();
addBasicTypes(Invalid);
addVariant(Invalid);
addInvalidSingleLetterTypes();
}
void tst_QDBusType::isValidFixedType()
{
QFETCH(QString, data);
QFETCH(bool, result);
QFETCH(bool, isValid);
QVERIFY2(data.size() == 1, "Test is malformed, this function must test only one-letter types");
QVERIFY(isValid || (!isValid && !result));
int type = data.at(0).unicode();
if (isValid)
QCOMPARE(bool(q_dbus_type_is_fixed(type)), result);
QCOMPARE(QDBusUtil::isValidFixedType(type), result);
}
void tst_QDBusType::isValidBasicType_data()
{
addColumns();
addBasicTypes(Valid);
addVariant(Invalid);
addInvalidSingleLetterTypes();
}
void tst_QDBusType::isValidBasicType()
{
QFETCH(QString, data);
QFETCH(bool, result);
QFETCH(bool, isValid);
QVERIFY2(data.size() == 1, "Test is malformed, this function must test only one-letter types");
QVERIFY(isValid || (!isValid && !result));
int type = data.at(0).unicode();
if (isValid)
QCOMPARE(bool(q_dbus_type_is_basic(type)), result);
QCOMPARE(QDBusUtil::isValidBasicType(type), result);
}
void tst_QDBusType::isValidSingleSignature_data()
{
addColumns();
addSingleSignatures();
addNakedDictEntry();
}
void tst_QDBusType::isValidSingleSignature()
{
QFETCH(QString, data);
QFETCH(bool, result);
QCOMPARE(bool(q_dbus_signature_validate_single(data.toLatin1(), 0)), result);
QCOMPARE(QDBusUtil::isValidSingleSignature(data), result);
}
void tst_QDBusType::isValidArray_data()
{
addColumns();
addSingleSignatures();
}
void tst_QDBusType::isValidArray()
{
QFETCH(QString, data);
QFETCH(bool, result);
data.prepend(QLatin1Char('a'));
QCOMPARE(bool(q_dbus_signature_validate_single(data.toLatin1(), 0)), result);
QCOMPARE(QDBusUtil::isValidSingleSignature(data), result);
data.prepend(QLatin1Char('a'));
QCOMPARE(bool(q_dbus_signature_validate_single(data.toLatin1(), 0)), result);
QCOMPARE(QDBusUtil::isValidSingleSignature(data), result);
}
void tst_QDBusType::isValidSignature_data()
{
isValidSingleSignature_data();
}
void tst_QDBusType::isValidSignature()
{
QFETCH(QString, data);
QFETCH(bool, result);
data.append(data);
if (data.at(0).unicode())
QCOMPARE(bool(q_dbus_signature_validate(data.toLatin1(), 0)), result);
QCOMPARE(QDBusUtil::isValidSignature(data), result);
}
QTEST_MAIN(tst_QDBusType)
#include "tst_qdbustype.moc"

View File

@ -0,0 +1,15 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdbusxmlparser Test:
#####################################################################
qt_internal_add_test(tst_qdbusxmlparser
SOURCES
tst_qdbusxmlparser.cpp
LIBRARIES
Qt::CorePrivate
Qt::DBusPrivate
Qt::Xml
)

View File

@ -0,0 +1,540 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QCoreApplication>
#include <QDomDocument>
#include <QMetaType>
#include <QTest>
#define USE_PRIVATE_CODE
#include "../qdbusmarshall/common.h"
class tst_QDBusXmlParser: public QObject
{
Q_OBJECT
private:
void parsing_common(const QString&);
QString clean_xml(const QString&);
private slots:
void initTestCase();
void parsing_data();
void parsing();
void parsingWithDoctype_data();
void parsingWithDoctype();
void methods_data();
void methods();
void signals__data();
void signals_();
void properties_data();
void properties();
};
void tst_QDBusXmlParser::initTestCase()
{
// Always initialize the hash seed with a known value to get reliable test results
QHashSeed::setDeterministicGlobalSeed();
}
void tst_QDBusXmlParser::parsing_data()
{
QTest::addColumn<QString>("xmlData");
QTest::addColumn<int>("interfaceCount");
QTest::addColumn<int>("objectCount");
QTest::addColumn<int>("annotationCount");
QTest::addColumn<QStringList>("introspection");
QStringList introspection;
QTest::newRow("null") << QString() << 0 << 0 << 0 << introspection;
QTest::newRow("empty") << QString("") << 0 << 0 << 0 << introspection;
QTest::newRow("junk") << "<junk/>" << 0 << 0 << 0 << introspection;
QTest::newRow("interface-inside-junk") << "<junk><interface name=\"iface.iface1\" /></junk>"
<< 0 << 0 << 0 << introspection;
QTest::newRow("object-inside-junk") << "<junk><node name=\"obj1\" /></junk>"
<< 0 << 0 << 0 << introspection;
QTest::newRow("zero-interfaces") << "<node/>" << 0 << 0 << 0 << introspection;
introspection << "<interface name=\"iface.iface1\"/>";
QTest::newRow("one-interface") << "<node><interface name=\"iface.iface1\" /></node>"
<< 1 << 0 << 0 << introspection;
introspection.clear();
introspection << "<interface name=\"iface.iface1\"/>"
<< "<interface name=\"iface.iface2\"/>";
QTest::newRow("two-interfaces") << "<node><interface name=\"iface.iface1\" />"
"<interface name=\"iface.iface2\" /></node>"
<< 2 << 0 << 0 << introspection;
introspection.clear();
QTest::newRow("one-object") << "<node><node name=\"obj1\"/></node>"
<< 0 << 1 << 0 << introspection;
QTest::newRow("two-objects") << "<node><node name=\"obj1\"/><node name=\"obj2\"/></node>"
<< 0 << 2 << 0 << introspection;
introspection << "<interface name=\"iface.iface1\"/>";
QTest::newRow("i1o1") << "<node><interface name=\"iface.iface1\"/><node name=\"obj1\"/></node>"
<< 1 << 1 << 0 << introspection;
introspection.clear();
introspection << "<interface name=\"iface.iface1\">"
" <annotation name=\"foo.testing\" value=\"nothing to see here\"/>"
"</interface>";
QTest::newRow("one-interface-annotated") << "<node><interface name=\"iface.iface1\">"
"<annotation name=\"foo.testing\" value=\"nothing to see here\" />"
"</interface></node>" << 1 << 0 << 1 << introspection;
introspection.clear();
introspection << "<interface name=\"iface.iface1\"/>";
QTest::newRow("one-interface-docnamespace") << "<?xml version=\"1.0\" xmlns:doc=\"foo\" ?><node>"
"<interface name=\"iface.iface1\"><doc:something />"
"</interface></node>" << 1 << 0 << 0 << introspection;
introspection.clear();
}
void tst_QDBusXmlParser::parsing_common(const QString &xmlData)
{
QDBusIntrospection::Object obj =
QDBusIntrospection::parseObject(xmlData, "local.testing", "/");
QFETCH(int, interfaceCount);
QFETCH(int, objectCount);
QFETCH(int, annotationCount);
QFETCH(QStringList, introspection);
QCOMPARE(obj.interfaces.size(), interfaceCount);
QCOMPARE(obj.childObjects.size(), objectCount);
QCOMPARE(QDBusIntrospection::parseInterface(xmlData).annotations.size(), annotationCount);
QDBusIntrospection::Interfaces ifaces = QDBusIntrospection::parseInterfaces(xmlData);
// also verify the naming
int i = 0;
foreach (QString name, obj.interfaces) {
const QString expectedName = QString("iface.iface%1").arg(i+1);
QCOMPARE(name, expectedName);
const QString expectedIntrospection = clean_xml(introspection.at(i++));
const QString resultIntrospection = clean_xml(ifaces.value(expectedName)->introspection);
QCOMPARE(resultIntrospection, expectedIntrospection);
}
i = 0;
foreach (QString name, obj.childObjects)
QCOMPARE(name, QString("obj%1").arg(++i));
}
QString tst_QDBusXmlParser::clean_xml(const QString &xmlData)
{
QDomDocument dom;
dom.setContent(xmlData);
return dom.toString();
}
void tst_QDBusXmlParser::parsing()
{
QFETCH(QString, xmlData);
parsing_common(xmlData);
}
void tst_QDBusXmlParser::parsingWithDoctype_data()
{
parsing_data();
}
void tst_QDBusXmlParser::parsingWithDoctype()
{
QString docType = "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
"\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n";
QFETCH(QString, xmlData);
QString toParse;
if (xmlData.startsWith(QLatin1String("<?xml"))) {
int split = xmlData.indexOf(QLatin1Char('>')) + 1;
toParse = xmlData.left(split) + docType + xmlData.mid(split);
} else {
toParse = docType + xmlData;
}
parsing_common(toParse);
}
void tst_QDBusXmlParser::methods_data()
{
QTest::addColumn<QString>("xmlDataFragment");
QTest::addColumn<MethodMap>("methodMap");
MethodMap map;
QTest::newRow("no-methods") << QString() << map;
// one method without arguments
QDBusIntrospection::Method method;
method.name = "Foo";
map << method;
QTest::newRow("one-method") << "<method name=\"Foo\"/>" << map;
// add another method without arguments
method.name = "Bar";
map << method;
QTest::newRow("two-methods") << "<method name=\"Foo\"/>"
"<method name=\"Bar\"/>"
<< map;
// invert the order of the XML declaration
QTest::newRow("two-methods-inverse") << "<method name=\"Bar\"/>"
"<method name=\"Foo\"/>"
<< map;
// add a third, with annotations
method.name = "Baz";
method.annotations.insert("foo.testing", "nothing to see here");
map << method;
QTest::newRow("method-with-annotation") <<
"<method name=\"Foo\"/>"
"<method name=\"Bar\"/>"
"<method name=\"Baz\"><annotation name=\"foo.testing\" value=\"nothing to see here\" /></method>"
<< map;
// arguments
map.clear();
method.annotations.clear();
method.name = "Method";
method.inputArgs << arg("s");
map << method;
QTest::newRow("one-in") <<
"<method name=\"Method\">"
"<arg type=\"s\" direction=\"in\"/>"
"</method>" << map;
// two arguments
method.inputArgs << arg("v");
map.clear();
map << method;
QTest::newRow("two-in") <<
"<method name=\"Method\">"
"<arg type=\"s\" direction=\"in\"/>"
"<arg type=\"v\" direction=\"in\"/>"
"</method>" << map;
// one invalid arg
method.inputArgs << arg("~", "invalid");
map.clear();
map << method;
QTest::newRow("two-in-one-invalid") <<
"<method name=\"Method\">"
"<arg type=\"s\" direction=\"in\"/>"
"<arg type=\"v\" direction=\"in\"/>"
"<arg type=\"~\" name=\"invalid\" direction=\"in\"/>"
"</method>" << map;
// one out argument
method.inputArgs.clear();
method.outputArgs << arg("s");
map.clear();
map << method;
QTest::newRow("one-out") <<
"<method name=\"Method\">"
"<arg type=\"s\" direction=\"out\"/>"
"</method>" << map;
// two in and one out
method.inputArgs << arg("s") << arg("v");
map.clear();
map << method;
QTest::newRow("two-in-one-out") <<
"<method name=\"Method\">"
"<arg type=\"s\" direction=\"in\"/>"
"<arg type=\"v\" direction=\"in\"/>"
"<arg type=\"s\" direction=\"out\"/>"
"</method>" << map;
// let's try an arg with name
method.outputArgs.clear();
method.inputArgs.clear();
method.inputArgs << arg("s", "foo");
map.clear();
map << method;
QTest::newRow("one-in-with-name") <<
"<method name=\"Method\">"
"<arg type=\"s\" name=\"foo\" direction=\"in\"/>"
"</method>" << map;
// two args with name
method.inputArgs << arg("i", "bar");
map.clear();
map << method;
QTest::newRow("two-in-with-name") <<
"<method name=\"Method\">"
"<arg type=\"s\" name=\"foo\" direction=\"in\"/>"
"<arg type=\"i\" name=\"bar\" direction=\"in\"/>"
"</method>" << map;
// one complex
map.clear();
method = QDBusIntrospection::Method();
// Method1(in STRING arg1, in BYTE arg2, out ARRAY of STRING)
method.inputArgs << arg("s", "arg1") << arg("y", "arg2");
method.outputArgs << arg("as");
method.name = "Method1";
map << method;
// Method2(in ARRAY of DICT_ENTRY of (STRING,VARIANT) variantMap, in UINT32 index,
// out STRING key, out VARIANT value)
// with annotation "foo.equivalent":"QVariantMap"
method = QDBusIntrospection::Method();
method.inputArgs << arg("a{sv}", "variantMap") << arg("u", "index");
method.outputArgs << arg("s", "key") << arg("v", "value");
method.annotations.insert("foo.equivalent", "QVariantMap");
method.name = "Method2";
map << method;
QTest::newRow("complex") <<
"<method name=\"Method1\">"
"<arg name=\"arg1\" type=\"s\" direction=\"in\"/>"
"<arg name=\"arg2\" type=\"y\" direction=\"in\"/>"
"<arg type=\"as\" direction=\"out\"/>"
"</method>"
"<method name=\"Method2\">"
"<arg name=\"variantMap\" type=\"a{sv}\" direction=\"in\"/>"
"<arg name=\"index\" type=\"u\" direction=\"in\"/>"
"<arg name=\"key\" type=\"s\" direction=\"out\"/>"
"<arg name=\"value\" type=\"v\" direction=\"out\"/>"
"<annotation name=\"foo.equivalent\" value=\"QVariantMap\"/>"
"</method>" << map;
}
void tst_QDBusXmlParser::methods()
{
QString intHeader = "<interface name=\"iface.iface1\">",
intFooter = "</interface>",
xmlHeader = "<node>" + intHeader,
xmlFooter = intFooter + "</node>";
QFETCH(QString, xmlDataFragment);
QDBusIntrospection::Interface iface =
QDBusIntrospection::parseInterface(xmlHeader + xmlDataFragment + xmlFooter);
QCOMPARE(iface.name, QString("iface.iface1"));
QCOMPARE(clean_xml(iface.introspection), clean_xml(intHeader + xmlDataFragment + intFooter));
QFETCH(MethodMap, methodMap);
MethodMap parsedMap = iface.methods;
QCOMPARE(parsedMap.size(), methodMap.size());
QCOMPARE(parsedMap, methodMap);
}
void tst_QDBusXmlParser::signals__data()
{
QTest::addColumn<QString>("xmlDataFragment");
QTest::addColumn<SignalMap>("signalMap");
SignalMap map;
QTest::newRow("no-signals") << QString() << map;
// one signal without arguments
QDBusIntrospection::Signal signal;
signal.name = "Foo";
map << signal;
QTest::newRow("one-signal") << "<signal name=\"Foo\"/>" << map;
// add another signal without arguments
signal.name = "Bar";
map << signal;
QTest::newRow("two-signals") << "<signal name=\"Foo\"/>"
"<signal name=\"Bar\"/>"
<< map;
// invert the order of the XML declaration
QTest::newRow("two-signals-inverse") << "<signal name=\"Bar\"/>"
"<signal name=\"Foo\"/>"
<< map;
// add a third, with annotations
signal.name = "Baz";
signal.annotations.insert("foo.testing", "nothing to see here");
map << signal;
QTest::newRow("signal-with-annotation") <<
"<signal name=\"Foo\"/>"
"<signal name=\"Bar\"/>"
"<signal name=\"Baz\"><annotation name=\"foo.testing\" value=\"nothing to see here\" /></signal>"
<< map;
// one out argument
map.clear();
signal.annotations.clear();
signal.outputArgs << arg("s");
signal.name = "Signal";
map.clear();
map << signal;
QTest::newRow("one-out") <<
"<signal name=\"Signal\">"
"<arg type=\"s\" direction=\"out\"/>"
"</signal>" << map;
// without saying which direction it is
QTest::newRow("one-out-no-direction") <<
"<signal name=\"Signal\">"
"<arg type=\"s\"/>"
"</signal>" << map;
// two args with name
signal.outputArgs << arg("i", "bar");
map.clear();
map << signal;
QTest::newRow("two-out-with-name") <<
"<signal name=\"Signal\">"
"<arg type=\"s\" direction=\"out\"/>"
"<arg type=\"i\" name=\"bar\"/>"
"</signal>" << map;
// one complex
map.clear();
signal = QDBusIntrospection::Signal();
// Signal1(out ARRAY of STRING)
signal.outputArgs << arg("as");
signal.name = "Signal1";
map << signal;
// Signal2(out STRING key, out VARIANT value)
// with annotation "foo.equivalent":"QVariantMap"
signal = QDBusIntrospection::Signal();
signal.outputArgs << arg("s", "key") << arg("v", "value");
signal.annotations.insert("foo.equivalent", "QVariantMap");
signal.name = "Signal2";
map << signal;
QTest::newRow("complex") <<
"<signal name=\"Signal1\">"
"<arg type=\"as\" direction=\"out\"/>"
"</signal>"
"<signal name=\"Signal2\">"
"<arg name=\"key\" type=\"s\" direction=\"out\"/>"
"<arg name=\"value\" type=\"v\" direction=\"out\"/>"
"<annotation name=\"foo.equivalent\" value=\"QVariantMap\"/>"
"</signal>" << map;
}
void tst_QDBusXmlParser::signals_()
{
QString intHeader = "<interface name=\"iface.iface1\">",
intFooter = "</interface>",
xmlHeader = "<node>" + intHeader,
xmlFooter = intFooter + "</node>";
QFETCH(QString, xmlDataFragment);
QDBusIntrospection::Interface iface =
QDBusIntrospection::parseInterface(xmlHeader + xmlDataFragment + xmlFooter);
QCOMPARE(iface.name, QString("iface.iface1"));
QCOMPARE(clean_xml(iface.introspection), clean_xml(intHeader + xmlDataFragment + intFooter));
QFETCH(SignalMap, signalMap);
SignalMap parsedMap = iface.signals_;
QCOMPARE(signalMap.size(), parsedMap.size());
QCOMPARE(signalMap, parsedMap);
}
void tst_QDBusXmlParser::properties_data()
{
QTest::addColumn<QString>("xmlDataFragment");
QTest::addColumn<PropertyMap>("propertyMap");
PropertyMap map;
QTest::newRow("no-signals") << QString() << map;
// one readable signal
QDBusIntrospection::Property prop;
prop.name = "foo";
prop.type = "s";
prop.access = QDBusIntrospection::Property::Read;
map << prop;
QTest::newRow("one-readable") << "<property access=\"read\" type=\"s\" name=\"foo\" />" << map;
// one writable signal
prop.access = QDBusIntrospection::Property::Write;
map.clear();
map << prop;
QTest::newRow("one-writable") << "<property access=\"write\" type=\"s\" name=\"foo\"/>" << map;
// one read- & writable signal
prop.access = QDBusIntrospection::Property::ReadWrite;
map.clear();
map << prop;
QTest::newRow("one-read-writable") << "<property access=\"readwrite\" type=\"s\" name=\"foo\"/>"
<< map;
// two, mixed properties
prop.name = "bar";
prop.type = "i";
prop.access = QDBusIntrospection::Property::Read;
map << prop;
QTest::newRow("two-1") <<
"<property access=\"readwrite\" type=\"s\" name=\"foo\"/>"
"<property access=\"read\" type=\"i\" name=\"bar\"/>" << map;
// invert the order of the declaration
QTest::newRow("two-2") <<
"<property access=\"read\" type=\"i\" name=\"bar\"/>"
"<property access=\"readwrite\" type=\"s\" name=\"foo\"/>" << map;
// add a third with annotations
prop.name = "baz";
prop.type = "as";
prop.access = QDBusIntrospection::Property::Write;
prop.annotations.insert("foo.annotation", "Hello, World");
prop.annotations.insert("foo.annotation2", "Goodbye, World");
map << prop;
QTest::newRow("complex") <<
"<property access=\"read\" type=\"i\" name=\"bar\"/>"
"<property access=\"write\" type=\"as\" name=\"baz\">"
"<annotation name=\"foo.annotation\" value=\"Hello, World\" />"
"<annotation name=\"foo.annotation2\" value=\"Goodbye, World\" />"
"</property>"
"<property access=\"readwrite\" type=\"s\" name=\"foo\"/>" << map;
// and now change the order
QTest::newRow("complex2") <<
"<property access=\"write\" type=\"as\" name=\"baz\">"
"<annotation name=\"foo.annotation2\" value=\"Goodbye, World\" />"
"<annotation name=\"foo.annotation\" value=\"Hello, World\" />"
"</property>"
"<property access=\"read\" type=\"i\" name=\"bar\"/>"
"<property access=\"readwrite\" type=\"s\" name=\"foo\"/>" << map;
}
void tst_QDBusXmlParser::properties()
{
QString intHeader = "<interface name=\"iface.iface1\">",
intFooter = "</interface>",
xmlHeader = "<node>" + intHeader,
xmlFooter = intFooter + "</node>";
QFETCH(QString, xmlDataFragment);
QDBusIntrospection::Interface iface =
QDBusIntrospection::parseInterface(xmlHeader + xmlDataFragment + xmlFooter);
QCOMPARE(iface.name, QString("iface.iface1"));
QCOMPARE(clean_xml(iface.introspection), clean_xml(intHeader + xmlDataFragment + intFooter));
QFETCH(PropertyMap, propertyMap);
PropertyMap parsedMap = iface.properties;
QCOMPARE(propertyMap.size(), parsedMap.size());
QCOMPARE(propertyMap, parsedMap);
}
QTEST_MAIN(tst_QDBusXmlParser)
#include "tst_qdbusxmlparser.moc"