1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
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 The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28#include <QCoreApplication>
29#include <QDebug>
30
31#define QFUTURE_TEST
32
33#include <QtTest/QtTest>
34#include <qfuture.h>
35#include <qfuturewatcher.h>
36#include <qresultstore.h>
37#include <qthreadpool.h>
38#include <qexception.h>
39#include <qrandom.h>
40#include <private/qfutureinterface_p.h>
41
42// COM interface macro.
43#if defined(Q_OS_WIN) && defined(interface)
44# undef interface
45#endif
46
47struct ResultStoreInt : QtPrivate::ResultStoreBase
48{
49 ~ResultStoreInt() { clear<int>(); }
50};
51
52class LambdaThread : public QThread
53{
54public:
55 LambdaThread(std::function<void ()> fn)
56 :m_fn(fn)
57 {
58
59 }
60
61 void run() override
62 {
63 m_fn();
64 }
65
66private:
67 std::function<void ()> m_fn;
68};
69
70class tst_QFuture: public QObject
71{
72 Q_OBJECT
73private slots:
74 void resultStore();
75 void future();
76 void futureInterface();
77 void refcounting();
78 void cancel();
79 void statePropagation();
80 void multipleResults();
81 void indexedResults();
82 void progress();
83 void progressText();
84 void resultsAfterFinished();
85 void resultsAsList();
86 void implicitConversions();
87 void iterators();
88 void iteratorsThread();
89 void pause();
90 void throttling();
91 void voidConversions();
92#ifndef QT_NO_EXCEPTIONS
93 void exceptions();
94 void nestedExceptions();
95#endif
96 void nonGlobalThreadPool();
97 void resultsReadyAt();
98};
99
100void tst_QFuture::resultStore()
101{
102 int int0 = 0;
103 int int1 = 1;
104 int int2 = 2;
105
106 {
107 ResultStoreInt store;
108 QCOMPARE(store.begin(), store.end());
109 QCOMPARE(store.resultAt(0), store.end());
110 QCOMPARE(store.resultAt(1), store.end());
111 }
112
113
114 {
115 ResultStoreInt store;
116 store.addResult(index: -1, result: &int0);
117 store.addResult(index: 1, result: &int1);
118 QtPrivate::ResultIteratorBase it = store.begin();
119 QCOMPARE(it.resultIndex(), 0);
120 QVERIFY(it == store.begin());
121 QVERIFY(it != store.end());
122
123 ++it;
124 QCOMPARE(it.resultIndex(), 1);
125 QVERIFY(it != store.begin());
126 QVERIFY(it != store.end());
127
128 ++it;
129 QVERIFY(it != store.begin());
130 QVERIFY(it == store.end());
131 }
132
133 QVector<int> vec0 = QVector<int>() << 2 << 3;
134 QVector<int> vec1 = QVector<int>() << 4 << 5;
135
136 {
137 ResultStoreInt store;
138 store.addResults(index: -1, results: &vec0, totalCount: 2);
139 store.addResults(index: -1, results: &vec1, totalCount: 2);
140 QtPrivate::ResultIteratorBase it = store.begin();
141 QCOMPARE(it.resultIndex(), 0);
142 QCOMPARE(it, store.begin());
143 QVERIFY(it != store.end());
144
145 ++it;
146 QCOMPARE(it.resultIndex(), 1);
147 QVERIFY(it != store.begin());
148 QVERIFY(it != store.end());
149
150 ++it;
151 QCOMPARE(it.resultIndex(), 2);
152
153 ++it;
154 QCOMPARE(it.resultIndex(), 3);
155
156 ++it;
157 QCOMPARE(it, store.end());
158 }
159 {
160 ResultStoreInt store;
161 store.addResult(index: -1, result: &int0);
162 store.addResults(index: -1, results: &vec1, totalCount: 2);
163 store.addResult(index: -1, result: &int1);
164
165 QtPrivate::ResultIteratorBase it = store.begin();
166 QCOMPARE(it.resultIndex(), 0);
167 QVERIFY(it == store.begin());
168 QVERIFY(it != store.end());
169
170 ++it;
171 QCOMPARE(it.resultIndex(), 1);
172 QVERIFY(it != store.begin());
173 QVERIFY(it != store.end());
174
175 ++it;
176 QCOMPARE(it.resultIndex(), 2);
177 QVERIFY(it != store.end());
178 ++it;
179 QCOMPARE(it.resultIndex(), 3);
180 QVERIFY(it != store.end());
181 ++it;
182 QVERIFY(it == store.end());
183
184 QCOMPARE(store.resultAt(0).resultIndex(), 0);
185 QCOMPARE(store.resultAt(1).resultIndex(), 1);
186 QCOMPARE(store.resultAt(2).resultIndex(), 2);
187 QCOMPARE(store.resultAt(3).resultIndex(), 3);
188 QCOMPARE(store.resultAt(4), store.end());
189 }
190 {
191 ResultStoreInt store;
192 store.addResult(index: -1, result: &int0);
193 store.addResults(index: -1, results: &vec0);
194 store.addResult(index: -1, result: &int1);
195
196 QtPrivate::ResultIteratorBase it = store.begin();
197 QCOMPARE(it.resultIndex(), 0);
198 QVERIFY(it == store.begin());
199 QVERIFY(it != store.end());
200
201 ++it;
202 QCOMPARE(it.resultIndex(), 1);
203 QVERIFY(it != store.begin());
204 QVERIFY(it != store.end());
205
206 ++it;
207 QCOMPARE(it.resultIndex(), 2);
208 QVERIFY(it != store.end());
209 ++it;
210 QCOMPARE(it.resultIndex(), 3);
211 QVERIFY(it != store.end());
212 ++it;
213 QVERIFY(it == store.end());
214
215 QCOMPARE(store.resultAt(0).value<int>(), int0);
216 QCOMPARE(store.resultAt(1).value<int>(), vec0[0]);
217 QCOMPARE(store.resultAt(2).value<int>(), vec0[1]);
218 QCOMPARE(store.resultAt(3).value<int>(), int1);
219 }
220 {
221 ResultStoreInt store;
222 store.addResult(index: -1, result: &int0);
223 store.addResults(index: -1, results: &vec0);
224 store.addResult(index: 200, result: &int1);
225
226 QCOMPARE(store.resultAt(0).value<int>(), int0);
227 QCOMPARE(store.resultAt(1).value<int>(), vec0[0]);
228 QCOMPARE(store.resultAt(2).value<int>(), vec0[1]);
229 QCOMPARE(store.resultAt(200).value<int>(), int1);
230 }
231
232 {
233 ResultStoreInt store;
234 store.addResult(index: 1, result: &int1);
235 store.addResult(index: 0, result: &int0);
236 store.addResult(index: -1, result: &int2);
237
238 QCOMPARE(store.resultAt(0).value<int>(), int0);
239 QCOMPARE(store.resultAt(1).value<int>(), int1);
240 QCOMPARE(store.resultAt(2).value<int>(), int2);
241 }
242
243 {
244 ResultStoreInt store;
245 QCOMPARE(store.contains(0), false);
246 QCOMPARE(store.contains(1), false);
247 QCOMPARE(store.contains(INT_MAX), false);
248 }
249
250 {
251 // Test filter mode, where "gaps" in the result array aren't allowed.
252 ResultStoreInt store;
253 store.setFilterMode(true);
254
255 store.addResult(index: 0, result: &int0);
256 QCOMPARE(store.contains(0), true);
257
258 store.addResult(index: 2, result: &int2); // add result at index 2
259 QCOMPARE(store.contains(2), false); // but 1 is missing, so this 2 won't be reported yet.
260
261 store.addResult(index: 1, result: &int1);
262 QCOMPARE(store.contains(1), true);
263 QCOMPARE(store.contains(2), true); // 2 should be visible now.
264
265 store.addResult(index: 4, result: &int0);
266 store.addResult(index: 5, result: &int0);
267 store.addResult(index: 7, result: &int0);
268 QCOMPARE(store.contains(4), false);
269 QCOMPARE(store.contains(5), false);
270 QCOMPARE(store.contains(7), false);
271
272 store.addResult(index: 3, result: &int0); // adding 3 makes 4 and 5 visible
273 QCOMPARE(store.contains(4), true);
274 QCOMPARE(store.contains(5), true);
275 QCOMPARE(store.contains(7), false);
276
277 store.addResult(index: 6, result: &int0); // adding 6 makes 7 visible
278
279 QCOMPARE(store.contains(6), true);
280 QCOMPARE(store.contains(7), true);
281 QCOMPARE(store.contains(8), false);
282 }
283
284 {
285 // test canceled results
286 ResultStoreInt store;
287 store.setFilterMode(true);
288
289 store.addResult(index: 0, result: &int0);
290 QCOMPARE(store.contains(0), true);
291
292 store.addResult(index: 2, result: &int0);
293 QCOMPARE(store.contains(2), false);
294
295 store.addCanceledResult(index: 1); // report no result at 1
296
297 QCOMPARE(store.contains(0), true);
298 QCOMPARE(store.contains(1), true); // 2 gets renamed to 1
299 QCOMPARE(store.contains(2), false);
300
301 store.addResult(index: 3, result: &int0);
302 QCOMPARE(store.contains(2), true); //3 gets renamed to 2
303
304 store.addResult(index: 6, result: &int0);
305 store.addResult(index: 7, result: &int0);
306 QCOMPARE(store.contains(3), false);
307
308 store.addCanceledResult(index: 4);
309 store.addCanceledResult(index: 5);
310
311 QCOMPARE(store.contains(3), true); //6 gets renamed to 3
312 QCOMPARE(store.contains(4), true); //7 gets renamed to 4
313
314 store.addResult(index: 8, result: &int0);
315 QCOMPARE(store.contains(5), true); //8 gets renamed to 4
316
317 QCOMPARE(store.contains(6), false);
318 QCOMPARE(store.contains(7), false);
319 }
320
321 {
322 // test addResult return value
323 ResultStoreInt store;
324 store.setFilterMode(true);
325
326 store.addResult(index: 0, result: &int0);
327 QCOMPARE(store.count(), 1); // result 0 becomes available
328 QCOMPARE(store.contains(0), true);
329
330 store.addResult(index: 2, result: &int0);
331 QCOMPARE(store.count(), 1);
332 QCOMPARE(store.contains(2), false);
333
334 store.addCanceledResult(index: 1);
335 QCOMPARE(store.count(), 2); // result 2 is renamed to 1 and becomes available
336
337 QCOMPARE(store.contains(0), true);
338 QCOMPARE(store.contains(1), true);
339 QCOMPARE(store.contains(2), false);
340
341 store.addResult(index: 3, result: &int0);
342 QCOMPARE(store.count(), 3);
343 QCOMPARE(store.contains(2), true);
344
345 store.addResult(index: 6, result: &int0);
346 QCOMPARE(store.count(), 3);
347 store.addResult(index: 7, result: &int0);
348 QCOMPARE(store.count(), 3);
349 QCOMPARE(store.contains(3), false);
350
351 store.addCanceledResult(index: 4);
352 store.addCanceledResult(index: 5);
353 QCOMPARE(store.count(), 5); // 6 and 7 is renamed to 3 and 4 and becomes available
354
355 QCOMPARE(store.contains(3), true);
356 QCOMPARE(store.contains(4), true);
357
358 store.addResult(index: 8, result: &int0);
359 QCOMPARE(store.contains(5), true);
360 QCOMPARE(store.count(), 6);
361
362 QCOMPARE(store.contains(6), false);
363 QCOMPARE(store.contains(7), false);
364 }
365
366 {
367 // test resultCount in non-filtered mode. It should always be possible
368 // to iterate through the results 0 to resultCount.
369 ResultStoreInt store;
370 store.addResult(index: 0, result: &int0);
371
372 QCOMPARE(store.count(), 1);
373
374 store.addResult(index: 2, result: &int0);
375
376 QCOMPARE(store.count(), 1);
377
378 store.addResult(index: 1, result: &int0);
379 QCOMPARE(store.count(), 3);
380 }
381
382 {
383 ResultStoreInt store;
384 store.addResult(index: 2, result: &int0);
385 QCOMPARE(store.count(), 0);
386
387 store.addResult(index: 1, result: &int0);
388 QCOMPARE(store.count(), 0);
389
390 store.addResult(index: 0, result: &int0);
391 QCOMPARE(store.count(), 3);
392 }
393
394 {
395 ResultStoreInt store;
396 store.addResults(index: 2, results: &vec1);
397 QCOMPARE(store.count(), 0);
398
399 store.addResult(index: 1, result: &int0);
400 QCOMPARE(store.count(), 0);
401
402 store.addResult(index: 0, result: &int0);
403 QCOMPARE(store.count(), 4);
404 }
405
406 {
407 ResultStoreInt store;
408 store.addResults(index: 2, results: &vec1);
409 QCOMPARE(store.count(), 0);
410
411 store.addResults(index: 0, results: &vec0);
412 QCOMPARE(store.count(), 4);
413 }
414 {
415 ResultStoreInt store;
416 store.addResults(index: 3, results: &vec1);
417 QCOMPARE(store.count(), 0);
418
419 store.addResults(index: 0, results: &vec0);
420 QCOMPARE(store.count(), 2);
421
422 store.addResult(index: 2, result: &int0);
423 QCOMPARE(store.count(), 5);
424 }
425
426 {
427 ResultStoreInt store;
428 store.setFilterMode(true);
429 store.addResults(index: 3, results: &vec1);
430 QCOMPARE(store.count(), 0);
431
432 store.addResults(index: 0, results: &vec0);
433 QCOMPARE(store.count(), 2);
434
435 store.addCanceledResult(index: 2);
436 QCOMPARE(store.count(), 4);
437 }
438
439 {
440 ResultStoreInt store;
441 store.setFilterMode(true);
442 store.addResults(index: 3, results: &vec1);
443 QCOMPARE(store.count(), 0);
444
445 store.addCanceledResults<int>(index: 0, count: 3);
446 QCOMPARE(store.count(), 2);
447 }
448
449 {
450 ResultStoreInt store;
451 store.setFilterMode(true);
452 store.addResults(index: 3, results: &vec1);
453 QCOMPARE(store.count(), 0);
454
455 store.addCanceledResults<int>(index: 0, count: 3);
456 QCOMPARE(store.count(), 2); // results at 3 and 4 become available at index 0, 1
457
458 store.addResult(index: 5, result: &int0);
459 QCOMPARE(store.count(), 3);// result 5 becomes available at index 2
460 }
461
462 {
463 ResultStoreInt store;
464 store.addResult(index: 1, result: &int0);
465 store.addResult(index: 3, result: &int0);
466 store.addResults(index: 6, results: &vec0);
467 QCOMPARE(store.contains(0), false);
468 QCOMPARE(store.contains(1), true);
469 QCOMPARE(store.contains(2), false);
470 QCOMPARE(store.contains(3), true);
471 QCOMPARE(store.contains(4), false);
472 QCOMPARE(store.contains(5), false);
473 QCOMPARE(store.contains(6), true);
474 QCOMPARE(store.contains(7), true);
475 }
476
477 {
478 ResultStoreInt store;
479 store.setFilterMode(true);
480 store.addResult(index: 1, result: &int0);
481 store.addResult(index: 3, result: &int0);
482 store.addResults(index: 6, results: &vec0);
483 QCOMPARE(store.contains(0), false);
484 QCOMPARE(store.contains(1), false);
485 QCOMPARE(store.contains(2), false);
486 QCOMPARE(store.contains(3), false);
487 QCOMPARE(store.contains(4), false);
488 QCOMPARE(store.contains(5), false);
489 QCOMPARE(store.contains(6), false);
490 QCOMPARE(store.contains(7), false);
491
492 store.addCanceledResult(index: 0);
493 store.addCanceledResult(index: 2);
494 store.addCanceledResults<int>(index: 4, count: 2);
495
496 QCOMPARE(store.contains(0), true);
497 QCOMPARE(store.contains(1), true);
498 QCOMPARE(store.contains(2), true);
499 QCOMPARE(store.contains(3), true);
500 QCOMPARE(store.contains(4), false);
501 QCOMPARE(store.contains(5), false);
502 QCOMPARE(store.contains(6), false);
503 QCOMPARE(store.contains(7), false);
504 }
505 {
506 ResultStoreInt store;
507 store.setFilterMode(true);
508 store.addCanceledResult(index: 0);
509 QCOMPARE(store.contains(0), false);
510
511 store.addResult(index: 1, result: &int0);
512 QCOMPARE(store.contains(0), true);
513 QCOMPARE(store.contains(1), false);
514 }
515}
516
517void tst_QFuture::future()
518{
519 // default constructors
520 QFuture<int> intFuture;
521 intFuture.waitForFinished();
522 QFuture<QString> stringFuture;
523 stringFuture.waitForFinished();
524 QFuture<void> voidFuture;
525 voidFuture.waitForFinished();
526 QFuture<void> defaultVoidFuture;
527 defaultVoidFuture.waitForFinished();
528
529 // copy constructor
530 QFuture<int> intFuture2(intFuture);
531 QFuture<void> voidFuture2(defaultVoidFuture);
532
533 // assigmnent operator
534 intFuture2 = QFuture<int>();
535 voidFuture2 = QFuture<void>();
536
537 // state
538 QCOMPARE(intFuture2.isStarted(), true);
539 QCOMPARE(intFuture2.isFinished(), true);
540}
541
542class IntResult : public QFutureInterface<int>
543{
544public:
545 QFuture<int> run()
546 {
547 this->reportStarted();
548 QFuture<int> future = QFuture<int>(this);
549
550 int res = 10;
551 reportFinished(result: &res);
552 return future;
553 }
554};
555
556int value = 10;
557
558class VoidResult : public QFutureInterfaceBase
559{
560public:
561 QFuture<void> run()
562 {
563 this->reportStarted();
564 QFuture<void> future = QFuture<void>(this);
565 reportFinished();
566 return future;
567 }
568};
569
570void tst_QFuture::futureInterface()
571{
572 {
573 QFuture<void> future;
574 {
575 QFutureInterface<void> i;
576 i.reportStarted();
577 future = i.future();
578 i.reportFinished();
579 }
580 }
581 {
582 QFuture<int> future;
583 {
584 QFutureInterface<int> i;
585 i.reportStarted();
586 i.reportResult(result: 10);
587 future = i.future();
588 i.reportFinished();
589 }
590 QCOMPARE(future.resultAt(0), 10);
591 }
592
593 {
594 QFuture<int> intFuture;
595
596 QCOMPARE(intFuture.isStarted(), true);
597 QCOMPARE(intFuture.isFinished(), true);
598
599 IntResult result;
600
601 result.reportStarted();
602 intFuture = result.future();
603
604 QCOMPARE(intFuture.isStarted(), true);
605 QCOMPARE(intFuture.isFinished(), false);
606
607 result.reportFinished(result: &value);
608
609 QCOMPARE(intFuture.isStarted(), true);
610 QCOMPARE(intFuture.isFinished(), true);
611
612 int e = intFuture.result();
613
614 QCOMPARE(intFuture.isStarted(), true);
615 QCOMPARE(intFuture.isFinished(), true);
616 QCOMPARE(intFuture.isCanceled(), false);
617
618 QCOMPARE(e, value);
619 intFuture.waitForFinished();
620
621 IntResult intAlgo;
622 intFuture = intAlgo.run();
623 QFuture<int> intFuture2(intFuture);
624 QCOMPARE(intFuture.result(), value);
625 QCOMPARE(intFuture2.result(), value);
626 intFuture.waitForFinished();
627
628 VoidResult a;
629 a.run().waitForFinished();
630 }
631
632 {
633 QFutureInterface<int> fi;
634 fi.reportStarted();
635 fi.reportResults(results: QVector<int> {});
636 fi.reportFinished();
637
638 QVERIFY(fi.results().empty());
639 }
640
641 {
642 QFutureInterface<int> fi;
643 fi.reportStarted();
644 QVector<int> values = { 1, 2, 3 };
645 fi.reportResults(results: values);
646 fi.reportResults(results: QVector<int> {});
647 fi.reportFinished();
648
649 QCOMPARE(fi.results(), values.toList());
650 }
651}
652
653template <typename T>
654void testRefCounting()
655{
656 QFutureInterface<T> interface;
657 QCOMPARE(interface.d->refCount.load(), 1);
658
659 {
660 interface.reportStarted();
661
662 QFuture<T> f = interface.future();
663 QCOMPARE(interface.d->refCount.load(), 2);
664
665 QFuture<T> f2(f);
666 QCOMPARE(interface.d->refCount.load(), 3);
667
668 QFuture<T> f3;
669 f3 = f2;
670 QCOMPARE(interface.d->refCount.load(), 4);
671
672 interface.reportFinished(0);
673 QCOMPARE(interface.d->refCount.load(), 4);
674 }
675
676 QCOMPARE(interface.d->refCount.load(), 1);
677}
678
679void tst_QFuture::refcounting()
680{
681 testRefCounting<int>();
682}
683
684void tst_QFuture::cancel()
685{
686 {
687 QFuture<void> f;
688 QFutureInterface<void> result;
689
690 result.reportStarted();
691 f = result.future();
692 QVERIFY(!f.isCanceled());
693 result.reportCanceled();
694 QVERIFY(f.isCanceled());
695 result.reportFinished();
696 QVERIFY(f.isCanceled());
697 f.waitForFinished();
698 QVERIFY(f.isCanceled());
699 }
700
701 // Cancel from the QFuture side and test if the result
702 // interface detects it.
703 {
704 QFutureInterface<void> result;
705
706 QFuture<void> f;
707 QVERIFY(f.isStarted());
708
709 result.reportStarted();
710 f = result.future();
711
712 QVERIFY(f.isStarted());
713
714 QVERIFY(!result.isCanceled());
715 f.cancel();
716
717 QVERIFY(result.isCanceled());
718
719 result.reportFinished();
720 }
721
722 // Test that finished futures can be canceled.
723 {
724 QFutureInterface<void> result;
725
726 QFuture<void> f;
727 QVERIFY(f.isStarted());
728
729 result.reportStarted();
730 f = result.future();
731
732 QVERIFY(f.isStarted());
733
734 result.reportFinished();
735
736 f.cancel();
737
738 QVERIFY(result.isCanceled());
739 QVERIFY(f.isCanceled());
740 }
741
742 // Results reported after canceled is called should not be propagated.
743 {
744
745 QFutureInterface<int> futureInterface;
746 futureInterface.reportStarted();
747 QFuture<int> f = futureInterface.future();
748
749 int result = 0;
750 futureInterface.reportResult(result: &result);
751 result = 1;
752 futureInterface.reportResult(result: &result);
753 f.cancel();
754 result = 2;
755 futureInterface.reportResult(result: &result);
756 result = 3;
757 futureInterface.reportResult(result: &result);
758 futureInterface.reportFinished();
759 QVERIFY(f.results().isEmpty());
760 }
761}
762
763void tst_QFuture::statePropagation()
764{
765 QFuture<void> f1;
766 QFuture<void> f2;
767
768 QCOMPARE(f1.isStarted(), true);
769
770 QFutureInterface<void> result;
771 result.reportStarted();
772 f1 = result.future();
773
774 f2 = f1;
775
776 QCOMPARE(f2.isStarted(), true);
777
778 result.reportCanceled();
779
780 QCOMPARE(f2.isStarted(), true);
781 QCOMPARE(f2.isCanceled(), true);
782
783 QFuture<void> f3 = f2;
784
785 QCOMPARE(f3.isStarted(), true);
786 QCOMPARE(f3.isCanceled(), true);
787
788 result.reportFinished();
789
790 QCOMPARE(f2.isStarted(), true);
791 QCOMPARE(f2.isCanceled(), true);
792
793 QCOMPARE(f3.isStarted(), true);
794 QCOMPARE(f3.isCanceled(), true);
795}
796
797/*
798 Tests that a QFuture can return multiple results.
799*/
800void tst_QFuture::multipleResults()
801{
802 IntResult a;
803 a.reportStarted();
804 QFuture<int> f = a.future();
805
806 QFuture<int> copy = f;
807 int result;
808
809 result = 1;
810 a.reportResult(result: &result);
811 QCOMPARE(f.resultAt(0), 1);
812
813 result = 2;
814 a.reportResult(result: &result);
815 QCOMPARE(f.resultAt(1), 2);
816
817 result = 3;
818 a.reportResult(result: &result);
819
820 result = 4;
821 a.reportFinished(result: &result);
822
823 QCOMPARE(f.results(), QList<int>() << 1 << 2 << 3 << 4);
824
825 // test foreach
826 QList<int> fasit = QList<int>() << 1 << 2 << 3 << 4;
827 {
828 QList<int> results;
829 foreach(int result, f)
830 results.append(t: result);
831 QCOMPARE(results, fasit);
832 }
833 {
834 QList<int> results;
835 foreach(int result, copy)
836 results.append(t: result);
837 QCOMPARE(results, fasit);
838 }
839}
840
841/*
842 Test out-of-order result reporting using indexes
843*/
844void tst_QFuture::indexedResults()
845{
846 {
847 QFutureInterface<QChar> Interface;
848 QFuture<QChar> f;
849 QVERIFY(f.isStarted());
850
851 Interface.reportStarted();
852 f = Interface.future();
853
854 QVERIFY(f.isStarted());
855
856 QChar result;
857
858 result = 'B';
859 Interface.reportResult(result: &result, index: 1);
860
861 QCOMPARE(f.resultAt(1), result);
862
863 result = 'A';
864 Interface.reportResult(result: &result, index: 0);
865 QCOMPARE(f.resultAt(0), result);
866
867 result = 'C';
868 Interface.reportResult(result: &result); // no index
869 QCOMPARE(f.resultAt(2), result);
870
871 Interface.reportFinished();
872
873 QCOMPARE(f.results(), QList<QChar>() << 'A' << 'B' << 'C');
874 }
875
876 {
877 // Test result reporting with a missing result in the middle
878 QFutureInterface<int> Interface;
879 Interface.reportStarted();
880 QFuture<int> f = Interface.future();
881 int result;
882
883 result = 0;
884 Interface.reportResult(result: &result, index: 0);
885 QVERIFY(f.isResultReadyAt(0));
886 QCOMPARE(f.resultAt(0), 0);
887
888 result = 3;
889 Interface.reportResult(result: &result, index: 3);
890 QVERIFY(f.isResultReadyAt(3));
891 QCOMPARE(f.resultAt(3), 3);
892
893 result = 2;
894 Interface.reportResult(result: &result, index: 2);
895 QVERIFY(f.isResultReadyAt(2));
896 QCOMPARE(f.resultAt(2), 2);
897
898 result = 4;
899 Interface.reportResult(result: &result); // no index
900 QVERIFY(f.isResultReadyAt(4));
901 QCOMPARE(f.resultAt(4), 4);
902
903 Interface.reportFinished();
904
905 QCOMPARE(f.results(), QList<int>() << 0 << 2 << 3 << 4);
906 }
907}
908
909void tst_QFuture::progress()
910{
911 QFutureInterface<QChar> result;
912 QFuture<QChar> f;
913
914 QCOMPARE (f.progressValue(), 0);
915
916 result.reportStarted();
917 f = result.future();
918
919 QCOMPARE (f.progressValue(), 0);
920
921 result.setProgressValue(50);
922
923 QCOMPARE (f.progressValue(), 50);
924
925 result.reportFinished();
926
927 QCOMPARE (f.progressValue(), 50);
928}
929
930void tst_QFuture::progressText()
931{
932 QFutureInterface<void> i;
933 i.reportStarted();
934 QFuture<void> f = i.future();
935
936 QCOMPARE(f.progressText(), QLatin1String(""));
937 i.setProgressValueAndText(progressValue: 1, progressText: QLatin1String("foo"));
938 QCOMPARE(f.progressText(), QLatin1String("foo"));
939 i.reportFinished();
940}
941
942/*
943 Test that results reported after finished are ignored.
944*/
945void tst_QFuture::resultsAfterFinished()
946{
947 {
948 IntResult a;
949 a.reportStarted();
950 QFuture<int> f = a.future();
951 int result;
952
953 QCOMPARE(f.resultCount(), 0);
954
955 result = 1;
956 a.reportResult(result: &result);
957 QCOMPARE(f.resultAt(0), 1);
958
959 a.reportFinished();
960
961 QCOMPARE(f.resultAt(0), 1);
962 QCOMPARE(f.resultCount(), 1);
963 result = 2;
964 a.reportResult(result: &result);
965 QCOMPARE(f.resultCount(), 1);
966 }
967 // cancel it
968 {
969 IntResult a;
970 a.reportStarted();
971 QFuture<int> f = a.future();
972 int result;
973
974 QCOMPARE(f.resultCount(), 0);
975
976 result = 1;
977 a.reportResult(result: &result);
978 QCOMPARE(f.resultAt(0), 1);
979 QCOMPARE(f.resultCount(), 1);
980
981 a.reportCanceled();
982
983 QCOMPARE(f.resultAt(0), 1);
984 QCOMPARE(f.resultCount(), 1);
985
986 result = 2;
987 a.reportResult(result: &result);
988 a.reportFinished();
989 }
990}
991
992void tst_QFuture::resultsAsList()
993{
994 IntResult a;
995 a.reportStarted();
996 QFuture<int> f = a.future();
997
998 int result;
999 result = 1;
1000 a.reportResult(result: &result);
1001 result = 2;
1002 a.reportResult(result: &result);
1003
1004 a.reportFinished();
1005
1006 QList<int> results = f.results();
1007 QCOMPARE(results, QList<int>() << 1 << 2);
1008}
1009
1010/*
1011 Test that QFuture<T> can be implicitly converted to T
1012*/
1013void tst_QFuture::implicitConversions()
1014{
1015 QFutureInterface<QString> iface;
1016 iface.reportStarted();
1017
1018 QFuture<QString> f(&iface);
1019
1020 const QString input("FooBar 2000");
1021 iface.reportFinished(result: &input);
1022
1023 const QString result = f;
1024 QCOMPARE(result, input);
1025 QCOMPARE(QString(f), input);
1026 QCOMPARE(static_cast<QString>(f), input);
1027}
1028
1029void tst_QFuture::iterators()
1030{
1031 {
1032 QFutureInterface<int> e;
1033 e.reportStarted();
1034 QFuture<int> f = e.future();
1035
1036 int result;
1037 result = 1;
1038 e.reportResult(result: &result);
1039 result = 2;
1040 e.reportResult(result: &result);
1041 result = 3;
1042 e.reportResult(result: &result);
1043 e.reportFinished();
1044
1045 QList<int> results;
1046 QFutureIterator<int> i(f);
1047 while (i.hasNext()) {
1048 results.append(t: i.next());
1049 }
1050
1051 QCOMPARE(results, f.results());
1052
1053 QFuture<int>::const_iterator i1 = f.begin(), i2 = i1 + 1;
1054 QFuture<int>::const_iterator c1 = i1, c2 = c1 + 1;
1055
1056 QCOMPARE(i1, i1);
1057 QCOMPARE(i1, c1);
1058 QCOMPARE(c1, i1);
1059 QCOMPARE(c1, c1);
1060 QCOMPARE(i2, i2);
1061 QCOMPARE(i2, c2);
1062 QCOMPARE(c2, i2);
1063 QCOMPARE(c2, c2);
1064 QCOMPARE(1 + i1, i1 + 1);
1065 QCOMPARE(1 + c1, c1 + 1);
1066
1067 QVERIFY(i1 != i2);
1068 QVERIFY(i1 != c2);
1069 QVERIFY(c1 != i2);
1070 QVERIFY(c1 != c2);
1071 QVERIFY(i2 != i1);
1072 QVERIFY(i2 != c1);
1073 QVERIFY(c2 != i1);
1074 QVERIFY(c2 != c1);
1075
1076 int x1 = *i1;
1077 Q_UNUSED(x1);
1078 int x2 = *i2;
1079 Q_UNUSED(x2);
1080 int y1 = *c1;
1081 Q_UNUSED(y1);
1082 int y2 = *c2;
1083 Q_UNUSED(y2);
1084 }
1085
1086 {
1087 QFutureInterface<QString> e;
1088 e.reportStarted();
1089 QFuture<QString> f = e.future();
1090
1091 e.reportResult(result: QString("one"));
1092 e.reportResult(result: QString("two"));
1093 e.reportResult(result: QString("three"));
1094 e.reportFinished();
1095
1096 QList<QString> results;
1097 QFutureIterator<QString> i(f);
1098 while (i.hasNext()) {
1099 results.append(t: i.next());
1100 }
1101
1102 QCOMPARE(results, f.results());
1103
1104 QFuture<QString>::const_iterator i1 = f.begin(), i2 = i1 + 1;
1105 QFuture<QString>::const_iterator c1 = i1, c2 = c1 + 1;
1106
1107 QCOMPARE(i1, i1);
1108 QCOMPARE(i1, c1);
1109 QCOMPARE(c1, i1);
1110 QCOMPARE(c1, c1);
1111 QCOMPARE(i2, i2);
1112 QCOMPARE(i2, c2);
1113 QCOMPARE(c2, i2);
1114 QCOMPARE(c2, c2);
1115 QCOMPARE(1 + i1, i1 + 1);
1116 QCOMPARE(1 + c1, c1 + 1);
1117
1118 QVERIFY(i1 != i2);
1119 QVERIFY(i1 != c2);
1120 QVERIFY(c1 != i2);
1121 QVERIFY(c1 != c2);
1122 QVERIFY(i2 != i1);
1123 QVERIFY(i2 != c1);
1124 QVERIFY(c2 != i1);
1125 QVERIFY(c2 != c1);
1126
1127 QString x1 = *i1;
1128 QString x2 = *i2;
1129 QString y1 = *c1;
1130 QString y2 = *c2;
1131
1132 QCOMPARE(x1, y1);
1133 QCOMPARE(x2, y2);
1134
1135 int i1Size = i1->size();
1136 int i2Size = i2->size();
1137 int c1Size = c1->size();
1138 int c2Size = c2->size();
1139
1140 QCOMPARE(i1Size, c1Size);
1141 QCOMPARE(i2Size, c2Size);
1142 }
1143
1144 {
1145 const int resultCount = 20;
1146
1147 QFutureInterface<int> e;
1148 e.reportStarted();
1149 QFuture<int> f = e.future();
1150
1151 for (int i = 0; i < resultCount; ++i) {
1152 e.reportResult(result: i);
1153 }
1154
1155 e.reportFinished();
1156
1157 {
1158 QFutureIterator<int> it(f);
1159 QFutureIterator<int> it2(it);
1160 }
1161
1162 {
1163 QFutureIterator<int> it(f);
1164
1165 for (int i = 0; i < resultCount - 1; ++i) {
1166 QVERIFY(it.hasNext());
1167 QCOMPARE(it.peekNext(), i);
1168 QCOMPARE(it.next(), i);
1169 }
1170
1171 QVERIFY(it.hasNext());
1172 QCOMPARE(it.peekNext(), resultCount - 1);
1173 QCOMPARE(it.next(), resultCount - 1);
1174 QVERIFY(!it.hasNext());
1175 }
1176
1177 {
1178 QFutureIterator<int> it(f);
1179 QVERIFY(it.hasNext());
1180 it.toBack();
1181 QVERIFY(!it.hasNext());
1182 it.toFront();
1183 QVERIFY(it.hasNext());
1184 }
1185 }
1186}
1187void tst_QFuture::iteratorsThread()
1188{
1189 const int expectedResultCount = 10;
1190 const int delay = 10;
1191 QFutureInterface<int> futureInterface;
1192
1193 // Create result producer thread. The results are
1194 // produced with delays in order to make the consumer
1195 // wait.
1196 QSemaphore sem;
1197 LambdaThread thread = {[=, &futureInterface, &sem](){
1198 for (int i = 1; i <= expectedResultCount; i += 2) {
1199 int result = i;
1200 futureInterface.reportResult(result: &result);
1201 result = i + 1;
1202 futureInterface.reportResult(result: &result);
1203 }
1204
1205 sem.acquire(n: 2);
1206 futureInterface.reportFinished();
1207 }};
1208
1209 futureInterface.reportStarted();
1210 QFuture<int> future = futureInterface.future();
1211
1212 // Iterate over results while the thread is producing them.
1213 thread.start();
1214 int resultCount = 0;
1215 int resultSum = 0;
1216 for (int result : future) {
1217 sem.release();
1218 ++resultCount;
1219 resultSum += result;
1220 }
1221 thread.wait();
1222
1223 QCOMPARE(resultCount, expectedResultCount);
1224 QCOMPARE(resultSum, expectedResultCount * (expectedResultCount + 1) / 2);
1225
1226 // Reverse iterate
1227 resultSum = 0;
1228 QFutureIterator<int> it(future);
1229 it.toBack();
1230 while (it.hasPrevious())
1231 resultSum += it.previous();
1232
1233 QCOMPARE(resultSum, expectedResultCount * (expectedResultCount + 1) / 2);
1234}
1235
1236class SignalSlotObject : public QObject
1237{
1238Q_OBJECT
1239public:
1240 SignalSlotObject()
1241 : finishedCalled(false),
1242 canceledCalled(false),
1243 rangeBegin(0),
1244 rangeEnd(0) { }
1245
1246public slots:
1247 void finished()
1248 {
1249 finishedCalled = true;
1250 }
1251
1252 void canceled()
1253 {
1254 canceledCalled = true;
1255 }
1256
1257 void resultReady(int index)
1258 {
1259 results.insert(value: index);
1260 }
1261
1262 void progressRange(int begin, int end)
1263 {
1264 rangeBegin = begin;
1265 rangeEnd = end;
1266 }
1267
1268 void progress(int progress)
1269 {
1270 reportedProgress.insert(value: progress);
1271 }
1272public:
1273 bool finishedCalled;
1274 bool canceledCalled;
1275 QSet<int> results;
1276 int rangeBegin;
1277 int rangeEnd;
1278 QSet<int> reportedProgress;
1279};
1280
1281void tst_QFuture::pause()
1282{
1283 QFutureInterface<void> Interface;
1284
1285 Interface.reportStarted();
1286 QFuture<void> f = Interface.future();
1287
1288 QVERIFY(!Interface.isPaused());
1289 f.pause();
1290 QVERIFY(Interface.isPaused());
1291 f.resume();
1292 QVERIFY(!Interface.isPaused());
1293 f.togglePaused();
1294 QVERIFY(Interface.isPaused());
1295 f.togglePaused();
1296 QVERIFY(!Interface.isPaused());
1297
1298 Interface.reportFinished();
1299}
1300
1301class ResultObject : public QObject
1302{
1303Q_OBJECT
1304public slots:
1305 void resultReady(int)
1306 {
1307
1308 }
1309public:
1310};
1311
1312// Test that that the isPaused() on future result interface returns true
1313// if we report a lot of results that are not handled.
1314void tst_QFuture::throttling()
1315{
1316 {
1317 QFutureInterface<void> i;
1318
1319 i.reportStarted();
1320 QFuture<void> f = i.future();
1321
1322 QVERIFY(!i.isThrottled());
1323
1324 i.setThrottled(true);
1325 QVERIFY(i.isThrottled());
1326
1327 i.setThrottled(false);
1328 QVERIFY(!i.isThrottled());
1329
1330 i.setThrottled(true);
1331 QVERIFY(i.isThrottled());
1332
1333 i.reportFinished();
1334 }
1335}
1336
1337void tst_QFuture::voidConversions()
1338{
1339 {
1340 QFutureInterface<int> iface;
1341 iface.reportStarted();
1342
1343 QFuture<int> intFuture(&iface);
1344 int value = 10;
1345 iface.reportFinished(result: &value);
1346
1347 QFuture<void> voidFuture(intFuture);
1348 voidFuture = intFuture;
1349
1350 QVERIFY(voidFuture == intFuture);
1351 }
1352
1353 {
1354 QFuture<void> voidFuture;
1355 {
1356 QFutureInterface<QList<int> > iface;
1357 iface.reportStarted();
1358
1359 QFuture<QList<int> > listFuture(&iface);
1360 iface.reportResult(result: QList<int>() << 1 << 2 << 3);
1361 voidFuture = listFuture;
1362 }
1363 QCOMPARE(voidFuture.resultCount(), 0);
1364 }
1365}
1366
1367
1368#ifndef QT_NO_EXCEPTIONS
1369
1370QFuture<void> createExceptionFuture()
1371{
1372 QFutureInterface<void> i;
1373 i.reportStarted();
1374 QFuture<void> f = i.future();
1375
1376 QException e;
1377 i.reportException(e);
1378 i.reportFinished();
1379 return f;
1380}
1381
1382QFuture<int> createExceptionResultFuture()
1383{
1384 QFutureInterface<int> i;
1385 i.reportStarted();
1386 QFuture<int> f = i.future();
1387 int r = 0;
1388 i.reportResult(result: r);
1389
1390 QException e;
1391 i.reportException(e);
1392 i.reportFinished();
1393 return f;
1394}
1395
1396class DerivedException : public QException
1397{
1398public:
1399 void raise() const override { throw *this; }
1400 DerivedException *clone() const override { return new DerivedException(*this); }
1401};
1402
1403QFuture<void> createDerivedExceptionFuture()
1404{
1405 QFutureInterface<void> i;
1406 i.reportStarted();
1407 QFuture<void> f = i.future();
1408
1409 DerivedException e;
1410 i.reportException(e);
1411 i.reportFinished();
1412 return f;
1413}
1414
1415void tst_QFuture::exceptions()
1416{
1417 // test throwing from waitForFinished
1418 {
1419 QFuture<void> f = createExceptionFuture();
1420 bool caught = false;
1421 try {
1422 f.waitForFinished();
1423 } catch (QException &) {
1424 caught = true;
1425 }
1426 QVERIFY(caught);
1427 }
1428
1429 // test result()
1430 {
1431 QFuture<int> f = createExceptionResultFuture();
1432 bool caught = false;
1433 try {
1434 f.result();
1435 } catch (QException &) {
1436 caught = true;
1437 }
1438 QVERIFY(caught);
1439 }
1440
1441 // test result() and destroy
1442 {
1443 bool caught = false;
1444 try {
1445 createExceptionResultFuture().result();
1446 } catch (QException &) {
1447 caught = true;
1448 }
1449 QVERIFY(caught);
1450 }
1451
1452 // test results()
1453 {
1454 QFuture<int> f = createExceptionResultFuture();
1455 bool caught = false;
1456 try {
1457 f.results();
1458 } catch (QException &) {
1459 caught = true;
1460 }
1461 QVERIFY(caught);
1462 }
1463
1464 // test foreach
1465 {
1466 QFuture<int> f = createExceptionResultFuture();
1467 bool caught = false;
1468 try {
1469 foreach (int e, f.results()) {
1470 Q_UNUSED(e);
1471 QFAIL("did not get exception");
1472 }
1473 } catch (QException &) {
1474 caught = true;
1475 }
1476 QVERIFY(caught);
1477 }
1478
1479 // catch derived exceptions
1480 {
1481 bool caught = false;
1482 try {
1483 createDerivedExceptionFuture().waitForFinished();
1484 } catch (QException &) {
1485 caught = true;
1486 }
1487 QVERIFY(caught);
1488 }
1489
1490 {
1491 bool caught = false;
1492 try {
1493 createDerivedExceptionFuture().waitForFinished();
1494 } catch (DerivedException &) {
1495 caught = true;
1496 }
1497 QVERIFY(caught);
1498 }
1499}
1500
1501class MyClass
1502{
1503public:
1504 ~MyClass()
1505 {
1506 QFuture<void> f = createExceptionFuture();
1507 try {
1508 f.waitForFinished();
1509 } catch (QException &) {
1510 caught = true;
1511 }
1512 }
1513 static bool caught;
1514};
1515
1516bool MyClass::caught = false;
1517
1518// This is a regression test for QTBUG-18149. where QFuture did not throw
1519// exceptions if called from destructors when the stack was already unwinding
1520// due to an exception having been thrown.
1521void tst_QFuture::nestedExceptions()
1522{
1523 try {
1524 MyClass m;
1525 Q_UNUSED(m);
1526 throw 0;
1527 } catch (int) {}
1528
1529 QVERIFY(MyClass::caught);
1530}
1531
1532#endif // QT_NO_EXCEPTIONS
1533
1534void tst_QFuture::nonGlobalThreadPool()
1535{
1536 static Q_CONSTEXPR int Answer = 42;
1537
1538 struct UselessTask : QRunnable, QFutureInterface<int>
1539 {
1540 QFuture<int> start(QThreadPool *pool)
1541 {
1542 setRunnable(this);
1543 setThreadPool(pool);
1544 reportStarted();
1545 QFuture<int> f = future();
1546 pool->start(runnable: this);
1547 return f;
1548 }
1549
1550 void run() override
1551 {
1552 const int ms = 100 + (QRandomGenerator::global()->bounded(highest: 100) - 100/2);
1553 QThread::msleep(ms);
1554 reportResult(result: Answer);
1555 reportFinished();
1556 }
1557 };
1558
1559 QThreadPool pool;
1560
1561 const int numTasks = QThread::idealThreadCount();
1562
1563 QVector<QFuture<int> > futures;
1564 futures.reserve(size: numTasks);
1565
1566 for (int i = 0; i < numTasks; ++i)
1567 futures.push_back(t: (new UselessTask)->start(pool: &pool));
1568
1569 QVERIFY(!pool.waitForDone(0)); // pool is busy (meaning our tasks did end up executing there)
1570
1571 QVERIFY(pool.waitForDone(10000)); // max sleep time in UselessTask::run is 150ms, so 10s should be enough
1572 // (and the call returns as soon as all tasks finished anyway, so the
1573 // maximum wait time only matters when the test fails)
1574
1575 Q_FOREACH (const QFuture<int> &future, futures) {
1576 QVERIFY(future.isFinished());
1577 QCOMPARE(future.result(), Answer);
1578 }
1579}
1580
1581void tst_QFuture::resultsReadyAt()
1582{
1583 QFutureInterface<int> iface;
1584 QFutureWatcher<int> watcher;
1585 watcher.setFuture(iface.future());
1586
1587 QTestEventLoop eventProcessor;
1588 connect(sender: &watcher, signal: &QFutureWatcher<int>::finished, receiver: &eventProcessor, slot: &QTestEventLoop::exitLoop);
1589
1590 const int nExpectedResults = 4;
1591 int reported = 0;
1592 int taken = 0;
1593 connect(sender: &watcher, signal: &QFutureWatcher<int>::resultsReadyAt,
1594 slot: [&iface, &reported, &taken](int begin, int end)
1595 {
1596 auto future = iface.future();
1597 QVERIFY(end - begin > 0);
1598 for (int i = begin; i < end; ++i, ++reported) {
1599 QVERIFY(future.isResultReadyAt(i));
1600 taken |= 1 << i;
1601 }
1602 });
1603
1604 auto report = [&iface](int index)
1605 {
1606 int dummyResult = 0b101010;
1607 iface.reportResult(result: &dummyResult, index);
1608 };
1609
1610 const QSignalSpy readyCounter(&watcher, &QFutureWatcher<int>::resultsReadyAt);
1611 QTimer::singleShot(interval: 0, slot: [&iface, &report]{
1612 // With filter mode == true, the result may go into the pending results.
1613 // Reporting it as ready will allow an application to try and access the
1614 // result, crashing on invalid (store.end()) iterator dereferenced.
1615 iface.setFilterMode(true);
1616 iface.reportStarted();
1617 report(0);
1618 report(1);
1619 // This one - should not be reported (it goes into pending):
1620 report(3);
1621 // Let's close the 'gap' and make them all ready:
1622 report(-1);
1623 iface.reportFinished();
1624 });
1625
1626 // Run event loop, QCoreApplication::postEvent is in use
1627 // in QFutureInterface:
1628 eventProcessor.enterLoopMSecs(ms: 2000);
1629 QVERIFY(!eventProcessor.timeout());
1630 if (QTest::currentTestFailed()) // Failed in our lambda observing 'ready at'
1631 return;
1632
1633 QCOMPARE(reported, nExpectedResults);
1634 QCOMPARE(nExpectedResults, iface.future().resultCount());
1635 QCOMPARE(readyCounter.count(), 3);
1636 QCOMPARE(taken, 0b1111);
1637}
1638
1639QTEST_MAIN(tst_QFuture)
1640#include "tst_qfuture.moc"
1641

source code of qtbase/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp