1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29
30#include <QtTest/QtTest>
31
32
33#include <qdatetime.h>
34
35class tst_QSignalSpy : public QObject
36{
37 Q_OBJECT
38
39Q_SIGNALS:
40 void sigFoo();
41
42private slots:
43 void spyWithoutArgs();
44 void spyWithBasicArgs();
45 void spyWithPointers();
46 void spyWithQtClasses();
47 void spyWithBasicQtClasses();
48 void spyWithQtTypedefs();
49
50 void wait_signalEmitted();
51 void wait_timeout();
52 void wait_signalEmittedLater();
53 void wait_signalEmittedTooLate();
54 void wait_signalEmittedMultipleTimes();
55
56 void spyFunctionPointerWithoutArgs();
57 void spyFunctionPointerWithBasicArgs();
58 void spyFunctionPointerWithPointers();
59 void spyFunctionPointerWithQtClasses();
60 void spyFunctionPointerWithBasicQtClasses();
61 void spyFunctionPointerWithQtTypedefs();
62
63 void waitFunctionPointer_signalEmitted();
64 void waitFunctionPointer_timeout();
65 void waitFunctionPointer_signalEmittedLater();
66 void waitFunctionPointer_signalEmittedTooLate();
67 void waitFunctionPointer_signalEmittedMultipleTimes();
68
69 void spyOnMetaMethod();
70
71 void spyOnMetaMethod_invalid();
72 void spyOnMetaMethod_invalid_data();
73};
74
75class QtTestObject: public QObject
76{
77 Q_OBJECT
78
79public:
80 QtTestObject();
81
82signals:
83 void sig0();
84 void sig1(int, int);
85 void sigLong(long, long);
86 void sig2(int *, int *);
87
88public:
89 QString slotResult;
90 friend class tst_QSignalSpy;
91};
92
93QtTestObject::QtTestObject()
94{
95}
96
97void tst_QSignalSpy::spyWithoutArgs()
98{
99 QtTestObject obj;
100
101 QSignalSpy spy(&obj, SIGNAL(sig0()));
102 QCOMPARE(spy.count(), 0);
103
104 emit obj.sig0();
105 QCOMPARE(spy.count(), 1);
106 emit obj.sig0();
107 QCOMPARE(spy.count(), 2);
108
109 QList<QVariant> args = spy.takeFirst();
110 QCOMPARE(args.count(), 0);
111}
112
113void tst_QSignalSpy::spyWithBasicArgs()
114{
115 QtTestObject obj;
116 QSignalSpy spy(&obj, SIGNAL(sig1(int,int)));
117
118 emit obj.sig1(1, 2);
119 QCOMPARE(spy.count(), 1);
120
121 QList<QVariant> args = spy.takeFirst();
122 QCOMPARE(args.count(), 2);
123 QCOMPARE(args.at(0).toInt(), 1);
124 QCOMPARE(args.at(1).toInt(), 2);
125
126 QSignalSpy spyl(&obj, SIGNAL(sigLong(long,long)));
127
128 emit obj.sigLong(1l, 2l);
129 args = spyl.takeFirst();
130 QCOMPARE(args.count(), 2);
131 QCOMPARE(qvariant_cast<long>(args.at(0)), 1l);
132 QCOMPARE(qvariant_cast<long>(args.at(1)), 2l);
133}
134
135
136void tst_QSignalSpy::spyWithPointers()
137{
138 qRegisterMetaType<int *>(typeName: "int*");
139
140 QtTestObject obj;
141 QSignalSpy spy(&obj, SIGNAL(sig2(int*,int*)));
142
143 int i1 = 1;
144 int i2 = 2;
145
146 emit obj.sig2(&i1, &i2);
147 QCOMPARE(spy.count(), 1);
148
149 QList<QVariant> args = spy.takeFirst();
150 QCOMPARE(args.count(), 2);
151 QCOMPARE(*static_cast<int * const *>(args.at(0).constData()), &i1);
152 QCOMPARE(*static_cast<int * const *>(args.at(1).constData()), &i2);
153}
154
155class QtTestObject2: public QObject
156{
157 Q_OBJECT
158 friend class tst_QSignalSpy;
159
160signals:
161 void sig(QString);
162 void sig2(const QDateTime &dt);
163 void sig3(QObject *o);
164 void sig4(QChar c);
165 void sig5(const QVariant &v);
166};
167
168void tst_QSignalSpy::spyWithBasicQtClasses()
169{
170 QtTestObject2 obj;
171
172 QSignalSpy spy(&obj, SIGNAL(sig(QString)));
173 emit obj.sig(QString("bubu"));
174 QCOMPARE(spy.count(), 1);
175 QCOMPARE(spy.at(0).count(), 1);
176 QCOMPARE(spy.at(0).at(0).toString(), QString("bubu"));
177
178 QSignalSpy spy2(&obj, SIGNAL(sig5(QVariant)));
179 QVariant val(45);
180 emit obj.sig5(v: val);
181 QCOMPARE(spy2.count(), 1);
182 QCOMPARE(spy2.at(0).count(), 1);
183 QCOMPARE(spy2.at(0).at(0), val);
184 QCOMPARE(qvariant_cast<QVariant>(spy2.at(0).at(0)), val);
185}
186
187void tst_QSignalSpy::spyWithQtClasses()
188{
189 QtTestObject2 obj;
190
191
192 QSignalSpy spy(&obj, SIGNAL(sig2(QDateTime)));
193 QDateTime dt = QDateTime::currentDateTime();
194 emit obj.sig2(dt);
195 QCOMPARE(spy.count(), 1);
196 QCOMPARE(spy.at(0).count(), 1);
197 QCOMPARE(spy.at(0).at(0).typeName(), "QDateTime");
198 QCOMPARE(*static_cast<const QDateTime *>(spy.at(0).at(0).constData()), dt);
199 QCOMPARE(spy.at(0).at(0).toDateTime(), dt);
200
201 QSignalSpy spy2(&obj, SIGNAL(sig3(QObject*)));
202 emit obj.sig3(o: this);
203 QCOMPARE(*static_cast<QObject * const *>(spy2.value(0).value(0).constData()),
204 (QObject *)this);
205 QCOMPARE(qvariant_cast<QObject *>(spy2.value(0).value(0)), (QObject*)this);
206
207 QSignalSpy spy3(&obj, SIGNAL(sig4(QChar)));
208 emit obj.sig4(c: QChar('A'));
209 QCOMPARE(qvariant_cast<QChar>(spy3.value(0).value(0)), QChar('A'));
210}
211
212class QtTestObject3: public QObject
213{
214 Q_OBJECT
215 friend class tst_QSignalSpy;
216
217signals:
218 void sig1(quint16);
219 void sig2(qlonglong, qulonglong);
220 void sig3(qint64, quint64);
221};
222
223void tst_QSignalSpy::spyWithQtTypedefs()
224{
225 QtTestObject3 obj;
226
227// QSignalSpy spy1(&obj, SIGNAL(sig1(quint16)));
228// emit obj.sig1(42);
229// QCOMPARE(spy1.value(0).value(0).toInt(), 42);
230
231 QSignalSpy spy2(&obj, SIGNAL(sig2(qlonglong,qulonglong)));
232 emit obj.sig2(42, 43);
233 QCOMPARE(spy2.value(0).value(0).toInt(), 42);
234 QCOMPARE(spy2.value(0).value(1).toInt(), 43);
235
236// QSignalSpy spy3(&obj, SIGNAL(sig3(qint64,quint64)));
237// emit obj.sig3(44, 45);
238// QCOMPARE(spy3.value(0).value(0).toInt(), 44);
239// QCOMPARE(spy3.value(0).value(1).toInt(), 45);
240}
241
242void tst_QSignalSpy::wait_signalEmitted()
243{
244 QTimer::singleShot(msec: 0, receiver: this, SIGNAL(sigFoo()));
245 QSignalSpy spy(this, SIGNAL(sigFoo()));
246 QVERIFY(spy.wait(1));
247}
248
249void tst_QSignalSpy::wait_timeout()
250{
251 QSignalSpy spy(this, SIGNAL(sigFoo()));
252 QVERIFY(!spy.wait(1));
253}
254
255void tst_QSignalSpy::wait_signalEmittedLater()
256{
257 QTimer::singleShot(msec: 500, receiver: this, SIGNAL(sigFoo()));
258 QSignalSpy spy(this, SIGNAL(sigFoo()));
259 QVERIFY(spy.wait(1000));
260}
261
262void tst_QSignalSpy::wait_signalEmittedTooLate()
263{
264 QTimer::singleShot(msec: 500, receiver: this, SIGNAL(sigFoo()));
265 QSignalSpy spy(this, SIGNAL(sigFoo()));
266 QVERIFY(!spy.wait(200));
267 QTRY_COMPARE(spy.count(), 1);
268}
269
270void tst_QSignalSpy::wait_signalEmittedMultipleTimes()
271{
272 QTimer::singleShot(msec: 100, receiver: this, SIGNAL(sigFoo()));
273 QTimer::singleShot(msec: 800, receiver: this, SIGNAL(sigFoo()));
274 QSignalSpy spy(this, SIGNAL(sigFoo()));
275 QVERIFY(spy.wait());
276 QCOMPARE(spy.count(), 1); // we don't wait for the second signal...
277 QVERIFY(spy.wait());
278 QCOMPARE(spy.count(), 2);
279 QVERIFY(!spy.wait(1));
280 QTimer::singleShot(msec: 10, receiver: this, SIGNAL(sigFoo()));
281 QVERIFY(spy.wait());
282 QCOMPARE(spy.count(), 3);
283}
284
285void tst_QSignalSpy::spyFunctionPointerWithoutArgs()
286{
287 QtTestObject obj;
288
289 QSignalSpy spy(&obj, &QtTestObject::sig0);
290 QCOMPARE(spy.count(), 0);
291
292 emit obj.sig0();
293 QCOMPARE(spy.count(), 1);
294 emit obj.sig0();
295 QCOMPARE(spy.count(), 2);
296
297 QList<QVariant> args = spy.takeFirst();
298 QCOMPARE(args.count(), 0);
299}
300
301void tst_QSignalSpy::spyFunctionPointerWithBasicArgs()
302{
303 QtTestObject obj;
304 QSignalSpy spy(&obj, &QtTestObject::sig1);
305
306 emit obj.sig1(1, 2);
307 QCOMPARE(spy.count(), 1);
308
309 QList<QVariant> args = spy.takeFirst();
310 QCOMPARE(args.count(), 2);
311 QCOMPARE(args.at(0).toInt(), 1);
312 QCOMPARE(args.at(1).toInt(), 2);
313
314 QSignalSpy spyl(&obj, &QtTestObject::sigLong);
315
316 emit obj.sigLong(1l, 2l);
317 args = spyl.takeFirst();
318 QCOMPARE(args.count(), 2);
319 QCOMPARE(qvariant_cast<long>(args.at(0)), 1l);
320 QCOMPARE(qvariant_cast<long>(args.at(1)), 2l);
321}
322
323
324void tst_QSignalSpy::spyFunctionPointerWithPointers()
325{
326 qRegisterMetaType<int *>(typeName: "int*");
327
328 QtTestObject obj;
329 QSignalSpy spy(&obj, &QtTestObject::sig2);
330
331 int i1 = 1;
332 int i2 = 2;
333
334 emit obj.sig2(&i1, &i2);
335 QCOMPARE(spy.count(), 1);
336
337 QList<QVariant> args = spy.takeFirst();
338 QCOMPARE(args.count(), 2);
339 QCOMPARE(*static_cast<int * const *>(args.at(0).constData()), &i1);
340 QCOMPARE(*static_cast<int * const *>(args.at(1).constData()), &i2);
341}
342
343void tst_QSignalSpy::spyFunctionPointerWithBasicQtClasses()
344{
345 QtTestObject2 obj;
346
347 QSignalSpy spy(&obj, &QtTestObject2::sig);
348 emit obj.sig(QString("bubu"));
349 QCOMPARE(spy.count(), 1);
350 QCOMPARE(spy.at(0).count(), 1);
351 QCOMPARE(spy.at(0).at(0).toString(), QString("bubu"));
352
353 QSignalSpy spy2(&obj, &QtTestObject2::sig5);
354 QVariant val(45);
355 emit obj.sig5(v: val);
356 QCOMPARE(spy2.count(), 1);
357 QCOMPARE(spy2.at(0).count(), 1);
358 QCOMPARE(spy2.at(0).at(0), val);
359 QCOMPARE(qvariant_cast<QVariant>(spy2.at(0).at(0)), val);
360}
361
362void tst_QSignalSpy::spyFunctionPointerWithQtClasses()
363{
364 QtTestObject2 obj;
365
366 QSignalSpy spy(&obj, &QtTestObject2::sig2);
367 QDateTime dt = QDateTime::currentDateTime();
368 emit obj.sig2(dt);
369 QCOMPARE(spy.count(), 1);
370 QCOMPARE(spy.at(0).count(), 1);
371 QCOMPARE(spy.at(0).at(0).typeName(), "QDateTime");
372 QCOMPARE(*static_cast<const QDateTime *>(spy.at(0).at(0).constData()), dt);
373 QCOMPARE(spy.at(0).at(0).toDateTime(), dt);
374
375 QSignalSpy spy2(&obj, &QtTestObject2::sig3);
376 emit obj.sig3(o: this);
377 QCOMPARE(*static_cast<QObject * const *>(spy2.value(0).value(0).constData()),
378 (QObject *)this);
379 QCOMPARE(qvariant_cast<QObject *>(spy2.value(0).value(0)), (QObject*)this);
380
381 QSignalSpy spy3(&obj, &QtTestObject2::sig4);
382 emit obj.sig4(c: QChar('A'));
383 QCOMPARE(qvariant_cast<QChar>(spy3.value(0).value(0)), QChar('A'));
384}
385
386void tst_QSignalSpy::spyFunctionPointerWithQtTypedefs()
387{
388 QtTestObject3 obj;
389
390 QSignalSpy spy2(&obj, &QtTestObject3::sig2);
391 emit obj.sig2(42, 43);
392 QCOMPARE(spy2.value(0).value(0).toInt(), 42);
393 QCOMPARE(spy2.value(0).value(1).toInt(), 43);
394}
395
396void tst_QSignalSpy::waitFunctionPointer_signalEmitted()
397{
398 QTimer::singleShot(msec: 0, receiver: this, SIGNAL(sigFoo()));
399 QSignalSpy spy(this, &tst_QSignalSpy::sigFoo);
400 QVERIFY(spy.wait(1));
401}
402
403void tst_QSignalSpy::waitFunctionPointer_timeout()
404{
405 QSignalSpy spy(this, &tst_QSignalSpy::sigFoo);
406 QVERIFY(!spy.wait(1));
407}
408
409void tst_QSignalSpy::waitFunctionPointer_signalEmittedLater()
410{
411 QTimer::singleShot(msec: 500, receiver: this, SIGNAL(sigFoo()));
412 QSignalSpy spy(this, &tst_QSignalSpy::sigFoo);
413 QVERIFY(spy.wait(1000));
414}
415
416void tst_QSignalSpy::waitFunctionPointer_signalEmittedTooLate()
417{
418 QTimer::singleShot(msec: 500, receiver: this, SIGNAL(sigFoo()));
419 QSignalSpy spy(this, &tst_QSignalSpy::sigFoo);
420 QVERIFY(!spy.wait(200));
421 QTest::qWait(ms: 400);
422 QCOMPARE(spy.count(), 1);
423}
424
425void tst_QSignalSpy::waitFunctionPointer_signalEmittedMultipleTimes()
426{
427 QTimer::singleShot(msec: 100, receiver: this, SIGNAL(sigFoo()));
428 QTimer::singleShot(msec: 800, receiver: this, SIGNAL(sigFoo()));
429 QSignalSpy spy(this, &tst_QSignalSpy::sigFoo);
430 QVERIFY(spy.wait());
431 QCOMPARE(spy.count(), 1); // we don't wait for the second signal...
432 QVERIFY(spy.wait());
433 QCOMPARE(spy.count(), 2);
434 QVERIFY(!spy.wait(1));
435 QTimer::singleShot(msec: 10, receiver: this, SIGNAL(sigFoo()));
436 QVERIFY(spy.wait());
437 QCOMPARE(spy.count(), 3);
438}
439
440void tst_QSignalSpy::spyOnMetaMethod()
441{
442 QObject obj;
443 auto mo = obj.metaObject();
444
445 auto signalIndex = mo->indexOfSignal(signal: "objectNameChanged(QString)");
446 QVERIFY(signalIndex != -1);
447
448 auto signal = mo->method(index: signalIndex);
449 QVERIFY(signal.isValid());
450 QCOMPARE(signal.methodType(), QMetaMethod::Signal);
451
452 QSignalSpy spy(&obj, signal);
453 QVERIFY(spy.isValid());
454
455 obj.setObjectName("A new object name");
456 QCOMPARE(spy.count(), 1);
457}
458
459Q_DECLARE_METATYPE(QMetaMethod);
460void tst_QSignalSpy::spyOnMetaMethod_invalid()
461{
462 QFETCH(QObject*, object);
463 QFETCH(QMetaMethod, signal);
464
465 QSignalSpy spy(object, signal);
466 QVERIFY(!spy.isValid());
467}
468
469void tst_QSignalSpy::spyOnMetaMethod_invalid_data()
470{
471 QTest::addColumn<QObject*>(name: "object");
472 QTest::addColumn<QMetaMethod>(name: "signal");
473
474 QTest::addRow(format: "Invalid object")
475 << static_cast<QObject*>(nullptr)
476 << QMetaMethod();
477
478 QTest::addRow(format: "Empty signal")
479 << new QObject(this)
480 << QMetaMethod();
481
482 QTest::addRow(format: "Method is not a signal")
483 << new QObject(this)
484 << QObject::staticMetaObject.method(index: QObject::staticMetaObject.indexOfMethod(method: "deleteLater()"));
485}
486
487QTEST_MAIN(tst_QSignalSpy)
488#include "tst_qsignalspy.moc"
489

source code of qtbase/tests/auto/testlib/qsignalspy/tst_qsignalspy.cpp