summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorSona Kurazyan <sona.kurazyan@qt.io>2021-11-10 09:36:26 +0100
committerSona Kurazyan <sona.kurazyan@qt.io>2021-12-02 11:24:54 +0100
commit9a9d960b123c83178eb2ac48a91178be6cbaabcf (patch)
tree8925e98a1d99d68ec876eb8f5cf4194086e6082f /tests
parentec613a4649844e0eaa2a64444732eef7eeef2b81 (diff)
QFuture: support cancellation of continuation chain through parent
This change allows canceling the chain of continuations attached to a future through canceling the future itself at any point of execution of the chain. [ChangeLog][QtCore][Important Behavior Changes] The chain of continuations attached to a future now can be cancelled through cancelling the future itself at any point of the execution of the chain, as it was documented. Previously canceling the future would cancel the chain only if it was done before the chain starts executing, otherwise the cancellation would be ignored. Now the part of the chain that wasn't started at the moment of cancellation will be canceled. Task-number: QTBUG-97582 Change-Id: I4c3b3c68e34d3a044243ac9a7a9ed3c38b7cb02e Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io> (cherry picked from commit eab40726be98616b7edac3a600e97b39fc6227cd)
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/corelib/thread/qfuture/tst_qfuture.cpp126
1 files changed, 126 insertions, 0 deletions
diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
index f5618b0a07..3feb3f66c0 100644
--- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
+++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
@@ -142,6 +142,7 @@ private slots:
void onFailedForMoveOnlyTypes();
#endif
void onCanceled();
+ void cancelContinuations();
void continuationsWithContext();
#if 0
// TODO: enable when QFuture::takeResults() is enabled
@@ -2845,6 +2846,131 @@ void tst_QFuture::onCanceled()
#endif // QT_NO_EXCEPTIONS
}
+void tst_QFuture::cancelContinuations()
+{
+ // The chain is cancelled in the middle of execution of continuations
+ {
+ QPromise<int> promise;
+
+ int checkpoint = 0;
+ auto future = promise.future().then([&](int value) {
+ ++checkpoint;
+ return value + 1;
+ }).then([&](int value) {
+ ++checkpoint;
+ promise.future().cancel();
+ return value + 1;
+ }).then([&](int value) {
+ ++checkpoint;
+ return value + 1;
+ }).onCanceled([] {
+ return -1;
+ });
+
+ promise.start();
+ promise.addResult(42);
+ promise.finish();
+
+ QCOMPARE(future.result(), -1);
+ QCOMPARE(checkpoint, 2);
+ }
+
+ // The chain is cancelled before the execution of continuations
+ {
+ auto f = QtFuture::makeReadyFuture(42);
+ f.cancel();
+
+ int checkpoint = 0;
+ auto future = f.then([&](int value) {
+ ++checkpoint;
+ return value + 1;
+ }).then([&](int value) {
+ ++checkpoint;
+ return value + 1;
+ }).then([&](int value) {
+ ++checkpoint;
+ return value + 1;
+ }).onCanceled([] {
+ return -1;
+ });
+
+ QCOMPARE(future.result(), -1);
+ QCOMPARE(checkpoint, 0);
+ }
+
+ // The chain is canceled partially, through an intermediate future
+ {
+ QPromise<int> promise;
+
+ int checkpoint = 0;
+ auto intermediate = promise.future().then([&](int value) {
+ ++checkpoint;
+ return value + 1;
+ });
+
+ auto future = intermediate.then([&](int value) {
+ ++checkpoint;
+ return value + 1;
+ }).then([&](int value) {
+ ++checkpoint;
+ return value + 1;
+ }).onCanceled([] {
+ return -1;
+ });
+
+ promise.start();
+ promise.addResult(42);
+
+ // This should cancel only the chain starting from intermediate
+ intermediate.cancel();
+
+ promise.finish();
+
+ QCOMPARE(future.result(), -1);
+ QCOMPARE(checkpoint, 1);
+ }
+
+#ifndef QT_NO_EXCEPTIONS
+ // The chain is cancelled in the middle of execution of continuations,
+ // while there's an exception in the chain, which is handeled inside
+ // the continuations.
+ {
+ QPromise<int> promise;
+
+ int checkpoint = 0;
+ auto future = promise.future().then([&](int value) {
+ ++checkpoint;
+ throw QException();
+ return value + 1;
+ }).then([&](QFuture<int> future) {
+ try {
+ auto res = future.result();
+ Q_UNUSED(res);
+ } catch (const QException &) {
+ ++checkpoint;
+ }
+ return 2;
+ }).then([&](int value) {
+ ++checkpoint;
+ promise.future().cancel();
+ return value + 1;
+ }).then([&](int value) {
+ ++checkpoint;
+ return value + 1;
+ }).onCanceled([] {
+ return -1;
+ });
+
+ promise.start();
+ promise.addResult(42);
+ promise.finish();
+
+ QCOMPARE(future.result(), -1);
+ QCOMPARE(checkpoint, 3);
+ }
+#endif // QT_NO_EXCEPTIONS
+}
+
void tst_QFuture::continuationsWithContext()
{
QThread thread;