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.cpp256
1 files changed, 191 insertions, 65 deletions
diff --git a/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp b/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp
index 52f4daa24a..2c12e41c93 100644
--- a/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp
+++ b/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QCoreApplication>
#include <QDebug>
@@ -39,6 +14,8 @@
#include <memory>
#include <chrono>
+using namespace std::chrono_literals;
+
class tst_QPromise : public QObject
{
Q_OBJECT
@@ -47,6 +24,7 @@ private slots:
void promise();
void futureFromPromise();
void addResult();
+ void addResultWithBracedInitializer();
void addResultOutOfOrder();
#ifndef QT_NO_EXCEPTIONS
void setException();
@@ -64,6 +42,10 @@ private slots:
void cancelWhenDestroyed();
#endif
void cancelWhenReassigned();
+ void cancelWhenDestroyedWithoutStarting();
+ void cancelWhenDestroyedRunsContinuations();
+ void cancelWhenDestroyedWithFailureHandler(); // QTBUG-114606
+ void continuationsRunWhenFinished();
void finishWhenSwapped();
void cancelWhenMoved();
void waitUntilResumed();
@@ -191,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;
@@ -208,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
@@ -279,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
@@ -292,6 +309,8 @@ void tst_QPromise::cancel()
testCancel(QPromise<void>());
testCancel(QPromise<int>());
+ testCancel(QPromise<CopyOnlyType>());
+ testCancel(QPromise<MoveOnlyType>());
}
void tst_QPromise::progress()
@@ -319,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();
@@ -346,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();
@@ -365,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();
@@ -391,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();
{
@@ -425,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();
@@ -444,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();
@@ -486,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
});
@@ -505,11 +514,123 @@ void tst_QPromise::cancelWhenReassigned()
#endif
}
-void tst_QPromise::finishWhenSwapped()
+template <typename T>
+static inline void testCancelWhenDestroyedWithoutStarting()
{
-#if !QT_CONFIG(cxx11_future)
- QSKIP("This test requires QThread::create");
+ QFuture<T> future;
+ {
+ QPromise<T> promise;
+ future = promise.future();
+ }
+ future.waitForFinished();
+ QVERIFY(!future.isStarted());
+ QVERIFY(future.isCanceled());
+ QVERIFY(future.isFinished());
+}
+
+void tst_QPromise::cancelWhenDestroyedWithoutStarting()
+{
+ testCancelWhenDestroyedWithoutStarting<void>();
+ testCancelWhenDestroyedWithoutStarting<int>();
+ testCancelWhenDestroyedWithoutStarting<CopyOnlyType>();
+ testCancelWhenDestroyedWithoutStarting<MoveOnlyType>();
+}
+
+template <typename T>
+static inline void testCancelWhenDestroyedRunsContinuations()
+{
+ QFuture<T> future;
+ bool onCanceledCalled = false;
+ bool thenCalled = false;
+ {
+ QPromise<T> promise;
+ future = promise.future();
+ future.then([&] (auto&&) {
+ thenCalled = true;
+ }).onCanceled([&] () {
+ onCanceledCalled = true;
+ });
+ }
+ QVERIFY(future.isFinished());
+ QVERIFY(!thenCalled);
+ QVERIFY(onCanceledCalled);
+}
+
+void tst_QPromise::cancelWhenDestroyedRunsContinuations()
+{
+ 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();
@@ -519,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
@@ -547,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
});
@@ -580,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)
@@ -598,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();
@@ -611,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();
@@ -627,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();