summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp')
-rw-r--r--tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp337
1 files changed, 260 insertions, 77 deletions
diff --git a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp
index 2e755351ee..8f8ab33e64 100644
--- a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp
+++ b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp
@@ -1,41 +1,22 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "tst_qcoreapplication.h"
#include <QtCore/QtCore>
-#include <QtTest/QtTest>
+#include <QTest>
+#include <private/qabstracteventdispatcher_p.h> // for qGlobalPostedEventsCount()
#include <private/qcoreapplication_p.h>
+#include <private/qcoreevent_p.h>
#include <private/qeventloop_p.h>
#include <private/qthread_p.h>
+#ifdef Q_OS_WIN
+#include <QtCore/qt_windows.h>
+#endif
+
typedef QCoreApplication TestApplication;
class EventSpy : public QObject
@@ -44,9 +25,12 @@ class EventSpy : public QObject
public:
QList<int> recordedEvents;
- bool eventFilter(QObject *, QEvent *event)
+ std::function<void(QObject *, QEvent *)> eventCallback;
+ bool eventFilter(QObject *target, QEvent *event) override
{
recordedEvents.append(event->type());
+ if (eventCallback)
+ eventCallback(target, event);
return false;
}
};
@@ -119,7 +103,7 @@ void tst_QCoreApplication::getSetCheck()
void tst_QCoreApplication::qAppName()
{
-#ifdef QT_GUI_LIB
+#ifdef QT_QGUIAPPLICATIONTEST
const char* appName = "tst_qguiapplication";
#else
const char* appName = "tst_qcoreapplication";
@@ -195,7 +179,7 @@ void tst_QCoreApplication::argc()
char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
TestApplication app(argc, argv);
QCOMPARE(argc, 1);
- QCOMPARE(app.arguments().count(), 1);
+ QCOMPARE(app.arguments().size(), 1);
}
{
@@ -206,7 +190,7 @@ void tst_QCoreApplication::argc()
const_cast<char*>("arg3") };
TestApplication app(argc, argv);
QCOMPARE(argc, 4);
- QCOMPARE(app.arguments().count(), 4);
+ QCOMPARE(app.arguments().size(), 4);
}
{
@@ -214,7 +198,7 @@ void tst_QCoreApplication::argc()
char **argv = 0;
TestApplication app(argc, argv);
QCOMPARE(argc, 0);
- QCOMPARE(app.arguments().count(), 0);
+ QCOMPARE(app.arguments().size(), 0);
}
{
@@ -223,7 +207,7 @@ void tst_QCoreApplication::argc()
const_cast<char*>("-qmljsdebugger=port:3768,block") };
TestApplication app(argc, argv);
QCOMPARE(argc, 1);
- QCOMPARE(app.arguments().count(), 1);
+ QCOMPARE(app.arguments().size(), 1);
}
}
@@ -234,7 +218,7 @@ class EventGenerator : public QObject
public:
QObject *other;
- bool event(QEvent *e)
+ bool event(QEvent *e) override
{
if (e->type() == QEvent::MaxUser) {
QCoreApplication::sendPostedEvents(other, 0);
@@ -424,7 +408,7 @@ signals:
void progress(int);
protected:
- void run()
+ void run() override
{
emit progress(1);
emit progress(2);
@@ -492,7 +476,7 @@ public slots:
}
public:
- bool event(QEvent *event)
+ bool event(QEvent *event) override
{
switch (event->type()) {
case QEvent::User:
@@ -534,18 +518,15 @@ void tst_QCoreApplication::applicationPid()
QVERIFY(QCoreApplication::applicationPid() > 0);
}
-QT_BEGIN_NAMESPACE
-Q_CORE_EXPORT uint qGlobalPostedEventsCount();
-QT_END_NAMESPACE
-
+#ifdef QT_BUILD_INTERNAL
class GlobalPostedEventsCountObject : public QObject
{
Q_OBJECT
public:
- QList<int> globalPostedEventsCount;
+ QList<qsizetype> globalPostedEventsCount;
- bool event(QEvent *event)
+ bool event(QEvent *event) override
{
if (event->type() == QEvent::User)
globalPostedEventsCount.append(qGlobalPostedEventsCount());
@@ -560,7 +541,7 @@ void tst_QCoreApplication::globalPostedEventsCount()
TestApplication app(argc, argv);
QCoreApplication::sendPostedEvents();
- QCOMPARE(qGlobalPostedEventsCount(), 0u);
+ QCOMPARE(qGlobalPostedEventsCount(), qsizetype(0));
GlobalPostedEventsCountObject x;
QCoreApplication::postEvent(&x, new QEvent(QEvent::User));
@@ -568,19 +549,15 @@ void tst_QCoreApplication::globalPostedEventsCount()
QCoreApplication::postEvent(&x, new QEvent(QEvent::User));
QCoreApplication::postEvent(&x, new QEvent(QEvent::User));
QCoreApplication::postEvent(&x, new QEvent(QEvent::User));
- QCOMPARE(qGlobalPostedEventsCount(), 5u);
+ QCOMPARE(qGlobalPostedEventsCount(), qsizetype(5));
QCoreApplication::sendPostedEvents();
- QCOMPARE(qGlobalPostedEventsCount(), 0u);
-
- QList<int> expected = QList<int>()
- << 4
- << 3
- << 2
- << 1
- << 0;
+ QCOMPARE(qGlobalPostedEventsCount(), qsizetype(0));
+
+ const QList<qsizetype> expected = {4, 3, 2, 1, 0};
QCOMPARE(x.globalPostedEventsCount, expected);
}
+#endif // QT_BUILD_INTERNAL
class ProcessEventsAlwaysSendsPostedEventsObject : public QObject
{
@@ -591,7 +568,7 @@ public:
: counter(0)
{ }
- bool event(QEvent *event)
+ bool event(QEvent *event) override
{
if (event->type() == QEvent::User)
++counter;
@@ -617,6 +594,108 @@ void tst_QCoreApplication::processEventsAlwaysSendsPostedEvents()
} while (t.elapsed() < 1000);
}
+#ifdef Q_OS_WIN
+void tst_QCoreApplication::sendPostedEventsInNativeLoop()
+{
+ int argc = 1;
+ char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
+ TestApplication app(argc, argv);
+
+ bool signalReceived = false;
+
+ // Post a message to the queue
+ QMetaObject::invokeMethod(this, [&signalReceived]() {
+ signalReceived = true;
+ }, Qt::QueuedConnection);
+
+ QElapsedTimer elapsedTimer;
+ elapsedTimer.start();
+
+ // Exec own message loop
+ MSG msg;
+ forever {
+ if (elapsedTimer.hasExpired(3000) || signalReceived)
+ break;
+
+ if (!::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ QThread::msleep(100);
+ continue;
+ }
+
+ ::TranslateMessage(&msg);
+ ::DispatchMessage(&msg);
+ }
+
+ QVERIFY(signalReceived);
+}
+#endif // Q_OS_WIN
+
+class QuitBlocker : public QObject
+{
+ Q_OBJECT
+
+public:
+ bool eventFilter(QObject *, QEvent *event) override
+ {
+ if (event->type() == QEvent::Quit) {
+ event->ignore();
+ return true;
+ }
+
+ return false;
+ }
+};
+
+void tst_QCoreApplication::quit()
+{
+ TestApplication::quit(); // Should not do anything
+
+ {
+ int argc = 1;
+ char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
+ TestApplication app(argc, argv);
+
+ EventSpy spy;
+ app.installEventFilter(&spy);
+
+ {
+ QTimer::singleShot(0, &app, SLOT(quit()));
+ app.exec();
+ QVERIFY(spy.recordedEvents.contains(QEvent::Quit));
+ }
+
+ spy.recordedEvents.clear();
+
+ {
+ QTimer::singleShot(0, qApp, SLOT(quit()));
+ app.exec();
+ QVERIFY(spy.recordedEvents.contains(QEvent::Quit));
+ }
+
+ spy.recordedEvents.clear();
+
+ {
+ QTimer::singleShot(0, [&]{ TestApplication::quit(); });
+ app.exec();
+ QVERIFY(spy.recordedEvents.contains(QEvent::Quit));
+ }
+
+ spy.recordedEvents.clear();
+
+ {
+ QuitBlocker quitBlocker;
+ app.installEventFilter(&quitBlocker);
+
+ QTimer::singleShot(0, [&]{ TestApplication::quit(); });
+ QTimer::singleShot(200, [&]{ TestApplication::exit(); });
+ app.exec();
+ QVERIFY(!spy.recordedEvents.contains(QEvent::Quit));
+ }
+ }
+
+ TestApplication::quit(); // Should not do anything
+}
+
void tst_QCoreApplication::reexec()
{
int argc = 1;
@@ -662,25 +741,21 @@ void tst_QCoreApplication::eventLoopExecAfterExit()
class DummyEventDispatcher : public QAbstractEventDispatcher {
public:
DummyEventDispatcher() : QAbstractEventDispatcher(), visited(false) {}
- bool processEvents(QEventLoop::ProcessEventsFlags) {
+ bool processEvents(QEventLoop::ProcessEventsFlags) override {
visited = true;
emit awake();
QCoreApplication::sendPostedEvents();
return false;
}
- bool hasPendingEvents() {
- return qGlobalPostedEventsCount();
- }
- void registerSocketNotifier(QSocketNotifier *) {}
- void unregisterSocketNotifier(QSocketNotifier *) {}
- void registerTimer(int , int , Qt::TimerType, QObject *) {}
- bool unregisterTimer(int ) { return false; }
- bool unregisterTimers(QObject *) { return false; }
- QList<TimerInfo> registeredTimers(QObject *) const { return QList<TimerInfo>(); }
- int remainingTime(int) { return 0; }
- void wakeUp() {}
- void interrupt() {}
- void flush() {}
+ void registerSocketNotifier(QSocketNotifier *) override {}
+ void unregisterSocketNotifier(QSocketNotifier *) override {}
+ void registerTimer(int , qint64 , Qt::TimerType, QObject *) override {}
+ bool unregisterTimer(int ) override { return false; }
+ bool unregisterTimers(QObject *) override { return false; }
+ QList<TimerInfo> registeredTimers(QObject *) const override { return QList<TimerInfo>(); }
+ int remainingTime(int) override { return 0; }
+ void wakeUp() override {}
+ void interrupt() override {}
#ifdef Q_OS_WIN
bool registerEventNotifier(QWinEventNotifier *) { return false; }
@@ -722,13 +797,13 @@ class JobObject : public QObject
Q_OBJECT
public:
- explicit JobObject(QEventLoop *loop, QObject *parent = 0)
+ explicit JobObject(QEventLoop *loop, QObject *parent = nullptr)
: QObject(parent), locker(loop)
{
QTimer::singleShot(1000, this, SLOT(timeout()));
}
- explicit JobObject(QObject *parent = 0)
+ explicit JobObject(QObject *parent = nullptr)
: QObject(parent)
{
QTimer::singleShot(1000, this, SLOT(timeout()));
@@ -758,7 +833,7 @@ class QuitTester : public QObject
{
Q_OBJECT
public:
- QuitTester(QObject *parent = 0)
+ QuitTester(QObject *parent = nullptr)
: QObject(parent)
{
QTimer::singleShot(0, this, SLOT(doTest()));
@@ -950,7 +1025,7 @@ void tst_QCoreApplication::addRemoveLibPaths()
TestApplication app(argc, argv);
// If libraryPaths only contains currentDir, neither will be in libraryPaths now.
- if (paths.length() != 1 && currentDir != paths[0]) {
+ if (paths.size() != 1 && currentDir != paths[0]) {
// Check that modifications stay alive across the creation of an application.
QVERIFY(QCoreApplication::libraryPaths().contains(currentDir));
QVERIFY(!QCoreApplication::libraryPaths().contains(paths[0]));
@@ -963,20 +1038,128 @@ void tst_QCoreApplication::addRemoveLibPaths()
}
#endif
+static bool theMainThreadIsSet()
+{
+ // QCoreApplicationPrivate::mainThread() has a Q_ASSERT we'd trigger
+ return QCoreApplicationPrivate::theMainThreadId.loadRelaxed() != nullptr;
+}
+
+static bool theMainThreadWasUnset = !theMainThreadIsSet(); // global static
+void tst_QCoreApplication::theMainThread()
+{
+ QVERIFY2(theMainThreadWasUnset, "Something set the theMainThread before main()");
+ QVERIFY(theMainThreadIsSet()); // we have at LEAST one QObject alive: tst_QCoreApplication
+
+ int argc = 1;
+ char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
+ TestApplication app(argc, argv);
+ QVERIFY(QCoreApplicationPrivate::theMainThreadId.loadRelaxed());
+ QVERIFY(QThread::isMainThread());
+ QCOMPARE(app.thread(), thread());
+ QCOMPARE(app.thread(), QThread::currentThread());
+}
+
static void createQObjectOnDestruction()
{
- // Make sure that we can create a QObject after the last QObject has been
- // destroyed (especially after QCoreApplication has).
- //
+ // Make sure that we can create a QObject (and thus have an associated
+ // QThread) after the last QObject has been destroyed (especially after
+ // QCoreApplication has).
+
+#if !defined(QT_QGUIAPPLICATIONTEST) && !defined(Q_OS_WIN)
+ // QCoreApplicationData's global static destructor has run and cleaned up
+ // the QAdoptedThread.
+ if (theMainThreadIsSet())
+ qFatal("theMainThreadIsSet() returned true; some QObject must have leaked");
+#endif
+
// Before the fixes, this would cause a dangling pointer dereference. If
// the problem comes back, it's possible that the following causes no
// effect.
QObject obj;
obj.thread()->setProperty("testing", 1);
+ if (!theMainThreadIsSet())
+ qFatal("theMainThreadIsSet() returned false");
+
+ // because we created a QObject after QCoreApplicationData was destroyed,
+ // the QAdoptedThread won't get cleaned up
}
Q_DESTRUCTOR_FUNCTION(createQObjectOnDestruction)
-#ifndef QT_GUI_LIB
+void tst_QCoreApplication::testDeleteLaterFromBeforeOutermostEventLoop()
+{
+ int argc = 0;
+ QCoreApplication app(argc, nullptr);
+
+ EventSpy *spy = new EventSpy();
+ QPointer<QObject> spyPointer = spy;
+
+ app.installEventFilter(spy);
+ spy->eventCallback = [spy](QObject *, QEvent *event) {
+ if (event->type() == QEvent::User + 1)
+ spy->deleteLater();
+ };
+
+ QCoreApplication::postEvent(&app, new QEvent(QEvent::Type(QEvent::User + 1)));
+ QCoreApplication::processEvents();
+
+ QEventLoop loop;
+ QTimer::singleShot(0, &loop, &QEventLoop::quit);
+ loop.exec();
+ QVERIFY(!spyPointer);
+}
+
+void tst_QCoreApplication::setIndividualAttributes_data()
+{
+ QTest::addColumn<Qt::ApplicationAttribute>("attribute");
+
+ const QMetaEnum &metaEnum = Qt::staticMetaObject.enumerator(Qt::staticMetaObject.indexOfEnumerator("ApplicationAttribute"));
+ // - 1 to avoid AA_AttributeCount.
+ for (int i = 0; i < metaEnum.keyCount(); ++i) {
+ const auto attribute = static_cast<Qt::ApplicationAttribute>(metaEnum.value(i));
+ if (attribute == Qt::AA_AttributeCount)
+ continue;
+
+ QTest::addRow("%s", metaEnum.key(i)) << attribute;
+ }
+}
+
+void tst_QCoreApplication::setIndividualAttributes()
+{
+ QFETCH(Qt::ApplicationAttribute, attribute);
+
+ const auto originalValue = QCoreApplication::testAttribute(attribute);
+ auto cleanup = qScopeGuard([=]() {
+ QCoreApplication::setAttribute(attribute, originalValue);
+ });
+
+ QCoreApplication::setAttribute(attribute, true);
+ QVERIFY(QCoreApplication::testAttribute(attribute));
+
+ QCoreApplication::setAttribute(attribute, false);
+ QVERIFY(!QCoreApplication::testAttribute(attribute));
+}
+
+void tst_QCoreApplication::setMultipleAttributes()
+{
+ const auto originalDontUseNativeMenuWindowsValue = QCoreApplication::testAttribute(Qt::AA_DontUseNativeMenuWindows);
+ const auto originalDisableSessionManagerValue = QCoreApplication::testAttribute(Qt::AA_DisableSessionManager);
+ auto cleanup = qScopeGuard([=]() {
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows, originalDontUseNativeMenuWindowsValue);
+ QCoreApplication::setAttribute(Qt::AA_DisableSessionManager, originalDisableSessionManagerValue);
+ });
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows, true);
+ QCoreApplication::setAttribute(Qt::AA_DisableSessionManager, true);
+ QVERIFY(QCoreApplication::testAttribute(Qt::AA_DontUseNativeMenuWindows));
+ QVERIFY(QCoreApplication::testAttribute(Qt::AA_DisableSessionManager));
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows, false);
+ QCoreApplication::setAttribute(Qt::AA_DisableSessionManager, false);
+ QVERIFY(!QCoreApplication::testAttribute(Qt::AA_DontUseNativeMenuWindows));
+ QVERIFY(!QCoreApplication::testAttribute(Qt::AA_DisableSessionManager));
+}
+
+#ifndef QT_QGUIAPPLICATIONTEST
QTEST_APPLESS_MAIN(tst_QCoreApplication)
#endif