mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-02 23:35:28 +08:00
qt 6.5.1 original
This commit is contained in:
30
tests/auto/dbus/CMakeLists.txt
Normal file
30
tests/auto/dbus/CMakeLists.txt
Normal 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()
|
14
tests/auto/dbus/qdbusabstractadaptor/CMakeLists.txt
Normal file
14
tests/auto/dbus/qdbusabstractadaptor/CMakeLists.txt
Normal 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)
|
254
tests/auto/dbus/qdbusabstractadaptor/myobject.h
Normal file
254
tests/auto/dbus/qdbusabstractadaptor/myobject.h
Normal 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
|
@ -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
|
||||
)
|
166
tests/auto/dbus/qdbusabstractadaptor/qmyserver/qmyserver.cpp
Normal file
166
tests/auto/dbus/qdbusabstractadaptor/qmyserver/qmyserver.cpp
Normal 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"
|
1896
tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp
Normal file
1896
tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp
Normal file
File diff suppressed because it is too large
Load Diff
23
tests/auto/dbus/qdbusabstractinterface/CMakeLists.txt
Normal file
23
tests/auto/dbus/qdbusabstractinterface/CMakeLists.txt
Normal 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
|
||||
)
|
||||
|
24
tests/auto/dbus/qdbusabstractinterface/interface.cpp
Normal file
24
tests/auto/dbus/qdbusabstractinterface/interface.cpp
Normal 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"
|
78
tests/auto/dbus/qdbusabstractinterface/interface.h
Normal file
78
tests/auto/dbus/qdbusabstractinterface/interface.h
Normal 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
|
@ -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<QString,QVariant>"/>
|
||||
<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>
|
@ -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
|
@ -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
|
||||
)
|
122
tests/auto/dbus/qdbusabstractinterface/qpinger/qpinger.cpp
Normal file
122
tests/auto/dbus/qdbusabstractinterface/qpinger/qpinger.cpp
Normal 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
13
tests/auto/dbus/qdbusconnection/CMakeLists.txt
Normal file
13
tests/auto/dbus/qdbusconnection/CMakeLists.txt
Normal 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
|
||||
)
|
1421
tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp
Normal file
1421
tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp
Normal file
File diff suppressed because it is too large
Load Diff
280
tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h
Normal file
280
tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h
Normal 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
|
||||
|
13
tests/auto/dbus/qdbusconnection_delayed/CMakeLists.txt
Normal file
13
tests/auto/dbus/qdbusconnection_delayed/CMakeLists.txt
Normal 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
|
||||
)
|
@ -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"
|
16
tests/auto/dbus/qdbusconnection_no_app/CMakeLists.txt
Normal file
16
tests/auto/dbus/qdbusconnection_no_app/CMakeLists.txt
Normal 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
|
||||
)
|
@ -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)
|
13
tests/auto/dbus/qdbusconnection_no_bus/CMakeLists.txt
Normal file
13
tests/auto/dbus/qdbusconnection_no_bus/CMakeLists.txt
Normal 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
|
||||
)
|
@ -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"
|
||||
|
16
tests/auto/dbus/qdbusconnection_no_libdbus/CMakeLists.txt
Normal file
16
tests/auto/dbus/qdbusconnection_no_libdbus/CMakeLists.txt
Normal 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
|
||||
)
|
@ -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"
|
||||
|
0
tests/auto/dbus/qdbusconnection_spyhook/BLACKLIST
Normal file
0
tests/auto/dbus/qdbusconnection_spyhook/BLACKLIST
Normal file
16
tests/auto/dbus/qdbusconnection_spyhook/CMakeLists.txt
Normal file
16
tests/auto/dbus/qdbusconnection_spyhook/CMakeLists.txt
Normal 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
|
||||
)
|
@ -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)
|
13
tests/auto/dbus/qdbuscontext/CMakeLists.txt
Normal file
13
tests/auto/dbus/qdbuscontext/CMakeLists.txt
Normal 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
|
||||
)
|
59
tests/auto/dbus/qdbuscontext/tst_qdbuscontext.cpp
Normal file
59
tests/auto/dbus/qdbuscontext/tst_qdbuscontext.cpp
Normal 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"
|
38
tests/auto/dbus/qdbusinterface/CMakeLists.txt
Normal file
38
tests/auto/dbus/qdbusinterface/CMakeLists.txt
Normal 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)
|
||||
|
120
tests/auto/dbus/qdbusinterface/myobject.h
Normal file
120
tests/auto/dbus/qdbusinterface/myobject.h
Normal 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<int>\"/>\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<int>\"/>\n"
|
||||
" <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QList<int>\"/>\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<int>\"/>\n"
|
||||
" <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QList<int>\"/>\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
|
16
tests/auto/dbus/qdbusinterface/qmyserver/CMakeLists.txt
Normal file
16
tests/auto/dbus/qdbusinterface/qmyserver/CMakeLists.txt
Normal 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
|
||||
)
|
148
tests/auto/dbus/qdbusinterface/qmyserver/qmyserver.cpp
Normal file
148
tests/auto/dbus/qdbusinterface/qmyserver/qmyserver.cpp
Normal 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"
|
1152
tests/auto/dbus/qdbusinterface/tst_qdbusinterface.cpp
Normal file
1152
tests/auto/dbus/qdbusinterface/tst_qdbusinterface.cpp
Normal file
File diff suppressed because it is too large
Load Diff
13
tests/auto/dbus/qdbuslocalcalls/CMakeLists.txt
Normal file
13
tests/auto/dbus/qdbuslocalcalls/CMakeLists.txt
Normal 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
|
||||
)
|
238
tests/auto/dbus/qdbuslocalcalls/tst_qdbuslocalcalls.cpp
Normal file
238
tests/auto/dbus/qdbuslocalcalls/tst_qdbuslocalcalls.cpp
Normal 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"
|
8
tests/auto/dbus/qdbusmarshall/CMakeLists.txt
Normal file
8
tests/auto/dbus/qdbusmarshall/CMakeLists.txt
Normal 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)
|
649
tests/auto/dbus/qdbusmarshall/common.h
Normal file
649
tests/auto/dbus/qdbusmarshall/common.h
Normal 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
|
||||
}
|
||||
}
|
32
tests/auto/dbus/qdbusmarshall/qdbusmarshall/CMakeLists.txt
Normal file
32
tests/auto/dbus/qdbusmarshall/qdbusmarshall/CMakeLists.txt
Normal 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
|
||||
)
|
14
tests/auto/dbus/qdbusmarshall/qpong/CMakeLists.txt
Normal file
14
tests/auto/dbus/qdbusmarshall/qpong/CMakeLists.txt
Normal 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
|
||||
)
|
51
tests/auto/dbus/qdbusmarshall/qpong/qpong.cpp
Normal file
51
tests/auto/dbus/qdbusmarshall/qpong/qpong.cpp
Normal 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"
|
1509
tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp
Normal file
1509
tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp
Normal file
File diff suppressed because it is too large
Load Diff
13
tests/auto/dbus/qdbusmetaobject/CMakeLists.txt
Normal file
13
tests/auto/dbus/qdbusmetaobject/CMakeLists.txt
Normal 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
|
||||
)
|
877
tests/auto/dbus/qdbusmetaobject/tst_qdbusmetaobject.cpp
Normal file
877
tests/auto/dbus/qdbusmetaobject/tst_qdbusmetaobject.cpp
Normal 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"
|
13
tests/auto/dbus/qdbusmetatype/CMakeLists.txt
Normal file
13
tests/auto/dbus/qdbusmetatype/CMakeLists.txt
Normal 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
|
||||
)
|
399
tests/auto/dbus/qdbusmetatype/tst_qdbusmetatype.cpp
Normal file
399
tests/auto/dbus/qdbusmetatype/tst_qdbusmetatype.cpp
Normal 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"
|
13
tests/auto/dbus/qdbuspendingcall/CMakeLists.txt
Normal file
13
tests/auto/dbus/qdbuspendingcall/CMakeLists.txt
Normal 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
|
||||
)
|
455
tests/auto/dbus/qdbuspendingcall/tst_qdbuspendingcall.cpp
Normal file
455
tests/auto/dbus/qdbuspendingcall/tst_qdbuspendingcall.cpp
Normal 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"
|
13
tests/auto/dbus/qdbuspendingreply/CMakeLists.txt
Normal file
13
tests/auto/dbus/qdbuspendingreply/CMakeLists.txt
Normal 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
|
||||
)
|
566
tests/auto/dbus/qdbuspendingreply/tst_qdbuspendingreply.cpp
Normal file
566
tests/auto/dbus/qdbuspendingreply/tst_qdbuspendingreply.cpp
Normal 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"
|
13
tests/auto/dbus/qdbusreply/CMakeLists.txt
Normal file
13
tests/auto/dbus/qdbusreply/CMakeLists.txt
Normal 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
|
||||
)
|
367
tests/auto/dbus/qdbusreply/tst_qdbusreply.cpp
Normal file
367
tests/auto/dbus/qdbusreply/tst_qdbusreply.cpp
Normal 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"
|
14
tests/auto/dbus/qdbusservicewatcher/CMakeLists.txt
Normal file
14
tests/auto/dbus/qdbusservicewatcher/CMakeLists.txt
Normal 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
|
||||
)
|
478
tests/auto/dbus/qdbusservicewatcher/tst_qdbusservicewatcher.cpp
Normal file
478
tests/auto/dbus/qdbusservicewatcher/tst_qdbusservicewatcher.cpp
Normal 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"
|
13
tests/auto/dbus/qdbusthreading/CMakeLists.txt
Normal file
13
tests/auto/dbus/qdbusthreading/CMakeLists.txt
Normal 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
|
||||
)
|
574
tests/auto/dbus/qdbusthreading/tst_qdbusthreading.cpp
Normal file
574
tests/auto/dbus/qdbusthreading/tst_qdbusthreading.cpp
Normal 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"
|
29
tests/auto/dbus/qdbustype/CMakeLists.txt
Normal file
29
tests/auto/dbus/qdbustype/CMakeLists.txt
Normal 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
|
||||
)
|
260
tests/auto/dbus/qdbustype/tst_qdbustype.cpp
Normal file
260
tests/auto/dbus/qdbustype/tst_qdbustype.cpp
Normal 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"
|
15
tests/auto/dbus/qdbusxmlparser/CMakeLists.txt
Normal file
15
tests/auto/dbus/qdbusxmlparser/CMakeLists.txt
Normal 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
|
||||
)
|
540
tests/auto/dbus/qdbusxmlparser/tst_qdbusxmlparser.cpp
Normal file
540
tests/auto/dbus/qdbusxmlparser/tst_qdbusxmlparser.cpp
Normal 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"
|
Reference in New Issue
Block a user