summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJarek Kobus <jaroslaw.kobus@qt.io>2020-09-29 16:50:01 +0200
committerJarek Kobus <jaroslaw.kobus@qt.io>2020-10-30 10:14:48 +0100
commitcc0be95ac782c9cf0bf994d0af6e2966cf29f8fa (patch)
treec98680e4bf18f05f1825d903f89dc44eec56eb56
parentcde42e2f762aa3fed1af7e26bbacc46deefc43bb (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.cpp111
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: