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