1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2016 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the test suite of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:GPL-EXCEPT$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU
20** General Public License version 3 as published by the Free Software
21** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include "tst_qcoreapplication.h"
31
32#include <QtCore/QtCore>
33#include <QtTest/QtTest>
34
35#include <private/qcoreapplication_p.h>
36#include <private/qeventloop_p.h>
37#include <private/qthread_p.h>
38
39typedef QCoreApplication TestApplication;
40
41class EventSpy : public QObject
42{
43 Q_OBJECT
44
45public:
46 QList<int> recordedEvents;
47 bool eventFilter(QObject *, QEvent *event)
48 {
49 recordedEvents.append(t: event->type());
50 return false;
51 }
52};
53
54class ThreadedEventReceiver : public QObject
55{
56 Q_OBJECT
57public:
58 QList<int> recordedEvents;
59 bool event(QEvent *event) override
60 {
61 if (event->type() != QEvent::Type(QEvent::User + 1))
62 return QObject::event(event);
63 recordedEvents.append(t: event->type());
64 QThread::currentThread()->quit();
65 QCoreApplication::quit();
66 moveToThread(thread: 0);
67 return true;
68 }
69};
70
71class Thread : public QDaemonThread
72{
73 void run() override
74 {
75 QThreadData *data = QThreadData::current();
76 QVERIFY(!data->requiresCoreApplication); // daemon thread
77 data->requiresCoreApplication = requiresCoreApplication;
78 QThread::run();
79 }
80
81public:
82 Thread() : requiresCoreApplication(true) {}
83 bool requiresCoreApplication;
84};
85
86void tst_QCoreApplication::sendEventsOnProcessEvents()
87{
88 int argc = 1;
89 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
90 TestApplication app(argc, argv);
91
92 EventSpy spy;
93 app.installEventFilter(filterObj: &spy);
94
95 QCoreApplication::postEvent(receiver: &app, event: new QEvent(QEvent::Type(QEvent::User + 1)));
96 QCoreApplication::processEvents();
97 QVERIFY(spy.recordedEvents.contains(QEvent::User + 1));
98}
99
100void tst_QCoreApplication::getSetCheck()
101{
102 // do not crash
103 QString v = QCoreApplication::applicationVersion();
104 v = QLatin1String("3.0.0 prerelease 1");
105 QCoreApplication::setApplicationVersion(v);
106 QCOMPARE(QCoreApplication::applicationVersion(), v);
107
108 // Test the property
109 {
110 int argc = 1;
111 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
112 TestApplication app(argc, argv);
113 QCOMPARE(app.property("applicationVersion").toString(), v);
114 }
115 v = QString();
116 QCoreApplication::setApplicationVersion(v);
117 QCOMPARE(QCoreApplication::applicationVersion(), v);
118}
119
120void tst_QCoreApplication::qAppName()
121{
122#ifdef QT_GUI_LIB
123 const char* appName = "tst_qguiapplication";
124#else
125 const char* appName = "tst_qcoreapplication";
126#endif
127
128 {
129 int argc = 1;
130 char *argv[] = { const_cast<char*>(appName) };
131 TestApplication app(argc, argv);
132 QCOMPARE(::qAppName(), QString::fromLatin1(appName));
133 QCOMPARE(QCoreApplication::applicationName(), QString::fromLatin1(appName));
134 }
135 // The application name should still be available after destruction;
136 // global statics often rely on this.
137 QCOMPARE(QCoreApplication::applicationName(), QString::fromLatin1(appName));
138
139 // Setting the appname before creating the application should work (QTBUG-45283)
140 const QString wantedAppName("my app name");
141 {
142 int argc = 1;
143 char *argv[] = { const_cast<char*>(appName) };
144 QCoreApplication::setApplicationName(wantedAppName);
145 TestApplication app(argc, argv);
146 QCOMPARE(::qAppName(), QString::fromLatin1(appName));
147 QCOMPARE(QCoreApplication::applicationName(), wantedAppName);
148 }
149 QCOMPARE(QCoreApplication::applicationName(), wantedAppName);
150
151 // Restore to initial value
152 QCoreApplication::setApplicationName(QString());
153 QCOMPARE(QCoreApplication::applicationName(), QString());
154}
155
156void tst_QCoreApplication::qAppVersion()
157{
158#if defined(Q_OS_WINRT)
159 const char appVersion[] = "1.0.0.0";
160#elif defined(Q_OS_WIN)
161 const char appVersion[] = "1.2.3.4";
162#elif defined(Q_OS_DARWIN) || defined(Q_OS_ANDROID)
163 const char appVersion[] = "1.2.3";
164#else
165 const char appVersion[] = "";
166#endif
167
168 {
169 int argc = 0;
170 char *argv[] = { nullptr };
171 TestApplication app(argc, argv);
172 QCOMPARE(QCoreApplication::applicationVersion(), QString::fromLatin1(appVersion));
173 }
174 // The application version should still be available after destruction
175 QCOMPARE(QCoreApplication::applicationVersion(), QString::fromLatin1(appVersion));
176
177 // Setting the appversion before creating the application should work
178 const QString wantedAppVersion("0.0.1");
179 {
180 int argc = 0;
181 char *argv[] = { nullptr };
182 QCoreApplication::setApplicationVersion(wantedAppVersion);
183 TestApplication app(argc, argv);
184 QCOMPARE(QCoreApplication::applicationVersion(), wantedAppVersion);
185 }
186 QCOMPARE(QCoreApplication::applicationVersion(), wantedAppVersion);
187
188 // Restore to initial value
189 QCoreApplication::setApplicationVersion(QString());
190 QCOMPARE(QCoreApplication::applicationVersion(), QString());
191}
192
193void tst_QCoreApplication::argc()
194{
195#if defined(Q_OS_WINRT)
196 QSKIP("QCoreApplication::arguments() parses arguments from actual command line on this platform.");
197#endif
198 {
199 int argc = 1;
200 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
201 TestApplication app(argc, argv);
202 QCOMPARE(argc, 1);
203 QCOMPARE(app.arguments().count(), 1);
204 }
205
206 {
207 int argc = 4;
208 char *argv[] = { const_cast<char*>(QTest::currentAppName()),
209 const_cast<char*>("arg1"),
210 const_cast<char*>("arg2"),
211 const_cast<char*>("arg3") };
212 TestApplication app(argc, argv);
213 QCOMPARE(argc, 4);
214 QCOMPARE(app.arguments().count(), 4);
215 }
216
217 {
218 int argc = 0;
219 char **argv = 0;
220 TestApplication app(argc, argv);
221 QCOMPARE(argc, 0);
222 QCOMPARE(app.arguments().count(), 0);
223 }
224
225 {
226 int argc = 2;
227 char *argv[] = { const_cast<char*>(QTest::currentAppName()),
228 const_cast<char*>("-qmljsdebugger=port:3768,block") };
229 TestApplication app(argc, argv);
230 QCOMPARE(argc, 1);
231 QCOMPARE(app.arguments().count(), 1);
232 }
233}
234
235class EventGenerator : public QObject
236{
237 Q_OBJECT
238
239public:
240 QObject *other;
241
242 bool event(QEvent *e)
243 {
244 if (e->type() == QEvent::MaxUser) {
245 QCoreApplication::sendPostedEvents(receiver: other, event_type: 0);
246 } else if (e->type() <= QEvent::User + 999) {
247 // post a new event in response to this posted event
248 int offset = e->type() - QEvent::User;
249 offset = (offset * 10 + offset % 10);
250 QCoreApplication::postEvent(receiver: this, event: new QEvent(QEvent::Type(QEvent::User + offset)), priority: offset);
251 }
252
253 return QObject::event(event: e);
254 }
255};
256
257void tst_QCoreApplication::postEvent()
258{
259 int argc = 1;
260 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
261 TestApplication app(argc, argv);
262
263 EventSpy spy;
264 EventGenerator odd, even;
265 odd.other = &even;
266 odd.installEventFilter(filterObj: &spy);
267 even.other = &odd;
268 even.installEventFilter(filterObj: &spy);
269
270 QCoreApplication::postEvent(receiver: &odd, event: new QEvent(QEvent::Type(QEvent::User + 1)));
271 QCoreApplication::postEvent(receiver: &even, event: new QEvent(QEvent::Type(QEvent::User + 2)));
272
273 QCoreApplication::postEvent(receiver: &odd, event: new QEvent(QEvent::Type(QEvent::User + 3)), priority: 1);
274 QCoreApplication::postEvent(receiver: &even, event: new QEvent(QEvent::Type(QEvent::User + 4)), priority: 2);
275
276 QCoreApplication::postEvent(receiver: &odd, event: new QEvent(QEvent::Type(QEvent::User + 5)), priority: -2);
277 QCoreApplication::postEvent(receiver: &even, event: new QEvent(QEvent::Type(QEvent::User + 6)), priority: -1);
278
279 QList<int> expected;
280 expected << QEvent::User + 4
281 << QEvent::User + 3
282 << QEvent::User + 1
283 << QEvent::User + 2
284 << QEvent::User + 6
285 << QEvent::User + 5;
286
287 QCoreApplication::sendPostedEvents();
288 // live lock protection ensures that we only send the initial events
289 QCOMPARE(spy.recordedEvents, expected);
290
291 expected.clear();
292 expected << QEvent::User + 66
293 << QEvent::User + 55
294 << QEvent::User + 44
295 << QEvent::User + 33
296 << QEvent::User + 22
297 << QEvent::User + 11;
298
299 spy.recordedEvents.clear();
300 QCoreApplication::sendPostedEvents();
301 // expect next sequence events
302 QCOMPARE(spy.recordedEvents, expected);
303
304 // have the generators call sendPostedEvents() on each other in
305 // response to an event
306 QCoreApplication::postEvent(receiver: &odd, event: new QEvent(QEvent::MaxUser), INT_MAX);
307 QCoreApplication::postEvent(receiver: &even, event: new QEvent(QEvent::MaxUser), INT_MAX);
308
309 expected.clear();
310 expected << int(QEvent::MaxUser)
311 << int(QEvent::MaxUser)
312 << QEvent::User + 555
313 << QEvent::User + 333
314 << QEvent::User + 111
315 << QEvent::User + 666
316 << QEvent::User + 444
317 << QEvent::User + 222;
318
319 spy.recordedEvents.clear();
320 QCoreApplication::sendPostedEvents();
321 QCOMPARE(spy.recordedEvents, expected);
322
323 expected.clear();
324 expected << QEvent::User + 6666
325 << QEvent::User + 5555
326 << QEvent::User + 4444
327 << QEvent::User + 3333
328 << QEvent::User + 2222
329 << QEvent::User + 1111;
330
331 spy.recordedEvents.clear();
332 QCoreApplication::sendPostedEvents();
333 QCOMPARE(spy.recordedEvents, expected);
334
335 // no more events
336 expected.clear();
337 spy.recordedEvents.clear();
338 QCoreApplication::sendPostedEvents();
339 QCOMPARE(spy.recordedEvents, expected);
340}
341
342void tst_QCoreApplication::removePostedEvents()
343{
344 int argc = 1;
345 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
346 TestApplication app(argc, argv);
347
348 EventSpy spy;
349 QObject one, two;
350 one.installEventFilter(filterObj: &spy);
351 two.installEventFilter(filterObj: &spy);
352
353 QList<int> expected;
354
355 // remove all events for one object
356 QCoreApplication::postEvent(receiver: &one, event: new QEvent(QEvent::Type(QEvent::User + 1)));
357 QCoreApplication::postEvent(receiver: &one, event: new QEvent(QEvent::Type(QEvent::User + 2)));
358 QCoreApplication::postEvent(receiver: &one, event: new QEvent(QEvent::Type(QEvent::User + 3)));
359 QCoreApplication::postEvent(receiver: &two, event: new QEvent(QEvent::Type(QEvent::User + 4)));
360 QCoreApplication::postEvent(receiver: &two, event: new QEvent(QEvent::Type(QEvent::User + 5)));
361 QCoreApplication::postEvent(receiver: &two, event: new QEvent(QEvent::Type(QEvent::User + 6)));
362 QCoreApplication::removePostedEvents(receiver: &one);
363 expected << QEvent::User + 4
364 << QEvent::User + 5
365 << QEvent::User + 6;
366 QCoreApplication::sendPostedEvents();
367 QCOMPARE(spy.recordedEvents, expected);
368 spy.recordedEvents.clear();
369 expected.clear();
370
371 // remove all events for all objects
372 QCoreApplication::postEvent(receiver: &one, event: new QEvent(QEvent::Type(QEvent::User + 7)));
373 QCoreApplication::postEvent(receiver: &two, event: new QEvent(QEvent::Type(QEvent::User + 8)));
374 QCoreApplication::postEvent(receiver: &one, event: new QEvent(QEvent::Type(QEvent::User + 9)));
375 QCoreApplication::postEvent(receiver: &two, event: new QEvent(QEvent::Type(QEvent::User + 10)));
376 QCoreApplication::postEvent(receiver: &one, event: new QEvent(QEvent::Type(QEvent::User + 11)));
377 QCoreApplication::postEvent(receiver: &two, event: new QEvent(QEvent::Type(QEvent::User + 12)));
378 QCoreApplication::removePostedEvents(receiver: 0);
379 QCoreApplication::sendPostedEvents();
380 QVERIFY(spy.recordedEvents.isEmpty());
381
382 // remove a specific type of event for one object
383 QCoreApplication::postEvent(receiver: &one, event: new QEvent(QEvent::Type(QEvent::User + 13)));
384 QCoreApplication::postEvent(receiver: &two, event: new QEvent(QEvent::Type(QEvent::User + 14)));
385 QCoreApplication::postEvent(receiver: &one, event: new QEvent(QEvent::Type(QEvent::User + 15)));
386 QCoreApplication::postEvent(receiver: &two, event: new QEvent(QEvent::Type(QEvent::User + 16)));
387 QCoreApplication::postEvent(receiver: &one, event: new QEvent(QEvent::Type(QEvent::User + 17)));
388 QCoreApplication::postEvent(receiver: &two, event: new QEvent(QEvent::Type(QEvent::User + 18)));
389 QCoreApplication::removePostedEvents(receiver: &one, eventType: QEvent::User + 13);
390 QCoreApplication::removePostedEvents(receiver: &two, eventType: QEvent::User + 18);
391 QCoreApplication::sendPostedEvents();
392 expected << QEvent::User + 14
393 << QEvent::User + 15
394 << QEvent::User + 16
395 << QEvent::User + 17;
396 QCOMPARE(spy.recordedEvents, expected);
397 spy.recordedEvents.clear();
398 expected.clear();
399
400 // remove a specific type of event for all objects
401 QCoreApplication::postEvent(receiver: &one, event: new QEvent(QEvent::Type(QEvent::User + 19)));
402 QCoreApplication::postEvent(receiver: &two, event: new QEvent(QEvent::Type(QEvent::User + 19)));
403 QCoreApplication::postEvent(receiver: &one, event: new QEvent(QEvent::Type(QEvent::User + 20)));
404 QCoreApplication::postEvent(receiver: &two, event: new QEvent(QEvent::Type(QEvent::User + 20)));
405 QCoreApplication::postEvent(receiver: &one, event: new QEvent(QEvent::Type(QEvent::User + 21)));
406 QCoreApplication::postEvent(receiver: &two, event: new QEvent(QEvent::Type(QEvent::User + 21)));
407 QCoreApplication::removePostedEvents(receiver: 0, eventType: QEvent::User + 20);
408 QCoreApplication::sendPostedEvents();
409 expected << QEvent::User + 19
410 << QEvent::User + 19
411 << QEvent::User + 21
412 << QEvent::User + 21;
413 QCOMPARE(spy.recordedEvents, expected);
414 spy.recordedEvents.clear();
415 expected.clear();
416}
417
418#if QT_CONFIG(thread)
419class DeliverInDefinedOrderThread : public QThread
420{
421 Q_OBJECT
422
423public:
424 DeliverInDefinedOrderThread()
425 : QThread()
426 { }
427
428signals:
429 void progress(int);
430
431protected:
432 void run()
433 {
434 emit progress(1);
435 emit progress(2);
436 emit progress(3);
437 emit progress(4);
438 emit progress(5);
439 emit progress(6);
440 emit progress(7);
441 }
442};
443
444class DeliverInDefinedOrderObject : public QObject
445{
446 Q_OBJECT
447
448 QPointer<QThread> thread;
449 int count;
450 int startCount;
451 int loopLevel;
452
453public:
454 DeliverInDefinedOrderObject(QObject *parent)
455 : QObject(parent), thread(0), count(0), startCount(0), loopLevel(0)
456 { }
457
458signals:
459 void done();
460
461public slots:
462 void startThread()
463 {
464 QVERIFY(!thread);
465 thread = new DeliverInDefinedOrderThread();
466 connect(sender: thread, SIGNAL(progress(int)), receiver: this, SLOT(threadProgress(int)));
467 connect(sender: thread, SIGNAL(finished()), receiver: this, SLOT(threadFinished()));
468 connect(sender: thread, SIGNAL(destroyed()), receiver: this, SLOT(threadDestroyed()));
469 thread->start();
470
471 QCoreApplication::postEvent(receiver: this, event: new QEvent(QEvent::MaxUser), priority: -1);
472 }
473
474 void threadProgress(int v)
475 {
476 ++count;
477 QCOMPARE(v, count);
478
479 QCoreApplication::postEvent(receiver: this, event: new QEvent(QEvent::MaxUser), priority: -1);
480 }
481
482 void threadFinished()
483 {
484 QCOMPARE(count, 7);
485 count = 0;
486 thread->deleteLater();
487
488 QCoreApplication::postEvent(receiver: this, event: new QEvent(QEvent::MaxUser), priority: -1);
489 }
490
491 void threadDestroyed()
492 {
493 if (++startCount < 20)
494 startThread();
495 else
496 emit done();
497 }
498
499public:
500 bool event(QEvent *event)
501 {
502 switch (event->type()) {
503 case QEvent::User:
504 {
505 ++loopLevel;
506 if (loopLevel == 2) {
507 // Ready. Starts a thread that emits (queued) signals, which should be handled in order
508 startThread();
509 }
510 QCoreApplication::postEvent(receiver: this, event: new QEvent(QEvent::MaxUser), priority: -1);
511 (void) QEventLoop().exec();
512 break;
513 }
514 default:
515 break;
516 }
517 return QObject::event(event);
518 }
519};
520
521void tst_QCoreApplication::deliverInDefinedOrder()
522{
523 int argc = 1;
524 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
525 TestApplication app(argc, argv);
526
527 DeliverInDefinedOrderObject obj(&app);
528 // causes sendPostedEvents() to recurse twice
529 QCoreApplication::postEvent(receiver: &obj, event: new QEvent(QEvent::User));
530 QCoreApplication::postEvent(receiver: &obj, event: new QEvent(QEvent::User));
531
532 QObject::connect(sender: &obj, SIGNAL(done()), receiver: &app, SLOT(quit()));
533 app.exec();
534}
535#endif // QT_CONFIG(thread)
536
537void tst_QCoreApplication::applicationPid()
538{
539 QVERIFY(QCoreApplication::applicationPid() > 0);
540}
541
542QT_BEGIN_NAMESPACE
543Q_CORE_EXPORT uint qGlobalPostedEventsCount();
544QT_END_NAMESPACE
545
546class GlobalPostedEventsCountObject : public QObject
547{
548 Q_OBJECT
549
550public:
551 QList<int> globalPostedEventsCount;
552
553 bool event(QEvent *event)
554 {
555 if (event->type() == QEvent::User)
556 globalPostedEventsCount.append(t: qGlobalPostedEventsCount());
557 return QObject::event(event);
558 }
559};
560
561void tst_QCoreApplication::globalPostedEventsCount()
562{
563 int argc = 1;
564 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
565 TestApplication app(argc, argv);
566
567 QCoreApplication::sendPostedEvents();
568 QCOMPARE(qGlobalPostedEventsCount(), 0u);
569
570 GlobalPostedEventsCountObject x;
571 QCoreApplication::postEvent(receiver: &x, event: new QEvent(QEvent::User));
572 QCoreApplication::postEvent(receiver: &x, event: new QEvent(QEvent::User));
573 QCoreApplication::postEvent(receiver: &x, event: new QEvent(QEvent::User));
574 QCoreApplication::postEvent(receiver: &x, event: new QEvent(QEvent::User));
575 QCoreApplication::postEvent(receiver: &x, event: new QEvent(QEvent::User));
576 QCOMPARE(qGlobalPostedEventsCount(), 5u);
577
578 QCoreApplication::sendPostedEvents();
579 QCOMPARE(qGlobalPostedEventsCount(), 0u);
580
581 QList<int> expected = QList<int>()
582 << 4
583 << 3
584 << 2
585 << 1
586 << 0;
587 QCOMPARE(x.globalPostedEventsCount, expected);
588}
589
590class ProcessEventsAlwaysSendsPostedEventsObject : public QObject
591{
592public:
593 int counter;
594
595 inline ProcessEventsAlwaysSendsPostedEventsObject()
596 : counter(0)
597 { }
598
599 bool event(QEvent *event)
600 {
601 if (event->type() == QEvent::User)
602 ++counter;
603 return QObject::event(event);
604 }
605};
606
607void tst_QCoreApplication::processEventsAlwaysSendsPostedEvents()
608{
609 int argc = 1;
610 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
611 TestApplication app(argc, argv);
612
613 ProcessEventsAlwaysSendsPostedEventsObject object;
614 QElapsedTimer t;
615 t.start();
616 int i = 1;
617 do {
618 QCoreApplication::postEvent(receiver: &object, event: new QEvent(QEvent::User));
619 QCoreApplication::processEvents();
620 QCOMPARE(object.counter, i);
621 ++i;
622 } while (t.elapsed() < 1000);
623}
624
625void tst_QCoreApplication::reexec()
626{
627 int argc = 1;
628 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
629 TestApplication app(argc, argv);
630
631 // exec once
632 QMetaObject::invokeMethod(obj: &app, member: "quit", type: Qt::QueuedConnection);
633 QCOMPARE(app.exec(), 0);
634
635 // and again
636 QMetaObject::invokeMethod(obj: &app, member: "quit", type: Qt::QueuedConnection);
637 QCOMPARE(app.exec(), 0);
638}
639
640void tst_QCoreApplication::execAfterExit()
641{
642 int argc = 1;
643 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
644 TestApplication app(argc, argv);
645
646 app.exit(retcode: 1);
647 QMetaObject::invokeMethod(obj: &app, member: "quit", type: Qt::QueuedConnection);
648 QCOMPARE(app.exec(), 0);
649}
650
651void tst_QCoreApplication::eventLoopExecAfterExit()
652{
653 int argc = 1;
654 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
655 TestApplication app(argc, argv);
656
657 // exec once and exit
658 QMetaObject::invokeMethod(obj: &app, member: "quit", type: Qt::QueuedConnection);
659 QCOMPARE(app.exec(), 0);
660
661 // and again, but this time using a QEventLoop
662 QEventLoop loop;
663 QMetaObject::invokeMethod(obj: &loop, member: "quit", type: Qt::QueuedConnection);
664 QCOMPARE(loop.exec(), 0);
665}
666
667class DummyEventDispatcher : public QAbstractEventDispatcher {
668public:
669 DummyEventDispatcher() : QAbstractEventDispatcher(), visited(false) {}
670 bool processEvents(QEventLoop::ProcessEventsFlags) {
671 visited = true;
672 emit awake();
673 QCoreApplication::sendPostedEvents();
674 return false;
675 }
676 bool hasPendingEvents() {
677 return qGlobalPostedEventsCount();
678 }
679 void registerSocketNotifier(QSocketNotifier *) {}
680 void unregisterSocketNotifier(QSocketNotifier *) {}
681 void registerTimer(int , int , Qt::TimerType, QObject *) {}
682 bool unregisterTimer(int ) { return false; }
683 bool unregisterTimers(QObject *) { return false; }
684 QList<TimerInfo> registeredTimers(QObject *) const { return QList<TimerInfo>(); }
685 int remainingTime(int) { return 0; }
686 void wakeUp() {}
687 void interrupt() {}
688 void flush() {}
689
690#ifdef Q_OS_WIN
691 bool registerEventNotifier(QWinEventNotifier *) { return false; }
692 void unregisterEventNotifier(QWinEventNotifier *) { }
693#endif
694
695 bool visited;
696};
697
698void tst_QCoreApplication::customEventDispatcher()
699{
700 // there should be no ED yet
701 QVERIFY(!QCoreApplication::eventDispatcher());
702 DummyEventDispatcher *ed = new DummyEventDispatcher;
703 QCoreApplication::setEventDispatcher(ed);
704 // the new ED should be set
705 QCOMPARE(QCoreApplication::eventDispatcher(), ed);
706 // test the alternative API of QAbstractEventDispatcher
707 QCOMPARE(QAbstractEventDispatcher::instance(), ed);
708 QPointer<DummyEventDispatcher> weak_ed(ed);
709 QVERIFY(!weak_ed.isNull());
710 {
711 int argc = 1;
712 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
713 TestApplication app(argc, argv);
714 // instantiating app should not overwrite the ED
715 QCOMPARE(QCoreApplication::eventDispatcher(), ed);
716 QMetaObject::invokeMethod(obj: &app, member: "quit", type: Qt::QueuedConnection);
717 app.exec();
718 // the custom ED has really been used?
719 QVERIFY(ed->visited);
720 }
721 // ED has been deleted?
722 QVERIFY(weak_ed.isNull());
723}
724
725class JobObject : public QObject
726{
727 Q_OBJECT
728public:
729
730 explicit JobObject(QEventLoop *loop, QObject *parent = 0)
731 : QObject(parent), locker(loop)
732 {
733 QTimer::singleShot(msec: 1000, receiver: this, SLOT(timeout()));
734 }
735
736 explicit JobObject(QObject *parent = 0)
737 : QObject(parent)
738 {
739 QTimer::singleShot(msec: 1000, receiver: this, SLOT(timeout()));
740 }
741
742public slots:
743 void startSecondaryJob()
744 {
745 new JobObject();
746 }
747
748private slots:
749 void timeout()
750 {
751 emit done();
752 deleteLater();
753 }
754
755signals:
756 void done();
757
758private:
759 QEventLoopLocker locker;
760};
761
762class QuitTester : public QObject
763{
764 Q_OBJECT
765public:
766 QuitTester(QObject *parent = 0)
767 : QObject(parent)
768 {
769 QTimer::singleShot(msec: 0, receiver: this, SLOT(doTest()));
770 }
771
772private slots:
773 void doTest()
774 {
775 QCoreApplicationPrivate *privateClass = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp));
776
777 {
778 QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 0);
779 // Test with a lock active so that the refcount doesn't drop to zero during these tests, causing a quit.
780 // (until we exit the scope)
781 QEventLoopLocker locker;
782
783 QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 1);
784
785 JobObject *job1 = new JobObject(this);
786
787 QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 2);
788
789 delete job1;
790
791 QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 1);
792
793 job1 = new JobObject(this);
794
795 QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 2);
796
797 JobObject *job2 = new JobObject(this);
798
799 QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 3);
800
801 delete job1;
802
803 QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 2);
804
805 JobObject *job3 = new JobObject(job2);
806 Q_UNUSED(job3);
807
808 QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 3);
809
810 JobObject *job4 = new JobObject(job2);
811 Q_UNUSED(job4);
812
813 QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 4);
814
815 delete job2;
816
817 QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 1);
818
819 }
820 QCOMPARE(privateClass->quitLockRef.loadRelaxed(), 0);
821 }
822};
823
824void tst_QCoreApplication::testQuitLock()
825{
826 int argc = 1;
827 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
828 TestApplication app(argc, argv);
829
830 QuitTester tester;
831 app.exec();
832}
833
834
835void tst_QCoreApplication::QTBUG31606_QEventDestructorDeadLock()
836{
837 class MyEvent : public QEvent
838 { public:
839 MyEvent() : QEvent(QEvent::Type(QEvent::User + 1)) {}
840 ~MyEvent() {
841 QCoreApplication::postEvent(qApp, event: new QEvent(QEvent::Type(QEvent::User+2)));
842 }
843 };
844
845 int argc = 1;
846 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
847 TestApplication app(argc, argv);
848
849 EventSpy spy;
850 app.installEventFilter(filterObj: &spy);
851
852 QCoreApplication::postEvent(receiver: &app, event: new MyEvent);
853 QCoreApplication::processEvents();
854 QVERIFY(spy.recordedEvents.contains(QEvent::User + 1));
855 QVERIFY(!spy.recordedEvents.contains(QEvent::User + 2));
856 QCoreApplication::processEvents();
857 QVERIFY(spy.recordedEvents.contains(QEvent::User + 2));
858}
859
860// this is almost identical to sendEventsOnProcessEvents
861void tst_QCoreApplication::applicationEventFilters_mainThread()
862{
863 int argc = 1;
864 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
865 TestApplication app(argc, argv);
866
867 EventSpy spy;
868 app.installEventFilter(filterObj: &spy);
869
870 QCoreApplication::postEvent(receiver: &app, event: new QEvent(QEvent::Type(QEvent::User + 1)));
871 QTimer::singleShot(msec: 10, receiver: &app, SLOT(quit()));
872 app.exec();
873 QVERIFY(spy.recordedEvents.contains(QEvent::User + 1));
874}
875
876void tst_QCoreApplication::applicationEventFilters_auxThread()
877{
878 int argc = 1;
879 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
880 TestApplication app(argc, argv);
881 QThread thread;
882 ThreadedEventReceiver receiver;
883 receiver.moveToThread(thread: &thread);
884
885 EventSpy spy;
886 app.installEventFilter(filterObj: &spy);
887
888 // this is very similar to sendEventsOnProcessEvents
889 QCoreApplication::postEvent(receiver: &receiver, event: new QEvent(QEvent::Type(QEvent::User + 1)));
890 QTimer::singleShot(msec: 1000, receiver: &app, SLOT(quit()));
891 thread.start();
892 app.exec();
893 QVERIFY(thread.wait(1000));
894 QVERIFY(receiver.recordedEvents.contains(QEvent::User + 1));
895 QVERIFY(!spy.recordedEvents.contains(QEvent::User + 1));
896}
897
898void tst_QCoreApplication::threadedEventDelivery_data()
899{
900 QTest::addColumn<bool>(name: "requiresCoreApplication");
901 QTest::addColumn<bool>(name: "createCoreApplication");
902 QTest::addColumn<bool>(name: "eventsReceived");
903
904 // invalid combination:
905 //QTest::newRow("default-without-coreapp") << true << false << false;
906 QTest::newRow(dataTag: "default") << true << true << true;
907 QTest::newRow(dataTag: "independent-without-coreapp") << false << false << true;
908 QTest::newRow(dataTag: "independent-with-coreapp") << false << true << true;
909}
910
911// posts the event before the QCoreApplication is destroyed, starts thread after
912void tst_QCoreApplication::threadedEventDelivery()
913{
914 QFETCH(bool, requiresCoreApplication);
915 QFETCH(bool, createCoreApplication);
916 QFETCH(bool, eventsReceived);
917
918 int argc = 1;
919 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
920 QScopedPointer<TestApplication> app(createCoreApplication ? new TestApplication(argc, argv) : 0);
921
922 Thread thread;
923 thread.requiresCoreApplication = requiresCoreApplication;
924 ThreadedEventReceiver receiver;
925 receiver.moveToThread(thread: &thread);
926 QCoreApplication::postEvent(receiver: &receiver, event: new QEvent(QEvent::Type(QEvent::User + 1)));
927
928 thread.start();
929 QVERIFY(thread.wait(1000));
930 QCOMPARE(receiver.recordedEvents.contains(QEvent::User + 1), eventsReceived);
931
932}
933
934void tst_QCoreApplication::testTrWithPercantegeAtTheEnd()
935{
936 QCoreApplication::translate(context: "testcontext", key: "this will crash%", disambiguation: "testdisamb", n: 3);
937}
938
939#if QT_CONFIG(library)
940void tst_QCoreApplication::addRemoveLibPaths()
941{
942 QStringList paths = QCoreApplication::libraryPaths();
943 if (paths.isEmpty())
944 QSKIP("Cannot add/remove library paths if there are none.");
945
946 QString currentDir = QDir().absolutePath();
947 QCoreApplication::addLibraryPath(currentDir);
948 QVERIFY(QCoreApplication::libraryPaths().contains(currentDir));
949
950 QCoreApplication::removeLibraryPath(paths[0]);
951 QVERIFY(!QCoreApplication::libraryPaths().contains(paths[0]));
952
953 int argc = 1;
954 char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
955 TestApplication app(argc, argv);
956
957 // If libraryPaths only contains currentDir, neither will be in libraryPaths now.
958 if (paths.length() != 1 && currentDir != paths[0]) {
959 // Check that modifications stay alive across the creation of an application.
960 QVERIFY(QCoreApplication::libraryPaths().contains(currentDir));
961 QVERIFY(!QCoreApplication::libraryPaths().contains(paths[0]));
962 }
963
964 QStringList replace;
965 replace << currentDir << paths[0];
966 QCoreApplication::setLibraryPaths(replace);
967 QCOMPARE(QCoreApplication::libraryPaths(), replace);
968}
969#endif
970
971static void createQObjectOnDestruction()
972{
973 // Make sure that we can create a QObject after the last QObject has been
974 // destroyed (especially after QCoreApplication has).
975 //
976 // Before the fixes, this would cause a dangling pointer dereference. If
977 // the problem comes back, it's possible that the following causes no
978 // effect.
979 QObject obj;
980 obj.thread()->setProperty(name: "testing", value: 1);
981}
982Q_DESTRUCTOR_FUNCTION(createQObjectOnDestruction)
983
984#ifndef QT_GUI_LIB
985QTEST_APPLESS_MAIN(tst_QCoreApplication)
986#endif
987
988#include "tst_qcoreapplication.moc"
989

source code of qtbase/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp