summaryrefslogtreecommitdiffstats
path: root/tests/auto
diff options
context:
space:
mode:
authorStephen Kelly <stephen.kelly@kdab.com>2011-10-26 13:29:51 +0200
committerQt by Nokia <qt-info@nokia.com>2012-01-31 23:22:15 +0100
commita512e210ac5b032c5fc2edf1ddf72e5a414485fd (patch)
tree0e9615f317fe5c24bd002155b205a01d5716a1d3 /tests/auto
parent36a590c90ddab6fa438b7b54b05d89e8f9698a52 (diff)
Add the event loop quitlock feature to QtCore.
A feature of a ref-counted quit (managed by a quit-lock class) is added to both QEventLoop and QCoreApplication. This allows, for example, an event loop to quit() when there is no more work for it to do. quitOnLastWindowClosed is implemented in terms of the refcount in QCoreApplication so that jobs can be completed before the application quits. Change-Id: I14c8f4e7ee12bbf81a6e5849290d4c8ff37fa110 Reviewed-by: David Faure <faure@kde.org> Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
Diffstat (limited to 'tests/auto')
-rw-r--r--tests/auto/corelib/kernel/qcoreapplication/qcoreapplication.pro2
-rw-r--r--tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp114
-rw-r--r--tests/auto/corelib/kernel/qeventloop/qeventloop.pro2
-rw-r--r--tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp82
-rw-r--r--tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp516
5 files changed, 712 insertions, 4 deletions
diff --git a/tests/auto/corelib/kernel/qcoreapplication/qcoreapplication.pro b/tests/auto/corelib/kernel/qcoreapplication/qcoreapplication.pro
index f9a38c2f14..14df20c986 100644
--- a/tests/auto/corelib/kernel/qcoreapplication/qcoreapplication.pro
+++ b/tests/auto/corelib/kernel/qcoreapplication/qcoreapplication.pro
@@ -1,4 +1,4 @@
CONFIG += testcase parallel_test
TARGET = tst_qcoreapplication
-QT = core testlib
+QT = core testlib core-private
SOURCES = tst_qcoreapplication.cpp
diff --git a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp
index fc3d8e0fbb..97c9757107 100644
--- a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp
+++ b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp
@@ -39,10 +39,13 @@
**
****************************************************************************/
-
#include <QtCore/QtCore>
#include <QtTest/QtTest>
+#include <private/qcoreapplication_p.h>
+#include <private/qeventloop_p.h>
+#include <private/qthread_p.h>
+
class tst_QCoreApplication: public QObject
{
Q_OBJECT
@@ -63,6 +66,7 @@ private slots:
void execAfterExit();
void eventLoopExecAfterExit();
void customEventDispatcher();
+ void testQuitLock();
};
class EventSpy : public QObject
@@ -640,5 +644,113 @@ void tst_QCoreApplication::customEventDispatcher()
QVERIFY(weak_ed.isNull());
}
+class JobObject : public QObject
+{
+ Q_OBJECT
+public:
+
+ explicit JobObject(QEventLoop *loop, QObject *parent = 0)
+ : QObject(parent), locker(loop)
+ {
+ QTimer::singleShot(1000, this, SLOT(timeout()));
+ }
+
+ explicit JobObject(QObject *parent = 0)
+ : QObject(parent)
+ {
+ QTimer::singleShot(1000, this, SLOT(timeout()));
+ }
+
+public slots:
+ void startSecondaryJob()
+ {
+ new JobObject();
+ }
+
+private slots:
+ void timeout()
+ {
+ emit done();
+ deleteLater();
+ }
+
+signals:
+ void done();
+
+private:
+ QEventLoopLocker locker;
+};
+
+class QuitTester : public QObject
+{
+ Q_OBJECT
+public:
+ QuitTester(QObject *parent = 0)
+ : QObject(parent)
+ {
+ QTimer::singleShot(0, this, SLOT(doTest()));
+ }
+
+private slots:
+ void doTest()
+ {
+ QCoreApplicationPrivate *privateClass = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp));
+
+ {
+ QCOMPARE(privateClass->quitLockRef.load(), 0);
+ // Test with a lock active so that the refcount doesn't drop to zero during these tests, causing a quit.
+ // (until we exit the scope)
+ QEventLoopLocker locker;
+
+ QCOMPARE(privateClass->quitLockRef.load(), 1);
+
+ JobObject *job1 = new JobObject(this);
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ delete job1;
+
+ QCOMPARE(privateClass->quitLockRef.load(), 1);
+
+ job1 = new JobObject(this);
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ JobObject *job2 = new JobObject(this);
+
+ QCOMPARE(privateClass->quitLockRef.load(), 3);
+
+ delete job1;
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ JobObject *job3 = new JobObject(job2);
+
+ QCOMPARE(privateClass->quitLockRef.load(), 3);
+
+ JobObject *job4 = new JobObject(job2);
+
+ QCOMPARE(privateClass->quitLockRef.load(), 4);
+
+ delete job2;
+
+ QCOMPARE(privateClass->quitLockRef.load(), 1);
+
+ }
+ QCOMPARE(privateClass->quitLockRef.load(), 0);
+ }
+};
+
+void tst_QCoreApplication::testQuitLock()
+{
+ int argc = 1;
+ char *argv[] = { "tst_qcoreapplication" };
+ QCoreApplication app(argc, argv);
+
+ QuitTester tester;
+ app.exec();
+}
+
+
QTEST_APPLESS_MAIN(tst_QCoreApplication)
#include "tst_qcoreapplication.moc"
diff --git a/tests/auto/corelib/kernel/qeventloop/qeventloop.pro b/tests/auto/corelib/kernel/qeventloop/qeventloop.pro
index d21a7d64f6..adfc810788 100644
--- a/tests/auto/corelib/kernel/qeventloop/qeventloop.pro
+++ b/tests/auto/corelib/kernel/qeventloop/qeventloop.pro
@@ -1,6 +1,6 @@
CONFIG += testcase
TARGET = tst_qeventloop
-QT = core network testlib
+QT = core network testlib core-private
SOURCES = tst_qeventloop.cpp
win32:!wince*:LIBS += -luser32
diff --git a/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp b/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp
index 897cba1f17..e2144134d9 100644
--- a/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp
+++ b/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp
@@ -45,6 +45,7 @@
#include <qcoreapplication.h>
#include <qcoreevent.h>
#include <qeventloop.h>
+#include <private/qeventloop_p.h>
#include <qmutex.h>
#include <qthread.h>
#include <qtimer.h>
@@ -194,6 +195,8 @@ private slots:
// keep this test last:
void nestedLoops();
+ void testQuitLock();
+
protected:
void customEvent(QEvent *e);
};
@@ -640,6 +643,85 @@ void tst_QEventLoop::deliverInDefinedOrder()
}
+class JobObject : public QObject
+{
+ Q_OBJECT
+public:
+
+ explicit JobObject(QEventLoop *loop, QObject *parent = 0)
+ : QObject(parent), loop(loop), locker(loop)
+ {
+ }
+
+ explicit JobObject(QObject *parent = 0)
+ : QObject(parent)
+ {
+ }
+
+public slots:
+ void start(int timeout = 200)
+ {
+ QTimer::singleShot(timeout, this, SLOT(timeout()));
+ }
+
+private slots:
+ void timeout()
+ {
+ emit done();
+ deleteLater();
+ }
+
+signals:
+ void done();
+
+private:
+ QEventLoop *loop;
+ QEventLoopLocker locker;
+};
+
+void tst_QEventLoop::testQuitLock()
+{
+ QEventLoop eventLoop;
+
+ QTimer timer;
+ timer.setInterval(100);
+ QSignalSpy timerSpy(&timer, SIGNAL(timeout()));
+ timer.start();
+
+ QEventLoopPrivate* privateClass = static_cast<QEventLoopPrivate*>(QObjectPrivate::get(&eventLoop));
+
+ QCOMPARE(privateClass->quitLockRef.load(), 0);
+
+ JobObject *job1 = new JobObject(&eventLoop, this);
+ job1->start(500);
+
+ QCOMPARE(privateClass->quitLockRef.load(), 1);
+
+ eventLoop.exec();
+
+ QCOMPARE(privateClass->quitLockRef.load(), 0);
+
+ // The job takes long enough that the timer times out several times.
+ QVERIFY(timerSpy.count() > 3);
+ timerSpy.clear();
+
+ job1 = new JobObject(&eventLoop, this);
+ job1->start(200);
+
+ JobObject *previousJob = job1;
+ for (int i = 0; i < 9; ++i) {
+ JobObject *subJob = new JobObject(&eventLoop, this);
+ connect(previousJob, SIGNAL(done()), subJob, SLOT(start()));
+ previousJob = subJob;
+ }
+
+ eventLoop.exec();
+
+ qDebug() << timerSpy.count();
+ // The timer times out more if it has more subjobs to do.
+ // We run 10 jobs in sequence here of about 200ms each.
+ QVERIFY(timerSpy.count() > 17);
+}
QTEST_MAIN(tst_QEventLoop)
#include "tst_qeventloop.moc"
diff --git a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
index ac8f2a34ce..4b8034c7c7 100644
--- a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
+++ b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
@@ -49,6 +49,7 @@
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QProcess>
+#include <QtCore/private/qeventloop_p.h>
#include <QtGui/QFontDatabase>
#include <QtGui/QClipboard>
@@ -138,6 +139,16 @@ private slots:
void qtbug_12673();
+ void testQuitLockRef();
+ void testQuitLock1();
+ void testQuitLock2();
+ void testQuitLock3();
+ void testQuitLock4();
+ void testQuitLock5();
+ void testQuitLock6();
+ void testQuitLock7();
+ void testQuitLock8();
+
void globalStaticObjectDestruction(); // run this last
};
@@ -189,7 +200,6 @@ public:
dialog.show();
dialog.close();
- hide();
event->ignore();
}
};
@@ -516,6 +526,7 @@ void tst_QApplication::lastWindowClosed()
QPointer<CloseWidget>widget = new CloseWidget;
QVERIFY(widget->testAttribute(Qt::WA_QuitOnClose));
+ widget->show();
QObject::connect(&app, SIGNAL(lastWindowClosed()), widget, SLOT(deleteLater()));
app.exec();
QVERIFY(!widget);
@@ -2048,6 +2059,509 @@ void tst_QApplication::qtbug_12673()
QCOMPARE(testProcess.exitStatus(), QProcess::NormalExit);
}
+class JobObject : public QObject
+{
+ Q_OBJECT
+public:
+ JobObject(int milliseconds, QObject *parent = 0)
+ : QObject(parent)
+ {
+ QTimer::singleShot(milliseconds, this, SLOT(timeout()));
+ }
+
+ JobObject(QObject *parent = 0)
+ : QObject(parent)
+ {
+ QTimer::singleShot(1000, this, SLOT(timeout()));
+ }
+
+private slots:
+ void timeout()
+ {
+ emit done();
+ deleteLater();
+ }
+
+signals:
+ void done();
+
+private:
+ QEventLoopLocker locker;
+};
+
+class QuitLockRefTester : public QObject
+{
+ Q_OBJECT
+public:
+ QuitLockRefTester(QObject *parent = 0)
+ : QObject(parent)
+ {
+ QTimer::singleShot(0, this, SLOT(doTest()));
+ }
+
+private slots:
+ void doTest()
+ {
+ QApplicationPrivate *privateClass = static_cast<QApplicationPrivate*>(QObjectPrivate::get(qApp));
+
+ {
+ QDialog *win1 = new QDialog;
+
+ // Test with a lock active so that the refcount doesn't drop to zero during these tests, causing a quit.
+ // (until we exit the scope)
+ QEventLoopLocker locker;
+
+ QCOMPARE(privateClass->quitLockRef.load(), 1);
+
+ win1->show();
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ QDialog *win2 = new QDialog;
+
+ win2->show();
+
+ QCOMPARE(privateClass->quitLockRef.load(), 3);
+
+ delete win1;
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ delete win2;
+
+ QCOMPARE(privateClass->quitLockRef.load(), 1);
+
+ win1 = new QDialog;
+
+ win1->show();
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ JobObject *job1 = new JobObject(this);
+
+ QCOMPARE(privateClass->quitLockRef.load(), 3);
+
+ delete win1;
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ delete job1;
+
+ QCOMPARE(privateClass->quitLockRef.load(), 1);
+
+ QWidget *w1 = new QWidget;
+
+ w1->show();
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ QWidget *w2 = new QMainWindow;
+
+ w2->show();
+
+ QCOMPARE(privateClass->quitLockRef.load(), 3);
+
+ QWidget *w3 = new QWidget(0, Qt::Dialog);
+
+ w3->show();
+
+ QCOMPARE(privateClass->quitLockRef.load(), 4);
+
+ delete w3;
+
+ QCOMPARE(privateClass->quitLockRef.load(), 3);
+
+ delete w2;
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ QWidget *subWidget1 = new QWidget(w1, Qt::Window);
+
+ // Even though We create a new widget and show it,
+ // the ref count does not go up because it is a child of
+ // w1, which is the top-level, and what we are actually
+ // refcounting.
+ subWidget1->show();
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ // When we use setParent(0) and re-show, the
+ // ref count does increase:
+ QCOMPARE(subWidget1->isVisible(), true);
+ subWidget1->setParent(0);
+ QCOMPARE(subWidget1->isVisible(), false);
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ subWidget1->show();
+ QCOMPARE(subWidget1->isVisible(), true);
+ QCOMPARE(privateClass->quitLockRef.load(), 3);
+
+ subWidget1->setParent(w1);
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ QWidget *subWidget2 = new QWidget(w1);
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ subWidget2->show();
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ delete subWidget2;
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ QWidget *subWidget3 = new QWidget(w1);
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ subWidget3->show();
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ subWidget3->hide();
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ delete subWidget3;
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ QWidget *subWidget4 = new QWidget(subWidget1);
+ QWidget *subWidget5 = new QWidget(subWidget1);
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ QWidget *subWidget6 = new QWidget(subWidget4, Qt::Window);
+
+ subWidget6->show();
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ delete w1;
+
+ QCOMPARE(privateClass->quitLockRef.load(), 1);
+
+ w1 = new QWidget;
+ w2 = new QWidget;
+ w3 = new QWidget;
+
+ QHBoxLayout *layout = new QHBoxLayout(w1);
+
+ layout->addWidget(w2);
+ layout->addWidget(w3);
+
+ QCOMPARE(privateClass->quitLockRef.load(), 1);
+
+ w1->show();
+
+ QCOMPARE(privateClass->quitLockRef.load(), 2);
+
+ w1->hide();
+ QCOMPARE(privateClass->quitLockRef.load(), 1);
+
+ delete w1;
+
+ }
+ QCOMPARE(privateClass->quitLockRef.load(), 0);
+ }
+};
+
+void tst_QApplication::testQuitLockRef()
+{
+ int argc = 1;
+ char *argv[] = { "tst_qapplication" };
+ QApplication app(argc, argv);
+
+ QuitLockRefTester tester;
+
+ app.exec();
+}
+
+void tst_QApplication::testQuitLock1()
+{
+ int argc = 1;
+ char *argv[] = { "tst_qcoreapplication" };
+ QApplication app(argc, argv);
+
+ QWidget *w = new QWidget;
+
+ w->show();
+
+ QMetaObject::invokeMethod(w, "close", Qt::QueuedConnection);
+
+ app.exec();
+
+ // No hang = pass.
+}
+
+void tst_QApplication::testQuitLock2()
+{
+ int argc = 1;
+ char *argv[] = { "tst_qcoreapplication" };
+ QApplication app(argc, argv);
+
+ QWidget *w1 = new QWidget;
+
+ w1->show();
+
+ QWidget *w2 = new QWidget;
+
+ w2->show();
+
+ QMetaObject::invokeMethod(w1, "deleteLater", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(w2, "hide", Qt::QueuedConnection);
+
+ app.exec();
+
+ // No hang = pass.
+}
+
+class Result : public QObject
+{
+ Q_OBJECT
+public:
+ Result(QObject *parent = 0)
+ : QObject(parent), m_passes(false)
+ {
+
+ }
+
+ bool result() const
+ {
+ return m_passes;
+ }
+
+public slots:
+
+ void setPasses()
+ {
+ setResult(true);
+ }
+
+ void setFails()
+ {
+ setResult(false);
+ }
+
+ void setResult(bool result)
+ {
+ m_passes = result;
+ }
+
+private:
+ bool m_passes;
+};
+
+void tst_QApplication::testQuitLock3()
+{
+ int argc = 1;
+ char *argv[] = { "tst_qcoreapplication" };
+ QApplication app(argc, argv);
+
+ Result *result = new Result(&app);
+
+ JobObject *job = new JobObject(&app);
+
+ QObject::connect(job, SIGNAL(done()), result, SLOT(setPasses()));
+
+ app.exec();
+
+ QVERIFY(result->result());
+}
+
+void tst_QApplication::testQuitLock4()
+{
+ int argc = 1;
+ char *argv[] = { "tst_qcoreapplication" };
+ QApplication app(argc, argv);
+
+ QWidget *w = new QWidget;
+
+ w->show();
+
+ Result *result = new Result(&app);
+ JobObject *job = new JobObject(1000, &app);
+
+ QTimer::singleShot(500, w, SLOT(deleteLater()));
+
+ QObject::connect(w, SIGNAL(destroyed()), result, SLOT(setFails()));
+ QObject::connect(job, SIGNAL(done()), result, SLOT(setPasses()));
+
+ app.exec();
+
+ QVERIFY(result->result());
+}
+
+class JobBeforeWindowRunner : public QObject
+{
+ Q_OBJECT
+public:
+ JobBeforeWindowRunner(QObject *parent = 0)
+ : QObject(parent), m_result(new Result(this))
+ {
+
+ }
+
+ void start()
+ {
+ JobObject *job = new JobObject(this);
+ connect(job, SIGNAL(done()), m_result, SLOT(setFails()));
+ connect(job, SIGNAL(destroyed()), SLOT(showWindowDelayed()), Qt::QueuedConnection);
+ }
+
+ bool result() const { return m_result->result(); }
+
+private slots:
+ void showWindowDelayed()
+ {
+ qApp->setQuitLockEnabled(true);
+ QTimer::singleShot(500, this, SLOT(showWindow()));
+ }
+
+ void showWindow()
+ {
+ QWidget *w = new QWidget;
+ w->show();
+ w->deleteLater();
+ connect(w, SIGNAL(destroyed()), m_result, SLOT(setPasses()));
+ }
+
+private:
+ Result * const m_result;
+};
+
+void tst_QApplication::testQuitLock5()
+{
+ int argc = 1;
+ char *argv[] = { "tst_qcoreapplication" };
+ QApplication app(argc, argv);
+ app.setQuitLockEnabled(false);
+ // Run a job before showing a window, and only enable the refcounting
+ // after doing so.
+ // Although the job brings the refcount to zero, the app does not exit
+ // until setQuitLockEnabled is called and the feature re-enabled.
+
+ JobBeforeWindowRunner *eventRunner = new JobBeforeWindowRunner(&app);
+
+ eventRunner->start();
+
+ app.exec();
+
+ QVERIFY(eventRunner->result());
+}
+
+class JobDuringWindowRunner : public QObject
+{
+ Q_OBJECT
+public:
+ JobDuringWindowRunner(QObject *parent = 0)
+ : QObject(parent), m_result(new Result(this))
+ {
+
+ }
+
+ void start()
+ {
+ JobObject *job = new JobObject(this);
+
+ QWidget *w = new QWidget;
+ w->show();
+ w->deleteLater();
+
+ QObject::connect(w, SIGNAL(destroyed()), m_result, SLOT(setFails()));
+ QObject::connect(job, SIGNAL(done()), m_result, SLOT(setPasses()));
+ }
+
+ bool result() const { return m_result->result(); }
+
+private:
+ Result * const m_result;
+};
+
+void tst_QApplication::testQuitLock6()
+{
+ int argc = 1;
+ char *argv[] = { "tst_qcoreapplication" };
+ QApplication app(argc, argv);
+
+ // A job runs, and while it is running, a window is shown and closed,
+ // then the job ends, which causes the quit.
+
+ JobDuringWindowRunner *eventRunner = new JobDuringWindowRunner(&app);
+
+ eventRunner->start();
+
+ app.exec();
+
+ QVERIFY(eventRunner->result());
+}
+class JobWindowJobWindowRunner : public QObject
+{
+ Q_OBJECT
+public:
+ JobWindowJobWindowRunner(QObject *parent = 0)
+ : QObject(parent), m_result(new Result(this))
+ {
+
+ }
+
+ void start()
+ {
+ JobObject *job = new JobObject(500, this);
+
+ QWidget *w = new QWidget;
+ w->show();
+ QTimer::singleShot(1000, w, SLOT(deleteLater()));
+
+ QObject::connect(w, SIGNAL(destroyed()), m_result, SLOT(setPasses()));
+ QObject::connect(job, SIGNAL(done()), m_result, SLOT(setFails()));
+ }
+
+ bool result() const { return m_result->result(); }
+private:
+ Result * const m_result;
+};
+
+void tst_QApplication::testQuitLock7()
+{
+ int argc = 1;
+ char *argv[] = { "tst_qcoreapplication" };
+ QApplication app(argc, argv);
+
+ // A job runs, and while it is running, a window is shown
+ // then the job ends, then the window is closed, which causes the quit.
+
+ JobWindowJobWindowRunner *eventRunner = new JobWindowJobWindowRunner(&app);
+
+ eventRunner->start();
+
+ app.exec();
+
+ QVERIFY(eventRunner->result());
+}
+
+void tst_QApplication::testQuitLock8()
+{
+ int argc = 1;
+ char *argv[] = { "tst_qcoreapplication" };
+ QApplication app(argc, argv);
+
+ QMainWindow *mw1 = new QMainWindow;
+ mw1->show();
+ QMainWindow *mw2 = new QMainWindow;
+ mw2->show();
+
+ QMetaObject::invokeMethod(mw1, "close", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(mw2, "close", Qt::QueuedConnection);
+
+ app.exec();
+
+ // No hang = pass
+}
+
+
/*
This test is meant to ensure that certain objects (public & commonly used)
can safely be used in a Q_GLOBAL_STATIC such that their destructors are