~ubuntu-branches/ubuntu/wily/qtbase-opensource-src/wily

« back to all changes in this revision

Viewing changes to tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 12:46:17 UTC
  • Revision ID: package-import@ubuntu.com-20130205124617-c8jouts182j002fx
Tags: upstream-5.0.1+dfsg
ImportĀ upstreamĀ versionĀ 5.0.1+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
 
4
** Contact: http://www.qt-project.org/legal
 
5
**
 
6
** This file is part of the test suite of the Qt Toolkit.
 
7
**
 
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.
 
16
**
 
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.
 
24
**
 
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.
 
28
**
 
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.
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
#include <QCoreApplication>
 
42
#include <QDebug>
 
43
#include <QtTest/QtTest>
 
44
 
 
45
#include <QtConcurrent>
 
46
#include <private/qfutureinterface_p.h>
 
47
 
 
48
using namespace QtConcurrent;
 
49
 
 
50
#include <QtTest/QtTest>
 
51
 
 
52
//#define PRINT
 
53
 
 
54
class tst_QFutureWatcher: public QObject
 
55
{
 
56
    Q_OBJECT
 
57
private slots:
 
58
    void startFinish();
 
59
    void progressValueChanged();
 
60
    void canceled();
 
61
    void resultAt();
 
62
    void resultReadyAt();
 
63
    void futureSignals();
 
64
    void watchFinishedFuture();
 
65
    void watchCanceledFuture();
 
66
    void disconnectRunningFuture();
 
67
    void tooMuchProgress();
 
68
    void progressText();
 
69
    void sharedFutureInterface();
 
70
    void changeFuture();
 
71
    void cancelEvents();
 
72
    void pauseEvents();
 
73
    void finishedState();
 
74
    void throttling();
 
75
    void incrementalMapResults();
 
76
    void incrementalFilterResults();
 
77
    void qfutureSynchronizer();
 
78
    void warnRace();
 
79
};
 
80
 
 
81
void sleeper()
 
82
{
 
83
    QTest::qSleep(100);
 
84
}
 
85
 
 
86
void tst_QFutureWatcher::startFinish()
 
87
{
 
88
    QFutureWatcher<void> futureWatcher;
 
89
 
 
90
    QSignalSpy startedSpy(&futureWatcher, SIGNAL(started()));
 
91
    QSignalSpy finishedSpy(&futureWatcher, SIGNAL(finished()));
 
92
 
 
93
    QVERIFY(startedSpy.isValid());
 
94
    QVERIFY(finishedSpy.isValid());
 
95
 
 
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();
 
101
    QTest::qWait(10);
 
102
    QCOMPARE(startedSpy.count(), 1);
 
103
    QCOMPARE(finishedSpy.count(), 1);
 
104
}
 
105
 
 
106
void mapSleeper(int &)
 
107
{
 
108
    QTest::qSleep(100);
 
109
}
 
110
 
 
111
QSet<int> progressValues;
 
112
QSet<QString> progressTexts;
 
113
QMutex mutex;
 
114
class ProgressObject : public QObject
 
115
{
 
116
Q_OBJECT
 
117
public slots:
 
118
    void printProgress(int);
 
119
    void printText(const QString &text);
 
120
    void registerProgress(int);
 
121
    void registerText(const QString &text);
 
122
};
 
123
 
 
124
void ProgressObject::printProgress(int progress)
 
125
{
 
126
    qDebug() << "thread" << QThread::currentThread() << "reports progress" << progress;
 
127
}
 
128
 
 
129
void ProgressObject::printText(const QString &text)
 
130
{
 
131
    qDebug() << "thread" << QThread::currentThread() << "reports progress text" << text;
 
132
}
 
133
 
 
134
void ProgressObject::registerProgress(int progress)
 
135
{
 
136
    QTest::qSleep(1);
 
137
    progressValues.insert(progress);
 
138
}
 
139
 
 
140
void ProgressObject::registerText(const QString &text)
 
141
{
 
142
    QTest::qSleep(1);
 
143
    progressTexts.insert(text);
 
144
}
 
145
 
 
146
 
 
147
QList<int> createList(int listSize)
 
148
{
 
149
    QList<int> list;
 
150
    for (int i = 0; i < listSize; ++i) {
 
151
        list.append(i);
 
152
    }
 
153
    return list;
 
154
}
 
155
 
 
156
void tst_QFutureWatcher::progressValueChanged()
 
157
{
 
158
#ifdef PRINT
 
159
    qDebug() << "main thread" << QThread::currentThread();
 
160
#endif
 
161
 
 
162
    progressValues.clear();
 
163
    const int listSize = 20;
 
164
    QList<int> list = createList(listSize);
 
165
 
 
166
    QFutureWatcher<void> futureWatcher;
 
167
    ProgressObject progressObject;
 
168
    QObject::connect(&futureWatcher, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
 
169
#ifdef PRINT
 
170
    QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), &progressObject, SLOT(printProgress(int)), Qt::DirectConnection );
 
171
#endif
 
172
    QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), &progressObject, SLOT(registerProgress(int)));
 
173
 
 
174
    futureWatcher.setFuture(QtConcurrent::map(list, mapSleeper));
 
175
 
 
176
    QTestEventLoop::instance().enterLoop(5);
 
177
    QVERIFY(!QTestEventLoop::instance().timeout());
 
178
    futureWatcher.disconnect();
 
179
    QVERIFY(progressValues.contains(0));
 
180
    QVERIFY(progressValues.contains(listSize));
 
181
}
 
182
 
 
183
class CancelObject : public QObject
 
184
{
 
185
Q_OBJECT
 
186
public:
 
187
    bool wasCanceled;
 
188
    CancelObject() : wasCanceled(false) {};
 
189
public slots:
 
190
    void cancel();
 
191
};
 
192
 
 
193
void CancelObject::cancel()
 
194
{
 
195
#ifdef PRINT
 
196
    qDebug() << "thread" << QThread::currentThread() << "reports canceled";
 
197
#endif
 
198
    wasCanceled = true;
 
199
}
 
200
 
 
201
void tst_QFutureWatcher::canceled()
 
202
{
 
203
    const int listSize = 20;
 
204
    QList<int> list = createList(listSize);
 
205
 
 
206
    QFutureWatcher<void> futureWatcher;
 
207
    QFuture<void> future;
 
208
    CancelObject cancelObject;
 
209
 
 
210
    QObject::connect(&futureWatcher, SIGNAL(canceled()), &cancelObject, SLOT(cancel()));
 
211
    QObject::connect(&futureWatcher, SIGNAL(canceled()),
 
212
        &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
 
213
 
 
214
    future = QtConcurrent::map(list, mapSleeper);
 
215
    futureWatcher.setFuture(future);
 
216
    futureWatcher.cancel();
 
217
    QTestEventLoop::instance().enterLoop(5);
 
218
    QVERIFY(!QTestEventLoop::instance().timeout());
 
219
 
 
220
    QVERIFY(future.isCanceled());
 
221
    QVERIFY(cancelObject.wasCanceled);
 
222
    futureWatcher.disconnect();
 
223
    future.waitForFinished();
 
224
}
 
225
 
 
226
class IntTask : public RunFunctionTask<int>
 
227
{
 
228
public:
 
229
    void runFunctor()
 
230
    {
 
231
        result = 10;
 
232
    }
 
233
};
 
234
 
 
235
void tst_QFutureWatcher::resultAt()
 
236
{
 
237
    QFutureWatcher<int> futureWatcher;
 
238
    futureWatcher.setFuture((new IntTask())->start());
 
239
    futureWatcher.waitForFinished();
 
240
    QCOMPARE(futureWatcher.result(), 10);
 
241
    QCOMPARE(futureWatcher.resultAt(0), 10);
 
242
}
 
243
 
 
244
void tst_QFutureWatcher::resultReadyAt()
 
245
{
 
246
    QFutureWatcher<int> futureWatcher;
 
247
    QObject::connect(&futureWatcher, SIGNAL(resultReadyAt(int)), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
 
248
 
 
249
    QFuture<int> future = (new IntTask())->start();
 
250
    futureWatcher.setFuture(future);
 
251
 
 
252
    QTestEventLoop::instance().enterLoop(1);
 
253
    QVERIFY(!QTestEventLoop::instance().timeout());
 
254
 
 
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);
 
260
 
 
261
    QTestEventLoop::instance().enterLoop(1);
 
262
    QVERIFY(!QTestEventLoop::instance().timeout());
 
263
}
 
264
 
 
265
class SignalSlotObject : public QObject
 
266
{
 
267
Q_OBJECT
 
268
 
 
269
signals:
 
270
    void cancel();
 
271
 
 
272
public slots:
 
273
    void started()
 
274
    {
 
275
        qDebug() << "started called";
 
276
    }
 
277
 
 
278
    void finished()
 
279
    {
 
280
        qDebug() << "finished called";
 
281
    }
 
282
 
 
283
    void canceled()
 
284
    {
 
285
        qDebug() << "canceled called";
 
286
    }
 
287
 
 
288
#ifdef PRINT
 
289
    void resultReadyAt(int index)
 
290
    {
 
291
        qDebug() << "result" << index << "ready";
 
292
    }
 
293
#else
 
294
    void resultReadyAt(int) { }
 
295
#endif
 
296
    void progressValueChanged(int progress)
 
297
    {
 
298
        qDebug() << "progress" << progress;
 
299
    }
 
300
 
 
301
    void progressRangeChanged(int min, int max)
 
302
    {
 
303
        qDebug() << "progress range" << min << max;
 
304
    }
 
305
 
 
306
};
 
307
 
 
308
void tst_QFutureWatcher::futureSignals()
 
309
{
 
310
    {
 
311
        QFutureInterface<int> a;
 
312
        QFutureWatcher<int> f;
 
313
 
 
314
        SignalSlotObject object;
 
315
#ifdef PRINT
 
316
        connect(&f, SIGNAL(finished()), &object, SLOT(finished()));
 
317
        connect(&f, SIGNAL(progressValueChanged(int)), &object, SLOT(progressValueChanged(int)));
 
318
#endif
 
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)));
 
322
        a.reportStarted();
 
323
        f.setFuture(a.future());
 
324
 
 
325
        QSignalSpy progressSpy(&f, SIGNAL(progressValueChanged(int)));
 
326
        QVERIFY(progressSpy.isValid());
 
327
        const int progress = 1;
 
328
        a.setProgressValue(progress);
 
329
        QTest::qWait(10);
 
330
        QCOMPARE(progressSpy.count(), 2);
 
331
        QCOMPARE(progressSpy.takeFirst().at(0).toInt(), 0);
 
332
        QCOMPARE(progressSpy.takeFirst().at(0).toInt(), 1);
 
333
 
 
334
        QSignalSpy finishedSpy(&f, SIGNAL(finished()));
 
335
        QSignalSpy resultReadySpy(&f, SIGNAL(resultReadyAt(int)));
 
336
 
 
337
        QVERIFY(finishedSpy.isValid());
 
338
        QVERIFY(resultReadySpy.isValid());
 
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
    QVERIFY(startedSpy.isValid());
 
383
    QVERIFY(finishedSpy.isValid());
 
384
    QVERIFY(resultReadySpy.isValid());
 
385
    QVERIFY(canceledSpy.isValid());
 
386
 
 
387
    watcher.setFuture(f);
 
388
    QTest::qWait(10);
 
389
 
 
390
    QCOMPARE(startedSpy.count(), 1);
 
391
    QCOMPARE(finishedSpy.count(), 1);
 
392
    QCOMPARE(resultReadySpy.count(), 1);
 
393
    QCOMPARE(canceledSpy.count(), 0);
 
394
}
 
395
 
 
396
void tst_QFutureWatcher::watchCanceledFuture()
 
397
{
 
398
    QFuture<int> f;
 
399
    QFutureWatcher<int> watcher;
 
400
 
 
401
    SignalSlotObject object;
 
402
#ifdef PRINT
 
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)));
 
408
#endif
 
409
    connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
 
410
 
 
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()));
 
415
 
 
416
    QVERIFY(startedSpy.isValid());
 
417
    QVERIFY(finishedSpy.isValid());
 
418
    QVERIFY(resultReadySpy.isValid());
 
419
    QVERIFY(canceledSpy.isValid());
 
420
 
 
421
    watcher.setFuture(f);
 
422
    QTest::qWait(10);
 
423
 
 
424
    QCOMPARE(startedSpy.count(), 1);
 
425
    QCOMPARE(finishedSpy.count(), 1);
 
426
    QCOMPARE(resultReadySpy.count(), 0);
 
427
    QCOMPARE(canceledSpy.count(), 1);
 
428
}
 
429
 
 
430
void tst_QFutureWatcher::disconnectRunningFuture()
 
431
{
 
432
    QFutureInterface<int> a;
 
433
    a.reportStarted();
 
434
 
 
435
    QFuture<int> f = a.future();
 
436
    QFutureWatcher<int> *watcher = new QFutureWatcher<int>();
 
437
    watcher->setFuture(f);
 
438
 
 
439
    SignalSlotObject object;
 
440
    connect(watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
 
441
 
 
442
    QSignalSpy finishedSpy(watcher, SIGNAL(finished()));
 
443
    QSignalSpy resultReadySpy(watcher, SIGNAL(resultReadyAt(int)));
 
444
 
 
445
    QVERIFY(finishedSpy.isValid());
 
446
    QVERIFY(resultReadySpy.isValid());
 
447
 
 
448
    const int result = 10;
 
449
    a.reportResult(&result);
 
450
    QTest::qWait(10);
 
451
    QCOMPARE(resultReadySpy.count(), 1);
 
452
 
 
453
    delete watcher;
 
454
 
 
455
    a.reportResult(&result);
 
456
    QTest::qWait(10);
 
457
    QCOMPARE(resultReadySpy.count(), 1);
 
458
 
 
459
    a.reportFinished(&result);
 
460
    QTest::qWait(10);
 
461
    QCOMPARE(finishedSpy.count(), 0);
 
462
}
 
463
 
 
464
const int maxProgress = 100000;
 
465
class ProgressEmitterTask : public RunFunctionTask<void>
 
466
{
 
467
public:
 
468
    void runFunctor()
 
469
    {
 
470
        setProgressRange(0, maxProgress);
 
471
        for (int p = 0; p <= maxProgress; ++p)
 
472
            setProgressValue(p);
 
473
    }
 
474
};
 
475
 
 
476
void tst_QFutureWatcher::tooMuchProgress()
 
477
{
 
478
    progressValues.clear();
 
479
    ProgressObject o;
 
480
 
 
481
    QFutureWatcher<void> f;
 
482
    QObject::connect(&f, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
 
483
#ifdef PRINT
 
484
    QObject::connect(&f, SIGNAL(progressValueChanged(int)), &o, SLOT(printProgress(int)));
 
485
#endif
 
486
    QObject::connect(&f, SIGNAL(progressValueChanged(int)), &o, SLOT(registerProgress(int)));
 
487
    f.setFuture((new ProgressEmitterTask())->start());
 
488
 
 
489
    QTestEventLoop::instance().enterLoop(5);
 
490
    QVERIFY(!QTestEventLoop::instance().timeout());
 
491
    QVERIFY(progressValues.contains(maxProgress));
 
492
}
 
493
 
 
494
template <typename T>
 
495
class ProgressTextTask : public RunFunctionTask<T>
 
496
{
 
497
public:
 
498
    void runFunctor()
 
499
    {
 
500
        this->setProgressValueAndText(1, QLatin1String("Foo 1"));
 
501
 
 
502
        while (this->isProgressUpdateNeeded() == false)
 
503
            QTest::qSleep(1);
 
504
        this->setProgressValueAndText(2, QLatin1String("Foo 2"));
 
505
 
 
506
        while (this->isProgressUpdateNeeded() == false)
 
507
            QTest::qSleep(1);
 
508
        this->setProgressValueAndText(3, QLatin1String("Foo 3"));
 
509
 
 
510
        while (this->isProgressUpdateNeeded() == false)
 
511
            QTest::qSleep(1);
 
512
        this->setProgressValueAndText(4, QLatin1String("Foo 4"));
 
513
    }
 
514
};
 
515
 
 
516
void tst_QFutureWatcher::progressText()
 
517
{
 
518
    {   // instantiate API for T=int and T=void.
 
519
        ProgressTextTask<int> a;
 
520
        ProgressTextTask<void> b;
 
521
    }
 
522
    {
 
523
        progressValues.clear();
 
524
        progressTexts.clear();
 
525
        QFuture<int> f = ((new ProgressTextTask<int>())->start());
 
526
        QFutureWatcher<int> watcher;
 
527
        ProgressObject o;
 
528
        QObject::connect(&watcher, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
 
529
#ifdef PRINT
 
530
        QObject::connect(&watcher, SIGNAL(progressValueChanged(int)), &o, SLOT(printProgress(int)));
 
531
        QObject::connect(&watcher, SIGNAL(progressTextChanged(QString)), &o, SLOT(printText(QString)));
 
532
#endif
 
533
        QObject::connect(&watcher, SIGNAL(progressValueChanged(int)), &o, SLOT(registerProgress(int)));
 
534
        QObject::connect(&watcher, SIGNAL(progressTextChanged(QString)), &o, SLOT(registerText(QString)));
 
535
 
 
536
        watcher.setFuture(f);
 
537
        QTestEventLoop::instance().enterLoop(5);
 
538
        QVERIFY(!QTestEventLoop::instance().timeout());
 
539
 
 
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")));
 
550
    }
 
551
}
 
552
 
 
553
template <typename T>
 
554
void callInterface(T &obj)
 
555
{
 
556
    obj.progressValue();
 
557
    obj.progressMinimum();
 
558
    obj.progressMaximum();
 
559
    obj.progressText();
 
560
 
 
561
    obj.isStarted();
 
562
    obj.isFinished();
 
563
    obj.isRunning();
 
564
    obj.isCanceled();
 
565
    obj.isPaused();
 
566
 
 
567
    obj.cancel();
 
568
    obj.pause();
 
569
    obj.resume();
 
570
    obj.togglePaused();
 
571
    obj.waitForFinished();
 
572
 
 
573
    const T& objConst = obj;
 
574
    objConst.progressValue();
 
575
    objConst.progressMinimum();
 
576
    objConst.progressMaximum();
 
577
    objConst.progressText();
 
578
 
 
579
    objConst.isStarted();
 
580
    objConst.isFinished();
 
581
    objConst.isRunning();
 
582
    objConst.isCanceled();
 
583
    objConst.isPaused();
 
584
}
 
585
 
 
586
template <typename T>
 
587
void callInterface(const T &obj)
 
588
{
 
589
    obj.result();
 
590
    obj.resultAt(0);
 
591
}
 
592
 
 
593
 
 
594
// QFutureWatcher and QFuture has a similar interface. Test
 
595
// that the functions we want ot have in both are actually
 
596
// there.
 
597
void tst_QFutureWatcher::sharedFutureInterface()
 
598
{
 
599
    QFutureInterface<int> iface;
 
600
    iface.reportStarted();
 
601
 
 
602
    QFuture<int> intFuture = iface.future();
 
603
 
 
604
    int value = 0;
 
605
    iface.reportFinished(&value);
 
606
 
 
607
    QFuture<void> voidFuture;
 
608
    QFutureWatcher<int> intWatcher;
 
609
    intWatcher.setFuture(intFuture);
 
610
    QFutureWatcher<void> voidWatcher;
 
611
 
 
612
    callInterface(intFuture);
 
613
    callInterface(voidFuture);
 
614
    callInterface(intWatcher);
 
615
    callInterface(voidWatcher);
 
616
 
 
617
    callInterface(intFuture);
 
618
    callInterface(intWatcher);
 
619
}
 
620
 
 
621
void tst_QFutureWatcher::changeFuture()
 
622
{
 
623
    QFutureInterface<int> iface;
 
624
    iface.reportStarted();
 
625
 
 
626
    QFuture<int> a = iface.future();
 
627
 
 
628
    int value = 0;
 
629
    iface.reportFinished(&value);
 
630
 
 
631
    QFuture<int> b;
 
632
 
 
633
    QFutureWatcher<int> watcher;
 
634
 
 
635
    SignalSlotObject object;
 
636
    connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
 
637
    QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int)));
 
638
    QVERIFY(resultReadySpy.isValid());
 
639
 
 
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.
 
643
 
 
644
    QCOMPARE(resultReadySpy.count(), 0);
 
645
 
 
646
    watcher.setFuture(a);
 
647
    watcher.setFuture(b);
 
648
    watcher.setFuture(a); // setting it back gets us one event, not two.
 
649
    QTest::qWait(10);
 
650
 
 
651
    QCOMPARE(resultReadySpy.count(), 1);
 
652
}
 
