summaryrefslogtreecommitdiffstats
path: root/tests/auto/qeventloop/tst_qeventloop.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qeventloop/tst_qeventloop.cpp')
-rw-r--r--tests/auto/qeventloop/tst_qeventloop.cpp398
1 files changed, 233 insertions, 165 deletions
diff --git a/tests/auto/qeventloop/tst_qeventloop.cpp b/tests/auto/qeventloop/tst_qeventloop.cpp
index edaa041..298d9fe 100644
--- a/tests/auto/qeventloop/tst_qeventloop.cpp
+++ b/tests/auto/qeventloop/tst_qeventloop.cpp
@@ -54,6 +54,11 @@
#include <QTcpServer>
#include <QTcpSocket>
+#ifdef Q_OS_SYMBIAN
+#include <e32base.h>
+#include <unistd.h>
+#endif
+
//TESTED_CLASS=
//TESTED_FILES=
@@ -186,6 +191,10 @@ public slots:
void init();
void cleanup();
private slots:
+ // This test *must* run first. See the definition for why.
+ void onlySymbianActiveScheduler();
+ void symbianNestedActiveSchedulerLoop_data();
+ void symbianNestedActiveSchedulerLoop();
void processEvents();
void exec();
void exit();
@@ -213,6 +222,101 @@ void tst_QEventLoop::init()
void tst_QEventLoop::cleanup()
{ }
+#ifdef Q_OS_SYMBIAN
+class OnlySymbianActiveScheduler_helper : public QObject
+{
+ Q_OBJECT
+
+public:
+ OnlySymbianActiveScheduler_helper(int fd, QTimer *zeroTimer)
+ : fd(fd),
+ timerCount(0),
+ zeroTimer(zeroTimer),
+ zeroTimerCount(0),
+ notifierCount(0)
+ {
+ }
+ ~OnlySymbianActiveScheduler_helper() {}
+
+public slots:
+ void timerSlot()
+ {
+ // Let all the events occur twice so we know they reactivated after
+ // each occurrence.
+ if (++timerCount >= 2) {
+ // This will hopefully run last, so stop the active scheduler.
+ CActiveScheduler::Stop();
+ }
+ }
+ void zeroTimerSlot()
+ {
+ if (++zeroTimerCount >= 2) {
+ zeroTimer->stop();
+ }
+ }
+ void notifierSlot()
+ {
+ if (++notifierCount >= 2) {
+ char dummy;
+ ::read(fd, &dummy, 1);
+ }
+ }
+
+private:
+ int fd;
+ int timerCount;
+ QTimer *zeroTimer;
+ int zeroTimerCount;
+ int notifierCount;
+};
+#endif
+
+void tst_QEventLoop::onlySymbianActiveScheduler() {
+#ifndef Q_OS_SYMBIAN
+ QSKIP("This is a Symbian-only test.", SkipAll);
+#else
+ // In here we try to use timers and sockets exclusively using the Symbian
+ // active scheduler and no processEvents().
+ // This test should therefore be run first, so that we can verify that
+ // the first occurrence of processEvents does not do any initalization that
+ // we depend on.
+
+ // Open up a pipe so we can test socket notifiers.
+ int pipeEnds[2];
+ if (::pipe(pipeEnds) != 0) {
+ QFAIL("Could not open pipe");
+ }
+ QSocketNotifier notifier(pipeEnds[0], QSocketNotifier::Read);
+ QSignalSpy notifierSpy(&notifier, SIGNAL(activated(int)));
+ char dummy = 1;
+ ::write(pipeEnds[1], &dummy, 1);
+
+ QTimer zeroTimer;
+ QSignalSpy zeroTimerSpy(&zeroTimer, SIGNAL(timeout()));
+ zeroTimer.setInterval(0);
+ zeroTimer.start();
+
+ QTimer timer;
+ QSignalSpy timerSpy(&timer, SIGNAL(timeout()));
+ timer.setInterval(2000); // Generous timeout or this test will fail if there is high load
+ timer.start();
+
+ OnlySymbianActiveScheduler_helper helper(pipeEnds[0], &zeroTimer);
+ connect(&notifier, SIGNAL(activated(int)), &helper, SLOT(notifierSlot()));
+ connect(&zeroTimer, SIGNAL(timeout()), &helper, SLOT(zeroTimerSlot()));
+ connect(&timer, SIGNAL(timeout()), &helper, SLOT(timerSlot()));
+
+ CActiveScheduler::Start();
+
+ ::close(pipeEnds[1]);
+ ::close(pipeEnds[0]);
+
+ QCOMPARE(notifierSpy.count(), 2);
+ QCOMPARE(zeroTimerSpy.count(), 2);
+ QCOMPARE(timerSpy.count(), 2);
+#endif
+}
+
void tst_QEventLoop::processEvents()
{
QSignalSpy spy1(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()));
@@ -265,6 +369,14 @@ void tst_QEventLoop::processEvents()
killTimer(timerId);
}
+#if defined(Q_OS_SYMBIAN) && defined(Q_CC_NOKIAX86)
+// Symbian needs bit longer timeout for emulator, as emulator startup causes additional delay
+# define EXEC_TIMEOUT 1000
+#else
+# define EXEC_TIMEOUT 100
+#endif
+
+
void tst_QEventLoop::exec()
{
{
@@ -272,15 +384,15 @@ void tst_QEventLoop::exec()
EventLoopExiter exiter(&eventLoop);
int returnCode;
- QTimer::singleShot(100, &exiter, SLOT(exit()));
+ QTimer::singleShot(EXEC_TIMEOUT, &exiter, SLOT(exit()));
returnCode = eventLoop.exec();
QCOMPARE(returnCode, 0);
- QTimer::singleShot(100, &exiter, SLOT(exit1()));
+ QTimer::singleShot(EXEC_TIMEOUT, &exiter, SLOT(exit1()));
returnCode = eventLoop.exec();
QCOMPARE(returnCode, 1);
- QTimer::singleShot(100, &exiter, SLOT(exit2()));
+ QTimer::singleShot(EXEC_TIMEOUT, &exiter, SLOT(exit2()));
returnCode = eventLoop.exec();
QCOMPARE(returnCode, 2);
}
@@ -313,16 +425,19 @@ void tst_QEventLoop::exec()
QEventLoop eventLoop;
EventLoopExecutor executor(&eventLoop);
- QTimer::singleShot(100, &executor, SLOT(exec()));
+ QTimer::singleShot(EXEC_TIMEOUT, &executor, SLOT(exec()));
int returnCode = eventLoop.exec();
QCOMPARE(returnCode, 0);
QCOMPARE(executor.returnCode, -1);
}
-#if !defined(QT_NO_EXCEPTIONS) && !defined(Q_OS_WINCE_WM)
+#if !defined(QT_NO_EXCEPTIONS) && !defined(Q_OS_WINCE_WM) && !defined(Q_OS_SYMBIAN)
// Windows Mobile cannot handle cross library exceptions
// qobject.cpp will try to rethrow the exception after handling
// which causes gwes.exe to crash
+
+ // Symbian doesn't propagate exceptions from eventloop, but converts them to
+ // CActiveScheduler errors instead -> this test will hang.
{
// QEventLoop::exec() is exception safe
QEventLoop eventLoop;
@@ -330,14 +445,14 @@ void tst_QEventLoop::exec()
try {
ExceptionThrower exceptionThrower;
- QTimer::singleShot(100, &exceptionThrower, SLOT(throwException()));
+ QTimer::singleShot(EXEC_TIMEOUT, &exceptionThrower, SLOT(throwException()));
(void) eventLoop.exec();
} catch (...) {
++caughtExceptions;
}
try {
ExceptionThrower exceptionThrower;
- QTimer::singleShot(100, &exceptionThrower, SLOT(throwException()));
+ QTimer::singleShot(EXEC_TIMEOUT, &exceptionThrower, SLOT(throwException()));
(void) eventLoop.exec();
} catch (...) {
++caughtExceptions;
@@ -512,7 +627,7 @@ void tst_QEventLoop::processEventsExcludeTimers()
// normal process events will send timers
eventLoop.processEvents(QEventLoop::X11ExcludeTimers);
-#ifndef Q_OS_UNIX
+#if !defined(Q_OS_UNIX) || defined(Q_OS_SYMBIAN)
QEXPECT_FAIL("", "X11ExcludeTimers only works on UN*X", Continue);
#endif
QCOMPARE(timerReceiver.gotTimerEvent, -1);
@@ -524,210 +639,163 @@ void tst_QEventLoop::processEventsExcludeTimers()
timerReceiver.gotTimerEvent = -1;
}
-QTEST_MAIN(tst_QEventLoop)
-#include "tst_qeventloop.moc"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+#ifdef Q_OS_SYMBIAN
+class DummyActiveObject : public CActive
+{
+public:
+ DummyActiveObject(int levels);
+ ~DummyActiveObject();
+ void Start();
+protected:
+ void DoCancel();
+ void RunL();
+public:
+ bool succeeded;
+private:
+ RTimer m_rTimer;
+ int remainingLevels;
+};
+class ActiveSchedulerLoop : public QObject
+{
+public:
+ ActiveSchedulerLoop(int levels) : succeeded(false), timerId(-1), remainingLevels(levels) {}
+ ~ActiveSchedulerLoop() {}
+ void timerEvent(QTimerEvent *e);
+public:
+ bool succeeded;
+ int timerId;
+ int remainingLevels;
+};
+DummyActiveObject::DummyActiveObject(int levels)
+ : CActive(CActive::EPriorityStandard),
+ succeeded(false),
+ remainingLevels(levels)
+{
+ m_rTimer.CreateLocal();
+}
+DummyActiveObject::~DummyActiveObject()
+{
+ Cancel();
+ m_rTimer.Close();
+}
+void DummyActiveObject::DoCancel()
+{
+ m_rTimer.Cancel();
+}
+void DummyActiveObject::RunL()
+{
+ if (remainingLevels - 1 <= 0) {
+ ActiveSchedulerLoop loop(remainingLevels - 1);
+ loop.timerId = loop.startTimer(0);
+ QCoreApplication::processEvents();
+ succeeded = loop.succeeded;
+ } else {
+ succeeded = true;
+ }
+ CActiveScheduler::Stop();
+}
-// previous test
+void DummyActiveObject::Start()
+{
+ m_rTimer.After(iStatus, 100000); // 100 ms
+ SetActive();
+}
-#if 0
+void ActiveSchedulerLoop::timerEvent(QTimerEvent *e)
+{
+ Q_UNUSED(e);
+ DummyActiveObject *dummy = new(ELeave) DummyActiveObject(remainingLevels);
+ CActiveScheduler::Add(dummy);
-#include <qwidget.h>
+ dummy->Start();
-#ifdef Q_WS_WIN
-#include <windows.h>
-#endif
+ CActiveScheduler::Start();
+ succeeded = dummy->succeeded;
+ delete dummy;
-//TESTED_CLASS=
-//TESTED_FILES=
+ killTimer(timerId);
+}
-class EventHandlerWidget : public QWidget
+// We cannot trap panics when the test case fails, so run it in a different thread instead.
+class ActiveSchedulerThread : public QThread
{
public:
- EventHandlerWidget( QWidget* parent = 0, const char* name = 0 ) : QWidget( parent, name )
- {
- installEventFilter( this );
- recievedPaintEvent = FALSE;
- recievedMouseEvent = FALSE;
- }
- ~EventHandlerWidget() {}
-
- bool recievedPaintEvent;
- bool recievedMouseEvent;
+ ActiveSchedulerThread(QEventLoop::ProcessEventsFlag flags);
+ ~ActiveSchedulerThread();
protected:
- bool eventFilter( QObject* o, QEvent* e )
- {
- if ( e->type() == QEvent::Paint )
- recievedPaintEvent = TRUE;
- else if ( e->type() == QEvent::MouseButtonPress )
- recievedMouseEvent = TRUE;
- return QWidget::eventFilter( o, e );
- }
-};
+ void run();
-class InBetweenObject : public QObject
-{
- Q_OBJECT
public:
- InBetweenObject(QObject *parent, QObject *child)
- : QObject(parent), childObject(child)
- {
- childObject->setParent(this);
- ++instanceCounter;
- }
-
- ~InBetweenObject()
- {
- --instanceCounter;
- }
-
- static int instanceCounter;
-
-protected:
- void childEvent(QChildEvent *e)
- {
- if (e->removed() && e->child() == childObject) {
- deleteLater();
- }
- }
+ volatile bool succeeded;
private:
- QObject *childObject;
+ QEventLoop::ProcessEventsFlag m_flags;
};
-class ObjectContainer : public QObject
-{
-public:
- ObjectContainer(QObject *parent = 0)
- : QObject(parent)
- {
- }
-
-protected:
- void childEvent(QChildEvent *e)
- {
- if (e->inserted() && !::qobject_cast<InBetweenObject*>(e->child())) {
- InBetweenObject *inBetween = new InBetweenObject(this, e->child());
- }
- }
-};
-
-class tst_QEventLoop : public QObject
-{
- Q_OBJECT
-public:
- tst_QEventLoop();
- ~tst_QEventLoop();
-public slots:
- void init();
- void cleanup();
-private slots:
- void processEvents();
- void eventHandlerPostsEvent();
-};
-
-tst_QEventLoop::tst_QEventLoop()
+ActiveSchedulerThread::ActiveSchedulerThread(QEventLoop::ProcessEventsFlag flags)
+ : succeeded(false),
+ m_flags(flags)
{
}
-tst_QEventLoop::~tst_QEventLoop()
+ActiveSchedulerThread::~ActiveSchedulerThread()
{
}
-void tst_QEventLoop::init()
+void ActiveSchedulerThread::run()
{
-}
+ ActiveSchedulerLoop loop(2);
+ loop.timerId = loop.startTimer(0);
+ // It may panic in here if the active scheduler and the Qt loop don't go together.
+ QCoreApplication::processEvents(m_flags);
-void tst_QEventLoop::cleanup()
-{
+ succeeded = loop.succeeded;
}
+#endif // ifdef Q_OS_SYMBIAN
-
-void tst_QEventLoop::processEvents()
+void tst_QEventLoop::symbianNestedActiveSchedulerLoop_data()
{
- EventHandlerWidget *mainWidget = new EventHandlerWidget( 0 );
- mainWidget->show();
- qApp->setMainWidget( mainWidget );
-
-#ifdef Q_WS_WIN
- QEventLoop* eventLoop = qApp->eventLoop();
- eventLoop->processEvents( QEventLoop::AllEvents );
- QVERIFY( !eventLoop->hasPendingEvents() );
+ QTest::addColumn<int>("processEventFlags");
- // Make sure the flag is cleared first
- mainWidget->recievedPaintEvent = FALSE;
-#ifdef Q_WS_WIN
- InvalidateRect( mainWidget->winId(), 0, TRUE );
-#endif
- QVERIFY( !mainWidget->recievedPaintEvent );
- eventLoop->processEvents( QEventLoop::AllEvents );
- QVERIFY( mainWidget->recievedPaintEvent );
-
-#ifdef Q_WS_WIN
- // TODO: Hardcoded for now...
- LPARAM lParam = MAKELPARAM( 10, 10 );
- PostMessage( mainWidget->winId(), WM_LBUTTONDOWN, 0, lParam );
-#endif
-
- mainWidget->recievedMouseEvent = FALSE;
- eventLoop->processEvents( QEventLoop::ExcludeUserInput );
- QVERIFY( !mainWidget->recievedMouseEvent );
-#else
- QSKIP( "QEventLoop test is not implememented on X11 yet", SkipAll);
-#endif
+ QTest::newRow("AllEvents") << (int)QEventLoop::AllEvents;
+ QTest::newRow("WaitForMoreEvents") << (int)QEventLoop::WaitForMoreEvents;
}
-int InBetweenObject::instanceCounter = 0;
-
-void tst_QEventLoop::eventHandlerPostsEvent()
+/*
+ Before you start fiddling with this test, you should have a good understanding of how
+ Symbian active objects work. What the test does is to try to screw up the semaphore count
+ in the active scheduler to cause stray signals, by running the Qt event loop and the
+ active scheduler inside each other. Naturally, its attempts to do this should be futile!
+*/
+void tst_QEventLoop::symbianNestedActiveSchedulerLoop()
{
- ObjectContainer container;
-
- QObject *object = new QObject(&container);
- qApp->processEvents();
- qApp->processEvents();
-
- QCOMPARE(InBetweenObject::instanceCounter, 1);
+#ifndef Q_OS_SYMBIAN
+ QSKIP("This is a Symbian only test.", SkipAll);
+#else
+ QFETCH(int, processEventFlags);
- object->deleteLater();
+ ActiveSchedulerThread thread((QEventLoop::ProcessEventsFlag)processEventFlags);
+ thread.start();
+ thread.wait(2000);
- qApp->processEvents();
- QCOMPARE(InBetweenObject::instanceCounter, 0);
-};
+ QVERIFY(thread.succeeded);
+#endif
+}
QTEST_MAIN(tst_QEventLoop)
#include "tst_qeventloop.moc"
-
-#endif