1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com>
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
30#include <QtTest/QtTest>
31
32#include <qcoreapplication.h>
33#include <qpointer.h>
34#include <qtimer.h>
35#include <qregularexpression.h>
36#include <qmetaobject.h>
37#include <qvariant.h>
38#include <QTcpServer>
39#include <QTcpSocket>
40#include <QThread>
41#include <QMutex>
42#include <QWaitCondition>
43#include <QScopedPointer>
44#if QT_CONFIG(process)
45# include <QProcess>
46#endif
47#include "qobject.h"
48#ifdef QT_BUILD_INTERNAL
49#include <private/qobject_p.h>
50#endif
51
52#include <math.h>
53
54class tst_QObject : public QObject
55{
56 Q_OBJECT
57private slots:
58 void disconnect();
59 void connectSlotsByName();
60 void connectSignalsToSignalsWithDefaultArguments();
61 void receivers();
62 void normalize();
63 void qobject_castTemplate();
64 void findChildren();
65 void connectDisconnectNotify_data();
66 void connectDisconnectNotify();
67 void connectDisconnectNotifyPMF();
68 void disconnectNotify_receiverDestroyed();
69 void disconnectNotify_metaObjConnection();
70 void connectNotify_connectSlotsByName();
71 void connectDisconnectNotify_shadowing();
72 void emitInDefinedOrder();
73 void customTypes();
74 void streamCustomTypes();
75 void metamethod();
76 void namespaces();
77 void threadSignalEmissionCrash();
78 void thread();
79 void thread0();
80 void moveToThread();
81 void senderTest();
82 void declareInterface();
83 void qpointerResetBeforeDestroyedSignal();
84#ifndef QT_NO_USERDATA
85 void testUserData();
86#endif
87 void childDeletesItsSibling();
88 void dynamicProperties();
89 void floatProperty();
90 void qrealProperty();
91 void property();
92 void recursiveSignalEmission();
93 void signalBlocking();
94 void blockingQueuedConnection();
95 void childEvents();
96 void installEventFilter();
97 void deleteSelfInSlot();
98 void disconnectSelfInSlotAndDeleteAfterEmit();
99 void dumpObjectInfo();
100 void connectToSender();
101 void qobjectConstCast();
102 void uniqConnection();
103 void uniqConnectionPtr();
104 void interfaceIid();
105 void deleteQObjectWhenDeletingEvent();
106 void overloads();
107 void isSignalConnected();
108 void isSignalConnectedAfterDisconnection();
109 void qMetaObjectConnect();
110 void qMetaObjectDisconnectOne();
111 void sameName();
112 void connectByMetaMethods();
113 void connectByMetaMethodSlotInsteadOfSignal();
114 void connectConstructorByMetaMethod();
115 void disconnectByMetaMethod();
116 void disconnectNotSignalMetaMethod();
117 void autoConnectionBehavior();
118 void baseDestroyed();
119 void pointerConnect();
120 void pointerDisconnect();
121 void emitInDefinedOrderPointer();
122 void customTypesPointer();
123 void connectCxx0x();
124 void connectToStaticCxx0x();
125 void connectCxx0xTypeMatching();
126 void connectCxx17Noexcept();
127 void connectConvert();
128 void connectWithReference();
129 void connectManyArguments();
130 void connectForwardDeclare();
131 void connectNoDefaultConstructorArg();
132 void returnValue_data();
133 void returnValue();
134 void returnValue2_data();
135 void returnValue2();
136 void connectVirtualSlots();
137 void connectSlotsVMIClass(); // VMI = Virtual or Multiple Inheritance
138 void connectPrivateSlots();
139 void connectFunctorArgDifference();
140 void connectFunctorOverloads();
141 void connectFunctorQueued();
142 void connectFunctorWithContext();
143 void connectFunctorWithContextUnique();
144 void connectFunctorDeadlock();
145 void connectFunctorMoveOnly();
146 void connectStaticSlotWithObject();
147 void disconnectDoesNotLeakFunctor();
148 void contextDoesNotLeakFunctor();
149 void connectBase();
150 void connectWarnings();
151 void qmlConnect();
152 void qmlConnectToQObjectReceiver();
153 void exceptions();
154 void noDeclarativeParentChangedOnDestruction();
155 void deleteLaterInAboutToBlockHandler();
156 void mutableFunctor();
157 void checkArgumentsForNarrowing();
158 void nullReceiver();
159 void functorReferencesConnection();
160 void disconnectDisconnects();
161};
162
163struct QObjectCreatedOnShutdown
164{
165 QObjectCreatedOnShutdown() {}
166 ~QObjectCreatedOnShutdown()
167 {
168 QObject();
169 }
170};
171static QObjectCreatedOnShutdown s_qobjectCreatedOnShutdown;
172
173class SenderObject : public QObject
174{
175 Q_OBJECT
176
177public:
178 SenderObject() : aPublicSlotCalled(0), recursionCount(0) {}
179
180 void emitSignal1AfterRecursion()
181 {
182 if (recursionCount++ < 100)
183 emitSignal1AfterRecursion();
184 else
185 emitSignal1();
186 }
187
188 void emitSignal1() { emit signal1(); }
189 void emitSignal2() { emit signal2(); }
190 void emitSignal3() { emit signal3(); }
191 void emitSignal4() { emit signal4(); }
192
193signals:
194 void signal1();
195 void signal2();
196 void signal3();
197 void signal4();
198 QT_MOC_COMPAT void signal5();
199 void signal6(void);
200 void signal7(int, const QString &);
201
202public slots:
203 void aPublicSlot() { aPublicSlotCalled++; }
204
205public:
206 Q_INVOKABLE void invoke1(){}
207 Q_SCRIPTABLE void sinvoke1(){}
208 int aPublicSlotCalled;
209protected:
210 Q_INVOKABLE QT_MOC_COMPAT void invoke2(){}
211 Q_INVOKABLE QT_MOC_COMPAT void invoke2(int){}
212 Q_SCRIPTABLE QT_MOC_COMPAT void sinvoke2(){}
213private:
214 Q_INVOKABLE void invoke3(int hinz = 0, int kunz = 0){Q_UNUSED(hinz) Q_UNUSED(kunz)}
215 Q_SCRIPTABLE void sinvoke3(){}
216
217 int recursionCount;
218};
219
220class ReceiverObject : public QObject
221{
222 Q_OBJECT
223
224public:
225 ReceiverObject()
226 : sequence_slot1( 0 )
227 , sequence_slot2( 0 )
228 , sequence_slot3( 0 )
229 , sequence_slot4( 0 )
230 {}
231
232 void reset()
233 {
234 sequence_slot4 = 0;
235 sequence_slot3 = 0;
236 sequence_slot2 = 0;
237 sequence_slot1 = 0;
238 count_slot1 = 0;
239 count_slot2 = 0;
240 count_slot3 = 0;
241 count_slot4 = 0;
242 }
243
244 int sequence_slot1;
245 int sequence_slot2;
246 int sequence_slot3;
247 int sequence_slot4;
248 int count_slot1;
249 int count_slot2;
250 int count_slot3;
251 int count_slot4;
252
253 bool called(int slot)
254 {
255 switch (slot) {
256 case 1: return sequence_slot1;
257 case 2: return sequence_slot2;
258 case 3: return sequence_slot3;
259 case 4: return sequence_slot4;
260 default: return false;
261 }
262 }
263
264 static int sequence;
265
266public slots:
267 void slot1() { sequence_slot1 = ++sequence; count_slot1++; }
268 void slot2() { sequence_slot2 = ++sequence; count_slot2++; }
269 void slot3() { sequence_slot3 = ++sequence; count_slot3++; }
270 void slot4() { sequence_slot4 = ++sequence; count_slot4++; }
271
272};
273
274int ReceiverObject::sequence = 0;
275
276static void playWithObjects()
277{
278 // Do operations that will lock the internal signalSlotLock mutex on many QObjects.
279 // The more QObjects, the higher the chance that the signalSlotLock mutex used
280 // is already in use. If the number of objects is higher than the number of mutexes in
281 // the pool (currently 131), the deadlock should always trigger. Use an even higher number
282 // to be on the safe side.
283 const int objectCount = 1024;
284 SenderObject lotsOfObjects[objectCount];
285 for (int i = 0; i < objectCount; ++i) {
286 QObject::connect(sender: &lotsOfObjects[i], signal: &SenderObject::signal1,
287 receiver: &lotsOfObjects[i], slot: &SenderObject::aPublicSlot);
288 }
289}
290
291void tst_QObject::disconnect()
292{
293 SenderObject s;
294 ReceiverObject r1;
295 ReceiverObject r2;
296
297 connect(sender: &s, SIGNAL(signal1()), receiver: &r1, SLOT(slot1()));
298
299 connect(sender: &s, SIGNAL(signal2()), receiver: &r1, SLOT(slot2()));
300 connect(sender: &s, SIGNAL(signal3()), receiver: &r1, SLOT(slot3()));
301 connect(sender: &s, SIGNAL(signal4()), receiver: &r1, SLOT(slot4()));
302
303 s.emitSignal1();
304 s.emitSignal2();
305 s.emitSignal3();
306 s.emitSignal4();
307
308 QVERIFY(r1.called(1));
309 QVERIFY(r1.called(2));
310 QVERIFY(r1.called(3));
311 QVERIFY(r1.called(4));
312 r1.reset();
313
314 // usual disconnect with all parameters given
315 bool ret = QObject::disconnect(sender: &s, SIGNAL(signal1()), receiver: &r1, SLOT(slot1()));
316
317 s.emitSignal1();
318
319 QVERIFY(!r1.called(1));
320 r1.reset();
321
322 QVERIFY(ret);
323 ret = QObject::disconnect(sender: &s, SIGNAL(signal1()), receiver: &r1, SLOT(slot1()));
324 QVERIFY(!ret);
325
326 // disconnect all signals from s from all slots from r1
327 QObject::disconnect(sender: &s, signal: 0, receiver: &r1, member: 0);
328
329 s.emitSignal2();
330 s.emitSignal3();
331 s.emitSignal4();
332
333 QVERIFY(!r1.called(2));
334 QVERIFY(!r1.called(3));
335 QVERIFY(!r1.called(4));
336 r1.reset();
337
338 connect(sender: &s, SIGNAL(signal1()), receiver: &r1, SLOT(slot1()));
339 connect(sender: &s, SIGNAL(signal1()), receiver: &r1, SLOT(slot2()));
340 connect(sender: &s, SIGNAL(signal1()), receiver: &r1, SLOT(slot3()));
341 connect(sender: &s, SIGNAL(signal2()), receiver: &r1, SLOT(slot4()));
342
343 // disconnect s's signal1() from all slots of r1
344 QObject::disconnect(sender: &s, SIGNAL(signal1()), receiver: &r1, member: 0);
345
346 s.emitSignal1();
347 s.emitSignal2();
348
349 QVERIFY(!r1.called(1));
350 QVERIFY(!r1.called(2));
351 QVERIFY(!r1.called(3));
352 QVERIFY(r1.called(4));
353 r1.reset();
354 // make sure all is disconnected again
355 QObject::disconnect(sender: &s, signal: 0, receiver: &r1, member: 0);
356
357 connect(sender: &s, SIGNAL(signal1()), receiver: &r1, SLOT(slot1()));
358 connect(sender: &s, SIGNAL(signal1()), receiver: &r2, SLOT(slot1()));
359 connect(sender: &s, SIGNAL(signal2()), receiver: &r1, SLOT(slot2()));
360 connect(sender: &s, SIGNAL(signal2()), receiver: &r2, SLOT(slot2()));
361 connect(sender: &s, SIGNAL(signal3()), receiver: &r1, SLOT(slot3()));
362 connect(sender: &s, SIGNAL(signal3()), receiver: &r2, SLOT(slot3()));
363
364 // disconnect signal1() from all receivers
365 QObject::disconnect(sender: &s, SIGNAL(signal1()), receiver: 0, member: 0);
366 s.emitSignal1();
367 s.emitSignal2();
368 s.emitSignal3();
369
370 QVERIFY(!r1.called(1));
371 QVERIFY(!r2.called(1));
372 QVERIFY(r1.called(2));
373 QVERIFY(r2.called(2));
374 QVERIFY(r1.called(2));
375 QVERIFY(r2.called(2));
376
377 r1.reset();
378 r2.reset();
379
380 // disconnect all signals of s from all receivers
381 QObject::disconnect(sender: &s, signal: 0, receiver: 0, member: 0);
382
383 QVERIFY(!r1.called(2));
384 QVERIFY(!r2.called(2));
385 QVERIFY(!r1.called(2));
386 QVERIFY(!r2.called(2));
387}
388
389class AutoConnectSender : public QObject
390{
391 Q_OBJECT
392
393public:
394 AutoConnectSender(QObject *parent)
395 : QObject(parent)
396 {}
397
398 void emitSignalNoParams() { emit signalNoParams(); }
399 void emitSignalWithParams(int i) { emit signalWithParams(i); }
400 void emitSignalWithParams(int i, QString string) { emit signalWithParams(i, string); }
401 void emitSignalManyParams(int i1, int i2, int i3, QString string, bool onoff) { emit signalManyParams(i1, i2, i3, string, onoff); }
402 void emitSignalManyParams(int i1, int i2, int i3, QString string, bool onoff, bool dummy) { emit signalManyParams(i1, i2, i3, string, onoff, dummy); }
403 void emitSignalManyParams2(int i1, int i2, int i3, QString string, bool onoff) { emit signalManyParams2(i1, i2, i3, string, onoff); }
404 void emitSignalLoopBack() { emit signalLoopBack(); }
405
406signals:
407 void signalNoParams();
408 void signalWithParams(int i);
409 void signalWithParams(int i, QString string);
410 void signalManyParams(int i1, int i2, int i3, QString string, bool onoff);
411 void signalManyParams(int i1, int i2, int i3, QString string, bool onoff, bool);
412 void signalManyParams2(int i1, int i2, int i3, QString string, bool onoff);
413 void signalLoopBack();
414};
415
416class AutoConnectReceiver : public QObject
417{
418 Q_OBJECT
419
420public:
421 QList<int> called_slots;
422
423 AutoConnectReceiver()
424 {
425 connect(sender: this, SIGNAL(on_Sender_signalLoopBack()), receiver: this, SLOT(slotLoopBack()));
426 }
427
428 void emitSignalNoParams() { emit signalNoParams(); }
429 void emit_signal_with_underscore() { emit signal_with_underscore(); }
430
431public slots:
432 void on_Sender_signalNoParams() { called_slots << 1; }
433 void on_Sender_signalWithParams(int i = 0) { called_slots << 2; Q_UNUSED(i); }
434 void on_Sender_signalWithParams(int i, QString string) { called_slots << 3; Q_UNUSED(i);Q_UNUSED(string); }
435 void on_Sender_signalManyParams() { called_slots << 4; }
436 void on_Sender_signalManyParams(int i1, int i2, int i3, QString string, bool onoff)
437 { called_slots << 5; Q_UNUSED(i1);Q_UNUSED(i2);Q_UNUSED(i3);Q_UNUSED(string);Q_UNUSED(onoff); }
438 void on_Sender_signalManyParams(int i1, int i2, int i3, QString string, bool onoff, bool dummy)
439 { called_slots << 6; Q_UNUSED(i1);Q_UNUSED(i2);Q_UNUSED(i3);Q_UNUSED(string);Q_UNUSED(onoff); Q_UNUSED(dummy);}
440 void on_Sender_signalManyParams2(int i1, int i2, int i3, QString string, bool onoff)
441 { called_slots << 7; Q_UNUSED(i1);Q_UNUSED(i2);Q_UNUSED(i3);Q_UNUSED(string);Q_UNUSED(onoff); }
442 void slotLoopBack() { called_slots << 8; }
443 void on_Receiver_signalNoParams() { called_slots << 9; }
444 void on_Receiver_signal_with_underscore() { called_slots << 10; }
445
446protected slots:
447 void o() { called_slots << -1; }
448 void on() { called_slots << -1; }
449 void on_() { called_slots << -1; }
450 void on_something() { called_slots << -1; }
451 void on_child_signal() { called_slots << -1; }
452
453signals:
454 void on_Sender_signalLoopBack();
455 void signalNoParams();
456 void signal_with_underscore();
457};
458
459void tst_QObject::connectSlotsByName()
460{
461 AutoConnectReceiver receiver;
462 receiver.setObjectName("Receiver");
463 AutoConnectSender sender(&receiver);
464 sender.setObjectName("Sender");
465
466 QTest::ignoreMessage(type: QtWarningMsg, message: "QMetaObject::connectSlotsByName: No matching signal for on_child_signal()");
467 QTest::ignoreMessage(type: QtWarningMsg, message: "QMetaObject::connectSlotsByName: Connecting slot on_Sender_signalManyParams() with the first of the following compatible signals: (\"signalManyParams(int,int,int,QString,bool)\", \"signalManyParams(int,int,int,QString,bool,bool)\")");
468 QMetaObject::connectSlotsByName(o: &receiver);
469
470 receiver.called_slots.clear();
471 sender.emitSignalNoParams();
472 QCOMPARE(receiver.called_slots, QList<int>() << 1);
473
474 receiver.called_slots.clear();
475 sender.emitSignalWithParams(i: 0);
476 QCOMPARE(receiver.called_slots, QList<int>() << 2);
477
478 receiver.called_slots.clear();
479 sender.emitSignalWithParams(i: 0, string: "string");
480 QCOMPARE(receiver.called_slots, QList<int>() << 3);
481
482 receiver.called_slots.clear();
483 sender.emitSignalManyParams(i1: 1, i2: 2, i3: 3, string: "string", onoff: true);
484 sender.emitSignalManyParams(i1: 1, i2: 2, i3: 3, string: "string", onoff: true, dummy: false);
485 // the slot '4' (signalManyParams()) will get connected
486 // to either of the two signalManyParams(...) overloads
487 QCOMPARE(receiver.called_slots, QList<int>() << 4 << 5 << 6);
488
489 receiver.called_slots.clear();
490 sender.emitSignalManyParams2(i1: 1, i2: 2, i3: 3, string: "string", onoff: true);
491 QCOMPARE(receiver.called_slots, QList<int>() << 7);
492
493 receiver.called_slots.clear();
494 sender.emitSignalLoopBack();
495 QCOMPARE(receiver.called_slots, QList<int>() << 8);
496
497 receiver.called_slots.clear();
498 receiver.emitSignalNoParams();
499 QCOMPARE(receiver.called_slots, QList<int>() << 9);
500
501 receiver.called_slots.clear();
502 receiver.emit_signal_with_underscore();
503 QCOMPARE(receiver.called_slots, QList<int>() << 10);
504}
505
506void tst_QObject::qobject_castTemplate()
507{
508 QScopedPointer<QObject> o;
509 QVERIFY(!::qobject_cast<QObject*>(o.data()));
510
511 o.reset(other: new SenderObject);
512 QVERIFY(::qobject_cast<SenderObject*>(o.data()));
513 QVERIFY(::qobject_cast<QObject*>(o.data()));
514 QVERIFY(!::qobject_cast<ReceiverObject*>(o.data()));
515}
516
517void tst_QObject::findChildren()
518{
519 QObject o;
520 QObject o1(&o);
521 QObject o2(&o);
522 QObject o11(&o1);
523 QObject o12(&o1);
524 QObject o111(&o11);
525 QObject unnamed(&o);
526 QTimer t1(&o);
527 QTimer t121(&o12);
528 QTimer emptyname(&o);
529
530 Q_SET_OBJECT_NAME(o);
531 Q_SET_OBJECT_NAME(o1);
532 Q_SET_OBJECT_NAME(o2);
533 Q_SET_OBJECT_NAME(o11);
534 Q_SET_OBJECT_NAME(o12);
535 Q_SET_OBJECT_NAME(o111);
536 Q_SET_OBJECT_NAME(t1);
537 Q_SET_OBJECT_NAME(t121);
538 emptyname.setObjectName("");
539
540 QObject *op = 0;
541
542 op = o.findChild<QObject*>(aName: "o1");
543 QCOMPARE(op, &o1);
544 op = o.findChild<QObject*>(aName: "o2");
545 QCOMPARE(op, &o2);
546 op = o.findChild<QObject*>(aName: "o11");
547 QCOMPARE(op, &o11);
548 op = o.findChild<QObject*>(aName: "o12");
549 QCOMPARE(op, &o12);
550 op = o.findChild<QObject*>(aName: "o111");
551 QCOMPARE(op, &o111);
552 op = o.findChild<QObject*>(aName: "t1");
553 QCOMPARE(op, static_cast<QObject *>(&t1));
554 op = o.findChild<QObject*>(aName: "t121");
555 QCOMPARE(op, static_cast<QObject *>(&t121));
556 op = o.findChild<QTimer*>(aName: "t1");
557 QCOMPARE(op, static_cast<QObject *>(&t1));
558 op = o.findChild<QTimer*>(aName: "t121");
559 QCOMPARE(op, static_cast<QObject *>(&t121));
560 op = o.findChild<QTimer*>(aName: "o12");
561 QCOMPARE(op, static_cast<QObject *>(0));
562 op = o.findChild<QObject*>(aName: "o");
563 QCOMPARE(op, static_cast<QObject *>(0));
564 op = o.findChild<QObject*>(aName: "harry");
565 QCOMPARE(op, static_cast<QObject *>(0));
566 op = o.findChild<QObject*>(aName: "o1");
567 QCOMPARE(op, &o1);
568
569 QList<QObject*> l;
570 QList<QTimer*> tl;
571
572 l = o.findChildren<QObject*>(aName: "o1");
573 QCOMPARE(l.size(), 1);
574 QCOMPARE(l.at(0), &o1);
575 l = o.findChildren<QObject*>(aName: "o2");
576 QCOMPARE(l.size(), 1);
577 QCOMPARE(l.at(0), &o2);
578 l = o.findChildren<QObject*>(aName: "o11");
579 QCOMPARE(l.size(), 1);
580 QCOMPARE(l.at(0), &o11);
581 l = o.findChildren<QObject*>(aName: "o12");
582 QCOMPARE(l.size(), 1);
583 QCOMPARE(l.at(0), &o12);
584 l = o.findChildren<QObject*>(aName: "o111");
585 QCOMPARE(l.size(), 1);
586 QCOMPARE(l.at(0), &o111);
587 l = o.findChildren<QObject*>(aName: "t1");
588 QCOMPARE(l.size(), 1);
589 QCOMPARE(l.at(0), static_cast<QObject *>(&t1));
590 l = o.findChildren<QObject*>(aName: "t121");
591 QCOMPARE(l.size(), 1);
592 QCOMPARE(l.at(0), static_cast<QObject *>(&t121));
593 tl = o.findChildren<QTimer*>(aName: "t1");
594 QCOMPARE(tl.size(), 1);
595 QCOMPARE(tl.at(0), &t1);
596 tl = o.findChildren<QTimer*>(aName: "t121");
597 QCOMPARE(tl.size(), 1);
598 QCOMPARE(tl.at(0), &t121);
599 l = o.findChildren<QObject*>(aName: "o");
600 QCOMPARE(l.size(), 0);
601 l = o.findChildren<QObject*>(aName: "harry");
602 QCOMPARE(l.size(), 0);
603 tl = o.findChildren<QTimer*>(aName: "o12");
604 QCOMPARE(tl.size(), 0);
605 l = o.findChildren<QObject*>(aName: "o1");
606 QCOMPARE(l.size(), 1);
607 QCOMPARE(l.at(0), &o1);
608
609 l = o.findChildren<QObject*>(re: QRegularExpression("^o.*$"));
610 QCOMPARE(l.size(), 5);
611 QVERIFY(l.contains(&o1));
612 QVERIFY(l.contains(&o2));
613 QVERIFY(l.contains(&o11));
614 QVERIFY(l.contains(&o12));
615 QVERIFY(l.contains(&o111));
616 l = o.findChildren<QObject*>(re: QRegularExpression("t.*"));
617 QCOMPARE(l.size(), 2);
618 QVERIFY(l.contains(&t1));
619 QVERIFY(l.contains(&t121));
620 tl = o.findChildren<QTimer*>(re: QRegularExpression("^.*$"));
621 QCOMPARE(tl.size(), 3);
622 QVERIFY(tl.contains(&t1));
623 QVERIFY(tl.contains(&t121));
624 tl = o.findChildren<QTimer*>(re: QRegularExpression("^o.*$"));
625 QCOMPARE(tl.size(), 0);
626 l = o.findChildren<QObject*>(re: QRegularExpression("^harry$"));
627 QCOMPARE(l.size(), 0);
628
629 l = o.findChildren<QObject*>(re: QRegularExpression("o.*"));
630 QCOMPARE(l.size(), 5);
631 QVERIFY(l.contains(&o1));
632 QVERIFY(l.contains(&o2));
633 QVERIFY(l.contains(&o11));
634 QVERIFY(l.contains(&o12));
635 QVERIFY(l.contains(&o111));
636 l = o.findChildren<QObject*>(re: QRegularExpression("t.*"));
637 QCOMPARE(l.size(), 2);
638 QVERIFY(l.contains(&t1));
639 QVERIFY(l.contains(&t121));
640 tl = o.findChildren<QTimer*>(re: QRegularExpression(".*"));
641 QCOMPARE(tl.size(), 3);
642 QVERIFY(tl.contains(&t1));
643 QVERIFY(tl.contains(&t121));
644 tl = o.findChildren<QTimer*>(re: QRegularExpression("o.*"));
645 QCOMPARE(tl.size(), 0);
646 l = o.findChildren<QObject*>(re: QRegularExpression("harry"));
647 QCOMPARE(l.size(), 0);
648
649 // empty and null string check
650 op = o.findChild<QObject*>();
651 QCOMPARE(op, &o1);
652 op = o.findChild<QObject*>(aName: "");
653 QCOMPARE(op, &unnamed);
654 op = o.findChild<QObject*>(aName: "unnamed");
655 QCOMPARE(op, static_cast<QObject *>(0));
656
657 l = o.findChildren<QObject*>();
658 QCOMPARE(l.size(), 9);
659 l = o.findChildren<QObject*>(aName: "");
660 QCOMPARE(l.size(), 2);
661 l = o.findChildren<QObject*>(aName: "unnamed");
662 QCOMPARE(l.size(), 0);
663
664 tl = o.findChildren<QTimer *>(aName: "t1");
665 QCOMPARE(tl.size(), 1);
666 QCOMPARE(tl.at(0), &t1);
667
668 // Find direct child/children
669
670 op = o.findChild<QObject*>(aName: "o1", options: Qt::FindDirectChildrenOnly);
671 QCOMPARE(op, &o1);
672 op = o.findChild<QObject*>(aName: "o2", options: Qt::FindDirectChildrenOnly);
673 QCOMPARE(op, &o2);
674 op = o.findChild<QObject*>(aName: "o11", options: Qt::FindDirectChildrenOnly);
675 QCOMPARE(op, static_cast<QObject *>(0));
676 op = o.findChild<QObject*>(aName: "o12", options: Qt::FindDirectChildrenOnly);
677 QCOMPARE(op, static_cast<QObject *>(0));
678 op = o.findChild<QObject*>(aName: "o111", options: Qt::FindDirectChildrenOnly);
679 QCOMPARE(op, static_cast<QObject *>(0));
680 op = o.findChild<QObject*>(aName: "t1", options: Qt::FindDirectChildrenOnly);
681 QCOMPARE(op, static_cast<QObject *>(&t1));
682 op = o.findChild<QObject*>(aName: "t121", options: Qt::FindDirectChildrenOnly);
683 QCOMPARE(op, static_cast<QObject *>(0));
684 op = o.findChild<QTimer*>(aName: "t1", options: Qt::FindDirectChildrenOnly);
685 QCOMPARE(op, static_cast<QObject *>(&t1));
686 op = o.findChild<QTimer*>(aName: "t121", options: Qt::FindDirectChildrenOnly);
687 QCOMPARE(op, static_cast<QObject *>(0));
688 op = o.findChild<QTimer*>(aName: "o12", options: Qt::FindDirectChildrenOnly);
689 QCOMPARE(op, static_cast<QObject *>(0));
690 op = o.findChild<QObject*>(aName: "o", options: Qt::FindDirectChildrenOnly);
691 QCOMPARE(op, static_cast<QObject *>(0));
692 op = o.findChild<QObject*>(aName: "harry", options: Qt::FindDirectChildrenOnly);
693 QCOMPARE(op, static_cast<QObject *>(0));
694 op = o.findChild<QObject*>(aName: "o1", options: Qt::FindDirectChildrenOnly);
695 QCOMPARE(op, &o1);
696
697 l = o.findChildren<QObject*>(aName: "o1", options: Qt::FindDirectChildrenOnly);
698 QCOMPARE(l.size(), 1);
699 QCOMPARE(l.at(0), &o1);
700 l = o.findChildren<QObject*>(aName: "o2", options: Qt::FindDirectChildrenOnly);
701 QCOMPARE(l.size(), 1);
702 QCOMPARE(l.at(0), &o2);
703 l = o.findChildren<QObject*>(aName: "o11", options: Qt::FindDirectChildrenOnly);
704 QCOMPARE(l.size(), 0);
705 l = o.findChildren<QObject*>(aName: "o12", options: Qt::FindDirectChildrenOnly);
706 QCOMPARE(l.size(), 0);
707 l = o.findChildren<QObject*>(aName: "o111", options: Qt::FindDirectChildrenOnly);
708 QCOMPARE(l.size(), 0);
709 l = o.findChildren<QObject*>(aName: "t1", options: Qt::FindDirectChildrenOnly);
710 QCOMPARE(l.size(), 1);
711 QCOMPARE(l.at(0), static_cast<QObject *>(&t1));
712 l = o.findChildren<QObject*>(aName: "t121", options: Qt::FindDirectChildrenOnly);
713 QCOMPARE(l.size(), 0);
714 tl = o.findChildren<QTimer*>(aName: "t1", options: Qt::FindDirectChildrenOnly);
715 QCOMPARE(tl.size(), 1);
716 QCOMPARE(tl.at(0), &t1);
717 tl = o.findChildren<QTimer*>(aName: "t121", options: Qt::FindDirectChildrenOnly);
718 QCOMPARE(tl.size(), 0);
719 l = o.findChildren<QObject*>(aName: "o", options: Qt::FindDirectChildrenOnly);
720 QCOMPARE(l.size(), 0);
721 l = o.findChildren<QObject*>(aName: "harry", options: Qt::FindDirectChildrenOnly);
722 QCOMPARE(l.size(), 0);
723 tl = o.findChildren<QTimer*>(aName: "o12", options: Qt::FindDirectChildrenOnly);
724 QCOMPARE(tl.size(), 0);
725 l = o.findChildren<QObject*>(aName: "o1", options: Qt::FindDirectChildrenOnly);
726 QCOMPARE(l.size(), 1);
727 QCOMPARE(l.at(0), &o1);
728
729 l = o.findChildren<QObject*>(re: QRegularExpression("^o.*$"), options: Qt::FindDirectChildrenOnly);
730 QCOMPARE(l.size(), 2);
731 QVERIFY(l.contains(&o1));
732 QVERIFY(l.contains(&o2));
733 l = o.findChildren<QObject*>(re: QRegularExpression("^t.*$"), options: Qt::FindDirectChildrenOnly);
734 QCOMPARE(l.size(), 1);
735 QVERIFY(l.contains(&t1));
736 tl = o.findChildren<QTimer*>(re: QRegularExpression("^.*$"), options: Qt::FindDirectChildrenOnly);
737 QCOMPARE(tl.size(), 2);
738 QVERIFY(tl.contains(&t1));
739 tl = o.findChildren<QTimer*>(re: QRegularExpression("^o.*$"), options: Qt::FindDirectChildrenOnly);
740 QCOMPARE(tl.size(), 0);
741 l = o.findChildren<QObject*>(re: QRegularExpression("^harry$"), options: Qt::FindDirectChildrenOnly);
742 QCOMPARE(l.size(), 0);
743
744 // empty and null string check
745 op = o.findChild<QObject*>(aName: QString(), options: Qt::FindDirectChildrenOnly);
746 QCOMPARE(op, &o1);
747 op = o.findChild<QObject*>(aName: "", options: Qt::FindDirectChildrenOnly);
748 QCOMPARE(op, &unnamed);
749 op = o.findChild<QObject*>(aName: "unnamed", options: Qt::FindDirectChildrenOnly);
750 QCOMPARE(op, static_cast<QObject *>(0));
751
752 l = o.findChildren<QObject*>(aName: QString(), options: Qt::FindDirectChildrenOnly);
753 QCOMPARE(l.size(), 5);
754 l = o.findChildren<QObject*>(aName: "", options: Qt::FindDirectChildrenOnly);
755 QCOMPARE(l.size(), 2);
756 l = o.findChildren<QObject*>(aName: "unnamed", options: Qt::FindDirectChildrenOnly);
757 QCOMPARE(l.size(), 0);
758
759 tl = o.findChildren<QTimer *>(aName: "t1", options: Qt::FindDirectChildrenOnly);
760 QCOMPARE(tl.size(), 1);
761 QCOMPARE(tl.at(0), &t1);
762}
763
764
765class NotifyObject : public SenderObject, public ReceiverObject
766{
767public:
768 NotifyObject() : SenderObject(), ReceiverObject()
769 {}
770
771 QList<QMetaMethod> connectedSignals;
772 QList<QMetaMethod> disconnectedSignals;
773 void clearNotifications()
774 {
775 connectedSignals.clear();
776 disconnectedSignals.clear();
777 }
778protected:
779 void connectNotify(const QMetaMethod &signal)
780 { connectedSignals.append(t: signal); }
781 void disconnectNotify(const QMetaMethod &signal)
782 { disconnectedSignals.append(t: signal); }
783};
784
785void tst_QObject::connectDisconnectNotify_data()
786{
787 QTest::addColumn<QString>(name: "a_signal");
788 QTest::addColumn<QString>(name: "a_slot");
789
790 QTest::newRow(dataTag: "combo1") << SIGNAL( signal1() ) << SLOT( slot1() );
791 QTest::newRow(dataTag: "combo2") << SIGNAL( signal2(void) ) << SLOT( slot2( ) );
792 QTest::newRow(dataTag: "combo3") << SIGNAL( signal3( ) ) << SLOT( slot3(void) );
793 QTest::newRow(dataTag: "combo4") << SIGNAL( signal4( void ) )<< SLOT( slot4( void ) );
794 QTest::newRow(dataTag: "combo5") << SIGNAL( signal6( void ) ) << SLOT( slot4() );
795 QTest::newRow(dataTag: "combo6") << SIGNAL( signal6() ) << SLOT( slot4() );
796 QTest::newRow(dataTag: "combo7") << SIGNAL( signal7( int , const QString & ) ) << SLOT( slot4() );
797}
798
799void tst_QObject::connectDisconnectNotify()
800{
801 NotifyObject s;
802 NotifyObject r;
803
804 QFETCH(QString, a_signal);
805 QFETCH(QString, a_slot);
806
807 // Obtaining meta methods
808 int signalIndx = ((SenderObject &)s).metaObject()->indexOfSignal(
809 signal: QMetaObject::normalizedSignature(method: a_signal.toLatin1().constData()+1).constData());
810 int methodIndx = ((ReceiverObject &)r).metaObject()->indexOfMethod(
811 method: QMetaObject::normalizedSignature(method: a_slot.toLatin1().constData()+1).constData());
812 QMetaMethod signal = ((SenderObject &)s).metaObject()->method(index: signalIndx);
813 QMetaMethod method = ((ReceiverObject &)r).metaObject()->method(index: methodIndx);
814 QVERIFY(signal.isValid());
815 QVERIFY(method.isValid());
816
817 // Test connectNotify
818 QVERIFY(QObject::connect((SenderObject *)&s, a_signal.toLatin1(),
819 (ReceiverObject *)&r, a_slot.toLatin1()));
820 QCOMPARE(s.connectedSignals.size(), 1);
821 QCOMPARE(s.connectedSignals.at(0), signal);
822 QVERIFY(s.disconnectedSignals.isEmpty());
823
824 // Test disconnectNotify
825 QVERIFY(QObject::disconnect((SenderObject *)&s, a_signal.toLatin1(),
826 (ReceiverObject *)&r, a_slot.toLatin1()));
827 QCOMPARE(s.disconnectedSignals.size(), 1);
828 QCOMPARE(s.disconnectedSignals.at(0), signal);
829 QCOMPARE(s.connectedSignals.size(), 1);
830
831 // Reconnect
832 s.clearNotifications();
833 QVERIFY(QObject::connect((SenderObject *)&s, a_signal.toLatin1(),
834 (ReceiverObject *)&r, a_slot.toLatin1()));
835 QCOMPARE(s.connectedSignals.size(), 1);
836 QCOMPARE(s.connectedSignals.at(0), signal);
837 QVERIFY(s.disconnectedSignals.isEmpty());
838
839 // Test disconnectNotify for a complete disconnect
840 QVERIFY(((SenderObject *)&s)->disconnect((ReceiverObject *)&r));
841 QCOMPARE(s.disconnectedSignals.size(), 1);
842 QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod());
843 QCOMPARE(s.connectedSignals.size(), 1);
844
845 // Test connectNotify when connecting by QMetaMethod
846 s.clearNotifications();
847 QVERIFY(QObject::connect((SenderObject *)&s, signal, (ReceiverObject *)&r, method));
848 QCOMPARE(s.connectedSignals.size(), 1);
849 QCOMPARE(s.connectedSignals.at(0), signal);
850 QVERIFY(s.disconnectedSignals.isEmpty());
851
852 // Test disconnectNotify when disconnecting by QMetaMethod
853 QVERIFY(QObject::disconnect((SenderObject *)&s, signal, (ReceiverObject *)&r, method));
854 QCOMPARE(s.disconnectedSignals.size(), 1);
855 QCOMPARE(s.disconnectedSignals.at(0), signal);
856 QCOMPARE(s.connectedSignals.size(), 1);
857
858 // Reconnect
859 s.clearNotifications();
860 QVERIFY(QObject::connect((SenderObject *)&s, a_signal.toLatin1(),
861 (ReceiverObject *)&r, a_slot.toLatin1()));
862
863 // Test disconnectNotify for a complete disconnect by QMetaMethod
864 QVERIFY(QObject::disconnect((SenderObject *)&s, QMetaMethod(), 0, QMetaMethod()));
865 QCOMPARE(s.disconnectedSignals.size(), 1);
866 QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod());
867 QCOMPARE(s.connectedSignals.size(), 1);
868
869 // Test connectNotify when connecting by index
870 s.clearNotifications();
871 QVERIFY(QMetaObject::connect((SenderObject *)&s, signalIndx, (ReceiverObject *)&r, methodIndx));
872 QCOMPARE(s.connectedSignals.size(), 1);
873 QCOMPARE(s.connectedSignals.at(0), signal);
874 QVERIFY(s.disconnectedSignals.isEmpty());
875
876 // Test disconnectNotify when disconnecting by index
877 QVERIFY(QMetaObject::disconnect((SenderObject *)&s, signalIndx,
878 (ReceiverObject *)&r, methodIndx));
879 QCOMPARE(s.disconnectedSignals.size(), 1);
880 QCOMPARE(s.disconnectedSignals.at(0), signal);
881 QCOMPARE(s.connectedSignals.size(), 1);
882}
883
884static void connectDisconnectNotifyTestSlot() {}
885
886void tst_QObject::connectDisconnectNotifyPMF()
887{
888 NotifyObject s;
889 NotifyObject r;
890
891 QMetaMethod signal = QMetaMethod::fromSignal(signal: &SenderObject::signal1);
892
893 // Test connectNotify
894 QVERIFY(QObject::connect((SenderObject *)&s, &SenderObject::signal1,
895 (ReceiverObject *)&r, &ReceiverObject::slot1));
896 QCOMPARE(s.connectedSignals.size(), 1);
897 QCOMPARE(s.connectedSignals.at(0), signal);
898 QVERIFY(s.disconnectedSignals.isEmpty());
899
900 // Test disconnectNotify
901 QVERIFY(QObject::disconnect((SenderObject *)&s, &SenderObject::signal1,
902 (ReceiverObject *)&r, &ReceiverObject::slot1));
903 QCOMPARE(s.disconnectedSignals.size(), 1);
904 QCOMPARE(s.disconnectedSignals.at(0), signal);
905 QCOMPARE(s.connectedSignals.size(), 1);
906
907 // Reconnect
908 s.clearNotifications();
909 QVERIFY(QObject::connect((SenderObject *)&s, &SenderObject::signal1,
910 (ReceiverObject *)&r, &ReceiverObject::slot1));
911 QCOMPARE(s.connectedSignals.size(), 1);
912 QCOMPARE(s.connectedSignals.at(0), signal);
913 QVERIFY(s.disconnectedSignals.isEmpty());
914
915 // Test disconnectNotify with wildcard slot
916 QVERIFY(QObject::disconnect((SenderObject *)&s, &SenderObject::signal1,
917 (ReceiverObject *)&r, 0));
918 QCOMPARE(s.disconnectedSignals.size(), 1);
919 QCOMPARE(s.disconnectedSignals.at(0), signal);
920 QCOMPARE(s.connectedSignals.size(), 1);
921
922 // Reconnect
923 s.clearNotifications();
924 QMetaObject::Connection conn = connect(sender: (SenderObject *)&s, signal: &SenderObject::signal1,
925 receiver: (ReceiverObject *)&r, slot: &ReceiverObject::slot1);
926
927 QVERIFY(conn);
928
929 // Test disconnectNotify when disconnecting by QMetaObject::Connection
930 QVERIFY(QObject::disconnect(conn));
931 QVERIFY(!s.disconnectedSignals.isEmpty());
932
933 // Test connectNotify when connecting by function pointer
934 s.clearNotifications();
935 QVERIFY(QObject::connect((SenderObject *)&s, &SenderObject::signal1,
936 connectDisconnectNotifyTestSlot));
937 QCOMPARE(s.connectedSignals.size(), 1);
938 QCOMPARE(s.connectedSignals.at(0), signal);
939 QVERIFY(s.disconnectedSignals.isEmpty());
940}
941
942void tst_QObject::disconnectNotify_receiverDestroyed()
943{
944 NotifyObject s;
945
946 {
947 NotifyObject r;
948 QVERIFY(QObject::connect((SenderObject *)&s, SIGNAL(signal1()),
949 (ReceiverObject *)&r, SLOT(slot1())));
950 }
951 QCOMPARE(s.disconnectedSignals.count(), 1);
952 QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod::fromSignal(&SenderObject::signal1));
953
954 s.disconnectedSignals.clear();
955
956 {
957 NotifyObject r;
958 QVERIFY(QObject::connect((SenderObject *)&s, SIGNAL(signal3()),
959 (ReceiverObject *)&r, SLOT(slot3())));
960 }
961
962 QCOMPARE(s.disconnectedSignals.count(), 1);
963 QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod::fromSignal(&SenderObject::signal3));
964
965 s.disconnectedSignals.clear();
966
967 {
968 NotifyObject r;
969 QVERIFY(QObject::connect((SenderObject *)&s, SIGNAL(destroyed()), (ReceiverObject *)&r, SLOT(slot3())));
970 }
971
972 QCOMPARE(s.disconnectedSignals.count(), 1);
973 QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod::fromSignal(&QObject::destroyed));
974}
975
976void tst_QObject::disconnectNotify_metaObjConnection()
977{
978 NotifyObject s;
979 {
980 NotifyObject r;
981
982 QMetaObject::Connection c = QObject::connect(sender: (SenderObject *)&s, SIGNAL(signal1()),
983 receiver: (ReceiverObject *)&r, SLOT(slot1()));
984 QVERIFY(c);
985 QVERIFY(QObject::disconnect(c));
986
987 QCOMPARE(s.disconnectedSignals.count(), 1);
988 QCOMPARE(s.disconnectedSignals.at(0), QMetaMethod::fromSignal(&SenderObject::signal1));
989
990 QCOMPARE(s.disconnectedSignals.count(), 1);
991 }
992}
993
994class ConnectByNameNotifySenderObject : public QObject
995{
996 Q_OBJECT
997public:
998 QList<QMetaMethod> connectedSignals;
999 QList<QMetaMethod> disconnectedSignals;
1000 void clearNotifications()
1001 {
1002 connectedSignals.clear();
1003 disconnectedSignals.clear();
1004 }
1005protected:
1006 void connectNotify(const QMetaMethod &signal)
1007 { connectedSignals.append(t: signal); }
1008 void disconnectNotify(const QMetaMethod &signal)
1009 { disconnectedSignals.append(t: signal); }
1010Q_SIGNALS:
1011 void signal1();
1012};
1013
1014class ConnectByNameNotifyReceiverObject : public QObject
1015{
1016 Q_OBJECT
1017 void createNotifyChild(const char *name)
1018 {
1019 QObject *o = new ConnectByNameNotifySenderObject;
1020 o->setParent(this);
1021 o->setObjectName(QString::fromLatin1(str: name));
1022 }
1023public:
1024 ConnectByNameNotifyReceiverObject()
1025 {
1026 createNotifyChild(name: "foo");
1027 createNotifyChild(name: "bar");
1028 createNotifyChild(name: "baz");
1029 };
1030
1031public Q_SLOTS:
1032 void on_foo_signal1() {}
1033 void on_bar_signal1() {}
1034 void on_baz_signal1() {}
1035};
1036
1037void tst_QObject::connectNotify_connectSlotsByName()
1038{
1039 ConnectByNameNotifyReceiverObject testObject;
1040 const QList<ConnectByNameNotifySenderObject *> senders =
1041 testObject.findChildren<ConnectByNameNotifySenderObject *>();
1042 for (ConnectByNameNotifySenderObject *o : senders) {
1043 QVERIFY(o->connectedSignals.isEmpty());
1044 QVERIFY(o->disconnectedSignals.isEmpty());
1045 }
1046
1047 QMetaObject::connectSlotsByName(o: &testObject);
1048
1049 for (ConnectByNameNotifySenderObject *o : senders) {
1050 QCOMPARE(o->connectedSignals.size(), 1);
1051 QCOMPARE(o->connectedSignals.at(0), QMetaMethod::fromSignal(&ConnectByNameNotifySenderObject::signal1));
1052 QVERIFY(o->disconnectedSignals.isEmpty());
1053 }
1054}
1055
1056class ConnectDisconnectNotifyShadowObject
1057 : public ConnectByNameNotifySenderObject
1058{
1059 Q_OBJECT
1060public Q_SLOTS:
1061 void slot1() {}
1062Q_SIGNALS:
1063 void signal1();
1064};
1065
1066void tst_QObject::connectDisconnectNotify_shadowing()
1067{
1068 ConnectDisconnectNotifyShadowObject s;
1069 // Obtain QMetaMethods
1070 QMetaMethod shadowedSignal1 = QMetaMethod::fromSignal(signal: &ConnectByNameNotifySenderObject::signal1);
1071 QMetaMethod redefinedSignal1 = QMetaMethod::fromSignal(signal: &ConnectDisconnectNotifyShadowObject::signal1);
1072 QVERIFY(shadowedSignal1 != redefinedSignal1);
1073 int slot1Index = s.metaObject()->indexOfSlot(slot: "slot1()");
1074 QVERIFY(slot1Index != -1);
1075 QMetaMethod slot1 = s.metaObject()->method(index: slot1Index);
1076
1077 // Test connectNotify
1078#ifndef QT_NO_DEBUG
1079 const char *warning = "QMetaObject::indexOfSignal: signal signal1() from "
1080 "ConnectByNameNotifySenderObject redefined in "
1081 "ConnectDisconnectNotifyShadowObject";
1082 QTest::ignoreMessage(type: QtWarningMsg, message: warning);
1083#endif
1084 QVERIFY(QObject::connect(&s, SIGNAL(signal1()), &s, SLOT(slot1())));
1085 QCOMPARE(s.connectedSignals.size(), 1);
1086 QCOMPARE(s.connectedSignals.at(0), redefinedSignal1);
1087 QVERIFY(s.disconnectedSignals.isEmpty());
1088
1089 // Test disconnectNotify
1090#ifndef QT_NO_DEBUG
1091 QTest::ignoreMessage(type: QtWarningMsg, message: warning);
1092#endif
1093 QVERIFY(QObject::disconnect(&s, SIGNAL(signal1()), &s, SLOT(slot1())));
1094 QCOMPARE(s.disconnectedSignals.size(), 1);
1095 QCOMPARE(s.disconnectedSignals.at(0), redefinedSignal1);
1096 QCOMPARE(s.connectedSignals.size(), 1);
1097
1098 // Test connectNotify when connecting by shadowed QMetaMethod
1099 s.clearNotifications();
1100 QVERIFY(QObject::connect(&s, shadowedSignal1, &s, slot1));
1101 QCOMPARE(s.connectedSignals.size(), 1);
1102 QCOMPARE(s.connectedSignals.at(0), shadowedSignal1);
1103 QVERIFY(s.disconnectedSignals.isEmpty());
1104
1105 // Test disconnectNotify when disconnecting by shadowed QMetaMethod
1106 QVERIFY(QObject::disconnect(&s, shadowedSignal1, &s, slot1));
1107 QCOMPARE(s.disconnectedSignals.size(), 1);
1108 QCOMPARE(s.disconnectedSignals.at(0), shadowedSignal1);
1109 QCOMPARE(s.connectedSignals.size(), 1);
1110
1111 // Test connectNotify when connecting by redefined QMetaMethod
1112 s.clearNotifications();
1113 QVERIFY(QObject::connect(&s, redefinedSignal1, &s, slot1));
1114 QCOMPARE(s.connectedSignals.size(), 1);
1115 QCOMPARE(s.connectedSignals.at(0), redefinedSignal1);
1116 QVERIFY(s.disconnectedSignals.isEmpty());
1117
1118 // Test disconnectNotify when disconnecting by redefined QMetaMethod
1119 QVERIFY(QObject::disconnect(&s, redefinedSignal1, &s, slot1));
1120 QCOMPARE(s.disconnectedSignals.size(), 1);
1121 QCOMPARE(s.disconnectedSignals.at(0), redefinedSignal1);
1122 QCOMPARE(s.connectedSignals.size(), 1);
1123}
1124
1125class SequenceObject : public ReceiverObject
1126{
1127 Q_OBJECT
1128
1129public:
1130 QObject *next;
1131 SequenceObject() : next(0) { }
1132
1133public slots:
1134 void slot1_disconnectThis()
1135 {
1136 slot1();
1137 disconnect(sender: sender(), SIGNAL(signal1()), receiver: this, SLOT(slot1_disconnectThis()));
1138 }
1139
1140 void slot2_reconnectThis()
1141 {
1142 slot2();
1143
1144 const QObject *s = sender();
1145 disconnect(sender: s, SIGNAL(signal1()), receiver: this, SLOT(slot2_reconnectThis()));
1146 connect(sender: s, SIGNAL(signal1()), receiver: this, SLOT(slot2_reconnectThis()));
1147 }
1148
1149 void slot1_disconnectNext()
1150 {
1151 slot1();
1152 disconnect(sender: sender(), SIGNAL(signal1()), receiver: next, SLOT(slot1()));
1153 }
1154
1155 void slot2_reconnectNext()
1156 {
1157 slot2();
1158
1159 // modify the connection list in 'this'
1160 disconnect(sender: sender(), SIGNAL(signal1()), receiver: next, SLOT(slot2()));
1161 connect(sender: sender(), SIGNAL(signal1()), receiver: next, SLOT(slot2()));
1162
1163 // modify the sender list in 'this'
1164 connect(sender: next, SIGNAL(destroyed()), receiver: this, SLOT(deleteLater()));
1165 connect(sender: QCoreApplication::instance(), SIGNAL(aboutToQuit()), receiver: this, SLOT(deleteLater()));
1166 disconnect(sender: next, SIGNAL(destroyed()), receiver: this, SLOT(deleteLater()));
1167 disconnect(sender: QCoreApplication::instance(), SIGNAL(aboutToQuit()), receiver: this, SLOT(deleteLater()));
1168 }
1169
1170 void slot1_deleteNext()
1171 {
1172 slot1();
1173 delete next;
1174 }
1175
1176 void slot2_deleteSender()
1177 {
1178 slot2();
1179 delete sender();
1180 }
1181};
1182
1183void tst_QObject::emitInDefinedOrder()
1184{
1185 SenderObject sender;
1186 ReceiverObject receiver1, receiver2, receiver3, receiver4;
1187
1188 connect(sender: &sender, SIGNAL(signal1()), receiver: &receiver1, SLOT(slot1()));
1189 connect(sender: &sender, SIGNAL(signal1()), receiver: &receiver2, SLOT(slot1()));
1190 connect(sender: &sender, SIGNAL(signal1()), receiver: &receiver3, SLOT(slot1()));
1191 connect(sender: &sender, SIGNAL(signal1()), receiver: &receiver4, SLOT(slot1()));
1192 connect(sender: &sender, SIGNAL(signal1()), receiver: &receiver1, SLOT(slot2()));
1193 connect(sender: &sender, SIGNAL(signal1()), receiver: &receiver2, SLOT(slot2()));
1194 connect(sender: &sender, SIGNAL(signal1()), receiver: &receiver3, SLOT(slot2()));
1195 connect(sender: &sender, SIGNAL(signal1()), receiver: &receiver4, SLOT(slot2()));
1196
1197 int sequence;
1198 ReceiverObject::sequence = sequence = 0;
1199 sender.emitSignal1();
1200 QCOMPARE(receiver1.sequence_slot1, ++sequence);
1201 QCOMPARE(receiver2.sequence_slot1, ++sequence);
1202 QCOMPARE(receiver3.sequence_slot1, ++sequence);
1203 QCOMPARE(receiver4.sequence_slot1, ++sequence);
1204 QCOMPARE(receiver1.sequence_slot2, ++sequence);
1205 QCOMPARE(receiver2.sequence_slot2, ++sequence);
1206 QCOMPARE(receiver3.sequence_slot2, ++sequence);
1207 QCOMPARE(receiver4.sequence_slot2, ++sequence);
1208
1209 QObject::disconnect(sender: &sender, SIGNAL(signal1()), receiver: &receiver2, SLOT(slot1()));
1210 connect(sender: &sender, SIGNAL(signal1()), receiver: &receiver2, SLOT(slot1()));
1211
1212 ReceiverObject::sequence = sequence = 0;
1213 sender.emitSignal1();
1214 QCOMPARE(receiver1.sequence_slot1, ++sequence);
1215 QCOMPARE(receiver3.sequence_slot1, ++sequence);
1216 QCOMPARE(receiver4.sequence_slot1, ++sequence);
1217 QCOMPARE(receiver1.sequence_slot2, ++sequence);
1218 QCOMPARE(receiver2.sequence_slot2, ++sequence);
1219 QCOMPARE(receiver3.sequence_slot2, ++sequence);
1220 QCOMPARE(receiver4.sequence_slot2, ++sequence);
1221 QCOMPARE(receiver2.sequence_slot1, ++sequence);
1222
1223 QObject::disconnect(sender: &sender, SIGNAL(signal1()), receiver: &receiver1, SLOT(slot1()));
1224 connect(sender: &sender, SIGNAL(signal1()), receiver: &receiver1, SLOT(slot1()));
1225
1226 ReceiverObject::sequence = sequence = 0;
1227 sender.emitSignal1();
1228 QCOMPARE(receiver3.sequence_slot1, ++sequence);
1229 QCOMPARE(receiver4.sequence_slot1, ++sequence);
1230 QCOMPARE(receiver1.sequence_slot2, ++sequence);
1231 QCOMPARE(receiver2.sequence_slot2, ++sequence);
1232 QCOMPARE(receiver3.sequence_slot2, ++sequence);
1233 QCOMPARE(receiver4.sequence_slot2, ++sequence);
1234 QCOMPARE(receiver2.sequence_slot1, ++sequence);
1235 QCOMPARE(receiver1.sequence_slot1, ++sequence);
1236
1237 // ensure emission order even if the connections change during emission
1238 SenderObject *sender2 = new SenderObject;
1239 SequenceObject seq1, seq2, *seq3 = new SequenceObject, seq4;
1240 seq1.next = &seq2;
1241 seq2.next = seq3;
1242 seq3->next = &seq4;
1243
1244 // try 1
1245 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq1, SLOT(slot1_disconnectThis()));
1246 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq2, SLOT(slot1_disconnectNext()));
1247 connect(sender: sender2, SIGNAL(signal1()), receiver: seq3, SLOT(slot1()));
1248 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq4, SLOT(slot1()));
1249 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq1, SLOT(slot2_reconnectThis()));
1250 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq2, SLOT(slot2_reconnectNext()));
1251 connect(sender: sender2, SIGNAL(signal1()), receiver: seq3, SLOT(slot2()));
1252 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq4, SLOT(slot2()));
1253
1254 SequenceObject::sequence = sequence = 0;
1255 sender2->emitSignal1();
1256 QVERIFY(seq1.called(1));
1257 QVERIFY(seq2.called(1));
1258 QVERIFY(!seq3->called(1));
1259 QVERIFY(seq4.called(1));
1260 QVERIFY(seq1.called(2));
1261 QVERIFY(seq2.called(2));
1262 QVERIFY(!seq3->called(2));
1263 QVERIFY(seq4.called(2));
1264 QCOMPARE(seq1.sequence_slot1, ++sequence);
1265 QCOMPARE(seq2.sequence_slot1, ++sequence);
1266 QCOMPARE(seq4.sequence_slot1, ++sequence);
1267 QCOMPARE(seq1.sequence_slot2, ++sequence);
1268 QCOMPARE(seq2.sequence_slot2, ++sequence);
1269 QCOMPARE(seq4.sequence_slot2, ++sequence);
1270
1271 QObject::disconnect(sender: sender2, signal: 0, receiver: &seq1, member: 0);
1272 QObject::disconnect(sender: sender2, signal: 0, receiver: &seq2, member: 0);
1273 QObject::disconnect(sender: sender2, signal: 0, receiver: seq3, member: 0);
1274 QObject::disconnect(sender: sender2, signal: 0, receiver: &seq4, member: 0);
1275 seq1.reset();
1276 seq2.reset();
1277 seq3->reset();
1278 seq4.reset();
1279
1280 // try 2
1281 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq1, SLOT(slot2_reconnectThis()));
1282 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq2, SLOT(slot2_reconnectNext()));
1283 connect(sender: sender2, SIGNAL(signal1()), receiver: seq3, SLOT(slot2()));
1284 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq4, SLOT(slot2()));
1285 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq1, SLOT(slot1_disconnectThis()));
1286 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq2, SLOT(slot1_disconnectNext()));
1287 connect(sender: sender2, SIGNAL(signal1()), receiver: seq3, SLOT(slot1()));
1288 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq4, SLOT(slot1()));
1289
1290 SequenceObject::sequence = sequence = 0;
1291 sender2->emitSignal1();
1292 QVERIFY(seq1.called(2));
1293 QVERIFY(seq2.called(2));
1294 QVERIFY(!seq3->called(2));
1295 QVERIFY(seq4.called(2));
1296 QVERIFY(seq1.called(1));
1297 QVERIFY(seq2.called(1));
1298 QVERIFY(!seq3->called(1));
1299 QVERIFY(seq4.called(1));
1300 QCOMPARE(seq1.sequence_slot2, ++sequence);
1301 QCOMPARE(seq2.sequence_slot2, ++sequence);
1302 QCOMPARE(seq4.sequence_slot2, ++sequence);
1303 QCOMPARE(seq1.sequence_slot1, ++sequence);
1304 QCOMPARE(seq2.sequence_slot1, ++sequence);
1305 QCOMPARE(seq4.sequence_slot1, ++sequence);
1306
1307 QObject::disconnect(sender: sender2, signal: 0, receiver: &seq1, member: 0);
1308 QObject::disconnect(sender: sender2, signal: 0, receiver: &seq2, member: 0);
1309 QObject::disconnect(sender: sender2, signal: 0, receiver: seq3, member: 0);
1310 QObject::disconnect(sender: sender2, signal: 0, receiver: &seq4, member: 0);
1311 seq1.reset();
1312 seq2.reset();
1313 seq3->reset();
1314 seq4.reset();
1315
1316 // try 3
1317 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq1, SLOT(slot1()));
1318 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq2, SLOT(slot1_disconnectNext()));
1319 connect(sender: sender2, SIGNAL(signal1()), receiver: seq3, SLOT(slot1()));
1320 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq4, SLOT(slot1()));
1321 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq1, SLOT(slot2()));
1322 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq2, SLOT(slot2_reconnectNext()));
1323 connect(sender: sender2, SIGNAL(signal1()), receiver: seq3, SLOT(slot2()));
1324 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq4, SLOT(slot2()));
1325
1326 SequenceObject::sequence = sequence = 0;
1327 sender2->emitSignal1();
1328 QVERIFY(seq1.called(1));
1329 QVERIFY(seq2.called(1));
1330 QVERIFY(!seq3->called(1));
1331 QVERIFY(seq4.called(1));
1332 QVERIFY(seq1.called(2));
1333 QVERIFY(seq2.called(2));
1334 QVERIFY(!seq3->called(2));
1335 QVERIFY(seq4.called(2));
1336 QCOMPARE(seq1.sequence_slot1, ++sequence);
1337 QCOMPARE(seq2.sequence_slot1, ++sequence);
1338 QCOMPARE(seq4.sequence_slot1, ++sequence);
1339 QCOMPARE(seq1.sequence_slot2, ++sequence);
1340 QCOMPARE(seq2.sequence_slot2, ++sequence);
1341 QCOMPARE(seq4.sequence_slot2, ++sequence);
1342
1343 // ensure emission order even if objects are destroyed during emission
1344 QObject::disconnect(sender: sender2, signal: 0, receiver: &seq1, member: 0);
1345 QObject::disconnect(sender: sender2, signal: 0, receiver: &seq2, member: 0);
1346 QObject::disconnect(sender: sender2, signal: 0, receiver: seq3, member: 0);
1347 QObject::disconnect(sender: sender2, signal: 0, receiver: &seq4, member: 0);
1348 seq1.reset();
1349 seq2.reset();
1350 seq3->reset();
1351 seq4.reset();
1352
1353 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq1, SLOT(slot1()));
1354 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq2, SLOT(slot1_deleteNext()));
1355 connect(sender: sender2, SIGNAL(signal1()), receiver: seq3, SLOT(slot1()));
1356 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq4, SLOT(slot1()));
1357 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq1, SLOT(slot2()));
1358 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq2, SLOT(slot2_deleteSender()));
1359 connect(sender: sender2, SIGNAL(signal1()), receiver: seq3, SLOT(slot2()));
1360 connect(sender: sender2, SIGNAL(signal1()), receiver: &seq4, SLOT(slot2()));
1361
1362 QPointer<SenderObject> psender = sender2;
1363 QPointer<SequenceObject> pseq3 = seq3;
1364
1365 SequenceObject::sequence = sequence = 0;
1366 sender2->emitSignal1();
1367 QCOMPARE(static_cast<QObject *>(psender), static_cast<QObject *>(0));
1368 QCOMPARE(static_cast<QObject *>(pseq3), static_cast<QObject *>(0));
1369 QVERIFY(seq1.called(1));
1370 QVERIFY(seq2.called(1));
1371 QVERIFY(seq4.called(1));
1372 QVERIFY(seq1.called(2));
1373 QVERIFY(seq2.called(2));
1374 QVERIFY(!seq4.called(2));
1375 QCOMPARE(seq1.sequence_slot1, ++sequence);
1376 QCOMPARE(seq2.sequence_slot1, ++sequence);
1377 QCOMPARE(seq4.sequence_slot1, ++sequence);
1378 QCOMPARE(seq1.sequence_slot2, ++sequence);
1379 QCOMPARE(seq2.sequence_slot2, ++sequence);
1380
1381 QPointer<SenderObject> psender3 = new SenderObject;
1382 connect(sender: psender3, SIGNAL(signal1()), receiver: psender3, SIGNAL(signal2()));
1383 connect(sender: psender3, SIGNAL(signal2()), receiver: &seq1, SLOT(slot2_deleteSender()));
1384 psender3->emitSignal1();
1385 QVERIFY(!psender3);
1386}
1387
1388static int instanceCount = 0;
1389
1390struct CheckInstanceCount
1391{
1392 const int saved;
1393 CheckInstanceCount() : saved(instanceCount) {}
1394 ~CheckInstanceCount() { QCOMPARE(saved, instanceCount); }
1395};
1396
1397
1398struct CustomType
1399{
1400 CustomType(int l1 = 0, int l2 = 0, int l3 = 0): i1(l1), i2(l2), i3(l3)
1401 { ++instanceCount; playWithObjects(); }
1402 CustomType(const CustomType &other): i1(other.i1), i2(other.i2), i3(other.i3)
1403 { ++instanceCount; playWithObjects(); }
1404 ~CustomType() { --instanceCount; playWithObjects(); }
1405 CustomType &operator=(const CustomType &) = default;
1406
1407 int i1, i2, i3;
1408 int value() { return i1 + i2 + i3; }
1409};
1410
1411Q_DECLARE_METATYPE(CustomType*)
1412Q_DECLARE_METATYPE(CustomType)
1413
1414class QCustomTypeChecker: public QObject
1415{
1416 Q_OBJECT
1417
1418public:
1419 QCustomTypeChecker(QObject *parent = 0): QObject(parent) {}
1420 void doEmit(CustomType ct)
1421 { emit signal1(ct); }
1422
1423public slots:
1424 void slot1(CustomType ct);
1425 void slot2(const QList<CustomType> &ct);
1426
1427signals:
1428 void signal1(CustomType ct);
1429 void signal2(const QList<CustomType> &ct);
1430
1431public:
1432 CustomType received;
1433};
1434
1435void QCustomTypeChecker::slot1(CustomType ct)
1436{ received = ct; }
1437
1438void QCustomTypeChecker::slot2(const QList< CustomType >& ct)
1439{ received = ct[0]; }
1440
1441void tst_QObject::customTypes()
1442{
1443 CustomType t0;
1444 CustomType t1(1, 2, 3);
1445 CustomType t2(2, 3, 4);
1446
1447 {
1448 QCustomTypeChecker checker;
1449 QCOMPARE(instanceCount, 4);
1450
1451 connect(sender: &checker, SIGNAL(signal1(CustomType)), receiver: &checker, SLOT(slot1(CustomType)),
1452 Qt::DirectConnection);
1453 QCOMPARE(checker.received.value(), 0);
1454 checker.doEmit(ct: t1);
1455 QCOMPARE(checker.received.value(), t1.value());
1456 checker.received = t0;
1457
1458 int idx = qRegisterMetaType<CustomType>(typeName: "CustomType");
1459 QCOMPARE(QMetaType::type("CustomType"), idx);
1460
1461 checker.disconnect();
1462 connect(sender: &checker, SIGNAL(signal1(CustomType)), receiver: &checker, SLOT(slot1(CustomType)),
1463 Qt::QueuedConnection);
1464 QCOMPARE(instanceCount, 4);
1465 checker.doEmit(ct: t2);
1466 QCOMPARE(instanceCount, 5);
1467 QCOMPARE(checker.received.value(), t0.value());
1468
1469 QCoreApplication::processEvents();
1470 QCOMPARE(checker.received.value(), t2.value());
1471 QCOMPARE(instanceCount, 4);
1472
1473 QVERIFY(QMetaType::isRegistered(idx));
1474 QCOMPARE(qRegisterMetaType<CustomType>("CustomType"), idx);
1475 QCOMPARE(QMetaType::type("CustomType"), idx);
1476 QVERIFY(QMetaType::isRegistered(idx));
1477 }
1478 QCOMPARE(instanceCount, 3);
1479}
1480
1481QDataStream &operator<<(QDataStream &stream, const CustomType &ct)
1482{
1483 stream << ct.i1 << ct.i2 << ct.i3;
1484 return stream;
1485}
1486
1487QDataStream &operator>>(QDataStream &stream, CustomType &ct)
1488{
1489 stream >> ct.i1;
1490 stream >> ct.i2;
1491 stream >> ct.i3;
1492 return stream;
1493}
1494
1495void tst_QObject::streamCustomTypes()
1496{
1497 QByteArray ba;
1498
1499 int idx = qRegisterMetaType<CustomType>(typeName: "CustomType");
1500 qRegisterMetaTypeStreamOperators<CustomType>(typeName: "CustomType");
1501
1502 {
1503 CustomType t1(1, 2, 3);
1504 QCOMPARE(instanceCount, 1);
1505 QDataStream stream(&ba, (QIODevice::OpenMode)QIODevice::WriteOnly);
1506 QMetaType::save(stream, type: idx, data: &t1);
1507 }
1508
1509 QCOMPARE(instanceCount, 0);
1510
1511 {
1512 CustomType t2;
1513 QCOMPARE(instanceCount, 1);
1514 QDataStream stream(&ba, (QIODevice::OpenMode)QIODevice::ReadOnly);
1515 QMetaType::load(stream, type: idx, data: &t2);
1516 QCOMPARE(instanceCount, 1);
1517 QCOMPARE(t2.i1, 1);
1518 QCOMPARE(t2.i2, 2);
1519 QCOMPARE(t2.i3, 3);
1520 }
1521 QCOMPARE(instanceCount, 0);
1522}
1523
1524typedef QString CustomString;
1525
1526class PropertyObject : public QObject
1527{
1528 Q_OBJECT
1529
1530 Q_PROPERTY(Alpha alpha READ alpha WRITE setAlpha)
1531 Q_PROPERTY(Priority priority READ priority WRITE setPriority)
1532 Q_PROPERTY(int number READ number WRITE setNumber)
1533 Q_PROPERTY(QString string READ string WRITE setString)
1534 Q_PROPERTY(QVariant variant READ variant WRITE setVariant)
1535 Q_PROPERTY(CustomType* custom READ custom WRITE setCustom)
1536 Q_PROPERTY(float myFloat READ myFloat WRITE setMyFloat)
1537 Q_PROPERTY(qreal myQReal READ myQReal WRITE setMyQReal)
1538 Q_PROPERTY(CustomString customString READ customString WRITE setCustomString )
1539
1540public:
1541 enum Alpha {
1542 Alpha0,
1543 Alpha1,
1544 Alpha2
1545 };
1546
1547 enum Priority { High, Low, VeryHigh, VeryLow };
1548
1549 PropertyObject()
1550 : m_alpha(Alpha0), m_priority(High), m_number(0), m_custom(0), m_float(42)
1551 {}
1552
1553 Alpha alpha() const { return m_alpha; }
1554 void setAlpha(Alpha alpha) { m_alpha = alpha; }
1555
1556 Priority priority() const { return m_priority; }
1557 void setPriority(Priority priority) { m_priority = priority; }
1558
1559 int number() const { return m_number; }
1560 void setNumber(int number) { m_number = number; }
1561
1562 QString string() const { return m_string; }
1563 void setString(const QString &string) { m_string = string; }
1564
1565 QVariant variant() const { return m_variant; }
1566 void setVariant(const QVariant &variant) { m_variant = variant; }
1567
1568 CustomType *custom() const { return m_custom; }
1569 void setCustom(CustomType *custom) { m_custom = custom; }
1570
1571 void setMyFloat(float value) { m_float = value; }
1572 inline float myFloat() const { return m_float; }
1573
1574 void setMyQReal(qreal value) { m_qreal = value; }
1575 qreal myQReal() const { return m_qreal; }
1576
1577 CustomString customString() const { return m_customString; }
1578 void setCustomString(const QString &string) { m_customString = string; }
1579
1580private:
1581 Alpha m_alpha;
1582 Priority m_priority;
1583 int m_number;
1584 QString m_string;
1585 QVariant m_variant;
1586 CustomType *m_custom;
1587 float m_float;
1588 qreal m_qreal;
1589 CustomString m_customString;
1590
1591 Q_ENUM(Alpha)
1592 Q_ENUM(Priority)
1593};
1594
1595Q_DECLARE_METATYPE(PropertyObject::Priority)
1596
1597void tst_QObject::threadSignalEmissionCrash()
1598{
1599 int loopCount = 1000;
1600 for (int i = 0; i < loopCount; ++i) {
1601 QTcpSocket socket;
1602 socket.connectToHost(hostName: "localhost", port: 80);
1603 }
1604}
1605
1606class TestThread : public QThread
1607{
1608 Q_OBJECT
1609public:
1610 inline void run()
1611 {
1612 *object = new QObject;
1613 *child = new QObject(*object);
1614 mutex.lock();
1615 cond.wakeOne();
1616 cond.wait(lockedMutex: &mutex);
1617 mutex.unlock();
1618 }
1619
1620 QObject **object, **child;
1621 QMutex mutex;
1622 QWaitCondition cond;
1623};
1624
1625void tst_QObject::thread()
1626{
1627 QThread *currentThread = QThread::currentThread();
1628 // the current thread is the same as the QApplication
1629 // thread... see tst_QApplication::thread()
1630
1631 {
1632 QObject object;
1633 // thread affinity for objects with no parent should be the
1634 // current thread
1635 QVERIFY(object.thread() != nullptr);
1636 QCOMPARE(object.thread(), currentThread);
1637 // children inherit their parent's thread
1638 QObject child(&object);
1639 QCOMPARE(child.thread(), object.thread());
1640 }
1641
1642 QObject *object = 0;
1643 QObject *child = 0;
1644
1645 {
1646 TestThread thr;
1647 QVERIFY(thr.thread() != nullptr);
1648 QCOMPARE(thr.thread(), currentThread);
1649
1650 thr.object = &object;
1651 thr.child = &child;
1652
1653 thr.mutex.lock();
1654 thr.start();
1655 thr.cond.wait(lockedMutex: &thr.mutex);
1656
1657 // thread affinity for an object with no parent should be the
1658 // thread in which the object was created
1659 QCOMPARE(object->thread(), (QThread *)&thr);
1660 // children inherit their parent's thread
1661 QCOMPARE(child->thread(), object->thread());
1662
1663 thr.cond.wakeOne();
1664 thr.mutex.unlock();
1665 thr.wait();
1666
1667 // even though the thread is no longer running, the affinity
1668 // should not change
1669 QCOMPARE(object->thread(), (QThread *)&thr);
1670 QCOMPARE(child->thread(), object->thread());
1671 }
1672
1673 // the thread has been destroyed, thread affinity should
1674 // automatically reset to no thread
1675 QCOMPARE(object->thread(), (QThread *)0);
1676 QCOMPARE(child->thread(), object->thread());
1677
1678 delete object;
1679}
1680
1681class MoveToThreadObject : public QObject
1682{
1683 Q_OBJECT
1684public:
1685 QThread *timerEventThread;
1686 QThread *customEventThread;
1687 QThread *slotThread;
1688
1689 MoveToThreadObject(QObject *parent = 0)
1690 : QObject(parent), timerEventThread(0), customEventThread(0), slotThread(0)
1691 { }
1692
1693 void customEvent(QEvent *)
1694 {
1695 if (customEventThread)
1696 qFatal(msg: "%s: customEventThread should be null", Q_FUNC_INFO);
1697 customEventThread = QThread::currentThread();
1698 emit theSignal();
1699 }
1700
1701 void timerEvent(QTimerEvent *)
1702 {
1703 if (timerEventThread)
1704 qFatal(msg: "%s: timerEventThread should be null", Q_FUNC_INFO);
1705 timerEventThread = QThread::currentThread();
1706 emit theSignal();
1707 }
1708
1709public slots:
1710 void theSlot()
1711 {
1712 if (slotThread)
1713 qFatal(msg: "%s: slotThread should be null", Q_FUNC_INFO);
1714 slotThread = QThread::currentThread();
1715 emit theSignal();
1716 }
1717
1718signals:
1719 void theSignal();
1720};
1721
1722class MoveToThreadThread : public QThread
1723{
1724public:
1725 ~MoveToThreadThread()
1726 {
1727 if (isRunning()) {
1728 terminate();
1729 wait();
1730 }
1731 }
1732 void start()
1733 {
1734 QEventLoop eventLoop;
1735 connect(sender: this, SIGNAL(started()), receiver: &eventLoop, SLOT(quit()), Qt::QueuedConnection);
1736 QThread::start();
1737 // wait for thread to start
1738 (void) eventLoop.exec();
1739 }
1740 void run()
1741 { (void) exec(); }
1742};
1743
1744void tst_QObject::thread0()
1745{
1746 QObject *object = new QObject;
1747 object->moveToThread(thread: 0);
1748 QObject *child = new QObject(object);
1749 QCOMPARE(child->parent(), object);
1750 QCOMPARE(child->thread(), (QThread *)0);
1751
1752#if 0
1753 // We don't support moving children into a parent that has no thread
1754 // affinity (yet?).
1755 QObject *child2 = new QObject;
1756 child2->moveToThread(0);
1757 child2->setParent(object);
1758 QCOMPARE(child2->parent(), object);
1759 QCOMPARE(child2->thread(), (QThread *)0);
1760#endif
1761
1762 delete object;
1763}
1764
1765void tst_QObject::moveToThread()
1766{
1767 QThread *currentThread = QThread::currentThread();
1768
1769 {
1770 QObject *object = new QObject;
1771 QObject *child = new QObject(object);
1772 QCOMPARE(object->thread(), currentThread);
1773 QCOMPARE(child->thread(), currentThread);
1774 object->moveToThread(thread: 0);
1775 QCOMPARE(object->thread(), (QThread *)0);
1776 QCOMPARE(child->thread(), (QThread *)0);
1777 object->moveToThread(thread: currentThread);
1778 QCOMPARE(object->thread(), currentThread);
1779 QCOMPARE(child->thread(), currentThread);
1780 object->moveToThread(thread: 0);
1781 QCOMPARE(object->thread(), (QThread *)0);
1782 QCOMPARE(child->thread(), (QThread *)0);
1783 // can delete an object with no thread anywhere
1784 delete object;
1785 }
1786
1787 {
1788 MoveToThreadThread thread;
1789 thread.start();
1790
1791 QObject *object = new QObject;
1792 QObject *child = new QObject(object);
1793 QPointer<QObject> opointer = object;
1794 QPointer<QObject> cpointer = object;
1795
1796 QCOMPARE(object->thread(), currentThread);
1797 QCOMPARE(child->thread(), currentThread);
1798 object->moveToThread(thread: &thread);
1799 QCOMPARE(object->thread(), (QThread *)&thread);
1800 QCOMPARE(child->thread(), (QThread *)&thread);
1801
1802 connect(sender: object, SIGNAL(destroyed()), receiver: &thread, SLOT(quit()), Qt::DirectConnection);
1803 QMetaObject::invokeMethod(obj: object, member: "deleteLater", type: Qt::QueuedConnection);
1804 thread.wait();
1805
1806 QVERIFY(opointer == nullptr);
1807 QVERIFY(cpointer == nullptr);
1808 }
1809
1810 {
1811 // make sure posted events are moved with the object
1812 MoveToThreadThread thread;
1813 thread.start();
1814
1815 MoveToThreadObject *object = new MoveToThreadObject;
1816 MoveToThreadObject *child = new MoveToThreadObject(object);
1817
1818 connect(sender: object, SIGNAL(theSignal()), receiver: &thread, SLOT(quit()), Qt::DirectConnection);
1819 QCoreApplication::postEvent(receiver: child, event: new QEvent(QEvent::User));
1820 QCoreApplication::postEvent(receiver: object, event: new QEvent(QEvent::User));
1821
1822 QCOMPARE(object->thread(), currentThread);
1823 QCOMPARE(child->thread(), currentThread);
1824 object->moveToThread(thread: &thread);
1825 QCOMPARE(object->thread(), (QThread *)&thread);
1826 QCOMPARE(child->thread(), (QThread *)&thread);
1827
1828 thread.wait();
1829
1830 QCOMPARE(object->customEventThread, (QThread *)&thread);
1831 QCOMPARE(child->customEventThread, (QThread *)&thread);
1832
1833 thread.start();
1834 connect(sender: object, SIGNAL(destroyed()), receiver: &thread, SLOT(quit()), Qt::DirectConnection);
1835 QMetaObject::invokeMethod(obj: object, member: "deleteLater", type: Qt::QueuedConnection);
1836 thread.wait();
1837 }
1838
1839 {
1840 // make sure timers are moved with the object
1841 MoveToThreadThread thread;
1842 thread.start();
1843
1844 MoveToThreadObject *object = new MoveToThreadObject;
1845 MoveToThreadObject *child = new MoveToThreadObject(object);
1846
1847 connect(sender: object, SIGNAL(theSignal()), receiver: &thread, SLOT(quit()), Qt::DirectConnection);
1848
1849 child->startTimer(interval: 90);
1850 object->startTimer(interval: 100);
1851
1852 QCOMPARE(object->thread(), currentThread);
1853 QCOMPARE(child->thread(), currentThread);
1854 object->moveToThread(thread: &thread);
1855 QCOMPARE(object->thread(), (QThread *)&thread);
1856 QCOMPARE(child->thread(), (QThread *)&thread);
1857
1858 thread.wait();
1859
1860 QCOMPARE(object->timerEventThread, (QThread *)&thread);
1861 QCOMPARE(child->timerEventThread, (QThread *)&thread);
1862
1863 thread.start();
1864 connect(sender: object, SIGNAL(destroyed()), receiver: &thread, SLOT(quit()), Qt::DirectConnection);
1865 QMetaObject::invokeMethod(obj: object, member: "deleteLater", type: Qt::QueuedConnection);
1866 thread.wait();
1867 }
1868
1869 // WinRT does not allow connection to localhost
1870#ifndef Q_OS_WINRT
1871 {
1872 // make sure socket notifiers are moved with the object
1873 MoveToThreadThread thread;
1874 thread.start();
1875
1876 QTcpServer server;
1877 QVERIFY(server.listen(QHostAddress::LocalHost, 0));
1878 QTcpSocket *socket = new QTcpSocket;
1879 MoveToThreadObject *child = new MoveToThreadObject(socket);
1880 connect(sender: socket, SIGNAL(disconnected()), receiver: child, SLOT(theSlot()), Qt::DirectConnection);
1881 connect(sender: child, SIGNAL(theSignal()), receiver: &thread, SLOT(quit()), Qt::DirectConnection);
1882
1883 socket->connectToHost(address: server.serverAddress(), port: server.serverPort());
1884
1885 QVERIFY(server.waitForNewConnection(1000));
1886 QTcpSocket *serverSocket = server.nextPendingConnection();
1887 QVERIFY(serverSocket);
1888
1889 socket->waitForConnected();
1890
1891 QCOMPARE(socket->thread(), currentThread);
1892 socket->moveToThread(thread: &thread);
1893 QCOMPARE(socket->thread(), (QThread *)&thread);
1894
1895 serverSocket->close();
1896
1897 QVERIFY(thread.wait(10000));
1898
1899 QCOMPARE(child->slotThread, (QThread *)&thread);
1900
1901 thread.start();
1902 connect(sender: socket, SIGNAL(destroyed()), receiver: &thread, SLOT(quit()), Qt::DirectConnection);
1903 QMetaObject::invokeMethod(obj: socket, member: "deleteLater", type: Qt::QueuedConnection);
1904 thread.wait();
1905 }
1906#endif
1907}
1908
1909
1910void tst_QObject::property()
1911{
1912 PropertyObject object;
1913 const QMetaObject *mo = object.metaObject();
1914 QMetaProperty property;
1915 QVERIFY(mo);
1916
1917 QVERIFY(mo->indexOfProperty("alpha") != -1);
1918 property = mo->property(index: mo->indexOfProperty(name: "alpha"));
1919 QVERIFY(property.isEnumType());
1920 QCOMPARE(property.typeName(), "Alpha");
1921 QCOMPARE(property.type(), QVariant::Int);
1922
1923 QVariant var = object.property(name: "alpha");
1924 QVERIFY(!var.isNull());
1925 QCOMPARE(var.toInt(), int(PropertyObject::Alpha0));
1926 object.setAlpha(PropertyObject::Alpha1);
1927 QCOMPARE(object.property("alpha").toInt(), int(PropertyObject::Alpha1));
1928 QVERIFY(object.setProperty("alpha", PropertyObject::Alpha2));
1929 QCOMPARE(object.property("alpha").toInt(), int(PropertyObject::Alpha2));
1930 QVERIFY(object.setProperty("alpha", "Alpha1"));
1931 QCOMPARE(object.property("alpha").toInt(), int(PropertyObject::Alpha1));
1932 QVERIFY(!object.setProperty("alpha", QVariant()));
1933
1934 QVERIFY(mo->indexOfProperty("number") != -1);
1935 QCOMPARE(object.property("number").toInt(), 0);
1936 object.setNumber(24);
1937 QCOMPARE(object.property("number"), QVariant(24));
1938 QVERIFY(object.setProperty("number", 12));
1939 QCOMPARE(object.property("number"), QVariant(12));
1940 QVERIFY(object.setProperty("number", "42"));
1941 QCOMPARE(object.property("number"), QVariant(42));
1942
1943 QVERIFY(mo->indexOfProperty("string") != -1);
1944 QCOMPARE(object.property("string").toString(), QString());
1945 object.setString("String1");
1946 QCOMPARE(object.property("string"), QVariant("String1"));
1947 QVERIFY(object.setProperty("string", "String2"));
1948 QCOMPARE(object.property("string"), QVariant("String2"));
1949 QVERIFY(object.setProperty("string", QVariant()));
1950
1951 const int idx = mo->indexOfProperty(name: "variant");
1952 QVERIFY(idx != -1);
1953 QCOMPARE(QMetaType::Type(mo->property(idx).type()), QMetaType::QVariant);
1954 QCOMPARE(object.property("variant"), QVariant());
1955 QVariant variant1(42);
1956 QVariant variant2("string");
1957 object.setVariant(variant1);
1958 QCOMPARE(object.property("variant"), variant1);
1959 QVERIFY(object.setProperty("variant", variant2));
1960 QCOMPARE(object.variant(), QVariant(variant2));
1961 QCOMPARE(object.property("variant"), variant2);
1962 QVERIFY(object.setProperty("variant", QVariant()));
1963 QCOMPARE(object.property("variant"), QVariant());
1964
1965 QVERIFY(mo->indexOfProperty("custom") != -1);
1966 property = mo->property(index: mo->indexOfProperty(name: "custom"));
1967 QVERIFY(property.isValid());
1968 QVERIFY(property.isWritable());
1969 QVERIFY(!property.isEnumType());
1970 QCOMPARE(property.typeName(), "CustomType*");
1971 qRegisterMetaType<CustomType*>();
1972 QCOMPARE(property.type(), QVariant::UserType);
1973 QCOMPARE(property.userType(), qMetaTypeId<CustomType*>());
1974
1975 CustomType *customPointer = 0;
1976 QVariant customVariant = object.property(name: "custom");
1977 customPointer = qvariant_cast<CustomType *>(v: customVariant);
1978 QCOMPARE(customPointer, object.custom());
1979
1980 CustomType custom;
1981 customPointer = &custom;
1982 customVariant.setValue(customPointer);
1983
1984 property = mo->property(index: mo->indexOfProperty(name: "custom"));
1985 QVERIFY(property.isWritable());
1986 QCOMPARE(property.typeName(), "CustomType*");
1987 QCOMPARE(property.type(), QVariant::UserType);
1988 QCOMPARE(property.userType(), qMetaTypeId<CustomType*>());
1989
1990 QVERIFY(object.setProperty("custom", customVariant));
1991 QCOMPARE(object.custom(), customPointer);
1992
1993 customVariant = object.property(name: "custom");
1994 customPointer = qvariant_cast<CustomType *>(v: customVariant);
1995 QCOMPARE(object.custom(), customPointer);
1996
1997 // this enum property has a meta type, but it's not yet registered, so we know this fails
1998 QVERIFY(mo->indexOfProperty("priority") != -1);
1999 property = mo->property(index: mo->indexOfProperty(name: "priority"));
2000 QVERIFY(property.isEnumType());
2001 QCOMPARE(property.typeName(), "Priority");
2002 QCOMPARE(property.type(), QVariant::Int);
2003
2004 var = object.property(name: "priority");
2005 QVERIFY(!var.isNull());
2006 QCOMPARE(var.toInt(), int(PropertyObject::High));
2007 object.setPriority(PropertyObject::Low);
2008 QCOMPARE(object.property("priority").toInt(), int(PropertyObject::Low));
2009 QVERIFY(object.setProperty("priority", PropertyObject::VeryHigh));
2010 QCOMPARE(object.property("priority").toInt(), int(PropertyObject::VeryHigh));
2011 QVERIFY(object.setProperty("priority", "High"));
2012 QCOMPARE(object.property("priority").toInt(), int(PropertyObject::High));
2013 QVERIFY(!object.setProperty("priority", QVariant()));
2014
2015 // now it's registered, so it works as expected
2016 int priorityMetaTypeId = qRegisterMetaType<PropertyObject::Priority>(typeName: "PropertyObject::Priority");
2017
2018 QVERIFY(mo->indexOfProperty("priority") != -1);
2019 property = mo->property(index: mo->indexOfProperty(name: "priority"));
2020 QVERIFY(property.isEnumType());
2021 QCOMPARE(property.typeName(), "Priority");
2022 QCOMPARE(property.type(), QVariant::UserType);
2023 QCOMPARE(property.userType(), priorityMetaTypeId);
2024
2025 var = object.property(name: "priority");
2026 QVERIFY(!var.isNull());
2027 QVERIFY(var.canConvert<PropertyObject::Priority>());
2028 QCOMPARE(qvariant_cast<PropertyObject::Priority>(var), PropertyObject::High);
2029 object.setPriority(PropertyObject::Low);
2030 QCOMPARE(qvariant_cast<PropertyObject::Priority>(object.property("priority")), PropertyObject::Low);
2031 QVERIFY(object.setProperty("priority", PropertyObject::VeryHigh));
2032 QCOMPARE(qvariant_cast<PropertyObject::Priority>(object.property("priority")), PropertyObject::VeryHigh);
2033 QVERIFY(object.setProperty("priority", "High"));
2034 QCOMPARE(qvariant_cast<PropertyObject::Priority>(object.property("priority")), PropertyObject::High);
2035 QVERIFY(!object.setProperty("priority", QVariant()));
2036
2037 var = object.property(name: "priority");
2038 QCOMPARE(qvariant_cast<PropertyObject::Priority>(var), PropertyObject::High);
2039 object.setPriority(PropertyObject::Low);
2040 QCOMPARE(qvariant_cast<PropertyObject::Priority>(object.property("priority")), PropertyObject::Low);
2041 object.setProperty(name: "priority", value: var);
2042 QCOMPARE(qvariant_cast<PropertyObject::Priority>(object.property("priority")), PropertyObject::High);
2043
2044 qRegisterMetaType<CustomString>(typeName: "CustomString");
2045 QVERIFY(mo->indexOfProperty("customString") != -1);
2046 QCOMPARE(object.property("customString").toString(), QString());
2047 object.setCustomString("String1");
2048 QCOMPARE(object.property("customString"), QVariant("String1"));
2049 QVERIFY(object.setProperty("customString", "String2"));
2050 QCOMPARE(object.property("customString"), QVariant("String2"));
2051 QVERIFY(object.setProperty("customString", QVariant()));
2052}
2053
2054void tst_QObject::metamethod()
2055{
2056 SenderObject obj;
2057 const QMetaObject *mobj = obj.metaObject();
2058 QMetaMethod m;
2059
2060 m = mobj->method(index: mobj->indexOfMethod(method: "invoke1()"));
2061 QVERIFY(m.methodSignature() == "invoke1()");
2062 QCOMPARE(m.methodType(), QMetaMethod::Method);
2063 QCOMPARE(m.access(), QMetaMethod::Public);
2064 QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
2065 QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
2066
2067 m = mobj->method(index: mobj->indexOfMethod(method: "sinvoke1()"));
2068 QVERIFY(m.methodSignature() == "sinvoke1()");
2069 QCOMPARE(m.methodType(), QMetaMethod::Method);
2070 QCOMPARE(m.access(), QMetaMethod::Public);
2071 QVERIFY((m.attributes() & QMetaMethod::Scriptable));
2072 QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
2073
2074 m = mobj->method(index: mobj->indexOfMethod(method: "invoke2()"));
2075 QVERIFY(m.methodSignature() == "invoke2()");
2076 QCOMPARE(m.methodType(), QMetaMethod::Method);
2077 QCOMPARE(m.access(), QMetaMethod::Protected);
2078 QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
2079 QVERIFY((m.attributes() & QMetaMethod::Compatibility));
2080
2081 m = mobj->method(index: mobj->indexOfMethod(method: "sinvoke2()"));
2082 QVERIFY(m.methodSignature() == "sinvoke2()");
2083 QCOMPARE(m.methodType(), QMetaMethod::Method);
2084 QCOMPARE(m.access(), QMetaMethod::Protected);
2085 QVERIFY((m.attributes() & QMetaMethod::Scriptable));
2086 QVERIFY((m.attributes() & QMetaMethod::Compatibility));
2087
2088 m = mobj->method(index: mobj->indexOfMethod(method: "invoke3()"));
2089 QVERIFY(m.methodSignature() == "invoke3()");
2090 QCOMPARE(m.methodType(), QMetaMethod::Method);
2091 QCOMPARE(m.access(), QMetaMethod::Private);
2092 QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
2093 QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
2094
2095 m = mobj->method(index: mobj->indexOfMethod(method: "sinvoke3()"));
2096 QVERIFY(m.methodSignature() == "sinvoke3()");
2097 QCOMPARE(m.methodType(), QMetaMethod::Method);
2098 QCOMPARE(m.access(), QMetaMethod::Private);
2099 QVERIFY((m.attributes() & QMetaMethod::Scriptable));
2100 QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
2101
2102 m = mobj->method(index: mobj->indexOfMethod(method: "signal5()"));
2103 QVERIFY(m.methodSignature() == "signal5()");
2104 QCOMPARE(m.methodType(), QMetaMethod::Signal);
2105 QCOMPARE(m.access(), QMetaMethod::Public);
2106 QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
2107 QVERIFY((m.attributes() & QMetaMethod::Compatibility));
2108
2109 m = mobj->method(index: mobj->indexOfMethod(method: "aPublicSlot()"));
2110 QVERIFY(m.methodSignature() == "aPublicSlot()");
2111 QCOMPARE(m.methodType(), QMetaMethod::Slot);
2112 QCOMPARE(m.access(), QMetaMethod::Public);
2113 QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
2114 QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
2115
2116 m = mobj->method(index: mobj->indexOfMethod(method: "invoke1()"));
2117 QCOMPARE(m.parameterNames().count(), 0);
2118 QCOMPARE(m.parameterTypes().count(), 0);
2119
2120 m = mobj->method(index: mobj->indexOfMethod(method: "invoke2(int)"));
2121 QCOMPARE(m.parameterNames().count(), 1);
2122 QCOMPARE(m.parameterTypes().count(), 1);
2123 QCOMPARE(m.parameterTypes().at(0), QByteArray("int"));
2124 QVERIFY(m.parameterNames().at(0).isEmpty());
2125
2126 m = mobj->method(index: mobj->indexOfMethod(method: "invoke3(int,int)"));
2127 QCOMPARE(m.parameterNames().count(), 2);
2128 QCOMPARE(m.parameterTypes().count(), 2);
2129 QCOMPARE(m.parameterTypes().at(0), QByteArray("int"));
2130 QCOMPARE(m.parameterNames().at(0), QByteArray("hinz"));
2131 QCOMPARE(m.parameterTypes().at(1), QByteArray("int"));
2132 QCOMPARE(m.parameterNames().at(1), QByteArray("kunz"));
2133
2134}
2135
2136namespace QObjectTest
2137{
2138 class TestObject: public QObject
2139 {
2140 Q_OBJECT
2141 public:
2142 TestObject(): QObject(), i(0) {}
2143 void doEmit() { emit aSignal(); }
2144 int i;
2145 public slots:
2146 void aSlot() { ++i; }
2147 signals:
2148 void aSignal();
2149 };
2150}
2151
2152void tst_QObject::namespaces()
2153{
2154 QObjectTest::TestObject obj;
2155
2156 QVERIFY(connect(&obj, SIGNAL(aSignal()), &obj, SLOT(aSlot())));
2157 obj.doEmit();
2158 QCOMPARE(obj.i, 1);
2159}
2160
2161class SuperObject : public QObject
2162{
2163 Q_OBJECT
2164public:
2165 QObject *theSender;
2166 int theSignalId;
2167
2168 SuperObject()
2169 {
2170 theSender = 0;
2171 theSignalId = 0;
2172 }
2173
2174 friend class tst_QObject;
2175
2176 using QObject::sender;
2177
2178public slots:
2179 void rememberSender()
2180 {
2181 theSender = sender();
2182 theSignalId = senderSignalIndex();
2183 }
2184
2185 void deleteAndRememberSender()
2186 {
2187 delete theSender;
2188 rememberSender();
2189 }
2190signals:
2191 void anotherSignal();
2192 void theSignal();
2193};
2194
2195void tst_QObject::senderTest()
2196{
2197 {
2198 SuperObject sender;
2199 SuperObject receiver;
2200 connect(sender: &sender, SIGNAL(anotherSignal()),
2201 receiver: &receiver, SLOT(rememberSender()));
2202 connect(sender: &sender, SIGNAL(theSignal()),
2203 receiver: &receiver, SLOT(rememberSender()));
2204 QCOMPARE(receiver.sender(), (QObject *)0);
2205 QCOMPARE(receiver.senderSignalIndex(), -1);
2206 emit sender.theSignal();
2207 QCOMPARE(receiver.theSender, (QObject *)&sender);
2208 QCOMPARE(receiver.sender(), (QObject *)0);
2209 QCOMPARE(receiver.theSignalId,
2210 sender.metaObject()->indexOfSignal("theSignal()"));
2211 QCOMPARE(receiver.senderSignalIndex(), -1);
2212
2213 emit sender.anotherSignal();
2214 QCOMPARE(receiver.theSignalId,
2215 sender.metaObject()->indexOfSignal("anotherSignal()"));
2216 QCOMPARE(receiver.senderSignalIndex(), -1);
2217 }
2218
2219 {
2220 SuperObject *sender = new SuperObject;
2221 SuperObject *receiver = new SuperObject;
2222 connect(sender, SIGNAL(theSignal()),
2223 receiver, SLOT(rememberSender()),
2224 Qt::BlockingQueuedConnection);
2225
2226 QThread thread;
2227 receiver->moveToThread(thread: &thread);
2228 connect(sender, SIGNAL(theSignal()),
2229 receiver: &thread, SLOT(quit()),
2230 Qt::DirectConnection);
2231
2232 QCOMPARE(receiver->sender(), (QObject *)0);
2233 QCOMPARE(receiver->senderSignalIndex(), -1);
2234 receiver->theSender = 0;
2235 receiver->theSignalId = -1;
2236 thread.start();
2237 emit sender->theSignal();
2238 QCOMPARE(receiver->theSender, (QObject *) sender);
2239 QCOMPARE(receiver->sender(), (QObject *)0);
2240 QCOMPARE(receiver->theSignalId,
2241 sender->metaObject()->indexOfSignal("theSignal()"));
2242 QCOMPARE(receiver->senderSignalIndex(), -1);
2243
2244 QVERIFY(thread.wait(10000));
2245 delete receiver;
2246 delete sender;
2247 }
2248
2249 {
2250 SuperObject *sender = new SuperObject;
2251 SuperObject receiver;
2252 connect(sender, SIGNAL(theSignal()),
2253 receiver: &receiver, SLOT(deleteAndRememberSender()));
2254 QCOMPARE(receiver.sender(), (QObject *)0);
2255 receiver.theSender = sender;
2256 emit sender->theSignal();
2257 QCOMPARE(receiver.theSender, (QObject *)0);
2258 QCOMPARE(receiver.sender(), (QObject *)0);
2259 }
2260
2261 {
2262 SuperObject *sender = new SuperObject;
2263 SuperObject *receiver = new SuperObject;
2264 connect(sender, SIGNAL(theSignal()),
2265 receiver, SLOT(deleteAndRememberSender()),
2266 Qt::BlockingQueuedConnection);
2267
2268 QThread thread;
2269 receiver->moveToThread(thread: &thread);
2270 connect(sender, SIGNAL(destroyed()),
2271 receiver: &thread, SLOT(quit()),
2272 Qt::DirectConnection);
2273
2274 QCOMPARE(receiver->sender(), (QObject *)0);
2275 receiver->theSender = sender;
2276 thread.start();
2277 emit sender->theSignal();
2278 QCOMPARE(receiver->theSender, (QObject *)0);
2279 QCOMPARE(receiver->sender(), (QObject *)0);
2280
2281 QVERIFY(thread.wait(10000));
2282 delete receiver;
2283 }
2284}
2285
2286namespace Foo
2287{
2288 struct Bar
2289 {
2290 virtual ~Bar() {}
2291 virtual int rtti() const = 0;
2292 };
2293
2294 struct Bleh
2295 {
2296 virtual ~Bleh() {}
2297 virtual int rtti() const = 0;
2298 };
2299}
2300
2301QT_BEGIN_NAMESPACE
2302Q_DECLARE_INTERFACE(Foo::Bar, "com.qtest.foobar")
2303QT_END_NAMESPACE
2304
2305#define Bleh_iid "com.qtest.bleh"
2306QT_BEGIN_NAMESPACE
2307Q_DECLARE_INTERFACE(Foo::Bleh, Bleh_iid)
2308QT_END_NAMESPACE
2309
2310class FooObject: public QObject, public Foo::Bar
2311{
2312 Q_OBJECT
2313 Q_INTERFACES(Foo::Bar)
2314public:
2315 int rtti() const { return 42; }
2316};
2317
2318class BlehObject : public QObject, public Foo::Bleh
2319{
2320 Q_OBJECT
2321 Q_INTERFACES(Foo::Bleh)
2322public:
2323 int rtti() const { return 43; }
2324};
2325
2326void tst_QObject::declareInterface()
2327{
2328 FooObject obj;
2329
2330 Foo::Bar *bar = qobject_cast<Foo::Bar *>(object: &obj);
2331 QVERIFY(bar);
2332 QCOMPARE(bar->rtti(), 42);
2333 QCOMPARE(static_cast<Foo::Bar *>(&obj), bar);
2334
2335 BlehObject bleh;
2336
2337 bar = qobject_cast<Foo::Bar *>(object: &bleh);
2338 QVERIFY(!bar);
2339 Foo::Bleh *b = qobject_cast<Foo::Bleh *>(object: &bleh);
2340 QCOMPARE(b->rtti(), 43);
2341 QCOMPARE(static_cast<Foo::Bleh *>(&bleh), b);
2342
2343}
2344
2345#ifndef QT_NO_USERDATA
2346class CustomData : public QObjectUserData
2347{
2348public:
2349 int id;
2350};
2351
2352void tst_QObject::testUserData()
2353{
2354 const int USER_DATA_COUNT = 100;
2355 int user_data_ids[USER_DATA_COUNT];
2356
2357 // Register a few
2358 for (int i=0; i<USER_DATA_COUNT; ++i) {
2359 user_data_ids[i] = QObject::registerUserData();
2360 }
2361
2362 // Randomize the table a bit
2363 for (int i=0; i<100; ++i) {
2364 int p1 = QRandomGenerator::global()->bounded(highest: USER_DATA_COUNT);
2365 int p2 = QRandomGenerator::global()->bounded(highest: USER_DATA_COUNT);
2366
2367 int tmp = user_data_ids[p1];
2368 user_data_ids[p1] = user_data_ids[p2];
2369 user_data_ids[p2] = tmp;
2370 }
2371
2372 // insert the user data into an object
2373 QObject my_test_object;
2374 for (int i=0; i<USER_DATA_COUNT; ++i) {
2375 CustomData *data = new CustomData;
2376 data->id = user_data_ids[i];
2377 my_test_object.setUserData(id: data->id, data);
2378 }
2379
2380 // verify that all ids and positions are matching
2381 for (int i=0; i<USER_DATA_COUNT; ++i) {
2382 int id = user_data_ids[i];
2383 CustomData *data = static_cast<CustomData *>(my_test_object.userData(id));
2384 QVERIFY(data != nullptr);
2385 QCOMPARE(data->id, id);
2386 }
2387}
2388#endif // QT_NO_USERDATA
2389
2390class DestroyedListener : public QObject
2391{
2392 Q_OBJECT
2393public:
2394 inline DestroyedListener() : pointerWasZero(false) {}
2395
2396 QPointer<QObject> pointer;
2397 bool pointerWasZero;
2398
2399private slots:
2400 inline void otherObjectDestroyed()
2401 { pointerWasZero = pointer.isNull(); }
2402};
2403
2404void tst_QObject::qpointerResetBeforeDestroyedSignal()
2405{
2406 QObject *obj = new QObject;
2407 DestroyedListener listener;
2408 listener.pointer = obj;
2409 listener.pointerWasZero = false;
2410 connect(sender: obj, SIGNAL(destroyed()), receiver: &listener, SLOT(otherObjectDestroyed()));
2411 delete obj;
2412 QVERIFY(listener.pointerWasZero);
2413 QVERIFY(listener.pointer.isNull());
2414}
2415
2416class DefaultArguments : public QObject
2417{
2418 Q_OBJECT
2419
2420public slots:
2421
2422 void theSlot(const QString &s) { result = s; }
2423
2424signals:
2425 void theOriginalSignal();
2426 void theSecondSignal(const QString &s = QString("secondDefault"));
2427
2428public:
2429
2430 void emitTheOriginalSignal() { emit theOriginalSignal(); }
2431 void emitTheSecondSignal() { emit theSecondSignal(); }
2432 QString result;
2433};
2434
2435void tst_QObject::connectSignalsToSignalsWithDefaultArguments()
2436{
2437 DefaultArguments o;
2438 connect(sender: &o, SIGNAL(theOriginalSignal()), receiver: &o, SIGNAL(theSecondSignal()));
2439 connect(sender: &o, SIGNAL(theSecondSignal(QString)), receiver: &o, SLOT(theSlot(QString)));
2440 QVERIFY( o.result.isEmpty() );
2441 o.emitTheSecondSignal();
2442 QCOMPARE(o.result, QString("secondDefault"));
2443 o.result = "Not called";
2444 o.emitTheOriginalSignal();
2445 QCOMPARE(o.result, QString("secondDefault"));
2446
2447}
2448
2449void tst_QObject::receivers()
2450{
2451 class Object : public QObject
2452 {
2453 public:
2454 int receivers(const char* signal) const
2455 { return QObject::receivers(signal); }
2456 };
2457
2458 Object object;
2459 QCOMPARE(object.receivers(SIGNAL(destroyed())), 0);
2460 object.connect(asender: &object, SIGNAL(destroyed()), SLOT(deleteLater()));
2461 QCOMPARE(object.receivers(SIGNAL(destroyed())), 1);
2462 object.connect(asender: &object, SIGNAL(destroyed()), SLOT(deleteLater()));
2463 QCOMPARE(object.receivers(SIGNAL(destroyed())), 2);
2464 object.disconnect(SIGNAL(destroyed()), receiver: &object, SLOT(deleteLater()));
2465 QCOMPARE(object.receivers(SIGNAL(destroyed())), 0);
2466}
2467
2468enum Enum { };
2469
2470struct Struct { };
2471class Class { };
2472template <typename T> class Template { };
2473
2474class NormalizeObject : public QObject
2475{
2476 Q_OBJECT
2477
2478public:
2479
2480signals:
2481 void uintPointerSignal(uint *);
2482 void ulongPointerSignal(ulong *);
2483 void constUintPointerSignal(const uint *);
2484 void constUlongPointerSignal(const ulong *);
2485
2486 void structSignal(Struct s);
2487 void classSignal(Class c);
2488 void enumSignal(Enum e);
2489
2490 void structPointerSignal(Struct *s);
2491 void classPointerSignal(Class *c);
2492 void enumPointerSignal(Enum *e);
2493
2494 void constStructPointerSignal(const Struct *s);
2495 void constClassPointerSignal(const Class *c);
2496 void constEnumPointerSignal(const Enum *e);
2497
2498 void constStructPointerConstPointerSignal(const Struct * const *s);
2499 void constClassPointerConstPointerSignal(const Class * const *c);
2500 void constEnumPointerConstPointerSignal(const Enum * const *e);
2501
2502 void unsignedintSignal(unsigned int);
2503 void unsignedSignal(unsigned);
2504 void unsignedlongSignal(unsigned long);
2505 void unsignedlonglongSignal(quint64);
2506 void unsignedlongintSignal(unsigned long int);
2507 void unsignedshortSignal(unsigned short);
2508 void unsignedcharSignal(unsigned char);
2509
2510 void typeRefSignal(Template<Class &> &ref);
2511 void constTypeRefSignal(const Template<Class const &> &ref);
2512 void typeConstRefSignal(Template<Class const &> const &ref);
2513
2514 void typePointerConstRefSignal(Class * const &);
2515
2516 void constTemplateSignal1( Template<int > );
2517 void constTemplateSignal2( Template< const int >);
2518
2519public slots:
2520 void uintPointerSlot(uint *) { }
2521 void ulongPointerSlot(ulong *) { }
2522 void constUintPointerSlot(const uint *) { }
2523 void constUlongPointerSlot(const ulong *) { }
2524
2525 void structSlot(Struct s) { Q_UNUSED(s); }
2526 void classSlot(Class c) { Q_UNUSED(c); }
2527 void enumSlot(Enum e) { Q_UNUSED(e); }
2528
2529 void structPointerSlot(Struct *s) { Q_UNUSED(s); }
2530 void classPointerSlot(Class *c) { Q_UNUSED(c); }
2531 void enumPointerSlot(Enum *e) { Q_UNUSED(e); }
2532
2533 void constStructPointerSlot(const Struct *s) { Q_UNUSED(s); }
2534 void constClassPointerSlot(const Class *c) { Q_UNUSED(c); }
2535 void constEnumPointerSlot(const Enum *e) { Q_UNUSED(e); }
2536
2537 void constStructPointerConstPointerSlot(const Struct * const *s) { Q_UNUSED(s); }
2538 void constClassPointerConstPointerSlot(const Class * const *c) { Q_UNUSED(c); }
2539 void constEnumPointerConstPointerSlot(const Enum * const *e) { Q_UNUSED(e); }
2540
2541 void uintSlot(uint) {};
2542 void unsignedintSlot(unsigned int) {};
2543 void unsignedSlot(unsigned) {};
2544 void unsignedlongSlot(unsigned long) {};
2545 void unsignedlonglongSlot(quint64) {};
2546 void unsignedlongintSlot(unsigned long int) {};
2547 void unsignedshortSlot(unsigned short) {};
2548 void unsignedcharSlot(unsigned char) {};
2549
2550 void typeRefSlot(Template<Class &> &) {}
2551 void constTypeRefSlot(const Template<const Class &> &) {}
2552 void typeConstRefSlot(Template<Class const &> const &) {}
2553
2554 void typePointerConstRefSlot(Class * const &) {}
2555
2556 void constTemplateSlot1(Template<int > const) {}
2557 void constTemplateSlot2(const Template<int > ) {}
2558 void constTemplateSlot3(const Template< const int >) {}
2559};
2560
2561void tst_QObject::normalize()
2562{
2563 NormalizeObject object;
2564
2565 // unsigned int -> uint, unsigned long -> ulong
2566 QVERIFY(object.connect(&object,
2567 SIGNAL(uintPointerSignal(uint *)),
2568 SLOT(uintPointerSlot(uint *))));
2569 QVERIFY(object.connect(&object,
2570 SIGNAL(uintPointerSignal(unsigned int *)),
2571 SLOT(uintPointerSlot(uint *))));
2572 QVERIFY(object.connect(&object,
2573 SIGNAL(uintPointerSignal(uint *)),
2574 SLOT(uintPointerSlot(unsigned int *))));
2575
2576 QVERIFY(object.connect(&object,
2577 SIGNAL(constUintPointerSignal(const uint *)),
2578 SLOT(constUintPointerSlot(const uint *))));
2579 QVERIFY(object.connect(&object,
2580 SIGNAL(constUintPointerSignal(const unsigned int *)),
2581 SLOT(constUintPointerSlot(const uint *))));
2582 QVERIFY(object.connect(&object,
2583 SIGNAL(constUintPointerSignal(const uint *)),
2584 SLOT(constUintPointerSlot(const unsigned int *))));
2585
2586 QVERIFY(object.connect(&object,
2587 SIGNAL(ulongPointerSignal(ulong *)),
2588 SLOT(ulongPointerSlot(ulong *))));
2589 QVERIFY(object.connect(&object,
2590 SIGNAL(ulongPointerSignal(unsigned long *)),
2591 SLOT(ulongPointerSlot(ulong *))));
2592 QVERIFY(object.connect(&object,
2593 SIGNAL(ulongPointerSignal(ulong *)),
2594 SLOT(ulongPointerSlot(unsigned long *))));
2595
2596 QVERIFY(object.connect(&object,
2597 SIGNAL(constUlongPointerSignal(const ulong *)),
2598 SLOT(constUlongPointerSlot(const ulong *))));
2599 QVERIFY(object.connect(&object,
2600 SIGNAL(constUlongPointerSignal(const unsigned long *)),
2601 SLOT(constUlongPointerSlot(const ulong *))));
2602 QVERIFY(object.connect(&object,
2603 SIGNAL(constUlongPointerSignal(const ulong *)),
2604 SLOT(constUlongPointerSlot(const unsigned long *))));
2605
2606 // struct, class, and enum are optional
2607 QVERIFY(object.connect(&object,
2608 SIGNAL(structSignal(struct Struct)),
2609 SLOT(structSlot(struct Struct))));
2610 QVERIFY(object.connect(&object,
2611 SIGNAL(structSignal(Struct)),
2612 SLOT(structSlot(struct Struct))));
2613 QVERIFY(object.connect(&object,
2614 SIGNAL(structSignal(struct Struct)),
2615 SLOT(structSlot(Struct))));
2616 QVERIFY(object.connect(&object,
2617 SIGNAL(classSignal(class Class)),
2618 SLOT(classSlot(class Class))));
2619 QVERIFY(object.connect(&object,
2620 SIGNAL(classSignal(Class)),
2621 SLOT(classSlot(class Class))));
2622 QVERIFY(object.connect(&object,
2623 SIGNAL(classSignal(class Class)),
2624 SLOT(classSlot(Class))));
2625 QVERIFY(object.connect(&object,
2626 SIGNAL(enumSignal(enum Enum)),
2627 SLOT(enumSlot(enum Enum))));
2628 QVERIFY(object.connect(&object,
2629 SIGNAL(enumSignal(Enum)),
2630 SLOT(enumSlot(enum Enum))));
2631 QVERIFY(object.connect(&object,
2632 SIGNAL(enumSignal(enum Enum)),
2633 SLOT(enumSlot(Enum))));
2634
2635 QVERIFY(object.connect(&object,
2636 SIGNAL(structPointerSignal(struct Struct *)),
2637 SLOT(structPointerSlot(struct Struct *))));
2638 QVERIFY(object.connect(&object,
2639 SIGNAL(structPointerSignal(Struct *)),
2640 SLOT(structPointerSlot(struct Struct *))));
2641 QVERIFY(object.connect(&object,
2642 SIGNAL(structPointerSignal(struct Struct *)),
2643 SLOT(structPointerSlot(Struct *))));
2644 QVERIFY(object.connect(&object,
2645 SIGNAL(classPointerSignal(class Class *)),
2646 SLOT(classPointerSlot(class Class *))));
2647 QVERIFY(object.connect(&object,
2648 SIGNAL(classPointerSignal(Class *)),
2649 SLOT(classPointerSlot(class Class *))));
2650 QVERIFY(object.connect(&object,
2651 SIGNAL(classPointerSignal(class Class *)),
2652 SLOT(classPointerSlot(Class *))));
2653 QVERIFY(object.connect(&object,
2654 SIGNAL(enumPointerSignal(enum Enum *)),
2655 SLOT(enumPointerSlot(enum Enum *))));
2656 QVERIFY(object.connect(&object,
2657 SIGNAL(enumPointerSignal(Enum *)),
2658 SLOT(enumPointerSlot(enum Enum *))));
2659 QVERIFY(object.connect(&object,
2660 SIGNAL(enumPointerSignal(enum Enum *)),
2661 SLOT(enumPointerSlot(Enum *))));
2662
2663 QVERIFY(object.connect(&object,
2664 SIGNAL(constStructPointerSignal(const struct Struct *)),
2665 SLOT(constStructPointerSlot(const struct Struct *))));
2666 QVERIFY(object.connect(&object,
2667 SIGNAL(constStructPointerSignal(const Struct *)),
2668 SLOT(constStructPointerSlot(const struct Struct *))));
2669 QVERIFY(object.connect(&object,
2670 SIGNAL(constStructPointerSignal(const struct Struct *)),
2671 SLOT(constStructPointerSlot(const Struct *))));
2672 QVERIFY(object.connect(&object,
2673 SIGNAL(constClassPointerSignal(const class Class *)),
2674 SLOT(constClassPointerSlot(const class Class *))));
2675 QVERIFY(object.connect(&object,
2676 SIGNAL(constClassPointerSignal(const Class *)),
2677 SLOT(constClassPointerSlot(const class Class *))));
2678 QVERIFY(object.connect(&object,
2679 SIGNAL(constClassPointerSignal(const class Class *)),
2680 SLOT(constClassPointerSlot(const Class *))));
2681 QVERIFY(object.connect(&object,
2682 SIGNAL(constEnumPointerSignal(const enum Enum *)),
2683 SLOT(constEnumPointerSlot(const enum Enum *))));
2684 QVERIFY(object.connect(&object,
2685 SIGNAL(constEnumPointerSignal(const Enum *)),
2686 SLOT(constEnumPointerSlot(const enum Enum *))));
2687 QVERIFY(object.connect(&object,
2688 SIGNAL(constEnumPointerSignal(const enum Enum *)),
2689 SLOT(constEnumPointerSlot(const Enum *))));
2690
2691 QVERIFY(object.connect(&object,
2692 SIGNAL(constStructPointerSignal(struct Struct const *)),
2693 SLOT(constStructPointerSlot(struct Struct const *))));
2694 QVERIFY(object.connect(&object,
2695 SIGNAL(constStructPointerSignal(Struct const *)),
2696 SLOT(constStructPointerSlot(struct Struct const *))));
2697 QVERIFY(object.connect(&object,
2698 SIGNAL(constStructPointerSignal(struct Struct const *)),
2699 SLOT(constStructPointerSlot(Struct const *))));
2700 QVERIFY(object.connect(&object,
2701 SIGNAL(constClassPointerSignal(class Class const *)),
2702 SLOT(constClassPointerSlot(class Class const *))));
2703 QVERIFY(object.connect(&object,
2704 SIGNAL(constClassPointerSignal(Class const *)),
2705 SLOT(constClassPointerSlot(class Class const *))));
2706 QVERIFY(object.connect(&object,
2707 SIGNAL(constClassPointerSignal(class Class const *)),
2708 SLOT(constClassPointerSlot(Class const *))));
2709 QVERIFY(object.connect(&object,
2710 SIGNAL(constEnumPointerSignal(enum Enum const *)),
2711 SLOT(constEnumPointerSlot(enum Enum const *))));
2712 QVERIFY(object.connect(&object,
2713 SIGNAL(constEnumPointerSignal(Enum const *)),
2714 SLOT(constEnumPointerSlot(enum Enum const *))));
2715 QVERIFY(object.connect(&object,
2716 SIGNAL(constEnumPointerSignal(enum Enum const *)),
2717 SLOT(constEnumPointerSlot(Enum const *))));
2718
2719 QVERIFY(object.connect(&object,
2720 SIGNAL(constStructPointerConstPointerSignal(const struct Struct * const *)),
2721 SLOT(constStructPointerConstPointerSlot(const struct Struct * const *))));
2722 QVERIFY(object.connect(&object,
2723 SIGNAL(constStructPointerConstPointerSignal(const Struct * const *)),
2724 SLOT(constStructPointerConstPointerSlot(const struct Struct * const *))));
2725 QVERIFY(object.connect(&object,
2726 SIGNAL(constStructPointerConstPointerSignal(const struct Struct * const *)),
2727 SLOT(constStructPointerConstPointerSlot(const Struct * const *))));
2728 QVERIFY(object.connect(&object,
2729 SIGNAL(constClassPointerConstPointerSignal(const class Class * const *)),
2730 SLOT(constClassPointerConstPointerSlot(const class Class * const *))));
2731 QVERIFY(object.connect(&object,
2732 SIGNAL(constClassPointerConstPointerSignal(const Class * const *)),
2733 SLOT(constClassPointerConstPointerSlot(const class Class * const *))));
2734 QVERIFY(object.connect(&object,
2735 SIGNAL(constClassPointerConstPointerSignal(const class Class * const *)),
2736 SLOT(constClassPointerConstPointerSlot(const Class * const *))));
2737 QVERIFY(object.connect(&object,
2738 SIGNAL(constEnumPointerConstPointerSignal(const enum Enum * const *)),
2739 SLOT(constEnumPointerConstPointerSlot(const enum Enum * const *))));
2740 QVERIFY(object.connect(&object,
2741 SIGNAL(constEnumPointerConstPointerSignal(const Enum * const *)),
2742 SLOT(constEnumPointerConstPointerSlot(const enum Enum * const *))));
2743 QVERIFY(object.connect(&object,
2744 SIGNAL(constEnumPointerConstPointerSignal(const enum Enum * const *)),
2745 SLOT(constEnumPointerConstPointerSlot(const Enum * const *))));
2746
2747 QVERIFY(object.connect(&object,
2748 SIGNAL(constStructPointerConstPointerSignal(struct Struct const * const *)),
2749 SLOT(constStructPointerConstPointerSlot(struct Struct const * const *))));
2750 QVERIFY(object.connect(&object,
2751 SIGNAL(constStructPointerConstPointerSignal(Struct const * const *)),
2752 SLOT(constStructPointerConstPointerSlot(struct Struct const * const *))));
2753 QVERIFY(object.connect(&object,
2754 SIGNAL(constStructPointerConstPointerSignal(struct Struct const * const *)),
2755 SLOT(constStructPointerConstPointerSlot(Struct const * const *))));
2756 QVERIFY(object.connect(&object,
2757 SIGNAL(constClassPointerConstPointerSignal(class Class const * const *)),
2758 SLOT(constClassPointerConstPointerSlot(class Class const * const *))));
2759 QVERIFY(object.connect(&object,
2760 SIGNAL(constClassPointerConstPointerSignal(Class const * const *)),
2761 SLOT(constClassPointerConstPointerSlot(class Class const * const *))));
2762 QVERIFY(object.connect(&object,
2763 SIGNAL(constClassPointerConstPointerSignal(class Class const * const *)),
2764 SLOT(constClassPointerConstPointerSlot(Class const * const *))));
2765 QVERIFY(object.connect(&object,
2766 SIGNAL(constEnumPointerConstPointerSignal(enum Enum const * const *)),
2767 SLOT(constEnumPointerConstPointerSlot(enum Enum const * const *))));
2768 QVERIFY(object.connect(&object,
2769 SIGNAL(constEnumPointerConstPointerSignal(Enum const * const *)),
2770 SLOT(constEnumPointerConstPointerSlot(enum Enum const * const *))));
2771 QVERIFY(object.connect(&object,
2772 SIGNAL(constEnumPointerConstPointerSignal(enum Enum const * const *)),
2773 SLOT(constEnumPointerConstPointerSlot(Enum const * const *))));
2774
2775 QVERIFY(object.connect(&object,
2776 SIGNAL(unsignedintSignal(unsigned int)),
2777 SLOT(unsignedintSlot(unsigned int))));
2778 QVERIFY(object.connect(&object,
2779 SIGNAL(unsignedSignal(unsigned)),
2780 SLOT(unsignedSlot(unsigned))));
2781 QVERIFY(object.connect(&object,
2782 SIGNAL(unsignedSignal(unsigned)),
2783 SLOT(uintSlot(uint))));
2784 QVERIFY(object.connect(&object,
2785 SIGNAL(unsignedlongSignal(unsigned long)),
2786 SLOT(unsignedlongSlot(unsigned long))));
2787 QVERIFY(object.connect(&object,
2788 SIGNAL(unsignedlonglongSignal(quint64)),
2789 SLOT(unsignedlonglongSlot(quint64))));
2790 QVERIFY(object.connect(&object,
2791 SIGNAL(unsignedlongintSignal(unsigned long int)),
2792 SLOT(unsignedlongintSlot(unsigned long int))));
2793 QVERIFY(object.connect(&object,
2794 SIGNAL(unsignedshortSignal(unsigned short)),
2795 SLOT(unsignedshortSlot(unsigned short))));
2796 QVERIFY(object.connect(&object,
2797 SIGNAL(unsignedcharSignal(unsigned char)),
2798 SLOT(unsignedcharSlot(unsigned char))));
2799
2800 // connect when original template signature and mixed usage of 'T<C const &> const &',
2801 // 'const T<const C &> &', and 'T<const C &>'
2802
2803 QVERIFY(object.connect(&object,
2804 SIGNAL(typeRefSignal(Template<Class &> &)),
2805 SLOT(typeRefSlot(Template<Class &> &))));
2806
2807 QVERIFY(object.connect(&object,
2808 SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
2809 SLOT(constTypeRefSlot(const Template<const Class &> &))));
2810 QVERIFY(object.connect(&object,
2811 SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
2812 SLOT(constTypeRefSlot(const Template<Class const &> &))));
2813 QVERIFY(object.connect(&object,
2814 SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
2815 SLOT(constTypeRefSlot(Template<Class const &> const &))));
2816 QVERIFY(object.connect(&object,
2817 SIGNAL(constTypeRefSignal(Template<const Class &> const &)),
2818 SLOT(constTypeRefSlot(Template<Class const &> const &))));
2819 QVERIFY(object.connect(&object,
2820 SIGNAL(constTypeRefSignal(Template<Class const &> const &)),
2821 SLOT(constTypeRefSlot(Template<Class const &> const &))));
2822
2823 QVERIFY(object.connect(&object,
2824 SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
2825 SLOT(typeConstRefSlot(const Template<const Class &> &))));
2826 QVERIFY(object.connect(&object,
2827 SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
2828 SLOT(typeConstRefSlot(const Template<Class const &> &))));
2829 QVERIFY(object.connect(&object,
2830 SIGNAL(constTypeRefSignal(const Template<const Class &> &)),
2831 SLOT(typeConstRefSlot(Template<Class const &> const &))));
2832 QVERIFY(object.connect(&object,
2833 SIGNAL(constTypeRefSignal(Template<const Class &> const &)),
2834 SLOT(typeConstRefSlot(Template<Class const &> const &))));
2835 QVERIFY(object.connect(&object,
2836 SIGNAL(constTypeRefSignal(Template<Class const &> const &)),
2837 SLOT(typeConstRefSlot(Template<Class const &> const &))));
2838
2839 QVERIFY(object.connect(&object,
2840 SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
2841 SLOT(constTypeRefSlot(const Template<const Class &> &))));
2842 QVERIFY(object.connect(&object,
2843 SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
2844 SLOT(constTypeRefSlot(const Template<Class const &> &))));
2845 QVERIFY(object.connect(&object,
2846 SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
2847 SLOT(constTypeRefSlot(Template<Class const &> const &))));
2848 QVERIFY(object.connect(&object,
2849 SIGNAL(typeConstRefSignal(Template<const Class &> const &)),
2850 SLOT(constTypeRefSlot(Template<Class const &> const &))));
2851 QVERIFY(object.connect(&object,
2852 SIGNAL(typeConstRefSignal(Template<Class const &> const &)),
2853 SLOT(constTypeRefSlot(Template<Class const &> const &))));
2854
2855 QVERIFY(object.connect(&object,
2856 SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
2857 SLOT(typeConstRefSlot(const Template<const Class &> &))));
2858 QVERIFY(object.connect(&object,
2859 SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
2860 SLOT(typeConstRefSlot(const Template<Class const &> &))));
2861 QVERIFY(object.connect(&object,
2862 SIGNAL(typeConstRefSignal(const Template<const Class &> &)),
2863 SLOT(typeConstRefSlot(Template<Class const &> const &))));
2864 QVERIFY(object.connect(&object,
2865 SIGNAL(typeConstRefSignal(Template<const Class &> const &)),
2866 SLOT(typeConstRefSlot(Template<Class const &> const &))));
2867 QVERIFY(object.connect(&object,
2868 SIGNAL(typeConstRefSignal(Template<Class const &> const &)),
2869 SLOT(typeConstRefSlot(Template<Class const &> const &))));
2870
2871 QVERIFY(object.connect(&object,
2872 SIGNAL(typePointerConstRefSignal(Class*const&)),
2873 SLOT(typePointerConstRefSlot(Class*const&))));
2874 QVERIFY(object.connect(&object,
2875 SIGNAL(typePointerConstRefSignal(Class*const&)),
2876 SLOT(typePointerConstRefSlot(Class*))));
2877 QVERIFY(object.connect(&object,
2878 SIGNAL(typePointerConstRefSignal(Class*)),
2879 SLOT(typePointerConstRefSlot(Class*const&))));
2880 QVERIFY(object.connect(&object,
2881 SIGNAL(typePointerConstRefSignal(Class*)),
2882 SLOT(typePointerConstRefSlot(Class*))));
2883
2884 QVERIFY( connect(&object, SIGNAL(constTemplateSignal1(Template <int>)),
2885 &object , SLOT(constTemplateSlot1 (Template<int > ) ) ));
2886 QVERIFY( connect(&object, SIGNAL(constTemplateSignal1(Template <int>)),
2887 &object , SLOT(constTemplateSlot2 (Template<int > ) ) ));
2888 QVERIFY( connect(&object, SIGNAL(constTemplateSignal2(Template <const int>)),
2889 &object , SLOT(constTemplateSlot3(Template<int const > ) ) ));
2890
2891 //type does not match
2892 QTest::ignoreMessage(type: QtWarningMsg, message: "QObject::connect: Incompatible sender/receiver arguments\n"
2893 " NormalizeObject::constTemplateSignal1(Template<int>) --> NormalizeObject::constTemplateSlot3(Template<const int>)");
2894 QVERIFY(!connect(&object, SIGNAL(constTemplateSignal1(Template <int>)),
2895 &object , SLOT(constTemplateSlot3(Template<int const> ) ) ));
2896}
2897
2898class SiblingDeleter : public QObject
2899{
2900public:
2901 inline SiblingDeleter(QObject *sibling, QObject *parent)
2902 : QObject(parent), sibling(sibling) {}
2903 inline virtual ~SiblingDeleter() { delete sibling; }
2904
2905private:
2906 QPointer<QObject> sibling;
2907};
2908
2909
2910void tst_QObject::childDeletesItsSibling()
2911{
2912 QObject *commonParent = new QObject(0);
2913 QPointer<QObject> child = new QObject(0);
2914 QPointer<QObject> siblingDeleter = new SiblingDeleter(child, commonParent);
2915 child->setParent(commonParent);
2916 delete commonParent; // don't crash
2917 QVERIFY(!child);
2918 QVERIFY(!siblingDeleter);
2919}
2920
2921void tst_QObject::floatProperty()
2922{
2923 PropertyObject obj;
2924 const int idx = obj.metaObject()->indexOfProperty(name: "myFloat");
2925 QVERIFY(idx > 0);
2926 QMetaProperty prop = obj.metaObject()->property(index: idx);
2927 QVERIFY(prop.isValid());
2928 QCOMPARE(int(prop.type()), QMetaType::type("float"));
2929 QVERIFY(!prop.write(&obj, QVariant("Hello")));
2930 QVERIFY(prop.write(&obj, QVariant::fromValue(128.0f)));
2931 QVariant v = prop.read(obj: &obj);
2932 QCOMPARE(v.userType(), int(QMetaType::Float));
2933 QCOMPARE(qvariant_cast<float>(v), 128.0f);
2934}
2935
2936void tst_QObject::qrealProperty()
2937{
2938 PropertyObject obj;
2939 const int idx = obj.metaObject()->indexOfProperty(name: "myQReal");
2940 QVERIFY(idx > 0);
2941 QMetaProperty prop = obj.metaObject()->property(index: idx);
2942 QVERIFY(prop.isValid());
2943 QCOMPARE(int(prop.type()), QMetaType::type("qreal"));
2944 QVERIFY(!prop.write(&obj, QVariant("Hello")));
2945
2946 QVERIFY(prop.write(&obj, QVariant::fromValue(128.0f)));
2947 QVariant v = prop.read(obj: &obj);
2948 QCOMPARE(v.userType(), qMetaTypeId<qreal>());
2949 QCOMPARE(qvariant_cast<qreal>(v), 128.0);
2950
2951 QVERIFY(prop.write(&obj, QVariant::fromValue(double(127))));
2952 v = prop.read(obj: &obj);
2953 QCOMPARE(v.userType(), qMetaTypeId<qreal>());
2954 QCOMPARE(qvariant_cast<qreal>(v), 127.0);
2955}
2956
2957class DynamicPropertyObject : public PropertyObject
2958{
2959public:
2960 inline DynamicPropertyObject() {}
2961
2962 inline virtual bool event(QEvent *e) {
2963 if (e->type() == QEvent::DynamicPropertyChange) {
2964 changedDynamicProperties.append(t: static_cast<QDynamicPropertyChangeEvent *>(e)->propertyName());
2965 }
2966 return QObject::event(event: e);
2967 }
2968
2969 QList<QByteArray> changedDynamicProperties;
2970};
2971
2972void tst_QObject::dynamicProperties()
2973{
2974 DynamicPropertyObject obj;
2975
2976 QVERIFY(obj.dynamicPropertyNames().isEmpty());
2977
2978 // set a non-dynamic property
2979 QVERIFY(obj.setProperty("number", 42));
2980 QVERIFY(obj.changedDynamicProperties.isEmpty());
2981 QCOMPARE(obj.property("number").toInt(), 42);
2982
2983 QVERIFY(!obj.setProperty("number", "invalid string"));
2984 QVERIFY(obj.changedDynamicProperties.isEmpty());
2985
2986 // set a dynamic property
2987 QVERIFY(!obj.setProperty("myuserproperty", "Hello"));
2988 QCOMPARE(obj.changedDynamicProperties.count(), 1);
2989 QCOMPARE(obj.changedDynamicProperties.first(), QByteArray("myuserproperty"));
2990 //check if there is no redundant DynamicPropertyChange events
2991 QVERIFY(!obj.setProperty("myuserproperty", "Hello"));
2992 QCOMPARE(obj.changedDynamicProperties.count(), 1);
2993
2994 QCOMPARE(obj.property("myuserproperty").type(), QVariant::String);
2995 QCOMPARE(obj.property("myuserproperty").toString(), QString("Hello"));
2996
2997 QCOMPARE(obj.dynamicPropertyNames().count(), 1);
2998 QCOMPARE(obj.dynamicPropertyNames().first(), QByteArray("myuserproperty"));
2999
3000 // change type of the dynamic property
3001 obj.changedDynamicProperties.clear();
3002 QVERIFY(!obj.setProperty("myuserproperty", QByteArray("Hello")));
3003 QCOMPARE(obj.changedDynamicProperties.count(), 1);
3004 QCOMPARE(obj.changedDynamicProperties.first(), QByteArray("myuserproperty"));
3005 QCOMPARE(obj.property("myuserproperty").type(), QVariant::ByteArray);
3006 QCOMPARE(obj.property("myuserproperty").toString(), QByteArray("Hello"));
3007
3008 // unset the property
3009 obj.changedDynamicProperties.clear();
3010 QVERIFY(!obj.setProperty("myuserproperty", QVariant()));
3011
3012 QCOMPARE(obj.changedDynamicProperties.count(), 1);
3013 QCOMPARE(obj.changedDynamicProperties.first(), QByteArray("myuserproperty"));
3014 obj.changedDynamicProperties.clear();
3015
3016 QVERIFY(obj.property("myuserproperty").isNull());
3017
3018 QVERIFY(obj.dynamicPropertyNames().isEmpty());
3019}
3020
3021void tst_QObject::recursiveSignalEmission()
3022{
3023#if !QT_CONFIG(process)
3024 QSKIP("No qprocess support", SkipAll);
3025#else
3026 QProcess proc;
3027
3028 // Add the executable's directory to path so that we can find the test helper next to it
3029 // in a cross-platform way. We must do this because the CWD is not pointing to this directory
3030 // in debug-and-release builds.
3031 QByteArray pathEnv = qgetenv(varName: "PATH");
3032 qputenv(varName: "PATH",
3033 value: pathEnv + QDir::listSeparator().toLatin1()
3034 + QCoreApplication::applicationDirPath().toLocal8Bit());
3035 auto restore = qScopeGuard(f: [&] { qputenv(varName: "PATH", value: pathEnv); });
3036
3037 // signalbug helper app should always be next to this test binary
3038 const QString path = QStringLiteral("signalbug_helper");
3039 proc.start(command: path);
3040 QVERIFY2(proc.waitForStarted(), qPrintable(QString::fromLatin1("Cannot start '%1': %2").arg(path, proc.errorString())));
3041 QVERIFY(proc.waitForFinished());
3042 QCOMPARE(proc.exitStatus(), QProcess::NormalExit);
3043 QCOMPARE(proc.exitCode(), 0);
3044#endif
3045}
3046
3047void tst_QObject::signalBlocking()
3048{
3049 SenderObject sender;
3050 ReceiverObject receiver;
3051
3052 receiver.connect(asender: &sender, SIGNAL(signal1()), SLOT(slot1()));
3053
3054 sender.emitSignal1();
3055 QVERIFY(receiver.called(1));
3056 receiver.reset();
3057
3058 sender.blockSignals(b: true);
3059
3060 sender.emitSignal1();
3061 QVERIFY(!receiver.called(1));
3062 receiver.reset();
3063
3064 sender.blockSignals(b: false);
3065
3066 sender.emitSignal1();
3067 QVERIFY(receiver.called(1));
3068 receiver.reset();
3069}
3070
3071void tst_QObject::blockingQueuedConnection()
3072{
3073 {
3074 SenderObject sender;
3075
3076 MoveToThreadThread thread;
3077 ReceiverObject receiver;
3078 receiver.moveToThread(thread: &thread);
3079 thread.start();
3080
3081 receiver.connect(asender: &sender, SIGNAL(signal1()), SLOT(slot1()), atype: Qt::BlockingQueuedConnection);
3082 sender.emitSignal1();
3083 QVERIFY(receiver.called(1));
3084
3085 receiver.reset();
3086 QVERIFY(QMetaObject::invokeMethod(&receiver, "slot1", Qt::BlockingQueuedConnection));
3087 QVERIFY(receiver.called(1));
3088
3089 connect(sender: &sender, signal: &SenderObject::signal2, receiver: &receiver, slot: &ReceiverObject::slot2, type: Qt::BlockingQueuedConnection);
3090 sender.emitSignal2();
3091 QVERIFY(receiver.called(2));
3092
3093 thread.quit();
3094 QVERIFY(thread.wait());
3095 }
3096}
3097
3098class EventSpy : public QObject
3099{
3100 Q_OBJECT
3101
3102public:
3103 typedef QList<QPair<QObject *, QEvent::Type> > EventList;
3104
3105 EventSpy(QObject *parent = 0)
3106 : QObject(parent)
3107 { }
3108
3109 EventList eventList()
3110 {
3111 return events;
3112 }
3113
3114 void clear()
3115 {
3116 events.clear();
3117 }
3118
3119 bool eventFilter(QObject *object, QEvent *event)
3120 {
3121 events.append(t: qMakePair(x: object, y: event->type()));
3122 return false;
3123 }
3124
3125private:
3126 EventList events;
3127};
3128
3129void tst_QObject::childEvents()
3130{
3131 EventSpy::EventList expected;
3132
3133 {
3134 // no children created, so we expect no events
3135 QObject object;
3136 EventSpy spy;
3137 object.installEventFilter(filterObj: &spy);
3138
3139 QCoreApplication::postEvent(receiver: &object, event: new QEvent(QEvent::Type(QEvent::User + 1)));
3140
3141 QCoreApplication::processEvents();
3142
3143 expected =
3144 EventSpy::EventList()
3145 << qMakePair(x: &object, y: QEvent::Type(QEvent::User + 1));
3146 QCOMPARE(spy.eventList(), expected);
3147 }
3148
3149 {
3150 // 2 children, so we expect 2 ChildAdded events
3151 QObject object;
3152 EventSpy spy;
3153 object.installEventFilter(filterObj: &spy);
3154
3155 QCoreApplication::postEvent(receiver: &object, event: new QEvent(QEvent::Type(QEvent::User + 1)));
3156
3157 QObject child1(&object);
3158 QObject child2;
3159 child2.setParent(&object);
3160
3161 QCoreApplication::postEvent(receiver: &object, event: new QEvent(QEvent::Type(QEvent::User + 2)));
3162
3163 expected =
3164 EventSpy::EventList()
3165 << qMakePair(x: &object, y: QEvent::ChildAdded)
3166 << qMakePair(x: &object, y: QEvent::ChildAdded);
3167 QCOMPARE(spy.eventList(), expected);
3168 spy.clear();
3169
3170 QCoreApplication::processEvents();
3171
3172 expected =
3173 EventSpy::EventList()
3174 << qMakePair(x: &object, y: QEvent::Type(QEvent::User + 1))
3175 << qMakePair(x: &object, y: QEvent::Type(QEvent::User + 2));
3176 QCOMPARE(spy.eventList(), expected);
3177 }
3178
3179 {
3180 // 2 children, but one is reparented away, so we expect:
3181 // 2 ChildAdded, 1 ChildRemoved
3182 QObject object;
3183 EventSpy spy;
3184 object.installEventFilter(filterObj: &spy);
3185
3186 QCoreApplication::postEvent(receiver: &object, event: new QEvent(QEvent::Type(QEvent::User + 1)));
3187
3188 QObject child1(&object);
3189 QObject child2;
3190 child2.setParent(&object);
3191 child2.setParent(0);
3192
3193 QCoreApplication::postEvent(receiver: &object, event: new QEvent(QEvent::Type(QEvent::User + 2)));
3194
3195 expected =
3196 EventSpy::EventList()
3197 << qMakePair(x: &object, y: QEvent::ChildAdded)
3198 << qMakePair(x: &object, y: QEvent::ChildAdded)
3199 << qMakePair(x: &object, y: QEvent::ChildRemoved);
3200 QCOMPARE(spy.eventList(), expected);
3201 spy.clear();
3202
3203 QCoreApplication::processEvents();
3204
3205 expected =
3206 EventSpy::EventList()
3207 << qMakePair(x: &object, y: QEvent::Type(QEvent::User + 1))
3208 << qMakePair(x: &object, y: QEvent::Type(QEvent::User + 2));
3209 QCOMPARE(spy.eventList(), expected);
3210 }
3211}
3212
3213void tst_QObject::installEventFilter()
3214{
3215 QEvent event(QEvent::User);
3216 EventSpy::EventList expected;
3217
3218 QObject object;
3219 EventSpy spy;
3220 object.installEventFilter(filterObj: &spy);
3221
3222 // nothing special, should just work
3223 QCoreApplication::sendEvent(receiver: &object, event: &event);
3224 expected =
3225 EventSpy::EventList()
3226 << qMakePair(x: &object, y: QEvent::User);
3227 QCOMPARE(spy.eventList(), expected);
3228 spy.clear();
3229
3230 // moving the filter causes QCoreApplication to skip the filter
3231 spy.moveToThread(thread: 0);
3232 QTest::ignoreMessage(type: QtWarningMsg, message: "QCoreApplication: Object event filter cannot be in a different thread.");
3233 QCoreApplication::sendEvent(receiver: &object, event: &event);
3234 QVERIFY(spy.eventList().isEmpty());
3235
3236 // move it back, and the filter works again
3237 spy.moveToThread(thread: object.thread());
3238 QCoreApplication::sendEvent(receiver: &object, event: &event);
3239 expected =
3240 EventSpy::EventList()
3241 << qMakePair(x: &object, y: QEvent::User);
3242 QCOMPARE(spy.eventList(), expected);
3243 spy.clear();
3244
3245 // cannot install an event filter that lives in a different thread
3246 object.removeEventFilter(obj: &spy);
3247 spy.moveToThread(thread: 0);
3248 QTest::ignoreMessage(type: QtWarningMsg, message: "QObject::installEventFilter(): Cannot filter events for objects in a different thread.");
3249 object.installEventFilter(filterObj: &spy);
3250 QCoreApplication::sendEvent(receiver: &object, event: &event);
3251 QVERIFY(spy.eventList().isEmpty());
3252}
3253
3254class EmitThread : public QThread
3255{ Q_OBJECT
3256public:
3257 void run(void) {
3258 emit work();
3259 }
3260signals:
3261 void work();
3262};
3263
3264namespace QObjectTest { // Do not clash with WinAPI 'DeleteObject'
3265class DeleteObject : public QObject
3266{
3267 Q_OBJECT
3268
3269public slots:
3270 void deleteSelf()
3271 {
3272 delete this;
3273 }
3274
3275 void relaySignalAndProcessEvents()
3276 {
3277 emit relayedSignal();
3278 QCoreApplication::processEvents();
3279 }
3280
3281signals:
3282 void relayedSignal();
3283};
3284} // namespace QObjectTest
3285
3286void tst_QObject::deleteSelfInSlot()
3287{
3288 {
3289 SenderObject sender;
3290 QObjectTest::DeleteObject *receiver = new QObjectTest::DeleteObject();
3291 receiver->connect(asender: &sender,
3292 SIGNAL(signal1()),
3293 SLOT(deleteSelf()),
3294 atype: Qt::BlockingQueuedConnection);
3295
3296 QThread thread;
3297 receiver->moveToThread(thread: &thread);
3298 thread.connect(asender: receiver, SIGNAL(destroyed()), SLOT(quit()), atype: Qt::DirectConnection);
3299 thread.start();
3300
3301 QPointer<QObjectTest::DeleteObject> p = receiver;
3302 sender.emitSignal1();
3303 QVERIFY(p.isNull());
3304
3305 QVERIFY(thread.wait(10000));
3306 }
3307
3308 {
3309 SenderObject sender;
3310 QObjectTest::DeleteObject *receiver = new QObjectTest::DeleteObject();
3311 receiver->connect(asender: &sender,
3312 SIGNAL(signal1()),
3313 SLOT(relaySignalAndProcessEvents()),
3314 atype: Qt::BlockingQueuedConnection);
3315 receiver->connect(asender: receiver,
3316 SIGNAL(relayedSignal()),
3317 SLOT(deleteSelf()),
3318 atype: Qt::QueuedConnection);
3319
3320 QThread thread;
3321 receiver->moveToThread(thread: &thread);
3322 thread.connect(asender: receiver, SIGNAL(destroyed()), SLOT(quit()), atype: Qt::DirectConnection);
3323 thread.start();
3324
3325 QPointer<QObjectTest::DeleteObject> p = receiver;
3326 sender.emitSignal1();
3327 QVERIFY(p.isNull());
3328
3329 QVERIFY(thread.wait(10000));
3330 }
3331
3332 {
3333 EmitThread sender;
3334 QObjectTest::DeleteObject *receiver = new QObjectTest::DeleteObject();
3335 connect(sender: &sender, SIGNAL(work()), receiver, SLOT(deleteSelf()), Qt::DirectConnection);
3336 QPointer<QObjectTest::DeleteObject> p = receiver;
3337 sender.start();
3338 QVERIFY(sender.wait(10000));
3339 QVERIFY(p.isNull());
3340 }
3341}
3342
3343class DisconnectObject : public QObject
3344{
3345 Q_OBJECT
3346
3347public slots:
3348 void disconnectSelf()
3349 {
3350 disconnect(sender: sender(), signal: 0, receiver: this, member: 0);
3351 }
3352
3353 void relaySignalAndProcessEvents()
3354 {
3355 emit relayedSignal();
3356 QCoreApplication::processEvents();
3357 }
3358
3359signals:
3360 void relayedSignal();
3361};
3362
3363void tst_QObject::disconnectSelfInSlotAndDeleteAfterEmit()
3364{
3365 {
3366 SenderObject sender;
3367 DisconnectObject *receiver = new DisconnectObject();
3368 receiver->connect(asender: &sender, SIGNAL(signal1()), SLOT(disconnectSelf()));
3369 sender.emitSignal1AfterRecursion();
3370 delete receiver;
3371 }
3372
3373 {
3374 SenderObject sender;
3375 DisconnectObject *receiver = new DisconnectObject();
3376 receiver->connect(asender: &sender,
3377 SIGNAL(signal1()),
3378 SLOT(disconnectSelf()),
3379 atype: Qt::BlockingQueuedConnection);
3380
3381 QThread thread;
3382 receiver->moveToThread(thread: &thread);
3383 thread.connect(asender: receiver, SIGNAL(destroyed()), SLOT(quit()), atype: Qt::DirectConnection);
3384 thread.start();
3385
3386 QPointer<DisconnectObject> p = receiver;
3387 sender.emitSignal1();
3388 QVERIFY(!p.isNull());
3389
3390 receiver->deleteLater();
3391
3392 QVERIFY(thread.wait(10000));
3393 QVERIFY(p.isNull());
3394 }
3395
3396 {
3397 SenderObject sender;
3398 DisconnectObject *receiver = new DisconnectObject();
3399 receiver->connect(asender: &sender,
3400 SIGNAL(signal1()),
3401 SLOT(relaySignalAndProcessEvents()),
3402 atype: Qt::BlockingQueuedConnection);
3403 receiver->connect(asender: receiver,
3404 SIGNAL(relayedSignal()),
3405 SLOT(disconnectSelf()),
3406 atype: Qt::QueuedConnection);
3407
3408 QThread thread;
3409 receiver->moveToThread(thread: &thread);
3410 thread.connect(asender: receiver, SIGNAL(destroyed()), SLOT(quit()), atype: Qt::DirectConnection);
3411 thread.start();
3412
3413 QPointer<DisconnectObject> p = receiver;
3414 sender.emitSignal1();
3415 QVERIFY(!p.isNull());
3416
3417 receiver->deleteLater();
3418
3419 QVERIFY(thread.wait(10000));
3420 QVERIFY(p.isNull());
3421 }
3422}
3423
3424void tst_QObject::dumpObjectInfo()
3425{
3426 QObject a, b;
3427 QObject::connect(sender: &a, signal: &QObject::destroyed, receiver: &b, slot: &QObject::deleteLater);
3428 QTest::ignoreMessage(type: QtDebugMsg, message: "OBJECT QObject::unnamed");
3429 QTest::ignoreMessage(type: QtDebugMsg, message: " SIGNALS OUT");
3430 QTest::ignoreMessage(type: QtDebugMsg, message: " signal: destroyed(QObject*)");
3431 QTest::ignoreMessage(type: QtDebugMsg, message: " <functor or function pointer>");
3432 QTest::ignoreMessage(type: QtDebugMsg, message: " SIGNALS IN");
3433 QTest::ignoreMessage(type: QtDebugMsg, message: " <None>");
3434 a.dumpObjectInfo(); // should not crash
3435}
3436
3437class ConnectToSender : public QObject
3438{ Q_OBJECT
3439 public slots:
3440 void uselessSlot() { count++; }
3441
3442 void harmfullSlot() {
3443 //this used to crash
3444 connect(sender: sender(), SIGNAL(signal4()), receiver: this, SLOT(uselessSlot()));
3445 //play a little bit with the memory in order to really get a segfault.
3446 connect(sender: sender(), SIGNAL(signal1()), receiver: this, SLOT(uselessSlot()));
3447 QList<double>() << 45 << 78 << 65 << 121 << 45 << 78 << 12;
3448 }
3449 public:
3450 int count;
3451};
3452
3453void tst_QObject::connectToSender()
3454{
3455 SenderObject s;
3456 ConnectToSender r;
3457 r.count = 0;
3458 QObject::connect(sender: &s, SIGNAL(signal1()), receiver: &r, SLOT(harmfullSlot()));
3459 QObject::connect(sender: &s, SIGNAL(signal1()), receiver: &r, SLOT(uselessSlot()));
3460
3461 s.emitSignal1();
3462
3463 QCOMPARE(r.count, 1);
3464 s.emitSignal4();
3465 QCOMPARE(r.count, 2);
3466}
3467
3468void tst_QObject::qobjectConstCast()
3469{
3470 FooObject obj;
3471
3472 QObject *ptr = &obj;
3473 const QObject *cptr = &obj;
3474
3475 QVERIFY(qobject_cast<FooObject *>(ptr));
3476 QVERIFY(qobject_cast<const FooObject *>(cptr));
3477}
3478
3479void tst_QObject::uniqConnection()
3480{
3481 SenderObject s;
3482 ReceiverObject r1;
3483 ReceiverObject r2;
3484 r1.reset();
3485 r2.reset();
3486 ReceiverObject::sequence = 0;
3487
3488 QVERIFY(connect(&s, SIGNAL(signal1()), &r1, SLOT(slot1()) , Qt::UniqueConnection) );
3489 QVERIFY(connect(&s, SIGNAL(signal1()), &r2, SLOT(slot1()) , Qt::UniqueConnection) );
3490 QVERIFY(connect(&s, SIGNAL(signal1()), &r1, SLOT(slot3()) , Qt::UniqueConnection) );
3491 QVERIFY(connect(&s, SIGNAL(signal3()), &r1, SLOT(slot3()) , Qt::UniqueConnection) );
3492
3493 s.emitSignal1();
3494 s.emitSignal2();
3495 s.emitSignal3();
3496 s.emitSignal4();
3497
3498 QCOMPARE(r1.count_slot1, 1);
3499 QCOMPARE(r1.count_slot2, 0);
3500 QCOMPARE(r1.count_slot3, 2);
3501 QCOMPARE(r1.count_slot4, 0);
3502 QCOMPARE(r2.count_slot1, 1);
3503 QCOMPARE(r2.count_slot2, 0);
3504 QCOMPARE(r2.count_slot3, 0);
3505 QCOMPARE(r2.count_slot4, 0);
3506 QCOMPARE(r1.sequence_slot1, 1);
3507 QCOMPARE(r2.sequence_slot1, 2);
3508 QCOMPARE(r1.sequence_slot3, 4);
3509
3510 r1.reset();
3511 r2.reset();
3512 ReceiverObject::sequence = 0;
3513
3514 QVERIFY( connect(&s, SIGNAL(signal4()), &r1, SLOT(slot4()) , Qt::UniqueConnection));
3515 QVERIFY( connect(&s, SIGNAL(signal4()), &r2, SLOT(slot4()) , Qt::UniqueConnection));
3516 QVERIFY(!connect(&s, SIGNAL(signal4()), &r2, SLOT(slot4()) , Qt::UniqueConnection));
3517 QVERIFY( connect(&s, SIGNAL(signal1()), &r2, SLOT(slot4()) , Qt::UniqueConnection));
3518 QVERIFY(!connect(&s, SIGNAL(signal4()), &r1, SLOT(slot4()) , Qt::UniqueConnection));
3519
3520 s.emitSignal4();
3521 QCOMPARE(r1.count_slot4, 1);
3522 QCOMPARE(r2.count_slot4, 1);
3523 QCOMPARE(r1.sequence_slot4, 1);
3524 QCOMPARE(r2.sequence_slot4, 2);
3525
3526 r1.reset();
3527 r2.reset();
3528 ReceiverObject::sequence = 0;
3529
3530 connect(sender: &s, SIGNAL(signal4()), receiver: &r1, SLOT(slot4()));
3531
3532 s.emitSignal4();
3533 QCOMPARE(r1.count_slot4, 2);
3534 QCOMPARE(r2.count_slot4, 1);
3535 QCOMPARE(r1.sequence_slot4, 3);
3536 QCOMPARE(r2.sequence_slot4, 2);
3537}
3538
3539void tst_QObject::uniqConnectionPtr()
3540{
3541 SenderObject s;
3542 ReceiverObject r1;
3543 ReceiverObject r2;
3544 r1.reset();
3545 r2.reset();
3546 ReceiverObject::sequence = 0;
3547
3548 QVERIFY(connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot1 ,
3549 Qt::UniqueConnection));
3550 QVERIFY(connect(&s, &SenderObject::signal1, &r2, &ReceiverObject::slot1 ,
3551 Qt::UniqueConnection));
3552 QVERIFY(connect(&s, &SenderObject::signal1, &r1, &ReceiverObject::slot3 ,
3553 Qt::UniqueConnection));
3554 QVERIFY(connect(&s, &SenderObject::signal3, &r1, &ReceiverObject::slot3 ,
3555 Qt::UniqueConnection));
3556
3557 s.emitSignal1();
3558 s.emitSignal2();
3559 s.emitSignal3();
3560 s.emitSignal4();
3561
3562 QCOMPARE(r1.count_slot1, 1);
3563 QCOMPARE(r1.count_slot2, 0);
3564 QCOMPARE(r1.count_slot3, 2);
3565 QCOMPARE(r1.count_slot4, 0);
3566 QCOMPARE(r2.count_slot1, 1);
3567 QCOMPARE(r2.count_slot2, 0);
3568 QCOMPARE(r2.count_slot3, 0);
3569 QCOMPARE(r2.count_slot4, 0);
3570 QCOMPARE(r1.sequence_slot1, 1);
3571 QCOMPARE(r2.sequence_slot1, 2);
3572 QCOMPARE(r1.sequence_slot3, 4);
3573
3574 r1.reset();
3575 r2.reset();
3576 ReceiverObject::sequence = 0;
3577
3578 QVERIFY( connect(&s, &SenderObject::signal4, &r1, &ReceiverObject::slot4 ,
3579 Qt::UniqueConnection));
3580 QVERIFY( connect(&s, &SenderObject::signal4, &r2, &ReceiverObject::slot4 ,
3581 Qt::UniqueConnection));
3582 QVERIFY(!connect(&s, &SenderObject::signal4, &r2, &ReceiverObject::slot4 ,
3583 Qt::UniqueConnection));
3584 QVERIFY( connect(&s, &SenderObject::signal1, &r2, &ReceiverObject::slot4 ,
3585 Qt::UniqueConnection));
3586 QVERIFY(!connect(&s, &SenderObject::signal4, &r1, &ReceiverObject::slot4 ,
3587 Qt::UniqueConnection));
3588
3589 s.emitSignal4();
3590 QCOMPARE(r1.count_slot4, 1);
3591 QCOMPARE(r2.count_slot4, 1);
3592 QCOMPARE(r1.sequence_slot4, 1);
3593 QCOMPARE(r2.sequence_slot4, 2);
3594
3595 r1.reset();
3596 r2.reset();
3597 ReceiverObject::sequence = 0;
3598
3599 connect(sender: &s, signal: &SenderObject::signal4, receiver: &r1, slot: &ReceiverObject::slot4);
3600
3601 s.emitSignal4();
3602 QCOMPARE(r1.count_slot4, 2);
3603 QCOMPARE(r2.count_slot4, 1);
3604 QCOMPARE(r1.sequence_slot4, 3);
3605 QCOMPARE(r2.sequence_slot4, 2);
3606}
3607
3608void tst_QObject::interfaceIid()
3609{
3610 QCOMPARE(QByteArray(qobject_interface_iid<Foo::Bleh *>()),
3611 QByteArray(Bleh_iid));
3612 QCOMPARE(QByteArray(qobject_interface_iid<Foo::Bar *>()),
3613 QByteArray("com.qtest.foobar"));
3614 QCOMPARE(QByteArray(qobject_interface_iid<FooObject *>()),
3615 QByteArray());
3616}
3617
3618void tst_QObject::deleteQObjectWhenDeletingEvent()
3619{
3620 // This is a regression test for an old bug that used to deadlock
3621 // when the QObject from the event was destroyed.
3622
3623 struct MyEvent : public QEvent
3624 {
3625 MyEvent() : QEvent(QEvent::User) { }
3626 QObject obj;
3627 };
3628
3629 QObject o;
3630 QCoreApplication::postEvent(receiver: &o, event: new MyEvent);
3631 QCoreApplication::removePostedEvents(receiver: &o); // here you would get a deadlock
3632}
3633
3634class OverloadObject : public QObject
3635{
3636 friend class tst_QObject;
3637 Q_OBJECT
3638 signals:
3639 void sig(int i, char c, qreal m = 12);
3640 void sig(int i, int j = 12);
3641 void sig(QObject *o, QObject *p, QObject *q = 0, QObject *r = 0) const;
3642 void other(int a = 0);
3643 void sig(QObject *o, OverloadObject *p = 0, QObject *q = 0, QObject *r = nullptr);
3644 void sig(double r = 0.5);
3645 public slots:
3646 void slo(int i, int j = 43)
3647 {
3648 s_num += 1;
3649 i1_num = i;
3650 i2_num = j;
3651 }
3652 void slo(QObject *o, QObject *p = qApp, QObject *q = qApp, QObject *r = qApp)
3653 {
3654 s_num += 10;
3655 o1_obj = o;
3656 o2_obj = p;
3657 o3_obj = q;
3658 o4_obj = r;
3659 }
3660 void slo()
3661 {
3662 s_num += 100;
3663 }
3664
3665 public:
3666 int s_num;
3667 int i1_num;
3668 int i2_num;
3669 QObject *o1_obj;
3670 QObject *o2_obj;
3671 QObject *o3_obj;
3672 QObject *o4_obj;
3673};
3674
3675void tst_QObject::overloads()
3676{
3677 OverloadObject obj1;
3678 OverloadObject obj2;
3679 QObject obj3;
3680 obj1.s_num = 0;
3681 obj2.s_num = 0;
3682
3683 connect (sender: &obj1, SIGNAL(sig(int)) , receiver: &obj1, SLOT(slo(int)));
3684 connect (sender: &obj1, SIGNAL(sig(QObject*,QObject*,QObject*)) , receiver: &obj1, SLOT(slo(QObject*,QObject*,QObject*)));
3685
3686 connect (sender: &obj1, SIGNAL(sig(QObject*,QObject*,QObject*,QObject*)) , receiver: &obj2, SLOT(slo(QObject*,QObject*,QObject*)));
3687 connect (sender: &obj1, SIGNAL(sig(QObject*)) , receiver: &obj2, SLOT(slo()));
3688 connect (sender: &obj1, SIGNAL(sig(int,int)) , receiver: &obj2, SLOT(slo(int,int)));
3689
3690 emit obj1.sig(r: 0.5); //connected to nothing
3691 emit obj1.sig(i: 1, c: 'a'); //connected to nothing
3692 QCOMPARE(obj1.s_num, 0);
3693 QCOMPARE(obj2.s_num, 0);
3694
3695 emit obj1.sig(i: 1); //this signal is connected
3696 QCOMPARE(obj1.s_num, 1);
3697 QCOMPARE(obj1.i1_num, 1);
3698 QCOMPARE(obj1.i2_num, 43); //default argument of the slot
3699
3700 QCOMPARE(obj2.s_num, 1);
3701 QCOMPARE(obj2.i1_num, 1);
3702 QCOMPARE(obj2.i2_num, 12); //default argument of the signal
3703
3704
3705 emit obj1.sig(o: &obj2); //this signal is conencted to obj2
3706 QCOMPARE(obj1.s_num, 1);
3707 QCOMPARE(obj2.s_num, 101);
3708 emit obj1.sig(o: &obj2, p: &obj3); //this signal is connected
3709 QCOMPARE(obj1.s_num, 11);
3710 QCOMPARE(obj1.o1_obj, (QObject *)&obj2);
3711 QCOMPARE(obj1.o2_obj, &obj3);
3712 QCOMPARE(obj1.o3_obj, (QObject *)0); //default arg of the signal
3713 QCOMPARE(obj1.o4_obj, (QObject *)qApp); //default arg of the slot
3714
3715 QCOMPARE(obj2.s_num, 111);
3716 QCOMPARE(obj2.o1_obj, (QObject *)&obj2);
3717 QCOMPARE(obj2.o2_obj, &obj3);
3718 QCOMPARE(obj2.o3_obj, (QObject *)0); //default arg of the signal
3719 QCOMPARE(obj2.o4_obj, (QObject *)qApp); //default arg of the slot
3720}
3721
3722class ManySignals : public QObject
3723{ Q_OBJECT
3724 friend class tst_QObject;
3725signals:
3726 void sig00(); void sig01(); void sig02(); void sig03(); void sig04();
3727 void sig05(); void sig06(); void sig07(); void sig08(); void sig09();
3728 void sig10(); void sig11(); void sig12(); void sig13(); void sig14();
3729 void sig15(); void sig16(); void sig17(); void sig18(); void sig19();
3730 void sig20(); void sig21(); void sig22(); void sig23(); void sig24();
3731 void sig25(); void sig26(); void sig27(); void sig28(); void sig29();
3732 void sig30(); void sig31(); void sig32(); void sig33(); void sig34();
3733 void sig35(); void sig36(); void sig37(); void sig38(); void sig39();
3734 void sig40(); void sig41(); void sig42(); void sig43(); void sig44();
3735 void sig45(); void sig46(); void sig47(); void sig48(); void sig49();
3736 void sig50(); void sig51(); void sig52(); void sig53(); void sig54();
3737 void sig55(); void sig56(); void sig57(); void sig58(); void sig59();
3738 void sig60(); void sig61(); void sig62(); void sig63(); void sig64();
3739 void sig65(); void sig66(); void sig67(); void sig68(); void sig69();
3740
3741public slots:
3742 void received() { rec++; }
3743public:
3744 int rec;
3745};
3746
3747
3748void tst_QObject::isSignalConnected()
3749{
3750 ManySignals o;
3751 const QMetaObject *meta = o.metaObject();
3752 o.rec = 0;
3753#ifdef QT_BUILD_INTERNAL
3754 QObjectPrivate *priv = QObjectPrivate::get(o: &o);
3755 QVERIFY(!priv->isSignalConnected(priv->signalIndex("destroyed()")));
3756 QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig00()")));
3757 QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig05()")));
3758 QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig15()")));
3759 QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig29()")));
3760 QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig60()")));
3761#endif
3762 QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed()"))));
3763 QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig00()"))));
3764 QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig05()"))));
3765 QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig15()"))));
3766 QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig29()"))));
3767 QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig60()"))));
3768 QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig69()"))));
3769
3770 QObject::connect(sender: &o, SIGNAL(sig00()), receiver: &o, SIGNAL(sig69()));
3771 QObject::connect(sender: &o, SIGNAL(sig34()), receiver: &o, SIGNAL(sig03()));
3772 QObject::connect(sender: &o, SIGNAL(sig69()), receiver: &o, SIGNAL(sig34()));
3773 QObject::connect(sender: &o, SIGNAL(sig03()), receiver: &o, SIGNAL(sig18()));
3774
3775#ifdef QT_BUILD_INTERNAL
3776 QVERIFY(!priv->isSignalConnected(priv->signalIndex("destroyed()")));
3777 QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig05()")));
3778 QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig15()")));
3779 QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig29()")));
3780
3781 QVERIFY(priv->isSignalConnected(priv->signalIndex("sig00()")));
3782 QVERIFY(priv->isSignalConnected(priv->signalIndex("sig03()")));
3783 QVERIFY(priv->isSignalConnected(priv->signalIndex("sig34()")));
3784 QVERIFY(priv->isSignalConnected(priv->signalIndex("sig69()")));
3785 QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig18()")));
3786#endif
3787 QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed()"))));
3788 QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed(QObject*)"))));
3789 QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig05()"))));
3790 QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig15()"))));
3791 QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig29()"))));
3792
3793 QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig00()"))));
3794 QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig03()"))));
3795 QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig34()"))));
3796 QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig69()"))));
3797 QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig18()"))));
3798
3799
3800 QObject::connect(sender: &o, SIGNAL(sig18()), receiver: &o, SIGNAL(sig29()));
3801 QObject::connect(sender: &o, SIGNAL(sig29()), receiver: &o, SIGNAL(sig62()));
3802 QObject::connect(sender: &o, SIGNAL(sig62()), receiver: &o, SIGNAL(sig28()));
3803 QObject::connect(sender: &o, SIGNAL(sig28()), receiver: &o, SIGNAL(sig27()));
3804
3805#ifdef QT_BUILD_INTERNAL
3806 QVERIFY(priv->isSignalConnected(priv->signalIndex("sig18()")));
3807 QVERIFY(priv->isSignalConnected(priv->signalIndex("sig62()")));
3808 QVERIFY(priv->isSignalConnected(priv->signalIndex("sig28()")));
3809 QVERIFY(priv->isSignalConnected(priv->signalIndex("sig69()")));
3810 QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig27()")));
3811#endif
3812 QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig18()"))));
3813 QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig62()"))));
3814 QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig28()"))));
3815 QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig69()"))));
3816 QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig27()"))));
3817
3818 QCOMPARE(o.rec, 0);
3819 emit o.sig01();
3820 emit o.sig34();
3821 QCOMPARE(o.rec, 0);
3822
3823 QObject::connect(sender: &o, SIGNAL(sig27()), receiver: &o, SLOT(received()));
3824
3825#ifdef QT_BUILD_INTERNAL
3826 QVERIFY(priv->isSignalConnected(priv->signalIndex("sig00()")));
3827 QVERIFY(priv->isSignalConnected(priv->signalIndex("sig03()")));
3828 QVERIFY(priv->isSignalConnected(priv->signalIndex("sig34()")));
3829 QVERIFY(priv->isSignalConnected(priv->signalIndex("sig18()")));
3830 QVERIFY(priv->isSignalConnected(priv->signalIndex("sig62()")));
3831 QVERIFY(priv->isSignalConnected(priv->signalIndex("sig28()")));
3832 QVERIFY(priv->isSignalConnected(priv->signalIndex("sig69()")));
3833 QVERIFY(priv->isSignalConnected(priv->signalIndex("sig27()")));
3834
3835 QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig04()")));
3836 QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig21()")));
3837 QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig25()")));
3838 QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig55()")));
3839#endif
3840
3841 emit o.sig00();
3842 QCOMPARE(o.rec, 1);
3843 emit o.sig69();
3844 QCOMPARE(o.rec, 2);
3845 emit o.sig36();
3846 QCOMPARE(o.rec, 2);
3847
3848 QObject::connect(sender: &o, signal: &QObject::destroyed, slot: qt_noop);
3849 QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed()"))));
3850 QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed(QObject*)"))));
3851
3852 QVERIFY(!o.isSignalConnected(QMetaMethod()));
3853}
3854
3855void tst_QObject::isSignalConnectedAfterDisconnection()
3856{
3857 ManySignals o;
3858 const QMetaObject *meta = o.metaObject();
3859
3860 const QMetaMethod sig00 = meta->method(index: meta->indexOfSignal(signal: "sig00()"));
3861 QVERIFY(!o.isSignalConnected(sig00));
3862 QObject::connect(sender: &o, signal: &ManySignals::sig00, slot: qt_noop);
3863 QVERIFY(o.isSignalConnected(sig00));
3864 QVERIFY(QObject::disconnect(&o, &ManySignals::sig00, 0, 0));
3865 QVERIFY(!o.isSignalConnected(sig00));
3866
3867 const QMetaMethod sig69 = meta->method(index: meta->indexOfSignal(signal: "sig69()"));
3868 QVERIFY(!o.isSignalConnected(sig69));
3869 QObject::connect(sender: &o, signal: &ManySignals::sig69, slot: qt_noop);
3870 QVERIFY(o.isSignalConnected(sig69));
3871 QVERIFY(QObject::disconnect(&o, &ManySignals::sig69, 0, 0));
3872 QVERIFY(!o.isSignalConnected(sig69));
3873
3874 {
3875 ManySignals o2;
3876 QObject::connect(sender: &o, signal: &ManySignals::sig00, receiver: &o2, slot: &ManySignals::sig00);
3877 QVERIFY(o.isSignalConnected(sig00));
3878 // o2 is destructed
3879 }
3880 QVERIFY(!o.isSignalConnected(sig00));
3881
3882 const QMetaMethod sig01 = meta->method(index: meta->indexOfSignal(signal: "sig01()"));
3883 QObject::connect(sender: &o, signal: &ManySignals::sig00, slot: qt_noop);
3884 QObject::connect(sender: &o, signal: &ManySignals::sig01, slot: qt_noop);
3885 QObject::connect(sender: &o, signal: &ManySignals::sig69, slot: qt_noop);
3886 QVERIFY(o.isSignalConnected(sig00));
3887 QVERIFY(o.isSignalConnected(sig01));
3888 QVERIFY(o.isSignalConnected(sig69));
3889 QVERIFY(QObject::disconnect(&o, &ManySignals::sig69, 0, 0));
3890 QVERIFY(o.isSignalConnected(sig00));
3891 QVERIFY(o.isSignalConnected(sig01));
3892 QVERIFY(!o.isSignalConnected(sig69));
3893 QVERIFY(QObject::disconnect(&o, &ManySignals::sig00, 0, 0));
3894 QVERIFY(!o.isSignalConnected(sig00));
3895 QVERIFY(o.isSignalConnected(sig01));
3896 QVERIFY(!o.isSignalConnected(sig69));
3897 QObject::connect(sender: &o, signal: &ManySignals::sig69, slot: qt_noop);
3898 QVERIFY(!o.isSignalConnected(sig00));
3899 QVERIFY(o.isSignalConnected(sig01));
3900 QVERIFY(o.isSignalConnected(sig69));
3901 QVERIFY(QObject::disconnect(&o, &ManySignals::sig01, 0, 0));
3902 QVERIFY(!o.isSignalConnected(sig00));
3903 QVERIFY(!o.isSignalConnected(sig01));
3904 QVERIFY(o.isSignalConnected(sig69));
3905}
3906
3907void tst_QObject::qMetaObjectConnect()
3908{
3909 ReceiverObject r1;
3910 ReceiverObject r2;
3911 int slot1Index, slot2Index, slot3Index;
3912 {
3913 SenderObject s;
3914 r1.reset();
3915 r2.reset();
3916 ReceiverObject::sequence = 0;
3917
3918 int signal1Index = s.metaObject()->indexOfSignal(signal: "signal1()");
3919 int signal3Index = s.metaObject()->indexOfSignal(signal: "signal3()");
3920 slot1Index = r1.metaObject()->indexOfSlot(slot: "slot1()");
3921 slot2Index = r1.metaObject()->indexOfSlot(slot: "slot2()");
3922 slot3Index = r1.metaObject()->indexOfSlot(slot: "slot3()");
3923
3924 QVERIFY(slot1Index > 0);
3925 QVERIFY(slot2Index > 0);
3926 QVERIFY(slot3Index > 0);
3927
3928 QVERIFY(QMetaObject::connect(&s, signal1Index, &r1, slot1Index));
3929 QVERIFY(QMetaObject::connect(&s, signal3Index, &r2, slot3Index));
3930 QVERIFY(QMetaObject::connect(&s, -1, &r2, slot2Index));
3931
3932 QCOMPARE(r1.count_slot1, 0);
3933 QCOMPARE(r1.count_slot2, 0);
3934 QCOMPARE(r1.count_slot3, 0);
3935 QCOMPARE(r2.count_slot1, 0);
3936 QCOMPARE(r2.count_slot2, 0);
3937 QCOMPARE(r2.count_slot3, 0);
3938
3939 s.emitSignal1();
3940
3941 QCOMPARE(r1.count_slot1, 1);
3942 QCOMPARE(r1.count_slot2, 0);
3943 QCOMPARE(r1.count_slot3, 0);
3944 QCOMPARE(r2.count_slot1, 0);
3945 QCOMPARE(r2.count_slot2, 1);
3946 QCOMPARE(r2.count_slot3, 0);
3947
3948 s.emitSignal2();
3949 s.emitSignal3();
3950 s.emitSignal4();
3951
3952 QCOMPARE(r1.count_slot1, 1);
3953 QCOMPARE(r1.count_slot2, 0);
3954 QCOMPARE(r1.count_slot3, 0);
3955 QCOMPARE(r2.count_slot1, 0);
3956 QCOMPARE(r2.count_slot2, 4);
3957 QCOMPARE(r2.count_slot3, 1);
3958
3959 QVERIFY(QMetaObject::disconnect(&s, signal1Index, &r1, slot1Index));
3960 QVERIFY(QMetaObject::disconnect(&s, signal3Index, &r2, slot3Index));
3961 QVERIFY(QMetaObject::disconnect(&s, -1, &r2, slot2Index));
3962
3963 s.emitSignal1();
3964 s.emitSignal2();
3965 s.emitSignal3();
3966 s.emitSignal4();
3967
3968 QCOMPARE(r1.count_slot1, 1);
3969 QCOMPARE(r1.count_slot2, 0);
3970 QCOMPARE(r1.count_slot3, 0);
3971 QCOMPARE(r2.count_slot1, 0);
3972 QCOMPARE(r2.count_slot2, 4);
3973 QCOMPARE(r2.count_slot3, 1);
3974
3975 //some "dynamic" signal
3976 QVERIFY(QMetaObject::connect(&s, s.metaObject()->methodOffset() + 20, &r1, slot3Index));
3977 QVERIFY(QMetaObject::connect(&s, s.metaObject()->methodOffset() + 35, &r2, slot1Index));
3978 QVERIFY(QMetaObject::connect(&s, -1, &r1, slot2Index));
3979
3980 r1.reset();
3981 r2.reset();
3982
3983 void *args[] = { 0 , 0 };
3984 QMetaObject::activate(sender: &s, signal_index: s.metaObject()->methodOffset() + 20, argv: args);
3985 QMetaObject::activate(sender: &s, signal_index: s.metaObject()->methodOffset() + 48, argv: args);
3986 QCOMPARE(r1.count_slot1, 0);
3987 QCOMPARE(r1.count_slot2, 2);
3988 QCOMPARE(r1.count_slot3, 1);
3989 QCOMPARE(r2.count_slot1, 0);
3990 QCOMPARE(r2.count_slot2, 0);
3991 QCOMPARE(r2.count_slot3, 0);
3992
3993 QMetaObject::activate(sender: &s, signal_index: s.metaObject()->methodOffset() + 35, argv: args);
3994 s.emitSignal1();
3995 s.emitSignal2();
3996
3997 QCOMPARE(r1.count_slot1, 0);
3998 QCOMPARE(r1.count_slot2, 5);
3999 QCOMPARE(r1.count_slot3, 1);
4000 QCOMPARE(r2.count_slot1, 1);
4001 QCOMPARE(r2.count_slot2, 0);
4002 QCOMPARE(r2.count_slot3, 0);
4003 }
4004
4005 r1.reset();
4006 r2.reset();
4007
4008#define SIGNAL_INDEX(S) obj1.metaObject()->indexOfSignal(QMetaObject::normalizedSignature(#S))
4009 OverloadObject obj1;
4010 QObject obj2, obj3;
4011
4012 QMetaObject::connect(sender: &obj1, SIGNAL_INDEX(sig(int)) , receiver: &r1, method_index: slot1Index);
4013 QMetaObject::connect(sender: &obj1, SIGNAL_INDEX(sig(QObject *, QObject *, QObject *)) ,
4014 receiver: &r2, method_index: slot1Index);
4015
4016 QMetaObject::connect(sender: &obj1, SIGNAL_INDEX(sig(QObject *, QObject *, QObject *, QObject *)) ,
4017 receiver: &r1, method_index: slot2Index);
4018 QMetaObject::connect(sender: &obj1, SIGNAL_INDEX(sig(QObject *)) , receiver: &r2, method_index: slot2Index);
4019 QMetaObject::connect(sender: &obj1, SIGNAL_INDEX(sig(int, int)) , receiver: &r1, method_index: slot3Index);
4020
4021 emit obj1.sig(r: 0.5); //connected to nothing
4022 emit obj1.sig(i: 1, c: 'a'); //connected to nothing
4023 QCOMPARE(r1.count_slot1, 0);
4024 QCOMPARE(r1.count_slot2, 0);
4025 QCOMPARE(r1.count_slot3, 0);
4026 QCOMPARE(r2.count_slot1, 0);
4027 QCOMPARE(r2.count_slot2, 0);
4028 QCOMPARE(r2.count_slot3, 0);
4029
4030 emit obj1.sig(i: 1); //this signal is connected
4031 emit obj1.sig(o: &obj2);
4032
4033 QCOMPARE(r1.count_slot1, 1);
4034 QCOMPARE(r1.count_slot2, 0);
4035 QCOMPARE(r1.count_slot3, 1);
4036 QCOMPARE(r2.count_slot1, 0);
4037 QCOMPARE(r2.count_slot2, 1);
4038 QCOMPARE(r2.count_slot3, 0);
4039
4040 emit obj1.sig(o: &obj2, p: &obj3); //this signal is connected
4041
4042 QCOMPARE(r1.count_slot1, 1);
4043 QCOMPARE(r1.count_slot2, 1);
4044 QCOMPARE(r1.count_slot3, 1);
4045 QCOMPARE(r2.count_slot1, 1);
4046 QCOMPARE(r2.count_slot2, 1);
4047 QCOMPARE(r2.count_slot3, 0);
4048}
4049
4050void tst_QObject::qMetaObjectDisconnectOne()
4051{
4052 SenderObject s;
4053 ReceiverObject r1;
4054
4055 int signal1Index = s.metaObject()->indexOfSignal(signal: "signal1()");
4056 int signal3Index = s.metaObject()->indexOfSignal(signal: "signal3()");
4057 int slot1Index = r1.metaObject()->indexOfSlot(slot: "slot1()");
4058 int slot2Index = r1.metaObject()->indexOfSlot(slot: "slot2()");
4059
4060 QVERIFY(signal1Index > 0);
4061 QVERIFY(signal3Index > 0);
4062 QVERIFY(slot1Index > 0);
4063 QVERIFY(slot2Index > 0);
4064
4065 QVERIFY(QMetaObject::connect(&s, signal1Index, &r1, slot1Index));
4066 QVERIFY(QMetaObject::connect(&s, signal3Index, &r1, slot2Index));
4067 QVERIFY(QMetaObject::connect(&s, signal3Index, &r1, slot2Index));
4068 QVERIFY(QMetaObject::connect(&s, signal3Index, &r1, slot2Index));
4069
4070 r1.reset();
4071 QCOMPARE(r1.count_slot1, 0);
4072 QCOMPARE(r1.count_slot2, 0);
4073
4074 s.emitSignal1();
4075 QCOMPARE(r1.count_slot1, 1);
4076 QCOMPARE(r1.count_slot2, 0);
4077
4078 s.emitSignal3();
4079 QCOMPARE(r1.count_slot1, 1);
4080 QCOMPARE(r1.count_slot2, 3);
4081
4082 r1.reset();
4083 QVERIFY(QMetaObject::disconnectOne(&s, signal1Index, &r1, slot1Index));
4084 QVERIFY(QMetaObject::disconnectOne(&s, signal3Index, &r1, slot2Index));
4085
4086 s.emitSignal1();
4087 QCOMPARE(r1.count_slot1, 0);
4088 QCOMPARE(r1.count_slot2, 0);
4089
4090 s.emitSignal3();
4091 QCOMPARE(r1.count_slot1, 0);
4092 QCOMPARE(r1.count_slot2, 2);
4093
4094 r1.reset();
4095 QVERIFY(!QMetaObject::disconnectOne(&s, signal1Index, &r1, slot1Index));
4096 QVERIFY( QMetaObject::disconnectOne(&s, signal3Index, &r1, slot2Index));
4097
4098 s.emitSignal1();
4099 QCOMPARE(r1.count_slot1, 0);
4100 QCOMPARE(r1.count_slot2, 0);
4101
4102 s.emitSignal3();
4103 QCOMPARE(r1.count_slot1, 0);
4104 QCOMPARE(r1.count_slot2, 1);
4105
4106 r1.reset();
4107 QVERIFY(!QMetaObject::disconnectOne(&s, signal1Index, &r1, slot1Index));
4108 QVERIFY( QMetaObject::disconnectOne(&s, signal3Index, &r1, slot2Index));
4109
4110 s.emitSignal1();
4111 QCOMPARE(r1.count_slot1, 0);
4112 QCOMPARE(r1.count_slot2, 0);
4113
4114 s.emitSignal3();
4115 QCOMPARE(r1.count_slot1, 0);
4116 QCOMPARE(r1.count_slot2, 0);
4117}
4118
4119class ConfusingObject : public SenderObject
4120{ Q_OBJECT
4121public slots:
4122 void signal1() { s++; }
4123signals:
4124 void aPublicSlot();
4125public:
4126 int s;
4127 ConfusingObject() : s(0) {}
4128 friend class tst_QObject;
4129};
4130
4131void tst_QObject::sameName()
4132{
4133 ConfusingObject c1, c2;
4134 QVERIFY(connect(&c1, SIGNAL(signal1()), &c1, SLOT(signal1())));
4135 c1.emitSignal1();
4136 QCOMPARE(c1.s, 1);
4137
4138 QVERIFY(connect(&c2, SIGNAL(signal1()), &c1, SIGNAL(signal1())));
4139 c2.emitSignal1();
4140 QCOMPARE(c1.s, 2);
4141
4142#ifndef QT_NO_DEBUG
4143 QTest::ignoreMessage(type: QtWarningMsg, message: "QMetaObject::indexOfSignal: signal aPublicSlot() from SenderObject redefined in ConfusingObject");
4144#endif
4145 QVERIFY(connect(&c2, SIGNAL(aPublicSlot()), &c1, SLOT(signal1())));
4146 c2.aPublicSlot();
4147 QCOMPARE(c2.aPublicSlotCalled, 0);
4148 QCOMPARE(c1.aPublicSlotCalled, 0);
4149 QCOMPARE(c1.s, 3);
4150
4151#ifndef QT_NO_DEBUG
4152 QTest::ignoreMessage(type: QtWarningMsg, message: "QMetaObject::indexOfSignal: signal aPublicSlot() from SenderObject redefined in ConfusingObject");
4153#endif
4154 QVERIFY(connect(&c2, SIGNAL(aPublicSlot()), &c1, SLOT(aPublicSlot())));
4155 c2.aPublicSlot();
4156 QCOMPARE(c2.aPublicSlotCalled, 0);
4157 QCOMPARE(c1.aPublicSlotCalled, 1);
4158 QCOMPARE(c1.s, 4);
4159}
4160
4161void tst_QObject::connectByMetaMethods()
4162{
4163 SenderObject s;
4164 ReceiverObject r;
4165 const QMetaObject *smeta = s.metaObject();
4166 const QMetaObject *rmeta = r.metaObject();
4167 int sigIndx = smeta->indexOfSignal(signal: QMetaObject::normalizedSignature(method: "signal1()"));
4168 int slotIndx = rmeta->indexOfSlot(slot: QMetaObject::normalizedSignature(method: "slot1()"));
4169 QVERIFY( sigIndx != -1 );
4170 QVERIFY( slotIndx != -1 );
4171 QMetaMethod signal = smeta->method(index: sigIndx);
4172 QMetaMethod slot = rmeta->method(index: slotIndx);
4173
4174 QVERIFY(connect(&s,signal, &r,slot));
4175
4176 QVERIFY(!r.called(1));
4177 s.emitSignal1();
4178 QVERIFY(r.called(1));
4179}
4180
4181void tst_QObject::connectByMetaMethodSlotInsteadOfSignal()
4182{
4183 SenderObject s;
4184 ReceiverObject r;
4185 const QMetaObject *smeta = s.metaObject();
4186 const QMetaObject *rmeta = r.metaObject();
4187 int badIndx = smeta->indexOfSlot(slot: QMetaObject::normalizedSignature(method: "aPublicSlot()"));
4188 int slotIndx = rmeta->indexOfSlot(slot: QMetaObject::normalizedSignature(method: "slot1()"));
4189 QVERIFY( badIndx != -1 );
4190 QVERIFY( slotIndx != -1 );
4191 QMetaMethod badMethod = smeta->method(index: badIndx);
4192 QMetaMethod slot = rmeta->method(index: slotIndx);
4193
4194 QTest::ignoreMessage(type: QtWarningMsg,message: "QObject::connect: Cannot connect SenderObject::aPublicSlot() to ReceiverObject::slot1()");
4195 QVERIFY(!connect(&s,badMethod, &r,slot));
4196}
4197
4198class Constructable: public QObject
4199{
4200 Q_OBJECT
4201
4202public:
4203 Q_INVOKABLE Constructable(){}
4204
4205};
4206
4207void tst_QObject::connectConstructorByMetaMethod()
4208{
4209 Constructable sc;
4210 Constructable rc;
4211 SenderObject s;
4212 ReceiverObject r;
4213
4214 const QMetaObject cmeta = Constructable::staticMetaObject;
4215 const QMetaObject *smeta = s.metaObject();
4216 const QMetaObject *rmeta = r.metaObject();
4217 int constructorIndx = cmeta.indexOfConstructor(constructor: QMetaObject::normalizedSignature(method: "Constructable()"));
4218 int sigIndx = smeta->indexOfSignal(signal: QMetaObject::normalizedSignature(method: "signal1()"));
4219 int slotIndx = rmeta->indexOfSlot(slot: QMetaObject::normalizedSignature(method: "slot1()"));
4220 QVERIFY( constructorIndx != -1 );
4221 QVERIFY( sigIndx != -1 );
4222 QVERIFY( slotIndx != -1 );
4223
4224 QMetaMethod constructor = cmeta.constructor(index: constructorIndx);
4225 QMetaMethod signal = smeta->method(index: sigIndx);
4226 QMetaMethod slot = rmeta->method(index: slotIndx);
4227
4228 QTest::ignoreMessage(type: QtWarningMsg,message: "QObject::connect: Cannot connect Constructable::Constructable() to ReceiverObject::slot1()");
4229 QVERIFY(!connect(&sc,constructor, &r,slot));
4230 QTest::ignoreMessage(type: QtWarningMsg,message: "QObject::connect: Cannot connect SenderObject::signal1() to Constructable::Constructable()");
4231 QVERIFY(!connect(&s,signal, &rc,constructor));
4232 QTest::ignoreMessage(type: QtWarningMsg,message: "QObject::connect: Cannot connect Constructable::Constructable() to Constructable::Constructable()");
4233 QVERIFY(!connect(&sc,constructor, &rc,constructor));
4234}
4235
4236void tst_QObject::disconnectByMetaMethod()
4237{
4238 SenderObject s;
4239 ReceiverObject r1;
4240 ReceiverObject r2;
4241
4242 QMetaMethod signal1 = s.metaObject()->method(index: s.metaObject()->indexOfMethod(method: "signal1()"));
4243 QMetaMethod signal2 = s.metaObject()->method(index: s.metaObject()->indexOfMethod(method: "signal2()"));
4244 QMetaMethod signal3 = s.metaObject()->method(index: s.metaObject()->indexOfMethod(method: "signal3()"));
4245
4246 QMetaMethod slot1 = r1.metaObject()->method(index: r1.metaObject()->indexOfMethod(method: "slot1()"));
4247 QMetaMethod slot2 = r1.metaObject()->method(index: r1.metaObject()->indexOfMethod(method: "slot2()"));
4248 QMetaMethod slot3 = r1.metaObject()->method(index: r1.metaObject()->indexOfMethod(method: "slot3()"));
4249 QMetaMethod slot4 = r1.metaObject()->method(index: r1.metaObject()->indexOfMethod(method: "slot4()"));
4250
4251 connect(sender: &s, signal: signal1, receiver: &r1, method: slot1);
4252
4253 s.emitSignal1();
4254
4255 QVERIFY(r1.called(1));
4256 r1.reset();
4257
4258 // usual disconnect with all parameters given
4259 bool ret = QObject::disconnect(sender: &s, signal: signal1, receiver: &r1, member: slot1);
4260
4261 s.emitSignal1();
4262
4263 QVERIFY(!r1.called(1));
4264 r1.reset();
4265
4266 QVERIFY(ret);
4267 ret = QObject::disconnect(sender: &s, signal: signal1, receiver: &r1, member: slot1);
4268 QVERIFY(!ret);
4269
4270 r1.reset();
4271
4272 connect(sender: &s, signal: signal1, receiver: &r1, method: slot1);
4273 connect(sender: &s, signal: signal1, receiver: &r1, method: slot2);
4274 connect(sender: &s, signal: signal1, receiver: &r1, method: slot3);
4275 connect(sender: &s, signal: signal2, receiver: &r1, method: slot4);
4276
4277 // disconnect s's signal1() from all slots of r1
4278 QObject::disconnect(sender: &s, signal: signal1, receiver: &r1, member: QMetaMethod());
4279
4280 s.emitSignal1();
4281 s.emitSignal2();
4282
4283 QVERIFY(!r1.called(1));
4284 QVERIFY(!r1.called(2));
4285 QVERIFY(!r1.called(3));
4286 QVERIFY(r1.called(4));
4287 r1.reset();
4288 // make sure all is disconnected again
4289 QObject::disconnect(sender: &s, signal: 0, receiver: &r1, member: 0);
4290
4291 connect(sender: &s, signal: signal1, receiver: &r1, method: slot1);
4292 connect(sender: &s, signal: signal1, receiver: &r2, method: slot1);
4293 connect(sender: &s, signal: signal2, receiver: &r1, method: slot2);
4294 connect(sender: &s, signal: signal2, receiver: &r2, method: slot2);
4295 connect(sender: &s, signal: signal3, receiver: &r1, method: slot3);
4296 connect(sender: &s, signal: signal3, receiver: &r2, method: slot3);
4297
4298 // disconnect signal1() from all receivers
4299 QObject::disconnect(sender: &s, signal: signal1, receiver: 0, member: QMetaMethod());
4300 s.emitSignal1();
4301 s.emitSignal2();
4302 s.emitSignal3();
4303
4304 QVERIFY(!r1.called(1));
4305 QVERIFY(!r2.called(1));
4306 QVERIFY(r1.called(2));
4307 QVERIFY(r2.called(2));
4308 QVERIFY(r1.called(2));
4309 QVERIFY(r2.called(2));
4310
4311 r1.reset();
4312 r2.reset();
4313
4314 // disconnect all signals of s from all receivers
4315 QObject::disconnect(sender: &s, signal: 0, receiver: 0, member: 0);
4316
4317 connect(sender: &s, signal: signal1, receiver: &r1, method: slot1);
4318 connect(sender: &s, signal: signal1, receiver: &r2, method: slot1);
4319
4320 // disconnect all signals from slot1 of r1
4321 QObject::disconnect(sender: &s, signal: QMetaMethod(), receiver: &r1, member: slot1);
4322
4323 s.emitSignal1();
4324
4325 QVERIFY(!r1.called(1));
4326 QVERIFY(r2.called(1));
4327}
4328
4329void tst_QObject::disconnectNotSignalMetaMethod()
4330{
4331 SenderObject s;
4332 ReceiverObject r;
4333
4334 connect(sender: &s, SIGNAL(signal1()), receiver: &r, SLOT(slot1()));
4335
4336 QMetaMethod slot = s.metaObject()->method(
4337 index: s.metaObject()->indexOfMethod(method: "aPublicSlot()"));
4338
4339 QTest::ignoreMessage(type: QtWarningMsg,message: "QObject::disconnect: Attempt to unbind non-signal SenderObject::aPublicSlot()");
4340 QVERIFY(!QObject::disconnect(&s, slot, &r, QMetaMethod()));
4341}
4342
4343class ThreadAffinityThread : public QThread
4344{
4345public:
4346 SenderObject *sender;
4347
4348 ThreadAffinityThread(SenderObject *sender)
4349 : sender(sender)
4350 { }
4351 void run()
4352 {
4353 sender->emitSignal1();
4354 }
4355};
4356
4357void tst_QObject::autoConnectionBehavior()
4358{
4359 SenderObject *sender = new SenderObject;
4360 ReceiverObject *receiver = new ReceiverObject;
4361 connect(sender, SIGNAL(signal1()), receiver, SLOT(slot1()));
4362
4363 // at emit, currentThread == sender->thread(), currentThread == receiver->thread(), sender->thread() == receiver->thread()
4364 QVERIFY(!receiver->called(1));
4365 sender->emitSignal1();
4366 QVERIFY(receiver->called(1));
4367 receiver->reset();
4368
4369 // at emit, currentThread != sender->thread(), currentThread != receiver->thread(), sender->thread() == receiver->thread()
4370 ThreadAffinityThread emitThread1(sender);
4371 QVERIFY(!receiver->called(1));
4372 emitThread1.start();
4373 QVERIFY(emitThread1.wait(30000));
4374 QVERIFY(!receiver->called(1));
4375 QCoreApplication::sendPostedEvents(receiver, event_type: QEvent::MetaCall);
4376 QVERIFY(receiver->called(1));
4377 receiver->reset();
4378
4379 // at emit, currentThread == sender->thread(), currentThread != receiver->thread(), sender->thread() != receiver->thread()
4380 sender->moveToThread(thread: &emitThread1);
4381 QVERIFY(!receiver->called(1));
4382 emitThread1.start();
4383 QVERIFY(emitThread1.wait(30000));
4384 QVERIFY(!receiver->called(1));
4385 QCoreApplication::sendPostedEvents(receiver, event_type: QEvent::MetaCall);
4386 QVERIFY(receiver->called(1));
4387 receiver->reset();
4388
4389 // at emit, currentThread != sender->thread(), currentThread == receiver->thread(), sender->thread() != receiver->thread()
4390 QVERIFY(!receiver->called(1));
4391 sender->emitSignal1();
4392 QVERIFY(receiver->called(1));
4393 receiver->reset();
4394
4395 // at emit, currentThread != sender->thread(), currentThread != receiver->thread(), sender->thread() != receiver->thread()
4396 ThreadAffinityThread emitThread2(sender);
4397 QThread receiverThread;
4398 QTimer *timer = new QTimer;
4399 timer->setSingleShot(true);
4400 timer->setInterval(100);
4401 connect(sender: &receiverThread, SIGNAL(started()), receiver: timer, SLOT(start()));
4402 connect(sender: timer, SIGNAL(timeout()), receiver: &receiverThread, SLOT(quit()), Qt::DirectConnection);
4403 connect(sender: &receiverThread, SIGNAL(finished()), receiver: timer, SLOT(deleteLater()));
4404 timer->moveToThread(thread: &receiverThread);
4405
4406 receiver->moveToThread(thread: &receiverThread);
4407 QVERIFY(!receiver->called(1));
4408 emitThread2.start();
4409 QVERIFY(emitThread2.wait(30000));
4410 QVERIFY(!receiver->called(1));
4411 receiverThread.start();
4412 QVERIFY(receiverThread.wait(30000));
4413 QVERIFY(receiver->called(1));
4414 receiver->reset();
4415
4416 delete sender;
4417 delete receiver;
4418}
4419
4420class BaseDestroyed : public QObject
4421{ Q_OBJECT
4422 QList<QString> fooList;
4423 bool destroyed;
4424public:
4425 BaseDestroyed() : destroyed(false)
4426 { fooList << "a" << "b"; }
4427 ~BaseDestroyed()
4428 {
4429 QVERIFY(!destroyed);
4430 destroyed = true;
4431 }
4432
4433public slots:
4434 void slotUseList()
4435 {
4436 QVERIFY(!destroyed);
4437 fooList << "c" << "d";
4438 }
4439};
4440
4441static void processEvents()
4442{
4443 qApp->processEvents();
4444}
4445
4446void tst_QObject::baseDestroyed()
4447{
4448 {
4449 BaseDestroyed d;
4450 connect(sender: &d, SIGNAL(destroyed()), receiver: &d, SLOT(slotUseList()));
4451 //When d goes out of scope, slotUseList should not be called as the BaseDestroyed has
4452 // already been destroyed while ~QObject emit destroyed
4453 }
4454 {
4455 BaseDestroyed d;
4456 connect(sender: &d, signal: &QObject::destroyed, slot: processEvents);
4457 QMetaObject::invokeMethod(obj: &d, member: "slotUseList", type: Qt::QueuedConnection);
4458 //the destructor will call processEvents, that should not call the slotUseList
4459 }
4460}
4461
4462void tst_QObject::pointerConnect()
4463{
4464 SenderObject s;
4465 ReceiverObject r1;
4466 ReceiverObject r2;
4467 r1.reset();
4468 r2.reset();
4469 ReceiverObject::sequence = 0;
4470 QTimer timer;
4471
4472 QVERIFY(connect(&s, &SenderObject::signal1 , &r1, &ReceiverObject::slot1));
4473 QVERIFY(connect(&s, &SenderObject::signal1 , &r2, &ReceiverObject::slot1));
4474 QVERIFY(connect(&s, &SenderObject::signal1 , &r1, &ReceiverObject::slot3));
4475 QVERIFY(connect(&s, &SenderObject::signal3 , &r1, &ReceiverObject::slot3));
4476 QVERIFY2(connect(&timer, &QTimer::timeout, &r1, &ReceiverObject::deleteLater),
4477 "Signal connection failed most likely due to failing comparison of pointers to member "
4478 "functions caused by problems with -reduce-relocations on this platform.");
4479
4480 s.emitSignal1();
4481 s.emitSignal2();
4482 s.emitSignal3();
4483 s.emitSignal4();
4484
4485 QCOMPARE(r1.count_slot1, 1);
4486 QCOMPARE(r1.count_slot2, 0);
4487 QCOMPARE(r1.count_slot3, 2);
4488 QCOMPARE(r1.count_slot4, 0);
4489 QCOMPARE(r2.count_slot1, 1);
4490 QCOMPARE(r2.count_slot2, 0);
4491 QCOMPARE(r2.count_slot3, 0);
4492 QCOMPARE(r2.count_slot4, 0);
4493 QCOMPARE(r1.sequence_slot1, 1);
4494 QCOMPARE(r2.sequence_slot1, 2);
4495 QCOMPARE(r1.sequence_slot3, 4);
4496
4497 r1.reset();
4498 r2.reset();
4499 ReceiverObject::sequence = 0;
4500
4501 QVERIFY(connect(&s, &SenderObject::signal4, &r1, &ReceiverObject::slot4));
4502 QVERIFY(connect(&s, &SenderObject::signal4, &r2, &ReceiverObject::slot4));
4503 QVERIFY(connect(&s, &SenderObject::signal1, &r2, &ReceiverObject::slot4));
4504
4505 s.emitSignal4();
4506 QCOMPARE(r1.count_slot4, 1);
4507 QCOMPARE(r2.count_slot4, 1);
4508 QCOMPARE(r1.sequence_slot4, 1);
4509 QCOMPARE(r2.sequence_slot4, 2);
4510
4511 r1.reset();
4512 r2.reset();
4513 ReceiverObject::sequence = 0;
4514
4515 connect(sender: &s, signal: &SenderObject::signal4 , receiver: &r1, slot: &ReceiverObject::slot4);
4516
4517 s.emitSignal4();
4518 QCOMPARE(r1.count_slot4, 2);
4519 QCOMPARE(r2.count_slot4, 1);
4520 QCOMPARE(r1.sequence_slot4, 3);
4521 QCOMPARE(r2.sequence_slot4, 2);
4522
4523 QMetaObject::Connection con;
4524 QVERIFY(!con);
4525 QVERIFY(!QObject::disconnect(con));
4526
4527 //connect a slot to a signal (== error)
4528 QTest::ignoreMessage(type: QtWarningMsg, message: "QObject::connect: signal not found in ReceiverObject");
4529 con = connect(sender: &r1, signal: &ReceiverObject::slot4 , receiver: &s, slot: &SenderObject::signal4);
4530 QVERIFY(!con);
4531 QVERIFY(!QObject::disconnect(con));
4532}
4533
4534void tst_QObject::pointerDisconnect()
4535{
4536 SenderObject s;
4537 ReceiverObject r1;
4538 ReceiverObject r2;
4539
4540 connect(sender: &s, signal: &SenderObject::signal1, receiver: &r1, slot: &ReceiverObject::slot1);
4541
4542 connect(sender: &s, signal: &SenderObject::signal2, receiver: &r1, slot: &ReceiverObject::slot2);
4543 connect(sender: &s, signal: &SenderObject::signal3, receiver: &r1, slot: &ReceiverObject::slot3);
4544 connect(sender: &s, signal: &SenderObject::signal4, receiver: &r1, slot: &ReceiverObject::slot4);
4545
4546 s.emitSignal1();
4547 s.emitSignal2();
4548 s.emitSignal3();
4549 s.emitSignal4();
4550
4551 QVERIFY(r1.called(1));
4552 QVERIFY(r1.called(2));
4553 QVERIFY(r1.called(3));
4554 QVERIFY(r1.called(4));
4555 r1.reset();
4556
4557 // usual disconnect with all parameters given
4558 bool ret = QObject::disconnect(sender: &s, signal: &SenderObject::signal1, receiver: &r1, slot: &ReceiverObject::slot1);
4559
4560 s.emitSignal1();
4561
4562 QVERIFY(!r1.called(1));
4563 r1.reset();
4564
4565 QVERIFY(ret);
4566 ret = QObject::disconnect(sender: &s, signal: &SenderObject::signal1, receiver: &r1, slot: &ReceiverObject::slot1);
4567 QVERIFY(!ret);
4568
4569 // disconnect all signals from s from all slots from r1
4570 QObject::disconnect(sender: &s, signal: 0, receiver: &r1, member: 0);
4571
4572 s.emitSignal2();
4573 s.emitSignal3();
4574 s.emitSignal4();
4575
4576 QVERIFY(!r1.called(2));
4577 QVERIFY(!r1.called(3));
4578 QVERIFY(!r1.called(4));
4579 r1.reset();
4580
4581 connect(sender: &s, signal: &SenderObject::signal1, receiver: &r1, slot: &ReceiverObject::slot1);
4582 connect(sender: &s, signal: &SenderObject::signal1, receiver: &r1, slot: &ReceiverObject::slot2);
4583 connect(sender: &s, signal: &SenderObject::signal1, receiver: &r1, slot: &ReceiverObject::slot3);
4584 connect(sender: &s, signal: &SenderObject::signal2, receiver: &r1, slot: &ReceiverObject::slot4);
4585
4586 // disconnect s's signal1() from all slots of r1
4587 QObject::disconnect(sender: &s, signal: &SenderObject::signal1, receiver: &r1, zero: 0);
4588
4589 s.emitSignal1();
4590 s.emitSignal2();
4591
4592 QVERIFY(!r1.called(1));
4593 QVERIFY(!r1.called(2));
4594 QVERIFY(!r1.called(3));
4595 QVERIFY(r1.called(4));
4596 r1.reset();
4597 // make sure all is disconnected again
4598 QObject::disconnect(sender: &s, signal: 0, receiver: &r1, member: 0);
4599
4600 connect(sender: &s, signal: &SenderObject::signal1, receiver: &r1, slot: &ReceiverObject::slot1);
4601 connect(sender: &s, signal: &SenderObject::signal1, receiver: &r2, slot: &ReceiverObject::slot1);
4602 connect(sender: &s, signal: &SenderObject::signal2, receiver: &r1, slot: &ReceiverObject::slot2);
4603 connect(sender: &s, signal: &SenderObject::signal2, receiver: &r2, slot: &ReceiverObject::slot2);
4604 connect(sender: &s, signal: &SenderObject::signal3, receiver: &r1, slot: &ReceiverObject::slot3);
4605 connect(sender: &s, signal: &SenderObject::signal3, receiver: &r2, slot: &ReceiverObject::slot3);
4606
4607 // disconnect signal1() from all receivers
4608 QObject::disconnect(sender: &s, signal: &SenderObject::signal1, receiver: 0, zero: 0);
4609 s.emitSignal1();
4610 s.emitSignal2();
4611 s.emitSignal3();
4612
4613 QVERIFY(!r1.called(1));
4614 QVERIFY(!r2.called(1));
4615 QVERIFY(r1.called(2));
4616 QVERIFY(r2.called(2));
4617 QVERIFY(r1.called(2));
4618 QVERIFY(r2.called(2));
4619
4620 r1.reset();
4621 r2.reset();
4622
4623 // disconnect all signals of s from all receivers
4624 QObject::disconnect(sender: &s, signal: 0, receiver: 0, member: 0);
4625
4626 QVERIFY(!r1.called(2));
4627 QVERIFY(!r2.called(2));
4628 QVERIFY(!r1.called(2));
4629 QVERIFY(!r2.called(2));
4630}
4631
4632
4633void tst_QObject::emitInDefinedOrderPointer()
4634{
4635 SenderObject sender;
4636 ReceiverObject receiver1, receiver2, receiver3, receiver4;
4637
4638 QMetaObject::Connection h0 = connect(sender: &sender, signal: &SenderObject::signal1, receiver: &receiver1, slot: &SequenceObject::slot1);
4639 QMetaObject::Connection h1 = connect(sender: &sender, signal: &SenderObject::signal1, receiver: &receiver2, slot: &SequenceObject::slot1);
4640 QVERIFY(h0);
4641 QVERIFY(h1);
4642 connect(sender: &sender, signal: &SenderObject::signal1, receiver: &receiver3, slot: &SequenceObject::slot1);
4643 connect(sender: &sender, signal: &SenderObject::signal1, receiver: &receiver4, slot: &SequenceObject::slot1);
4644 connect(sender: &sender, signal: &SenderObject::signal1, receiver: &receiver1, slot: &SequenceObject::slot2);
4645 connect(sender: &sender, signal: &SenderObject::signal1, receiver: &receiver2, slot: &SequenceObject::slot2);
4646 connect(sender: &sender, signal: &SenderObject::signal1, receiver: &receiver3, slot: &SequenceObject::slot2);
4647 connect(sender: &sender, signal: &SenderObject::signal1, receiver: &receiver4, slot: &SequenceObject::slot2);
4648
4649 int sequence;
4650 ReceiverObject::sequence = sequence = 0;
4651 sender.emitSignal1();
4652 QCOMPARE(receiver1.sequence_slot1, ++sequence);
4653 QCOMPARE(receiver2.sequence_slot1, ++sequence);
4654 QCOMPARE(receiver3.sequence_slot1, ++sequence);
4655 QCOMPARE(receiver4.sequence_slot1, ++sequence);
4656 QCOMPARE(receiver1.sequence_slot2, ++sequence);
4657 QCOMPARE(receiver2.sequence_slot2, ++sequence);
4658 QCOMPARE(receiver3.sequence_slot2, ++sequence);
4659 QCOMPARE(receiver4.sequence_slot2, ++sequence);
4660
4661 QObject::disconnect(h1);
4662 h1 = connect(sender: &sender, signal: &SenderObject::signal1, receiver: &receiver2, slot: &SequenceObject::slot1);
4663
4664 ReceiverObject::sequence = sequence = 0;
4665 sender.emitSignal1();
4666 QCOMPARE(receiver1.sequence_slot1, ++sequence);
4667 QCOMPARE(receiver3.sequence_slot1, ++sequence);
4668 QCOMPARE(receiver4.sequence_slot1, ++sequence);
4669 QCOMPARE(receiver1.sequence_slot2, ++sequence);
4670 QCOMPARE(receiver2.sequence_slot2, ++sequence);
4671 QCOMPARE(receiver3.sequence_slot2, ++sequence);
4672 QCOMPARE(receiver4.sequence_slot2, ++sequence);
4673 QCOMPARE(receiver2.sequence_slot1, ++sequence);
4674
4675 QObject::disconnect(h0);
4676 h0 = connect(sender: &sender, signal: &SenderObject::signal1, receiver: &receiver1, slot: &SequenceObject::slot1);
4677
4678 ReceiverObject::sequence = sequence = 0;
4679 sender.emitSignal1();
4680 QCOMPARE(receiver3.sequence_slot1, ++sequence);
4681 QCOMPARE(receiver4.sequence_slot1, ++sequence);
4682 QCOMPARE(receiver1.sequence_slot2, ++sequence);
4683 QCOMPARE(receiver2.sequence_slot2, ++sequence);
4684 QCOMPARE(receiver3.sequence_slot2, ++sequence);
4685 QCOMPARE(receiver4.sequence_slot2, ++sequence);
4686 QCOMPARE(receiver2.sequence_slot1, ++sequence);
4687 QCOMPARE(receiver1.sequence_slot1, ++sequence);
4688
4689 QVERIFY(QObject::disconnect(h0));
4690 QVERIFY(!QObject::disconnect(h0));
4691}
4692
4693
4694void tst_QObject::customTypesPointer()
4695{
4696 CustomType t0;
4697 CustomType t1(1, 2, 3);
4698 CustomType t2(2, 3, 4);
4699
4700 {
4701 QCustomTypeChecker checker;
4702 QCOMPARE(instanceCount, 4);
4703
4704 connect(sender: &checker, signal: &QCustomTypeChecker::signal1, receiver: &checker, slot: &QCustomTypeChecker::slot1,
4705 type: Qt::DirectConnection);
4706 QCOMPARE(checker.received.value(), 0);
4707 checker.doEmit(ct: t1);
4708 QCOMPARE(checker.received.value(), t1.value());
4709 checker.received = t0;
4710
4711
4712 checker.disconnect();
4713
4714 int idx = qRegisterMetaType<CustomType>(typeName: "CustomType");
4715 QCOMPARE(QMetaType::type("CustomType"), idx);
4716
4717 connect(sender: &checker, signal: &QCustomTypeChecker::signal1, receiver: &checker, slot: &QCustomTypeChecker::slot1,
4718 type: Qt::QueuedConnection);
4719 QCOMPARE(instanceCount, 4);
4720 checker.doEmit(ct: t2);
4721 QCOMPARE(instanceCount, 5);
4722 QCOMPARE(checker.received.value(), t0.value());
4723
4724 QCoreApplication::processEvents();
4725 QCOMPARE(checker.received.value(), t2.value());
4726 QCOMPARE(instanceCount, 4);
4727
4728 QVERIFY(QMetaType::isRegistered(idx));
4729 QCOMPARE(qRegisterMetaType<CustomType>("CustomType"), idx);
4730 QCOMPARE(QMetaType::type("CustomType"), idx);
4731 QVERIFY(QMetaType::isRegistered(idx));
4732
4733 // Test auto registered type (QList<CustomType>)
4734 QList<CustomType> list;
4735 QCOMPARE(instanceCount, 4);
4736 list.append(t: t1);
4737 QCOMPARE(instanceCount, 5);
4738 QVERIFY(connect(&checker, &QCustomTypeChecker::signal2,
4739 &checker, &QCustomTypeChecker::slot2, Qt::QueuedConnection));
4740 emit checker.signal2(ct: list);
4741 QCOMPARE(instanceCount, 5); //because the list is implicitly shared.
4742 list.clear();
4743 QCOMPARE(instanceCount, 5);
4744 QCoreApplication::processEvents();
4745 QCOMPARE(checker.received.value(), t1.value());
4746 QCOMPARE(instanceCount, 4);
4747 }
4748 QCOMPARE(instanceCount, 3);
4749}
4750
4751void tst_QObject::connectCxx0x()
4752{
4753 SenderObject s;
4754 ReceiverObject r1;
4755
4756 QObject::connect(sender: &s, signal: &SenderObject::signal1, receiver: &r1, slot: &ReceiverObject::slot1);
4757 QObject::connect(sender: &s, signal: &SenderObject::signal3, receiver: &r1, slot: &ReceiverObject::slot2);
4758 QObject::connect(sender: &s, signal: &SenderObject::signal3, receiver: &r1, slot: &ReceiverObject::slot2);
4759 QObject::connect(sender: &s, signal: &SenderObject::signal3, receiver: &r1, slot: &ReceiverObject::slot2);
4760
4761 r1.reset();
4762 QCOMPARE(r1.count_slot1, 0);
4763 QCOMPARE(r1.count_slot2, 0);
4764
4765 s.emitSignal1();
4766 QCOMPARE(r1.count_slot1, 1);
4767 QCOMPARE(r1.count_slot2, 0);
4768
4769 s.emitSignal3();
4770 QCOMPARE(r1.count_slot1, 1);
4771 QCOMPARE(r1.count_slot2, 3);
4772
4773 // connect signal to signal
4774 QObject::connect(sender: &s, signal: &SenderObject::signal2, receiver: &s, slot: &SenderObject::signal1);
4775
4776 r1.reset();
4777 s.emitSignal2();
4778 QCOMPARE(r1.count_slot1, 1);
4779}
4780
4781int receivedCount;
4782void receiverFunction() { ++receivedCount; }
4783
4784void tst_QObject::connectToStaticCxx0x()
4785{
4786 SenderObject *s = new SenderObject;
4787
4788 void (*receiver)() = receiverFunction;
4789
4790 QObject::connect(sender: s, signal: &SenderObject::signal1, slot: receiver);
4791 receivedCount = 0;
4792 s->emitSignal1();
4793 QCOMPARE(receivedCount, 1);
4794
4795 QObject::connect(sender: s, signal: &SenderObject::signal1, slot: receiver);
4796 receivedCount = 0;
4797 s->emitSignal1();
4798 QCOMPARE(receivedCount, 2);
4799
4800 delete s;
4801}
4802
4803class LotsOfSignalsAndSlots: public QObject
4804{
4805 Q_OBJECT
4806 typedef void (*fptr)();
4807
4808 public slots:
4809 void slot_v() {}
4810 void slot_v_noexcept() noexcept {}
4811 void slot_vi(int) {}
4812 void slot_vi_noexcept() noexcept {}
4813 void slot_vii(int, int) {}
4814 void slot_viii(int, int, int) {}
4815 int slot_i() { return 0; }
4816 int slot_i_noexcept() noexcept { return 0; }
4817 int slot_ii(int) { return 0; }
4818 int slot_iii(int, int) { return 0; }
4819 int slot_iiii(int, int, int) { return 0; }
4820 void slot_vRi(int &) {}
4821 void slot_vs(short) {}
4822 void slot_vRs(short&) {}
4823 /* #ifdef Q_COMPILER_RVALUE_REFS
4824 void slot_vOi(int &&) {}
4825 void slot_vOs(short &&) {}
4826 #endif*/
4827 void slot_vPFvvE(fptr) {}
4828
4829 void const_slot_v() const {};
4830 void const_slot_v_noexcept() const noexcept {}
4831 void const_slot_vi(int) const {};
4832 void const_slot_vi_noexcept(int) const noexcept {}
4833
4834 static void static_slot_v() {}
4835 static void static_slot_v_noexcept() noexcept {}
4836 static void static_slot_vi(int) {}
4837 static void static_slot_vi_noexcept(int) noexcept {}
4838 static void static_slot_vii(int, int) {}
4839 static void static_slot_viii(int, int, int) {}
4840 static int static_slot_i() { return 0; }
4841 static int static_slot_i_noexcept() noexcept { return 0; }
4842 static int static_slot_ii(int) { return 0; }
4843 static int static_slot_iii(int, int) { return 0; }
4844 static int static_slot_iiii(int, int, int) { return 0; }
4845 static void static_slot_vRi(int &) {}
4846 static void static_slot_vs(short) {}
4847 static void static_slot_vRs(short&) {}
4848/* #if defined(Q_COMPILER_RVALUE_REFS) || defined(QT_ENABLE_CXX0X)
4849 static void static_slot_vOi(int &&) {}
4850 static void static_slot_vOs(short &&) {}
4851 #endif*/
4852 static void static_slot_vPFvvE(fptr) {}
4853
4854 void slot_vcRQObject(const QObject &) {}
4855 void slot_vRQObject(QObject &) {}
4856
4857 signals:
4858 void signal_v();
4859 void signal_vi(int);
4860 void signal_vii(int, int);
4861 void signal_viii(int, int, int);
4862 void signal_vRi(int &);
4863 void signal_vs(short);
4864 void signal_vRs(short &);
4865/* #if defined(Q_COMPILER_RVALUE_REFS) || defined(QT_ENABLE_CXX0X)
4866 void signal_vOi(int &&);
4867 void signal_vOs(short &&);
4868 #endif*/
4869 void signal_vPFvvE(fptr);
4870
4871 void const_signal_v() const;
4872 void const_signal_vi(int) const;
4873
4874 void signal_vcRQObject(const QObject &);
4875 void signal_vRQObject(QObject &);
4876
4877 void signal(short&, short, long long, short);
4878 void otherSignal(const char *);
4879};
4880
4881void tst_QObject::connectCxx0xTypeMatching()
4882{
4883 // this is just about connecting the signals to the slots
4884 // if this fails, this will be a compiler failure
4885 typedef LotsOfSignalsAndSlots Foo;
4886 Foo obj;
4887
4888 // member connects
4889 QObject::connect(sender: &obj, signal: &Foo::signal_v, receiver: &obj, slot: &Foo::slot_v);
4890 QObject::connect(sender: &obj, signal: &Foo::signal_v, receiver: &obj, slot: &Foo::slot_i);
4891
4892 QObject::connect(sender: &obj, signal: &Foo::signal_vi, receiver: &obj, slot: &Foo::slot_v);
4893 QObject::connect(sender: &obj, signal: &Foo::signal_vi, receiver: &obj, slot: &Foo::slot_i);
4894 QObject::connect(sender: &obj, signal: &Foo::signal_vi, receiver: &obj, slot: &Foo::slot_vi);
4895 QObject::connect(sender: &obj, signal: &Foo::signal_vi, receiver: &obj, slot: &Foo::slot_ii);
4896
4897 QObject::connect(sender: &obj, signal: &Foo::signal_vii, receiver: &obj, slot: &Foo::slot_v);
4898 QObject::connect(sender: &obj, signal: &Foo::signal_vii, receiver: &obj, slot: &Foo::slot_i);
4899 QObject::connect(sender: &obj, signal: &Foo::signal_vii, receiver: &obj, slot: &Foo::slot_vi);
4900 QObject::connect(sender: &obj, signal: &Foo::signal_vii, receiver: &obj, slot: &Foo::slot_ii);
4901 QObject::connect(sender: &obj, signal: &Foo::signal_vii, receiver: &obj, slot: &Foo::slot_vii);
4902 QObject::connect(sender: &obj, signal: &Foo::signal_vii, receiver: &obj, slot: &Foo::slot_iii);
4903
4904 QObject::connect(sender: &obj, signal: &Foo::signal_viii, receiver: &obj, slot: &Foo::slot_v);
4905 QObject::connect(sender: &obj, signal: &Foo::signal_viii, receiver: &obj, slot: &Foo::slot_i);
4906 QObject::connect(sender: &obj, signal: &Foo::signal_viii, receiver: &obj, slot: &Foo::slot_vi);
4907 QObject::connect(sender: &obj, signal: &Foo::signal_viii, receiver: &obj, slot: &Foo::slot_ii);
4908 QObject::connect(sender: &obj, signal: &Foo::signal_viii, receiver: &obj, slot: &Foo::slot_vii);
4909 QObject::connect(sender: &obj, signal: &Foo::signal_viii, receiver: &obj, slot: &Foo::slot_iii);
4910 QObject::connect(sender: &obj, signal: &Foo::signal_viii, receiver: &obj, slot: &Foo::slot_viii);
4911 QObject::connect(sender: &obj, signal: &Foo::signal_viii, receiver: &obj, slot: &Foo::slot_iiii);
4912
4913 QObject::connect(sender: &obj, signal: &Foo::signal_vi, receiver: &obj, slot: &Foo::slot_vi); // repeated from above
4914 QObject::connect(sender: &obj, signal: &Foo::signal_vRi, receiver: &obj, slot: &Foo::slot_vi);
4915 QObject::connect(sender: &obj, signal: &Foo::signal_vRi, receiver: &obj, slot: &Foo::slot_vRi);
4916/*#if defined(Q_COMPILER_RVALUE_REFS) || defined(QT_ENABLE_CXX0X)
4917 QObject::connect(&obj, &Foo::signal_vOi, &obj, &Foo::slot_vi);
4918 QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_vOi);
4919 QObject::connect(&obj, &Foo::signal_vRi, &obj, &Foo::slot_vOi);
4920 QObject::connect(&obj, &Foo::signal_vOi, &obj, &Foo::slot_vOi);
4921#endif*/
4922 // these are not supposed to compile:
4923 //QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::slot_vRi);
4924 //QObject::connect(&obj, &Foo::signal_vOi, &obj, &Foo::slot_vRi);
4925
4926 QObject::connect(sender: &obj, signal: &Foo::signal_vs, receiver: &obj, slot: &Foo::slot_vi);
4927 QObject::connect(sender: &obj, signal: &Foo::signal_vRs, receiver: &obj, slot: &Foo::slot_vi);
4928/*#if defined(Q_COMPILER_RVALUE_REFS) || defined(QT_ENABLE_CXX0X)
4929 QObject::connect(&obj, &Foo::signal_vOs, &obj, &Foo::slot_vi);
4930 QObject::connect(&obj, &Foo::signal_vRs, &obj, &Foo::slot_vOi);
4931 QObject::connect(&obj, &Foo::signal_vOs, &obj, &Foo::slot_vOi);
4932 // these are not supposed to compile:
4933 //QObject::connect(&obj, &Foo::signal_vOs, &obj, &Foo::slot_vRi);
4934 //QObject::connect(&obj, &Foo::signal_vRs, &obj, &Foo::slot_vRi);
4935#endif*/
4936
4937 QObject::connect(sender: &obj, signal: &Foo::signal_vPFvvE, receiver: &obj, slot: &Foo::slot_v);
4938 QObject::connect(sender: &obj, signal: &Foo::signal_vPFvvE, receiver: &obj, slot: &Foo::slot_i);
4939 QObject::connect(sender: &obj, signal: &Foo::signal_vPFvvE, receiver: &obj, slot: &Foo::slot_vPFvvE);
4940
4941 QObject::connect(sender: &obj, signal: &Foo::signal_v, slot: &Foo::static_slot_v);
4942 QObject::connect(sender: &obj, signal: &Foo::signal_v, slot: &Foo::static_slot_i);
4943
4944 QObject::connect(sender: &obj, signal: &Foo::signal_vi, slot: &Foo::static_slot_v);
4945 QObject::connect(sender: &obj, signal: &Foo::signal_vi, slot: &Foo::static_slot_i);
4946 QObject::connect(sender: &obj, signal: &Foo::signal_vi, slot: &Foo::static_slot_vi);
4947 QObject::connect(sender: &obj, signal: &Foo::signal_vi, slot: &Foo::static_slot_ii);
4948
4949 QObject::connect(sender: &obj, signal: &Foo::signal_vii, slot: &Foo::static_slot_v);
4950 QObject::connect(sender: &obj, signal: &Foo::signal_vii, slot: &Foo::static_slot_i);
4951 QObject::connect(sender: &obj, signal: &Foo::signal_vii, slot: &Foo::static_slot_vi);
4952 QObject::connect(sender: &obj, signal: &Foo::signal_vii, slot: &Foo::static_slot_ii);
4953 QObject::connect(sender: &obj, signal: &Foo::signal_vii, slot: &Foo::static_slot_vii);
4954 QObject::connect(sender: &obj, signal: &Foo::signal_vii, slot: &Foo::static_slot_iii);
4955
4956 QObject::connect(sender: &obj, signal: &Foo::signal_viii, slot: &Foo::static_slot_v);
4957 QObject::connect(sender: &obj, signal: &Foo::signal_viii, slot: &Foo::static_slot_i);
4958 QObject::connect(sender: &obj, signal: &Foo::signal_viii, slot: &Foo::static_slot_vi);
4959 QObject::connect(sender: &obj, signal: &Foo::signal_viii, slot: &Foo::static_slot_ii);
4960 QObject::connect(sender: &obj, signal: &Foo::signal_viii, slot: &Foo::static_slot_vii);
4961 QObject::connect(sender: &obj, signal: &Foo::signal_viii, slot: &Foo::static_slot_iii);
4962 QObject::connect(sender: &obj, signal: &Foo::signal_viii, slot: &Foo::static_slot_viii);
4963 QObject::connect(sender: &obj, signal: &Foo::signal_viii, slot: &Foo::static_slot_iiii);
4964
4965/*#if defined(Q_COMPILER_RVALUE_REFS) && defined(QT_ENABLE_CXX0X)
4966 QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_vOi);
4967 QObject::connect(&obj, &Foo::signal_vRi, &Foo::static_slot_vi);
4968 QObject::connect(&obj, &Foo::signal_vRi, &Foo::static_slot_vRi);
4969 QObject::connect(&obj, &Foo::signal_vRi, &Foo::static_slot_vOi);
4970 QObject::connect(&obj, &Foo::signal_vOi, &Foo::static_slot_vi);
4971 QObject::connect(&obj, &Foo::signal_vOi, &Foo::static_slot_vOi);
4972 //QObject::connect(&obj, &Foo::signal_vi, &Foo::static_slot_vRi);
4973 //QObject::connect(&obj, &Foo::signal_vOi, &Foo::static_slot_vRi);
4974#endif*/
4975
4976 QObject::connect(sender: &obj, signal: &Foo::signal_vs, slot: &Foo::static_slot_vi);
4977 QObject::connect(sender: &obj, signal: &Foo::signal_vRs, slot: &Foo::static_slot_vi);
4978/*#if defined(Q_COMPILER_RVALUE_REFS) && defined(QT_ENABLE_CXX0X)
4979 QObject::connect(&obj, &Foo::signal_vOs, &Foo::static_slot_vi);
4980 QObject::connect(&obj, &Foo::signal_vRs, &Foo::static_slot_vOi);
4981 QObject::connect(&obj, &Foo::signal_vOs, &Foo::static_slot_vOi);
4982 //QObject::connect(&obj, &Foo::signal_vOs, &Foo::static_slot_vRi);
4983 //QObject::connect(&obj, &Foo::signal_vRs, &Foo::static_slot_vRi);
4984#endif*/
4985 QObject::connect(sender: &obj, signal: &Foo::signal_vPFvvE, slot: &Foo::static_slot_v);
4986 QObject::connect(sender: &obj, signal: &Foo::signal_vPFvvE, slot: &Foo::static_slot_i);
4987 QObject::connect(sender: &obj, signal: &Foo::signal_vPFvvE, slot: &Foo::static_slot_vPFvvE);
4988
4989 QVERIFY(QObject::connect(&obj, &Foo::const_signal_v, &obj, &Foo::const_slot_v));
4990 QVERIFY(QObject::connect(&obj, &Foo::const_signal_vi, &obj, &Foo::const_slot_v));
4991 QVERIFY(QObject::connect(&obj, &Foo::const_signal_vi, &obj, &Foo::slot_vi));
4992 QVERIFY(QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::const_slot_vi));
4993 QVERIFY(QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::const_slot_v));
4994
4995 QVERIFY(QObject::connect(&obj, &Foo::signal_vcRQObject, &obj, &Foo::slot_vcRQObject));
4996 QVERIFY(QObject::connect(&obj, &Foo::signal_vRQObject, &obj, &Foo::slot_vRQObject));
4997 QVERIFY(QObject::connect(&obj, &Foo::signal_vRQObject, &obj, &Foo::slot_vcRQObject));
4998 // QVERIFY(QObject::connect(&obj, &Foo::signal_vcRQObject, &obj, &Foo::slot_vRQObject)); // Should be an error (const& -> &)
4999
5000 QVERIFY(QObject::connect(&obj, &Foo::signal_vRi, &obj, &Foo::slot_vs));
5001
5002}
5003
5004void receiverFunction_noexcept() noexcept {}
5005struct Functor_noexcept { void operator()() noexcept {} };
5006void tst_QObject::connectCxx17Noexcept()
5007{
5008 // this is about connecting signals to slots with the noexcept qualifier
5009 // as semantics changed due to http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html
5010 typedef LotsOfSignalsAndSlots Foo;
5011 Foo obj;
5012
5013 QObject::connect(sender: &obj, signal: &Foo::signal_v, receiver: &obj, slot: &Foo::slot_v_noexcept);
5014 QObject::connect(sender: &obj, signal: &Foo::signal_v, receiver: &obj, slot: &Foo::slot_i_noexcept);
5015 QObject::connect(sender: &obj, signal: &Foo::signal_v, receiver: &obj, slot: &Foo::slot_vi_noexcept);
5016
5017 QObject::connect(sender: &obj, signal: &Foo::signal_vii, slot: &Foo::static_slot_v_noexcept);
5018 QObject::connect(sender: &obj, signal: &Foo::signal_vii, slot: &Foo::static_slot_i_noexcept);
5019 QObject::connect(sender: &obj, signal: &Foo::signal_vii, slot: &Foo::static_slot_vi_noexcept);
5020
5021 QVERIFY(QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::const_slot_vi_noexcept));
5022 QVERIFY(QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::const_slot_v_noexcept));
5023
5024 QObject::connect(sender: &obj, signal: &Foo::signal_v, slot: receiverFunction_noexcept);
5025
5026 Functor_noexcept fn;
5027 QObject::connect(sender: &obj, signal: &Foo::signal_v, slot: fn);
5028}
5029
5030class StringVariant : public QObject
5031{ Q_OBJECT
5032signals:
5033 void stringSignal(const QString &str);
5034public slots:
5035 void variantSlot(const QVariant &v) { var = v; }
5036public:
5037 QVariant var;
5038 friend class tst_QObject;
5039};
5040
5041struct Functor {
5042 QVariant *var;
5043 void operator() (const QVariant &v) {
5044 *var = v;
5045 }
5046};
5047
5048void tst_QObject::connectConvert()
5049{
5050 StringVariant obj;
5051 QVERIFY(connect(&obj, &StringVariant::stringSignal, &obj, &StringVariant::variantSlot));
5052 QString s = QString::fromLatin1(str: "Hello World");
5053 emit obj.stringSignal(str: s);
5054 QCOMPARE(obj.var.toString(), s);
5055 QVERIFY(obj.var.toString().isSharedWith(s));
5056
5057 QVariant var;
5058 Functor f;
5059 f.var = &var;
5060 QVERIFY(connect(&obj, &StringVariant::stringSignal, f));
5061 s = QString::fromLatin1(str: "GoodBye");
5062 emit obj.stringSignal(str: s);
5063 QCOMPARE(obj.var.toString(), s);
5064 QVERIFY(obj.var.toString().isSharedWith(s));
5065 QCOMPARE(var, obj.var);
5066}
5067
5068class ConnectWithReferenceObject : public QObject {
5069 Q_OBJECT
5070 friend class tst_QObject;
5071signals:
5072 void boolRef(bool &, bool);
5073 void stringRef(QString &, const QString &);
5074 void boolPtr(bool *, bool);
5075 void stringPtr(QString *, const QString &);
5076public slots:
5077 void boolRefSlot(bool &b1, bool b2) { b1 = b2; }
5078 void stringRefSlot(QString &s1, const QString &s2) { s1 = s2; }
5079 void boolPtrSlot(bool *b1, bool b2) { *b1 = b2; }
5080 void stringPtrSlot(QString *s1, const QString &s2) { *s1 = s2; }
5081
5082 void stringSlot1(QString s) { last = s; }
5083 void stringSlot2(const QString &s) { last = s; }
5084 void stringSlot3(QString &s) { last = s; }
5085public:
5086 QString last;
5087};
5088
5089void tst_QObject::connectWithReference()
5090{
5091 ConnectWithReferenceObject o;
5092 bool b1 = true;
5093 QString s1 = QString::fromLatin1(str: "str1");
5094 const QString s2 = QString::fromLatin1(str: "str2");
5095 const QString s3 = QString::fromLatin1(str: "str3");
5096 o.boolRef(b1, false);
5097 o.stringRef(s1, s2);
5098 QCOMPARE(b1, true);
5099 QCOMPARE(s1, QString::fromLatin1("str1"));
5100 o.boolPtr(&b1, false);
5101 o.stringPtr(&s1, s2);
5102 QCOMPARE(b1, true);
5103 QCOMPARE(s1, QString::fromLatin1("str1"));
5104
5105 QVERIFY(connect(&o, &ConnectWithReferenceObject::boolRef, &o, &ConnectWithReferenceObject::boolRefSlot));
5106 QVERIFY(connect(&o, &ConnectWithReferenceObject::stringRef, &o, &ConnectWithReferenceObject::stringRefSlot));
5107 QVERIFY(connect(&o, &ConnectWithReferenceObject::boolPtr, &o, &ConnectWithReferenceObject::boolPtrSlot));
5108 QVERIFY(connect(&o, &ConnectWithReferenceObject::stringPtr, &o, &ConnectWithReferenceObject::stringPtrSlot));
5109 o.boolRef(b1, false);
5110 o.stringRef(s1, s2);
5111 QCOMPARE(b1, false);
5112 QCOMPARE(s1, QString::fromLatin1("str2"));
5113
5114 o.boolPtr(&b1, true);
5115 o.stringPtr(&s1, s3);
5116 QCOMPARE(b1, true);
5117 QCOMPARE(s1, QString::fromLatin1("str3"));
5118
5119 {
5120 ConnectWithReferenceObject o2;
5121 QVERIFY(connect(&o2, &ConnectWithReferenceObject::stringRef, &o2, &ConnectWithReferenceObject::stringSlot1));
5122 o2.stringRef(s1, s2);
5123 QCOMPARE(s1, s3);
5124 QCOMPARE(o2.last, s3);
5125 }
5126 {
5127 ConnectWithReferenceObject o2;
5128 QVERIFY(connect(&o2, &ConnectWithReferenceObject::stringRef, &o2, &ConnectWithReferenceObject::stringSlot2));
5129 o2.stringRef(s1, s2);
5130 QCOMPARE(s1, s3);
5131 QCOMPARE(o2.last, s3);
5132 }
5133 {
5134 ConnectWithReferenceObject o2;
5135 QVERIFY(connect(&o2, &ConnectWithReferenceObject::stringRef, &o2, &ConnectWithReferenceObject::stringSlot3));
5136 o2.stringRef(s1, s2);
5137 QCOMPARE(s1, s3);
5138 QCOMPARE(o2.last, s3);
5139 }
5140}
5141
5142class ManyArgumentObject : public QObject {
5143 Q_OBJECT
5144signals:
5145 void signal1(const QString &);
5146 void signal2(const QString &, const QString &);
5147 void signal3(const QString &, const QString &, const QString &);
5148 void signal4(const QString &, const QString &, const QString &, const QString&);
5149 void signal5(const QString &, const QString &, const QString &, const QString&, const QString&);
5150 void signal6(const QString &, const QString &, const QString &, const QString&, const QString&, const QString&);
5151
5152public slots:
5153#define MANYARGUMENT_COMPARE(L) QCOMPARE(L, QString(#L))
5154 void slot1(const QString &a) {
5155 MANYARGUMENT_COMPARE(a);
5156 count++;
5157 }
5158 void slot2(const QString &a, const QString &b) {
5159 MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b);
5160 count++;
5161 }
5162 void slot3(const QString &a, const QString &b, const QString &c) {
5163 MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c);
5164 count++;
5165 }
5166 void slot4(const QString &a, const QString &b, const QString &c, const QString&d) {
5167 MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c);
5168 MANYARGUMENT_COMPARE(d);
5169 count++;
5170 }
5171 void slot5(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e) {
5172 MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c);
5173 MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e);
5174 count++;
5175 }
5176 void slot6(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e, const QString&f) {
5177 MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c);
5178 MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); MANYARGUMENT_COMPARE(f);
5179 count++;
5180 }
5181public:
5182 int count;
5183
5184};
5185
5186namespace ManyArgumentNamespace {
5187 int count;
5188 void slot1(const QString &a) {
5189 MANYARGUMENT_COMPARE(a);
5190 count++;
5191 }
5192 void slot2(const QString &a, const QString &b) {
5193 MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b);
5194 count++;
5195 }
5196 void slot3(const QString &a, const QString &b, const QString &c) {
5197 MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c);
5198 count++;
5199 }
5200 void slot4(const QString &a, const QString &b, const QString &c, const QString&d) {
5201 MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c);
5202 MANYARGUMENT_COMPARE(d);
5203 count++;
5204 }
5205 void slot5(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e) {
5206 MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c);
5207 MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e);
5208 count++;
5209 }
5210 void slot6(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e, const QString&f) {
5211 MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c);
5212 MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); MANYARGUMENT_COMPARE(f);
5213 count++;
5214 }
5215
5216 struct Funct1 {
5217 void operator()(const QString &a) {
5218 MANYARGUMENT_COMPARE(a);
5219 count++;
5220 }
5221 };
5222
5223 struct Funct2 {
5224 void operator()(const QString &a, const QString &b) {
5225 MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b);
5226 count++;
5227 }
5228 };
5229
5230 struct Funct3 {
5231 void operator()(const QString &a, const QString &b, const QString &c) {
5232 MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c);
5233 count++;
5234 }
5235 };
5236
5237 struct Funct4 {
5238 void operator()(const QString &a, const QString &b, const QString &c, const QString&d) {
5239 MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c);
5240 MANYARGUMENT_COMPARE(d);
5241 count++;
5242 }
5243 };
5244
5245 struct Funct5 {
5246 void operator()(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e) {
5247 MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c);
5248 MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e);
5249 count++;
5250 }
5251 };
5252
5253 struct Funct6 {
5254 void operator()(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e, const QString&f) {
5255 MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c);
5256 MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); MANYARGUMENT_COMPARE(f);
5257 count++;
5258 }
5259 };
5260}
5261
5262void tst_QObject::connectManyArguments()
5263{
5264 ManyArgumentObject ob;
5265 ob.count = 0;
5266 ManyArgumentNamespace::count = 0;
5267 connect(sender: &ob, signal: &ManyArgumentObject::signal1, receiver: &ob, slot: &ManyArgumentObject::slot1);
5268 connect(sender: &ob, signal: &ManyArgumentObject::signal2, receiver: &ob, slot: &ManyArgumentObject::slot2);
5269 connect(sender: &ob, signal: &ManyArgumentObject::signal3, receiver: &ob, slot: &ManyArgumentObject::slot3);
5270 connect(sender: &ob, signal: &ManyArgumentObject::signal4, receiver: &ob, slot: &ManyArgumentObject::slot4);
5271 connect(sender: &ob, signal: &ManyArgumentObject::signal5, receiver: &ob, slot: &ManyArgumentObject::slot5);
5272 connect(sender: &ob, signal: &ManyArgumentObject::signal6, receiver: &ob, slot: &ManyArgumentObject::slot6);
5273 connect(sender: &ob, signal: &ManyArgumentObject::signal1, slot: ManyArgumentNamespace::slot1);
5274 connect(sender: &ob, signal: &ManyArgumentObject::signal2, slot: ManyArgumentNamespace::slot2);
5275 connect(sender: &ob, signal: &ManyArgumentObject::signal3, slot: ManyArgumentNamespace::slot3);
5276 connect(sender: &ob, signal: &ManyArgumentObject::signal4, slot: ManyArgumentNamespace::slot4);
5277 connect(sender: &ob, signal: &ManyArgumentObject::signal5, slot: ManyArgumentNamespace::slot5);
5278 connect(sender: &ob, signal: &ManyArgumentObject::signal6, slot: ManyArgumentNamespace::slot6);
5279
5280
5281 connect(sender: &ob, signal: &ManyArgumentObject::signal6, receiver: &ob, slot: &ManyArgumentObject::signal5);
5282 connect(sender: &ob, signal: &ManyArgumentObject::signal5, receiver: &ob, slot: &ManyArgumentObject::signal4);
5283 connect(sender: &ob, signal: &ManyArgumentObject::signal4, receiver: &ob, slot: &ManyArgumentObject::signal3);
5284 connect(sender: &ob, signal: &ManyArgumentObject::signal3, receiver: &ob, slot: &ManyArgumentObject::signal2);
5285 connect(sender: &ob, signal: &ManyArgumentObject::signal2, receiver: &ob, slot: &ManyArgumentObject::signal1);
5286
5287 emit ob.signal6("a", "b", "c", "d", "e", "f");
5288 QCOMPARE(ob.count, 6);
5289 QCOMPARE(ManyArgumentNamespace::count, 6);
5290
5291
5292 ManyArgumentObject ob2;
5293 ob2.count = 0;
5294 ManyArgumentNamespace::count = 0;
5295 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, receiver: &ob2, slot: &ManyArgumentObject::slot1);
5296 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, receiver: &ob2, slot: &ManyArgumentObject::slot2);
5297 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, receiver: &ob2, slot: &ManyArgumentObject::slot3);
5298 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, receiver: &ob2, slot: &ManyArgumentObject::slot4);
5299 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, receiver: &ob2, slot: &ManyArgumentObject::slot5);
5300 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, receiver: &ob2, slot: &ManyArgumentObject::slot6);
5301 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, slot: ManyArgumentNamespace::slot1);
5302 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, slot: ManyArgumentNamespace::slot2);
5303 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, slot: ManyArgumentNamespace::slot3);
5304 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, slot: ManyArgumentNamespace::slot4);
5305 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, slot: ManyArgumentNamespace::slot5);
5306 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, slot: ManyArgumentNamespace::slot6);
5307 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, slot: ManyArgumentNamespace::Funct1());
5308 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, slot: ManyArgumentNamespace::Funct2());
5309 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, slot: ManyArgumentNamespace::Funct3());
5310 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, slot: ManyArgumentNamespace::Funct4());
5311 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, slot: ManyArgumentNamespace::Funct5());
5312 connect(sender: &ob2, signal: &ManyArgumentObject::signal6, slot: ManyArgumentNamespace::Funct6());
5313
5314 emit ob2.signal6("a", "b", "c", "d", "e", "f");
5315 QCOMPARE(ob2.count, 6);
5316 QCOMPARE(ManyArgumentNamespace::count, 12);
5317}
5318
5319class ForwardDeclared;
5320
5321class ForwardDeclareArguments : public QObject
5322{
5323 Q_OBJECT
5324signals:
5325 void mySignal(const ForwardDeclared&);
5326public slots:
5327 void mySlot(const ForwardDeclared&) {}
5328};
5329
5330void tst_QObject::connectForwardDeclare()
5331{
5332 ForwardDeclareArguments ob;
5333 // it should compile
5334 QVERIFY(connect(&ob, &ForwardDeclareArguments::mySignal, &ob, &ForwardDeclareArguments::mySlot, Qt::QueuedConnection));
5335}
5336
5337class NoDefaultConstructor
5338{
5339 Q_GADGET
5340public:
5341 NoDefaultConstructor(int) {}
5342};
5343
5344class NoDefaultContructorArguments : public QObject
5345{
5346 Q_OBJECT
5347signals:
5348 void mySignal(const NoDefaultConstructor&);
5349public slots:
5350 void mySlot(const NoDefaultConstructor&) {}
5351};
5352
5353void tst_QObject::connectNoDefaultConstructorArg()
5354{
5355 NoDefaultContructorArguments ob;
5356 // it should compile
5357 QVERIFY(connect(&ob, &NoDefaultContructorArguments::mySignal, &ob, &NoDefaultContructorArguments::mySlot, Qt::QueuedConnection));
5358}
5359
5360struct MoveOnly
5361{
5362 int value;
5363 explicit MoveOnly(int v = 1) : value(v) {}
5364 MoveOnly(MoveOnly &&o) : value(o.value) { o.value = -1; }
5365 MoveOnly &operator=(MoveOnly &&o) { value = o.value; o.value = -1; return *this; }
5366 Q_DISABLE_COPY(MoveOnly);
5367};
5368
5369class ReturnValue : public QObject {
5370friend class tst_QObject;
5371Q_OBJECT
5372signals:
5373 QVariant returnVariant(int);
5374 QString returnString(int);
5375 int returnInt(int);
5376 void returnVoid(int);
5377 CustomType returnCustomType(int);
5378 MoveOnly returnMoveOnly(int);
5379
5380 QObject *returnPointer();
5381public slots:
5382 QVariant returnVariantSlot(int i) { return i; }
5383 QString returnStringSlot(int i) { return QString::number(i); }
5384 int returnIntSlot(int i) { return i; }
5385 CustomType returnCustomTypeSlot(int i) { return CustomType(i); }
5386 void returnVoidSlot() {}
5387 int return23() { return 23; }
5388 QString returnHello() { return QStringLiteral("hello"); }
5389 QObject *returnThisSlot1() { return this; }
5390 ReturnValue *returnThisSlot2() { return this; }
5391 MoveOnly returnMoveOnlySlot(int i) { return MoveOnly(i); }
5392public:
5393 struct VariantFunctor {
5394 QVariant operator()(int i) { return i; }
5395 };
5396 struct CustomTypeFunctor {
5397 CustomType operator()(int i) { return CustomType(i); }
5398 };
5399 struct StringFunctor {
5400 QString operator()(int i) { return QString::number(i); }
5401 };
5402 struct IntFunctor {
5403 int operator()(int i) { return i; }
5404 };
5405 struct VoidFunctor {
5406 void operator()(int) {}
5407 };
5408 struct MoveOnlyFunctor {
5409 MoveOnly operator()(int i) { return MoveOnly(i); }
5410 };
5411};
5412
5413QString someFunctionReturningString(int i) {
5414 return '\'' + QString::number(i) + '\'';
5415}
5416
5417void tst_QObject::returnValue_data()
5418{
5419 QTest::addColumn<bool>(name: "isBlockingQueued");
5420
5421 QTest::newRow(dataTag: "DirectConnection") << false;
5422 QTest::newRow(dataTag: "BlockingQueuedConnection") << true;
5423}
5424
5425void tst_QObject::returnValue()
5426{
5427 CheckInstanceCount checker;
5428
5429 QFETCH(bool, isBlockingQueued);
5430 QThread thread;
5431 ReturnValue receiver;
5432 Qt::ConnectionType type = Qt::DirectConnection;
5433 if (isBlockingQueued) {
5434 thread.start();
5435 receiver.moveToThread(thread: &thread);
5436 type = Qt::BlockingQueuedConnection;
5437 }
5438
5439 { // connected to nothing
5440 CheckInstanceCount checker;
5441 ReturnValue r;
5442 QCOMPARE(emit r.returnVariant(45), QVariant());
5443 QCOMPARE(emit r.returnString(45), QString());
5444 QCOMPARE(emit r.returnInt(45), int());
5445 emit r.returnVoid(45);
5446 QCOMPARE((emit r.returnCustomType(45)).value(), CustomType().value());
5447 QCOMPARE((emit r.returnPointer()), static_cast<QObject *>(0));
5448 QCOMPARE((emit r.returnMoveOnly(666)).value, MoveOnly().value);
5449 }
5450 { // connected to a slot returning the same type
5451 CheckInstanceCount checker;
5452 ReturnValue r;
5453 QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnVariantSlot, type));
5454 QCOMPARE(emit r.returnVariant(45), QVariant(45));
5455 QVERIFY(connect(&r, &ReturnValue::returnString, &receiver, &ReturnValue::returnStringSlot, type));
5456 QCOMPARE(emit r.returnString(45), QString::fromLatin1("45"));
5457 QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::returnIntSlot, type));
5458 QCOMPARE(emit r.returnInt(45), int(45));
5459 QVERIFY(connect(&r, &ReturnValue::returnCustomType, &receiver, &ReturnValue::returnCustomTypeSlot, type));
5460 QCOMPARE((emit r.returnCustomType(45)).value(), CustomType(45).value());
5461 QVERIFY(connect(&r, &ReturnValue::returnPointer, &receiver, &ReturnValue::returnThisSlot1, type));
5462 QCOMPARE((emit r.returnPointer()), static_cast<QObject *>(&receiver));
5463 QVERIFY(connect(&r, &ReturnValue::returnMoveOnly, &receiver, &ReturnValue::returnMoveOnlySlot, type));
5464 QCOMPARE((emit r.returnMoveOnly(666)).value, 666);
5465 }
5466 if (!isBlockingQueued) { // connected to simple functions or functor
5467 CheckInstanceCount checker;
5468 ReturnValue r;
5469 QVERIFY(connect(&r, &ReturnValue::returnString, someFunctionReturningString));
5470 QCOMPARE(emit r.returnString(49), QString::fromLatin1("'49'"));
5471
5472 ReturnValue::CustomTypeFunctor customTypeFunctor;
5473 QVERIFY(connect(&r, &ReturnValue::returnCustomType, customTypeFunctor));
5474 QCOMPARE((emit r.returnCustomType(49)).value(), CustomType(49).value());
5475
5476 ReturnValue::VariantFunctor variantFunctor;
5477 QVERIFY(connect(&r, &ReturnValue::returnVariant, variantFunctor));
5478 QCOMPARE(emit r.returnVariant(45), QVariant(45));
5479
5480 ReturnValue::IntFunctor intFunctor;
5481 QVERIFY(connect(&r, &ReturnValue::returnInt, intFunctor));
5482 QCOMPARE(emit r.returnInt(45), int(45));
5483
5484 ReturnValue::MoveOnlyFunctor moveOnlyFunctor;
5485 QVERIFY(connect(&r, &ReturnValue::returnMoveOnly, moveOnlyFunctor));
5486 QCOMPARE((emit r.returnMoveOnly(666)).value, 666);
5487 }
5488 { // connected to a slot with different type
5489 CheckInstanceCount checker;
5490 ReturnValue r;
5491 QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnStringSlot, type));
5492 QCOMPARE(emit r.returnVariant(48), QVariant(QString::fromLatin1("48")));
5493 QVERIFY(connect(&r, &ReturnValue::returnCustomType, &receiver, &ReturnValue::returnIntSlot, type));
5494 QCOMPARE((emit r.returnCustomType(48)).value(), CustomType(48).value());
5495 QVERIFY(connect(&r, &ReturnValue::returnVoid, &receiver, &ReturnValue::returnCustomTypeSlot, type));
5496 emit r.returnVoid(48);
5497 QVERIFY(connect(&r, &ReturnValue::returnPointer, &receiver, &ReturnValue::returnThisSlot2, type));
5498 QCOMPARE((emit r.returnPointer()), static_cast<QObject *>(&receiver));
5499 }
5500 if (!isBlockingQueued) { // connected to functor with different type
5501 CheckInstanceCount checker;
5502 ReturnValue r;
5503
5504 ReturnValue::CustomTypeFunctor customTypeFunctor;
5505 QVERIFY(connect(&r, &ReturnValue::returnCustomType, customTypeFunctor));
5506 QCOMPARE((emit r.returnCustomType(49)).value(), CustomType(49).value());
5507
5508 ReturnValue::StringFunctor stringFunctor;
5509 QVERIFY(connect(&r, &ReturnValue::returnVariant, stringFunctor));
5510 QCOMPARE(emit r.returnVariant(45), QVariant(QString::fromLatin1("45")));
5511 }
5512 { // connected to a void
5513 CheckInstanceCount checker;
5514 ReturnValue r;
5515 QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnVoidSlot, type));
5516 QCOMPARE(emit r.returnVariant(45), QVariant());
5517 QVERIFY(connect(&r, &ReturnValue::returnString, &receiver, &ReturnValue::returnVoidSlot, type));
5518 QCOMPARE(emit r.returnString(45), QString());
5519 QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::returnVoidSlot, type));
5520 QCOMPARE(emit r.returnInt(45), int());
5521 QVERIFY(connect(&r, &ReturnValue::returnCustomType, &receiver, &ReturnValue::returnVoidSlot, type));
5522 QCOMPARE((emit r.returnCustomType(45)).value(), CustomType().value());
5523 QVERIFY(connect(&r, &ReturnValue::returnPointer, &receiver, &ReturnValue::returnVoidSlot, type));
5524 QCOMPARE((emit r.returnPointer()), static_cast<QObject *>(0));
5525 QVERIFY(connect(&r, &ReturnValue::returnMoveOnly, &receiver, &ReturnValue::returnVoidSlot, type));
5526 QCOMPARE((emit r.returnMoveOnly(666)).value, MoveOnly().value);
5527 }
5528 if (!isBlockingQueued) {
5529 // queued connection should not forward the return value
5530 CheckInstanceCount checker;
5531 ReturnValue r;
5532 QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnVariantSlot, Qt::QueuedConnection));
5533 QCOMPARE(emit r.returnVariant(45), QVariant());
5534 QVERIFY(connect(&r, &ReturnValue::returnString, &receiver, &ReturnValue::returnStringSlot, Qt::QueuedConnection));
5535 QCOMPARE(emit r.returnString(45), QString());
5536 QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::returnIntSlot, Qt::QueuedConnection));
5537 QCOMPARE(emit r.returnInt(45), int());
5538 QVERIFY(connect(&r, &ReturnValue::returnCustomType, &receiver, &ReturnValue::returnCustomTypeSlot, Qt::QueuedConnection));
5539 QCOMPARE((emit r.returnCustomType(45)).value(), CustomType().value());
5540 QVERIFY(connect(&r, &ReturnValue::returnPointer, &receiver, &ReturnValue::returnThisSlot1, Qt::QueuedConnection));
5541 QCOMPARE((emit r.returnPointer()), static_cast<QObject *>(0));
5542 QVERIFY(connect(&r, &ReturnValue::returnMoveOnly, &receiver, &ReturnValue::returnMoveOnlySlot, Qt::QueuedConnection));
5543 QCOMPARE((emit r.returnMoveOnly(666)).value, MoveOnly().value);
5544
5545 QCoreApplication::processEvents();
5546
5547 QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnStringSlot, Qt::QueuedConnection));
5548 QCOMPARE(emit r.returnVariant(48), QVariant());
5549 QVERIFY(connect(&r, &ReturnValue::returnCustomType, &receiver, &ReturnValue::returnIntSlot, Qt::QueuedConnection));
5550 QCOMPARE((emit r.returnCustomType(48)).value(), CustomType().value());
5551 QVERIFY(connect(&r, &ReturnValue::returnVoid, &receiver, &ReturnValue::returnCustomTypeSlot, Qt::QueuedConnection));
5552 emit r.returnVoid(48);
5553 QCoreApplication::processEvents();
5554 }
5555
5556 { // connected to many slots
5557 ReturnValue::VoidFunctor voidFunctor;
5558 ReturnValue::IntFunctor intFunctor;
5559 ReturnValue r;
5560 QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnVariantSlot, type));
5561 QCOMPARE(emit r.returnVariant(45), QVariant(45));
5562 QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::return23, type));
5563 QCOMPARE(emit r.returnVariant(45), QVariant(23));
5564 QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnVoidSlot, type));
5565 QCOMPARE(emit r.returnVariant(45), QVariant(23));
5566 QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::returnHello, type));
5567 QCOMPARE(emit r.returnVariant(45), QVariant(QStringLiteral("hello")));
5568 QVERIFY(connect(&r, &ReturnValue::returnVariant, voidFunctor));
5569 QCOMPARE(emit r.returnVariant(45), QVariant(QStringLiteral("hello")));
5570 QVERIFY(connect(&r, &ReturnValue::returnVariant, intFunctor));
5571 QCOMPARE(emit r.returnVariant(45), QVariant(45));
5572 QVERIFY(connect(&r, &ReturnValue::returnVariant, &receiver, &ReturnValue::return23, Qt::QueuedConnection));
5573 QCOMPARE(emit r.returnVariant(45), QVariant(45));
5574
5575 QCOMPARE(emit r.returnInt(45), int());
5576 QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::returnVoidSlot, type));
5577 QCOMPARE(emit r.returnInt(45), int());
5578 QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::returnIntSlot, type));
5579 QCOMPARE(emit r.returnInt(45), int(45));
5580 QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::return23, type));
5581 QCOMPARE(emit r.returnInt(45), int(23));
5582 QVERIFY(connect(&r, &ReturnValue::returnInt, voidFunctor));
5583 QCOMPARE(emit r.returnInt(45), int(23));
5584 QVERIFY(connect(&r, &ReturnValue::returnInt, intFunctor));
5585 QCOMPARE(emit r.returnInt(45), int(45));
5586 QVERIFY(connect(&r, &ReturnValue::returnInt, &receiver, &ReturnValue::return23, Qt::QueuedConnection));
5587 QCOMPARE(emit r.returnInt(45), int(45));
5588
5589 QCoreApplication::processEvents();
5590 }
5591
5592 if (isBlockingQueued) {
5593 thread.quit();
5594 thread.wait();
5595 }
5596}
5597
5598void tst_QObject::returnValue2_data()
5599{ returnValue_data(); }
5600
5601//String based syntax
5602void tst_QObject::returnValue2()
5603{
5604 CheckInstanceCount checker;
5605
5606 QFETCH(bool, isBlockingQueued);
5607 QThread thread;
5608 ReturnValue receiver;
5609 Qt::ConnectionType type = Qt::DirectConnection;
5610 if (isBlockingQueued) {
5611 thread.start();
5612 receiver.moveToThread(thread: &thread);
5613 type = Qt::BlockingQueuedConnection;
5614 }
5615
5616 { // connected to a simple slot
5617 CheckInstanceCount checker;
5618 ReturnValue r;
5619 QVERIFY(connect(&r, SIGNAL(returnVariant(int)), &receiver, SLOT(returnVariantSlot(int)), type));
5620 QCOMPARE(emit r.returnVariant(45), QVariant(45));
5621 QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnStringSlot(int)), type));
5622 QCOMPARE(emit r.returnString(45), QString(QStringLiteral("45")));
5623 QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnIntSlot(int)), type));
5624 QCOMPARE(emit r.returnInt(45), int(45));
5625 QVERIFY(connect(&r, SIGNAL(returnCustomType(int)), &receiver, SLOT(returnCustomTypeSlot(int)), type));
5626 QCOMPARE((emit r.returnCustomType(45)).value(), CustomType(45).value());
5627 QVERIFY(connect(&r, SIGNAL(returnMoveOnly(int)), &receiver, SLOT(returnMoveOnlySlot(int)), type));
5628 QCOMPARE((emit r.returnMoveOnly(45)).value, 45);
5629 }
5630 { // connected to a slot returning void
5631 CheckInstanceCount checker;
5632 ReturnValue r;
5633 QVERIFY(connect(&r, SIGNAL(returnVariant(int)), &receiver, SLOT(returnVoidSlot()), type));
5634 QCOMPARE(emit r.returnVariant(45), QVariant());
5635 QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnVoidSlot()), type));
5636 QCOMPARE(emit r.returnString(45), QString());
5637 QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnVoidSlot()), type));
5638 QCOMPARE(emit r.returnInt(45), int());
5639 QVERIFY(connect(&r, SIGNAL(returnCustomType(int)), &receiver, SLOT(returnVoidSlot()), type));
5640 QCOMPARE((emit r.returnCustomType(45)).value(), CustomType().value());
5641 QVERIFY(connect(&r, SIGNAL(returnMoveOnly(int)), &receiver, SLOT(returnVoidSlot()), type));
5642 QCOMPARE((emit r.returnMoveOnly(45)).value, MoveOnly().value);
5643 }
5644 if (!isBlockingQueued) {
5645 // queued connection should not forward the return value
5646 CheckInstanceCount checker;
5647 ReturnValue r;
5648 QVERIFY(connect(&r, SIGNAL(returnVariant(int)), &receiver, SLOT(returnVariantSlot(int)), Qt::QueuedConnection));
5649 QCOMPARE(emit r.returnVariant(45), QVariant());
5650 QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnStringSlot(int)), Qt::QueuedConnection));
5651 QCOMPARE(emit r.returnString(45), QString());
5652 QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnIntSlot(int)), Qt::QueuedConnection));
5653 QCOMPARE(emit r.returnInt(45), int());
5654 QVERIFY(connect(&r, SIGNAL(returnCustomType(int)), &receiver, SLOT(returnCustomTypeSlot(int)), Qt::QueuedConnection));
5655 QCOMPARE((emit r.returnCustomType(45)).value(), CustomType().value());
5656 QVERIFY(connect(&r, SIGNAL(returnMoveOnly(int)), &receiver, SLOT(returnMoveOnlySlot(int)), Qt::QueuedConnection));
5657 QCOMPARE((emit r.returnMoveOnly(45)).value, MoveOnly().value);
5658
5659 QCoreApplication::processEvents();
5660
5661 //Queued conneciton with different return type should be safe
5662 QVERIFY(connect(&r, SIGNAL(returnVariant(int)), &receiver, SLOT(returnStringSlot(int)), Qt::QueuedConnection));
5663 QCOMPARE(emit r.returnVariant(48), QVariant());
5664 QVERIFY(connect(&r, SIGNAL(returnCustomType(int)), &receiver, SLOT(returnIntSlot(int)), Qt::QueuedConnection));
5665 QCOMPARE((emit r.returnCustomType(48)).value(), CustomType().value());
5666 QVERIFY(connect(&r, SIGNAL(returnVoid(int)), &receiver, SLOT(returnCustomTypeSlot(int)), Qt::QueuedConnection));
5667 emit r.returnVoid(48);
5668 QCoreApplication::processEvents();
5669 }
5670 { // connected to many slots
5671 ReturnValue r;
5672 QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnIntSlot(int)), type));
5673 QCOMPARE(emit r.returnInt(45), int(45));
5674 QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnVoidSlot()), type));
5675 QCOMPARE(emit r.returnInt(45), int(45));
5676 QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(return23()), type));
5677 QCOMPARE(emit r.returnInt(45), int(23));
5678 QVERIFY(connect(&r, SIGNAL(returnInt(int)), &receiver, SLOT(returnIntSlot(int)), Qt::QueuedConnection));
5679 QCOMPARE(emit r.returnInt(45), int(23));
5680
5681 QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnStringSlot(int)), type));
5682 QCOMPARE(emit r.returnString(45), QString(QStringLiteral("45")));
5683 QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnVoidSlot()), type));
5684 QCOMPARE(emit r.returnString(45), QString(QStringLiteral("45")));
5685 QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnHello()), type));
5686 QCOMPARE(emit r.returnString(45), QString(QStringLiteral("hello")));
5687 QVERIFY(connect(&r, SIGNAL(returnString(int)), &receiver, SLOT(returnStringSlot(int)), Qt::QueuedConnection));
5688 QCOMPARE(emit r.returnString(45), QString(QStringLiteral("hello")));
5689 }
5690 if (isBlockingQueued) {
5691 thread.quit();
5692 thread.wait();
5693 }
5694}
5695
5696class VirtualSlotsObjectBase : public QObject {
5697 Q_OBJECT
5698public slots:
5699 virtual void slot1() {
5700 base_counter1++;
5701 }
5702public:
5703 VirtualSlotsObjectBase() : base_counter1(0) {}
5704 int base_counter1;
5705signals:
5706 void signal1();
5707};
5708
5709class VirtualSlotsObject : public VirtualSlotsObjectBase {
5710 Q_OBJECT
5711public slots:
5712 virtual void slot1() {
5713 derived_counter1++;
5714 }
5715public:
5716 VirtualSlotsObject() : derived_counter1(0) {}
5717 int derived_counter1;
5718};
5719
5720void tst_QObject::connectVirtualSlots()
5721{
5722 VirtualSlotsObject obj;
5723 QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection));
5724 QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection));
5725
5726 emit obj.signal1();
5727 QCOMPARE(obj.base_counter1, 0);
5728 QCOMPARE(obj.derived_counter1, 1);
5729
5730 QVERIFY(QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1));
5731 QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1));
5732
5733 emit obj.signal1();
5734 QCOMPARE(obj.base_counter1, 0);
5735 QCOMPARE(obj.derived_counter1, 1);
5736
5737 /* the C++ standard say the comparison between pointer to virtual member function is unspecified
5738 QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection));
5739 QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObject::slot1, Qt::UniqueConnection));
5740 */
5741}
5742
5743struct VirtualBase
5744{
5745 int virtual_base_count;
5746 VirtualBase() : virtual_base_count(0) {}
5747 virtual ~VirtualBase() {}
5748 virtual void slot2() = 0;
5749};
5750
5751class ObjectWithVirtualBase : public VirtualSlotsObject, public virtual VirtualBase
5752{
5753 Q_OBJECT
5754public:
5755 ObjectWithVirtualBase() : regular_call_count(0), derived_counter2(0) {}
5756 int regular_call_count;
5757 int derived_counter2;
5758
5759public slots:
5760 void regularSlot() { ++regular_call_count; }
5761 virtual void slot1() { ++derived_counter2; }
5762 virtual void slot2() { ++virtual_base_count; }
5763};
5764
5765struct NormalBase
5766{
5767 QByteArray lastCalled;
5768 virtual ~NormalBase() {}
5769 virtual void virtualBaseSlot() { lastCalled = "virtualBaseSlot"; }
5770 void normalBaseSlot() { lastCalled = "normalBaseSlot"; }
5771};
5772
5773class ObjectWithMultiInheritance : public VirtualSlotsObject, public NormalBase
5774{
5775 Q_OBJECT
5776};
5777
5778// Normally, the class that inherit QObject always must go first, because of the way qobject_cast
5779// work, and moc checks for that. But if we don't use Q_OBJECT, this should work
5780class ObjectWithMultiInheritance2 : public NormalBase, public VirtualSlotsObject
5781{
5782 // no QObject as QObject always must go first
5783 // Q_OBJECT
5784};
5785
5786// VMI = Virtual or Multiple Inheritance
5787// (in this case, both)
5788void tst_QObject::connectSlotsVMIClass()
5789{
5790 // test connecting by the base
5791 {
5792 ObjectWithVirtualBase obj;
5793 QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection));
5794 QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection));
5795
5796 emit obj.signal1();
5797 QCOMPARE(obj.base_counter1, 0);
5798 QCOMPARE(obj.derived_counter1, 0);
5799 QCOMPARE(obj.derived_counter2, 1);
5800 QCOMPARE(obj.virtual_base_count, 0);
5801
5802 QVERIFY(QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1));
5803 QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1));
5804
5805 emit obj.signal1();
5806 QCOMPARE(obj.base_counter1, 0);
5807 QCOMPARE(obj.derived_counter1, 0);
5808 QCOMPARE(obj.derived_counter2, 1);
5809 QCOMPARE(obj.virtual_base_count, 0);
5810 }
5811
5812 // test connecting with the actual class
5813 {
5814 ObjectWithVirtualBase obj;
5815 QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::regularSlot, Qt::UniqueConnection));
5816 QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::regularSlot, Qt::UniqueConnection));
5817 QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1, Qt::UniqueConnection));
5818 QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1, Qt::UniqueConnection));
5819
5820 emit obj.signal1();
5821 QCOMPARE(obj.base_counter1, 0);
5822 QCOMPARE(obj.derived_counter1, 0);
5823 QCOMPARE(obj.derived_counter2, 1);
5824 QCOMPARE(obj.regular_call_count, 1);
5825 QCOMPARE(obj.virtual_base_count, 0);
5826
5827 QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::regularSlot));
5828 QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::regularSlot));
5829 QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1));
5830 QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1));
5831
5832 emit obj.signal1();
5833 QCOMPARE(obj.base_counter1, 0);
5834 QCOMPARE(obj.derived_counter1, 0);
5835 QCOMPARE(obj.derived_counter2, 1);
5836 QCOMPARE(obj.regular_call_count, 1);
5837 QCOMPARE(obj.virtual_base_count, 0);
5838
5839 /* the C++ standard say the comparison between pointer to virtual member function is unspecified
5840 QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &VirtualSlotsObjectBase::slot1, Qt::UniqueConnection));
5841 QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot1, Qt::UniqueConnection));
5842 */
5843 }
5844
5845 // test connecting a slot that is virtual from the virtual base
5846 {
5847 ObjectWithVirtualBase obj;
5848 QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot2, Qt::UniqueConnection));
5849 QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot2, Qt::UniqueConnection));
5850
5851 emit obj.signal1();
5852 QCOMPARE(obj.base_counter1, 0);
5853 QCOMPARE(obj.derived_counter1, 0);
5854 QCOMPARE(obj.derived_counter2, 0);
5855 QCOMPARE(obj.virtual_base_count, 1);
5856 QCOMPARE(obj.regular_call_count, 0);
5857
5858 QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot2));
5859 QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, &ObjectWithVirtualBase::slot2));
5860
5861 emit obj.signal1();
5862 QCOMPARE(obj.base_counter1, 0);
5863 QCOMPARE(obj.derived_counter1, 0);
5864 QCOMPARE(obj.derived_counter2, 0);
5865 QCOMPARE(obj.virtual_base_count, 1);
5866 QCOMPARE(obj.regular_call_count, 0);
5867 }
5868
5869 // test connecting a slot that is virtual within the second base
5870 {
5871 ObjectWithMultiInheritance obj;
5872 void (ObjectWithMultiInheritance::*slot)() = &ObjectWithMultiInheritance::virtualBaseSlot;
5873 QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection));
5874 QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection));
5875
5876 emit obj.signal1();
5877 QCOMPARE(obj.base_counter1, 0);
5878 QCOMPARE(obj.derived_counter1, 0);
5879 QCOMPARE(obj.lastCalled, QByteArray("virtualBaseSlot"));
5880 obj.lastCalled.clear();
5881
5882 QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot));
5883 QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot));
5884
5885 emit obj.signal1();
5886 QCOMPARE(obj.base_counter1, 0);
5887 QCOMPARE(obj.derived_counter1, 0);
5888 QCOMPARE(obj.lastCalled, QByteArray());
5889 }
5890
5891 // test connecting a slot that is not virtual within the second base
5892 {
5893 ObjectWithMultiInheritance obj;
5894 void (ObjectWithMultiInheritance::*slot)() = &ObjectWithMultiInheritance::normalBaseSlot;
5895 QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection));
5896 QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection));
5897
5898 emit obj.signal1();
5899 QCOMPARE(obj.base_counter1, 0);
5900 QCOMPARE(obj.derived_counter1, 0);
5901 QCOMPARE(obj.lastCalled, QByteArray("normalBaseSlot"));
5902 obj.lastCalled.clear();
5903
5904 QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot));
5905 QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot));
5906
5907 emit obj.signal1();
5908 QCOMPARE(obj.base_counter1, 0);
5909 QCOMPARE(obj.derived_counter1, 0);
5910 QCOMPARE(obj.lastCalled, QByteArray());
5911 }
5912
5913 // test connecting a slot within the first non-QObject base
5914 {
5915 ObjectWithMultiInheritance2 obj;
5916 void (ObjectWithMultiInheritance2::*slot)() = &ObjectWithMultiInheritance2::normalBaseSlot;
5917 QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection));
5918 QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection));
5919
5920 emit obj.signal1();
5921 QCOMPARE(obj.base_counter1, 0);
5922 QCOMPARE(obj.derived_counter1, 0);
5923 QCOMPARE(obj.lastCalled, QByteArray("normalBaseSlot"));
5924 obj.lastCalled.clear();
5925
5926 QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot));
5927 QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot));
5928
5929 emit obj.signal1();
5930 QCOMPARE(obj.base_counter1, 0);
5931 QCOMPARE(obj.derived_counter1, 0);
5932 QCOMPARE(obj.lastCalled, QByteArray());
5933 }
5934
5935 // test connecting a slot within the second QObject base
5936 {
5937 ObjectWithMultiInheritance2 obj;
5938 void (ObjectWithMultiInheritance2::*slot)() = &ObjectWithMultiInheritance2::slot1;
5939 QVERIFY( QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection));
5940 QVERIFY(!QObject::connect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot, Qt::UniqueConnection));
5941
5942 emit obj.signal1();
5943 QCOMPARE(obj.base_counter1, 0);
5944 QCOMPARE(obj.derived_counter1, 1);
5945 QCOMPARE(obj.lastCalled, QByteArray());
5946
5947 QVERIFY( QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot));
5948 QVERIFY(!QObject::disconnect(&obj, &VirtualSlotsObjectBase::signal1, &obj, slot));
5949
5950 emit obj.signal1();
5951 QCOMPARE(obj.base_counter1, 0);
5952 QCOMPARE(obj.derived_counter1, 1);
5953 QCOMPARE(obj.lastCalled, QByteArray());
5954 }
5955}
5956
5957#ifndef QT_BUILD_INTERNAL
5958void tst_QObject::connectPrivateSlots()
5959{QSKIP("Needs QT_BUILD_INTERNAL");}
5960#else
5961class ConnectToPrivateSlotPrivate;
5962
5963class ConnectToPrivateSlot :public QObject {
5964 Q_OBJECT
5965public:
5966 ConnectToPrivateSlot();
5967 void test(SenderObject *obj1) ;
5968 Q_DECLARE_PRIVATE(ConnectToPrivateSlot)
5969};
5970
5971class ConnectToPrivateSlotPrivate : public QObjectPrivate {
5972 Q_DECLARE_PUBLIC(ConnectToPrivateSlot)
5973public:
5974 int receivedCount;
5975 QVariant receivedValue;
5976
5977 void thisIsAPrivateSlot() {
5978 receivedCount++;
5979 };
5980
5981 void thisIsAPrivateSlotWithArg(const QVariant &v) {
5982 receivedCount++;
5983 receivedValue = v;
5984 };
5985};
5986
5987ConnectToPrivateSlot::ConnectToPrivateSlot(): QObject(*new ConnectToPrivateSlotPrivate) {}
5988
5989void ConnectToPrivateSlot::test(SenderObject* obj1) {
5990 Q_D(ConnectToPrivateSlot);
5991 d->receivedCount = 0;
5992 QVERIFY(QObjectPrivate::connect(obj1, &SenderObject::signal1, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot));
5993 QVERIFY(QObjectPrivate::connect(obj1, &SenderObject::signal7, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlotWithArg));
5994 QCOMPARE(d->receivedCount, 0);
5995 obj1->signal1();
5996 QCOMPARE(d->receivedCount, 1);
5997 QCOMPARE(d->receivedValue, QVariant());
5998 obj1->signal7(666, QLatin1String("_"));
5999 QCOMPARE(d->receivedCount, 2);
6000 QCOMPARE(d->receivedValue, QVariant(666));
6001 QVERIFY(QObjectPrivate::connect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot, Qt::UniqueConnection));
6002 QVERIFY(!QObjectPrivate::connect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot, Qt::UniqueConnection));
6003 obj1->signal2();
6004 QCOMPARE(d->receivedCount, 3);
6005 QVERIFY(QObjectPrivate::disconnect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot));
6006 obj1->signal2();
6007 QCOMPARE(d->receivedCount, 3);
6008 QVERIFY(!QObjectPrivate::disconnect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot));
6009}
6010
6011void tst_QObject::connectPrivateSlots()
6012{
6013 SenderObject sender;
6014 {
6015 ConnectToPrivateSlot o;
6016 o.test(obj1: &sender);
6017 }
6018 sender.signal7(777, QLatin1String("check that deleting the object properly disconnected"));
6019 sender.signal1();
6020}
6021#endif
6022
6023struct SlotFunctor
6024{
6025 void operator()() {}
6026};
6027
6028struct SlotFunctorString
6029{
6030 void operator()(const QString &) {}
6031};
6032
6033void tst_QObject::connectFunctorArgDifference()
6034{
6035 QTimer timer;
6036 // Compile-time tests that the connection is successful.
6037 connect(sender: &timer, signal: &QTimer::timeout, slot: SlotFunctor());
6038 connect(sender: &timer, signal: &QTimer::objectNameChanged, slot: SlotFunctorString());
6039 connect(qApp, signal: &QCoreApplication::aboutToQuit, slot: SlotFunctor());
6040
6041 connect(sender: &timer, signal: &QTimer::objectNameChanged, slot: SlotFunctor());
6042 QStringListModel model;
6043 connect(sender: &model, signal: &QStringListModel::rowsInserted, slot: SlotFunctor());
6044
6045 connect(sender: &timer, signal: &QTimer::timeout, slot: [=](){});
6046 connect(sender: &timer, signal: &QTimer::objectNameChanged, slot: [=](const QString &){});
6047 connect(qApp, signal: &QCoreApplication::aboutToQuit, slot: [=](){});
6048
6049 connect(sender: &timer, signal: &QTimer::objectNameChanged, slot: [=](){});
6050 connect(sender: &model, signal: &QStringListModel::rowsInserted, slot: [=](){});
6051 connect(sender: &model, signal: &QStringListModel::rowsInserted, slot: [=](const QModelIndex &){});
6052
6053 QVERIFY(true);
6054}
6055
6056class ContextObject : public QObject
6057{
6058 Q_OBJECT
6059public:
6060 void compareSender(QObject *s) { QCOMPARE(s, sender()); }
6061};
6062
6063struct SlotArgFunctor
6064{
6065 SlotArgFunctor(int *s) : status(s), context(nullptr), sender(nullptr) {}
6066 SlotArgFunctor(ContextObject *context, QObject *sender, int *s) : status(s), context(context), sender(sender) {}
6067 void operator()() { *status = 2; if (context) context->compareSender(s: sender); }
6068
6069protected:
6070 int *status;
6071 ContextObject *context;
6072 QObject *sender;
6073};
6074
6075void tst_QObject::connectFunctorQueued()
6076{
6077 int status = 1;
6078 SenderObject obj;
6079 QEventLoop e;
6080
6081 connect(sender: &obj, signal: &SenderObject::signal1, context: this, slot: SlotArgFunctor(&status), type: Qt::QueuedConnection);
6082 connect(sender: &obj, signal: &SenderObject::signal1, receiver: &e, slot: &QEventLoop::quit, type: Qt::QueuedConnection);
6083
6084 obj.emitSignal1();
6085 QCOMPARE(status, 1);
6086 e.exec();
6087 QCOMPARE(status, 2);
6088
6089 status = 1;
6090 connect(sender: &obj, signal: &SenderObject::signal1, context: this, slot: [&status] { status = 2; }, type: Qt::QueuedConnection);
6091
6092 obj.emitSignal1();
6093 QCOMPARE(status, 1);
6094 e.exec();
6095 QCOMPARE(status, 2);
6096}
6097
6098void tst_QObject::connectFunctorWithContext()
6099{
6100 int status = 1;
6101 SenderObject obj;
6102 ContextObject *context = new ContextObject;
6103 QEventLoop e;
6104
6105 connect(sender: &obj, signal: &SenderObject::signal1, context, slot: SlotArgFunctor(&status));
6106 connect(sender: &obj, signal: &SenderObject::signal1, receiver: &e, slot: &QEventLoop::quit, type: Qt::QueuedConnection);
6107
6108 // When the context gets deleted, the connection should decay and the signal shouldn't trigger
6109 // The connection is queued to make sure the destroyed signal propagates correctly and
6110 // cuts the connection.
6111 connect(sender: context, signal: &QObject::destroyed, receiver: &obj, slot: &SenderObject::signal1, type: Qt::QueuedConnection);
6112 context->deleteLater();
6113
6114 QCOMPARE(status, 1);
6115 e.exec();
6116 QCOMPARE(status, 1);
6117
6118 // Check the sender arg is set correctly in the context
6119 context = new ContextObject;
6120
6121 connect(sender: &obj, signal: &SenderObject::signal1, context,
6122 slot: SlotArgFunctor(context, &obj, &status), type: Qt::QueuedConnection);
6123
6124 obj.emitSignal1();
6125 QCOMPARE(status, 1);
6126 e.exec();
6127 QCOMPARE(status, 2);
6128
6129 status = 1;
6130 connect(sender: &obj, signal: &SenderObject::signal1, context: this, slot: [this, &status, &obj] { status = 2; QCOMPARE(sender(), &obj); }, type: Qt::QueuedConnection);
6131
6132 obj.emitSignal1();
6133 QCOMPARE(status, 1);
6134 e.exec();
6135 QCOMPARE(status, 2);
6136
6137 // Free
6138 context->deleteLater();
6139}
6140
6141class StatusChanger : public QObject
6142{
6143 Q_OBJECT
6144public:
6145 StatusChanger(int *status) : m_status(status)
6146 {
6147 }
6148 ~StatusChanger()
6149 {
6150 *m_status = 2;
6151 }
6152private:
6153 int *m_status;
6154};
6155
6156class DispatcherWatcher : public QObject
6157{
6158 Q_OBJECT
6159public:
6160 DispatcherWatcher(QEventLoop &e, int *statusAwake, int *statusAboutToBlock) :
6161 m_eventLoop(&e),
6162 m_statusAwake(statusAwake),
6163 m_statusAboutToBlock(statusAboutToBlock),
6164 m_aboutToBlocks(0),
6165 m_awakes(0)
6166 {
6167 awake = new StatusChanger(statusAwake);
6168 abouttoblock = new StatusChanger(statusAboutToBlock);
6169 QCOMPARE(*statusAwake, 1);
6170 QCOMPARE(*statusAboutToBlock, 1);
6171 connect(sender: QAbstractEventDispatcher::instance(), SIGNAL(awake()), receiver: this, SLOT(onAwake()));
6172 connect(sender: QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()), receiver: this, SLOT(onAboutToBlock()));
6173
6174 }
6175
6176 ~DispatcherWatcher()
6177 {
6178 if (awake)
6179 awake->deleteLater();
6180 if (abouttoblock)
6181 abouttoblock->deleteLater();
6182 }
6183
6184public slots:
6185 // The order of these 2 handlers differs on different event dispatchers
6186 void onAboutToBlock()
6187 {
6188 if (abouttoblock) {
6189 abouttoblock->deleteLater();
6190 abouttoblock = 0;
6191 }
6192 ++m_aboutToBlocks;
6193 }
6194 void onAwake()
6195 {
6196 if (awake) {
6197 awake->deleteLater();
6198 awake = 0;
6199 }
6200 ++m_awakes;
6201
6202 }
6203 void onSignal1()
6204 {
6205 // Status check. At this point the event loop should have spinned enough to delete all the objects.
6206 QCOMPARE(*m_statusAwake, 2);
6207 QCOMPARE(*m_statusAboutToBlock, 2);
6208 QMetaObject::invokeMethod(obj: m_eventLoop, member: "quit", type: Qt::QueuedConnection);
6209 }
6210
6211private:
6212 StatusChanger *awake;
6213 StatusChanger *abouttoblock;
6214 QEventLoop *m_eventLoop;
6215 int *m_statusAwake;
6216 int *m_statusAboutToBlock;
6217 int m_aboutToBlocks;
6218 int m_awakes;
6219};
6220
6221
6222void tst_QObject::deleteLaterInAboutToBlockHandler()
6223{
6224 int statusAwake = 1;
6225 int statusAboutToBlock = 1;
6226 QEventLoop e;
6227 DispatcherWatcher dw(e, &statusAwake, &statusAboutToBlock);
6228 QTimer::singleShot(interval: 2000, receiver: &dw, slot: &DispatcherWatcher::onSignal1);
6229
6230 QCOMPARE(statusAwake, 1);
6231 QCOMPARE(statusAboutToBlock, 1);
6232 e.exec();
6233 QCOMPARE(statusAwake, 2);
6234 QCOMPARE(statusAboutToBlock, 2);
6235}
6236
6237void tst_QObject::connectFunctorWithContextUnique()
6238{
6239 // Qt::UniqueConnections currently don't work for functors, but we need to
6240 // be sure that they don't crash. If that is implemented, change this test.
6241
6242 SenderObject sender;
6243 ReceiverObject receiver;
6244 QObject::connect(sender: &sender, signal: &SenderObject::signal1, receiver: &receiver, slot: &ReceiverObject::slot1);
6245 receiver.count_slot1 = 0;
6246
6247 QObject::connect(sender: &sender, signal: &SenderObject::signal1, context: &receiver, slot: SlotFunctor(), type: Qt::UniqueConnection);
6248
6249 sender.emitSignal1();
6250 QCOMPARE(receiver.count_slot1, 1);
6251}
6252
6253class MyFunctor
6254{
6255public:
6256 explicit MyFunctor(QObject *objectToDisconnect)
6257 : m_objectToDisconnect(objectToDisconnect)
6258 {}
6259
6260 ~MyFunctor() {
6261 playWithObjects();
6262 }
6263
6264 void operator()() {
6265 // This will cause the slot object associated with this functor to be destroyed after
6266 // this function returns. That in turn will destroy this functor.
6267 // If our dtor runs with the signalSlotLock held, the bunch of connect()
6268 // performed there will deadlock trying to lock that lock again.
6269 m_objectToDisconnect->disconnect();
6270 }
6271
6272private:
6273 QObject *m_objectToDisconnect;
6274};
6275
6276void tst_QObject::connectFunctorDeadlock()
6277{
6278 SenderObject sender;
6279 MyFunctor functor(&sender);
6280 QObject::connect(sender: &sender, signal: &SenderObject::signal1, slot: functor);
6281 sender.emitSignal1();
6282}
6283
6284void tst_QObject::connectFunctorMoveOnly()
6285{
6286 struct MoveOnlyFunctor {
6287 Q_DISABLE_COPY(MoveOnlyFunctor)
6288 MoveOnlyFunctor(int *status) : status(status) {}
6289 MoveOnlyFunctor(MoveOnlyFunctor &&o) : status(o.status) { o.status = nullptr; };
6290 void operator()(int i) { *status = i; }
6291 void operator()() { *status = -8; }
6292 int *status;
6293 };
6294
6295 int status = 1;
6296 SenderObject obj;
6297 QEventLoop e;
6298
6299 connect(sender: &obj, signal: &SenderObject::signal1, slot: MoveOnlyFunctor(&status));
6300 QCOMPARE(status, 1);
6301 obj.signal1();
6302 QCOMPARE(status, -8);
6303
6304 connect(sender: &obj, signal: &SenderObject::signal7, slot: MoveOnlyFunctor(&status));
6305 QCOMPARE(status, -8);
6306 obj.signal7(7888, "Hello");
6307 QCOMPARE(status, 7888);
6308
6309 // With a context
6310 status = 1;
6311 connect(sender: &obj, signal: &SenderObject::signal2, context: this, slot: MoveOnlyFunctor(&status));
6312 QCOMPARE(status, 1);
6313 obj.signal2();
6314 QCOMPARE(status, -8);
6315
6316 // QueuedConnection
6317 status = 1;
6318 connect(sender: &obj, signal: &SenderObject::signal3, context: this, slot: MoveOnlyFunctor(&status), type: Qt::QueuedConnection);
6319 obj.signal3();
6320 QCOMPARE(status, 1);
6321 QCoreApplication::processEvents();
6322 QCOMPARE(status, -8);
6323}
6324
6325static int s_static_slot_checker = 1;
6326
6327class StaticSlotChecker : public QObject
6328{
6329 Q_OBJECT
6330public Q_SLOTS:
6331 static void staticSlot() { s_static_slot_checker = 2; }
6332};
6333
6334void tst_QObject::connectStaticSlotWithObject()
6335{
6336 SenderObject sender;
6337 StaticSlotChecker *receiver = new StaticSlotChecker;
6338 QEventLoop e;
6339
6340 QVERIFY(connect(&sender, &SenderObject::signal1, receiver, &StaticSlotChecker::staticSlot, Qt::QueuedConnection));
6341 connect(sender: &sender, signal: &SenderObject::signal1, receiver: &e, slot: &QEventLoop::quit, type: Qt::QueuedConnection);
6342
6343 sender.emitSignal1();
6344 QCOMPARE(s_static_slot_checker, 1);
6345 e.exec();
6346 QCOMPARE(s_static_slot_checker, 2);
6347
6348 s_static_slot_checker = 1;
6349
6350 connect(sender: receiver, signal: &QObject::destroyed, receiver: &sender, slot: &SenderObject::signal1, type: Qt::QueuedConnection);
6351 receiver->deleteLater();
6352
6353 QCOMPARE(s_static_slot_checker, 1);
6354 e.exec();
6355 QCOMPARE(s_static_slot_checker, 1);
6356}
6357
6358struct ComplexFunctor {
6359 ComplexFunctor(int &overload, QList<QVariant> &result) : overload(overload), result(result) {}
6360 void operator()(int a, int b) {
6361 overload = 1;
6362 result << a << b;
6363 }
6364 void operator()(double a, double b) {
6365 overload = 2;
6366 result << a << b;
6367 }
6368 void operator()(const QString &s) {
6369 overload = 3;
6370 result << s;
6371 }
6372 void operator()(const QString &) const {
6373 Q_ASSERT(!"Should not be called because the non-const one should");
6374 overload = -1;
6375 }
6376 template<typename T1, typename T2, typename T3, typename T4>
6377 void operator()(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4) {
6378 overload = 4;
6379 result << QVariant::fromValue(t1) << QVariant::fromValue(t2) << QVariant::fromValue(t3) << QVariant::fromValue(t4);
6380 }
6381 int &overload;
6382 QList<QVariant> &result;
6383protected:
6384 void operator()() const {
6385 Q_ASSERT(!"Should not be called because it is protected");
6386 overload = -1;
6387 }
6388};
6389
6390struct ComplexFunctorDeriv : ComplexFunctor {
6391 ComplexFunctorDeriv(int &overload, QList<QVariant> &result) : ComplexFunctor(overload, result) {}
6392
6393 void operator()() const {
6394 overload = 10;
6395 }
6396 void operator()(int a, int b) {
6397 overload = 11;
6398 result << a << b;
6399 }
6400 using ComplexFunctor::operator();
6401private:
6402 void operator()(int) {
6403 Q_ASSERT(!"Should not be called because it is private");
6404 overload = -1;
6405 }
6406};
6407
6408class FunctorArgDifferenceObject : public QObject
6409{
6410 Q_OBJECT
6411signals:
6412 void signal_ii(int,int);
6413 void signal_iiS(int,int, const QString &);
6414 void signal_dd(double,double);
6415 void signal_ddS(double,double, const QString &);
6416 void signal_S(const QString &);
6417 void signal_SSSS(const QString &, const QString &, const QString &, const QString &);
6418 void signal_iiSS(int, int, const QString &, const QString &);
6419 void signal_VV(const QVariant &, const QVariant &);
6420};
6421
6422template<typename Functor, typename Signal>
6423void connectFunctorOverload_impl(Signal signal, int expOverload, QList<QVariant> expResult)
6424{
6425 FunctorArgDifferenceObject obj;
6426 int overload;
6427 QList<QVariant> result;
6428 QVERIFY(QObject::connect(&obj, signal, Functor(overload, result)));
6429
6430 obj.signal_ii(1,2);
6431 obj.signal_iiS(3,4,"5");
6432 obj.signal_dd(6.6,7.7);
6433 obj.signal_ddS(8.8,9.9,"10");
6434 obj.signal_S("11");
6435 obj.signal_SSSS("12", "13", "14", "15");
6436 obj.signal_iiSS(16, 17, "18", "19");
6437 obj.signal_VV(20,21);
6438
6439 QCOMPARE(overload, expOverload);
6440 QCOMPARE(result, expResult);
6441}
6442
6443void tst_QObject::connectFunctorOverloads()
6444{
6445#if defined (Q_COMPILER_VARIADIC_TEMPLATES)
6446 connectFunctorOverload_impl<ComplexFunctor>(signal: &FunctorArgDifferenceObject::signal_ii, expOverload: 1,
6447 expResult: (QList<QVariant>() << 1 << 2));
6448 connectFunctorOverload_impl<ComplexFunctor>(signal: &FunctorArgDifferenceObject::signal_iiS, expOverload: 1,
6449 expResult: (QList<QVariant>() << 3 << 4));
6450 connectFunctorOverload_impl<ComplexFunctor>(signal: &FunctorArgDifferenceObject::signal_dd, expOverload: 2,
6451 expResult: (QList<QVariant>() << 6.6 << 7.7));
6452 connectFunctorOverload_impl<ComplexFunctor>(signal: &FunctorArgDifferenceObject::signal_ddS, expOverload: 2,
6453 expResult: (QList<QVariant>() << 8.8 << 9.9));
6454 connectFunctorOverload_impl<ComplexFunctor>(signal: &FunctorArgDifferenceObject::signal_S, expOverload: 3,
6455 expResult: (QList<QVariant>() << QString("11")));
6456 connectFunctorOverload_impl<ComplexFunctor>(signal: &FunctorArgDifferenceObject::signal_SSSS, expOverload: 4,
6457 expResult: (QList<QVariant>() << QString("12") << QString("13") << QString("14") << QString("15")));
6458 connectFunctorOverload_impl<ComplexFunctor>(signal: &FunctorArgDifferenceObject::signal_iiSS, expOverload: 4,
6459 expResult: (QList<QVariant>() << 16 << 17 << QString("18") << QString("19")));
6460 connectFunctorOverload_impl<ComplexFunctorDeriv>(signal: &FunctorArgDifferenceObject::signal_ii, expOverload: 11,
6461 expResult: (QList<QVariant>() << 1 << 2));
6462 connectFunctorOverload_impl<ComplexFunctorDeriv>(signal: &FunctorArgDifferenceObject::signal_iiS, expOverload: 11,
6463 expResult: (QList<QVariant>() << 3 << 4));
6464 connectFunctorOverload_impl<ComplexFunctorDeriv>(signal: &FunctorArgDifferenceObject::signal_dd, expOverload: 2,
6465 expResult: (QList<QVariant>() << 6.6 << 7.7));
6466 connectFunctorOverload_impl<ComplexFunctorDeriv>(signal: &FunctorArgDifferenceObject::signal_ddS, expOverload: 2,
6467 expResult: (QList<QVariant>() << 8.8 << 9.9));
6468 connectFunctorOverload_impl<ComplexFunctorDeriv>(signal: &FunctorArgDifferenceObject::signal_S, expOverload: 3,
6469 expResult: (QList<QVariant>() << QString("11")));
6470 connectFunctorOverload_impl<ComplexFunctorDeriv>(signal: &FunctorArgDifferenceObject::signal_SSSS, expOverload: 4,
6471 expResult: (QList<QVariant>() << QString("12") << QString("13") << QString("14") << QString("15")));
6472 connectFunctorOverload_impl<ComplexFunctorDeriv>(signal: &FunctorArgDifferenceObject::signal_iiSS, expOverload: 4,
6473 expResult: (QList<QVariant>() << 16 << 17 << QString("18") << QString("19")));
6474 connectFunctorOverload_impl<ComplexFunctorDeriv>(signal: &FunctorArgDifferenceObject::signal_VV, expOverload: 10,
6475 expResult: (QList<QVariant>()));
6476
6477
6478#else
6479 QSKIP("Does not compile without C++11 variadic template");
6480#endif
6481}
6482
6483class GetSenderObject : public QObject
6484{
6485 Q_OBJECT
6486public:
6487 using QObject::sender; // make public
6488
6489public Q_SLOTS:
6490 void triggerSignal() { Q_EMIT aSignal(); }
6491
6492Q_SIGNALS:
6493 void aSignal();
6494};
6495
6496static int countedStructObjectsCount = 0;
6497struct CountedStruct
6498{
6499 CountedStruct() : sender(nullptr) { ++countedStructObjectsCount; }
6500 CountedStruct(GetSenderObject *sender) : sender(sender) { ++countedStructObjectsCount; }
6501 CountedStruct(const CountedStruct &o) : sender(o.sender) { ++countedStructObjectsCount; }
6502 CountedStruct &operator=(const CountedStruct &) { return *this; }
6503 // calling sender() here allows us to check if there's a deadlock
6504 ~CountedStruct() { --countedStructObjectsCount; if (sender) (void)sender->sender(); }
6505 void operator()() const { }
6506
6507 GetSenderObject *sender;
6508};
6509
6510void tst_QObject::disconnectDoesNotLeakFunctor()
6511{
6512 QCOMPARE(countedStructObjectsCount, 0);
6513 {
6514 GetSenderObject obj;
6515 QMetaObject::Connection c;
6516 {
6517 CountedStruct s(&obj);
6518 QCOMPARE(countedStructObjectsCount, 1);
6519
6520 c = connect(sender: &obj, signal: &GetSenderObject::aSignal, slot: s);
6521 QVERIFY(c);
6522 QCOMPARE(countedStructObjectsCount, 2);
6523 QVERIFY(QObject::disconnect(c));
6524 QCOMPARE(countedStructObjectsCount, 1);
6525 }
6526 QCOMPARE(countedStructObjectsCount, 0);
6527 }
6528 QCOMPARE(countedStructObjectsCount, 0);
6529 {
6530 GetSenderObject obj;
6531 QMetaObject::Connection c;
6532 {
6533 CountedStruct s(&obj);
6534 QObject context;
6535 QCOMPARE(countedStructObjectsCount, 1);
6536
6537 c = connect(sender: &obj, signal: &GetSenderObject::aSignal, context: &context, slot: s);
6538 QVERIFY(c);
6539 QCOMPARE(countedStructObjectsCount, 2);
6540 QVERIFY(QObject::disconnect(c));
6541 QCOMPARE(countedStructObjectsCount, 1);
6542 }
6543 QCOMPARE(countedStructObjectsCount, 0);
6544 }
6545 QCOMPARE(countedStructObjectsCount, 0);
6546 {
6547 QMetaObject::Connection c1, c2;
6548 {
6549 CountedStruct s;
6550 QCOMPARE(countedStructObjectsCount, 1);
6551 QTimer timer;
6552
6553 c1 = connect(sender: &timer, signal: &QTimer::timeout, slot: s);
6554 QVERIFY(c1);
6555 c2 = c1;
6556 QVERIFY(c2);
6557 QCOMPARE(countedStructObjectsCount, 2);
6558 QVERIFY(QObject::disconnect(c1));
6559 QVERIFY(!c1);
6560 QVERIFY(!c2);
6561 // functor object has been destroyed
6562 QCOMPARE(countedStructObjectsCount, 1);
6563 QVERIFY(!QObject::disconnect(c2));
6564 QCOMPARE(countedStructObjectsCount, 1);
6565 }
6566 QCOMPARE(countedStructObjectsCount, 0);
6567 }
6568 QCOMPARE(countedStructObjectsCount, 0);
6569 {
6570 CountedStruct s;
6571 QCOMPARE(countedStructObjectsCount, 1);
6572 QTimer timer;
6573
6574 QMetaObject::Connection c = connect(sender: &timer, signal: &QTimer::timeout, slot: s);
6575 QVERIFY(c);
6576 QCOMPARE(countedStructObjectsCount, 2);
6577 QVERIFY(QObject::disconnect(c));
6578 QCOMPARE(countedStructObjectsCount, 1);
6579 }
6580 QCOMPARE(countedStructObjectsCount, 0);
6581 {
6582 QTimer timer;
6583
6584 QMetaObject::Connection c = connect(sender: &timer, signal: &QTimer::timeout, slot: CountedStruct());
6585 QVERIFY(c);
6586 QCOMPARE(countedStructObjectsCount, 1); // only one instance, in Qt internals
6587 QVERIFY(QObject::disconnect(c));
6588 QCOMPARE(countedStructObjectsCount, 0); // functor being destroyed
6589 }
6590 QCOMPARE(countedStructObjectsCount, 0);
6591 {
6592 QTimer *timer = new QTimer;
6593 QEventLoop e;
6594
6595 connect(sender: timer, signal: &QTimer::timeout, slot: CountedStruct());
6596 QCOMPARE(countedStructObjectsCount, 1); // only one instance, in Qt internals
6597 timer->deleteLater();
6598 connect(sender: timer, signal: &QObject::destroyed, receiver: &e, slot: &QEventLoop::quit, type: Qt::QueuedConnection);
6599 e.exec();
6600 QCOMPARE(countedStructObjectsCount, 0); // functor being destroyed
6601 }
6602 QCOMPARE(countedStructObjectsCount, 0);
6603 {
6604 GetSenderObject obj;
6605
6606 connect(sender: &obj, signal: &GetSenderObject::aSignal, slot: CountedStruct(&obj));
6607 QCOMPARE(countedStructObjectsCount, 1);
6608 }
6609 QCOMPARE(countedStructObjectsCount, 0);
6610 {
6611 GetSenderObject obj;
6612
6613 connect(sender: &obj, signal: &GetSenderObject::aSignal, slot: CountedStruct(&obj));
6614 QCOMPARE(countedStructObjectsCount, 1);
6615 QObject::disconnect(sender: &obj, signal: &GetSenderObject::aSignal, receiver: 0, zero: 0);
6616 }
6617 QCOMPARE(countedStructObjectsCount, 0);
6618 {
6619 CountedStruct s;
6620 QCOMPARE(countedStructObjectsCount, 1);
6621 QTimer timer;
6622
6623 QMetaObject::Connection c = connect(sender: &timer, signal: &QTimer::timeout, slot: [s](){});
6624 QVERIFY(c);
6625 QCOMPARE(countedStructObjectsCount, 2);
6626 QVERIFY(QObject::disconnect(c));
6627 QCOMPARE(countedStructObjectsCount, 1);
6628 }
6629 QCOMPARE(countedStructObjectsCount, 0);
6630}
6631
6632void tst_QObject::contextDoesNotLeakFunctor()
6633{
6634 QCOMPARE(countedStructObjectsCount, 0);
6635 {
6636 QMetaObject::Connection c;
6637 {
6638 QEventLoop e;
6639 ContextObject *context = new ContextObject;
6640 SenderObject obj;
6641
6642 connect(sender: &obj, signal: &SenderObject::signal1, context, slot: CountedStruct());
6643 connect(sender: context, signal: &QObject::destroyed, receiver: &e, slot: &QEventLoop::quit, type: Qt::QueuedConnection);
6644 context->deleteLater();
6645
6646 QCOMPARE(countedStructObjectsCount, 1);
6647 e.exec();
6648 QCOMPARE(countedStructObjectsCount, 0);
6649 }
6650 QCOMPARE(countedStructObjectsCount, 0);
6651 }
6652 QCOMPARE(countedStructObjectsCount, 0);
6653 {
6654 GetSenderObject obj;
6655 QMetaObject::Connection c;
6656 {
6657 CountedStruct s(&obj);
6658 QEventLoop e;
6659 ContextObject *context = new ContextObject;
6660 QCOMPARE(countedStructObjectsCount, 1);
6661
6662 connect(sender: &obj, signal: &GetSenderObject::aSignal, context, slot: s);
6663 QCOMPARE(countedStructObjectsCount, 2);
6664
6665 connect(sender: context, signal: &QObject::destroyed, receiver: &e, slot: &QEventLoop::quit, type: Qt::QueuedConnection);
6666 context->deleteLater();
6667
6668 e.exec();
6669 QCOMPARE(countedStructObjectsCount, 1);
6670 }
6671 QCOMPARE(countedStructObjectsCount, 0);
6672 }
6673 QCOMPARE(countedStructObjectsCount, 0);
6674 {
6675 CountedStruct s;
6676 QEventLoop e;
6677 ContextObject *context = new ContextObject;
6678 QCOMPARE(countedStructObjectsCount, 1);
6679 QTimer timer;
6680
6681 connect(sender: &timer, signal: &QTimer::timeout, context, slot: [s](){});
6682 QCOMPARE(countedStructObjectsCount, 2);
6683 connect(sender: context, signal: &QObject::destroyed, receiver: &e, slot: &QEventLoop::quit, type: Qt::QueuedConnection);
6684 context->deleteLater();
6685 e.exec();
6686 QCOMPARE(countedStructObjectsCount, 1);
6687 }
6688 QCOMPARE(countedStructObjectsCount, 0);
6689}
6690
6691class SubSender : public SenderObject {
6692 Q_OBJECT
6693};
6694
6695void tst_QObject::connectBase()
6696{
6697 SubSender sub;
6698 ReceiverObject r1;
6699 r1.reset();
6700
6701 QVERIFY( connect( &sub, &SubSender::signal1 , &r1, &ReceiverObject::slot1 ) );
6702 QVERIFY( connect( &sub, static_cast<void (SenderObject::*)()>(&SubSender::signal2) , &r1, &ReceiverObject::slot2 ) );
6703 QVERIFY( connect( &sub, static_cast<void (SubSender::*)()>(&SubSender::signal3) , &r1, &ReceiverObject::slot3 ) );
6704
6705 sub.emitSignal1();
6706 sub.emitSignal2();
6707 sub.emitSignal3();
6708
6709 QCOMPARE( r1.count_slot1, 1 );
6710 QCOMPARE( r1.count_slot2, 1 );
6711 QCOMPARE( r1.count_slot3, 1 );
6712
6713 QVERIFY( QObject::disconnect( &sub, &SubSender::signal1 , &r1, &ReceiverObject::slot1 ) );
6714 QVERIFY( QObject::disconnect( &sub, static_cast<void (SenderObject::*)()>(&SubSender::signal2) , &r1, &ReceiverObject::slot2 ) );
6715 QVERIFY( QObject::disconnect( &sub, static_cast<void (SubSender::*)()>(&SubSender::signal3) , &r1, &ReceiverObject::slot3 ) );
6716
6717 sub.emitSignal1();
6718 sub.emitSignal2();
6719 sub.emitSignal3();
6720
6721 QCOMPARE( r1.count_slot1, 1 );
6722 QCOMPARE( r1.count_slot2, 1 );
6723 QCOMPARE( r1.count_slot3, 1 );
6724}
6725
6726void tst_QObject::connectWarnings()
6727{
6728 SubSender sub;
6729 SenderObject obj;
6730 ReceiverObject r1;
6731 r1.reset();
6732
6733 QTest::ignoreMessage(type: QtWarningMsg, message: "QObject::connect(SenderObject, ReceiverObject): invalid nullptr parameter");
6734 connect(sender: static_cast<const SenderObject *>(nullptr), signal: &SubSender::signal1, receiver: &r1, slot: &ReceiverObject::slot1);
6735
6736 QTest::ignoreMessage(type: QtWarningMsg, message: "QObject::connect(SubSender, Unknown): invalid nullptr parameter");
6737 connect(sender: &sub, signal: &SubSender::signal1, receiver: static_cast<ReceiverObject *>(nullptr), slot: &ReceiverObject::slot1);
6738
6739 QTest::ignoreMessage(type: QtWarningMsg, message: "QObject::connect(SenderObject, ReceiverObject): invalid nullptr parameter");
6740 connect(sender: static_cast<const SenderObject *>(nullptr), signal: &SenderObject::signal1, receiver: &r1, slot: &ReceiverObject::slot1);
6741
6742 QTest::ignoreMessage(type: QtWarningMsg, message: "QObject::connect(SenderObject, Unknown): invalid nullptr parameter");
6743 connect(sender: &obj, signal: &SenderObject::signal1, receiver: static_cast<ReceiverObject *>(nullptr), slot: &ReceiverObject::slot1);
6744}
6745
6746struct QmlReceiver : public QtPrivate::QSlotObjectBase
6747{
6748 int callCount;
6749 void *magic;
6750
6751 QmlReceiver()
6752 : QtPrivate::QSlotObjectBase(&impl)
6753 , callCount(0)
6754 , magic(0)
6755 {}
6756
6757 static void impl(int which, QSlotObjectBase *this_, QObject *, void **metaArgs, bool *ret)
6758 {
6759 switch (which) {
6760 case Destroy: delete static_cast<QmlReceiver*>(this_); return;
6761 case Call: static_cast<QmlReceiver*>(this_)->callCount++; return;
6762 case Compare: *ret = static_cast<QmlReceiver*>(this_)->magic == metaArgs[0]; return;
6763 case NumOperations: break;
6764 }
6765 }
6766};
6767
6768void tst_QObject::qmlConnect()
6769{
6770#ifdef QT_BUILD_INTERNAL
6771 SenderObject sender;
6772 QmlReceiver *receiver = new QmlReceiver;
6773 receiver->magic = receiver;
6774 receiver->ref();
6775
6776 QVERIFY(QObjectPrivate::connect(&sender, sender.metaObject()->indexOfSignal("signal1()"),
6777 receiver, Qt::AutoConnection));
6778
6779 QCOMPARE(receiver->callCount, 0);
6780 sender.emitSignal1();
6781 QCOMPARE(receiver->callCount, 1);
6782
6783 void *a[] = {
6784 receiver
6785 };
6786 QVERIFY(QObjectPrivate::disconnect(&sender, sender.metaObject()->indexOfSignal("signal1()"), reinterpret_cast<void**>(&a)));
6787
6788 sender.emitSignal1();
6789 QCOMPARE(receiver->callCount, 1);
6790
6791 receiver->destroyIfLastRef();
6792#else
6793 QSKIP("Needs QT_BUILD_INTERNAL");
6794#endif
6795}
6796
6797void tst_QObject::qmlConnectToQObjectReceiver()
6798{
6799#ifdef QT_BUILD_INTERNAL
6800 SenderObject sender;
6801 QScopedPointer<QObject> receiver(new QObject);
6802 QmlReceiver *slotObject = new QmlReceiver;
6803 slotObject->magic = slotObject;
6804 slotObject->ref(); // extra ref so that slot object is not implicitly deleted
6805
6806 QVERIFY(QObjectPrivate::connect(&sender, sender.metaObject()->indexOfSignal("signal1()"),
6807 receiver.get(), slotObject, Qt::AutoConnection));
6808
6809 QCOMPARE(slotObject->callCount, 0);
6810 sender.emitSignal1();
6811 QCOMPARE(slotObject->callCount, 1);
6812
6813 receiver.reset(); // this should disconnect the slotObject
6814
6815 sender.emitSignal1();
6816 QCOMPARE(slotObject->callCount, 1);
6817
6818 slotObject->destroyIfLastRef();
6819#else
6820 QSKIP("Needs QT_BUILD_INTERNAL");
6821#endif
6822}
6823
6824#ifndef QT_NO_EXCEPTIONS
6825class ObjectException : public std::exception { };
6826
6827struct ThrowFunctor
6828{
6829 CountedStruct operator()(const CountedStruct &, CountedStruct s2) const
6830 {
6831 throw ObjectException();
6832 return s2;
6833 }
6834 CountedStruct s;
6835};
6836#endif
6837
6838class ExceptionThrower : public QObject
6839{
6840 Q_OBJECT
6841public slots:
6842 CountedStruct throwException(const CountedStruct &, CountedStruct s2)
6843 {
6844#ifndef QT_NO_EXCEPTIONS
6845 throw ObjectException();
6846#endif
6847 return s2;
6848 }
6849signals:
6850 CountedStruct mySignal(const CountedStruct &s1, CountedStruct s2);
6851};
6852
6853class CountedExceptionThrower : public QObject
6854{
6855 Q_OBJECT
6856
6857public:
6858 explicit CountedExceptionThrower(bool throwException, QObject *parent = nullptr)
6859 : QObject(parent)
6860 {
6861 if (throwException)
6862 throw ObjectException();
6863 ++counter;
6864 }
6865
6866 ~CountedExceptionThrower()
6867 {
6868 --counter;
6869 }
6870
6871 static int counter;
6872};
6873
6874int CountedExceptionThrower::counter = 0;
6875
6876void tst_QObject::exceptions()
6877{
6878#ifndef QT_NO_EXCEPTIONS
6879 ReceiverObject receiver;
6880
6881 // String based syntax
6882 {
6883 QCOMPARE(countedStructObjectsCount, 0);
6884 ExceptionThrower thrower;
6885 receiver.reset();
6886
6887 connect(sender: &thrower, SIGNAL(mySignal(CountedStruct,CountedStruct)), receiver: &receiver, SLOT(slot1()));
6888 connect(sender: &thrower, SIGNAL(mySignal(CountedStruct,CountedStruct)), receiver: &thrower, SLOT(throwException(CountedStruct,CountedStruct)));
6889 connect(sender: &thrower, SIGNAL(mySignal(CountedStruct,CountedStruct)), receiver: &receiver, SLOT(slot2()));
6890 try {
6891 CountedStruct s;
6892 emit thrower.mySignal(s1: s, s2: s);
6893 QFAIL("Exception not thrown?");
6894 } catch (ObjectException&) {}
6895 QCOMPARE(receiver.count_slot1, 1);
6896 QCOMPARE(receiver.count_slot2, 0);
6897 QCOMPARE(countedStructObjectsCount, 0);
6898 }
6899 // Pointer to member function
6900 {
6901 QCOMPARE(countedStructObjectsCount, 0);
6902 ExceptionThrower thrower;
6903 receiver.reset();
6904
6905 connect(sender: &thrower, signal: &ExceptionThrower::mySignal, receiver: &receiver, slot: &ReceiverObject::slot1);
6906 connect(sender: &thrower, signal: &ExceptionThrower::mySignal, receiver: &thrower, slot: &ExceptionThrower::throwException);
6907 connect(sender: &thrower, signal: &ExceptionThrower::mySignal, receiver: &receiver, slot: &ReceiverObject::slot2);
6908 try {
6909 CountedStruct s;
6910 emit thrower.mySignal(s1: s, s2: s);
6911 QFAIL("Exception not thrown?");
6912 } catch (ObjectException&) {}
6913 QCOMPARE(receiver.count_slot1, 1);
6914 QCOMPARE(receiver.count_slot2, 0);
6915 QCOMPARE(countedStructObjectsCount, 0);
6916 }
6917 // Functor
6918 {
6919 QCOMPARE(countedStructObjectsCount, 0);
6920 ExceptionThrower thrower;
6921 receiver.reset();
6922
6923 connect(sender: &thrower, signal: &ExceptionThrower::mySignal, receiver: &receiver, slot: &ReceiverObject::slot1);
6924 connect(sender: &thrower, signal: &ExceptionThrower::mySignal, slot: ThrowFunctor());
6925 connect(sender: &thrower, signal: &ExceptionThrower::mySignal, receiver: &receiver, slot: &ReceiverObject::slot2);
6926 try {
6927 CountedStruct s;
6928 emit thrower.mySignal(s1: s, s2: s);
6929 QFAIL("Exception not thrown?");
6930 } catch (ObjectException&) {}
6931 QCOMPARE(receiver.count_slot1, 1);
6932 QCOMPARE(receiver.count_slot2, 0);
6933 QCOMPARE(countedStructObjectsCount, 1); // the Functor
6934 }
6935 QCOMPARE(countedStructObjectsCount, 0);
6936
6937 // Child object reaping in case of exceptions thrown by constructors
6938 {
6939 QCOMPARE(CountedExceptionThrower::counter, 0);
6940
6941 try {
6942 class ParentObject : public QObject {
6943 public:
6944 explicit ParentObject(QObject *parent = nullptr)
6945 : QObject(parent)
6946 {
6947 new CountedExceptionThrower(false, this);
6948 new CountedExceptionThrower(false, this);
6949 new CountedExceptionThrower(true, this); // throws
6950 }
6951 };
6952
6953 ParentObject p;
6954 QFAIL("Exception not thrown");
6955 } catch (const ObjectException &) {
6956 } catch (...) {
6957 QFAIL("Wrong exception thrown");
6958 }
6959
6960 QCOMPARE(CountedExceptionThrower::counter, 0);
6961
6962 try {
6963 QObject o;
6964 new CountedExceptionThrower(false, &o);
6965 new CountedExceptionThrower(false, &o);
6966 new CountedExceptionThrower(true, &o); // throws
6967
6968 QFAIL("Exception not thrown");
6969 } catch (const ObjectException &) {
6970 } catch (...) {
6971 QFAIL("Wrong exception thrown");
6972 }
6973
6974 QCOMPARE(CountedExceptionThrower::counter, 0);
6975
6976 try {
6977 QObject o;
6978 CountedExceptionThrower c1(false, &o);
6979 CountedExceptionThrower c2(false, &o);
6980 CountedExceptionThrower c3(true, &o); // throws
6981
6982 QFAIL("Exception not thrown");
6983 } catch (const ObjectException &) {
6984 } catch (...) {
6985 QFAIL("Wrong exception thrown");
6986 }
6987
6988 QCOMPARE(CountedExceptionThrower::counter, 0);
6989 }
6990
6991#else
6992 QSKIP("Needs exceptions");
6993#endif
6994}
6995
6996#ifdef QT_BUILD_INTERNAL
6997static bool parentChangeCalled = false;
6998
6999static void testParentChanged(QAbstractDeclarativeData *, QObject *, QObject *)
7000{
7001 parentChangeCalled = true;
7002}
7003#endif
7004
7005void tst_QObject::noDeclarativeParentChangedOnDestruction()
7006{
7007#ifdef QT_BUILD_INTERNAL
7008 typedef void (*ParentChangedCallback)(QAbstractDeclarativeData *, QObject *, QObject *);
7009 QScopedValueRollback<ParentChangedCallback> rollback(QAbstractDeclarativeData::parentChanged);
7010 QAbstractDeclarativeData::parentChanged = testParentChanged;
7011
7012 QObject *parent = new QObject;
7013 QObject *child = new QObject;
7014
7015 QAbstractDeclarativeDataImpl dummy;
7016 dummy.ownedByQml1 = false;
7017 QObjectPrivate::get(o: child)->declarativeData = &dummy;
7018
7019 parentChangeCalled = false;
7020 child->setParent(parent);
7021
7022 QVERIFY(parentChangeCalled);
7023 parentChangeCalled = false;
7024
7025 delete child;
7026 QVERIFY(!parentChangeCalled);
7027
7028 delete parent;
7029#else
7030 QSKIP("Needs QT_BUILD_INTERNAL");
7031#endif
7032}
7033
7034struct MutableFunctor {
7035 int count;
7036 MutableFunctor() : count(0) {}
7037 int operator()() { return ++count; }
7038};
7039
7040void tst_QObject::mutableFunctor()
7041{
7042 ReturnValue o;
7043 MutableFunctor functor;
7044 QCOMPARE(functor.count, 0);
7045 connect(sender: &o, signal: &ReturnValue::returnInt, slot: functor);
7046 QCOMPARE(emit o.returnInt(0), 1);
7047 QCOMPARE(emit o.returnInt(0), 2); // each emit should increase the internal count
7048
7049 QCOMPARE(functor.count, 0); // but the original object should have been copied at connect time
7050}
7051
7052void tst_QObject::checkArgumentsForNarrowing()
7053{
7054 enum UnscopedEnum {};
7055 enum SignedUnscopedEnum { SignedUnscopedEnumV1 = -1, SignedUnscopedEnumV2 = 1 };
7056
7057 // a constexpr would suffice, but MSVC2013 RTM doesn't support them...
7058#define IS_UNSCOPED_ENUM_SIGNED (std::is_signed<typename std::underlying_type<UnscopedEnum>::type>::value)
7059
7060#define NARROWS_IF(x, y, test) Q_STATIC_ASSERT((QtPrivate::AreArgumentsNarrowedBase<x, y>::value) == (test))
7061#define FITS_IF(x, y, test) Q_STATIC_ASSERT((QtPrivate::AreArgumentsNarrowedBase<x, y>::value) != (test))
7062#define NARROWS(x, y) NARROWS_IF(x, y, true)
7063#define FITS(x, y) FITS_IF(x, y, true)
7064
7065 Q_STATIC_ASSERT(sizeof(UnscopedEnum) <= sizeof(int));
7066 Q_STATIC_ASSERT(sizeof(SignedUnscopedEnum) <= sizeof(int));
7067
7068 // floating point to integral
7069 NARROWS(float, bool);
7070 NARROWS(double, bool);
7071 NARROWS(long double, bool);
7072
7073 NARROWS(float, char);
7074 NARROWS(double, char);
7075 NARROWS(long double, char);
7076
7077 NARROWS(float, short);
7078 NARROWS(double, short);
7079 NARROWS(long double, short);
7080
7081 NARROWS(float, int);
7082 NARROWS(double, int);
7083 NARROWS(long double, int);
7084
7085 NARROWS(float, long);
7086 NARROWS(double, long);
7087 NARROWS(long double, long);
7088
7089 NARROWS(float, long long);
7090 NARROWS(double, long long);
7091 NARROWS(long double, long long);
7092
7093
7094 // floating point to a smaller floating point
7095 NARROWS_IF(double, float, (sizeof(double) > sizeof(float)));
7096 NARROWS_IF(long double, float, (sizeof(long double) > sizeof(float)));
7097 FITS(float, double);
7098 FITS(float, long double);
7099
7100 NARROWS_IF(long double, double, (sizeof(long double) > sizeof(double)));
7101 FITS(double, long double);
7102
7103
7104 // integral to floating point
7105 NARROWS(bool, float);
7106 NARROWS(bool, double);
7107 NARROWS(bool, long double);
7108
7109 NARROWS(char, float);
7110 NARROWS(char, double);
7111 NARROWS(char, long double);
7112
7113 NARROWS(short, float);
7114 NARROWS(short, double);
7115 NARROWS(short, long double);
7116
7117 NARROWS(int, float);
7118 NARROWS(int, double);
7119 NARROWS(int, long double);
7120
7121 NARROWS(long, float);
7122 NARROWS(long, double);
7123 NARROWS(long, long double);
7124
7125 NARROWS(long long, float);
7126 NARROWS(long long, double);
7127 NARROWS(long long, long double);
7128
7129
7130 // enum to floating point
7131 NARROWS(UnscopedEnum, float);
7132 NARROWS(UnscopedEnum, double);
7133 NARROWS(UnscopedEnum, long double);
7134
7135 NARROWS(SignedUnscopedEnum, float);
7136 NARROWS(SignedUnscopedEnum, double);
7137 NARROWS(SignedUnscopedEnum, long double);
7138
7139
7140 // integral to smaller integral
7141 FITS(bool, bool);
7142 FITS(char, char);
7143 FITS(signed char, signed char);
7144 FITS(signed char, short);
7145 FITS(signed char, int);
7146 FITS(signed char, long);
7147 FITS(signed char, long long);
7148 FITS(unsigned char, unsigned char);
7149 FITS(unsigned char, unsigned short);
7150 FITS(unsigned char, unsigned int);
7151 FITS(unsigned char, unsigned long);
7152 FITS(unsigned char, unsigned long long);
7153
7154 NARROWS_IF(bool, unsigned char, (sizeof(bool) > sizeof(char) || std::is_signed<bool>::value));
7155 NARROWS_IF(bool, unsigned short, (sizeof(bool) > sizeof(short) || std::is_signed<bool>::value));
7156 NARROWS_IF(bool, unsigned int, (sizeof(bool) > sizeof(int) || std::is_signed<bool>::value));
7157 NARROWS_IF(bool, unsigned long, (sizeof(bool) > sizeof(long) || std::is_signed<bool>::value));
7158 NARROWS_IF(bool, unsigned long long, (sizeof(bool) > sizeof(long long) || std::is_signed<bool>::value));
7159
7160 NARROWS_IF(short, char, (sizeof(short) > sizeof(char) || std::is_unsigned<char>::value));
7161 NARROWS_IF(short, unsigned char, (sizeof(short) > sizeof(char)));
7162 NARROWS_IF(short, signed char, (sizeof(short) > sizeof(char)));
7163
7164 NARROWS_IF(unsigned short, char, (sizeof(short) > sizeof(char) || std::is_signed<char>::value));
7165 NARROWS_IF(unsigned short, unsigned char, (sizeof(short) > sizeof(char)));
7166 NARROWS_IF(unsigned short, signed char, (sizeof(short) > sizeof(char)));
7167
7168 FITS(short, short);
7169 FITS(short, int);
7170 FITS(short, long);
7171 FITS(short, long long);
7172
7173 FITS(unsigned short, unsigned short);
7174 FITS(unsigned short, unsigned int);
7175 FITS(unsigned short, unsigned long);
7176 FITS(unsigned short, unsigned long long);
7177
7178 NARROWS_IF(int, char, (sizeof(int) > sizeof(char) || std::is_unsigned<char>::value));
7179 NARROWS(int, unsigned char);
7180 NARROWS_IF(int, signed char, (sizeof(int) > sizeof(char)));
7181 NARROWS_IF(int, short, (sizeof(int) > sizeof(short)));
7182 NARROWS(int, unsigned short);
7183
7184 NARROWS_IF(unsigned int, char, (sizeof(int) > sizeof(char) || std::is_signed<char>::value));
7185 NARROWS_IF(unsigned int, unsigned char, (sizeof(int) > sizeof(char)));
7186 NARROWS(unsigned int, signed char);
7187 NARROWS(unsigned int, short);
7188 NARROWS_IF(unsigned int, unsigned short, (sizeof(int) > sizeof(short)));
7189
7190 FITS(int, int);
7191 FITS(int, long);
7192 FITS(int, long long);
7193
7194 FITS(unsigned int, unsigned int);
7195 FITS(unsigned int, unsigned long);
7196 FITS(unsigned int, unsigned long long);
7197
7198 NARROWS_IF(long, char, (sizeof(long) > sizeof(char) || std::is_unsigned<char>::value));
7199 NARROWS(long, unsigned char);
7200 NARROWS_IF(long, signed char, (sizeof(long) > sizeof(char)));
7201 NARROWS_IF(long, short, (sizeof(long) > sizeof(short)));
7202 NARROWS(long, unsigned short);
7203 NARROWS_IF(long, int, (sizeof(long) > sizeof(int)));
7204 NARROWS(long, unsigned int);
7205
7206 NARROWS_IF(unsigned long, char, (sizeof(long) > sizeof(char) || std::is_signed<char>::value));
7207 NARROWS_IF(unsigned long, unsigned char, (sizeof(long) > sizeof(char)));
7208 NARROWS(unsigned long, signed char);
7209 NARROWS(unsigned long, short);
7210 NARROWS_IF(unsigned long, unsigned short, (sizeof(long) > sizeof(short)));
7211 NARROWS(unsigned long, int);
7212 NARROWS_IF(unsigned long, unsigned int, (sizeof(long) > sizeof(int)));
7213
7214 FITS(long, long);
7215 FITS(long, long long);
7216
7217 FITS(unsigned long, unsigned long);
7218 FITS(unsigned long, unsigned long long);
7219
7220 NARROWS_IF(long long, char, (sizeof(long long) > sizeof(char) || std::is_unsigned<char>::value));
7221 NARROWS(long long, unsigned char);
7222 NARROWS_IF(long long, signed char, (sizeof(long long) > sizeof(char)));
7223 NARROWS_IF(long long, short, (sizeof(long long) > sizeof(short)));
7224 NARROWS(long long, unsigned short);
7225 NARROWS_IF(long long, int, (sizeof(long long) > sizeof(int)));
7226 NARROWS(long long, unsigned int);
7227 NARROWS_IF(long long, long, (sizeof(long long) > sizeof(long)));
7228 NARROWS(long long, unsigned long);
7229
7230 NARROWS_IF(unsigned long long, char, (sizeof(long long) > sizeof(char) || std::is_signed<char>::value));
7231 NARROWS_IF(unsigned long long, unsigned char, (sizeof(long long) > sizeof(char)));
7232 NARROWS(unsigned long long, signed char);
7233 NARROWS(unsigned long long, short);
7234 NARROWS_IF(unsigned long long, unsigned short, (sizeof(long long) > sizeof(short)));
7235 NARROWS(unsigned long long, int);
7236 NARROWS_IF(unsigned long long, unsigned int, (sizeof(long long) > sizeof(int)));
7237 NARROWS(unsigned long long, long);
7238 NARROWS_IF(unsigned long long, unsigned long, (sizeof(long long) > sizeof(long)));
7239
7240 FITS(long long, long long);
7241 FITS(unsigned long long, unsigned long long);
7242
7243
7244 // integral to integral with different signedness. smaller ones tested above
7245 NARROWS(signed char, unsigned char);
7246 NARROWS(signed char, unsigned short);
7247 NARROWS(signed char, unsigned int);
7248 NARROWS(signed char, unsigned long);
7249 NARROWS(signed char, unsigned long long);
7250
7251 NARROWS(unsigned char, signed char);
7252 FITS(unsigned char, short);
7253 FITS(unsigned char, int);
7254 FITS(unsigned char, long);
7255 FITS(unsigned char, long long);
7256
7257 NARROWS(short, unsigned short);
7258 NARROWS(short, unsigned int);
7259 NARROWS(short, unsigned long);
7260 NARROWS(short, unsigned long long);
7261
7262 NARROWS(unsigned short, short);
7263 FITS(unsigned short, int);
7264 FITS(unsigned short, long);
7265 FITS(unsigned short, long long);
7266
7267 NARROWS(int, unsigned int);
7268 NARROWS(int, unsigned long);
7269 NARROWS(int, unsigned long long);
7270
7271 NARROWS(unsigned int, int);
7272 NARROWS_IF(unsigned int, long, (sizeof(int) >= sizeof(long)));
7273 FITS(unsigned int, long long);
7274
7275 NARROWS(long, unsigned long);
7276 NARROWS(long, unsigned long long);
7277
7278 NARROWS(unsigned long, long);
7279 NARROWS_IF(unsigned long, long long, (sizeof(long) >= sizeof(long long)));
7280
7281 NARROWS(long long, unsigned long long);
7282 NARROWS(unsigned long long, long long);
7283
7284 // enum to smaller integral
7285 // (note that we know that sizeof(UnscopedEnum) <= sizeof(int)
7286 FITS(UnscopedEnum, UnscopedEnum);
7287 FITS(SignedUnscopedEnum, SignedUnscopedEnum);
7288
7289 NARROWS_IF(UnscopedEnum, char, ((sizeof(UnscopedEnum) > sizeof(char)) || (sizeof(UnscopedEnum) == sizeof(char) && IS_UNSCOPED_ENUM_SIGNED == std::is_signed<char>::value)));
7290 NARROWS_IF(UnscopedEnum, signed char, ((sizeof(UnscopedEnum) > sizeof(char)) || (sizeof(UnscopedEnum) == sizeof(char) && !IS_UNSCOPED_ENUM_SIGNED)));
7291 NARROWS_IF(UnscopedEnum, unsigned char, ((sizeof(UnscopedEnum) > sizeof(char)) || IS_UNSCOPED_ENUM_SIGNED));
7292
7293 NARROWS_IF(UnscopedEnum, short, ((sizeof(UnscopedEnum) > sizeof(short)) || (sizeof(UnscopedEnum) == sizeof(short) && !IS_UNSCOPED_ENUM_SIGNED)));
7294 NARROWS_IF(UnscopedEnum, unsigned short, ((sizeof(UnscopedEnum) > sizeof(short)) || IS_UNSCOPED_ENUM_SIGNED));
7295
7296 NARROWS_IF(UnscopedEnum, int, (sizeof(UnscopedEnum) == sizeof(int) && !IS_UNSCOPED_ENUM_SIGNED));
7297 NARROWS_IF(UnscopedEnum, unsigned int, IS_UNSCOPED_ENUM_SIGNED);
7298
7299 NARROWS_IF(UnscopedEnum, long, (sizeof(UnscopedEnum) == sizeof(long) && !IS_UNSCOPED_ENUM_SIGNED));
7300 NARROWS_IF(UnscopedEnum, unsigned long, IS_UNSCOPED_ENUM_SIGNED);
7301
7302 NARROWS_IF(UnscopedEnum, long long, (sizeof(UnscopedEnum) == sizeof(long long) && !IS_UNSCOPED_ENUM_SIGNED));
7303 NARROWS_IF(UnscopedEnum, unsigned long long, IS_UNSCOPED_ENUM_SIGNED);
7304
7305 Q_STATIC_ASSERT(std::is_signed<typename std::underlying_type<SignedUnscopedEnum>::type>::value);
7306
7307 NARROWS_IF(SignedUnscopedEnum, signed char, (sizeof(SignedUnscopedEnum) > sizeof(char)));
7308 NARROWS_IF(SignedUnscopedEnum, short, (sizeof(SignedUnscopedEnum) > sizeof(short)));
7309 FITS(SignedUnscopedEnum, int);
7310 FITS(SignedUnscopedEnum, long);
7311 FITS(SignedUnscopedEnum, long long);
7312
7313
7314 enum class ScopedEnumBackedBySChar : signed char { A };
7315 enum class ScopedEnumBackedByUChar : unsigned char { A };
7316 enum class ScopedEnumBackedByShort : short { A };
7317 enum class ScopedEnumBackedByUShort : unsigned short { A };
7318 enum class ScopedEnumBackedByInt : int { A };
7319 enum class ScopedEnumBackedByUInt : unsigned int { A };
7320 enum class ScopedEnumBackedByLong : long { A };
7321 enum class ScopedEnumBackedByULong : unsigned long { A };
7322 enum class ScopedEnumBackedByLongLong : long long { A };
7323 enum class ScopedEnumBackedByULongLong : unsigned long long { A };
7324
7325 FITS(ScopedEnumBackedBySChar, ScopedEnumBackedBySChar);
7326 FITS(ScopedEnumBackedByUChar, ScopedEnumBackedByUChar);
7327 FITS(ScopedEnumBackedByShort, ScopedEnumBackedByShort);
7328 FITS(ScopedEnumBackedByUShort, ScopedEnumBackedByUShort);
7329 FITS(ScopedEnumBackedByInt, ScopedEnumBackedByInt);
7330 FITS(ScopedEnumBackedByUInt, ScopedEnumBackedByUInt);
7331 FITS(ScopedEnumBackedByLong, ScopedEnumBackedByLong);
7332 FITS(ScopedEnumBackedByULong, ScopedEnumBackedByULong);
7333 FITS(ScopedEnumBackedByLongLong, ScopedEnumBackedByLongLong);
7334 FITS(ScopedEnumBackedByULongLong, ScopedEnumBackedByULongLong);
7335
7336 FITS(ScopedEnumBackedBySChar, signed char);
7337 FITS(ScopedEnumBackedByUChar, unsigned char);
7338 FITS(ScopedEnumBackedByShort, short);
7339 FITS(ScopedEnumBackedByUShort, unsigned short);
7340 FITS(ScopedEnumBackedByInt, int);
7341 FITS(ScopedEnumBackedByUInt, unsigned int);
7342 FITS(ScopedEnumBackedByLong, long);
7343 FITS(ScopedEnumBackedByULong, unsigned long);
7344 FITS(ScopedEnumBackedByLongLong, long long);
7345 FITS(ScopedEnumBackedByULongLong, unsigned long long);
7346
7347 FITS(ScopedEnumBackedBySChar, signed char);
7348 FITS(ScopedEnumBackedBySChar, short);
7349 FITS(ScopedEnumBackedBySChar, int);
7350 FITS(ScopedEnumBackedBySChar, long);
7351 FITS(ScopedEnumBackedBySChar, long long);
7352
7353 FITS(ScopedEnumBackedByUChar, unsigned char);
7354 FITS(ScopedEnumBackedByUChar, unsigned short);
7355 FITS(ScopedEnumBackedByUChar, unsigned int);
7356 FITS(ScopedEnumBackedByUChar, unsigned long);
7357 FITS(ScopedEnumBackedByUChar, unsigned long long);
7358
7359 NARROWS_IF(ScopedEnumBackedByShort, char, (sizeof(short) > sizeof(char) || std::is_unsigned<char>::value));
7360 NARROWS_IF(ScopedEnumBackedByUShort, char, (sizeof(short) > sizeof(char) || std::is_signed<char>::value));
7361 NARROWS_IF(ScopedEnumBackedByInt, char, (sizeof(int) > sizeof(char) || std::is_unsigned<char>::value));
7362 NARROWS_IF(ScopedEnumBackedByUInt, char, (sizeof(int) > sizeof(char) || std::is_signed<char>::value));
7363 NARROWS_IF(ScopedEnumBackedByLong, char, (sizeof(long) > sizeof(char) || std::is_unsigned<char>::value));
7364 NARROWS_IF(ScopedEnumBackedByULong, char, (sizeof(long) > sizeof(char) || std::is_signed<char>::value));
7365 NARROWS_IF(ScopedEnumBackedByLongLong, char, (sizeof(long long) > sizeof(char) || std::is_unsigned<char>::value));
7366 NARROWS_IF(ScopedEnumBackedByULongLong, char, (sizeof(long long) > sizeof(char) || std::is_signed<char>::value));
7367
7368 NARROWS_IF(ScopedEnumBackedByShort, signed char, (sizeof(short) > sizeof(char)));
7369 NARROWS(ScopedEnumBackedByUShort, signed char);
7370 NARROWS_IF(ScopedEnumBackedByInt, signed char, (sizeof(int) > sizeof(char)));
7371 NARROWS(ScopedEnumBackedByUInt, signed char);
7372 NARROWS_IF(ScopedEnumBackedByLong, signed char, (sizeof(long) > sizeof(char)));
7373 NARROWS(ScopedEnumBackedByULong, signed char);
7374 NARROWS_IF(ScopedEnumBackedByLongLong, signed char, (sizeof(long long) > sizeof(char)));
7375 NARROWS(ScopedEnumBackedByULongLong, signed char);
7376
7377 NARROWS(ScopedEnumBackedByShort, unsigned char);
7378 NARROWS_IF(ScopedEnumBackedByUShort, unsigned char, (sizeof(short) > sizeof(char)));
7379 NARROWS(ScopedEnumBackedByInt, unsigned char);
7380 NARROWS_IF(ScopedEnumBackedByUInt, unsigned char, (sizeof(int) > sizeof(char)));
7381 NARROWS(ScopedEnumBackedByLong, unsigned char);
7382 NARROWS_IF(ScopedEnumBackedByULong, unsigned char, (sizeof(long) > sizeof(char)));
7383 NARROWS(ScopedEnumBackedByLongLong, unsigned char);
7384 NARROWS_IF(ScopedEnumBackedByULongLong, unsigned char, (sizeof(long long) > sizeof(char)));
7385
7386 NARROWS_IF(ScopedEnumBackedByInt, short, (sizeof(int) > sizeof(short)));
7387 NARROWS(ScopedEnumBackedByUInt, short);
7388 NARROWS_IF(ScopedEnumBackedByLong, short, (sizeof(long) > sizeof(short)));
7389 NARROWS(ScopedEnumBackedByULong, short);
7390 NARROWS_IF(ScopedEnumBackedByLongLong, short, (sizeof(long long) > sizeof(short)));
7391 NARROWS(ScopedEnumBackedByULongLong, short);
7392
7393 NARROWS(ScopedEnumBackedByInt, unsigned short);
7394 NARROWS_IF(ScopedEnumBackedByUInt, unsigned short, (sizeof(int) > sizeof(short)));
7395 NARROWS(ScopedEnumBackedByLong, unsigned short);
7396 NARROWS_IF(ScopedEnumBackedByULong, unsigned short, (sizeof(long) > sizeof(short)));
7397 NARROWS(ScopedEnumBackedByLongLong, unsigned short);
7398 NARROWS_IF(ScopedEnumBackedByULongLong, unsigned short, (sizeof(long long) > sizeof(short)));
7399
7400 NARROWS_IF(ScopedEnumBackedByLong, int, (sizeof(long) > sizeof(int)));
7401 NARROWS(ScopedEnumBackedByULong, int);
7402 NARROWS_IF(ScopedEnumBackedByLongLong, int, (sizeof(long long) > sizeof(int)));
7403 NARROWS(ScopedEnumBackedByULongLong, int);
7404
7405 NARROWS(ScopedEnumBackedByLong, unsigned int);
7406 NARROWS_IF(ScopedEnumBackedByULong, unsigned int, (sizeof(long) > sizeof(int)));
7407 NARROWS(ScopedEnumBackedByLongLong, unsigned int);
7408 NARROWS_IF(ScopedEnumBackedByULongLong, unsigned int, (sizeof(long long) > sizeof(int)));
7409
7410 NARROWS_IF(ScopedEnumBackedByLongLong, long, (sizeof(long long) > sizeof(long)));
7411 NARROWS(ScopedEnumBackedByULongLong, long);
7412
7413 NARROWS(ScopedEnumBackedByLongLong, unsigned long);
7414 NARROWS_IF(ScopedEnumBackedByULongLong, unsigned long, (sizeof(long long) > sizeof(long)));
7415
7416 // different signedness of the underlying type
7417 NARROWS(SignedUnscopedEnum, unsigned char);
7418 NARROWS(SignedUnscopedEnum, unsigned short);
7419 NARROWS(SignedUnscopedEnum, unsigned int);
7420 NARROWS(SignedUnscopedEnum, unsigned long);
7421 NARROWS(SignedUnscopedEnum, unsigned long long);
7422
7423 NARROWS(ScopedEnumBackedBySChar, unsigned char);
7424 NARROWS(ScopedEnumBackedBySChar, unsigned short);
7425 NARROWS(ScopedEnumBackedBySChar, unsigned int);
7426 NARROWS(ScopedEnumBackedBySChar, unsigned long);
7427 NARROWS(ScopedEnumBackedBySChar, unsigned long long);
7428
7429 NARROWS(ScopedEnumBackedByShort, unsigned char);
7430 NARROWS(ScopedEnumBackedByShort, unsigned short);
7431 NARROWS(ScopedEnumBackedByShort, unsigned int);
7432 NARROWS(ScopedEnumBackedByShort, unsigned long);
7433 NARROWS(ScopedEnumBackedByShort, unsigned long long);
7434
7435 NARROWS(ScopedEnumBackedByInt, unsigned char);
7436 NARROWS(ScopedEnumBackedByInt, unsigned short);
7437 NARROWS(ScopedEnumBackedByInt, unsigned int);
7438 NARROWS(ScopedEnumBackedByInt, unsigned long);
7439 NARROWS(ScopedEnumBackedByInt, unsigned long long);
7440
7441 NARROWS(ScopedEnumBackedByLong, unsigned char);
7442 NARROWS(ScopedEnumBackedByLong, unsigned short);
7443 NARROWS(ScopedEnumBackedByLong, unsigned int);
7444 NARROWS(ScopedEnumBackedByLong, unsigned long);
7445 NARROWS(ScopedEnumBackedByLong, unsigned long long);
7446
7447 NARROWS(ScopedEnumBackedByLongLong, unsigned char);
7448 NARROWS(ScopedEnumBackedByLongLong, unsigned short);
7449 NARROWS(ScopedEnumBackedByLongLong, unsigned int);
7450 NARROWS(ScopedEnumBackedByLongLong, unsigned long);
7451 NARROWS(ScopedEnumBackedByLongLong, unsigned long long);
7452
7453 NARROWS(ScopedEnumBackedByUChar, signed char);
7454 FITS_IF(ScopedEnumBackedByUChar, short, (sizeof(char) < sizeof(short)));
7455 FITS_IF(ScopedEnumBackedByUChar, int, (sizeof(char) < sizeof(int)));
7456 FITS_IF(ScopedEnumBackedByUChar, long, (sizeof(char) < sizeof(long)));
7457 FITS_IF(ScopedEnumBackedByUChar, long long, (sizeof(char) < sizeof(long long)));
7458
7459 NARROWS(ScopedEnumBackedByUShort, signed char);
7460 NARROWS(ScopedEnumBackedByUShort, short);
7461 FITS_IF(ScopedEnumBackedByUShort, int, (sizeof(short) < sizeof(int)));
7462 FITS_IF(ScopedEnumBackedByUShort, long, (sizeof(short) < sizeof(long)));
7463 FITS_IF(ScopedEnumBackedByUShort, long long, (sizeof(short) < sizeof(long long)));
7464
7465 NARROWS(ScopedEnumBackedByUInt, signed char);
7466 NARROWS(ScopedEnumBackedByUInt, short);
7467 NARROWS(ScopedEnumBackedByUInt, int);
7468 FITS_IF(ScopedEnumBackedByUInt, long, (sizeof(ScopedEnumBackedByUInt) < sizeof(long)));
7469 FITS(ScopedEnumBackedByUInt, long long);
7470
7471 NARROWS(ScopedEnumBackedByULong, signed char);
7472 NARROWS(ScopedEnumBackedByULong, short);
7473 NARROWS(ScopedEnumBackedByULong, int);
7474 NARROWS(ScopedEnumBackedByULong, long);
7475 FITS_IF(ScopedEnumBackedByULong, long long, (sizeof(ScopedEnumBackedByULong) < sizeof(long long)));
7476
7477 NARROWS(ScopedEnumBackedByULongLong, signed char);
7478 NARROWS(ScopedEnumBackedByULongLong, short);
7479 NARROWS(ScopedEnumBackedByULongLong, int);
7480 NARROWS(ScopedEnumBackedByULongLong, long);
7481 NARROWS(ScopedEnumBackedByULongLong, long long);
7482
7483 // other types which should be always unaffected
7484 FITS(void *, void *);
7485
7486 FITS(QString, QString);
7487 FITS(QString &, QString &);
7488 FITS(const QString &, const QString &);
7489
7490 FITS(QObject, QObject);
7491 FITS(QObject *, QObject *);
7492 FITS(const QObject *, const QObject *);
7493
7494 FITS(std::nullptr_t, std::nullptr_t);
7495
7496 FITS(QString, QObject);
7497 FITS(QString, QVariant);
7498 FITS(QString, void *);
7499 FITS(QString, long long);
7500 FITS(bool, const QObject *&);
7501 FITS(int (*)(bool), void (QObject::*)());
7502
7503 {
7504 // wg21.link/P1957
7505 NARROWS(char*, bool);
7506 NARROWS(void (QObject::*)(), bool);
7507 }
7508
7509#undef IS_UNSCOPED_ENUM_SIGNED
7510
7511#undef NARROWS_IF
7512#undef FITS_IF
7513#undef NARROWS
7514#undef FITS
7515}
7516
7517void tst_QObject::nullReceiver()
7518{
7519 QObject o;
7520 QObject *nullObj = nullptr; // Passing nullptr directly doesn't compile with gcc 4.8
7521 QVERIFY(!connect(&o, &QObject::destroyed, nullObj, &QObject::deleteLater));
7522 QVERIFY(!connect(&o, &QObject::destroyed, nullObj, [] {}));
7523 QVERIFY(!connect(&o, &QObject::destroyed, nullObj, Functor_noexcept()));
7524 QVERIFY(!connect(&o, SIGNAL(destroyed()), nullObj, SLOT(deleteLater())));
7525}
7526
7527void tst_QObject::functorReferencesConnection()
7528{
7529 countedStructObjectsCount = 0;
7530 QMetaObject::Connection globalCon;
7531 {
7532 GetSenderObject obj;
7533 CountedStruct counted(&obj);
7534 QCOMPARE(countedStructObjectsCount, 1);
7535 auto c = QSharedPointer<QMetaObject::Connection>::create();
7536 int slotCalled = 0;
7537 *c = connect(sender: &obj, signal: &GetSenderObject::aSignal, context: &obj, slot: [&slotCalled, c, counted] {
7538 QObject::disconnect(*c);
7539 slotCalled++;
7540 });
7541 globalCon = *c; // keep a handle to the connection somewhere;
7542 QVERIFY(globalCon);
7543 QCOMPARE(countedStructObjectsCount, 2);
7544 obj.triggerSignal();
7545 QCOMPARE(slotCalled, 1);
7546 QCOMPARE(countedStructObjectsCount, 1);
7547 QVERIFY(!globalCon);
7548 obj.triggerSignal();
7549 QCOMPARE(slotCalled, 1);
7550 QCOMPARE(countedStructObjectsCount, 1);
7551 }
7552 QCOMPARE(countedStructObjectsCount, 0);
7553
7554 {
7555 GetSenderObject obj;
7556 CountedStruct counted(&obj);
7557 QCOMPARE(countedStructObjectsCount, 1);
7558 auto *rec = new QObject;
7559 int slotCalled = 0;
7560 globalCon = connect(sender: &obj, signal: &GetSenderObject::aSignal, context: rec, slot: [&slotCalled, rec, counted] {
7561 delete rec;
7562 slotCalled++;
7563 });
7564 QCOMPARE(countedStructObjectsCount, 2);
7565 obj.triggerSignal();
7566 QCOMPARE(slotCalled, 1);
7567 QCOMPARE(countedStructObjectsCount, 1);
7568 QVERIFY(!globalCon);
7569 obj.triggerSignal();
7570 QCOMPARE(slotCalled, 1);
7571 QCOMPARE(countedStructObjectsCount, 1);
7572 }
7573 QCOMPARE(countedStructObjectsCount, 0);
7574 {
7575 int slotCalled = 0;
7576 QEventLoop eventLoop;
7577 {
7578 // Sender will be destroyed when the labda goes out of scope lambda, so it will exit the event loop
7579 auto sender = QSharedPointer<GetSenderObject>::create();
7580 connect(sender: sender.data(), signal: &QObject::destroyed, receiver: &eventLoop, slot: &QEventLoop::quit, type: Qt::QueuedConnection);
7581 globalCon = connect(sender: sender.data(), signal: &GetSenderObject::aSignal, context: this, slot: [&slotCalled, sender, &globalCon, this] {
7582 ++slotCalled;
7583 // This signal will be connected, but should never be called as the sender will be destroyed before
7584 auto c2 = connect(sender: sender.data(), signal: &GetSenderObject::aSignal, slot: [] { QFAIL("Should not be called"); });
7585 QVERIFY(c2);
7586 QVERIFY(QObject::disconnect(sender.data(), nullptr, this, nullptr));
7587 QVERIFY(!globalCon); // this connection has been disconnected
7588 QVERIFY(c2); // sender should not have been deleted yet, only after the emission is done
7589 });
7590 QMetaObject::invokeMethod(object: sender.data(), function: &GetSenderObject::triggerSignal, type: Qt::QueuedConnection);
7591 QMetaObject::invokeMethod(object: sender.data(), function: &GetSenderObject::triggerSignal, type: Qt::QueuedConnection);
7592 QMetaObject::invokeMethod(object: sender.data(), function: &GetSenderObject::triggerSignal, type: Qt::QueuedConnection);
7593 }
7594 eventLoop.exec();
7595 QCOMPARE(slotCalled, 1);
7596 }
7597
7598 {
7599 GetSenderObject obj;
7600 CountedStruct counted(&obj);
7601 QCOMPARE(countedStructObjectsCount, 1);
7602 auto c1 = QSharedPointer<QMetaObject::Connection>::create();
7603 auto c2 = QSharedPointer<QMetaObject::Connection>::create();
7604 int slot1Called = 0;
7605 int slot3Called = 0;
7606 *c1 = connect(sender: &obj, signal: &GetSenderObject::aSignal, context: &obj, slot: [&slot1Called, &slot3Called, &obj, c1, c2, counted] {
7607 auto c3 = connect(sender: &obj, signal: &GetSenderObject::aSignal, slot: [counted, &slot3Called] {
7608 slot3Called++;
7609 });
7610 // top-level + the one in the 3 others lambdas
7611 QCOMPARE(countedStructObjectsCount, 4);
7612 QObject::disconnect(*c2);
7613 slot1Called++;
7614 });
7615 connect(sender: &obj, signal: &GetSenderObject::aSignal, slot: [] {}); // just a dummy signal to fill the connection list
7616 *c2 = connect(sender: &obj, signal: &GetSenderObject::aSignal, slot: [counted, c2] { QFAIL("should not be called"); });
7617 QVERIFY(c1 && c2);
7618 QCOMPARE(countedStructObjectsCount, 3); // top-level + c1 + c2
7619 obj.triggerSignal();
7620 QCOMPARE(slot1Called, 1);
7621 QCOMPARE(slot3Called, 0);
7622 QCOMPARE(countedStructObjectsCount, 3); // top-level + c1 + c3
7623 QObject::disconnect(*c1);
7624 QCOMPARE(countedStructObjectsCount, 2); // top-level + c3
7625 obj.triggerSignal();
7626 QCOMPARE(slot1Called, 1);
7627 QCOMPARE(slot3Called, 1);
7628 }
7629 {
7630 struct DestroyEmit {
7631 Q_DISABLE_COPY(DestroyEmit);
7632 explicit DestroyEmit(SenderObject *obj) : obj(obj) {}
7633 SenderObject *obj;
7634 ~DestroyEmit() {
7635 obj->emitSignal1();
7636 }
7637 };
7638 SenderObject obj;
7639 int slot1Called = 0;
7640 int slot2Called = 0;
7641 int slot3Called = 0;
7642 auto c1 = QSharedPointer<QMetaObject::Connection>::create();
7643 auto de = QSharedPointer<DestroyEmit>::create(arguments: &obj);
7644 *c1 = connect(sender: &obj, signal: &SenderObject::signal1, slot: [&slot1Called, &slot3Called, de, c1, &obj] {
7645 connect(sender: &obj, signal: &SenderObject::signal1, slot: [&slot3Called] { slot3Called++; });
7646 slot1Called++;
7647 QObject::disconnect(*c1);
7648 });
7649 de.clear();
7650 connect(sender: &obj, signal: &SenderObject::signal1, slot: [&slot2Called] { slot2Called++; });
7651 obj.emitSignal1();
7652 QCOMPARE(slot1Called, 1);
7653 QCOMPARE(slot2Called, 2); // because also called from ~DestroyEmit
7654 QCOMPARE(slot3Called, 1);
7655 }
7656}
7657
7658void tst_QObject::disconnectDisconnects()
7659{
7660 // Test what happens if the destructor of an functor slot also disconnects more slot;
7661
7662 SenderObject s1;
7663 QScopedPointer<QObject> receiver(new QObject);
7664
7665 auto s2 = QSharedPointer<SenderObject>::create();
7666 QPointer<QObject> s2_tracker = s2.data();
7667 int count = 0;
7668 connect(sender: &s1, signal: &SenderObject::signal1, slot: [&count] { count++; }); // α
7669 connect(sender: &s1, signal: &SenderObject::signal1, context: receiver.data(), slot: [s2] { QFAIL("!!"); }); // β
7670 connect(sender: s2.data(), signal: &SenderObject::signal1, context: receiver.data(), slot: [] { QFAIL("!!"); });
7671 connect(sender: &s1, signal: &SenderObject::signal2, context: receiver.data(), slot: [] { QFAIL("!!"); });
7672 connect(sender: s2.data(), signal: &SenderObject::signal2, context: receiver.data(), slot: [] { QFAIL("!!"); });
7673 connect(sender: &s1, signal: &SenderObject::signal1, slot: [&count] { count++; }); // γ
7674 connect(sender: &s1, signal: &SenderObject::signal2, slot: [&count] { count++; }); // δ
7675 s2.clear();
7676
7677 QVERIFY(s2_tracker);
7678 receiver
7679 .reset(); // this will delete the receiver which must also delete s2 as β is disconnected
7680 QVERIFY(!s2_tracker);
7681 // test that the data structures are still in order
7682 s1.emitSignal1();
7683 QCOMPARE(count, 2); // α + γ
7684 s1.emitSignal2();
7685 QCOMPARE(count, 3); // + δ
7686}
7687
7688// Test for QtPrivate::HasQ_OBJECT_Macro
7689Q_STATIC_ASSERT(QtPrivate::HasQ_OBJECT_Macro<tst_QObject>::Value);
7690Q_STATIC_ASSERT(!QtPrivate::HasQ_OBJECT_Macro<SiblingDeleter>::Value);
7691
7692QTEST_MAIN(tst_QObject)
7693#include "tst_qobject.moc"
7694

source code of qtbase/tests/auto/corelib/kernel/qobject/tst_qobject.cpp