1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2016 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the test suite of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:GPL-EXCEPT$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU
20** General Public License version 3 as published by the Free Software
21** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29#include <qcoreapplication.h>
30#include <qdebug.h>
31
32#include <QtTest/QtTest>
33
34#include <QtDBus>
35
36#include "../qdbusmarshall/common.h"
37#include "myobject.h"
38
39static const char serviceName[] = "org.qtproject.autotests.qmyserver";
40static const char objectPath[] = "/org/qtproject/qmyserver";
41static const char *interfaceName = serviceName;
42
43const char *slotSpy;
44QString valueSpy;
45
46QT_BEGIN_NAMESPACE
47namespace QTest {
48 char *toString(QDBusMessage::MessageType t)
49 {
50 switch (t)
51 {
52 case QDBusMessage::InvalidMessage:
53 return qstrdup("InvalidMessage");
54 case QDBusMessage::MethodCallMessage:
55 return qstrdup("MethodCallMessage");
56 case QDBusMessage::ReplyMessage:
57 return qstrdup("ReplyMessage");
58 case QDBusMessage::ErrorMessage:
59 return qstrdup("ErrorMessage");
60 case QDBusMessage::SignalMessage:
61 return qstrdup("SignalMessage");
62 default:
63 return 0;
64 }
65 }
66}
67QT_END_NAMESPACE
68
69class TypesInterface: public QDBusAbstractAdaptor
70{
71 Q_OBJECT
72 Q_CLASSINFO("D-Bus Interface", "local.TypesInterface")
73public:
74 TypesInterface(QObject *parent)
75 : QDBusAbstractAdaptor(parent)
76 { }
77
78 union
79 {
80 bool b;
81 uchar uc;
82 short s;
83 ushort us;
84 int i;
85 uint ui;
86 qlonglong ll;
87 qulonglong ull;
88 double d;
89 } dataSpy;
90 QVariant variantSpy;
91 QString stringSpy;
92 QVariantList listSpy;
93 QStringList stringlistSpy;
94 QByteArray bytearraySpy;
95 QVariantMap mapSpy;
96 StringStringMap ssmapSpy;
97 LLDateTimeMap lldtmapSpy;
98 MyStruct structSpy;
99
100public slots:
101 void methodBool(bool b)
102 {
103 slotSpy = "void TypesInterface::methodBool(bool)";
104 dataSpy.b = b;
105 }
106
107 void methodUChar(uchar uc)
108 {
109 slotSpy = "void TypesInterface::methodUChar(uchar)";
110 dataSpy.uc = uc;
111 }
112
113 void methodShort(short s)
114 {
115 slotSpy = "void TypesInterface::methodShort(short)";
116 dataSpy.s = s;
117 }
118
119 void methodUShort(ushort us)
120 {
121 slotSpy = "void TypesInterface::methodUShort(ushort)";
122 dataSpy.us = us;
123 }
124
125 void methodInt(int i)
126 {
127 slotSpy = "void TypesInterface::methodInt(int)";
128 dataSpy.i = i;
129 }
130
131 void methodUInt(uint ui)
132 {
133 slotSpy = "void TypesInterface::methodUInt(uint)";
134 dataSpy.ui = ui;
135 }
136
137 void methodLongLong(qlonglong ll)
138 {
139 slotSpy = "void TypesInterface::methodLongLong(qlonglong)";
140 dataSpy.ll = ll;
141 }
142
143 void methodULongLong(qulonglong ull)
144 {
145 slotSpy = "void TypesInterface::methodULongLong(qulonglong)";
146 dataSpy.ull = ull;
147 }
148
149 void methodDouble(double d)
150 {
151 slotSpy = "void TypesInterface::methodDouble(double)";
152 dataSpy.d = d;
153 }
154
155 void methodString(const QString &s)
156 {
157 slotSpy = "void TypesInterface::methodString(const QString &)";
158 stringSpy = s;
159 }
160
161 void methodObjectPath(const QDBusObjectPath &op)
162 {
163 slotSpy = "void TypesInterface::methodObjectPath(const QDBusObjectPath &)";
164 stringSpy = op.path();
165 }
166
167 void methodSignature(const QDBusSignature &s)
168 {
169 slotSpy = "void TypesInterface::methodSignature(const QDBusSignature &)";
170 stringSpy = s.signature();
171 }
172
173 void methodVariant(const QDBusVariant &v)
174 {
175 slotSpy = "void TypesInterface::methodVariant(const QDBusVariant &)";
176 variantSpy = v.variant();
177 }
178
179 void methodList(const QVariantList &l)
180 {
181 slotSpy = "void TypesInterface::methodList(const QVariantList &)";
182 listSpy = l;
183 }
184
185 void methodStringList(const QStringList &sl)
186 {
187 slotSpy = "void TypesInterface::methodStringList(const QStringList &)";
188 stringlistSpy = sl;
189 }
190
191 void methodByteArray(const QByteArray &ba)
192 {
193 slotSpy = "void TypesInterface::methodByteArray(const QByteArray &)";
194 bytearraySpy = ba;
195 }
196
197 void methodMap(const QVariantMap &m)
198 {
199 slotSpy = "void TypesInterface::methodMap(const QVariantMap &)";
200 mapSpy = m;
201 }
202
203 void methodSSMap(const StringStringMap &ssmap)
204 {
205 slotSpy = "void TypesInterface::methodSSMap(const StringStringMap &)";
206 ssmapSpy = ssmap;
207 }
208
209 void methodLLDateTimeMap(const LLDateTimeMap &lldtmap)
210 {
211 slotSpy = "void TypesInterface::methodLLDateTimeMap(const LLDateTimeMap &)";
212 lldtmapSpy = lldtmap;
213 }
214
215 void methodStruct(const MyStruct &s)
216 {
217 slotSpy = "void TypesInterface::methodStruct(const MyStruct &)";
218 structSpy = s;
219 }
220
221 bool retrieveBool()
222 {
223 return dataSpy.b;
224 }
225
226 uchar retrieveUChar()
227 {
228 return dataSpy.uc;
229 }
230
231 short retrieveShort()
232 {
233 return dataSpy.s;
234 }
235
236 ushort retrieveUShort()
237 {
238 return dataSpy.us;
239 }
240
241 int retrieveInt()
242 {
243 return dataSpy.i;
244 }
245
246 uint retrieveUInt()
247 {
248 return dataSpy.ui;
249 }
250
251 qlonglong retrieveLongLong()
252 {
253 return dataSpy.ll;
254 }
255
256 qulonglong retrieveULongLong()
257 {
258 return dataSpy.ull;
259 }
260
261 double retrieveDouble()
262 {
263 return dataSpy.d;
264 }
265
266 QString retrieveString()
267 {
268 return stringSpy;
269 }
270
271 QDBusObjectPath retrieveObjectPath()
272 {
273 return QDBusObjectPath(stringSpy);
274 }
275
276 QDBusSignature retrieveSignature()
277 {
278 return QDBusSignature(stringSpy);
279 }
280
281 QDBusVariant retrieveVariant()
282 {
283 return QDBusVariant(variantSpy);
284 }
285
286 QVariantList retrieveList()
287 {
288 return listSpy;
289 }
290
291 QStringList retrieveStringList()
292 {
293 return stringlistSpy;
294 }
295
296 QByteArray retrieveByteArray()
297 {
298 return bytearraySpy;
299 }
300
301 QVariantMap retrieveMap()
302 {
303 return mapSpy;
304 }
305
306 StringStringMap retrieveSSMap()
307 {
308 return ssmapSpy;
309 }
310
311 LLDateTimeMap retrieveLLDateTimeMap()
312 {
313 return lldtmapSpy;
314 }
315
316 MyStruct retrieveStruct()
317 {
318 return structSpy;
319 }
320};
321
322void newMyObjectPeer(int nInterfaces = 4)
323{
324 QDBusMessage req = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath, interface: interfaceName, method: "newMyObject");
325 req << nInterfaces;
326 QDBusMessage reply = QDBusConnection::sessionBus().call(message: req);
327}
328
329void registerMyObjectPeer(const QString & path, QDBusConnection::RegisterOptions options = QDBusConnection::ExportAdaptors)
330{
331 QDBusMessage req = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath, interface: interfaceName, method: "registerMyObject");
332 req << path;
333 req << (int)options;
334 QDBusMessage reply = QDBusConnection::sessionBus().call(message: req);
335}
336
337void syncPeer()
338{
339 static int counter = 0;
340 QString reqId = QString::number(++counter);
341
342 // wait for the sync signal with the right ID
343 QEventLoop loop;
344 QDBusConnection con("peer");
345 con.connect(service: QString(), path: objectPath, interface: interfaceName, name: "syncReceived",
346 argumentMatch: QStringList() << reqId, signature: QString(), receiver: &loop, SLOT(quit()));
347
348 QDBusMessage req = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath, interface: interfaceName, method: "requestSync");
349 req << reqId;
350 QDBusConnection::sessionBus().send(message: req);
351
352 loop.exec();
353}
354
355void emitSignalPeer(const QString &interface, const QString &name, const QVariant &parameter)
356{
357 if (parameter.isValid())
358 {
359 QDBusMessage req = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath, interface: interfaceName, method: "emitSignal");
360 req << interface;
361 req << name;
362 req << QVariant::fromValue(value: QDBusVariant(parameter));
363 QDBusConnection::sessionBus().send(message: req);
364 }
365 else
366 {
367 QDBusMessage req = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath, interface: interfaceName, method: "emitSignal2");
368 req << interface;
369 req << name;
370 QDBusConnection::sessionBus().send(message: req);
371 }
372}
373
374QString slotSpyPeer()
375{
376 QDBusMessage req = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath, interface: interfaceName, method: "slotSpyServer");
377 QDBusMessage reply = QDBusConnection::sessionBus().call(message: req);
378 return reply.arguments().at(i: 0).toString();
379}
380
381QString valueSpyPeer()
382{
383 QDBusMessage req = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath, interface: interfaceName, method: "valueSpyServer");
384 QDBusMessage reply = QDBusConnection::sessionBus().call(message: req);
385 return reply.arguments().at(i: 0).toString();
386}
387
388void clearValueSpyPeer()
389{
390 QDBusMessage req = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath, interface: interfaceName, method: "clearValueSpy");
391 QDBusMessage reply = QDBusConnection::sessionBus().call(message: req);
392}
393
394class tst_QDBusAbstractAdaptor: public QObject
395{
396 Q_OBJECT
397
398private slots:
399 void initTestCase();
400 void cleanupTestCase();
401
402 void methodCalls_data();
403 void methodCalls();
404 void methodCallScriptable();
405 void signalEmissions_data();
406 void signalEmissions();
407 void sameSignalDifferentPaths();
408 void sameObjectDifferentPaths();
409 void scriptableSignalOrNot();
410 void overloadedSignalEmission_data();
411 void overloadedSignalEmission();
412 void readProperties();
413 void readPropertiesInvalidInterface();
414 void readPropertiesEmptyInterface_data();
415 void readPropertiesEmptyInterface();
416 void readAllProperties();
417 void readAllPropertiesInvalidInterface();
418 void readAllPropertiesEmptyInterface_data();
419 void readAllPropertiesEmptyInterface();
420 void writeProperties();
421
422 void methodCallsPeer_data();
423 void methodCallsPeer();
424 void methodCallScriptablePeer();
425 void signalEmissionsPeer_data();
426 void signalEmissionsPeer();
427 void sameSignalDifferentPathsPeer();
428 void sameObjectDifferentPathsPeer();
429 void scriptableSignalOrNotPeer();
430 void overloadedSignalEmissionPeer_data();
431 void overloadedSignalEmissionPeer();
432 void readPropertiesPeer();
433 void readPropertiesInvalidInterfacePeer();
434 void readPropertiesEmptyInterfacePeer_data();
435 void readPropertiesEmptyInterfacePeer();
436 void readAllPropertiesPeer();
437 void readAllPropertiesInvalidInterfacePeer();
438 void readAllPropertiesEmptyInterfacePeer_data();
439 void readAllPropertiesEmptyInterfacePeer();
440 void writePropertiesPeer();
441
442 void typeMatching_data();
443 void typeMatching();
444
445 void methodWithMoreThanOneReturnValue();
446 void methodWithMoreThanOneReturnValuePeer();
447private:
448 QProcess proc;
449};
450
451class WaitForQMyServer: public QObject
452{
453 Q_OBJECT
454public:
455 WaitForQMyServer();
456 bool ok();
457public Q_SLOTS:
458 void ownerChange(const QString &name)
459 {
460 if (name == serviceName)
461 loop.quit();
462 }
463
464private:
465 QEventLoop loop;
466};
467
468WaitForQMyServer::WaitForQMyServer()
469{
470 QDBusConnection con = QDBusConnection::sessionBus();
471 if (!ok()) {
472 connect(asender: con.interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)),
473 SLOT(ownerChange(QString)));
474 QTimer::singleShot(msec: 2000, receiver: &loop, SLOT(quit()));
475 loop.exec();
476 }
477}
478
479bool WaitForQMyServer::ok()
480{
481 return QDBusConnection::sessionBus().isConnected() &&
482 QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName);
483}
484
485void tst_QDBusAbstractAdaptor::initTestCase()
486{
487 commonInit();
488
489 // start peer server
490#ifdef Q_OS_WIN
491# define EXE ".exe"
492#else
493# define EXE ""
494#endif
495 proc.setProcessChannelMode(QProcess::ForwardedErrorChannel);
496 proc.start(QFINDTESTDATA("qmyserver/qmyserver" EXE));
497 QVERIFY2(proc.waitForStarted(), qPrintable(proc.errorString()));
498 QVERIFY(proc.waitForReadyRead());
499
500 WaitForQMyServer w;
501 QVERIFY(w.ok());
502
503 // get peer server address
504 QDBusMessage req = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath, interface: interfaceName, method: "address");
505 QDBusMessage rpl = QDBusConnection::sessionBus().call(message: req);
506 QCOMPARE(rpl.type(), QDBusMessage::ReplyMessage);
507 QString address = rpl.arguments().at(i: 0).toString();
508
509 // connect to peer server
510 QDBusConnection peercon = QDBusConnection::connectToPeer(address, name: "peer");
511 QVERIFY(peercon.isConnected());
512
513 QDBusMessage req2 = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath, interface: interfaceName, method: "waitForConnected");
514 QDBusMessage rpl2 = QDBusConnection::sessionBus().call(message: req2);
515 QVERIFY2(rpl2.type() == QDBusMessage::ReplyMessage, rpl2.errorMessage().toLatin1());
516}
517
518void tst_QDBusAbstractAdaptor::cleanupTestCase()
519{
520 QDBusMessage msg = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath, interface: interfaceName, method: "quit");
521 QDBusConnection::sessionBus().call(message: msg);
522 proc.waitForFinished(msecs: 200);
523 proc.close();
524}
525
526void tst_QDBusAbstractAdaptor::methodCalls_data()
527{
528 QTest::addColumn<int>(name: "nInterfaces");
529 QTest::newRow(dataTag: "0") << 0;
530 QTest::newRow(dataTag: "1") << 1;
531 QTest::newRow(dataTag: "2") << 2;
532 QTest::newRow(dataTag: "3") << 3;
533 QTest::newRow(dataTag: "4") << 4;
534}
535
536void tst_QDBusAbstractAdaptor::methodCalls()
537{
538 QDBusConnection con = QDBusConnection::sessionBus();
539 QVERIFY(con.isConnected());
540
541 //QDBusInterface emptycon.baseService(), "/", QString());
542
543 {
544 // must fail: no object
545 QDBusInterface if1(con.baseService(), "/", "local.Interface1", con);
546 QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage);
547 }
548
549 QFETCH(int, nInterfaces);
550 MyObject obj(nInterfaces);
551 con.registerObject(path: "/", object: &obj);
552
553 QDBusInterface if1(con.baseService(), "/", "local.Interface1", con);
554 QDBusInterface if2(con.baseService(), "/", "local.Interface2", con);
555 QDBusInterface if3(con.baseService(), "/", "local.Interface3", con);
556 QDBusInterface if4(con.baseService(), "/", "local.Interface4", con);
557
558 // must fail: no such method
559 QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage);
560 if (!nInterfaces--)
561 return;
562 if (!nInterfaces--)
563 return;
564
565 // simple call: one such method exists
566 QCOMPARE(if2.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ReplyMessage);
567 QCOMPARE(slotSpy, "void Interface2::method()");
568 if (!nInterfaces--)
569 return;
570
571 // multiple methods in multiple interfaces, no name overlap
572 QCOMPARE(if1.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ErrorMessage);
573 QCOMPARE(if1.call(QDBus::BlockWithGui, "methodInt").type(), QDBusMessage::ErrorMessage);
574 QCOMPARE(if1.call(QDBus::BlockWithGui, "methodString").type(), QDBusMessage::ErrorMessage);
575 QCOMPARE(if2.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ErrorMessage);
576 QCOMPARE(if2.call(QDBus::BlockWithGui, "methodInt").type(), QDBusMessage::ErrorMessage);
577 QCOMPARE(if2.call(QDBus::BlockWithGui, "methodString").type(), QDBusMessage::ErrorMessage);
578
579 QCOMPARE(if3.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ReplyMessage);
580 QCOMPARE(slotSpy, "void Interface3::methodVoid()");
581 QCOMPARE(if3.call(QDBus::BlockWithGui, "methodInt", 42).type(), QDBusMessage::ReplyMessage);
582 QCOMPARE(slotSpy, "void Interface3::methodInt(int)");
583 QCOMPARE(if3.call(QDBus::BlockWithGui, "methodString", QString("")).type(), QDBusMessage::ReplyMessage);
584 QCOMPARE(slotSpy, "void Interface3::methodString(QString)");
585
586 if (!nInterfaces--)
587 return;
588
589 // method overloading: different interfaces
590 QCOMPARE(if4.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ReplyMessage);
591 QCOMPARE(slotSpy, "void Interface4::method()");
592
593 // method overloading: different parameters
594 QCOMPARE(if4.call(QDBus::BlockWithGui, "method.i", 42).type(), QDBusMessage::ReplyMessage);
595 QCOMPARE(slotSpy, "void Interface4::method(int)");
596 QCOMPARE(if4.call(QDBus::BlockWithGui, "method.s", QString()).type(), QDBusMessage::ReplyMessage);
597 QCOMPARE(slotSpy, "void Interface4::method(QString)");
598
599}
600
601void tst_QDBusAbstractAdaptor::methodCallScriptable()
602{
603 QDBusConnection con = QDBusConnection::sessionBus();
604 QVERIFY(con.isConnected());
605
606 MyObject obj(2);
607 con.registerObject(path: "/", object: &obj);
608
609 QDBusInterface if2(con.baseService(), "/", "local.Interface2", con);
610
611 QCOMPARE(if2.call(QDBus::BlockWithGui,"scriptableMethod").type(), QDBusMessage::ReplyMessage);
612 QCOMPARE(slotSpy, "void Interface2::scriptableMethod()");
613}
614
615static void emitSignal(MyObject *obj, const QString &iface, const QString &name,
616 const QVariant &parameter)
617{
618 if (iface.endsWith(c: '2'))
619 obj->if2->emitSignal(name, parameter);
620 else if (iface.endsWith(c: '3'))
621 obj->if3->emitSignal(name, value: parameter);
622 else if (iface.endsWith(c: '4'))
623 obj->if4->emitSignal(name, value: parameter);
624 else
625 obj->emitSignal(name, value: parameter);
626}
627
628void tst_QDBusAbstractAdaptor::signalEmissions_data()
629{
630 QTest::addColumn<QString>(name: "interface");
631 QTest::addColumn<QString>(name: "name");
632 QTest::addColumn<QString>(name: "signature");
633 QTest::addColumn<QVariant>(name: "parameter");
634
635 QTest::newRow(dataTag: "Interface2.signal") << "local.Interface2" << "signal" << QString() << QVariant();
636 QTest::newRow(dataTag: "Interface3.signalVoid") << "local.Interface3" << "signalVoid" << QString() << QVariant();
637 QTest::newRow(dataTag: "Interface3.signalInt") << "local.Interface3" << "signalInt" << "i" << QVariant(1);
638 QTest::newRow(dataTag: "Interface3.signalString") << "local.Interface3" << "signalString" << "s" << QVariant("foo");
639 QTest::newRow(dataTag: "MyObject.scriptableSignalVoid") << "local.MyObject" << "scriptableSignalVoid" << QString() << QVariant();
640 QTest::newRow(dataTag: "MyObject.scriptableSignalInt") << "local.MyObject" << "scriptableSignalInt" << "i" << QVariant(1);
641 QTest::newRow(dataTag: "MyObject.nySignalString") << "local.MyObject" << "scriptableSignalString" << "s" << QVariant("foo");
642}
643
644void tst_QDBusAbstractAdaptor::signalEmissions()
645{
646 QFETCH(QString, interface);
647 QFETCH(QString, name);
648 QFETCH(QVariant, parameter);
649
650 QDBusConnection con = QDBusConnection::sessionBus();
651 QVERIFY(con.isConnected());
652 con.registerService(serviceName: "org.qtproject.tst_QDBusAbstractAdaptor");
653
654 MyObject obj(3);
655 con.registerObject(path: "/", object: &obj, options: QDBusConnection::ExportAdaptors
656 | QDBusConnection::ExportScriptableSignals);
657
658 // connect all signals and emit only one
659 {
660 QDBusSignalSpy spy;
661 con.connect(service: con.baseService(), path: "/", interface: "local.Interface2", name: "signal",
662 receiver: &spy, SLOT(slot(QDBusMessage)));
663 con.connect(service: con.baseService(), path: "/", interface: "local.Interface3", name: "signalVoid",
664 receiver: &spy, SLOT(slot(QDBusMessage)));
665 con.connect(service: con.baseService(), path: "/", interface: "local.Interface3", name: "signalInt",
666 receiver: &spy, SLOT(slot(QDBusMessage)));
667 con.connect(service: con.baseService(), path: "/", interface: "local.Interface3", name: "signalString",
668 receiver: &spy, SLOT(slot(QDBusMessage)));
669 con.connect(service: con.baseService(), path: "/", interface: "local.MyObject", name: "scriptableSignalVoid",
670 receiver: &spy, SLOT(slot(QDBusMessage)));
671 con.connect(service: con.baseService(), path: "/", interface: "local.MyObject", name: "scriptableSignalInt",
672 receiver: &spy, SLOT(slot(QDBusMessage)));
673 con.connect(service: con.baseService(), path: "/", interface: "local.MyObject", name: "scriptableSignalString",
674 receiver: &spy, SLOT(slot(QDBusMessage)));
675
676 emitSignal(obj: &obj, iface: interface, name, parameter);
677
678 QTRY_COMPARE(spy.count, 1);
679 QCOMPARE(spy.interface, interface);
680 QCOMPARE(spy.name, name);
681 QTEST(spy.signature, "signature");
682 QCOMPARE(spy.value, parameter);
683 }
684
685 // connect one signal and emit them all
686 {
687 QDBusSignalSpy spy;
688 con.connect(service: con.baseService(), path: "/", interface, name, receiver: &spy, SLOT(slot(QDBusMessage)));
689 emitSignal(obj: &obj, iface: "local.Interface2", name: "signal", parameter: QVariant());
690 emitSignal(obj: &obj, iface: "local.Interface3", name: "signalVoid", parameter: QVariant());
691 emitSignal(obj: &obj, iface: "local.Interface3", name: "signalInt", parameter: QVariant(1));
692 emitSignal(obj: &obj, iface: "local.Interface3", name: "signalString", parameter: QVariant("foo"));
693 emitSignal(obj: &obj, iface: "local.MyObject", name: "scriptableSignalVoid", parameter: QVariant());
694 emitSignal(obj: &obj, iface: "local.MyObject", name: "scriptableSignalInt", parameter: QVariant(1));
695 emitSignal(obj: &obj, iface: "local.MyObject", name: "scriptableSignalString", parameter: QVariant("foo"));
696
697 QTRY_COMPARE(spy.count, 1);
698 QCOMPARE(spy.interface, interface);
699 QCOMPARE(spy.name, name);
700 QTEST(spy.signature, "signature");
701 QCOMPARE(spy.value, parameter);
702 }
703}
704
705void tst_QDBusAbstractAdaptor::sameSignalDifferentPaths()
706{
707 QDBusConnection con = QDBusConnection::sessionBus();
708 QVERIFY(con.isConnected());
709
710 MyObject obj(2);
711
712 con.registerObject(path: "/p1",object: &obj);
713 con.registerObject(path: "/p2",object: &obj);
714
715 QDBusSignalSpy spy;
716 con.connect(service: con.baseService(), path: "/p1", interface: "local.Interface2", name: "signal", receiver: &spy, SLOT(slot(QDBusMessage)));
717 obj.if2->emitSignal(QString(), QVariant());
718
719 QTRY_COMPARE(spy.count, 1);
720 QCOMPARE(spy.interface, QString("local.Interface2"));
721 QCOMPARE(spy.name, QString("signal"));
722 QVERIFY(spy.signature.isEmpty());
723
724 // now connect the other one
725 spy.count = 0;
726 con.connect(service: con.baseService(), path: "/p2", interface: "local.Interface2", name: "signal", receiver: &spy, SLOT(slot(QDBusMessage)));
727 obj.if2->emitSignal(QString(), QVariant());
728
729 QTRY_COMPARE(spy.count, 2);
730}
731
732void tst_QDBusAbstractAdaptor::sameObjectDifferentPaths()
733{
734 QDBusConnection con = QDBusConnection::sessionBus();
735 QVERIFY(con.isConnected());
736
737 MyObject obj(2);
738
739 con.registerObject(path: "/p1",object: &obj);
740 con.registerObject(path: "/p2",object: &obj, options: { }); // don't export anything
741
742 QDBusSignalSpy spy;
743 con.connect(service: con.baseService(), path: "/p1", interface: "local.Interface2", name: "signal", receiver: &spy, SLOT(slot(QDBusMessage)));
744 con.connect(service: con.baseService(), path: "/p2", interface: "local.Interface2", name: "signal", receiver: &spy, SLOT(slot(QDBusMessage)));
745 obj.if2->emitSignal(QString(), QVariant());
746
747 QTRY_COMPARE(spy.count, 1);
748 QCOMPARE(spy.interface, QString("local.Interface2"));
749 QCOMPARE(spy.name, QString("signal"));
750 QVERIFY(spy.signature.isEmpty());
751}
752
753void tst_QDBusAbstractAdaptor::scriptableSignalOrNot()
754{
755 QDBusConnection con = QDBusConnection::sessionBus();
756 QVERIFY(con.isConnected());
757
758 {
759 MyObject obj(0);
760
761 con.registerObject(path: "/p1",object: &obj, options: QDBusConnection::ExportScriptableSignals);
762 con.registerObject(path: "/p2",object: &obj, options: { }); // don't export anything
763
764 QDBusSignalSpy spy;
765 con.connect(service: con.baseService(), path: "/p1", interface: "local.MyObject", name: "scriptableSignalVoid", receiver: &spy, SLOT(slot(QDBusMessage)));
766 con.connect(service: con.baseService(), path: "/p2", interface: "local.MyObject", name: "scriptableSignalVoid", receiver: &spy, SLOT(slot(QDBusMessage)));
767 con.connect(service: con.baseService(), path: "/p1", interface: "local.MyObject", name: "nonScriptableSignalVoid", receiver: &spy, SLOT(slot(QDBusMessage)));
768 con.connect(service: con.baseService(), path: "/p2", interface: "local.MyObject", name: "nonScriptableSignalVoid", receiver: &spy, SLOT(slot(QDBusMessage)));
769 obj.emitSignal(name: "scriptableSignalVoid", value: QVariant());
770 obj.emitSignal(name: "nonScriptableSignalVoid", value: QVariant());
771
772 QTRY_COMPARE(spy.count, 1); // only /p1 must have emitted
773 QCOMPARE(spy.interface, QString("local.MyObject"));
774 QCOMPARE(spy.name, QString("scriptableSignalVoid"));
775 QCOMPARE(spy.path, QString("/p1"));
776 QVERIFY(spy.signature.isEmpty());
777 }
778
779 {
780 MyObject obj(0);
781
782 con.registerObject(path: "/p1",object: &obj, options: QDBusConnection::ExportScriptableSignals);
783 con.registerObject(path: "/p2",object: &obj, options: QDBusConnection::ExportScriptableSignals
784 | QDBusConnection::ExportNonScriptableSignals);
785
786 QDBusSignalSpy spy;
787 con.connect(service: con.baseService(), path: "/p1", interface: "local.MyObject", name: "nonScriptableSignalVoid", receiver: &spy, SLOT(slot(QDBusMessage)));
788 con.connect(service: con.baseService(), path: "/p2", interface: "local.MyObject", name: "nonScriptableSignalVoid", receiver: &spy, SLOT(slot(QDBusMessage)));
789 obj.emitSignal(name: "nonScriptableSignalVoid", value: QVariant());
790
791 QTRY_COMPARE(spy.count, 1); // only /p2 must have emitted now
792 QCOMPARE(spy.interface, QString("local.MyObject"));
793 QCOMPARE(spy.name, QString("nonScriptableSignalVoid"));
794 QCOMPARE(spy.path, QString("/p2"));
795 QVERIFY(spy.signature.isEmpty());
796 }
797
798 {
799 QDBusSignalSpy spy;
800 con.connect(service: con.baseService(), path: "/p1", interface: "local.MyObject", name: "destroyed", receiver: &spy, SLOT(slot(QDBusMessage)));
801 con.connect(service: con.baseService(), path: "/p2", interface: "local.MyObject", name: "destroyed", receiver: &spy, SLOT(slot(QDBusMessage)));
802
803 {
804 MyObject obj(0);
805
806 con.registerObject(path: "/p1",object: &obj, options: QDBusConnection::ExportScriptableSignals);
807 con.registerObject(path: "/p2",object: &obj, options: QDBusConnection::ExportScriptableSignals
808 | QDBusConnection::ExportNonScriptableSignals);
809 } // <--- QObject emits the destroyed(QObject*) signal at this point
810
811 QTest::qWait(ms: 200);
812
813 QCOMPARE(spy.count, 0);
814 }
815}
816
817void tst_QDBusAbstractAdaptor::overloadedSignalEmission_data()
818{
819 QTest::addColumn<QString>(name: "signature");
820 QTest::addColumn<QVariant>(name: "parameter");
821 QTest::newRow(dataTag: "void") << QString("") << QVariant();
822 QTest::newRow(dataTag: "int") << "i" << QVariant(1);
823 QTest::newRow(dataTag: "string") << "s" << QVariant("foo");
824}
825
826void tst_QDBusAbstractAdaptor::overloadedSignalEmission()
827{
828 QDBusConnection con = QDBusConnection::sessionBus();
829 QVERIFY(con.isConnected());
830
831 MyObject obj;
832 con.registerObject(path: "/", object: &obj);
833
834 QString interface = "local.Interface4";
835 QString name = "signal";
836 QFETCH(QVariant, parameter);
837 //QDBusInterface *if4 = new QDBusInterface(con.baseService(), "/", interface, con);
838
839 // connect all signals and emit only one
840 {
841 QDBusSignalSpy spy;
842 con.connect(service: con.baseService(), path: "/", interface: "local.Interface4", name: "signal", signature: "",
843 receiver: &spy, SLOT(slot(QDBusMessage)));
844 con.connect(service: con.baseService(), path: "/", interface: "local.Interface4", name: "signal", signature: "i",
845 receiver: &spy, SLOT(slot(QDBusMessage)));
846 con.connect(service: con.baseService(), path: "/", interface: "local.Interface4", name: "signal", signature: "s",
847 receiver: &spy, SLOT(slot(QDBusMessage)));
848
849 emitSignal(obj: &obj, iface: interface, name, parameter);
850
851 QTRY_COMPARE(spy.count, 1);
852 QCOMPARE(spy.interface, interface);
853 QCOMPARE(spy.name, name);
854 QTEST(spy.signature, "signature");
855 QCOMPARE(spy.value, parameter);
856 }
857
858 QFETCH(QString, signature);
859 // connect one signal and emit them all
860 {
861 QDBusSignalSpy spy;
862 con.connect(service: con.baseService(), path: "/", interface, name, signature, receiver: &spy, SLOT(slot(QDBusMessage)));
863 emitSignal(obj: &obj, iface: "local.Interface4", name: "signal", parameter: QVariant());
864 emitSignal(obj: &obj, iface: "local.Interface4", name: "signal", parameter: QVariant(1));
865 emitSignal(obj: &obj, iface: "local.Interface4", name: "signal", parameter: QVariant("foo"));
866
867 QTRY_COMPARE(spy.count, 1);
868 QCOMPARE(spy.interface, interface);
869 QCOMPARE(spy.name, name);
870 QTEST(spy.signature, "signature");
871 QCOMPARE(spy.value, parameter);
872 }
873}
874
875void tst_QDBusAbstractAdaptor::readProperties()
876{
877 QDBusConnection con = QDBusConnection::sessionBus();
878 QVERIFY(con.isConnected());
879
880 MyObject obj;
881 con.registerObject(path: "/", object: &obj);
882
883 QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con);
884 for (int i = 2; i <= 4; ++i) {
885 QString name = QString("Interface%1").arg(a: i);
886
887 for (int j = 1; j <= 2; ++j) {
888 QString propname = QString("prop%1").arg(a: j);
889 QDBusReply<QVariant> reply =
890 properties.call(mode: QDBus::BlockWithGui, method: "Get", args: "local." + name, args&: propname);
891 QVariant value = reply;
892
893 QCOMPARE(value.userType(), int(QVariant::String));
894 QCOMPARE(value.toString(), QString("QString %1::%2() const").arg(name, propname));
895 }
896 }
897}
898
899void tst_QDBusAbstractAdaptor::readPropertiesInvalidInterface()
900{
901 QDBusConnection con = QDBusConnection::sessionBus();
902 QVERIFY(con.isConnected());
903
904 MyObject obj;
905 con.registerObject(path: "/", object: &obj);
906
907 QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con);
908
909 // test an invalid interface:
910 QDBusReply<QVariant> reply = properties.call(mode: QDBus::BlockWithGui, method: "Get", args: "local.DoesntExist", args: "prop1");
911 QVERIFY(!reply.isValid());
912}
913
914void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterface_data()
915{
916 QTest::addColumn<QVariantMap>(name: "expectedProperties");
917 QTest::addColumn<bool>(name: "existing");
918
919 QVariantMap expectedProperties;
920 expectedProperties["prop1"] = QVariant();
921 expectedProperties["prop2"] = QVariant();
922 expectedProperties["interface3prop"] = "QString Interface3::interface3prop() const";
923 expectedProperties["interface4prop"] = "QString Interface4::interface4prop() const";
924 QTest::newRow(dataTag: "existing") << expectedProperties << true;
925
926 expectedProperties.clear();
927 expectedProperties["prop5"] = QVariant();
928 expectedProperties["foobar"] = QVariant();
929 QTest::newRow(dataTag: "non-existing") << expectedProperties << false;
930}
931
932void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterface()
933{
934 QDBusConnection con = QDBusConnection::sessionBus();
935 QVERIFY(con.isConnected());
936
937 MyObject obj;
938 con.registerObject(path: "/", object: &obj);
939
940 QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con);
941
942 QFETCH(QVariantMap, expectedProperties);
943 QFETCH(bool, existing);
944
945 QVariantMap::ConstIterator it = expectedProperties.constBegin();
946 for ( ; it != expectedProperties.constEnd(); ++it) {
947 QDBusReply<QVariant> reply = properties.call(mode: QDBus::BlockWithGui, method: "Get", args: "", args: it.key());
948
949 if (existing) {
950 QVERIFY2(reply.isValid(), qPrintable(it.key()));
951 } else {
952 QVERIFY2(!reply.isValid(), qPrintable(it.key()));
953 continue;
954 }
955
956 QCOMPARE(int(reply.value().type()), int(QVariant::String));
957 if (it.value().isValid())
958 QCOMPARE(reply.value().toString(), it.value().toString());
959 }
960}
961
962void tst_QDBusAbstractAdaptor::readAllProperties()
963{
964 QDBusConnection con = QDBusConnection::sessionBus();
965 QVERIFY(con.isConnected());
966
967 MyObject obj;
968 con.registerObject(path: "/", object: &obj);
969
970 QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con);
971 for (int i = 2; i <= 4; ++i) {
972 QString name = QString("Interface%1").arg(a: i);
973 QDBusReply<QVariantMap> reply =
974 properties.call(mode: QDBus::BlockWithGui, method: "GetAll", args: "local." + name);
975
976 for (int j = 1; j <= 2; ++j) {
977 QString propname = QString("prop%1").arg(a: j);
978 QVERIFY2(reply.value().contains(propname),
979 qPrintable(propname + " on " + name));
980 QVariant value = reply.value().value(akey: propname);
981
982 QCOMPARE(value.userType(), int(QVariant::String));
983 QCOMPARE(value.toString(), QString("QString %1::%2() const").arg(name, propname));
984 }
985 }
986}
987
988void tst_QDBusAbstractAdaptor::readAllPropertiesInvalidInterface()
989{
990 QDBusConnection con = QDBusConnection::sessionBus();
991 QVERIFY(con.isConnected());
992
993 MyObject obj;
994 con.registerObject(path: "/", object: &obj);
995
996 QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con);
997
998 // test an invalid interface:
999 QDBusReply<QVariantMap> reply = properties.call(mode: QDBus::BlockWithGui, method: "GetAll", args: "local.DoesntExist");
1000 QVERIFY(!reply.isValid());
1001}
1002
1003void tst_QDBusAbstractAdaptor::readAllPropertiesEmptyInterface_data()
1004{
1005 readPropertiesEmptyInterface_data();
1006}
1007
1008void tst_QDBusAbstractAdaptor::readAllPropertiesEmptyInterface()
1009{
1010 QDBusConnection con = QDBusConnection::sessionBus();
1011 QVERIFY(con.isConnected());
1012
1013 MyObject obj;
1014 con.registerObject(path: "/", object: &obj);
1015
1016 QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con);
1017
1018 QDBusReply<QVariantMap> reply = properties.call(mode: QDBus::BlockWithGui, method: "GetAll", args: "");
1019 QVERIFY(reply.isValid());
1020
1021 QVariantMap allprops = reply;
1022
1023 QFETCH(QVariantMap, expectedProperties);
1024 QFETCH(bool, existing);
1025
1026 QVariantMap::ConstIterator it = expectedProperties.constBegin();
1027 if (existing) {
1028 for ( ; it != expectedProperties.constEnd(); ++it) {
1029 QVERIFY2(allprops.contains(it.key()), qPrintable(it.key()));
1030
1031 QVariant propvalue = allprops.value(akey: it.key());
1032 QVERIFY2(!propvalue.isNull(), qPrintable(it.key()));
1033 QVERIFY2(propvalue.isValid(), qPrintable(it.key()));
1034
1035 QString stringvalue = propvalue.toString();
1036 QVERIFY2(!stringvalue.isEmpty(), qPrintable(it.key()));
1037
1038 if (it.value().isValid())
1039 QCOMPARE(stringvalue, it.value().toString());
1040
1041 // remove this property from the map
1042 allprops.remove(akey: it.key());
1043 }
1044
1045 QVERIFY2(allprops.isEmpty(),
1046 qPrintable(QStringList(allprops.keys()).join(' ')));
1047 } else {
1048 for ( ; it != expectedProperties.constEnd(); ++it)
1049 QVERIFY2(!allprops.contains(it.key()), qPrintable(it.key()));
1050 }
1051}
1052
1053void tst_QDBusAbstractAdaptor::writeProperties()
1054{
1055 QDBusConnection con = QDBusConnection::sessionBus();
1056 QVERIFY(con.isConnected());
1057
1058 MyObject obj;
1059 con.registerObject(path: "/", object: &obj);
1060
1061 QDBusInterface properties(con.baseService(), "/", "org.freedesktop.DBus.Properties", con);
1062 for (int i = 2; i <= 4; ++i) {
1063 QString name = QString("Interface%1").arg(a: i);
1064
1065 valueSpy.clear();
1066 properties.call(mode: QDBus::BlockWithGui, method: "Set", args: "local." + name, args: QString("prop1"),
1067 args: QVariant::fromValue(value: QDBusVariant(name)));
1068 QVERIFY(valueSpy.isEmpty()); // call mustn't have succeeded
1069
1070 properties.call(mode: QDBus::BlockWithGui, method: "Set", args: "local." + name, args: QString("prop2"),
1071 args: QVariant::fromValue(value: QDBusVariant(name)));
1072 QCOMPARE(valueSpy, name);
1073 QCOMPARE(QString(slotSpy), QString("void %1::setProp2(const QString &)").arg(name));
1074 }
1075}
1076
1077void tst_QDBusAbstractAdaptor::methodCallsPeer_data()
1078{
1079 methodCalls_data();
1080}
1081
1082void tst_QDBusAbstractAdaptor::methodCallsPeer()
1083{
1084 QSKIP("Test is currently too flaky (QTBUG-66223)");
1085 if (QSysInfo::productType().compare(s: "opensuse", cs: Qt::CaseInsensitive) == 0
1086 && QSysInfo::productVersion() == QLatin1String("42.1")
1087 && qgetenv(varName: "QTEST_ENVIRONMENT").split(sep: ' ').contains(t: "ci")) {
1088 QSKIP("This test is occasionally hanging in the CI");
1089 }
1090 QDBusConnection con("peer");
1091 QVERIFY(con.isConnected());
1092
1093 {
1094 // must fail: no object
1095 QDBusInterface if1(QString(), "/", "local.Interface1", con);
1096 QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage);
1097 }
1098
1099 QFETCH(int, nInterfaces);
1100 newMyObjectPeer(nInterfaces);
1101 registerMyObjectPeer(path: "/");
1102
1103 QDBusInterface if1(QString(), "/", "local.Interface1", con);
1104 QDBusInterface if2(QString(), "/", "local.Interface2", con);
1105 QDBusInterface if3(QString(), "/", "local.Interface3", con);
1106 QDBusInterface if4(QString(), "/", "local.Interface4", con);
1107
1108 // must fail: no such method
1109 QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage);
1110 if (!nInterfaces--)
1111 return;
1112 if (!nInterfaces--)
1113 return;
1114
1115 // simple call: one such method exists
1116 QCOMPARE(if2.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ReplyMessage);
1117 QCOMPARE(slotSpyPeer(), QStringLiteral("void Interface2::method()"));
1118 if (!nInterfaces--)
1119 return;
1120
1121 // multiple methods in multiple interfaces, no name overlap
1122 QCOMPARE(if1.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ErrorMessage);
1123 QCOMPARE(if1.call(QDBus::BlockWithGui, "methodInt").type(), QDBusMessage::ErrorMessage);
1124 QCOMPARE(if1.call(QDBus::BlockWithGui, "methodString").type(), QDBusMessage::ErrorMessage);
1125 QCOMPARE(if2.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ErrorMessage);
1126 QCOMPARE(if2.call(QDBus::BlockWithGui, "methodInt").type(), QDBusMessage::ErrorMessage);
1127 QCOMPARE(if2.call(QDBus::BlockWithGui, "methodString").type(), QDBusMessage::ErrorMessage);
1128
1129 QCOMPARE(if3.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ReplyMessage);
1130 QCOMPARE(slotSpyPeer(), QStringLiteral("void Interface3::methodVoid()"));
1131 QCOMPARE(if3.call(QDBus::BlockWithGui, "methodInt", 42).type(), QDBusMessage::ReplyMessage);
1132 QCOMPARE(slotSpyPeer(), QStringLiteral("void Interface3::methodInt(int)"));
1133 QCOMPARE(if3.call(QDBus::BlockWithGui, "methodString", QString("")).type(), QDBusMessage::ReplyMessage);
1134 QCOMPARE(slotSpyPeer(), QStringLiteral("void Interface3::methodString(QString)"));
1135
1136 if (!nInterfaces--)
1137 return;
1138
1139 // method overloading: different interfaces
1140 QCOMPARE(if4.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ReplyMessage);
1141 QCOMPARE(slotSpyPeer(), QStringLiteral("void Interface4::method()"));
1142
1143 // method overloading: different parameters
1144 QCOMPARE(if4.call(QDBus::BlockWithGui, "method.i", 42).type(), QDBusMessage::ReplyMessage);
1145 QCOMPARE(slotSpyPeer(), QStringLiteral("void Interface4::method(int)"));
1146 QCOMPARE(if4.call(QDBus::BlockWithGui, "method.s", QString()).type(), QDBusMessage::ReplyMessage);
1147 QCOMPARE(slotSpyPeer(), QStringLiteral("void Interface4::method(QString)"));
1148}
1149
1150void tst_QDBusAbstractAdaptor::methodCallScriptablePeer()
1151{
1152 QSKIP("Test is currently too flaky (QTBUG-66223)");
1153 QDBusConnection con("peer");
1154 QVERIFY(con.isConnected());
1155
1156 newMyObjectPeer(nInterfaces: 2);
1157 registerMyObjectPeer(path: "/");
1158
1159 QDBusInterface if2(QString(), "/", "local.Interface2", con);
1160
1161 QCOMPARE(if2.call(QDBus::BlockWithGui,"scriptableMethod").type(), QDBusMessage::ReplyMessage);
1162 QCOMPARE(slotSpyPeer(), QStringLiteral("void Interface2::scriptableMethod()"));
1163}
1164
1165void tst_QDBusAbstractAdaptor::signalEmissionsPeer_data()
1166{
1167 signalEmissions_data();
1168}
1169
1170void tst_QDBusAbstractAdaptor::signalEmissionsPeer()
1171{
1172 QSKIP("Test is currently too flaky (QTBUG-66223)");
1173 QFETCH(QString, interface);
1174 QFETCH(QString, name);
1175 QFETCH(QVariant, parameter);
1176
1177 QDBusConnection con("peer");
1178 QVERIFY(con.isConnected());
1179
1180 newMyObjectPeer(nInterfaces: 3);
1181 registerMyObjectPeer(path: "/", options: QDBusConnection::ExportAdaptors
1182 | QDBusConnection::ExportScriptableSignals);
1183
1184 // connect all signals and emit only one
1185 {
1186 syncPeer();
1187
1188 QDBusSignalSpy spy;
1189 con.connect(service: QString(), path: "/", interface: "local.Interface2", name: "signal",
1190 receiver: &spy, SLOT(slot(QDBusMessage)));
1191 con.connect(service: QString(), path: "/", interface: "local.Interface3", name: "signalVoid",
1192 receiver: &spy, SLOT(slot(QDBusMessage)));
1193 con.connect(service: QString(), path: "/", interface: "local.Interface3", name: "signalInt",
1194 receiver: &spy, SLOT(slot(QDBusMessage)));
1195 con.connect(service: QString(), path: "/", interface: "local.Interface3", name: "signalString",
1196 receiver: &spy, SLOT(slot(QDBusMessage)));
1197 con.connect(service: QString(), path: "/", interface: "local.MyObject", name: "scriptableSignalVoid",
1198 receiver: &spy, SLOT(slot(QDBusMessage)));
1199 con.connect(service: QString(), path: "/", interface: "local.MyObject", name: "scriptableSignalInt",
1200 receiver: &spy, SLOT(slot(QDBusMessage)));
1201 con.connect(service: QString(), path: "/", interface: "local.MyObject", name: "scriptableSignalString",
1202 receiver: &spy, SLOT(slot(QDBusMessage)));
1203
1204 emitSignalPeer(interface, name, parameter);
1205
1206 QTRY_COMPARE(spy.count, 1);
1207 QCOMPARE(spy.interface, interface);
1208 QCOMPARE(spy.name, name);
1209 QTEST(spy.signature, "signature");
1210 QCOMPARE(spy.value, parameter);
1211 }
1212
1213 // connect one signal and emit them all
1214 {
1215 syncPeer();
1216
1217 QDBusSignalSpy spy;
1218 con.connect(service: QString(), path: "/", interface, name, receiver: &spy, SLOT(slot(QDBusMessage)));
1219 emitSignalPeer(interface: "local.Interface2", name: "signal", parameter: QVariant());
1220 emitSignalPeer(interface: "local.Interface3", name: "signalVoid", parameter: QVariant());
1221 emitSignalPeer(interface: "local.Interface3", name: "signalInt", parameter: QVariant(1));
1222 emitSignalPeer(interface: "local.Interface3", name: "signalString", parameter: QVariant("foo"));
1223 emitSignalPeer(interface: "local.MyObject", name: "scriptableSignalVoid", parameter: QVariant());
1224 emitSignalPeer(interface: "local.MyObject", name: "scriptableSignalInt", parameter: QVariant(1));
1225 emitSignalPeer(interface: "local.MyObject", name: "scriptableSignalString", parameter: QVariant("foo"));
1226
1227 QTRY_COMPARE(spy.count, 1);
1228 QCOMPARE(spy.interface, interface);
1229 QCOMPARE(spy.name, name);
1230 QTEST(spy.signature, "signature");
1231 QCOMPARE(spy.value, parameter);
1232 }
1233}
1234
1235void tst_QDBusAbstractAdaptor::sameSignalDifferentPathsPeer()
1236{
1237 QSKIP("Test is currently too flaky (QTBUG-66223)");
1238 QDBusConnection con("peer");
1239 QVERIFY(con.isConnected());
1240
1241 newMyObjectPeer(nInterfaces: 2);
1242
1243 registerMyObjectPeer(path: "/p1");
1244 registerMyObjectPeer(path: "/p2");
1245
1246 syncPeer();
1247 QDBusSignalSpy spy;
1248 con.connect(service: QString(), path: "/p1", interface: "local.Interface2", name: "signal", receiver: &spy, SLOT(slot(QDBusMessage)));
1249 emitSignalPeer(interface: "local.Interface2", name: QString(), parameter: QVariant());
1250
1251 QTRY_COMPARE(spy.count, 1);
1252 QCOMPARE(spy.interface, QString("local.Interface2"));
1253 QCOMPARE(spy.name, QString("signal"));
1254 QVERIFY(spy.signature.isEmpty());
1255
1256 // now connect the other one
1257 spy.count = 0;
1258 con.connect(service: QString(), path: "/p2", interface: "local.Interface2", name: "signal", receiver: &spy, SLOT(slot(QDBusMessage)));
1259 emitSignalPeer(interface: "local.Interface2", name: QString(), parameter: QVariant());
1260
1261 QTRY_COMPARE(spy.count, 2);
1262}
1263
1264void tst_QDBusAbstractAdaptor::sameObjectDifferentPathsPeer()
1265{
1266 QSKIP("Test is currently too flaky (QTBUG-66223)");
1267 QDBusConnection con("peer");
1268 QVERIFY(con.isConnected());
1269
1270 newMyObjectPeer(nInterfaces: 2);
1271
1272 registerMyObjectPeer(path: "/p1");
1273 registerMyObjectPeer(path: "/p2", options: { }); // don't export anything
1274
1275 syncPeer();
1276 QDBusSignalSpy spy;
1277 con.connect(service: QString(), path: "/p1", interface: "local.Interface2", name: "signal", receiver: &spy, SLOT(slot(QDBusMessage)));
1278 con.connect(service: QString(), path: "/p2", interface: "local.Interface2", name: "signal", receiver: &spy, SLOT(slot(QDBusMessage)));
1279 emitSignalPeer(interface: "local.Interface2", name: QString(), parameter: QVariant());
1280
1281 QTRY_COMPARE(spy.count, 1);
1282 QCOMPARE(spy.interface, QString("local.Interface2"));
1283 QCOMPARE(spy.name, QString("signal"));
1284 QVERIFY(spy.signature.isEmpty());
1285}
1286
1287void tst_QDBusAbstractAdaptor::scriptableSignalOrNotPeer()
1288{
1289 QSKIP("Test is currently too flaky (QTBUG-66223)");
1290 QDBusConnection con("peer");;
1291 QVERIFY(con.isConnected());
1292
1293 {
1294 newMyObjectPeer(nInterfaces: 0);
1295
1296 registerMyObjectPeer(path: "/p1", options: QDBusConnection::ExportScriptableSignals);
1297 registerMyObjectPeer(path: "/p2", options: { }); // don't export anything
1298
1299 syncPeer();
1300 QDBusSignalSpy spy;
1301 con.connect(service: QString(), path: "/p1", interface: "local.MyObject", name: "scriptableSignalVoid", receiver: &spy, SLOT(slot(QDBusMessage)));
1302 con.connect(service: QString(), path: "/p2", interface: "local.MyObject", name: "scriptableSignalVoid", receiver: &spy, SLOT(slot(QDBusMessage)));
1303 con.connect(service: QString(), path: "/p1", interface: "local.MyObject", name: "nonScriptableSignalVoid", receiver: &spy, SLOT(slot(QDBusMessage)));
1304 con.connect(service: QString(), path: "/p2", interface: "local.MyObject", name: "nonScriptableSignalVoid", receiver: &spy, SLOT(slot(QDBusMessage)));
1305 emitSignalPeer(interface: "local.MyObject", name: "scriptableSignalVoid", parameter: QVariant());
1306 emitSignalPeer(interface: "local.MyObject", name: "nonScriptableSignalVoid", parameter: QVariant());
1307
1308 QTRY_COMPARE(spy.count, 1); // only /p1 must have emitted
1309 QCOMPARE(spy.interface, QString("local.MyObject"));
1310 QCOMPARE(spy.name, QString("scriptableSignalVoid"));
1311 QCOMPARE(spy.path, QString("/p1"));
1312 QVERIFY(spy.signature.isEmpty());
1313 }
1314
1315 {
1316 newMyObjectPeer(nInterfaces: 0);
1317
1318 registerMyObjectPeer(path: "/p1", options: QDBusConnection::ExportScriptableSignals);
1319 registerMyObjectPeer(path: "/p2", options: QDBusConnection::ExportScriptableSignals
1320 | QDBusConnection::ExportNonScriptableSignals);
1321
1322 syncPeer();
1323 QDBusSignalSpy spy;
1324 con.connect(service: QString(), path: "/p1", interface: "local.MyObject", name: "nonScriptableSignalVoid", receiver: &spy, SLOT(slot(QDBusMessage)));
1325 con.connect(service: QString(), path: "/p2", interface: "local.MyObject", name: "nonScriptableSignalVoid", receiver: &spy, SLOT(slot(QDBusMessage)));
1326 emitSignalPeer(interface: "local.MyObject", name: "nonScriptableSignalVoid", parameter: QVariant());
1327
1328 QTRY_COMPARE(spy.count, 1); // only /p2 must have emitted now
1329 QCOMPARE(spy.interface, QString("local.MyObject"));
1330 QCOMPARE(spy.name, QString("nonScriptableSignalVoid"));
1331 QCOMPARE(spy.path, QString("/p2"));
1332 QVERIFY(spy.signature.isEmpty());
1333 }
1334
1335 {
1336 QDBusSignalSpy spy;
1337 con.connect(service: QString(), path: "/p1", interface: "local.MyObject", name: "destroyed", receiver: &spy, SLOT(slot(QDBusMessage)));
1338 con.connect(service: QString(), path: "/p2", interface: "local.MyObject", name: "destroyed", receiver: &spy, SLOT(slot(QDBusMessage)));
1339
1340 {
1341 newMyObjectPeer(nInterfaces: 0);
1342
1343 registerMyObjectPeer(path: "/p1", options: QDBusConnection::ExportScriptableSignals);
1344 registerMyObjectPeer(path: "/p2", options: QDBusConnection::ExportScriptableSignals
1345 | QDBusConnection::ExportNonScriptableSignals);
1346 } // <--- QObject emits the destroyed(QObject*) signal at this point
1347
1348 QTest::qWait(ms: 200);
1349
1350 QCOMPARE(spy.count, 0);
1351 }
1352}
1353
1354void tst_QDBusAbstractAdaptor::overloadedSignalEmissionPeer_data()
1355{
1356 overloadedSignalEmission_data();
1357}
1358
1359void tst_QDBusAbstractAdaptor::overloadedSignalEmissionPeer()
1360{
1361 QSKIP("Test is currently too flaky (QTBUG-66223)");
1362 QDBusConnection con("peer");
1363 QVERIFY(con.isConnected());
1364
1365 newMyObjectPeer();
1366 registerMyObjectPeer(path: "/");
1367
1368 QString interface = "local.Interface4";
1369 QString name = "signal";
1370 QFETCH(QVariant, parameter);
1371 //QDBusInterface *if4 = new QDBusInterface(QString(), "/", interface, con);
1372
1373 // connect all signals and emit only one
1374 {
1375 syncPeer();
1376 QDBusSignalSpy spy;
1377 con.connect(service: QString(), path: "/", interface: "local.Interface4", name: "signal", signature: "",
1378 receiver: &spy, SLOT(slot(QDBusMessage)));
1379 con.connect(service: QString(), path: "/", interface: "local.Interface4", name: "signal", signature: "i",
1380 receiver: &spy, SLOT(slot(QDBusMessage)));
1381 con.connect(service: QString(), path: "/", interface: "local.Interface4", name: "signal", signature: "s",
1382 receiver: &spy, SLOT(slot(QDBusMessage)));
1383
1384 emitSignalPeer(interface, name, parameter);
1385
1386 QTRY_COMPARE(spy.count, 1);
1387 QCOMPARE(spy.interface, interface);
1388 QCOMPARE(spy.name, name);
1389 QTEST(spy.signature, "signature");
1390 QCOMPARE(spy.value, parameter);
1391 }
1392
1393 QFETCH(QString, signature);
1394 // connect one signal and emit them all
1395 {
1396 syncPeer();
1397 QDBusSignalSpy spy;
1398 con.connect(service: QString(), path: "/", interface, name, signature, receiver: &spy, SLOT(slot(QDBusMessage)));
1399 emitSignalPeer(interface: "local.Interface4", name: "signal", parameter: QVariant());
1400 emitSignalPeer(interface: "local.Interface4", name: "signal", parameter: QVariant(1));
1401 emitSignalPeer(interface: "local.Interface4", name: "signal", parameter: QVariant("foo"));
1402
1403 QTRY_COMPARE(spy.count, 1);
1404 QCOMPARE(spy.interface, interface);
1405 QCOMPARE(spy.name, name);
1406 QTEST(spy.signature, "signature");
1407 QCOMPARE(spy.value, parameter);
1408 }
1409}
1410
1411void tst_QDBusAbstractAdaptor::readPropertiesPeer()
1412{
1413 QSKIP("Test is currently too flaky (QTBUG-66223)");
1414 QDBusConnection con("peer");
1415 QVERIFY(con.isConnected());
1416
1417 newMyObjectPeer();
1418 registerMyObjectPeer(path: "/");
1419
1420 QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con);
1421 for (int i = 2; i <= 4; ++i) {
1422 QString name = QString("Interface%1").arg(a: i);
1423
1424 for (int j = 1; j <= 2; ++j) {
1425 QString propname = QString("prop%1").arg(a: j);
1426 QDBusReply<QVariant> reply =
1427 properties.call(mode: QDBus::BlockWithGui, method: "Get", args: "local." + name, args&: propname);
1428 QVariant value = reply;
1429
1430 QCOMPARE(value.userType(), int(QVariant::String));
1431 QCOMPARE(value.toString(), QString("QString %1::%2() const").arg(name, propname));
1432 }
1433 }
1434}
1435
1436void tst_QDBusAbstractAdaptor::readPropertiesInvalidInterfacePeer()
1437{
1438 QSKIP("Test is currently too flaky (QTBUG-66223)");
1439 QDBusConnection con("peer");
1440 QVERIFY(con.isConnected());
1441
1442 newMyObjectPeer();
1443 registerMyObjectPeer(path: "/");
1444
1445 QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con);
1446
1447 // test an invalid interface:
1448 QDBusReply<QVariant> reply = properties.call(mode: QDBus::BlockWithGui, method: "Get", args: "local.DoesntExist", args: "prop1");
1449 QVERIFY(!reply.isValid());
1450}
1451
1452void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterfacePeer_data()
1453{
1454 readPropertiesEmptyInterface_data();
1455}
1456
1457void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterfacePeer()
1458{
1459 QSKIP("Test is currently too flaky (QTBUG-66223)");
1460 QDBusConnection con("peer");
1461 QVERIFY(con.isConnected());
1462
1463 newMyObjectPeer();
1464 registerMyObjectPeer(path: "/");
1465
1466 QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con);
1467
1468 QFETCH(QVariantMap, expectedProperties);
1469 QFETCH(bool, existing);
1470
1471 QVariantMap::ConstIterator it = expectedProperties.constBegin();
1472 for ( ; it != expectedProperties.constEnd(); ++it) {
1473 QDBusReply<QVariant> reply = properties.call(mode: QDBus::BlockWithGui, method: "Get", args: "", args: it.key());
1474
1475 if (existing) {
1476 QVERIFY2(reply.isValid(), qPrintable(it.key()));
1477 } else {
1478 QVERIFY2(!reply.isValid(), qPrintable(it.key()));
1479 continue;
1480 }
1481
1482 QCOMPARE(int(reply.value().type()), int(QVariant::String));
1483 if (it.value().isValid())
1484 QCOMPARE(reply.value().toString(), it.value().toString());
1485 }
1486}
1487
1488void tst_QDBusAbstractAdaptor::readAllPropertiesPeer()
1489{
1490 QSKIP("Test is currently too flaky (QTBUG-66223)");
1491 QDBusConnection con("peer");
1492 QVERIFY(con.isConnected());
1493
1494 newMyObjectPeer();
1495 registerMyObjectPeer(path: "/");
1496
1497 QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con);
1498 for (int i = 2; i <= 4; ++i) {
1499 QString name = QString("Interface%1").arg(a: i);
1500 QDBusReply<QVariantMap> reply =
1501 properties.call(mode: QDBus::BlockWithGui, method: "GetAll", args: "local." + name);
1502
1503 for (int j = 1; j <= 2; ++j) {
1504 QString propname = QString("prop%1").arg(a: j);
1505 QVERIFY2(reply.value().contains(propname),
1506 qPrintable(propname + " on " + name));
1507 QVariant value = reply.value().value(akey: propname);
1508
1509 QCOMPARE(value.userType(), int(QVariant::String));
1510 QCOMPARE(value.toString(), QString("QString %1::%2() const").arg(name, propname));
1511 }
1512 }
1513}
1514
1515void tst_QDBusAbstractAdaptor::readAllPropertiesInvalidInterfacePeer()
1516{
1517 QSKIP("Test is currently too flaky (QTBUG-66223)");
1518 QDBusConnection con("peer");
1519 QVERIFY(con.isConnected());
1520
1521 newMyObjectPeer();
1522 registerMyObjectPeer(path: "/");
1523
1524 QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con);
1525
1526 // test an invalid interface:
1527 QDBusReply<QVariantMap> reply = properties.call(mode: QDBus::BlockWithGui, method: "GetAll", args: "local.DoesntExist");
1528 QVERIFY(!reply.isValid());
1529}
1530
1531void tst_QDBusAbstractAdaptor::readAllPropertiesEmptyInterfacePeer_data()
1532{
1533 readAllPropertiesEmptyInterface_data();
1534}
1535
1536void tst_QDBusAbstractAdaptor::readAllPropertiesEmptyInterfacePeer()
1537{
1538 QDBusConnection con("peer");
1539 QVERIFY(con.isConnected());
1540
1541 newMyObjectPeer();
1542 registerMyObjectPeer(path: "/");
1543
1544 QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con);
1545
1546 QDBusReply<QVariantMap> reply = properties.call(mode: QDBus::BlockWithGui, method: "GetAll", args: "");
1547 QVERIFY(reply.isValid());
1548
1549 QVariantMap allprops = reply;
1550
1551 QFETCH(QVariantMap, expectedProperties);
1552 QFETCH(bool, existing);
1553
1554 QVariantMap::ConstIterator it = expectedProperties.constBegin();
1555 if (existing) {
1556 for ( ; it != expectedProperties.constEnd(); ++it) {
1557 QVERIFY2(allprops.contains(it.key()), qPrintable(it.key()));
1558
1559 QVariant propvalue = allprops.value(akey: it.key());
1560 QVERIFY2(!propvalue.isNull(), qPrintable(it.key()));
1561 QVERIFY2(propvalue.isValid(), qPrintable(it.key()));
1562
1563 QString stringvalue = propvalue.toString();
1564 QVERIFY2(!stringvalue.isEmpty(), qPrintable(it.key()));
1565
1566 if (it.value().isValid())
1567 QCOMPARE(stringvalue, it.value().toString());
1568
1569 // remove this property from the map
1570 allprops.remove(akey: it.key());
1571 }
1572
1573 QVERIFY2(allprops.isEmpty(),
1574 qPrintable(QStringList(allprops.keys()).join(' ')));
1575 } else {
1576 for ( ; it != expectedProperties.constEnd(); ++it)
1577 QVERIFY2(!allprops.contains(it.key()), qPrintable(it.key()));
1578 }
1579}
1580
1581void tst_QDBusAbstractAdaptor::writePropertiesPeer()
1582{
1583 QSKIP("Test is currently too flaky (QTBUG-66223)");
1584 QDBusConnection con("peer");
1585 QVERIFY(con.isConnected());
1586
1587 newMyObjectPeer();
1588 registerMyObjectPeer(path: "/");
1589
1590 QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con);
1591 for (int i = 2; i <= 4; ++i) {
1592 QString name = QString("Interface%1").arg(a: i);
1593
1594 clearValueSpyPeer();
1595 properties.call(mode: QDBus::BlockWithGui, method: "Set", args: "local." + name, args: QString("prop1"),
1596 args: QVariant::fromValue(value: QDBusVariant(name)));
1597 QVERIFY(valueSpyPeer().isEmpty()); // call mustn't have succeeded
1598
1599 properties.call(mode: QDBus::BlockWithGui, method: "Set", args: "local." + name, args: QString("prop2"),
1600 args: QVariant::fromValue(value: QDBusVariant(name)));
1601 QCOMPARE(valueSpyPeer(), name);
1602 QCOMPARE(QString(slotSpyPeer()), QString("void %1::setProp2(const QString &)").arg(name));
1603 }
1604}
1605
1606#if 0
1607void tst_QDBusAbstractAdaptor::adaptorIntrospection_data()
1608{
1609 methodCalls_data();
1610}
1611
1612void tst_QDBusAbstractAdaptor::adaptorIntrospection()
1613{
1614 QDBusConnection con = QDBus::sessionBus();
1615 QVERIFY(con.isConnected());
1616
1617 QObject obj;
1618 con.registerObject("/", &obj);
1619
1620 QFETCH(int, nInterfaces);
1621 switch (nInterfaces)
1622 {
1623 case 4:
1624 new Interface4(&obj);
1625 case 3:
1626 new Interface3(&obj);
1627 case 2:
1628 new Interface2(&obj);
1629 case 1:
1630 new Interface1(&obj);
1631 }
1632
1633 QDBusObject dobj = con.findObject(con.baseService(), "/");
1634 QVERIFY(dobj.isValid());
1635
1636 QString xml = dobj.introspect();
1637 QVERIFY(!xml.isEmpty());
1638
1639 QStringList interfaces = dobj.interfaces();
1640 QCOMPARE(interfaces.count(), nInterfaces + 2);
1641 switch (nInterfaces)
1642 {
1643 case 4: {
1644 QVERIFY(interfaces.contains("local.Interface4"));
1645 QDBusInterface iface(dobj, "local.Interface4");
1646 QCOMPARE(iface.methodData(), Interface4::methodData);
1647 QCOMPARE(iface.signalData(), Interface4::signalData);
1648 QCOMPARE(iface.propertyData(), Interface4::propertyData);
1649 }
1650 case 3: {
1651 QVERIFY(interfaces.contains("local.Interface3"));
1652 QDBusInterface iface(dobj, "local.Interface3");
1653 QCOMPARE(iface.methodData(), Interface3::methodData);
1654 QCOMPARE(iface.signalData(), Interface3::signalData);
1655 QCOMPARE(iface.propertyData(), Interface3::propertyData);
1656 }
1657 case 2: {
1658 QVERIFY(interfaces.contains("local.Interface2"));
1659 QDBusInterface iface(dobj, "local.Interface2");
1660 QCOMPARE(iface.methodData(), Interface2::methodData);
1661 QCOMPARE(iface.signalData(), Interface2::signalData);
1662 QCOMPARE(iface.propertyData(), Interface2::propertyData);
1663 }
1664 case 1: {
1665 QVERIFY(interfaces.contains("local.Interface1"));
1666 QDBusInterface iface(dobj, "local.Interface1");
1667 QCOMPARE(iface.methodData(), Interface1::methodData);
1668 QCOMPARE(iface.signalData(), Interface1::signalData);
1669 QCOMPARE(iface.propertyData(), Interface1::propertyData);
1670 }
1671 }
1672}
1673
1674void tst_QDBusAbstractAdaptor::objectTreeIntrospection()
1675{
1676 QDBusConnection con = QDBus::sessionBus();
1677 QVERIFY(con.isConnected());
1678
1679 {
1680 QDBusObject dobj = con.findObject(con.baseService(), "/");
1681 QString xml = dobj.introspect();
1682
1683 QDBusIntrospection::Object tree =
1684 QDBusIntrospection::parseObject(xml);
1685 QVERIFY(tree.childObjects.isEmpty());
1686 }
1687
1688 QObject root;
1689 con.registerObject("/", &root);
1690 {
1691 QDBusObject dobj = con.findObject(con.baseService(), "/");
1692 QString xml = dobj.introspect();
1693
1694 QDBusIntrospection::Object tree =
1695 QDBusIntrospection::parseObject(xml);
1696 QVERIFY(tree.childObjects.isEmpty());
1697 }
1698
1699 QObject p1;
1700 con.registerObject("/p1", &p1);
1701 {
1702 QDBusObject dobj = con.findObject(con.baseService(), "/");
1703 QString xml = dobj.introspect();
1704
1705 QDBusIntrospection::Object tree =
1706 QDBusIntrospection::parseObject(xml);
1707 QVERIFY(tree.childObjects.contains("p1"));
1708 }
1709
1710 con.unregisterObject("/");
1711 {
1712 QDBusObject dobj = con.findObject(con.baseService(), "/");
1713 QString xml = dobj.introspect();
1714
1715 QDBusIntrospection::Object tree =
1716 QDBusIntrospection::parseObject(xml);
1717 QVERIFY(tree.childObjects.contains("p1"));
1718 }
1719
1720 con.registerObject("/p1/q/r", &root);
1721 {
1722 QDBusObject dobj = con.findObject(con.baseService(), "/p1");
1723 QString xml = dobj.introspect();
1724
1725 QDBusIntrospection::Object tree =
1726 QDBusIntrospection::parseObject(xml);
1727 QVERIFY(tree.childObjects.contains("q"));
1728 }
1729 {
1730 QDBusObject dobj = con.findObject(con.baseService(), "/p1/q");
1731 QString xml = dobj.introspect();
1732
1733 QDBusIntrospection::Object tree =
1734 QDBusIntrospection::parseObject(xml);
1735 QVERIFY(tree.childObjects.contains("r"));
1736 }
1737
1738 con.unregisterObject("/p1", QDBusConnection::UnregisterTree);
1739 {
1740 QDBusObject dobj = con.findObject(con.baseService(), "/");
1741 QString xml = dobj.introspect();
1742
1743 QDBusIntrospection::Object tree =
1744 QDBusIntrospection::parseObject(xml);
1745 QVERIFY(tree.childObjects.isEmpty());
1746 }
1747
1748 QObject p2;
1749 con.registerObject("/p2", &p2, QDBusConnection::ExportChildObjects);
1750 {
1751 QDBusObject dobj = con.findObject(con.baseService(), "/");
1752 QString xml = dobj.introspect();
1753
1754 QDBusIntrospection::Object tree =
1755 QDBusIntrospection::parseObject(xml);
1756 QVERIFY(!tree.childObjects.contains("p1"));
1757 QVERIFY(tree.childObjects.contains("p2"));
1758 }
1759
1760 QObject q;
1761 q.setParent(&p2);
1762 {
1763 QDBusObject dobj = con.findObject(con.baseService(), "/p2");
1764 QString xml = dobj.introspect();
1765
1766 QDBusIntrospection::Object tree =
1767 QDBusIntrospection::parseObject(xml);
1768 QVERIFY(!tree.childObjects.contains("q"));
1769 }
1770
1771 q.setObjectName("q");
1772 {
1773 QDBusObject dobj = con.findObject(con.baseService(), "/p2");
1774 QString xml = dobj.introspect();
1775
1776 QDBusIntrospection::Object tree =
1777 QDBusIntrospection::parseObject(xml);
1778 QVERIFY(tree.childObjects.contains("q"));
1779 }
1780
1781 q.setParent(0);
1782 {
1783 QDBusObject dobj = con.findObject(con.baseService(), "/p2");
1784 QString xml = dobj.introspect();
1785
1786 QDBusIntrospection::Object tree =
1787 QDBusIntrospection::parseObject(xml);
1788 QVERIFY(!tree.childObjects.contains("q"));
1789 }
1790}
1791#endif
1792
1793void tst_QDBusAbstractAdaptor::typeMatching_data()
1794{
1795 QTest::addColumn<QString>(name: "basename");
1796 QTest::addColumn<QString>(name: "signature");
1797 QTest::addColumn<QVariant>(name: "value");
1798
1799 QTest::newRow(dataTag: "bool") << "Bool" << "b" << QVariant(true);
1800 QTest::newRow(dataTag: "byte") << "UChar" << "y" << QVariant::fromValue(value: uchar(42));
1801 QTest::newRow(dataTag: "short") << "Short" << "n" << QVariant::fromValue(value: short(-43));
1802 QTest::newRow(dataTag: "ushort") << "UShort" << "q" << QVariant::fromValue(value: ushort(44));
1803 QTest::newRow(dataTag: "int") << "Int" << "i" << QVariant(42);
1804 QTest::newRow(dataTag: "uint") << "UInt" << "u" << QVariant(42U);
1805 QTest::newRow(dataTag: "qlonglong") << "LongLong" << "x" << QVariant(Q_INT64_C(42));
1806 QTest::newRow(dataTag: "qulonglong") << "ULongLong" << "t" << QVariant(Q_UINT64_C(42));
1807 QTest::newRow(dataTag: "double") << "Double" << "d" << QVariant(2.5);
1808 QTest::newRow(dataTag: "string") << "String" << "s" << QVariant("Hello, World!");
1809
1810 QTest::newRow(dataTag: "variant") << "Variant" << "v" << QVariant::fromValue(value: QDBusVariant("Hello again!"));
1811 QTest::newRow(dataTag: "list") << "List" << "av" << QVariant(QVariantList()
1812 << 42
1813 << QString("foo")
1814 << QByteArray("bar")
1815 << QVariant::fromValue(value: QDBusVariant(QString("baz"))));
1816 QTest::newRow(dataTag: "stringlist") << "StringList" << "as" << QVariant(QStringList() << "Hello" << "world");
1817 QTest::newRow(dataTag: "bytearray") << "ByteArray" << "ay" << QVariant(QByteArray("foo"));
1818
1819 QVariantMap map;
1820 map["one"] = 1; // int
1821 map["The answer to life, the Universe and everything"] = 42u; // uint
1822 map["In the beginning..."] = QString("There was nothing"); // string
1823 map["but Unix came and said"] = QByteArray("\"Hello, World\""); // bytearray
1824 map["two"] = QVariant::fromValue(value: short(2)); // short
1825 QTest::newRow(dataTag: "map") << "Map" << "a{sv}" << QVariant(map);
1826
1827 StringStringMap ssmap;
1828 ssmap["a"] = "A";
1829 ssmap["A"] = "a";
1830 QTest::newRow(dataTag: "ssmap") << "SSMap" << "a{ss}" << QVariant::fromValue(value: ssmap);
1831
1832 LLDateTimeMap lldtmap;
1833 lldtmap[-1] = QDateTime();
1834 QDateTime now = QDateTime::currentDateTime();
1835 lldtmap[now.toSecsSinceEpoch()] = now; // array of struct of int64 and struct of 3 ints and struct of 4 ints and int
1836 QTest::newRow(dataTag: "lldtmap") << "LLDateTimeMap" << "a{x((iii)(iiii)i)}" << QVariant::fromValue(value: lldtmap);
1837
1838 MyStruct s;
1839 s.i = 42;
1840 s.s = "A value";
1841 QTest::newRow(dataTag: "struct") << "Struct" << "(is)" << QVariant::fromValue(value: s);
1842}
1843
1844void tst_QDBusAbstractAdaptor::typeMatching()
1845{
1846 QObject obj;
1847 new TypesInterface(&obj);
1848
1849 QDBusConnection con = QDBusConnection::sessionBus();
1850 con.registerObject(path: "/types", object: &obj);
1851
1852 QFETCH(QString, basename);
1853 QFETCH(QString, signature);
1854 QFETCH(QVariant, value);
1855
1856 QDBusMessage reply;
1857 QDBusInterface iface(con.baseService(), "/types", "local.TypesInterface", con);
1858
1859 reply = iface.callWithArgumentList(mode: QDBus::BlockWithGui, method: "method" + basename,
1860 args: QVariantList() << value);
1861 QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
1862
1863 reply = iface.call(mode: QDBus::BlockWithGui, method: "retrieve" + basename);
1864 QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
1865 QCOMPARE(reply.arguments().count(), 1);
1866
1867 const QVariant &retval = reply.arguments().at(i: 0);
1868 QVERIFY(compare(retval, value));
1869}
1870
1871void tst_QDBusAbstractAdaptor::methodWithMoreThanOneReturnValue()
1872{
1873 QDBusConnection con = QDBusConnection::sessionBus();
1874 QVERIFY(con.isConnected());
1875
1876 MyObject obj;
1877 con.registerObject(path: "/", object: &obj);
1878
1879 QString testString = "This is a test string.";
1880
1881 QDBusInterface remote(con.baseService(), "/", "local.Interface3", con);
1882 QDBusMessage reply = remote.call(mode: QDBus::BlockWithGui, method: "methodStringString", args&: testString);
1883 QCOMPARE(reply.arguments().count(), 2);
1884
1885 QDBusReply<int> intreply = reply;
1886 QVERIFY(intreply.isValid());
1887 QCOMPARE(intreply.value(), 42);
1888
1889 QCOMPARE(reply.arguments().at(1).userType(), int(QVariant::String));
1890 QCOMPARE(qdbus_cast<QString>(reply.arguments().at(1)), testString);
1891}
1892
1893void tst_QDBusAbstractAdaptor::methodWithMoreThanOneReturnValuePeer()
1894{
1895 QSKIP("Test is currently too flaky (QTBUG-66223)");
1896 QDBusConnection con("peer");
1897 QVERIFY(con.isConnected());
1898
1899 newMyObjectPeer();
1900 registerMyObjectPeer(path: "/");
1901
1902 QString testString = "This is a test string.";
1903
1904 QDBusInterface remote(QString(), "/", "local.Interface3", con);
1905 QDBusMessage reply = remote.call(mode: QDBus::BlockWithGui, method: "methodStringString", args&: testString);
1906 QCOMPARE(reply.arguments().count(), 2);
1907
1908 QDBusReply<int> intreply = reply;
1909 QVERIFY(intreply.isValid());
1910 QCOMPARE(intreply.value(), 42);
1911
1912 QCOMPARE(reply.arguments().at(1).userType(), int(QVariant::String));
1913 QCOMPARE(qdbus_cast<QString>(reply.arguments().at(1)), testString);
1914}
1915
1916QTEST_MAIN(tst_QDBusAbstractAdaptor)
1917
1918#include "tst_qdbusabstractadaptor.moc"
1919

source code of qtbase/tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp