1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the test suite of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
41
#include <QCoreApplication>
43
#include <QtTest/QtTest>
45
#include <QtConcurrent>
46
#include <private/qfutureinterface_p.h>
48
using namespace QtConcurrent;
50
#include <QtTest/QtTest>
54
class tst_QFutureWatcher: public QObject
59
void progressValueChanged();
64
void watchFinishedFuture();
65
void watchCanceledFuture();
66
void disconnectRunningFuture();
67
void tooMuchProgress();
69
void sharedFutureInterface();
75
void incrementalMapResults();
76
void incrementalFilterResults();
77
void qfutureSynchronizer();
86
void tst_QFutureWatcher::startFinish()
88
QFutureWatcher<void> futureWatcher;
90
QSignalSpy startedSpy(&futureWatcher, SIGNAL(started()));
91
QSignalSpy finishedSpy(&futureWatcher, SIGNAL(finished()));
93
QVERIFY(startedSpy.isValid());
94
QVERIFY(finishedSpy.isValid());
96
futureWatcher.setFuture(QtConcurrent::run(sleeper));
97
QTest::qWait(10); // spin the event loop to deliver queued signals.
98
QCOMPARE(startedSpy.count(), 1);
99
QCOMPARE(finishedSpy.count(), 0);
100
futureWatcher.future().waitForFinished();
102
QCOMPARE(startedSpy.count(), 1);
103
QCOMPARE(finishedSpy.count(), 1);
106
void mapSleeper(int &)
111
QSet<int> progressValues;
112
QSet<QString> progressTexts;
114
class ProgressObject : public QObject
118
void printProgress(int);
119
void printText(const QString &text);
120
void registerProgress(int);
121
void registerText(const QString &text);
124
void ProgressObject::printProgress(int progress)
126
qDebug() << "thread" << QThread::currentThread() << "reports progress" << progress;
129
void ProgressObject::printText(const QString &text)
131
qDebug() << "thread" << QThread::currentThread() << "reports progress text" << text;
134
void ProgressObject::registerProgress(int progress)
137
progressValues.insert(progress);
140
void ProgressObject::registerText(const QString &text)
143
progressTexts.insert(text);
147
QList<int> createList(int listSize)
150
for (int i = 0; i < listSize; ++i) {
156
void tst_QFutureWatcher::progressValueChanged()
159
qDebug() << "main thread" << QThread::currentThread();
162
progressValues.clear();
163
const int listSize = 20;
164
QList<int> list = createList(listSize);
166
QFutureWatcher<void> futureWatcher;
167
ProgressObject progressObject;
168
QObject::connect(&futureWatcher, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
170
QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), &progressObject, SLOT(printProgress(int)), Qt::DirectConnection );
172
QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), &progressObject, SLOT(registerProgress(int)));
174
futureWatcher.setFuture(QtConcurrent::map(list, mapSleeper));
176
QTestEventLoop::instance().enterLoop(5);
177
QVERIFY(!QTestEventLoop::instance().timeout());
178
futureWatcher.disconnect();
179
QVERIFY(progressValues.contains(0));
180
QVERIFY(progressValues.contains(listSize));
183
class CancelObject : public QObject
188
CancelObject() : wasCanceled(false) {};
193
void CancelObject::cancel()
196
qDebug() << "thread" << QThread::currentThread() << "reports canceled";
201
void tst_QFutureWatcher::canceled()
203
const int listSize = 20;
204
QList<int> list = createList(listSize);
206
QFutureWatcher<void> futureWatcher;
207
QFuture<void> future;
208
CancelObject cancelObject;
210
QObject::connect(&futureWatcher, SIGNAL(canceled()), &cancelObject, SLOT(cancel()));
211
QObject::connect(&futureWatcher, SIGNAL(canceled()),
212
&QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
214
future = QtConcurrent::map(list, mapSleeper);
215
futureWatcher.setFuture(future);
216
futureWatcher.cancel();
217
QTestEventLoop::instance().enterLoop(5);
218
QVERIFY(!QTestEventLoop::instance().timeout());
220
QVERIFY(future.isCanceled());
221
QVERIFY(cancelObject.wasCanceled);
222
futureWatcher.disconnect();
223
future.waitForFinished();
226
class IntTask : public RunFunctionTask<int>
235
void tst_QFutureWatcher::resultAt()
237
QFutureWatcher<int> futureWatcher;
238
futureWatcher.setFuture((new IntTask())->start());
239
futureWatcher.waitForFinished();
240
QCOMPARE(futureWatcher.result(), 10);
241
QCOMPARE(futureWatcher.resultAt(0), 10);
244
void tst_QFutureWatcher::resultReadyAt()
246
QFutureWatcher<int> futureWatcher;
247
QObject::connect(&futureWatcher, SIGNAL(resultReadyAt(int)), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
249
QFuture<int> future = (new IntTask())->start();
250
futureWatcher.setFuture(future);
252
QTestEventLoop::instance().enterLoop(1);
253
QVERIFY(!QTestEventLoop::instance().timeout());
255
// Setting the future again should give us another signal.
256
// (this is to prevent the race where the task associated
257
// with the future finishes before setFuture is called.)
258
futureWatcher.setFuture(QFuture<int>());
259
futureWatcher.setFuture(future);
261
QTestEventLoop::instance().enterLoop(1);
262
QVERIFY(!QTestEventLoop::instance().timeout());
265
class SignalSlotObject : public QObject
275
qDebug() << "started called";
280
qDebug() << "finished called";
285
qDebug() << "canceled called";
289
void resultReadyAt(int index)
291
qDebug() << "result" << index << "ready";
294
void resultReadyAt(int) { }
296
void progressValueChanged(int progress)
298
qDebug() << "progress" << progress;
301
void progressRangeChanged(int min, int max)
303
qDebug() << "progress range" << min << max;
308
void tst_QFutureWatcher::futureSignals()
311
QFutureInterface<int> a;
312
QFutureWatcher<int> f;
314
SignalSlotObject object;
316
connect(&f, SIGNAL(finished()), &object, SLOT(finished()));
317
connect(&f, SIGNAL(progressValueChanged(int)), &object, SLOT(progressValueChanged(int)));
319
// must connect to resultReadyAt so that the watcher can detect the connection
320
// (QSignalSpy does not trigger it.)
321
connect(&f, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
323
f.setFuture(a.future());
325
QSignalSpy progressSpy(&f, SIGNAL(progressValueChanged(int)));
326
QVERIFY(progressSpy.isValid());
327
const int progress = 1;
328
a.setProgressValue(progress);
330
QCOMPARE(progressSpy.count(), 2);
331
QCOMPARE(progressSpy.takeFirst().at(0).toInt(), 0);
332
QCOMPARE(progressSpy.takeFirst().at(0).toInt(), 1);
334
QSignalSpy finishedSpy(&f, SIGNAL(finished()));
335
QSignalSpy resultReadySpy(&f, SIGNAL(resultReadyAt(int)));
337
QVERIFY(finishedSpy.isValid());
338
QVERIFY(resultReadySpy.isValid());
340
const int result = 10;
341
a.reportResult(&result);
343
QCOMPARE(resultReadySpy.count(), 1);
344
a.reportFinished(&result);
347
QCOMPARE(resultReadySpy.count(), 2);
348
QCOMPARE(resultReadySpy.takeFirst().at(0).toInt(), 0); // check the index
349
QCOMPARE(resultReadySpy.takeFirst().at(0).toInt(), 1);
351
QCOMPARE(finishedSpy.count(), 1);
355
void tst_QFutureWatcher::watchFinishedFuture()
357
QFutureInterface<int> iface;
358
iface.reportStarted();
360
QFuture<int> f = iface.future();
363
iface.reportFinished(&value);
365
QFutureWatcher<int> watcher;
367
SignalSlotObject object;
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)));
375
connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
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()));
382
QVERIFY(startedSpy.isValid());
383
QVERIFY(finishedSpy.isValid());
384
QVERIFY(resultReadySpy.isValid());
385
QVERIFY(canceledSpy.isValid());
387
watcher.setFuture(f);
390
QCOMPARE(startedSpy.count(), 1);
391
QCOMPARE(finishedSpy.count(), 1);
392
QCOMPARE(resultReadySpy.count(), 1);
393
QCOMPARE(canceledSpy.count(), 0);
396
void tst_QFutureWatcher::watchCanceledFuture()
399
QFutureWatcher<int> watcher;
401
SignalSlotObject object;
403
connect(&watcher, SIGNAL(started()), &object, SLOT(started()));
404
connect(&watcher, SIGNAL(canceled()), &object, SLOT(canceled()));
405
connect(&watcher, SIGNAL(finished()), &object, SLOT(finished()));
406
connect(&watcher, SIGNAL(progressValueChanged(int)), &object, SLOT(progressValueChanged(int)));
407
connect(&watcher, SIGNAL(progressRangeChanged(int,int)), &object, SLOT(progressRangeChanged(int,int)));
409
connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
411
QSignalSpy startedSpy(&watcher, SIGNAL(started()));
412
QSignalSpy finishedSpy(&watcher, SIGNAL(finished()));
413
QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int)));
414
QSignalSpy canceledSpy(&watcher, SIGNAL(canceled()));
416
QVERIFY(startedSpy.isValid());
417
QVERIFY(finishedSpy.isValid());
418
QVERIFY(resultReadySpy.isValid());
419
QVERIFY(canceledSpy.isValid());
421
watcher.setFuture(f);
424
QCOMPARE(startedSpy.count(), 1);
425
QCOMPARE(finishedSpy.count(), 1);
426
QCOMPARE(resultReadySpy.count(), 0);
427
QCOMPARE(canceledSpy.count(), 1);
430
void tst_QFutureWatcher::disconnectRunningFuture()
432
QFutureInterface<int> a;
435
QFuture<int> f = a.future();
436
QFutureWatcher<int> *watcher = new QFutureWatcher<int>();
437
watcher->setFuture(f);
439
SignalSlotObject object;
440
connect(watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
442
QSignalSpy finishedSpy(watcher, SIGNAL(finished()));
443
QSignalSpy resultReadySpy(watcher, SIGNAL(resultReadyAt(int)));
445
QVERIFY(finishedSpy.isValid());
446
QVERIFY(resultReadySpy.isValid());
448
const int result = 10;
449
a.reportResult(&result);
451
QCOMPARE(resultReadySpy.count(), 1);
455
a.reportResult(&result);
457
QCOMPARE(resultReadySpy.count(), 1);
459
a.reportFinished(&result);
461
QCOMPARE(finishedSpy.count(), 0);
464
const int maxProgress = 100000;
465
class ProgressEmitterTask : public RunFunctionTask<void>
470
setProgressRange(0, maxProgress);
471
for (int p = 0; p <= maxProgress; ++p)
476
void tst_QFutureWatcher::tooMuchProgress()
478
progressValues.clear();
481
QFutureWatcher<void> f;
482
QObject::connect(&f, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
484
QObject::connect(&f, SIGNAL(progressValueChanged(int)), &o, SLOT(printProgress(int)));
486
QObject::connect(&f, SIGNAL(progressValueChanged(int)), &o, SLOT(registerProgress(int)));
487
f.setFuture((new ProgressEmitterTask())->start());
489
QTestEventLoop::instance().enterLoop(5);
490
QVERIFY(!QTestEventLoop::instance().timeout());
491
QVERIFY(progressValues.contains(maxProgress));
494
template <typename T>
495
class ProgressTextTask : public RunFunctionTask<T>
500
this->setProgressValueAndText(1, QLatin1String("Foo 1"));
502
while (this->isProgressUpdateNeeded() == false)
504
this->setProgressValueAndText(2, QLatin1String("Foo 2"));
506
while (this->isProgressUpdateNeeded() == false)
508
this->setProgressValueAndText(3, QLatin1String("Foo 3"));
510
while (this->isProgressUpdateNeeded() == false)
512
this->setProgressValueAndText(4, QLatin1String("Foo 4"));
516
void tst_QFutureWatcher::progressText()
518
{ // instantiate API for T=int and T=void.
519
ProgressTextTask<int> a;
520
ProgressTextTask<void> b;
523
progressValues.clear();
524
progressTexts.clear();
525
QFuture<int> f = ((new ProgressTextTask<int>())->start());
526
QFutureWatcher<int> watcher;
528
QObject::connect(&watcher, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
530
QObject::connect(&watcher, SIGNAL(progressValueChanged(int)), &o, SLOT(printProgress(int)));
531
QObject::connect(&watcher, SIGNAL(progressTextChanged(QString)), &o, SLOT(printText(QString)));
533
QObject::connect(&watcher, SIGNAL(progressValueChanged(int)), &o, SLOT(registerProgress(int)));
534
QObject::connect(&watcher, SIGNAL(progressTextChanged(QString)), &o, SLOT(registerText(QString)));
536
watcher.setFuture(f);
537
QTestEventLoop::instance().enterLoop(5);
538
QVERIFY(!QTestEventLoop::instance().timeout());
540
QCOMPARE(f.progressText(), QLatin1String("Foo 4"));
541
QCOMPARE(f.progressValue(), 4);
542
QVERIFY(progressValues.contains(1));
543
QVERIFY(progressValues.contains(2));
544
QVERIFY(progressValues.contains(3));
545
QVERIFY(progressValues.contains(4));
546
QVERIFY(progressTexts.contains(QLatin1String("Foo 1")));
547
QVERIFY(progressTexts.contains(QLatin1String("Foo 2")));
548
QVERIFY(progressTexts.contains(QLatin1String("Foo 3")));
549
QVERIFY(progressTexts.contains(QLatin1String("Foo 4")));
553
template <typename T>
554
void callInterface(T &obj)
557
obj.progressMinimum();
558
obj.progressMaximum();
571
obj.waitForFinished();
573
const T& objConst = obj;
574
objConst.progressValue();
575
objConst.progressMinimum();
576
objConst.progressMaximum();
577
objConst.progressText();
579
objConst.isStarted();
580
objConst.isFinished();
581
objConst.isRunning();
582
objConst.isCanceled();
586
template <typename T>
587
void callInterface(const T &obj)
594
// QFutureWatcher and QFuture has a similar interface. Test
595
// that the functions we want ot have in both are actually
597
void tst_QFutureWatcher::sharedFutureInterface()
599
QFutureInterface<int> iface;
600
iface.reportStarted();
602
QFuture<int> intFuture = iface.future();
605
iface.reportFinished(&value);
607
QFuture<void> voidFuture;
608
QFutureWatcher<int> intWatcher;
609
intWatcher.setFuture(intFuture);
610
QFutureWatcher<void> voidWatcher;
612
callInterface(intFuture);
613
callInterface(voidFuture);
614
callInterface(intWatcher);
615
callInterface(voidWatcher);
617
callInterface(intFuture);
618
callInterface(intWatcher);
621
void tst_QFutureWatcher::changeFuture()
623
QFutureInterface<int> iface;
624
iface.reportStarted();
626
QFuture<int> a = iface.future();
629
iface.reportFinished(&value);
633
QFutureWatcher<int> watcher;
635
SignalSlotObject object;
636
connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
637
QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int)));
638
QVERIFY(resultReadySpy.isValid());
640
watcher.setFuture(a); // Watch 'a' which will genere a resultReady event.
641
watcher.setFuture(b); // But oh no! we're switching to another future
642
QTest::qWait(10); // before the event gets delivered.
644
QCOMPARE(resultReadySpy.count(), 0);
646
watcher.setFuture(a);
647
watcher.setFuture(b);
648
watcher.setFuture(a); // setting it back gets us one event, not two.
651
QCOMPARE(resultReadySpy.count(), 1);
654
// Test that events aren't delivered from canceled futures
655
void tst_QFutureWatcher::cancelEvents()
657
QFutureInterface<int> iface;
658
iface.reportStarted();
660
QFuture<int> a = iface.future();
663
iface.reportFinished(&value);
665
QFutureWatcher<int> watcher;
667
SignalSlotObject object;
668
connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
669
QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int)));
670
QVERIFY(resultReadySpy.isValid());
672
watcher.setFuture(a);
677
QCOMPARE(resultReadySpy.count(), 0);
680
// Tests that events from paused futures are saved and
681
// delivered on resume.
682
void tst_QFutureWatcher::pauseEvents()
685
QFutureInterface<int> iface;
686
iface.reportStarted();
688
QFuture<int> a = iface.future();
691
iface.reportFinished(&value);
693
QFutureWatcher<int> watcher;
695
SignalSlotObject object;
696
connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
697
QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int)));
698
QVERIFY(resultReadySpy.isValid());
700
watcher.setFuture(a);
704
QCOMPARE(resultReadySpy.count(), 0);
708
QCOMPARE(resultReadySpy.count(), 1);
711
QFutureInterface<int> iface;
712
iface.reportStarted();
714
QFuture<int> a = iface.future();
717
iface.reportFinished(&value);
719
QFutureWatcher<int> watcher;
721
SignalSlotObject object;
722
connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
723
QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int)));
724
QVERIFY(resultReadySpy.isValid());
726
watcher.setFuture(a);
730
watcher.setFuture(b); // If we watch b instead, resuming a
731
a.resume(); // should give us no results.
734
QCOMPARE(resultReadySpy.count(), 0);
738
// Test that the finished state for the watcher gets
739
// set when the finished event is delivered.
740
// This means it will lag the finished state for the future,
741
// but makes it more useful.
742
void tst_QFutureWatcher::finishedState()
744
QFutureInterface<int> iface;
745
iface.reportStarted();
746
QFuture<int> future = iface.future();
747
QFutureWatcher<int> watcher;
749
watcher.setFuture(future);
752
iface.reportFinished();
753
QVERIFY(future.isFinished());
754
QVERIFY(watcher.isFinished() == false);
757
QVERIFY(watcher.isFinished());
761
Verify that throttling kicks in if you report a lot of results,
762
and that it clears when the result events are processed.
764
void tst_QFutureWatcher::throttling()
766
QFutureInterface<int> iface;
767
iface.reportStarted();
768
QFuture<int> future = iface.future();
769
QFutureWatcher<int> watcher;
770
watcher.setFuture(future);
772
QVERIFY(iface.isThrottled() == false);
774
for (int i = 0; i < 1000; ++i) {
776
iface.reportResult(result);
779
QVERIFY(iface.isThrottled() == true);
781
QTest::qWait(100); // process events.
783
QVERIFY(iface.isThrottled() == false);
785
iface.reportFinished();
788
int mapper(const int &i)
793
class ResultReadyTester : public QObject
797
ResultReadyTester(QFutureWatcher<int> *watcher)
798
:m_watcher(watcher), filter(false), ok(true), count(0)
803
void resultReadyAt(int index)
806
if (m_watcher->future().isResultReadyAt(index) == false)
808
if (!filter && m_watcher->future().resultAt(index) != index)
810
if (filter && m_watcher->future().resultAt(index) != index * 2 + 1)
814
QFutureWatcher<int> *m_watcher;
820
void tst_QFutureWatcher::incrementalMapResults()
822
QFutureWatcher<int> watcher;
824
SignalSlotObject object;
826
connect(&watcher, SIGNAL(finished()), &object, SLOT(finished()));
827
connect(&watcher, SIGNAL(progressValueChanged(int)), &object, SLOT(progressValueChanged(int)));
828
connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
831
QObject::connect(&watcher, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
833
ResultReadyTester resultReadyTester(&watcher);
834
connect(&watcher, SIGNAL(resultReadyAt(int)), &resultReadyTester, SLOT(resultReadyAt(int)));
836
const int count = 10000;
838
for (int i = 0; i < count; ++i)
841
QFuture<int> future = QtConcurrent::mapped(ints, mapper);
842
watcher.setFuture(future);
844
QTestEventLoop::instance().enterLoop(10);
845
QVERIFY(!QTestEventLoop::instance().timeout());
846
QCOMPARE(resultReadyTester.count, count);
847
QVERIFY(resultReadyTester.ok);
848
QVERIFY(watcher.isFinished());
849
future.waitForFinished();
857
void tst_QFutureWatcher::incrementalFilterResults()
859
QFutureWatcher<int> watcher;
861
SignalSlotObject object;
863
connect(&watcher, SIGNAL(finished()), &object, SLOT(finished()));
864
connect(&watcher, SIGNAL(progressValueChanged(int)), &object, SLOT(progressValueChanged(int)));
865
connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
868
QObject::connect(&watcher, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
871
ResultReadyTester resultReadyTester(&watcher);
872
resultReadyTester.filter = true;
873
connect(&watcher, SIGNAL(resultReadyAt(int)), &resultReadyTester, SLOT(resultReadyAt(int)));
875
const int count = 10000;
877
for (int i = 0; i < count; ++i)
880
QFuture<int> future = QtConcurrent::filtered(ints, filterer);
881
watcher.setFuture(future);
883
QTestEventLoop::instance().enterLoop(10);
884
QVERIFY(!QTestEventLoop::instance().timeout());
885
QCOMPARE(resultReadyTester.count, count / 2);
886
QVERIFY(resultReadyTester.ok);
887
QVERIFY(watcher.isFinished());
888
future.waitForFinished();
891
void tst_QFutureWatcher::qfutureSynchronizer()
893
int taskCount = 1000;
898
QFutureSynchronizer<void> sync;
900
sync.setCancelOnWait(true);
901
for (int i = 0; i < taskCount; ++i) {
902
sync.addFuture(run(sleeper));
906
// Test that we're not running each task.
907
QVERIFY(t.elapsed() < taskCount * 10);
910
class DummyObject : public QObject {
915
static void function(QMutex *m)
917
QMutexLocker lock(m);
921
void tst_QFutureWatcher::warnRace()
923
#ifndef Q_OS_MAC //I don't know why it is not working on mac
925
QTest::ignoreMessage(QtWarningMsg, "QFutureWatcher::connect: connecting after calling setFuture() is likely to produce race");
928
QFutureWatcher<void> watcher;
933
QFuture<void> future = QtConcurrent::run(DummyObject::function, &mutex);
934
watcher.setFuture(future);
935
QTRY_VERIFY(future.isStarted());
936
connect(&watcher, SIGNAL(finished()), &object, SLOT(dummySlot()));
938
future.waitForFinished();
941
QTEST_MAIN(tst_QFutureWatcher)
942
#include "tst_qfuturewatcher.moc"