diff options
author | Jarek Kobus <jaroslaw.kobus@qt.io> | 2020-09-29 16:50:01 +0200 |
---|---|---|
committer | Jarek Kobus <jaroslaw.kobus@qt.io> | 2020-10-30 10:14:48 +0100 |
commit | cc0be95ac782c9cf0bf994d0af6e2966cf29f8fa (patch) | |
tree | c98680e4bf18f05f1825d903f89dc44eec56eb56 | |
parent | cde42e2f762aa3fed1af7e26bbacc46deefc43bb (diff) |
QtConcurrent: Provide a test for runWithPromise with handlers
Test runWithPromise with "then" and "onCanceled" handlers.
Test the case when QFuture::cancel() is being called when
the task's thread already started, so that a call to
QPromise::isCanceled() from inside the running thread
returns different values in the same task's run. This nicely
proves that communication between QFuture and QPromise
works between different threads.
Task-number: QTBUG-84868
Change-Id: Icb2e0b1f99e2dcd919d881515f1ccd08e2f25b8c
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
-rw-r--r-- | tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp | 111 |
1 files changed, 110 insertions, 1 deletions
diff --git a/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp b/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp index 1132954a82..01b7c1b895 100644 --- a/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp +++ b/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp @@ -26,8 +26,11 @@ ** ****************************************************************************/ #include <qtconcurrentrun.h> -#include <qfuture.h> +#include <QFuture> +#include <QMutex> +#include <QMutexLocker> #include <QString> +#include <QWaitCondition> #include <QtTest/QtTest> using namespace QtConcurrent; @@ -55,6 +58,7 @@ private slots: void callableObjectWithState(); void withPromise(); void withPromiseInThreadPool(); + void withPromiseAndThen(); void moveOnlyType(); void crefFunction(); void customPromise(); @@ -1346,6 +1350,111 @@ void tst_QtConcurrentRun::withPromiseInThreadPool() QList<QString>({QString(QLatin1String("rvalue"))})); } +void tst_QtConcurrentRun::withPromiseAndThen() +{ + bool runExecuted = false; + bool cancelReceivedBeforeSync = false; + bool cancelReceivedAfterSync = false; + + bool syncBegin = false; + bool syncEnd = false; + + QMutex mutex; + QWaitCondition condition; + + auto reset = [&]() { + runExecuted = false; + cancelReceivedBeforeSync = false; + cancelReceivedAfterSync = false; + syncBegin = false; + syncEnd = false; + }; + + auto setFlag = [&mutex, &condition] (bool &flag) { + QMutexLocker locker(&mutex); + flag = true; + condition.wakeOne(); + }; + + auto waitForFlag = [&mutex, &condition] (const bool &flag) { + QMutexLocker locker(&mutex); + while (!flag) + condition.wait(&mutex); + }; + + auto report1WithCancel = [&](QPromise<int> &promise) { + runExecuted = true; + cancelReceivedBeforeSync = promise.isCanceled(); + + setFlag(syncBegin); + waitForFlag(syncEnd); + + cancelReceivedAfterSync = promise.isCanceled(); + if (cancelReceivedAfterSync) + return; + promise.addResult(1); + }; + + { + auto future = run(report1WithCancel); + + waitForFlag(syncBegin); + future.cancel(); + setFlag(syncEnd); + + future.waitForFinished(); + QCOMPARE(future.results().count(), 0); + QVERIFY(runExecuted); + QVERIFY(!cancelReceivedBeforeSync); + QVERIFY(cancelReceivedAfterSync); + } + + reset(); + + { + bool thenExecuted = false; + bool cancelExecuted = false; + auto future = run(report1WithCancel); + auto resultFuture = future.then(QtFuture::Launch::Async, [&](int) { thenExecuted = true; }) + .onCanceled([&]() { cancelExecuted = true; }); + + waitForFlag(syncBegin); + // no cancel this time + setFlag(syncEnd); + + resultFuture.waitForFinished(); + QCOMPARE(future.results().count(), 1); + QCOMPARE(future.result(), 1); + QVERIFY(runExecuted); + QVERIFY(thenExecuted); + QVERIFY(!cancelExecuted); + QVERIFY(!cancelReceivedBeforeSync); + QVERIFY(!cancelReceivedAfterSync); + } + + reset(); + + { + bool thenExecuted = false; + bool cancelExecuted = false; + auto future = run(report1WithCancel); + auto resultFuture = future.then(QtFuture::Launch::Async, [&](int) { thenExecuted = true; }) + .onCanceled([&]() { cancelExecuted = true; }); + + waitForFlag(syncBegin); + future.cancel(); + setFlag(syncEnd); + + resultFuture.waitForFinished(); + QCOMPARE(future.results().count(), 0); + QVERIFY(runExecuted); + QVERIFY(!thenExecuted); + QVERIFY(cancelExecuted); + QVERIFY(!cancelReceivedBeforeSync); + QVERIFY(cancelReceivedAfterSync); + } +} + class MoveOnlyType { public: |