summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/thread/qpromise/tst_qpromise.cpp')
-rw-r--r--tests/auto/corelib/thread/qpromise/tst_qpromise.cpp211
1 files changed, 164 insertions, 47 deletions
diff --git a/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp b/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp
index 12206aa9fc..2c12e41c93 100644
--- a/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp
+++ b/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QCoreApplication>
#include <QDebug>
@@ -14,6 +14,8 @@
#include <memory>
#include <chrono>
+using namespace std::chrono_literals;
+
class tst_QPromise : public QObject
{
Q_OBJECT
@@ -22,6 +24,7 @@ private slots:
void promise();
void futureFromPromise();
void addResult();
+ void addResultWithBracedInitializer();
void addResultOutOfOrder();
#ifndef QT_NO_EXCEPTIONS
void setException();
@@ -41,6 +44,8 @@ private slots:
void cancelWhenReassigned();
void cancelWhenDestroyedWithoutStarting();
void cancelWhenDestroyedRunsContinuations();
+ void cancelWhenDestroyedWithFailureHandler(); // QTBUG-114606
+ void continuationsRunWhenFinished();
void finishWhenSwapped();
void cancelWhenMoved();
void waitUntilResumed();
@@ -168,6 +173,15 @@ void tst_QPromise::addResult()
QCOMPARE(f.resultCount(), 3);
QCOMPARE(f.resultAt(2), result);
}
+ // add multiple results in one go:
+ {
+ QList results = {42, 4242, 424242};
+ QVERIFY(promise.addResults(results));
+ QCOMPARE(f.resultCount(), 6);
+ QCOMPARE(f.resultAt(3), 42);
+ QCOMPARE(f.resultAt(4), 4242);
+ QCOMPARE(f.resultAt(5), 424242);
+ }
// add as lvalue at position and overwrite
{
int result = -1;
@@ -185,6 +199,28 @@ void tst_QPromise::addResult()
}
}
+void tst_QPromise::addResultWithBracedInitializer() // QTBUG-111826
+{
+ struct MyClass
+ {
+ QString strValue;
+ int intValue = 0;
+#ifndef __cpp_aggregate_paren_init // make emplacement work with MyClass
+ MyClass(QString s, int i) : strValue(std::move(s)), intValue(i) {}
+#endif
+ };
+
+ {
+ QPromise<MyClass> myPromise;
+ myPromise.addResult({"bar", 1});
+ }
+
+ {
+ QPromise<MyClass> myPromise;
+ myPromise.emplaceResult("bar", 1);
+ }
+}
+
void tst_QPromise::addResultOutOfOrder()
{
// Compare results available in QFuture to expected results
@@ -256,6 +292,10 @@ void tst_QPromise::setException()
std::make_exception_ptr(TestException()));
RUN_TEST_FUNC(testExceptionCaught, QPromise<int>(),
std::make_exception_ptr(TestException()));
+ RUN_TEST_FUNC(testExceptionCaught, QPromise<CopyOnlyType>(),
+ std::make_exception_ptr(TestException()));
+ RUN_TEST_FUNC(testExceptionCaught, QPromise<MoveOnlyType>(),
+ std::make_exception_ptr(TestException()));
}
#endif
@@ -269,6 +309,8 @@ void tst_QPromise::cancel()
testCancel(QPromise<void>());
testCancel(QPromise<int>());
+ testCancel(QPromise<CopyOnlyType>());
+ testCancel(QPromise<MoveOnlyType>());
}
void tst_QPromise::progress()
@@ -296,13 +338,13 @@ void tst_QPromise::progress()
RUN_TEST_FUNC(testProgress, QPromise<void>());
RUN_TEST_FUNC(testProgress, QPromise<int>());
+ RUN_TEST_FUNC(testProgress, QPromise<CopyOnlyType>());
+ RUN_TEST_FUNC(testProgress, QPromise<MoveOnlyType>());
}
void tst_QPromise::addInThread()
{
-#if !QT_CONFIG(cxx11_future)
- QSKIP("This test requires QThread::create");
-#else
+#if QT_CONFIG(cxx11_future)
const auto testAddResult = [] (auto promise, const auto &result) {
promise.start();
auto f = promise.future();
@@ -323,9 +365,7 @@ void tst_QPromise::addInThread()
void tst_QPromise::addInThreadMoveOnlyObject()
{
-#if !QT_CONFIG(cxx11_future)
- QSKIP("This test requires QThread::create");
-#else
+#if QT_CONFIG(cxx11_future)
QPromise<MoveOnlyType> promise;
promise.start();
auto f = promise.future();
@@ -342,9 +382,7 @@ void tst_QPromise::addInThreadMoveOnlyObject()
void tst_QPromise::reportFromMultipleThreads()
{
-#if !QT_CONFIG(cxx11_future)
- QSKIP("This test requires QThread::create");
-#else
+#if QT_CONFIG(cxx11_future)
QPromise<int> promise;
auto f = promise.future();
promise.start();
@@ -368,9 +406,7 @@ void tst_QPromise::reportFromMultipleThreads()
void tst_QPromise::reportFromMultipleThreadsByMovedPromise()
{
-#if !QT_CONFIG(cxx11_future)
- QSKIP("This test requires QThread::create");
-#else
+#if QT_CONFIG(cxx11_future)
QPromise<int> initialPromise;
auto f = initialPromise.future();
{
@@ -402,9 +438,7 @@ void tst_QPromise::reportFromMultipleThreadsByMovedPromise()
void tst_QPromise::doNotCancelWhenFinished()
{
-#if !QT_CONFIG(cxx11_future)
- QSKIP("This test requires QThread::create");
-#else
+#if QT_CONFIG(cxx11_future)
const auto testFinishedPromise = [] (auto promise) {
auto f = promise.future();
promise.start();
@@ -421,15 +455,15 @@ void tst_QPromise::doNotCancelWhenFinished()
RUN_TEST_FUNC(testFinishedPromise, QPromise<void>());
RUN_TEST_FUNC(testFinishedPromise, QPromise<int>());
RUN_TEST_FUNC(testFinishedPromise, QPromise<QString>());
+ RUN_TEST_FUNC(testFinishedPromise, QPromise<CopyOnlyType>());
+ RUN_TEST_FUNC(testFinishedPromise, QPromise<MoveOnlyType>());
#endif
}
#ifndef QT_NO_EXCEPTIONS
void tst_QPromise::cancelWhenDestroyed()
{
-#if !QT_CONFIG(cxx11_future)
- QSKIP("This test requires QThread::create");
-#else
+#if QT_CONFIG(cxx11_future)
QPromise<int> initialPromise;
auto f = initialPromise.future();
@@ -463,15 +497,13 @@ void tst_QPromise::cancelWhenDestroyed()
void tst_QPromise::cancelWhenReassigned()
{
-#if !QT_CONFIG(cxx11_future)
- QSKIP("This test requires QThread::create");
-#else
+#if QT_CONFIG(cxx11_future)
QPromise<int> promise;
auto f = promise.future();
promise.start();
ThreadWrapper thr([p = std::move(promise)] () mutable {
- QThread::msleep(100);
+ QThread::sleep(100ms);
p = QPromise<int>(); // assign new promise, old must be correctly destroyed
});
@@ -482,11 +514,12 @@ void tst_QPromise::cancelWhenReassigned()
#endif
}
-void tst_QPromise::cancelWhenDestroyedWithoutStarting()
+template <typename T>
+static inline void testCancelWhenDestroyedWithoutStarting()
{
- QFuture<void> future;
+ QFuture<T> future;
{
- QPromise<void> promise;
+ QPromise<T> promise;
future = promise.future();
}
future.waitForFinished();
@@ -495,17 +528,26 @@ void tst_QPromise::cancelWhenDestroyedWithoutStarting()
QVERIFY(future.isFinished());
}
-void tst_QPromise::cancelWhenDestroyedRunsContinuations()
+void tst_QPromise::cancelWhenDestroyedWithoutStarting()
+{
+ testCancelWhenDestroyedWithoutStarting<void>();
+ testCancelWhenDestroyedWithoutStarting<int>();
+ testCancelWhenDestroyedWithoutStarting<CopyOnlyType>();
+ testCancelWhenDestroyedWithoutStarting<MoveOnlyType>();
+}
+
+template <typename T>
+static inline void testCancelWhenDestroyedRunsContinuations()
{
- QFuture<void> future;
+ QFuture<T> future;
bool onCanceledCalled = false;
bool thenCalled = false;
{
- QPromise<void> promise;
+ QPromise<T> promise;
future = promise.future();
- future.then([&] {
+ future.then([&] (auto&&) {
thenCalled = true;
- }).onCanceled([&] {
+ }).onCanceled([&] () {
onCanceledCalled = true;
});
}
@@ -514,11 +556,81 @@ void tst_QPromise::cancelWhenDestroyedRunsContinuations()
QVERIFY(onCanceledCalled);
}
-void tst_QPromise::finishWhenSwapped()
+void tst_QPromise::cancelWhenDestroyedRunsContinuations()
{
-#if !QT_CONFIG(cxx11_future)
- QSKIP("This test requires QThread::create");
+ testCancelWhenDestroyedRunsContinuations<void>();
+ testCancelWhenDestroyedRunsContinuations<int>();
+ testCancelWhenDestroyedRunsContinuations<CopyOnlyType>();
+ testCancelWhenDestroyedRunsContinuations<MoveOnlyType>();
+}
+
+template <typename T>
+static inline void testCancelWhenDestroyedWithFailureHandler()
+{
+ QFuture<T> future;
+ bool onFailedCalled = false;
+ bool thenCalled = false;
+ {
+ QPromise<T> promise;
+ future = promise.future();
+ future
+ .onFailed([&] () {
+ onFailedCalled = true;
+ if constexpr (!std::is_same_v<void, T>)
+ return T{};
+ })
+ .then([&] (auto&&) {
+ thenCalled = true;
+ });
+ }
+ QVERIFY(future.isFinished());
+ QVERIFY(!onFailedCalled);
+ QVERIFY(!thenCalled);
+}
+
+void tst_QPromise::cancelWhenDestroyedWithFailureHandler()
+{
+#ifndef QT_NO_EXCEPTIONS
+ testCancelWhenDestroyedWithFailureHandler<void>();
+ testCancelWhenDestroyedWithFailureHandler<int>();
+ testCancelWhenDestroyedWithFailureHandler<CopyOnlyType>();
+ testCancelWhenDestroyedWithFailureHandler<MoveOnlyType>();
#else
+ QSKIP("Exceptions are disabled, skipping the test");
+#endif
+}
+
+template <typename T>
+static inline void testContinuationsRunWhenFinished()
+{
+ QPromise<T> promise;
+ QFuture<T> future = promise.future();
+
+ bool thenCalled = false;
+ future.then([&] (auto&&) {
+ thenCalled = true;
+ });
+
+ promise.start();
+ if constexpr (!std::is_void_v<T>) {
+ promise.addResult(T{});
+ }
+ promise.finish();
+
+ QVERIFY(thenCalled);
+}
+
+void tst_QPromise::continuationsRunWhenFinished()
+{
+ testContinuationsRunWhenFinished<void>();
+ testContinuationsRunWhenFinished<int>();
+ testContinuationsRunWhenFinished<CopyOnlyType>();
+ testContinuationsRunWhenFinished<MoveOnlyType>();
+}
+
+void tst_QPromise::finishWhenSwapped()
+{
+#if QT_CONFIG(cxx11_future)
QPromise<int> promise1;
auto f1 = promise1.future();
promise1.start();
@@ -528,7 +640,7 @@ void tst_QPromise::finishWhenSwapped()
promise2.start();
ThreadWrapper thr([&promise1, &promise2] () mutable {
- QThread::msleep(100);
+ QThread::sleep(100ms);
promise1.addResult(0);
promise2.addResult(1);
swap(promise1, promise2); // ADL must resolve this
@@ -556,22 +668,21 @@ void tst_QPromise::finishWhenSwapped()
#endif
}
-void tst_QPromise::cancelWhenMoved()
+template <typename T>
+void testCancelWhenMoved()
{
-#if !QT_CONFIG(cxx11_future)
- QSKIP("This test requires QThread::create");
-#else
- QPromise<int> promise1;
+#if QT_CONFIG(cxx11_future)
+ QPromise<T> promise1;
auto f1 = promise1.future();
promise1.start();
- QPromise<int> promise2;
+ QPromise<T> promise2;
auto f2 = promise2.future();
promise2.start();
// Move promises to local scope to test cancellation behavior
ThreadWrapper thr([p1 = std::move(promise1), p2 = std::move(promise2)] () mutable {
- QThread::msleep(100);
+ QThread::sleep(100ms);
p1 = std::move(p2);
p1.finish(); // this finish is for future #2
});
@@ -589,6 +700,14 @@ void tst_QPromise::cancelWhenMoved()
#endif
}
+void tst_QPromise::cancelWhenMoved()
+{
+ testCancelWhenMoved<void>();
+ testCancelWhenMoved<int>();
+ testCancelWhenMoved<CopyOnlyType>();
+ testCancelWhenMoved<MoveOnlyType>();
+}
+
void tst_QPromise::waitUntilResumed()
{
#if !QT_CONFIG(cxx11_future)
@@ -607,7 +726,7 @@ void tst_QPromise::waitUntilResumed()
while (!f.isSuspended()) { // busy wait until worker thread suspends
QCOMPARE(f.isFinished(), false); // exit condition in case of failure
- QThread::msleep(50); // allow another thread to actually carry on
+ QThread::sleep(50ms); // allow another thread to actually carry on
}
f.resume();
@@ -620,9 +739,7 @@ void tst_QPromise::waitUntilResumed()
void tst_QPromise::waitUntilCanceled()
{
-#if !QT_CONFIG(cxx11_future)
- QSKIP("This test requires QThread::create");
-#else
+#if QT_CONFIG(cxx11_future)
QPromise<int> promise;
promise.start();
auto f = promise.future();
@@ -636,7 +753,7 @@ void tst_QPromise::waitUntilCanceled()
while (!f.isSuspended()) { // busy wait until worker thread suspends
QCOMPARE(f.isFinished(), false); // exit condition in case of failure
- QThread::msleep(50); // allow another thread to actually carry on
+ QThread::sleep(50ms); // allow another thread to actually carry on
}
f.cancel();