653
 
 
654
// Test that events aren't delivered from canceled futures
 
655
void tst_QFutureWatcher::cancelEvents()
 
656
{
 
657
    QFutureInterface<int> iface;
 
658
    iface.reportStarted();
 
659
 
 
660
    QFuture<int> a = iface.future();
 
661
 
 
662
    int value = 0;
 
663
    iface.reportFinished(&value);
 
664
 
 
665
    QFutureWatcher<int> watcher;
 
666
 
 
667
    SignalSlotObject object;
 
668
    connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
 
669
    QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int)));
 
670
    QVERIFY(resultReadySpy.isValid());
 
671
 
 
672
    watcher.setFuture(a);
 
673
    watcher.cancel();
 
674
 
 
675
    QTest::qWait(10);
 
676
 
 
677
    QCOMPARE(resultReadySpy.count(), 0);
 
678
}
 
679
 
 
680
// Tests that events from paused futures are saved and
 
681
// delivered on resume.
 
682
void tst_QFutureWatcher::pauseEvents()
 
683
{
 
684
    {
 
685
        QFutureInterface<int> iface;
 
686
        iface.reportStarted();
 
687
 
 
688
        QFuture<int> a = iface.future();
 
689
 
 
690
        int value = 0;
 
691
        iface.reportFinished(&value);
 
692
 
 
693
        QFutureWatcher<int> watcher;
 
694
 
 
695
        SignalSlotObject object;
 
696
        connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
 
697
        QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int)));
 
