| 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 |  | 
| 39 | typedef QCoreApplication TestApplication; | 
| 40 |  | 
| 41 | class EventSpy : public QObject | 
| 42 | { | 
| 43 |    Q_OBJECT | 
| 44 |  | 
| 45 | public: | 
| 46 |     QList<int> recordedEvents; | 
| 47 |     bool eventFilter(QObject *, QEvent *event) | 
| 48 |     { | 
| 49 |         recordedEvents.append(t: event->type()); | 
| 50 |         return false; | 
| 51 |     } | 
| 52 | }; | 
| 53 |  | 
| 54 | class ThreadedEventReceiver : public QObject | 
| 55 | { | 
| 56 |     Q_OBJECT | 
| 57 | public: | 
| 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 |  | 
| 71 | class 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 |  | 
| 81 | public: | 
| 82 |     Thread() : requiresCoreApplication(true) {} | 
| 83 |     bool requiresCoreApplication; | 
| 84 | }; | 
| 85 |  | 
| 86 | void 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 |  | 
| 100 | void 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 |  | 
| 120 | void 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 |  | 
| 156 | void 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 |  | 
| 193 | void 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 |  | 
| 235 | class EventGenerator : public QObject | 
| 236 | { | 
| 237 |     Q_OBJECT | 
| 238 |  | 
| 239 | public: | 
| 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 |  | 
| 257 | void 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 |  | 
| 342 | void 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) | 
| 419 | class DeliverInDefinedOrderThread : public QThread | 
| 420 | { | 
| 421 |     Q_OBJECT | 
| 422 |  | 
| 423 | public: | 
| 424 |     DeliverInDefinedOrderThread() | 
| 425 |         : QThread() | 
| 426 |     { } | 
| 427 |  | 
| 428 | signals: | 
| 429 |     void progress(int); | 
| 430 |  | 
| 431 | protected: | 
| 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 |  | 
| 444 | class DeliverInDefinedOrderObject : public QObject | 
| 445 | { | 
| 446 |     Q_OBJECT | 
| 447 |  | 
| 448 |     QPointer<QThread> thread; | 
| 449 |     int count; | 
| 450 |     int startCount; | 
| 451 |     int loopLevel; | 
| 452 |  | 
| 453 | public: | 
| 454 |     DeliverInDefinedOrderObject(QObject *parent) | 
| 455 |         : QObject(parent), thread(0), count(0), startCount(0), loopLevel(0) | 
| 456 |     { } | 
| 457 |  | 
| 458 | signals: | 
| 459 |     void done(); | 
| 460 |  | 
| 461 | public 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 |  | 
| 499 | public: | 
| 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 |  | 
| 521 | void 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 |  | 
| 537 | void tst_QCoreApplication::applicationPid() | 
| 538 | { | 
| 539 |     QVERIFY(QCoreApplication::applicationPid() > 0); | 
| 540 | } | 
| 541 |  | 
| 542 | QT_BEGIN_NAMESPACE | 
| 543 | Q_CORE_EXPORT uint qGlobalPostedEventsCount(); | 
| 544 | QT_END_NAMESPACE | 
| 545 |  | 
| 546 | class GlobalPostedEventsCountObject : public QObject | 
| 547 | { | 
| 548 |     Q_OBJECT | 
| 549 |  | 
| 550 | public: | 
| 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 |  | 
| 561 | void 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 |  | 
| 590 | class ProcessEventsAlwaysSendsPostedEventsObject : public QObject | 
| 591 | { | 
| 592 | public: | 
| 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 |  | 
| 607 | void 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 |  | 
| 625 | void 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 |  | 
| 640 | void 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 |  | 
| 651 | void 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 |  | 
| 667 | class DummyEventDispatcher : public QAbstractEventDispatcher { | 
| 668 | public: | 
| 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 |  | 
| 698 | void 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 |  | 
| 725 | class JobObject : public QObject | 
| 726 | { | 
| 727 |     Q_OBJECT | 
| 728 | public: | 
| 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 |  | 
| 742 | public slots: | 
| 743 |     void startSecondaryJob() | 
| 744 |     { | 
| 745 |         new JobObject(); | 
| 746 |     } | 
| 747 |  | 
| 748 | private slots: | 
| 749 |     void timeout() | 
| 750 |     { | 
| 751 |         emit done(); | 
| 752 |         deleteLater(); | 
| 753 |     } | 
| 754 |  | 
| 755 | signals: | 
| 756 |     void done(); | 
| 757 |  | 
| 758 | private: | 
| 759 |     QEventLoopLocker locker; | 
| 760 | }; | 
| 761 |  | 
| 762 | class QuitTester : public QObject | 
| 763 | { | 
| 764 |     Q_OBJECT | 
| 765 | public: | 
| 766 |     QuitTester(QObject *parent = 0) | 
| 767 |       : QObject(parent) | 
| 768 |     { | 
| 769 |         QTimer::singleShot(msec: 0, receiver: this, SLOT(doTest())); | 
| 770 |     } | 
| 771 |  | 
| 772 | private 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 |  | 
| 824 | void 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 |  | 
| 835 | void 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 | 
| 861 | void 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 |  | 
| 876 | void 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 |  | 
| 898 | void 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 | 
| 912 | void 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 |  | 
| 934 | void tst_QCoreApplication::testTrWithPercantegeAtTheEnd() | 
| 935 | { | 
| 936 |     QCoreApplication::translate(context: "testcontext" , key: "this will crash%" , disambiguation: "testdisamb" , n: 3); | 
| 937 | } | 
| 938 |  | 
| 939 | #if QT_CONFIG(library) | 
| 940 | void 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 |  | 
| 971 | static 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 | } | 
| 982 | Q_DESTRUCTOR_FUNCTION(createQObjectOnDestruction) | 
| 983 |  | 
| 984 | #ifndef QT_GUI_LIB | 
| 985 | QTEST_APPLESS_MAIN(tst_QCoreApplication) | 
| 986 | #endif | 
| 987 |  | 
| 988 | #include "tst_qcoreapplication.moc" | 
| 989 |  |