1 #include <QtConcurrent>
2 #include <QTest>
3 #include <QFuture>
4 #include <QFutureWatcher>
5 #include <Automator>
6 #include <QFutureWatcher>
7 #include "trackingdata.h"
8 #include "testfunctions.h"
9 #include "asyncfuture.h"
10 #include "spec.h"
11 #include "tools.h"
12 
13 using namespace AsyncFuture;
14 using namespace Tools;
15 using namespace Test;
16 
17 template <typename T>
finishedFuture(T value)18 QFuture<T> finishedFuture(T value) {
19 
20     auto o = deferred<T>();
21 
22     o.complete(value);
23 
24     return o.future();
25 }
26 
mapFunc(int value)27 static int mapFunc(int value) {
28     return value * value;
29 }
30 
Spec(QObject * parent)31 Spec::Spec(QObject *parent) : QObject(parent)
32 {
33     auto ref = [=]() {
34         QTest::qExec(this, 0, 0); // Autotest detect available test cases of a QObject by looking for "QTest::qExec" in source code
35     };
36     Q_UNUSED(ref);
37 }
38 
initTestCase()39 void Spec::initTestCase()
40 {
41     {
42         QCOMPARE(TrackingData::aliveCount(), 0);
43 
44         TrackingData d1;
45         Q_UNUSED(d1);
46         QCOMPARE(TrackingData::aliveCount(), 1);
47 
48         TrackingData d2;
49         Q_UNUSED(d2);
50         QCOMPARE(TrackingData::aliveCount(), 2);
51     }
52 
53     QCOMPARE(TrackingData::aliveCount(), 0);
54 
55 }
56 
cleanup()57 void Spec::cleanup()
58 {
59     QCOMPARE(TrackingData::aliveCount(), 0);
60 }
61 
square(int value)62 static int square(int value) {
63     Automator::wait(50);
64 
65     return value * value;
66 }
67 
test_QFuture_cancel()68 void Spec::test_QFuture_cancel()
69 {
70     QList<int> input;
71     for (int i = 0 ; i < 100;i++) {
72         input << i;
73     }
74 
75     QFuture<int> future = QtConcurrent::mapped(input, square);
76 
77     QCOMPARE(future.isRunning(), true);
78     QCOMPARE(future.isFinished(), false);
79     QCOMPARE(future.isCanceled(), false);
80 
81     future.cancel();
82 
83     QVERIFY(waitUntil([&](){
84         return !future.isRunning();
85     }, 1000));
86 
87     QCOMPARE(future.isRunning(), false);
88     QCOMPARE(future.isFinished(), true);
89     QCOMPARE(future.isCanceled(), true);
90 }
91 
test_QFuture_isResultReadyAt()92 void Spec::test_QFuture_isResultReadyAt()
93 {
94     auto defer = deferred<int>();
95     auto future = defer.future();
96 
97     QVERIFY(!future.isResultReadyAt(0));
98     defer.complete(10);
99     QVERIFY(future.isResultReadyAt(0));
100     QVERIFY(!future.isResultReadyAt(1));
101     QVERIFY(future.results().size() == 1);
102     QVERIFY(future.result() == 10);
103     QVERIFY(future.results()[0] == 10);
104 
105 }
106 
test_QFutureWatcher_in_thread()107 void Spec::test_QFutureWatcher_in_thread()
108 {
109     // It prove to use QFutureWatcher in a thread do not works if QEventLoop is not used.
110 
111     {
112         bool called = false;
113         QFutureWatcher<void>* watcher = 0;
114         QFuture<void> future;
115 
116         auto worker = [&]() {
117              watcher = new QFutureWatcher<void>();
118              future = timeout(50);
119              QObject::connect(watcher, &QFutureWatcher<void>::finished, [&]() {
120                  called = true;
121              });
122              watcher->setFuture(future);
123         };
124 
125         auto f = QtConcurrent::run(worker);
126 
127         QVERIFY(waitUntil(f,1000));
128 
129         waitUntil([&]() {
130             return called;
131         }, 1000);
132 
133         QVERIFY(future.isFinished());
134         QVERIFY(called == false); // It is not called as the thread is terminated
135         delete watcher;
136     }
137 
138     {
139         // Work around solution: Create QFutureWatcher on main thread.
140 
141         bool called = false;
142         QFutureWatcher<void>* watcher = 0;
143         QFuture<void> future;
144 
145         auto worker = [&]() {
146 
147              future = QFuture<void>();
148 
149              {
150                  QObject obj;
151                  QObject::connect(&obj, &QObject::destroyed,
152                                   QCoreApplication::instance(),
153                                   [&]() {
154                      watcher = new QFutureWatcher<void>();
155                      QObject::connect(watcher, &QFutureWatcher<void>::finished, [&]() {
156                          called = true;
157                      });
158                      watcher->setFuture(future);
159                  });
160              }
161         };
162 
163         auto f = QtConcurrent::run(worker);
164 
165         QVERIFY(waitUntil(f,1000));
166 
167         QVERIFY(waitUntil([&]() {
168             return watcher != 0;
169         }, 1000));
170 
171         waitUntil([&]() {
172             return called;
173         }, 1000);
174 
175         QVERIFY(future.isFinished());
176         QVERIFY(called == true);
177         delete watcher;
178     }
179 }
180 
test_QtConcurrent_exception()181 void Spec::test_QtConcurrent_exception()
182 {
183     auto future = QtConcurrent::run([]() {
184         Automator::wait(100);
185         throw QException();
186         return 99;
187     });
188 
189     QCOMPARE(future.isFinished(), false);
190     QCOMPARE(future.isCanceled(), false);
191 
192     await(future);
193 
194     QCOMPARE(future.isFinished(), true);
195     QCOMPARE(future.isCanceled(), true);
196     QCOMPARE(future.isResultReadyAt(0) , false);
197 }
198 
199 #define TYPEOF(x) std::decay<decltype(x)>::type
200 
test_function_traits()201 void Spec::test_function_traits()
202 {
203     int dummy = 0;
204 
205     auto func1 = []() {
206     };
207 
208     Q_UNUSED(func1);
209 
210     QVERIFY(Private::function_traits<TYPEOF(func1)>::result_type_is_future == 0);
211     QVERIFY((std::is_same<Private::function_traits<TYPEOF(func1)>::future_arg_type, void>::value) == 1);
212     QVERIFY((std::is_same<Private::arg0_traits<decltype(func1)>::type, void>::value) == 1);
213     QVERIFY((std::is_same<Private::observable_traits<decltype(func1)>::type, void>::value) == 1);
214 
215     auto func2 = []() -> QFuture<int> {
216         return QFuture<int>();
217     };
218 
219     Q_UNUSED(func2);
220 
221     QVERIFY(Private::function_traits<TYPEOF(func2)>::result_type_is_future == true);
222     QVERIFY((std::is_same<Private::function_traits<TYPEOF(func2)>::future_arg_type, void>::value) == 0);
223     QVERIFY((std::is_same<Private::function_traits<TYPEOF(func2)>::future_arg_type, int>::value) == 1);
224     QVERIFY((std::is_same<Private::observable_traits<decltype(func2)>::type, int>::value) == 1);
225 
226 
227     auto func3 = []() -> QFuture<void> {
228         return QFuture<void>();
229     };
230 
231     Q_UNUSED(func3);
232 
233     QVERIFY(Private::function_traits<TYPEOF(func3)>::result_type_is_future == true);
234     QVERIFY((std::is_same<Private::function_traits<TYPEOF(func3)>::future_arg_type, void>::value) == 1);
235     QVERIFY((std::is_same<Private::observable_traits<decltype(func3)>::type, void>::value) == 1);
236 
237     auto func4 = [=](bool) mutable -> void  {
238         dummy++;
239     };
240     Q_UNUSED(func4);
241 
242     QVERIFY((std::is_same<Private::function_traits<TYPEOF(func4)>::template arg<0>::type, bool>::value) == 1);
243     QVERIFY((std::is_same<Private::arg0_traits<decltype(func4)>::type, bool>::value) == 1);
244     QVERIFY((std::is_same<Private::observable_traits<decltype(func4)>::type, void>::value) == 1);
245 
246     auto func5 = [=]() mutable -> QFuture<QFuture<int>> {
247         return QFuture<QFuture<int>>();
248     };
249 
250     QVERIFY((std::is_same<Private::observable_traits<decltype(func5)>::type, int>::value) == 1);
251 
252     {
253         QFuture<QFuture<bool>> f1;
254         static_assert(std::is_same<Private::future_traits<decltype(f1)>::arg_type, bool>::value, "");
255 
256         QFuture<QFuture<QFuture<int>>> f2;
257         static_assert(std::is_same<Private::future_traits<decltype(f2)>::arg_type, int>::value, "");
258 
259     }
260 
261 }
262 
test_private_DeferredFuture()263 void Spec::test_private_DeferredFuture()
264 {
265     auto defer = Private::DeferredFuture<void>::create();
266 
267     auto worker = [=]() {
268         Automator::wait(50);
269     };
270 
271     defer->complete(QtConcurrent::run(worker));
272 
273     QFuture<void> future = defer->future();
274     QCOMPARE(future.isFinished(), false);
275     QCOMPARE(future.isRunning(), true);
276 
277     QVERIFY(waitUntil(future, 1000));
278 
279     QCOMPARE(future.isFinished(), true);
280     QCOMPARE(future.isRunning(), false);
281 
282 }
283 
284 
test_private_run()285 void Spec::test_private_run()
286 {
287     QFuture<bool> bFuture = finishedFuture<bool>(true);
288     QFuture<void> vFuture;
289     QFuture<int> iFuture = finishedFuture<int>(10);
290 
291     auto iCallbackBool = [](bool value) {
292         Q_UNUSED(value);
293         return 1;
294     };
295 
296     auto iCallbackVoid = []() {
297         return 2;
298     };
299 
300     auto vCallbackBool = []() {
301     };
302 
303     auto value = AsyncFuture::Private::eval(iCallbackBool, bFuture);
304     QCOMPARE(value.value, 1);
305 
306     value = AsyncFuture::Private::eval(iCallbackVoid, bFuture);
307     QCOMPARE(value.value, 2);
308 
309     value = AsyncFuture::Private::eval(iCallbackVoid, vFuture);
310     QCOMPARE(value.value, 2);
311 
312     AsyncFuture::Private::eval(vCallbackBool, bFuture);
313 
314     auto iCallbackFutureI = [](QFuture<int> future){
315         return future.result();
316     };
317 
318     auto d = deferred<int>();
319     iFuture = d.future();
320     d.complete(20);
321     QVERIFY(waitUntil(iFuture,1000));
322 
323     value = AsyncFuture::Private::eval(iCallbackFutureI, iFuture);
324     QCOMPARE(value.value, 20);
325 
326     //Error statement
327     // value = ObservableFuture::Private::run(iCallbackBool, vFuture);
328 }
329 
test_observe_future_future()330 void Spec::test_observe_future_future()
331 {
332     auto worker = [=]() {
333         QList<int> list;
334         list << 1 << 2 << 3 << 4;
335         return QtConcurrent::mapped(list, mapFunc);
336     };
337 
338     // Convert QFuture<QFuture<int>> to QFuture<int>
339     QFuture<int> future = observe(QtConcurrent::run(worker)).future();
340     QVERIFY(!future.isFinished());
341     await(future);
342 
343     QCOMPARE(future.progressValue(), 4);
344     QCOMPARE(future.isStarted(), true);
345 
346     QList<int> result = future.results();
347     QCOMPARE(result.size(), 4);
348 }
349 
test_Observable_context()350 void Spec::test_Observable_context()
351 {
352 
353     QFuture<bool> bFuture;
354     QFuture<int> iFuture;
355     QFuture<void> vFuture, vFuture2;
356 
357     /* Case 1. QFuture<bool> + int(bool) */
358 
359     auto bWorker = [=]() -> bool {
360         Automator::wait(50);
361         return true;
362     };
363 
364     auto iCleanupBool = [&](bool value) -> int {
365         Automator::wait(50);
366         Q_UNUSED(value);
367         return 5;
368     };
369 
370     bFuture = QtConcurrent::run(bWorker);
371     iFuture = observe(bFuture).context(this,iCleanupBool).future();
372     QCOMPARE(iFuture.isFinished(), false);
373     QCOMPARE(iFuture.isRunning(), true);
374 
375     QVERIFY(waitUntil([&](){
376         return iFuture.isFinished();
377     }, 1000));
378 
379     QCOMPARE(iFuture.isRunning(), false);
380     QCOMPARE(iFuture.isFinished(), true);
381     QCOMPARE(iFuture.result(), 5);
382 
383     /* Case 2: QFuture<bool> + void(bool) */
384 
385     bool vCleanupBoolCalled = false;
386 
387     auto vCleanupBool = [&](bool value) -> void {
388         Q_UNUSED(value);
389         Automator::wait(50);
390         vCleanupBoolCalled = true;
391     };
392 
393     bFuture = QtConcurrent::run(bWorker);
394     vFuture = observe(bFuture).context(this, vCleanupBool).future();
395     QCOMPARE(vFuture.isFinished(), false);
396 
397     QVERIFY(waitUntil([&](){
398         return vFuture.isFinished();
399     }, 1000));
400 
401     QCOMPARE(vFuture.isFinished(), true);
402     QCOMPARE(vCleanupBoolCalled, true);
403 
404     /* Case3: QFuture<void> + void(void) */
405 
406     bool vCleanupVoidCalled = false;
407 
408     auto vCleanupVoid = [&]() -> void {
409         Automator::wait(50);
410         vCleanupVoidCalled = true;
411     };
412 
413     auto vWorker = []() -> void {
414             Automator::wait(50);
415     };
416 
417     vFuture = QtConcurrent::run(vWorker);
418     vFuture2 = observe(vFuture).context(this, vCleanupVoid).future();
419     QCOMPARE(vFuture2.isFinished(), false);
420 
421     QVERIFY(waitUntil([&](){
422         return vFuture2.isFinished();
423     }, 1000));
424 
425     QCOMPARE(vFuture2.isFinished(), true);
426     QCOMPARE(vCleanupVoidCalled, true);
427 
428     /* Remarks: QFuture<void> + void(bool) */
429     /* It is not a valid situation */
430 
431     /* Extra case. Depend on a finished future */
432     {
433         vCleanupVoidCalled = false;
434         auto d = deferred<void>();
435         d.complete();
436         vFuture = d.future();
437         QCOMPARE(vFuture.isFinished(), true);
438         QCOMPARE(vFuture.isCanceled(), false);
439 
440         vFuture2 = observe(vFuture).context(this, vCleanupVoid).future();
441         QCOMPARE(vFuture2.isFinished(), false);
442 
443         QVERIFY(waitUntil([&](){
444             return vFuture2.isFinished();
445         }, 1000));
446 
447         QCOMPARE(vFuture2.isFinished(), true);
448         QCOMPARE(vCleanupVoidCalled, true);
449     }
450 }
451 
test_Observable_context_destroyed()452 void Spec::test_Observable_context_destroyed()
453 {
454     QObject* context = new QObject();
455 
456     auto bWorker = [=]() -> bool {
457         Automator::wait(500);
458         return true;
459     };
460 
461     bool vCleanupVoidCalled = false;
462     auto vCleanupVoid = [&]() -> void {
463         vCleanupVoidCalled = true;
464     };
465 
466     QFuture<bool> bFuture = QtConcurrent::run(bWorker);
467 
468     QFuture<void> vFuture = observe(bFuture).context(context, vCleanupVoid).future();
469 
470     QCOMPARE(vFuture.isFinished(), false);
471     delete context;
472 
473     QCOMPARE(vFuture.isFinished(), true);
474     QCOMPARE(vFuture.isCanceled(), true);
475     QCOMPARE(vCleanupVoidCalled, false);
476 
477 
478     QVERIFY(waitUntil([&](){
479         return bFuture.isFinished();
480     }, 1000));
481 }
482 
test_Observable_context_in_thread()483 void Spec::test_Observable_context_in_thread()
484 {
485     auto worker = [&]() -> void {
486         QObject context;
487 
488         QThread* workerThread = QThread::currentThread();
489 
490         QVERIFY(workerThread != QCoreApplication::instance()->thread());
491 
492         auto worker = [=]() -> void {
493             QVERIFY(QThread::currentThread() != workerThread);
494 
495             Automator::wait(50);
496         };
497 
498         auto cleanup = [&]() -> void {
499             QVERIFY(QThread::currentThread() == workerThread);
500             Automator::wait(50);
501         };
502 
503         auto f1 = QtConcurrent::run(worker);
504         auto f2 = observe(f1).context(&context, cleanup).future();
505 
506         QVERIFY(waitUntil([&](){
507             return f2.isFinished();
508         }, 1000));
509     };
510 
511     QThreadPool pool;
512     pool.setMaxThreadCount(1);
513     QFuture<void> future = QtConcurrent::run(&pool, worker);
514 
515     future.waitForFinished();
516 }
517 
test_Observable_context_in_different_thread()518 void Spec::test_Observable_context_in_different_thread()
519 {
520     QObject context;
521 
522     auto worker = [&]() -> void {
523 
524         QThread* workerThread = QThread::currentThread();
525 
526         QVERIFY(workerThread != QCoreApplication::instance()->thread());
527 
528         auto worker = [=]() -> void {
529             QVERIFY(QThread::currentThread() != workerThread);
530 
531             Automator::wait(50);
532         };
533 
534         auto cleanup = [&]() -> void {
535             QVERIFY(QThread::currentThread() != workerThread);
536             Automator::wait(50);
537         };
538 
539         auto f1 = QtConcurrent::run(worker);
540         auto f2 = observe(f1).context(&context, cleanup).future();
541 
542         QVERIFY(waitUntil([&](){
543             return f2.isFinished();
544         }, 1000));
545     };
546 
547     QThreadPool pool;
548     pool.setMaxThreadCount(1);
549     QFuture<void> future = QtConcurrent::run(&pool, worker);
550 
551     waitUntil(future);
552 }
553 
test_Observable_context_return_future()554 void Spec::test_Observable_context_return_future()
555 {
556     auto bWorker = [=]() -> bool {
557         Automator::wait(50);
558         return true;
559     };
560 
561     auto futureCleanupBool = [&](bool value) {
562         Q_UNUSED(value)
563         auto internalWorker = [=]() -> int {
564             Automator::wait(50);
565 
566             return 10;
567         };
568         QFuture<int> future = QtConcurrent::run(internalWorker);
569         return future;
570     };
571 
572     QFuture<bool> bFuture = QtConcurrent::run(bWorker);
573 
574     Observable<int> observable = observe(bFuture).context(this, futureCleanupBool);
575 
576     waitUntil(observable.future(), 1000);
577 
578 }
579 
test_Observable_signal()580 void Spec::test_Observable_signal()
581 {
582     auto proxy = new SignalProxy(this);
583 
584     QFuture<void> vFuture = observe(proxy, &SignalProxy::proxy0).future();
585 
586     QCOMPARE(vFuture.isFinished(), false);
587     QCOMPARE(vFuture.isRunning(), true);
588 
589     QMetaObject::invokeMethod(proxy, "proxy0");
590 
591     QCOMPARE(vFuture.isFinished(), false);
592     QCOMPARE(vFuture.isRunning(), true);
593 
594     QVERIFY(waitUntil([&](){
595         return vFuture.isFinished();
596     }, 1000));
597 
598     QCOMPARE(vFuture.isFinished(), true);
599     QCOMPARE(vFuture.isRunning(), false);
600 
601     delete proxy;
602 }
603 
test_Observable_signal_with_argument()604 void Spec::test_Observable_signal_with_argument()
605 {
606     auto *proxy = new SignalProxy(this);
607 
608     QFuture<int> iFuture = observe(proxy, &SignalProxy::proxy1).future();
609 
610     QCOMPARE(iFuture.isFinished(), false);
611     QCOMPARE(iFuture.isRunning(), true);
612     QMetaObject::invokeMethod(proxy,
613                               "proxy1",
614                               Qt::DirectConnection,
615                               Q_ARG(int, 5));
616 
617     QCOMPARE(iFuture.isFinished(), false);
618     QCOMPARE(iFuture.isRunning(), true);
619 
620     QVERIFY(waitUntil([&](){
621         return iFuture.isFinished();
622     }, 1000));
623 
624     QCOMPARE(iFuture.isFinished(), true);
625     QCOMPARE(iFuture.isRunning(), false);
626     QCOMPARE(iFuture.result(), 5);
627 
628     delete proxy;
629 }
630 
test_Observable_signal_by_signature()631 void Spec::test_Observable_signal_by_signature()
632 {
633 
634     {
635         // Observe a signal with no argument
636         auto proxy = new SignalProxy(this);
637 
638         QFuture<void> vFuture = observe(proxy, SIGNAL(proxy0())).future();
639 
640         QCOMPARE(vFuture.isFinished(), false);
641         QCOMPARE(vFuture.isRunning(), true);
642 
643         QMetaObject::invokeMethod(proxy, "proxy0");
644 
645         QCOMPARE(vFuture.isFinished(), false);
646         QCOMPARE(vFuture.isRunning(), true);
647 
648         QVERIFY(waitUntil([&](){
649             return vFuture.isFinished();
650         }, 1000));
651 
652         QCOMPARE(vFuture.isFinished(), true);
653         QCOMPARE(vFuture.isRunning(), false);
654 
655         delete proxy;
656     }
657 
658     {
659         // Observe a sigal without argument
660         auto *proxy = new SignalProxy(this);
661 
662         QFuture<QVariant> iFuture = observe(proxy, SIGNAL(proxy1(int))).future();
663 
664         QCOMPARE(iFuture.isFinished(), false);
665         QCOMPARE(iFuture.isRunning(), true);
666         QMetaObject::invokeMethod(proxy,
667                                   "proxy1",
668                                   Qt::DirectConnection,
669                                   Q_ARG(int, 5));
670 
671         QCOMPARE(iFuture.isFinished(), false);
672         QCOMPARE(iFuture.isRunning(), true);
673 
674         QVERIFY(waitUntil([&](){
675             return iFuture.isFinished();
676         }, 1000));
677 
678         QCOMPARE(iFuture.isFinished(), true);
679         QCOMPARE(iFuture.isRunning(), false);
680         QCOMPARE(iFuture.result().toInt(), 5);
681 
682         delete proxy;
683     }
684 
685     {
686         // invalid signature
687 
688         auto *proxy = new SignalProxy(this);
689 
690         QFuture<QVariant> iFuture = observe(proxy, SIGNAL(noSuchSignal())).future();
691         QCOMPARE(iFuture.isCanceled(), true);
692         Q_UNUSED(iFuture);
693 
694         delete proxy;
695     }
696 
697 }
698 
test_Observable_signal_destroyed()699 void Spec::test_Observable_signal_destroyed()
700 {
701     auto proxy = new SignalProxy(this);
702 
703     QFuture<void> vFuture = observe(proxy, &SignalProxy::proxy0).future();
704 
705     QCOMPARE(vFuture.isFinished(), false);
706     QCOMPARE(vFuture.isRunning(), true);
707 
708     delete proxy;
709 
710     QCOMPARE(vFuture.isFinished(), true);
711     QCOMPARE(vFuture.isRunning(), false);
712     QCOMPARE(vFuture.isCanceled(), true);
713 }
714 
test_Observable_subscribe()715 void Spec::test_Observable_subscribe()
716 {
717     {
718         // complete
719         auto o = deferred<int>();
720         auto c1 = Callable<int>();
721         auto result = o.subscribe(c1.func).future();
722 
723         QCOMPARE(result.isFinished(), false);
724         o.complete(10);
725 
726         QCOMPARE(c1.called, false);
727         waitUntil(o.future());
728         QCOMPARE(c1.called, true);
729         QCOMPARE(c1.value, 10);
730         QCOMPARE(result.isFinished(), true);
731         QCOMPARE(result.isCanceled(), false);
732     }
733 
734     {
735         // cancel
736         auto o = deferred<int>();
737         auto c1 = Callable<int>();
738         auto c2 = Callable<void>();
739         auto result = o.subscribe(c1.func, c2.func).future();
740         o.cancel();
741 
742         QCOMPARE(c1.called, false);
743         QCOMPARE(result.isFinished(), false);
744 
745         waitUntil(o.future());
746 
747         QCOMPARE(c1.called, false);
748         QCOMPARE(c2.called, true);
749         QCOMPARE(result.isFinished(), true);
750         QCOMPARE(result.isCanceled(), true);
751     }
752 }
753 
test_Observable_subscribe_in_thread()754 void Spec::test_Observable_subscribe_in_thread()
755 {
756     QThreadPool pool;
757     pool.setMaxThreadCount(4);
758 
759     auto worker = [&]() -> void {
760         QThread* workerThread = QThread::currentThread();
761 
762         QVERIFY(workerThread != QCoreApplication::instance()->thread());
763 
764         auto worker = [=]() -> void {
765             QVERIFY(QThread::currentThread() != workerThread);
766             Automator::wait(50);
767         };
768 
769         auto cleanup = [&]() -> void {
770             QVERIFY(QThread::currentThread() == QCoreApplication::instance()->thread());
771             Automator::wait(50);
772         };
773 
774         auto f1 = QtConcurrent::run(&pool, worker);
775         auto f2 = observe(f1).subscribe(cleanup).future();
776 
777         QVERIFY(waitUntil([&](){
778             return f2.isFinished();
779         }, 1000));
780     };
781 
782     QFuture<void> future = QtConcurrent::run(&pool, worker);
783 
784     QVERIFY(waitUntil(future , 1000));
785 }
786 
test_Observable_subscribe_return_future()787 void Spec::test_Observable_subscribe_return_future()
788 {
789     auto bWorker = [=]() -> bool {
790         Automator::wait(50);
791         return true;
792     };
793 
794     auto futureCleanupBool = [&](bool value) {
795         Q_UNUSED(value)
796         auto internalWorker = [=]() -> int {
797             Automator::wait(50);
798 
799             return 10;
800         };
801         QFuture<int> future = QtConcurrent::run(internalWorker);
802         return future;
803     };
804 
805     Observable<bool> observable1 = observe(QtConcurrent::run(bWorker));
806     Observable<int> observable2 = observable1.subscribe(futureCleanupBool);
807 
808     waitUntil(observable2.future(), 1000);
809     QCOMPARE(observable2.future().result(), 10);
810 
811     observable2 = observe(QtConcurrent::run(bWorker)).subscribe(futureCleanupBool,[]() {});
812     QCOMPARE(observable2.future().isFinished(), false);
813     waitUntil(observable2.future(), 1000);
814     QCOMPARE(observable2.future().result(), 10);
815 }
816 
test_Observable_subscribe_return_canceledFuture()817 void Spec::test_Observable_subscribe_return_canceledFuture()
818 {
819     auto start = Deferred<void>();
820     auto f1 = start.future();
821     QList<int> sequence;
822     QList<int> expectedSequence;
823     expectedSequence << 2;
824 
825     auto defer = Deferred<void>();
826     defer.cancel();
827     auto canceledFuture = defer.future();
828 
829     auto f2 = observe(f1).subscribe([&]() {
830         sequence << 2;
831         return canceledFuture;
832     }).future();
833 
834     auto f3 = observe(f2).subscribe([&]() {
835         sequence << 3;
836     }).future();
837 
838     start.complete();
839 
840     waitUntil(f3, 1000);
841 
842     QCOMPARE(sequence, expectedSequence);
843 
844 }
845 
test_Observable_subscribe_return_mappedFuture()846 void Spec::test_Observable_subscribe_return_mappedFuture()
847 {
848     auto future = observe(QtConcurrent::run([](){})).subscribe([=]() {
849         QList<int> input;
850         input << 1 << 2 << 3;
851         auto ret = QtConcurrent::mapped(input, square);
852         return ret;
853     }).future();
854 
855     QTRY_COMPARE(future.isRunning(), false);
856 
857     QCOMPARE(future.progressMaximum(), 3);
858     QList<int> expected;
859     expected << 1 << 4 << 9;
860 
861     QCOMPARE(future.results(), expected);
862 }
863 
test_Observable_subscribe_return_emptyListFuture()864 void Spec::test_Observable_subscribe_return_emptyListFuture()
865 {
866     auto future = observe(QtConcurrent::run([](){})).subscribe([=]() {
867         QList<int> res;
868         auto defer = AsyncFuture::deferred<int>();
869         defer.complete(res);
870         return defer.future();
871     }).future();
872 
873     await(future);
874 
875     QList<int> expected;
876 
877     QCOMPARE(future.results(), expected);
878 }
879 
test_Observable_subscribe_exception()880 void Spec::test_Observable_subscribe_exception()
881 {
882 
883     auto future = observe(QtConcurrent::run([](){})).subscribe([=]() {
884         throw QException();
885     }).future();
886 
887     await(future);
888 
889     QCOMPARE(future.isCanceled(), true);
890 
891     future = observe(QtConcurrent::run([](){})).subscribe([=]() {
892         throw std::exception();
893     }).future();
894 
895     await(future);
896 
897     QCOMPARE(future.isCanceled(), true);
898 
899 }
900 
test_Observable_onProgress()901 void Spec::test_Observable_onProgress()
902 {
903     class CustomDeferred: public AsyncFuture::Deferred<int> {
904     public:
905 
906         void setProgressValue(int value) {
907             AsyncFuture::Deferred<int>::deferredFuture->setProgressValue(value);
908         }
909 
910         void setProgressRange(int min, int max) {
911             AsyncFuture::Deferred<int>::deferredFuture->setProgressRange(min, max);
912         }
913 
914         void reportResult(int value, int index) {
915             AsyncFuture::Deferred<int>::deferredFuture->reportResult(value, index);
916         }
917 
918     };
919 
920     CustomDeferred defer;
921     auto future = defer.future();
922 
923     int count = 0;
924     int value = 999;
925     int min = 999;
926     int max = -1;
927 
928     bool inMainThread = false;
929 
930     defer.onProgress([&]() -> bool {
931         count++;
932         value = future.progressValue();
933         min = future.progressMinimum();
934         max = future.progressMaximum();
935 
936         inMainThread = (QThread::currentThread() == QCoreApplication::instance()->thread());
937         return value != max;
938     });
939 
940     QCOMPARE(count, 0);
941     defer.setProgressRange(0, 10);
942 
943     QTRY_VERIFY2_WITH_TIMEOUT(count > 0, "", 1000);
944     QCOMPARE(value, 0);
945     QCOMPARE(min, 0);
946     QCOMPARE(max, 10);
947     QVERIFY(inMainThread);
948     int oldCount = count;
949 
950     defer.setProgressValue(5);
951     QTRY_VERIFY2_WITH_TIMEOUT(oldCount != count, "", 1000);
952 
953     QCOMPARE(value, 5);
954     QCOMPARE(min, 0);
955     QCOMPARE(max, 10);
956     QVERIFY(inMainThread);
957     oldCount = count;
958 
959     defer.setProgressValue(10);
960     QTRY_VERIFY2_WITH_TIMEOUT(oldCount != count, "", 1000);
961 
962     QCOMPARE(value, 10);
963     QCOMPARE(min, 0);
964     QCOMPARE(max, 10);
965     QVERIFY(inMainThread);
966     oldCount = count;
967 
968     defer.setProgressValue(12);
969     Automator::wait(100);
970 
971     QVERIFY(oldCount == count);
972 
973     {
974         // Test with mutable function
975 
976         auto defer = AsyncFuture::deferred<void>();
977 
978         defer.onProgress([=]() mutable -> void {
979 
980         });
981 
982     }
983 }
984 
test_Observable_onCanceled()985 void Spec::test_Observable_onCanceled()
986 {
987     bool canceled = false;
988     auto defer = deferred<void>();
989 
990     defer.onCanceled([&]() {
991         canceled = true;
992     });
993 
994     defer.cancel();
995     QCOMPARE(canceled, false);
996     await(defer.future());
997     Automator::wait(10);
998 
999     QCOMPARE(canceled, true);
1000 }
1001 
test_Observable_onCanceled_deferred()1002 void Spec::test_Observable_onCanceled_deferred()
1003 {
1004     auto d1 = deferred<void>();
1005     auto d2 = deferred<void>();
1006 
1007     d1.onCanceled(d2);
1008 
1009     d1.cancel();
1010 
1011     QCOMPARE(d1.future().isFinished(), true);
1012     QCOMPARE(d2.future().isFinished(), false);
1013     QCOMPARE(d2.future().isCanceled(), false);
1014 
1015     await(d2.future());
1016 
1017     QCOMPARE(d2.future().isFinished(), true);
1018     QCOMPARE(d2.future().isCanceled(), true);
1019 }
1020 
test_Observable_onCanceled_future()1021 void Spec::test_Observable_onCanceled_future()
1022 {
1023     auto d1 = deferred<int>();
1024     auto d2 = deferred<int>();
1025 
1026     d1.onCanceled(d2.future());
1027 
1028     d1.future().cancel();
1029 
1030     QCOMPARE(d1.future().isCanceled(), true);
1031     QCOMPARE(d1.future().isFinished(), false);
1032 
1033     QCOMPARE(d2.future().isCanceled(), false);
1034     QCOMPARE(d2.future().isFinished(), false);
1035 
1036     QTRY_COMPARE(d2.future().isCanceled(), true);
1037 
1038     QCOMPARE(d2.future().isFinished(), false);
1039 }
1040 
test_Observable_onCompleted()1041 void Spec::test_Observable_onCompleted()
1042 {
1043     bool called = false;
1044     auto defer = deferred<void>();
1045 
1046     defer.onCompleted([&]() {
1047         called = true;
1048     });
1049 
1050     defer.complete();
1051     QCOMPARE(called, false);
1052     await(defer.future());
1053     Automator::wait(10);
1054 
1055     QCOMPARE(called, true);
1056 }
1057 
test_Observable_onFinished()1058 void Spec::test_Observable_onFinished()
1059 {
1060     {
1061         Counter onFinished;
1062 
1063         QCOMPARE(onFinished.called, 0);
1064 
1065         auto defer = deferred<void>();
1066 
1067         defer.onFinished(onFinished());
1068 
1069         defer.complete();
1070 
1071         await(defer.future());
1072 
1073         QTRY_COMPARE(onFinished.called, 1);
1074     }
1075 
1076     {
1077 
1078         Counter onFinished;
1079 
1080         QCOMPARE(onFinished.called, 0);
1081 
1082         auto defer = deferred<void>();
1083 
1084         defer.onFinished(onFinished());
1085 
1086         defer.cancel();
1087 
1088         await(defer.future());
1089 
1090         QTRY_COMPARE(onFinished.called, 1);
1091     }
1092 
1093 }
1094 
test_Observable_setProgressValue()1095 void Spec::test_Observable_setProgressValue()
1096 {
1097 
1098     auto defer = deferred<int>();
1099     auto future = defer.future();
1100 
1101     QCOMPARE(future.progressValue(), 0);
1102     QCOMPARE(future.progressMinimum(), 0);
1103     QCOMPARE(future.progressMaximum(), 0);
1104 
1105     defer.setProgressValue(10);
1106     defer.setProgressRange(5, 30);
1107 
1108     QCOMPARE(future.progressValue(), 10);
1109     QCOMPARE(future.progressMinimum(), 5);
1110     QCOMPARE(future.progressMaximum(), 30);
1111 }
1112 
test_Deferred()1113 void Spec::test_Deferred()
1114 {
1115     {
1116         // defer<bool>::complete
1117         auto d = AsyncFuture::deferred<bool>();
1118         auto d2 = d;
1119         auto future = d.future();
1120         Callable<bool> callable;
1121         observe(future).context(this,callable.func);
1122 
1123         QCOMPARE(future.isRunning(), true);
1124         QCOMPARE(future.isFinished(), false);
1125 
1126         d.complete(true);
1127 
1128         QCOMPARE(callable.called, false);
1129         QCOMPARE(future.isRunning(), false);
1130         QCOMPARE(future.isFinished(), true);
1131 
1132         tick();
1133 
1134         QCOMPARE(callable.called, true);
1135         QCOMPARE(future.isRunning(), false);
1136         QCOMPARE(future.isFinished(), true);
1137 	QCOMPARE(future.isResultReadyAt(0), true);
1138         QCOMPARE(future.result(), true);
1139 
1140         d2.complete(true);
1141     }
1142 
1143     {
1144         // defer<void>::complete
1145         QFuture<void> future;
1146         {
1147             auto d = AsyncFuture::deferred<void>();
1148             future = d.future();
1149             QCOMPARE(future.isRunning(), true);
1150             QCOMPARE(future.isFinished(), false);
1151 
1152             d.complete();
1153 
1154             QCOMPARE(future.isRunning(), false);
1155             QCOMPARE(future.isFinished(), true);
1156         }
1157 
1158         // d was destroyed, but future leave
1159 
1160         waitUntil(future, 1000);
1161 
1162         QCOMPARE(future.isRunning(), false);
1163         QCOMPARE(future.isFinished(), true);
1164     }
1165 
1166     {
1167         // defer<bool>::cancel
1168         auto d = AsyncFuture::deferred<bool>();
1169         auto future = d.future();
1170         QCOMPARE(future.isRunning(), true);
1171         QCOMPARE(future.isFinished(), false);
1172 
1173         d.cancel();
1174 
1175         QCOMPARE(future.isRunning(), false);
1176         QCOMPARE(future.isFinished(), true);
1177         QCOMPARE(future.isCanceled(), true);
1178 
1179         QCOMPARE(future.isResultReadyAt(0), false);
1180     }
1181 
1182 
1183     {
1184         // defer<void>::cancel
1185         auto d = AsyncFuture::deferred<void>();
1186         auto future = d.future();
1187         QCOMPARE(future.isRunning(), true);
1188         QCOMPARE(future.isFinished(), false);
1189 
1190         d.cancel();
1191 
1192         QCOMPARE(future.isRunning(), false);
1193         QCOMPARE(future.isFinished(), true);
1194         QCOMPARE(future.isCanceled(), true);
1195     }
1196 
1197     {
1198         // destroy defer<void>
1199         QFuture<void> future;
1200         {
1201             auto d = AsyncFuture::deferred<void>();
1202             future = d.future();
1203             QCOMPARE(future.isRunning(), true);
1204             QCOMPARE(future.isFinished(), false);
1205         }
1206 
1207         QCOMPARE(future.isRunning(), false);
1208         QCOMPARE(future.isFinished(), true);
1209         QCOMPARE(future.isCanceled(), true);
1210     }
1211 
1212 }
1213 
test_Deferred_complete_future()1214 void Spec::test_Deferred_complete_future()
1215 {
1216     auto timeout = []() {
1217         Automator::wait(50);
1218     };
1219 
1220     {
1221         // Case: complete(QFuture) which could be finished without error
1222         QFuture<void> future;
1223 
1224         {
1225             auto d = deferred<void>();
1226             future = d.future();
1227 
1228             // d is destroyed but complete(QFuture) increased the ref count and therefore it won't be canceled
1229             d.complete(QtConcurrent::run(timeout));
1230         }
1231 
1232         QCOMPARE(future.isFinished(), false);
1233         QCOMPARE(future.isCanceled(), false);
1234 
1235         waitUntil(future);
1236 
1237         QCOMPARE(future.isFinished(), true);
1238         QCOMPARE(future.isCanceled(), false);
1239     }
1240 
1241     {
1242         // case: complete(future) which will be canceled.
1243 
1244         auto source = deferred<void>();
1245 
1246         // Case: complete(QFuture) which could be finished without error
1247         QFuture<void> future;
1248         {
1249             auto d = deferred<void>();
1250             future = d.future();
1251             d.complete(source.future());
1252         }
1253 
1254         QCOMPARE(future.isFinished(), false);
1255         QCOMPARE(future.isCanceled(), false);
1256 
1257         source.cancel();
1258 
1259         QCOMPARE(future.isFinished(), false);
1260         QCOMPARE(future.isCanceled(), false);
1261 
1262         QVERIFY(waitUntil(future, 1000));
1263 
1264         QCOMPARE(future.isFinished(), true);
1265         QCOMPARE(future.isCanceled(), true);
1266     }
1267 
1268     {
1269         // case: 3 - complete QFuture<QFuture<>>
1270 
1271         auto defer = deferred<int>();
1272 
1273         {
1274             auto worker = [=]() {
1275                 auto internalWorker = [=]() {
1276                     return 99;
1277                 };
1278                 return QtConcurrent::run(internalWorker);
1279             };
1280 
1281             QFuture<QFuture<int>> future = QtConcurrent::run(worker);
1282             defer.complete(future);
1283         }
1284 
1285         auto future = defer.future();
1286         QCOMPARE(future.isFinished(), false);
1287         QCOMPARE(future.isCanceled(), false);
1288 
1289         await(future, 1000);
1290 
1291         QCOMPARE(future.isFinished(), true);
1292         QCOMPARE(future.isCanceled(), false);
1293         QCOMPARE(future.result(), 99);
1294     }
1295 }
1296 
test_Deferred_complete_future_future()1297 void Spec::test_Deferred_complete_future_future()
1298 {
1299     /*
1300      Remarks:
1301      - Deferred<void>::complete(QFuture<QFuture<int>>)
1302      - That is not supported.
1303      */
1304 
1305     auto worker = [=]() {
1306         Automator::wait(50);
1307         QList<int> list;
1308         list << 1 << 2 <<3;
1309 
1310         return QtConcurrent::mapped(list, mapFunc);
1311     };
1312 
1313     QList<int> expectedResult;
1314     expectedResult << 1 << 4 << 9;
1315 
1316     {
1317         // Deferred<int>::complete(QFuture<QFuture<int>>)
1318         auto f1 = QtConcurrent::run(worker);
1319 
1320         auto defer = deferred<int>();
1321 
1322         defer.complete(f1);
1323         auto f2 = defer.future();
1324         QCOMPARE(f2.progressValue(), 0);
1325         QCOMPARE(f2.progressMaximum(), 0);
1326 
1327         await(f2);
1328 
1329         QCOMPARE(f2.progressValue(), 3);
1330         QCOMPARE(f2.progressMaximum(), 3);
1331 
1332         QCOMPARE(f2.results() , expectedResult);
1333     }
1334 
1335 
1336 }
1337 
test_Deferred_complete_list()1338 void Spec::test_Deferred_complete_list()
1339 {
1340     auto defer = deferred<int>();
1341 
1342     QList<int> expected;
1343 
1344     expected << 1 << 2 << 3;
1345 
1346     defer.complete(expected);
1347 
1348     auto future = defer.future();
1349     QVERIFY(future.isFinished());
1350 
1351     QVERIFY(future.results() == expected);
1352 }
1353 
test_Deferred_complete_empty_list()1354 void Spec::test_Deferred_complete_empty_list()
1355 {
1356     auto defer = deferred<int>();
1357     QList<int> expected;
1358 
1359     defer.complete(expected);
1360 
1361     auto future = defer.future();
1362     QVERIFY(future.isFinished());
1363 
1364     QVERIFY(future.results() == expected);
1365 }
1366 
test_Deferred_cancel_future()1367 void Spec::test_Deferred_cancel_future()
1368 {
1369 
1370     auto timeout = []() {
1371         Automator::wait(50);
1372     };
1373 
1374     {
1375         // Case: cancel(QFuture) which could be finished without error
1376         QFuture<void> future;
1377 
1378         {
1379             auto d = deferred<void>();
1380             future = d.future();
1381 
1382             // d is destroyed but complete(QFuture) increased the ref count and therefore it won't be canceled
1383             d.cancel(QtConcurrent::run(timeout));
1384         }
1385 
1386         QCOMPARE(future.isFinished(), false);
1387         QCOMPARE(future.isCanceled(), false);
1388 
1389         waitUntil(future);
1390 
1391         QCOMPARE(future.isFinished(), true);
1392         QCOMPARE(future.isCanceled(), true);
1393     }
1394 
1395     {
1396         // case: complete(future) which will be canceled.
1397 
1398         auto completeSource = deferred<void>();
1399         auto cancelSource = deferred<void>();
1400 
1401         // Case: complete(QFuture) which could will be canceled
1402         QFuture<void> future;
1403         {
1404             auto d = deferred<void>();
1405             future = d.future();
1406             d.complete(completeSource.future());
1407             d.cancel(cancelSource.future());
1408         }
1409 
1410         QCOMPARE(future.isFinished(), false);
1411         QCOMPARE(future.isCanceled(), false);
1412 
1413         cancelSource.cancel();
1414 
1415         QCOMPARE(future.isFinished(), false);
1416         QCOMPARE(future.isCanceled(), false);
1417 
1418         waitUntil(future, 500);
1419 
1420         QCOMPARE(future.isFinished(), false);
1421         QCOMPARE(future.isCanceled(), false);
1422         // It won't reponse to a canceled future
1423 
1424         // However, if you didn't call complete(), the future will be canceled due to ref count system
1425 
1426         completeSource.complete();
1427         QVERIFY(waitUntil(future, 1000));
1428 
1429         QCOMPARE(future.isFinished(), true);
1430         QCOMPARE(future.isCanceled(), false);
1431     }
1432 }
1433 
test_Deferred_future_cancel()1434 void Spec::test_Deferred_future_cancel()
1435 {
1436     {
1437         int canceledCount = 0;
1438 
1439         auto defer = deferred<void>();
1440 
1441         defer.onCanceled([&]() {
1442             canceledCount++;
1443         });
1444 
1445         defer.future().cancel();
1446         Automator::wait(50);
1447 
1448         auto future = defer.future();
1449 
1450         QTRY_COMPARE(canceledCount, 1);
1451         Automator::wait(50);
1452 
1453         QCOMPARE(future.isCanceled(), true);
1454         QCOMPARE(future.isFinished(), false);
1455     }
1456 
1457 
1458 }
1459 
test_Deferred_across_thread()1460 void Spec::test_Deferred_across_thread()
1461 {
1462     auto defer = deferred<int>();
1463 
1464     auto worker = [=]() mutable {
1465         Automator::wait(50);
1466         defer.complete(99);
1467     };
1468 
1469     QtConcurrent::run(worker);
1470 
1471     Test::waitUntil(defer.future());
1472     QCOMPARE(defer.future().result(), 99);
1473 }
1474 
test_Deferred_inherit()1475 void Spec::test_Deferred_inherit()
1476 {
1477     class CustomDeferredVoid : public Deferred<void> {
1478     public:
1479         CustomDeferredVoid() {
1480             deferredFuture->setProgressRange(0, 3);
1481         }
1482     };
1483 
1484     class CustomDeferredInt : public Deferred<int> {
1485     public:
1486         CustomDeferredInt() {
1487             deferredFuture->setProgressRange(0, 3);
1488         }
1489 
1490         void reportResult(int value, int index) {
1491             int progressValue = future().progressValue();
1492             deferredFuture->reportResult(value, index);
1493             deferredFuture->setProgressValue(progressValue + 1);
1494         }
1495     };
1496 
1497     CustomDeferredInt defer;
1498     QCOMPARE(defer.future().progressValue(), 0);
1499     QList<int> progressList;
1500 
1501     QFutureWatcher<int> watcher;
1502     connect(&watcher, &QFutureWatcher<int>::progressValueChanged, [&](int value) {
1503         progressList << value;
1504     });
1505     watcher.setFuture(defer.future());
1506 
1507     defer.reportResult(2, 2);
1508     QCOMPARE(defer.future().progressValue(), 1);
1509 
1510     defer.reportResult(1, 1);
1511     QCOMPARE(defer.future().progressValue(), 2);
1512 
1513     defer.reportResult(3, 0);
1514     QCOMPARE(defer.future().progressValue(), 3);
1515 
1516     QVERIFY(!defer.future().isFinished());
1517 
1518 // If you call the following code, valgrind could complains memory leakage in reportResult().
1519 // Reference: https://www.travis-ci.org/benlau/asyncfuture/builds/246818440
1520 /*
1521     QList<int> expected;
1522     expected << 0 << 1 << 2;
1523     defer.complete(expected);
1524 
1525     QVERIFY(defer.future().results() == expected);
1526 */
1527     Automator::wait(100);
1528     QVERIFY(progressList.size() > 1);
1529     QVERIFY(progressList.size() < 3);
1530     for (int i = 0 ; i < progressList.size() - 1;i++) {
1531         QVERIFY(progressList[i] < progressList[i+1]);
1532     }
1533 }
1534 
test_Deferred_track()1535 void Spec::test_Deferred_track()
1536 {
1537     class CustomDeferred : public Deferred<int> {
1538     public:
1539         AsyncFuture::Private::DeferredFuture<int>* deferred() const {
1540             return deferredFuture.data();
1541         }
1542     };
1543 
1544     CustomDeferred cd;
1545     cd.deferred()->setProgressRange(0, 10);
1546 
1547     AsyncFuture::Deferred<int> defer;
1548     defer.track(cd.future());
1549 
1550     QCOMPARE(defer.future().progressMaximum(), 10);
1551     QCOMPARE(defer.future().progressValue(), 0);
1552 
1553     cd.deferred()->setProgressValue(1);
1554 
1555     QTRY_COMPARE(defer.future().progressMaximum(), 10);
1556     QTRY_COMPARE(defer.future().progressValue(), 1);
1557 
1558     cd.deferred()->setProgressValue(10);
1559     Automator::wait(10);
1560 
1561     QCOMPARE(defer.future().progressMaximum(), 10);
1562     QCOMPARE(defer.future().progressValue(), 10);
1563     QVERIFY(!defer.future().isFinished());
1564 
1565 }
1566 
test_Deferred_track_started()1567 void Spec::test_Deferred_track_started()
1568 {
1569     QFuture<void> future;
1570     QFutureWatcher<void> watcher;
1571 
1572     QList<int> input;
1573     input << 0 << 1 << 2;
1574 
1575     future = observe(QtConcurrent::run([=]() { })).subscribe([=]() {
1576         return QtConcurrent::map(input , square);
1577     }).future();
1578 
1579     bool started = false;
1580 
1581     connect(&watcher, &QFutureWatcher<void>::started, [&]() {
1582         started = true;
1583     });
1584 
1585     watcher.setFuture(future);
1586 
1587     QTRY_COMPARE(started, true);
1588 
1589     await(future, 1000);
1590     QCOMPARE(future.isFinished(), true);
1591 }
1592 
test_Deferred_setProgress()1593 void Spec::test_Deferred_setProgress()
1594 {
1595     class CustomDeferred : public Deferred<void> {
1596     public:
1597         CustomDeferred() {
1598         }
1599 
1600         void setProgressRange(int minimum, int maximum) {
1601             deferredFuture->setProgressRange(minimum, maximum);
1602         }
1603 
1604         void setProgressValue(int value) {
1605             deferredFuture->setProgressValue(value);
1606         }
1607     };
1608 
1609     CustomDeferred defer;
1610 
1611     QCOMPARE(defer.future().progressMaximum(), 0);
1612     QCOMPARE(defer.future().progressMinimum(), 0);
1613     QCOMPARE(defer.future().progressValue(), 0);
1614 
1615     defer.setProgressRange(2,10);
1616     defer.setProgressValue(3);
1617 
1618     QCOMPARE(defer.future().progressMaximum(), 10);
1619     QCOMPARE(defer.future().progressMinimum(), 2);
1620     QCOMPARE(defer.future().progressValue(), 3);
1621 }
1622 
test_Deferred_reportStarted()1623 void Spec::test_Deferred_reportStarted()
1624 {
1625     {
1626         auto defer = deferred<void>();
1627 
1628         Counter started;
1629         QFutureWatcher<void> watcher;
1630 
1631         connect(&watcher, &QFutureWatcher<void>::started, started());
1632         watcher.setFuture(defer.future());
1633 
1634         defer.reportStarted();
1635 
1636         Automator::wait(10);
1637 
1638         QCOMPARE(started.called, 1);
1639     }
1640 
1641     {
1642         auto defer = deferred<int>();
1643 
1644         Counter started;
1645         QFutureWatcher<void> watcher;
1646 
1647         connect(&watcher, &QFutureWatcher<void>::started, started());
1648         watcher.setFuture(defer.future());
1649 
1650         defer.reportStarted();
1651 
1652         Automator::wait(10);
1653 
1654         QCOMPARE(started.called, 1);
1655     }
1656 
1657 }
1658 
test_Combinator()1659 void Spec::test_Combinator()
1660 {
1661     {
1662         // case: all completed
1663         auto d1 = deferred<int>();
1664         auto d2 = deferred<QString>();
1665         auto d3 = deferred<void>();
1666         auto c = Callable<void>();
1667 
1668         auto combinator = combine();
1669         combinator << d1.future() << d2.future() << d3.future();
1670 
1671         QFuture<void> future = combinator.future();
1672 
1673         observe(future).subscribe(c.func);
1674 
1675         d1.complete(1);
1676         d2.complete("second");
1677         d3.complete();
1678 
1679         QCOMPARE(c.called, false);
1680         QCOMPARE(future.isFinished(), false);
1681 
1682         QVERIFY(waitUntil(future,1000));
1683 
1684         QCOMPARE(c.called, true);
1685         QCOMPARE(future.isFinished(), true);
1686     }
1687 
1688 
1689     {
1690         // case: all completed (but Combinator was destroyed )
1691         QFuture<void> future ;
1692 
1693         auto d1 = deferred<int>();
1694         auto d2 = deferred<QString>();
1695         auto d3 = deferred<void>();
1696         auto c = Callable<void>();
1697 
1698         {
1699             future = (combine() << d1.future() << d2.future() << d3.future()).future();
1700         }
1701 
1702         observe(future).subscribe(c.func);
1703 
1704         d1.complete(1);
1705         d2.complete("second");
1706         d3.complete();
1707 
1708         QCOMPARE(c.called, false);
1709         QCOMPARE(future.isFinished(), false);
1710 
1711         QVERIFY(waitUntil(future,1000));
1712 
1713         QCOMPARE(future.isFinished(), true);
1714         QCOMPARE(c.called, true);
1715     }
1716 
1717     {
1718         // case: combine(false), cancel
1719         auto d1 = deferred<int>();
1720         auto d2 = deferred<QString>();
1721         auto d3 = deferred<void>();
1722 
1723         auto combinator = combine();
1724         combinator << d1.future() << d2.future() << d3.future();
1725 
1726         QFuture<void> future = combinator.future();
1727 
1728         Callable<void> canceled;
1729 
1730         observe(future).subscribe([](){}, canceled.func);
1731 
1732         d1.complete(2);
1733         d2.cancel();
1734 
1735         QVERIFY(waitUntil(future,1000));
1736 
1737         QCOMPARE(future.isFinished(), true);
1738         QCOMPARE(future.isCanceled(), true);
1739         QCOMPARE(canceled.called, true);
1740     }
1741 
1742     {
1743         // case: combine(true), cancel
1744         auto d1 = deferred<int>();
1745         auto d2 = deferred<QString>();
1746         auto d3 = deferred<void>();
1747 
1748         auto combinator = combine(AllSettled);
1749         combinator << d1.future() << d2.future() << d3.future();
1750 
1751         QFuture<void> future = combinator.future();
1752 
1753         Callable<void> completed;
1754         Callable<void> canceled;
1755 
1756         observe(future).subscribe(completed.func, canceled.func);
1757 
1758         d1.complete(2);
1759         d2.cancel();
1760 
1761         QVERIFY(!waitUntil(future,1000));
1762 
1763         QCOMPARE(future.isFinished(), false);
1764         QCOMPARE(future.isCanceled(), false);
1765 
1766         QCOMPARE(canceled.called, false);
1767         d3.complete();
1768 
1769         QVERIFY(waitUntil(future,1000));
1770         QCOMPARE(future.isFinished(), true);
1771         QCOMPARE(future.isCanceled(), true);
1772         QCOMPARE(canceled.called, true);
1773     }
1774 
1775     {
1776         // ccombinator << Deferred << Deferred
1777         auto d1 = deferred<int>();
1778         auto d2 = deferred<QString>();
1779         auto d3 = deferred<void>();
1780 
1781         auto combinator = combine(AllSettled);
1782         combinator << d1 << d2 << d3;
1783 
1784         QFuture<void> future = combinator.future();
1785 
1786         Callable<void> completed;
1787         Callable<void> canceled;
1788 
1789         observe(future).subscribe(completed.func, canceled.func);
1790 
1791         d1.complete(2);
1792         d2.cancel();
1793 
1794         QVERIFY(!waitUntil(future,1000));
1795 
1796         QCOMPARE(future.isFinished(), false);
1797         QCOMPARE(future.isCanceled(), false);
1798 
1799         QCOMPARE(canceled.called, false);
1800         d3.complete();
1801 
1802         QVERIFY(waitUntil(future,1000));
1803         QCOMPARE(future.isFinished(), true);
1804         QCOMPARE(future.isCanceled(), true);
1805         QCOMPARE(canceled.called, true);
1806 
1807 
1808     }
1809 
1810 }
1811 
test_Combinator_add_to_already_finished()1812 void Spec::test_Combinator_add_to_already_finished()
1813 {
1814     {
1815         // case: combine(true), cancel
1816         auto d1 = deferred<int>();
1817         auto d2 = deferred<QString>();
1818         auto d3 = deferred<void>();
1819         auto d4 = deferred<bool>();
1820 
1821         Combinator copy;
1822 
1823         {
1824             auto combinator = combine();
1825             copy = combinator;
1826 
1827             combinator << d1.future() << d2.future() << d3.future();
1828 
1829             d1.complete(1);
1830             d2.complete("second");
1831             d3.complete();
1832 
1833             QVERIFY(waitUntil(combinator.future(), 1000));
1834         }
1835 
1836         copy << d4.future();
1837         d4.complete(true);
1838 
1839         QVERIFY(waitUntil(copy.future(), 1000)); // It is already resolved
1840     }
1841 }
1842 
test_Combinator_progressValue()1843 void Spec::test_Combinator_progressValue()
1844 {
1845 
1846     {
1847         auto d1 = timeout(50);
1848         auto d2 = timeout(60);
1849         auto d3 = timeout(30);
1850 
1851         auto combinator = combine();
1852 
1853         auto future = combinator.future();
1854 
1855         QCOMPARE(future.progressValue(), 0);
1856         QCOMPARE(future.progressMaximum(), 0);
1857 
1858         combinator << d1 << d2 << d3;
1859 
1860         QCOMPARE(future.progressValue(), 0);
1861         QCOMPARE(future.progressMaximum(), 3);
1862 
1863         await(future);
1864 
1865         QCOMPARE(future.progressValue(), 3);
1866         QCOMPARE(future.progressMaximum(), 3);
1867 
1868     }
1869 
1870 }
1871 
test_alive()1872 void Spec::test_alive()
1873 {
1874 
1875     {
1876         auto d1 = deferred<TrackingData>();
1877         auto d2 = deferred<TrackingData>();
1878 
1879         d2.complete(d1.future());
1880 
1881         QCOMPARE(TrackingData::aliveCount(), 0);
1882 
1883         {
1884             TrackingData dummy;
1885             d1.complete(dummy);
1886             QCOMPARE(TrackingData::aliveCount(), 1);
1887         }
1888 
1889         QCOMPARE(TrackingData::aliveCount(), 1);
1890 
1891         await(d2.future());
1892         Automator::wait(10);
1893     }
1894 
1895     Automator::wait(10);
1896     QCOMPARE(TrackingData::aliveCount(), 0);
1897 
1898 }
1899