698
        QVERIFY(resultReadySpy.isValid());
 
699
 
 
700
        watcher.setFuture(a);
 
701
        watcher.pause();
 
702
 
 
703
        QTest::qWait(10);
 
704
        QCOMPARE(resultReadySpy.count(), 0);
 
705
 
 
706
        watcher.resume();
 
707
        QTest::qWait(10);
 
708
        QCOMPARE(resultReadySpy.count(), 1);
 
709
    }
 
710
    {
 
711
        QFutureInterface<int> iface;
 
712
        iface.reportStarted();
 
713
 
 
714
        QFuture<int> a = iface.future();
 
715
 
 
716
        int value = 0;
 
717
        iface.reportFinished(&value);
 
718
 
 
719
        QFutureWatcher<int> watcher;
 
720
 
 
721
        SignalSlotObject object;
 
722
        connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int)));
 
723
        QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int)));
 
724
        QVERIFY(resultReadySpy.isValid());
 
725
 
 
726
        watcher.setFuture(a);
 
727
        a.pause();
 
728
 
 
729
        QFuture<int> b;
 
730
        watcher.setFuture(b); // If we watch b instead, resuming a
 
731
        a.resume();           // should give us no results.
 
732
 
 
733
        QTest::qWait(10);
 
734
        QCOMPARE(resultReadySpy.count(), 0);
 
735
    }
 
736
}
 
737
 
 
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()
 
743
{
 
744
    QFutureInterface<int> iface;
 
745
    iface.reportStarted();
 
746
    QFuture<int> future = iface.future();
 
747
    QFutureWatcher<int> watcher;
 
748
 
 
749
    watcher.setFuture(future);
 
750
    QTest::qWait(10);
 
751
 
 
752
    iface.reportFinished();
 
753
    QVERIFY(future.isFinished());
 
754
    QVERIFY(watcher.isFinished() == false);
 
755
 
 
756
    QTest::qWait(10);
 
757
    QVERIFY(watcher.isFinished());
 
758
}
 
759
 
 
760
/*
 
761
    Verify that throttling kicks in if you report a lot of results,
 
762
    and that it clears when the result events are processed.
 
763
*/
 
764
void tst_QFutureWatcher::throttling()
 
765
{
 
766
    QFutureInterface<int> iface;
 
767
    iface.reportStarted();
 
768
    QFuture<int> future = iface.future();
 
769
    QFutureWatcher<int> watcher;
 
770
    watcher.setFuture(future);
 
771
 
 
772
    QVERIFY(iface.isThrottled() == false);
 
773
 
 
774
    for (int i = 0; i < 1000; ++i) {
 
775
        int result = 0;
 
776
        iface.reportResult(result);
 
777
    }
 
778
 
 
779
    QVERIFY(iface.isThrottled() == true);
 
780
 
 
781
    QTest::qWait(100); // process events.
 
782
 
 
783
    QVERIFY(iface.isThrottled() == false);
 
784
 
 
785
    iface.reportFinished();
 
786
}
 
787
 
 
788
int mapper(const int &i)
 
789
{
 
790
    return i;
 
791
}
 
792
 
 
793
class ResultReadyTester : public QObject
 
794
{
 
795
Q_OBJECT
 
796
public:
 
797
    ResultReadyTester(QFutureWatcher<int> *watcher)
 
798
    :m_watcher(watcher), filter(false), ok(true), count(0)
 
799
    {
 
800
        
 
801
    }
 
802
public slots:
 
803
    void resultReadyAt(int index)
 
804
    {
 
805
        ++count;
 
806
        if (m_watcher->future().isResultReadyAt(index) == false)
 
807
            ok = false;
 
808
        if (!filter && m_watcher->future().resultAt(index) != index)
 
809
            ok = false;
 
810
        if (filter && m_watcher->future().resultAt(index) != index * 2 + 1)
 
811
            ok = false;
 
812
    }
 
813
public:
 
814
    QFutureWatcher<int> *m_watcher;
 
815
    bool filter;
 
816
    bool ok;
 
817
    int count;
 
818
};
 
819
 
 
820
void tst_QFutureWatcher::incrementalMapResults()
 
821
{
 
822
    QFutureWatcher<int> watcher;
 
823
 
 
824
    SignalSlotObject object;
 
825
#ifdef PRINT
 
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)));
 
829
#endif
 
830
 
 
831
    QObject::connect(&watcher, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
 
832
 
 
833
    ResultReadyTester resultReadyTester(&watcher);
 
834
    connect(&watcher, SIGNAL(resultReadyAt(int)), &resultReadyTester, SLOT(resultReadyAt(int)));
 
835
 
 
836
    const int count = 10000;
 
837
    QList<int> ints; 
 
838
    for (int i = 0; i < count; ++i)
 
839
        ints << i;
 
840
 
 
841
    QFuture<int> future = QtConcurrent::mapped(ints, mapper);
 
842
    watcher.setFuture(future);
 
843
 
 
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(); 
 
850
}
 
851
 
 
852
bool filterer(int i)
 
853
{
 
854
    return (i % 2);
 
855
}
 
856
 
 
857
void tst_QFutureWatcher::incrementalFilterResults()
 
858
{
 
859
    QFutureWatcher<int> watcher;
 
860
 
 
861
    SignalSlotObject object;
 
862
#ifdef PRINT
 
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)));
 
866
#endif
 
867
 
 
868
    QObject::connect(&watcher, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
 
869
 
 
870
 
 
871
    ResultReadyTester resultReadyTester(&watcher);
 
872
    resultReadyTester.filter = true;
 
873
    connect(&watcher, SIGNAL(resultReadyAt(int)), &resultReadyTester, SLOT(resultReadyAt(int)));
 
874
 
 
875
    const int count = 10000;
 
876
    QList<int> ints; 
 
877
    for (int i = 0; i < count; ++i)
 
878
        ints << i;
 
879
 
 
880
    QFuture<int> future = QtConcurrent::filtered(ints, filterer);
 
881
    watcher.setFuture(future);
 
882
 
 
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(); 
 
889
}
 
890
 
 
891
void tst_QFutureWatcher::qfutureSynchronizer()
 
892
{
 
893
    int taskCount = 1000; 
 
894
    QTime t;
 
895
    t.start();
 
896
 
 
897
    {
 
898
        QFutureSynchronizer<void> sync;
 
899
 
 
900
        sync.setCancelOnWait(true);
 
901
        for (int i = 0; i < taskCount; ++i) {
 
902
            sync.addFuture(run(sleeper));
 
903
        }
 
904
    }
 
905
 
 
906
    // Test that we're not running each task.
 
907
    QVERIFY(t.elapsed() < taskCount * 10);
 
908
}
 
909
 
 
910
class DummyObject : public QObject {
 
911
    Q_OBJECT
 
912
public slots:
 
913
    void dummySlot() {}
 
914
public:
 
915
    static void function(QMutex *m)
 
916
    {
 
917
        QMutexLocker lock(m);
 
918
    }
 
919
};
 
920
 
 
921
void tst_QFutureWatcher::warnRace()
 
922
{
 
923
#ifndef Q_OS_MAC //I don't know why it is not working on mac
 
924
#ifndef QT_NO_DEBUG
 
925
    QTest::ignoreMessage(QtWarningMsg, "QFutureWatcher::connect: connecting after calling setFuture() is likely to produce race");
 
926
#endif
 
927
#endif
 
928
    QFutureWatcher<void> watcher;
 
929
    DummyObject object;
 
930
    QMutex mutex;
 
931
    mutex.lock();
 
932
 
 
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()));
 
937
    mutex.unlock();
 
938
    future.waitForFinished();
 
939
}
 
940
 
 
941
QTEST_MAIN(tst_QFutureWatcher)
 
942
#include "tst_qfuturewatcher.moc"