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