diff options
Diffstat (limited to 'tests/auto/corelib/thread/qpromise/tst_qpromise.cpp')
-rw-r--r-- | tests/auto/corelib/thread/qpromise/tst_qpromise.cpp | 256 |
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(); |