tests/auto/qfuturewatcher/tst_qfuturewatcher.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 #include <QCoreApplication>
       
    42 #include <QDebug>
       
    43 #include <QtTest/QtTest>
       
    44 
       
    45 #include <qfuture.h>
       
    46 #include "../qfuture/versioncheck.h"
       
    47 #include <qfuturewatcher.h>
       
    48 #include <qtconcurrentrun.h>
       
    49 #include <qtconcurrentmap.h>
       
    50 
       
    51 #ifndef QT_NO_CONCURRENT_TEST
       
    52 #include <private/qfutureinterface_p.h>
       
    53 
       
    54 using namespace QtConcurrent;
       
    55 
       
    56 #include <QtTest/QtTest>
       
    57 
       
    58 //#define PRINT
       
    59 
       
    60 class tst_QFutureWatcher: public QObject
       
    61 {
       
    62     Q_OBJECT
       
    63 private slots:
       
    64     void startFinish();
       
    65     void progressValueChanged();
       
    66     void canceled();
       
    67     void resultAt();
       
    68     void resultReadyAt();
       
    69     void futureSignals();
       
    70     void watchFinishedFuture();
       
    71     void watchCanceledFuture();
       
    72     void disconnectRunningFuture();
       
    73     void toMuchProgress();
       
    74     void progressText();
       
    75     void sharedFutureInterface();
       
    76     void changeFuture();
       
    77     void cancelEvents();
       
    78     void pauseEvents();
       
    79     void finishedState();
       
    80     void throttling();
       
    81     void incrementalMapResults();
       
    82     void incrementalFilterResults();
       
    83     void qfutureSynchornizer();
       
    84 };
       
    85 
       
    86 QTEST_MAIN(tst_QFutureWatcher)
       
    87 
       
    88 void sleeper()
       
    89 {
       
    90     QTest::qSleep(100);
       
    91 }
       
    92 
       
    93 void tst_QFutureWatcher::startFinish()
       
    94 {
       
    95     QFutureWatcher<void> futureWatcher;
       
    96 
       
    97     QSignalSpy started(&futureWatcher, SIGNAL(started()));
       
    98     QSignalSpy finished(&futureWatcher, SIGNAL(finished()));
       
    99 
       
   100     futureWatcher.setFuture(QtConcurrent::run(sleeper));
       
   101     QTest::qWait(10); // spin the event loop to deliver queued signals.
       
   102     QCOMPARE(started.count(), 1);
       
   103     QCOMPARE(finished.count(), 0);
       
   104     futureWatcher.future().waitForFinished();
       
   105     QTest::qWait(10);
       
   106     QCOMPARE(started.count(), 1);
       
   107     QCOMPARE(finished.count(), 1);
       
   108 }
       
   109 
       
   110 void mapSleeper(int &)
       
   111 {
       
   112     QTest::qSleep(100);
       
   113 }
       
   114 
       
   115 QSet<int> progressValues;
       
   116 QSet<QString> progressTexts;
       
   117 QMutex mutex;
       
   118 class ProgressObject : public QObject
       
   119 {
       
   120 Q_OBJECT
       
   121 public slots:
       
   122     void printProgress(int);
       
   123     void printText(const QString &text);
       
   124     void registerProgress(int);
       
   125     void registerText(const QString &text);
       
   126 };
       
   127 
       
   128 void ProgressObject::printProgress(int progress)
       
   129 {
       
   130     qDebug() << "thread" << QThread::currentThread() << "reports progress" << progress;
       
   131 }
       
   132 
       
   133 void ProgressObject::printText(const QString &text)
       
   134 {
       
   135     qDebug() << "thread" << QThread::currentThread() << "reports progress text" << text;
       
   136 }
       
   137 
       
   138 void ProgressObject::registerProgress(int progress)
       
   139 {
       
   140     QTest::qSleep(1);
       
   141     progressValues.insert(progress);
       
   142 }
       
   143 
       
   144 void ProgressObject::registerText(const QString &text)
       
   145 {
       
   146     QTest::qSleep(1);
       
   147     progressTexts.insert(text);
       
   148 }
       
   149 
       
   150 
       
   151 QList<int> createList(int listSize)
       
   152 {
       
   153     QList<int> list;
       
   154     for (int i = 0; i < listSize; ++i) {
       
   155         list.append(i);
       
   156     }
       
   157     return list;
       
   158 }
       
   159 
       
   160 void tst_QFutureWatcher::progressValueChanged()
       
   161 {
       
   162 #ifdef PRINT
       
   163     qDebug() << "main thread" << QThread::currentThread();
       
   164 #endif
       
   165 
       
   166     progressValues.clear();
       
   167     const int listSize = 20;
       
   168     QList<int> list = createList(listSize);
       
   169 
       
   170     QFutureWatcher<void> futureWatcher;
       
   171     ProgressObject progressObject;
       
   172     QObject::connect(&futureWatcher, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
   173 #ifdef PRINT
       
   174     QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), &progressObject, SLOT(printProgress(int)), Qt::DirectConnection );
       
   175 #endif
       
   176     QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), &progressObject, SLOT(registerProgress(int)));
       
   177 
       
   178     futureWatcher.setFuture(QtConcurrent::map(list, mapSleeper));
       
   179 
       
   180     QTestEventLoop::instance().enterLoop(5);
       
   181     QVERIFY(!QTestEventLoop::instance().timeout());
       
   182     futureWatcher.disconnect();
       
   183     QVERIFY(progressValues.contains(0));
       
   184     QVERIFY(progressValues.contains(listSize));
       
   185 }
       
   186 
       
   187 class CancelObject : public QObject
       
   188 {
       
   189 Q_OBJECT
       
   190 public:
       
   191     bool wasCanceled;
       
   192     CancelObject() : wasCanceled(false) {};
       
   193 public slots:
       
   194     void cancel();
       
   195 };
       
   196 
       
   197 void CancelObject::cancel()
       
   198 {
       
   199 #ifdef PRINT
       
   200     qDebug() << "thread" << QThread::currentThread() << "reports canceled";
       
   201 #endif
       
   202     wasCanceled = true;
       
   203 }
       
   204 
       
   205 void tst_QFutureWatcher::canceled()
       
   206 {
       
   207     const int listSize = 20;
       
   208     QList<int> list = createList(listSize);
       
   209 
       
   210     QFutureWatcher<void> futureWatcher;
       
   211     QFuture<void> future;
       
   212     CancelObject cancelObject;
       
   213 
       
   214     QObject::connect(&futureWatcher, SIGNAL(canceled()), &cancelObject, SLOT(cancel()));
       
   215     QObject::connect(&futureWatcher, SIGNAL(canceled()),
       
   216         &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
       
   217 
       
   218     future = QtConcurrent::map(list, mapSleeper);
       
   219     futureWatcher.setFuture(future);
       
   220     futureWatcher.cancel();
       
   221     QTestEventLoop::instance().enterLoop(5);
       
   222     QVERIFY(!QTestEventLoop::instance().timeout());
       
   223 
       
   224     QVERIFY(future.isCanceled());
       
   225     QVERIFY(cancelObject.wasCanceled);
       
   226     futureWatcher.disconnect();
       
   227     future.waitForFinished();
       
   228 }
       
   229 
       
   230 class IntTask : public RunFunctionTask<int>
       
   231 {
       
   232 public:
       
   233     void runFunctor()
       
   234     {
       
   235         result = 10;
       
   236     }
       
   237 };
       
   238 
       
   239 void tst_QFutureWatcher::resultAt()
       
   240 {
       
   241     QFutureWatcher<int> futureWatcher;
       
   242     futureWatcher.setFuture((new IntTask())->start());
       
   243     futureWatcher.waitForFinished();
       
   244     QCOMPARE(futureWatcher.result(), 10);
       
   245     QCOMPARE(futureWatcher.resultAt(0), 10);
       
   246 }
       
   247 
       
   248 void tst_QFutureWatcher::resultReadyAt()
       
   249 {
       
   250     QFutureWatcher<int> futureWatcher;
       
   251     QObject::connect(&futureWatcher, SIGNAL(resultReadyAt(int)), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
       
   252 
       
   253     QFuture<int> future = (new IntTask())->start();
       
   254     futureWatcher.setFuture(future);
       
   255 
       
   256     QTestEventLoop::instance().enterLoop(1);
       
   257     QVERIFY(!QTestEventLoop::instance().timeout());
       
   258 
       
   259     // Setting the future again should give us another signal.
       
   260     // (this is to prevent the race where the task associated
       
   261     // with the future finishes before setFuture is called.)
       
   262     futureWatcher.setFuture(QFuture<int>());
       
   263     futureWatcher.setFuture(future);
       
   264 
       
   265     QTestEventLoop::instance().enterLoop(1);
       
   266     QVERIFY(!QTestEventLoop::instance().timeout());
       
   267 }
       
   268 
       
   269 class SignalSlotObject : public QObject
       
   270 {
       
   271 Q_OBJECT
       
   272 
       
   273 signals:
       
   274     void cancel();
       
   275 
       
   276 public slots:
       
   277     void started()
       
   278     {
       
   279         qDebug() << "started called";
       
   280     }
       
   281 
       
   282     void finished()
       
   283     {
       
   284         qDebug() << "finished called";
       
   285     }
       
   286 
       
   287     void canceled()
       
   288     {
       
   289         qDebug() << "canceled called";
       
   290     }
       
   291 
       
   292 #ifdef PRINT
       
   293     void resultReadyAt(int index)
       
   294     {
       
   295         qDebug() << "result" << index << "ready";
       
   296     }
       
   297 #else
       
   298     void resultReadyAt(int) { }
       
   299 #endif
       
   300     void progressValueChanged(int progress)
       
   301     {
       
   302         qDebug() << "progress" << progress;
       
   303     }
       
   304 
       
   305     void progressRangeChanged(int min, int max)
       
   306     {
       
   307         qDebug() << "progress range" << min << max;
       
   308     }
       
   309 
       
   310 };
       
   311 
       
   312 void tst_QFutureWatcher::futureSignals()
       
   313 {
       
   314     {
       
   315         QFutureInterface<int> a;
       
   316         QFutureWatcher<int> f;
       
   317 
       
   318         SignalSlotObject object;
       
   319 #ifdef PRINT
       
   320         connect(&f, SIGNAL(finished()), &object, SLOT(finished()));
       
   321         connect(&f, SIGNAL(progressValueChanged(int)), &object, SLOT(progressValueChanged(int)));
       
   322 #endif
       
   323         // must connect to resultReadyAt so that the watcher can detect the connection
       
   324         // (QSignalSpy does not trigger it.)
       
   325         connect(&f, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
       
   326         a.reportStarted();
       
   327         f.setFuture(a.future());
       
   328 
       
   329         QSignalSpy progressSpy(&f, SIGNAL(progressValueChanged(int)));
       
   330         const int progress = 1;
       
   331         a.setProgressValue(progress);
       
   332         QTest::qWait(10);
       
   333         QCOMPARE(progressSpy.count(), 2);
       
   334         QCOMPARE(progressSpy.takeFirst().at(0).toInt(), 0);
       
   335         QCOMPARE(progressSpy.takeFirst().at(0).toInt(), 1);
       
   336 
       
   337         QSignalSpy finishedSpy(&f, SIGNAL(finished()));
       
   338         QSignalSpy resultReadySpy(&f, SIGNAL(resultReadyAt(int)));
       
   339 
       
   340         const int result = 10;
       
   341         a.reportResult(&result);
       
   342         QTest::qWait(10);
       
   343         QCOMPARE(resultReadySpy.count(), 1);
       
   344         a.reportFinished(&result);
       
   345         QTest::qWait(10);
       
   346 
       
   347         QCOMPARE(resultReadySpy.count(), 2);
       
   348         QCOMPARE(resultReadySpy.takeFirst().at(0).toInt(), 0); // check the index
       
   349         QCOMPARE(resultReadySpy.takeFirst().at(0).toInt(), 1);
       
   350 
       
   351         QCOMPARE(finishedSpy.count(), 1);
       
   352     }
       
   353 }
       
   354 
       
   355 void tst_QFutureWatcher::watchFinishedFuture()
       
   356 {
       
   357     QFutureInterface<int> iface;
       
   358     iface.reportStarted();
       
   359 
       
   360     QFuture<int> f = iface.future();
       
   361 
       
   362     int value = 100;
       
   363     iface.reportFinished(&value);
       
   364 
       
   365     QFutureWatcher<int> watcher;
       
   366 
       
   367     SignalSlotObject object;
       
   368 #ifdef PRINT
       
   369     connect(&watcher, SIGNAL(started()), &object, SLOT(started()));
       
   370     connect(&watcher, SIGNAL(canceled()), &object, SLOT(canceled()));
       
   371     connect(&watcher, SIGNAL(finished()), &object, SLOT(finished()));
       
   372     connect(&watcher, SIGNAL(progressValueChanged(int)), &object, SLOT(progressValueChanged(int)));
       
   373     connect(&watcher, SIGNAL(progressRangeChanged(int, int)), &object, SLOT(progressRangeChanged(int, int)));
       
   374 #endif
       
   375     connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
       
   376 
       
   377     QSignalSpy startedSpy(&watcher, SIGNAL(started()));
       
   378     QSignalSpy finishedSpy(&watcher, SIGNAL(finished()));
       
   379     QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int)));
       
   380     QSignalSpy canceledSpy(&watcher, SIGNAL(canceled()));
       
   381 
       
   382     watcher.setFuture(f);
       
   383     QTest::qWait(10);
       
   384 
       
   385     QCOMPARE(startedSpy.count(), 1);
       
   386     QCOMPARE(finishedSpy.count(), 1);
       
   387     QCOMPARE(resultReadySpy.count(), 1);
       
   388     QCOMPARE(canceledSpy.count(), 0);
       
   389 }
       
   390 
       
   391 void tst_QFutureWatcher::watchCanceledFuture()
       
   392 {
       
   393     QFuture<int> f;
       
   394     QFutureWatcher<int> watcher;
       
   395 
       
   396     SignalSlotObject object;
       
   397 #ifdef PRINT
       
   398     connect(&watcher, SIGNAL(started()), &object, SLOT(started()));
       
   399     connect(&watcher, SIGNAL(canceled()), &object, SLOT(canceled()));
       
   400     connect(&watcher, SIGNAL(finished()), &object, SLOT(finished()));
       
   401     connect(&watcher, SIGNAL(progressValueChanged(int)), &object, SLOT(progressValueChanged(int)));
       
   402     connect(&watcher, SIGNAL(progressRangeChanged(int, int)), &object, SLOT(progressRangeChanged(int, int)));
       
   403 #endif
       
   404     connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
       
   405 
       
   406     QSignalSpy startedSpy(&watcher, SIGNAL(started()));
       
   407     QSignalSpy finishedSpy(&watcher, SIGNAL(finished()));
       
   408     QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int)));
       
   409     QSignalSpy canceledSpy(&watcher, SIGNAL(canceled()));
       
   410 
       
   411     watcher.setFuture(f);
       
   412     QTest::qWait(10);
       
   413 
       
   414     QCOMPARE(startedSpy.count(), 1);
       
   415     QCOMPARE(finishedSpy.count(), 1);
       
   416     QCOMPARE(resultReadySpy.count(), 0);
       
   417     QCOMPARE(canceledSpy.count(), 1);
       
   418 }
       
   419 
       
   420 void tst_QFutureWatcher::disconnectRunningFuture()
       
   421 {
       
   422     QFutureInterface<int> a;
       
   423     a.reportStarted();
       
   424 
       
   425     QFuture<int> f = a.future();
       
   426     QFutureWatcher<int> *watcher = new QFutureWatcher<int>();
       
   427     watcher->setFuture(f);
       
   428 
       
   429     SignalSlotObject object;
       
   430     connect(watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
       
   431 
       
   432     QSignalSpy finishedSpy(watcher, SIGNAL(finished()));
       
   433     QSignalSpy resultReadySpy(watcher, SIGNAL(resultReadyAt(int)));
       
   434 
       
   435     const int result = 10;
       
   436     a.reportResult(&result);
       
   437     QTest::qWait(10);
       
   438     QCOMPARE(resultReadySpy.count(), 1);
       
   439 
       
   440     delete watcher;
       
   441 
       
   442     a.reportResult(&result);
       
   443     QTest::qWait(10);
       
   444     QCOMPARE(resultReadySpy.count(), 1);
       
   445 
       
   446     a.reportFinished(&result);
       
   447     QTest::qWait(10);
       
   448     QCOMPARE(finishedSpy.count(), 0);
       
   449 }
       
   450 
       
   451 const int maxProgress = 100000;
       
   452 class ProgressEmitterTask : public RunFunctionTask<void>
       
   453 {
       
   454 public:
       
   455     void runFunctor()
       
   456     {
       
   457         setProgressRange(0, maxProgress);
       
   458         for (int p = 0; p <= maxProgress; ++p)
       
   459             setProgressValue(p);
       
   460     }
       
   461 };
       
   462 
       
   463 void tst_QFutureWatcher::toMuchProgress()
       
   464 {
       
   465     progressValues.clear();
       
   466     ProgressObject o;
       
   467 
       
   468     QFutureWatcher<void> f;
       
   469     f.setFuture((new ProgressEmitterTask())->start());
       
   470     QObject::connect(&f, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
   471 #ifdef PRINT
       
   472     QObject::connect(&f, SIGNAL(progressValueChanged(int)), &o, SLOT(printProgress(int)));
       
   473 #endif
       
   474     QObject::connect(&f, SIGNAL(progressValueChanged(int)), &o, SLOT(registerProgress(int)));
       
   475 
       
   476     QTestEventLoop::instance().enterLoop(5);
       
   477     QVERIFY(!QTestEventLoop::instance().timeout());
       
   478     QVERIFY(progressValues.contains(maxProgress));
       
   479 }
       
   480 
       
   481 template <typename T>
       
   482 class ProgressTextTask : public RunFunctionTask<T>
       
   483 {
       
   484 public:
       
   485     void runFunctor()
       
   486     {
       
   487         while (this->isProgressUpdateNeeded() == false)
       
   488             QTest::qSleep(1);
       
   489         this->setProgressValueAndText(1, QLatin1String("Foo 1"));
       
   490 
       
   491         while (this->isProgressUpdateNeeded() == false)
       
   492             QTest::qSleep(1);
       
   493         this->setProgressValueAndText(2, QLatin1String("Foo 2"));
       
   494 
       
   495         while (this->isProgressUpdateNeeded() == false)
       
   496             QTest::qSleep(1);
       
   497         this->setProgressValueAndText(3, QLatin1String("Foo 3"));
       
   498     }
       
   499 };
       
   500 
       
   501 void tst_QFutureWatcher::progressText()
       
   502 {
       
   503     {   // instantiate API for T=int and T=void.
       
   504         ProgressTextTask<int> a;
       
   505         ProgressTextTask<void> b;
       
   506     }
       
   507     {
       
   508         progressValues.clear();
       
   509         progressTexts.clear();
       
   510         QFuture<int> f = ((new ProgressTextTask<int>())->start());
       
   511         QFutureWatcher<int> watcher;
       
   512         ProgressObject o;
       
   513         QObject::connect(&watcher, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
   514 #ifdef PRINT
       
   515         QObject::connect(&watcher, SIGNAL(progressValueChanged(int)), &o, SLOT(printProgress(int)));
       
   516         QObject::connect(&watcher, SIGNAL(progressTextChanged(const QString &)), &o, SLOT(printText(const QString &)));
       
   517 #endif
       
   518         QObject::connect(&watcher, SIGNAL(progressValueChanged(int)), &o, SLOT(registerProgress(int)));
       
   519         QObject::connect(&watcher, SIGNAL(progressTextChanged(const QString &)), &o, SLOT(registerText(const QString &)));
       
   520 
       
   521         watcher.setFuture(f);
       
   522         QTestEventLoop::instance().enterLoop(5);
       
   523         QVERIFY(!QTestEventLoop::instance().timeout());
       
   524 
       
   525         QCOMPARE(f.progressText(), QLatin1String("Foo 3"));
       
   526         QCOMPARE(f.progressValue(), 3);
       
   527         QVERIFY(progressValues.contains(1));
       
   528         QVERIFY(progressValues.contains(2));
       
   529         QVERIFY(progressValues.contains(3));
       
   530         QVERIFY(progressTexts.contains(QLatin1String("Foo 1")));
       
   531         QVERIFY(progressTexts.contains(QLatin1String("Foo 2")));
       
   532         QVERIFY(progressTexts.contains(QLatin1String("Foo 3")));
       
   533     }
       
   534 }
       
   535 
       
   536 template <typename T>
       
   537 void callInterface(T &obj)
       
   538 {
       
   539     obj.progressValue();
       
   540     obj.progressMinimum();
       
   541     obj.progressMaximum();
       
   542     obj.progressText();
       
   543 
       
   544     obj.isStarted();
       
   545     obj.isFinished();
       
   546     obj.isRunning();
       
   547     obj.isCanceled();
       
   548     obj.isPaused();
       
   549 
       
   550     obj.cancel();
       
   551     obj.pause();
       
   552     obj.resume();
       
   553     obj.togglePaused();
       
   554     obj.waitForFinished();
       
   555 
       
   556     const T& objConst = obj;
       
   557     objConst.progressValue();
       
   558     objConst.progressMinimum();
       
   559     objConst.progressMaximum();
       
   560     objConst.progressText();
       
   561 
       
   562     objConst.isStarted();
       
   563     objConst.isFinished();
       
   564     objConst.isRunning();
       
   565     objConst.isCanceled();
       
   566     objConst.isPaused();
       
   567 }
       
   568 
       
   569 template <typename T>
       
   570 void callInterface(const T &obj)
       
   571 {
       
   572     obj.result();
       
   573     obj.resultAt(0);
       
   574 }
       
   575 
       
   576 
       
   577 // QFutureWatcher and QFuture has a similar interface. Test
       
   578 // that the functions we want ot have in both are actually
       
   579 // there.
       
   580 void tst_QFutureWatcher::sharedFutureInterface()
       
   581 {
       
   582     QFutureInterface<int> iface;
       
   583     iface.reportStarted();
       
   584 
       
   585     QFuture<int> intFuture = iface.future();
       
   586 
       
   587     int value = 0;
       
   588     iface.reportFinished(&value);
       
   589 
       
   590     QFuture<void> voidFuture;
       
   591     QFutureWatcher<int> intWatcher;
       
   592     intWatcher.setFuture(intFuture);
       
   593     QFutureWatcher<void> voidWatcher;
       
   594 
       
   595     callInterface(intFuture);
       
   596     callInterface(voidFuture);
       
   597     callInterface(intWatcher);
       
   598     callInterface(voidWatcher);
       
   599 
       
   600     callInterface(intFuture);
       
   601     callInterface(intWatcher);
       
   602 }
       
   603 
       
   604 void tst_QFutureWatcher::changeFuture()
       
   605 {
       
   606     QFutureInterface<int> iface;
       
   607     iface.reportStarted();
       
   608 
       
   609     QFuture<int> a = iface.future();
       
   610 
       
   611     int value = 0;
       
   612     iface.reportFinished(&value);
       
   613 
       
   614     QFuture<int> b;
       
   615 
       
   616     QFutureWatcher<int> watcher;
       
   617 
       
   618     SignalSlotObject object;
       
   619     connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
       
   620     QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int)));
       
   621 
       
   622     watcher.setFuture(a); // Watch 'a' which will genere a resultReady event.
       
   623     watcher.setFuture(b); // But oh no! we're switching to another future
       
   624     QTest::qWait(10);     // before the event gets delivered.
       
   625 
       
   626     QCOMPARE(resultReadySpy.count(), 0);
       
   627 
       
   628     watcher.setFuture(a);
       
   629     watcher.setFuture(b);
       
   630     watcher.setFuture(a); // setting it back gets us one event, not two.
       
   631     QTest::qWait(10);
       
   632 
       
   633     QCOMPARE(resultReadySpy.count(), 1);
       
   634 }
       
   635 
       
   636 // Test that events aren't delivered from canceled futures
       
   637 void tst_QFutureWatcher::cancelEvents()
       
   638 {
       
   639     QFutureInterface<int> iface;
       
   640     iface.reportStarted();
       
   641 
       
   642     QFuture<int> a = iface.future();
       
   643 
       
   644     int value = 0;
       
   645     iface.reportFinished(&value);
       
   646 
       
   647     QFutureWatcher<int> watcher;
       
   648 
       
   649     SignalSlotObject object;
       
   650     connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
       
   651     QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int)));
       
   652 
       
   653     watcher.setFuture(a);
       
   654     watcher.cancel();
       
   655 
       
   656     QTest::qWait(10);
       
   657 
       
   658     QCOMPARE(resultReadySpy.count(), 0);
       
   659 }
       
   660 
       
   661 // Tests that events from paused futures are saved and
       
   662 // delivered on resume.
       
   663 void tst_QFutureWatcher::pauseEvents()
       
   664 {
       
   665     {
       
   666         QFutureInterface<int> iface;
       
   667         iface.reportStarted();
       
   668 
       
   669         QFuture<int> a = iface.future();
       
   670 
       
   671         int value = 0;
       
   672         iface.reportFinished(&value);
       
   673 
       
   674         QFutureWatcher<int> watcher;
       
   675 
       
   676         SignalSlotObject object;
       
   677         connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
       
   678         QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int)));
       
   679 
       
   680         watcher.setFuture(a);
       
   681         watcher.pause();
       
   682 
       
   683         QTest::qWait(10);
       
   684         QCOMPARE(resultReadySpy.count(), 0);
       
   685 
       
   686         watcher.resume();
       
   687         QTest::qWait(10);
       
   688         QCOMPARE(resultReadySpy.count(), 1);
       
   689     }
       
   690     {
       
   691         QFutureInterface<int> iface;
       
   692         iface.reportStarted();
       
   693 
       
   694         QFuture<int> a = iface.future();
       
   695 
       
   696         int value = 0;
       
   697         iface.reportFinished(&value);
       
   698 
       
   699         QFutureWatcher<int> watcher;
       
   700 
       
   701         SignalSlotObject object;
       
   702         connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
       
   703         QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int)));
       
   704 
       
   705         watcher.setFuture(a);
       
   706         a.pause();
       
   707 
       
   708         QFuture<int> b;
       
   709         watcher.setFuture(b); // If we watch b instead, resuming a
       
   710         a.resume();           // should give us no results.
       
   711 
       
   712         QTest::qWait(10);
       
   713         QCOMPARE(resultReadySpy.count(), 0);
       
   714     }
       
   715 }
       
   716 
       
   717 // Test that the finished state for the watcher gets
       
   718 // set when the finished event is delivered.
       
   719 // This means it will lag the finished state for the future,
       
   720 // but makes it more useful.
       
   721 void tst_QFutureWatcher::finishedState()
       
   722 {
       
   723     QFutureInterface<int> iface;
       
   724     iface.reportStarted();
       
   725     QFuture<int> future = iface.future();
       
   726     QFutureWatcher<int> watcher;
       
   727 
       
   728     watcher.setFuture(future);
       
   729     QTest::qWait(10);
       
   730 
       
   731     iface.reportFinished();
       
   732     QVERIFY(future.isFinished());
       
   733     QVERIFY(watcher.isFinished() == false);
       
   734 
       
   735     QTest::qWait(10);
       
   736     QVERIFY(watcher.isFinished());
       
   737 }
       
   738 
       
   739 /*
       
   740     Verify that throttling kicks in if you report a lot of results,
       
   741     and that it clears when the result events are processed.
       
   742 */
       
   743 void tst_QFutureWatcher::throttling()
       
   744 {
       
   745     QFutureInterface<int> iface;
       
   746     iface.reportStarted();
       
   747     QFuture<int> future = iface.future();
       
   748     QFutureWatcher<int> watcher;
       
   749     watcher.setFuture(future);
       
   750 
       
   751     QVERIFY(iface.isThrottled() == false);
       
   752 
       
   753     for (int i = 0; i < 1000; ++i) {
       
   754         int result = 0;
       
   755         iface.reportResult(result);
       
   756     }
       
   757 
       
   758     QVERIFY(iface.isThrottled() == true);
       
   759 
       
   760     QTest::qWait(100); // process events.
       
   761 
       
   762     QVERIFY(iface.isThrottled() == false);
       
   763 
       
   764     iface.reportFinished();
       
   765 }
       
   766 
       
   767 int mapper(const int &i)
       
   768 {
       
   769     return i;
       
   770 }
       
   771 
       
   772 class ResultReadyTester : public QObject
       
   773 {
       
   774 Q_OBJECT
       
   775 public:
       
   776     ResultReadyTester(QFutureWatcher<int> *watcher)
       
   777     :m_watcher(watcher), filter(false), ok(true), count(0)
       
   778     {
       
   779         
       
   780     }
       
   781 public slots:
       
   782     void resultReadyAt(int index)
       
   783     {
       
   784         ++count;
       
   785         if (m_watcher->future().isResultReadyAt(index) == false)
       
   786             ok = false;
       
   787         if (!filter && m_watcher->future().resultAt(index) != index)
       
   788             ok = false;
       
   789         if (filter && m_watcher->future().resultAt(index) != index * 2 + 1)
       
   790             ok = false;
       
   791     }
       
   792 public:
       
   793     QFutureWatcher<int> *m_watcher;
       
   794     bool filter;
       
   795     bool ok;
       
   796     int count;
       
   797 };
       
   798 
       
   799 void tst_QFutureWatcher::incrementalMapResults()
       
   800 {
       
   801     QFutureWatcher<int> watcher;
       
   802 
       
   803     SignalSlotObject object;
       
   804 #ifdef PRINT
       
   805     connect(&watcher, SIGNAL(finished()), &object, SLOT(finished()));
       
   806     connect(&watcher, SIGNAL(progressValueChanged(int)), &object, SLOT(progressValueChanged(int)));
       
   807     connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
       
   808 #endif
       
   809 
       
   810     QObject::connect(&watcher, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
   811 
       
   812     ResultReadyTester resultReadyTester(&watcher);
       
   813     connect(&watcher, SIGNAL(resultReadyAt(int)), &resultReadyTester, SLOT(resultReadyAt(int)));
       
   814 
       
   815     const int count = 10000;
       
   816     QList<int> ints; 
       
   817     for (int i = 0; i < count; ++i)
       
   818         ints << i;
       
   819 
       
   820     QFuture<int> future = QtConcurrent::mapped(ints, mapper);
       
   821     watcher.setFuture(future);
       
   822 
       
   823     QTestEventLoop::instance().enterLoop(10);
       
   824     QVERIFY(!QTestEventLoop::instance().timeout());
       
   825     QCOMPARE(resultReadyTester.count, count);
       
   826     QVERIFY(resultReadyTester.ok);
       
   827     QVERIFY(watcher.isFinished());
       
   828     future.waitForFinished(); 
       
   829 }
       
   830 
       
   831 bool filterer(int i)
       
   832 {
       
   833     return (i % 2);
       
   834 }
       
   835 
       
   836 void tst_QFutureWatcher::incrementalFilterResults()
       
   837 {
       
   838     QFutureWatcher<int> watcher;
       
   839 
       
   840     SignalSlotObject object;
       
   841 #ifdef PRINT
       
   842     connect(&watcher, SIGNAL(finished()), &object, SLOT(finished()));
       
   843     connect(&watcher, SIGNAL(progressValueChanged(int)), &object, SLOT(progressValueChanged(int)));
       
   844     connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
       
   845 #endif
       
   846 
       
   847     QObject::connect(&watcher, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
   848 
       
   849 
       
   850     ResultReadyTester resultReadyTester(&watcher);
       
   851     resultReadyTester.filter = true;
       
   852     connect(&watcher, SIGNAL(resultReadyAt(int)), &resultReadyTester, SLOT(resultReadyAt(int)));
       
   853 
       
   854     const int count = 10000;
       
   855     QList<int> ints; 
       
   856     for (int i = 0; i < count; ++i)
       
   857         ints << i;
       
   858 
       
   859     QFuture<int> future = QtConcurrent::filtered(ints, filterer);
       
   860     watcher.setFuture(future);
       
   861 
       
   862     QTestEventLoop::instance().enterLoop(10);
       
   863     QVERIFY(!QTestEventLoop::instance().timeout());
       
   864     QCOMPARE(resultReadyTester.count, count / 2);
       
   865     QVERIFY(resultReadyTester.ok);
       
   866     QVERIFY(watcher.isFinished());
       
   867     future.waitForFinished(); 
       
   868 }
       
   869 
       
   870 void tst_QFutureWatcher::qfutureSynchornizer()
       
   871 {
       
   872     int taskCount = 1000; 
       
   873     QTime t;
       
   874     t.start();
       
   875 
       
   876     {
       
   877         QFutureSynchronizer<void> sync;
       
   878 
       
   879         sync.setCancelOnWait(true);
       
   880         for (int i = 0; i < taskCount; ++i) {
       
   881             sync.addFuture(run(sleeper));
       
   882         }
       
   883     }
       
   884 
       
   885     // Test that we're not running each task.
       
   886     QVERIFY(t.elapsed() < taskCount * 10);
       
   887 }
       
   888 
       
   889 #include "tst_qfuturewatcher.moc"
       
   890 
       
   891 #else
       
   892 QTEST_NOOP_MAIN
       
   893 #endif