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