From 963ec621e1cc11fcb087147f424a558a70d28026 Mon Sep 17 00:00:00 2001 From: Simon Brunel Date: Mon, 25 Feb 2019 20:03:19 +0100 Subject: [PATCH] Rename qPromise() helper to QtPromise::resolve() For consistency with other helpers, deprecate `qPromise()` in favor of `QtPromise::resolve()` but also add support for calling this helper with lvalue. Add extra unit tests to make sure that rvalue is not copied. --- docs/.vuepress/config.js | 2 +- docs/qtpromise/api-reference.md | 6 +- docs/qtpromise/exceptions/canceled.md | 2 +- docs/qtpromise/getting-started.md | 2 +- docs/qtpromise/helpers/qpromise.md | 21 -- docs/qtpromise/helpers/resolve.md | 21 ++ docs/qtpromise/qpromise/resolve.md | 2 +- docs/qtpromise/qpromise/wait.md | 2 +- docs/qtpromise/qtconcurrent.md | 6 +- src/qtpromise/qpromise.inl | 4 +- src/qtpromise/qpromise_p.h | 30 +- src/qtpromise/qpromisehelpers.h | 42 ++- .../qtpromise/benchmark/tst_benchmark.cpp | 94 +----- .../qtpromise/deprecations/deprecations.pri | 5 + .../qtpromise/deprecations/deprecations.pro | 3 + .../deprecations/helpers/helpers.pro | 3 + .../helpers/qpromise/qpromise.pro | 5 + .../helpers/qpromise/tst_qpromise.cpp | 268 ++++++++++++++++++ .../qtpromise/exceptions/tst_exceptions.cpp | 2 +- tests/auto/qtpromise/future/tst_future.cpp | 26 +- tests/auto/qtpromise/helpers/all/tst_all.cpp | 42 +-- .../qtpromise/helpers/attempt/tst_attempt.cpp | 2 +- .../qtpromise/helpers/resolve/resolve.pro | 1 + .../qtpromise/helpers/resolve/tst_resolve.cpp | 254 +++++++++++++---- .../auto/qtpromise/qpromise/each/tst_each.cpp | 4 +- .../qtpromise/qpromise/filter/tst_filter.cpp | 2 +- tests/auto/qtpromise/qpromise/map/tst_map.cpp | 24 +- tests/auto/qtpromise/qpromise/qpromise.pro | 1 + .../qtpromise/qpromise/resolve/resolve.pro | 4 + .../qpromise/resolve/tst_resolve.cpp | 165 +++++++++++ tests/auto/qtpromise/qtpromise.pri | 3 +- tests/auto/qtpromise/qtpromise.pro | 1 + tests/auto/qtpromise/shared/data.h | 76 +++++ tests/auto/qtpromise/thread/tst_thread.cpp | 8 +- 34 files changed, 880 insertions(+), 253 deletions(-) delete mode 100644 docs/qtpromise/helpers/qpromise.md create mode 100644 docs/qtpromise/helpers/resolve.md create mode 100644 tests/auto/qtpromise/deprecations/deprecations.pri create mode 100644 tests/auto/qtpromise/deprecations/deprecations.pro create mode 100644 tests/auto/qtpromise/deprecations/helpers/helpers.pro create mode 100644 tests/auto/qtpromise/deprecations/helpers/qpromise/qpromise.pro create mode 100644 tests/auto/qtpromise/deprecations/helpers/qpromise/tst_qpromise.cpp create mode 100644 tests/auto/qtpromise/qpromise/resolve/resolve.pro create mode 100644 tests/auto/qtpromise/qpromise/resolve/tst_resolve.cpp create mode 100644 tests/auto/qtpromise/shared/data.h diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index d195861..6ac38b1 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -51,7 +51,7 @@ module.exports = { 'qtpromise/helpers/each', 'qtpromise/helpers/filter', 'qtpromise/helpers/map', - 'qtpromise/helpers/qpromise', + 'qtpromise/helpers/resolve', 'qtpromise/helpers/qpromiseall' ] }, diff --git a/docs/qtpromise/api-reference.md b/docs/qtpromise/api-reference.md index f2429dc..344eda5 100644 --- a/docs/qtpromise/api-reference.md +++ b/docs/qtpromise/api-reference.md @@ -31,7 +31,7 @@ * [`QtPromise::each`](helpers/each.md) * [`QtPromise::filter`](helpers/filter.md) * [`QtPromise::map`](helpers/map.md) -* [`qPromise`](helpers/qpromise.md) +* [`QtPromise::resolve`](helpers/resolve.md) * [`qPromiseAll`](helpers/qpromiseall.md) ## Exceptions @@ -39,3 +39,7 @@ * [`QPromiseCanceledException`](exceptions/canceled.md) * [`QPromiseTimeoutException`](exceptions/timeout.md) * [`QPromiseUndefinedException`](exceptions/undefined.md) + +## Deprecations + +* `QtPromise::qPromise`: use [`QtPromise::resolve`](helpers/resolve.md) instead (since 0.5.0) diff --git a/docs/qtpromise/exceptions/canceled.md b/docs/qtpromise/exceptions/canceled.md index f46fb3f..c9c1ba0 100644 --- a/docs/qtpromise/exceptions/canceled.md +++ b/docs/qtpromise/exceptions/canceled.md @@ -9,7 +9,7 @@ title: QPromiseCanceledException This exception is thrown for promise created from a [`QFuture`](../qtconcurrent.md) which has been canceled (e.g. using [`QFuture::cancel()`](http://doc.qt.io/qt-5/qfuture.html#cancel)), for example: ```cpp -auto output = qPromise(future) +auto output = QtPromise::resolve(future) .fail([](const QPromiseCanceledException&) { // `future` has been canceled! }); diff --git a/docs/qtpromise/getting-started.md b/docs/qtpromise/getting-started.md index f873b3e..e49245c 100644 --- a/docs/qtpromise/getting-started.md +++ b/docs/qtpromise/getting-started.md @@ -56,7 +56,7 @@ The following method `uncompress` data in a separate thread and returns a [promi ```cpp QPromise uncompress(const QByteArray& data) { - return qPromise(QtConcurrent::run([](const QByteArray& data) { + return QtPromise::resolve(QtConcurrent::run([](const QByteArray& data) { Entries entries; // {...} uncompress data and parse content. diff --git a/docs/qtpromise/helpers/qpromise.md b/docs/qtpromise/helpers/qpromise.md deleted file mode 100644 index 26ddb77..0000000 --- a/docs/qtpromise/helpers/qpromise.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: qPromise ---- - -# qPromise - -*Since: 0.1.0* - -``` -qPromise(T value) -> QPromise -``` - -Similar to the [`QPromise::resolve`](../qpromise/resolve.md) static method, creates a promise resolved from a given `value` without the extra typing: - -```cpp -auto promise = qPromise(); // QPromise -auto promise = qPromise(42); // QPromise -auto promise = qPromise(QString("foo")); // QPromise -``` - -This method also allows to convert `QFuture` to `QPromise` delayed until the `QFuture` is finished ([read more](../qtconcurrent.md#convert)). diff --git a/docs/qtpromise/helpers/resolve.md b/docs/qtpromise/helpers/resolve.md new file mode 100644 index 0000000..b5cb34b --- /dev/null +++ b/docs/qtpromise/helpers/resolve.md @@ -0,0 +1,21 @@ +--- +title: resolve +--- + +# QtPromise::resolve + +*Since: 0.5.0* + +``` +QtPromise::resolve(T value) -> QPromise +``` + +Similar to the [`QPromise::resolve`](../qpromise/resolve.md) static method, creates a promise resolved from a given `value` but without the extra typing: + +```cpp +auto promise = QtPromise::resolve(); // QPromise +auto promise = QtPromise::resolve(42); // QPromise +auto promise = QtPromise::resolve(QString("foo")); // QPromise +``` + +This method also allows to convert `QFuture` to `QPromise`, delayed until the `QFuture` is finished ([read more](../qtconcurrent.md#convert)). diff --git a/docs/qtpromise/qpromise/resolve.md b/docs/qtpromise/qpromise/resolve.md index 1ca85ef..9e2b8e4 100644 --- a/docs/qtpromise/qpromise/resolve.md +++ b/docs/qtpromise/qpromise/resolve.md @@ -25,4 +25,4 @@ QPromise compute(const QString& type) } ``` -See also: [`qPromise`](../helpers/qpromise.md) +See also: [`QtPromise::resolve`](../helpers/resolve.md) diff --git a/docs/qtpromise/qpromise/wait.md b/docs/qtpromise/qpromise/wait.md index db9b2c6..22fda45 100644 --- a/docs/qtpromise/qpromise/wait.md +++ b/docs/qtpromise/qpromise/wait.md @@ -15,7 +15,7 @@ This method holds the execution of the remaining code until the `input` promise ```cpp int result = -1; -QPromise input = qPromise(QtConcurrent::run([]() { +QPromise input = QtPromise::resolve(QtConcurrent::run([]() { return 42; })).tap([&](int res) { result = res; diff --git a/docs/qtpromise/qtconcurrent.md b/docs/qtpromise/qtconcurrent.md index 4bb4ea1..cef0c3d 100644 --- a/docs/qtpromise/qtconcurrent.md +++ b/docs/qtpromise/qtconcurrent.md @@ -4,7 +4,7 @@ QtPromise integrates with [QtConcurrent](https://doc.qt.io/qt-5/qtconcurrent-ind ## Convert -Converting `QFuture` to `QPromise` is done using the [`qPromise`](helpers/qpromise.md) helper: +Converting `QFuture` to `QPromise` is done using the [`QtPromise::resolve`](helpers/resolve.md) helper: ```cpp QFuture future = QtConcurrent::run([]() { @@ -12,13 +12,13 @@ QFuture future = QtConcurrent::run([]() { return 42; }); -QPromise promise = qPromise(future); +QPromise promise = QtPromise::resolve(future); ``` or simply: ```cpp -auto promise = qPromise(QtConcurrent::run([]() { +auto promise = QtPromise::resolve(QtConcurrent::run([]() { // {...} })); ``` diff --git a/src/qtpromise/qpromise.inl b/src/qtpromise/qpromise.inl index a645470..cddffd7 100644 --- a/src/qtpromise/qpromise.inl +++ b/src/qtpromise/qpromise.inl @@ -279,9 +279,7 @@ inline QPromise QPromise::all(const Sequence, Args... inline QPromise QPromise::resolve() { - return QPromise([](const QPromiseResolve& resolve) { - resolve(); - }); + return QtPromise::resolve(); } } // namespace QtPromise diff --git a/src/qtpromise/qpromise_p.h b/src/qtpromise/qpromise_p.h index accbbf8..f8d8556 100644 --- a/src/qtpromise/qpromise_p.h +++ b/src/qtpromise/qpromise_p.h @@ -110,9 +110,24 @@ private: template struct PromiseDeduce { - using Type = QtPromise::QPromise>; + using Type = QtPromise::QPromise; }; +template +struct PromiseDeduce + : public PromiseDeduce +{ }; + +template +struct PromiseDeduce + : public PromiseDeduce +{ }; + +template +struct PromiseDeduce + : public PromiseDeduce +{ }; + template struct PromiseDeduce> : public PromiseDeduce @@ -128,22 +143,21 @@ struct PromiseFunctor template struct PromiseFulfill { - static void call( - T&& value, - const QtPromise::QPromiseResolve& resolve, - const QtPromise::QPromiseReject&) + template + static void call(V&& value, const TResolve& resolve, const TReject&) { - resolve(std::move(value)); + resolve(std::forward(value)); } }; template struct PromiseFulfill> { + template static void call( const QtPromise::QPromise& promise, - const QtPromise::QPromiseResolve& resolve, - const QtPromise::QPromiseReject& reject) + const TResolve& resolve, + const TReject& reject) { if (promise.isFulfilled()) { resolve(promise.m_d->value()); diff --git a/src/qtpromise/qpromisehelpers.h b/src/qtpromise/qpromisehelpers.h index c1fc0a5..50a5b05 100644 --- a/src/qtpromise/qpromisehelpers.h +++ b/src/qtpromise/qpromisehelpers.h @@ -7,21 +7,34 @@ namespace QtPromise { template -static inline typename QtPromisePrivate::PromiseDeduce::Type qPromise(T&& value) +static inline typename QtPromisePrivate::PromiseDeduce::Type +resolve(T&& value) { using namespace QtPromisePrivate; - using Promise = typename PromiseDeduce::Type; - return Promise([&]( - const QPromiseResolve& resolve, - const QPromiseReject& reject) { - PromiseFulfill::call(std::forward(value), resolve, reject); + using PromiseType = typename PromiseDeduce::Type; + using ValueType = typename PromiseType::Type; + using ResolveType = QPromiseResolve; + using RejectType = QPromiseReject; + + return PromiseType([&](ResolveType&& resolve, RejectType&& reject) { + PromiseFulfill>::call( + std::forward(value), + std::forward(resolve), + std::forward(reject)); }); } -static inline QPromise qPromise() +template +static inline QPromise +resolve(QPromise value) { - return QPromise([]( - const QPromiseResolve& resolve) { + return std::move(value); +} + +static inline QPromise +resolve() +{ + return QPromise([](const QPromiseResolve& resolve) { resolve(); }); } @@ -153,6 +166,17 @@ static inline QPromise filter(const Sequence& values, Functor fn) }); } +// DEPRECATIONS (remove at version 1) + +template +Q_DECL_DEPRECATED_X("Use QtPromise::resolve instead") +static inline auto +qPromise(Args&&... args) + -> decltype(QtPromise::resolve(std::forward(args)...)) +{ + return QtPromise::resolve(std::forward(args)...); +} + } // namespace QtPromise #endif // QTPROMISE_QPROMISEHELPERS_H diff --git a/tests/auto/qtpromise/benchmark/tst_benchmark.cpp b/tests/auto/qtpromise/benchmark/tst_benchmark.cpp index 4fb1150..f9c5cd1 100644 --- a/tests/auto/qtpromise/benchmark/tst_benchmark.cpp +++ b/tests/auto/qtpromise/benchmark/tst_benchmark.cpp @@ -1,3 +1,5 @@ +#include "../shared/data.h" + // QtPromise #include @@ -20,7 +22,6 @@ class tst_benchmark : public QObject private Q_SLOTS: void valueResolve(); - void valueResolveStatic(); void valueReject(); void valueThen(); void valueFinally(); @@ -34,72 +35,6 @@ private Q_SLOTS: QTEST_MAIN(tst_benchmark) #include "tst_benchmark.moc" -struct Logs { - int ctor = 0; - int copy = 0; - int move = 0; - int refs = 0; - - void reset() { - ctor = 0; - copy = 0; - move = 0; - refs = 0; - } -}; - -struct Logger -{ - Logger() { logs().ctor++; logs().refs++; } - Logger(const Logger&) { logs().copy++; logs().refs++; } - Logger(Logger&&) { logs().move++; logs().refs++; } - ~Logger() { logs().refs--; } - - Logger& operator=(const Logger&) { logs().copy++; return *this; } - Logger& operator=(Logger&&) { logs().move++; return *this; } - -public: // STATICS - static Logs& logs() { static Logs logs; return logs; } -}; - -struct Data : public Logger -{ - Data(int v): Logger(), m_value(v) {} - int value() const { return m_value; } - - // MSVC 2013 doesn't support implicit generation of the move constructor and - // operator, so we need to explicitly define these methods and thus the copy - // constructor and operator also need to be explicitly defined (error C2280). - // https://stackoverflow.com/a/26581337 - - Data(const Data& other) - : Logger(other) - , m_value(other.m_value) - { } - - Data(Data&& other) : Logger(std::forward(other)) - { - qSwap(m_value, other.m_value); - } - - Data& operator=(const Data& other) - { - Logger::operator=(other); - m_value = other.m_value; - return *this; - } - - Data& operator=(Data&& other) - { - Logger::operator=(std::forward(other)); - qSwap(m_value, other.m_value); - return *this; - } - -private: - int m_value; -}; - void tst_benchmark::valueResolve() { { // should move the value when resolved by rvalue @@ -127,31 +62,6 @@ void tst_benchmark::valueResolve() } } -void tst_benchmark::valueResolveStatic() -{ - { // should move the value when resolved by rvalue - Data::logs().reset(); - QPromise::resolve(Data(42)).wait(); - - QCOMPARE(Data::logs().ctor, 1); - QCOMPARE(Data::logs().copy, 0); - QCOMPARE(Data::logs().move, 1); // move value to the promise data - QCOMPARE(Data::logs().refs, 0); - } - { // should create one copy of the value when resolved by lvalue - { - Data::logs().reset(); - Data value(42); - QPromise::resolve(value).wait(); - } - - QCOMPARE(Data::logs().ctor, 1); - QCOMPARE(Data::logs().copy, 1); // copy value to the promise data - QCOMPARE(Data::logs().move, 0); - QCOMPARE(Data::logs().refs, 0); - } -} - void tst_benchmark::valueReject() { { // should not create any data if rejected diff --git a/tests/auto/qtpromise/deprecations/deprecations.pri b/tests/auto/qtpromise/deprecations/deprecations.pri new file mode 100644 index 0000000..671915f --- /dev/null +++ b/tests/auto/qtpromise/deprecations/deprecations.pri @@ -0,0 +1,5 @@ +include(../qtpromise.pri) + +DEFINES -= QT_DEPRECATED_WARNINGS +gcc:QMAKE_CXXFLAGS += -Wno-deprecated-declarations +msvc:QMAKE_CXXFLAGS -= -wd4996 diff --git a/tests/auto/qtpromise/deprecations/deprecations.pro b/tests/auto/qtpromise/deprecations/deprecations.pro new file mode 100644 index 0000000..8c4a60e --- /dev/null +++ b/tests/auto/qtpromise/deprecations/deprecations.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS += \ + helpers diff --git a/tests/auto/qtpromise/deprecations/helpers/helpers.pro b/tests/auto/qtpromise/deprecations/helpers/helpers.pro new file mode 100644 index 0000000..794894f --- /dev/null +++ b/tests/auto/qtpromise/deprecations/helpers/helpers.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS += \ + qpromise diff --git a/tests/auto/qtpromise/deprecations/helpers/qpromise/qpromise.pro b/tests/auto/qtpromise/deprecations/helpers/qpromise/qpromise.pro new file mode 100644 index 0000000..33e0374 --- /dev/null +++ b/tests/auto/qtpromise/deprecations/helpers/qpromise/qpromise.pro @@ -0,0 +1,5 @@ +QT += concurrent +TARGET = tst_deprecations_helpers_qpromise +SOURCES += $$PWD/tst_qpromise.cpp + +include(../../deprecations.pri) diff --git a/tests/auto/qtpromise/deprecations/helpers/qpromise/tst_qpromise.cpp b/tests/auto/qtpromise/deprecations/helpers/qpromise/tst_qpromise.cpp new file mode 100644 index 0000000..c5ffb05 --- /dev/null +++ b/tests/auto/qtpromise/deprecations/helpers/qpromise/tst_qpromise.cpp @@ -0,0 +1,268 @@ +#include "../../../shared/data.h" +#include "../../../shared/utils.h" + +// QtPromise +#include + +// Qt +#include +#include + +// STL +#include + +using namespace QtPromise; + +class tst_deprecations_helpers_qpromise : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void value(); + void noValue(); + void moveRValue(); + void copyLValue(); + void qtSharedPtr(); + void stdSharedPtr(); + void typedPromise(); + void voidPromise(); + void typedFuture(); + void voidFuture(); +}; + +QTEST_MAIN(tst_deprecations_helpers_qpromise) +#include "tst_qpromise.moc" + +void tst_deprecations_helpers_qpromise::value() +{ + int v0 = 42; + const int v1 = 42; + + auto p0 = qPromise(42); + auto p1 = qPromise(v0); + auto p2 = qPromise(v1); + + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + + for (const auto& p : {p0, p1, p2}) { + QCOMPARE(p.isFulfilled(), true); + } + for (const auto& p : {p0, p1, p2}) { + QCOMPARE(waitForValue(p, -1), 42); + } +} + +void tst_deprecations_helpers_qpromise::noValue() +{ + auto p = qPromise(); + + Q_STATIC_ASSERT((std::is_same>::value)); + + QCOMPARE(p.isFulfilled(), true); + QCOMPARE(waitForValue(p, -1, 42), 42); +} + +void tst_deprecations_helpers_qpromise::moveRValue() +{ + Data::logs().reset(); + + { + auto p = qPromise(Data(42)).wait(); + + Q_STATIC_ASSERT((std::is_same>::value)); + } + + QCOMPARE(Data::logs().ctor, 1); + QCOMPARE(Data::logs().copy, 0); + QCOMPARE(Data::logs().move, 1); + QCOMPARE(Data::logs().refs, 0); +} + +void tst_deprecations_helpers_qpromise::copyLValue() +{ + Data::logs().reset(); + + { + Data value(42); + auto p = qPromise(value).wait(); + + Q_STATIC_ASSERT((std::is_same>::value)); + } + + QCOMPARE(Data::logs().ctor, 1); + QCOMPARE(Data::logs().copy, 1); + QCOMPARE(Data::logs().move, 0); + QCOMPARE(Data::logs().refs, 0); +} + +// https://github.com/simonbrunel/qtpromise/issues/6 +void tst_deprecations_helpers_qpromise::qtSharedPtr() +{ + Data::logs().reset(); + + QWeakPointer wptr; + + { + QSharedPointer sptr0(new Data(42)); + const QSharedPointer sptr1 = sptr0; + + auto p0 = qPromise(QSharedPointer(new Data(42))); + auto p1 = qPromise(sptr0); + auto p2 = qPromise(sptr1); + + Q_STATIC_ASSERT((std::is_same>>::value)); + Q_STATIC_ASSERT((std::is_same>>::value)); + Q_STATIC_ASSERT((std::is_same>>::value)); + + QCOMPARE(waitForValue(p1, QSharedPointer()), sptr0); + QCOMPARE(waitForValue(p2, QSharedPointer()), sptr1); + + wptr = sptr0; + + QCOMPARE(wptr.isNull(), false); + QCOMPARE(Data::logs().refs, 2); + } + + QCOMPARE(wptr.isNull(), true); + + QCOMPARE(Data::logs().ctor, 2); + QCOMPARE(Data::logs().copy, 0); + QCOMPARE(Data::logs().move, 0); + QCOMPARE(Data::logs().refs, 0); +} + +// https://github.com/simonbrunel/qtpromise/issues/6 +void tst_deprecations_helpers_qpromise::stdSharedPtr() +{ + Data::logs().reset(); + + std::weak_ptr wptr; + + { + std::shared_ptr sptr0(new Data(42)); + const std::shared_ptr sptr1 = sptr0; + + auto p0 = qPromise(std::shared_ptr(new Data(42))); + auto p1 = qPromise(sptr0); + auto p2 = qPromise(sptr1); + + Q_STATIC_ASSERT((std::is_same>>::value)); + Q_STATIC_ASSERT((std::is_same>>::value)); + Q_STATIC_ASSERT((std::is_same>>::value)); + + QCOMPARE(waitForValue(p1, std::shared_ptr()), sptr0); + QCOMPARE(waitForValue(p2, std::shared_ptr()), sptr1); + + wptr = sptr0; + + QCOMPARE(wptr.use_count(), 4l); + QCOMPARE(Data::logs().refs, 2); + } + + QCOMPARE(wptr.use_count(), 0l); + + QCOMPARE(Data::logs().ctor, 2); + QCOMPARE(Data::logs().copy, 0); + QCOMPARE(Data::logs().move, 0); + QCOMPARE(Data::logs().refs, 0); +} + +void tst_deprecations_helpers_qpromise::typedPromise() +{ + auto resolver = [](const QPromiseResolve& resolve) { + QtPromisePrivate::qtpromise_defer([=](){ + resolve(42); + }); + }; + + QPromise v0(resolver); + const QPromise v1 = v0; + + auto p0 = qPromise(QPromise(resolver)); + auto p1 = qPromise(v0); + auto p2 = qPromise(v1); + + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + + for (const auto& promise : {p0, p1, p2}) { + QCOMPARE(promise.isPending(), true); + } + for (const auto& promise : {p0, p1, p2}) { + QCOMPARE(waitForValue(promise, -1), 42); + } +} + +void tst_deprecations_helpers_qpromise::voidPromise() +{ + auto resolver = [](const QPromiseResolve& resolve) { + QtPromisePrivate::qtpromise_defer([=](){ + resolve(); + }); + }; + + QPromise v0(resolver); + const QPromise v1 = v0; + + auto p0 = qPromise(QPromise(resolver)); + auto p1 = qPromise(v0); + auto p2 = qPromise(v1); + + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + + for (const auto& promise : {p0, p1, p2}) { + QCOMPARE(promise.isPending(), true); + } + for (const auto& promise : {p0, p1, p2}) { + QCOMPARE(waitForValue(promise, -1, 42), 42); + } +} + +void tst_deprecations_helpers_qpromise::typedFuture() +{ + auto fn = [](){ return 42; }; + QFuture v0 = QtConcurrent::run(fn); + const QFuture v1 = v0; + + auto p0 = qPromise(QtConcurrent::run(fn)); + auto p1 = qPromise(v0); + auto p2 = qPromise(v1); + + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + + for (const auto& promise : {p0, p1, p2}) { + QCOMPARE(promise.isPending(), true); + } + for (const auto& promise : {p0, p1, p2}) { + QCOMPARE(waitForValue(promise, -1), 42); + } +} + +void tst_deprecations_helpers_qpromise::voidFuture() +{ + auto fn = [](){ }; + QFuture v0 = QtConcurrent::run(fn); + const QFuture v1 = v0; + + auto p0 = qPromise(QtConcurrent::run(fn)); + auto p1 = qPromise(v0); + auto p2 = qPromise(v1); + + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + + for (const auto& promise : {p0, p1, p2}) { + QCOMPARE(promise.isPending(), true); + } + for (const auto& promise : {p0, p1, p2}) { + QCOMPARE(waitForValue(promise, -1, 42), 42); + } +} diff --git a/tests/auto/qtpromise/exceptions/tst_exceptions.cpp b/tests/auto/qtpromise/exceptions/tst_exceptions.cpp index 358f35e..bcdf030 100644 --- a/tests/auto/qtpromise/exceptions/tst_exceptions.cpp +++ b/tests/auto/qtpromise/exceptions/tst_exceptions.cpp @@ -29,7 +29,7 @@ namespace { template void verify() { - auto p = qPromise(QtConcurrent::run([]() { throw E(); })); + auto p = QtPromise::resolve(QtConcurrent::run([]() { throw E(); })); QCOMPARE(p.isPending(), true); QCOMPARE(waitForRejected(p), true); QCOMPARE(p.isRejected(), true); diff --git a/tests/auto/qtpromise/future/tst_future.cpp b/tests/auto/qtpromise/future/tst_future.cpp index f7278fc..4d704ef 100644 --- a/tests/auto/qtpromise/future/tst_future.cpp +++ b/tests/auto/qtpromise/future/tst_future.cpp @@ -52,7 +52,7 @@ QTEST_MAIN(tst_future) void tst_future::fulfilled() { int result = -1; - auto p = qPromise(QtConcurrent::run([]() { + auto p = QtPromise::resolve(QtConcurrent::run([]() { return 42; })); @@ -70,7 +70,7 @@ void tst_future::fulfilled() void tst_future::fulfilled_void() { int result = -1; - auto p = qPromise(QtConcurrent::run([]() { })); + auto p = QtPromise::resolve(QtConcurrent::run([]() { })); Q_STATIC_ASSERT((std::is_same>::value)); QCOMPARE(p.isPending(), true); @@ -86,7 +86,7 @@ void tst_future::fulfilled_void() void tst_future::rejected() { QString error; - auto p = qPromise(QtConcurrent::run([]() { + auto p = QtPromise::resolve(QtConcurrent::run([]() { throw MyException("foo"); return 42; })); @@ -106,7 +106,7 @@ void tst_future::rejected() void tst_future::rejected_void() { QString error; - auto p = qPromise(QtConcurrent::run([]() { + auto p = QtPromise::resolve(QtConcurrent::run([]() { throw MyException("foo"); })); @@ -125,7 +125,7 @@ void tst_future::rejected_void() void tst_future::unhandled() { QString error; - auto p = qPromise(QtConcurrent::run([]() { + auto p = QtPromise::resolve(QtConcurrent::run([]() { throw QString("foo"); return 42; })); @@ -149,7 +149,7 @@ void tst_future::unhandled() void tst_future::unhandled_void() { QString error; - auto p = qPromise(QtConcurrent::run([]() { + auto p = QtPromise::resolve(QtConcurrent::run([]() { throw QString("foo"); })); @@ -169,7 +169,7 @@ void tst_future::unhandled_void() void tst_future::canceled() { QString error; - auto p = qPromise(QFuture()); // Constructs an empty, canceled future. + auto p = QtPromise::resolve(QFuture()); // Constructs an empty, canceled future. QCOMPARE(p.isPending(), true); @@ -185,7 +185,7 @@ void tst_future::canceled() void tst_future::canceled_void() { QString error; - auto p = qPromise(QFuture()); // Constructs an empty, canceled future. + auto p = QtPromise::resolve(QFuture()); // Constructs an empty, canceled future. QCOMPARE(p.isPending(), true); @@ -200,7 +200,7 @@ void tst_future::canceled_void() void tst_future::canceledFromThread() { QString error; - auto p = qPromise(QtConcurrent::run([]() { + auto p = QtPromise::resolve(QtConcurrent::run([]() { throw QPromiseCanceledException(); })); @@ -217,7 +217,7 @@ void tst_future::canceledFromThread() void tst_future::then() { QString result; - auto input = qPromise(42); + auto input = QtPromise::resolve(42); auto output = input.then([](int res) { return QtConcurrent::run([=]() { return QString("foo%1").arg(res); @@ -238,7 +238,7 @@ void tst_future::then() void tst_future::then_void() { QString result; - auto input = qPromise(); + auto input = QtPromise::resolve(); auto output = input.then([&]() { return QtConcurrent::run([&]() { result = "foo"; @@ -300,7 +300,7 @@ void tst_future::fail_void() void tst_future::finally() { - auto input = qPromise(42); + auto input = QtPromise::resolve(42); auto output = input.finally([]() { return QtConcurrent::run([]() { return QString("foo"); @@ -323,7 +323,7 @@ void tst_future::finally() void tst_future::finallyRejected() { - auto input = qPromise(42); + auto input = QtPromise::resolve(42); auto output = input.finally([]() { return QtConcurrent::run([]() { throw MyException("foo"); diff --git a/tests/auto/qtpromise/helpers/all/tst_all.cpp b/tests/auto/qtpromise/helpers/all/tst_all.cpp index a6e4ec3..706c6dc 100644 --- a/tests/auto/qtpromise/helpers/all/tst_all.cpp +++ b/tests/auto/qtpromise/helpers/all/tst_all.cpp @@ -37,13 +37,13 @@ struct SequenceTester static void exec() { Sequence promises{ - QtPromise::qPromise(42), - QtPromise::qPromise(43), - QtPromise::qPromise(44) + QtPromise::resolve(42), + QtPromise::resolve(43), + QtPromise::resolve(44) }; - promises.push_back(QtPromise::qPromise(45)); - promises.insert(++promises.begin(), QtPromise::qPromise(46)); + promises.push_back(QtPromise::resolve(45)); + promises.insert(++promises.begin(), QtPromise::resolve(46)); promises.pop_back(); auto p = QtPromise::qPromiseAll(promises); @@ -60,13 +60,13 @@ struct SequenceTester, Args...>> static void exec() { Sequence, Args...> promises{ - QtPromise::qPromise(), - QtPromise::qPromise(), - QtPromise::qPromise() + QtPromise::resolve(), + QtPromise::resolve(), + QtPromise::resolve() }; - promises.push_back(QtPromise::qPromise()); - promises.insert(++promises.begin(), QtPromise::qPromise()); + promises.push_back(QtPromise::resolve()); + promises.insert(++promises.begin(), QtPromise::resolve()); promises.pop_back(); auto p = QtPromise::qPromiseAll(promises); @@ -99,8 +99,8 @@ void tst_helpers_all::emptySequence_void() void tst_helpers_all::allPromisesSucceed() { - auto p0 = QtPromise::qPromise(42); - auto p1 = QtPromise::qPromise(44); + auto p0 = QtPromise::resolve(42); + auto p1 = QtPromise::resolve(44); auto p2 = QPromise([](const QPromiseResolve& resolve) { QtPromisePrivate::qtpromise_defer([=](){ resolve(43); @@ -120,8 +120,8 @@ void tst_helpers_all::allPromisesSucceed() void tst_helpers_all::allPromisesSucceed_void() { - auto p0 = QtPromise::qPromise(); - auto p1 = QtPromise::qPromise(); + auto p0 = QtPromise::resolve(); + auto p1 = QtPromise::resolve(); auto p2 = QPromise([](const QPromiseResolve& resolve) { QtPromisePrivate::qtpromise_defer([=](){ resolve(); @@ -141,8 +141,8 @@ void tst_helpers_all::allPromisesSucceed_void() void tst_helpers_all::atLeastOnePromiseReject() { - auto p0 = QtPromise::qPromise(42); - auto p1 = QtPromise::qPromise(44); + auto p0 = QtPromise::resolve(42); + auto p1 = QtPromise::resolve(44); auto p2 = QPromise([](const QPromiseResolve&, const QPromiseReject& reject) { QtPromisePrivate::qtpromise_defer([=](){ reject(QString("foo")); @@ -162,8 +162,8 @@ void tst_helpers_all::atLeastOnePromiseReject() void tst_helpers_all::atLeastOnePromiseReject_void() { - auto p0 = QtPromise::qPromise(); - auto p1 = QtPromise::qPromise(); + auto p0 = QtPromise::resolve(); + auto p1 = QtPromise::resolve(); auto p2 = QPromise([](const QPromiseResolve&, const QPromiseReject& reject) { QtPromisePrivate::qtpromise_defer([=](){ reject(QString("foo")); @@ -183,9 +183,9 @@ void tst_helpers_all::atLeastOnePromiseReject_void() void tst_helpers_all::preserveOrder() { - auto p0 = QtPromise::qPromise(42).delay(500); - auto p1 = QtPromise::qPromise(43).delay(100); - auto p2 = QtPromise::qPromise(44).delay(250); + auto p0 = QtPromise::resolve(42).delay(500); + auto p1 = QtPromise::resolve(43).delay(100); + auto p2 = QtPromise::resolve(44).delay(250); auto p = QtPromise::qPromiseAll(QVector>{p0, p1, p2}); diff --git a/tests/auto/qtpromise/helpers/attempt/tst_attempt.cpp b/tests/auto/qtpromise/helpers/attempt/tst_attempt.cpp index 87b9ff3..3c12eea 100644 --- a/tests/auto/qtpromise/helpers/attempt/tst_attempt.cpp +++ b/tests/auto/qtpromise/helpers/attempt/tst_attempt.cpp @@ -64,7 +64,7 @@ void tst_helpers_attempt::futureResult() void tst_helpers_attempt::promiseResult() { auto p = QtPromise::attempt([]() { - return QtPromise::qPromise(42).delay(200); + return QtPromise::resolve(42).delay(200); }); Q_STATIC_ASSERT((std::is_same>::value)); diff --git a/tests/auto/qtpromise/helpers/resolve/resolve.pro b/tests/auto/qtpromise/helpers/resolve/resolve.pro index 5ee83e6..dc32edd 100644 --- a/tests/auto/qtpromise/helpers/resolve/resolve.pro +++ b/tests/auto/qtpromise/helpers/resolve/resolve.pro @@ -1,3 +1,4 @@ +QT += concurrent TARGET = tst_helpers_resolve SOURCES += $$PWD/tst_resolve.cpp diff --git a/tests/auto/qtpromise/helpers/resolve/tst_resolve.cpp b/tests/auto/qtpromise/helpers/resolve/tst_resolve.cpp index ad6cfeb..19893a0 100644 --- a/tests/auto/qtpromise/helpers/resolve/tst_resolve.cpp +++ b/tests/auto/qtpromise/helpers/resolve/tst_resolve.cpp @@ -1,9 +1,11 @@ +#include "../../shared/data.h" #include "../../shared/utils.h" // QtPromise #include // Qt +#include #include // STL @@ -16,109 +18,251 @@ class tst_helpers_resolve : public QObject Q_OBJECT private Q_SLOTS: - void resolveWithValue(); - void resolveWithNoValue(); - void resolveWithTypedPromise(); - void resolveWithVoidPromise(); - void resolveWithQSharedPtr(); - void resolveWithStdSharedPtr(); + void value(); + void noValue(); + void moveRValue(); + void copyLValue(); + void qtSharedPtr(); + void stdSharedPtr(); + void typedPromise(); + void voidPromise(); + void typedFuture(); + void voidFuture(); }; QTEST_MAIN(tst_helpers_resolve) #include "tst_resolve.moc" -void tst_helpers_resolve::resolveWithValue() +void tst_helpers_resolve::value() { - const int value = 42; - auto p0 = QPromise::resolve(value); - auto p1 = QPromise::resolve(43); + int v0 = 42; + const int v1 = 42; + + auto p0 = QtPromise::resolve(42); + auto p1 = QtPromise::resolve(v0); + auto p2 = QtPromise::resolve(v1); Q_STATIC_ASSERT((std::is_same>::value)); Q_STATIC_ASSERT((std::is_same>::value)); - QCOMPARE(p0.isFulfilled(), true); - QCOMPARE(p1.isFulfilled(), true); - QCOMPARE(waitForValue(p0, -1), 42); - QCOMPARE(waitForValue(p1, -1), 43); + Q_STATIC_ASSERT((std::is_same>::value)); + + for (const auto& p : {p0, p1, p2}) { + QCOMPARE(p.isFulfilled(), true); + } + for (const auto& p : {p0, p1, p2}) { + QCOMPARE(waitForValue(p, -1), 42); + } } -void tst_helpers_resolve::resolveWithNoValue() +void tst_helpers_resolve::noValue() { - auto p = QPromise::resolve(); + auto p = QtPromise::resolve(); Q_STATIC_ASSERT((std::is_same>::value)); + QCOMPARE(p.isFulfilled(), true); QCOMPARE(waitForValue(p, -1, 42), 42); } -void tst_helpers_resolve::resolveWithTypedPromise() +void tst_helpers_resolve::moveRValue() { - auto p = QtPromise::qPromise( - QPromise([](const QPromiseResolve& resolve) { - QtPromisePrivate::qtpromise_defer([=](){ - resolve("foo"); - }); - })); + Data::logs().reset(); - Q_STATIC_ASSERT((std::is_same>::value)); + { + auto p = QtPromise::resolve(Data(42)).wait(); - QCOMPARE(p.isPending(), true); - QCOMPARE(waitForValue(p, QString()), QString("foo")); + Q_STATIC_ASSERT((std::is_same>::value)); + } + + QCOMPARE(Data::logs().ctor, 1); + QCOMPARE(Data::logs().copy, 0); + QCOMPARE(Data::logs().move, 1); + QCOMPARE(Data::logs().refs, 0); } -void tst_helpers_resolve::resolveWithVoidPromise() +void tst_helpers_resolve::copyLValue() { - int check; - auto p = QtPromise::qPromise( - QPromise([&](const QPromiseResolve& resolve) { - QtPromisePrivate::qtpromise_defer([=, &check](){ - check = 8; - resolve(); - }); - })); + Data::logs().reset(); - Q_STATIC_ASSERT((std::is_same>::value)); + { + Data value(42); + auto p = QtPromise::resolve(value).wait(); - QCOMPARE(p.isPending(), true); - QCOMPARE(waitForValue(p, -1, 42), 42); - QCOMPARE(check, 8); + Q_STATIC_ASSERT((std::is_same>::value)); + } + + QCOMPARE(Data::logs().ctor, 1); + QCOMPARE(Data::logs().copy, 1); + QCOMPARE(Data::logs().move, 0); + QCOMPARE(Data::logs().refs, 0); } // https://github.com/simonbrunel/qtpromise/issues/6 -void tst_helpers_resolve::resolveWithQSharedPtr() +void tst_helpers_resolve::qtSharedPtr() { - QWeakPointer wptr; + Data::logs().reset(); + + QWeakPointer wptr; { - QSharedPointer sptr(new int(42)); - auto p = QPromise>::resolve(sptr); + QSharedPointer sptr0(new Data(42)); + const QSharedPointer sptr1 = sptr0; - QCOMPARE(waitForValue(p, QSharedPointer()), sptr); + auto p0 = QtPromise::resolve(QSharedPointer(new Data(42))); + auto p1 = QtPromise::resolve(sptr0); + auto p2 = QtPromise::resolve(sptr1); - wptr = sptr; - sptr.reset(); + Q_STATIC_ASSERT((std::is_same>>::value)); + Q_STATIC_ASSERT((std::is_same>>::value)); + Q_STATIC_ASSERT((std::is_same>>::value)); - QCOMPARE(wptr.isNull(), false); // "p" still holds a reference + QCOMPARE(waitForValue(p1, QSharedPointer()), sptr0); + QCOMPARE(waitForValue(p2, QSharedPointer()), sptr1); + + wptr = sptr0; + + QCOMPARE(wptr.isNull(), false); + QCOMPARE(Data::logs().refs, 2); } QCOMPARE(wptr.isNull(), true); + + QCOMPARE(Data::logs().ctor, 2); + QCOMPARE(Data::logs().copy, 0); + QCOMPARE(Data::logs().move, 0); + QCOMPARE(Data::logs().refs, 0); } // https://github.com/simonbrunel/qtpromise/issues/6 -void tst_helpers_resolve::resolveWithStdSharedPtr() +void tst_helpers_resolve::stdSharedPtr() { - std::weak_ptr wptr; + Data::logs().reset(); + + std::weak_ptr wptr; { - std::shared_ptr sptr(new int(42)); - auto p = QPromise>::resolve(sptr); + std::shared_ptr sptr0(new Data(42)); + const std::shared_ptr sptr1 = sptr0; - QCOMPARE(waitForValue(p, std::shared_ptr()), sptr); + auto p0 = QtPromise::resolve(std::shared_ptr(new Data(42))); + auto p1 = QtPromise::resolve(sptr0); + auto p2 = QtPromise::resolve(sptr1); - wptr = sptr; - sptr.reset(); + Q_STATIC_ASSERT((std::is_same>>::value)); + Q_STATIC_ASSERT((std::is_same>>::value)); + Q_STATIC_ASSERT((std::is_same>>::value)); - QCOMPARE(wptr.use_count(), 1l); // "p" still holds a reference + QCOMPARE(waitForValue(p1, std::shared_ptr()), sptr0); + QCOMPARE(waitForValue(p2, std::shared_ptr()), sptr1); + + wptr = sptr0; + + QCOMPARE(wptr.use_count(), 4l); + QCOMPARE(Data::logs().refs, 2); } QCOMPARE(wptr.use_count(), 0l); + + QCOMPARE(Data::logs().ctor, 2); + QCOMPARE(Data::logs().copy, 0); + QCOMPARE(Data::logs().move, 0); + QCOMPARE(Data::logs().refs, 0); +} + +void tst_helpers_resolve::typedPromise() +{ + auto resolver = [](const QPromiseResolve& resolve) { + QtPromisePrivate::qtpromise_defer([=](){ + resolve(42); + }); + }; + + QPromise v0(resolver); + const QPromise v1 = v0; + + auto p0 = QtPromise::resolve(QPromise(resolver)); + auto p1 = QtPromise::resolve(v0); + auto p2 = QtPromise::resolve(v1); + + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + + for (const auto& promise : {p0, p1, p2}) { + QCOMPARE(promise.isPending(), true); + } + for (const auto& promise : {p0, p1, p2}) { + QCOMPARE(waitForValue(promise, -1), 42); + } +} + +void tst_helpers_resolve::voidPromise() +{ + auto resolver = [](const QPromiseResolve& resolve) { + QtPromisePrivate::qtpromise_defer([=](){ + resolve(); + }); + }; + + QPromise v0(resolver); + const QPromise v1 = v0; + + auto p0 = QtPromise::resolve(QPromise(resolver)); + auto p1 = QtPromise::resolve(v0); + auto p2 = QtPromise::resolve(v1); + + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + + for (const auto& promise : {p0, p1, p2}) { + QCOMPARE(promise.isPending(), true); + } + for (const auto& promise : {p0, p1, p2}) { + QCOMPARE(waitForValue(promise, -1, 42), 42); + } +} + +void tst_helpers_resolve::typedFuture() +{ + auto fn = [](){ return 42; }; + QFuture v0 = QtConcurrent::run(fn); + const QFuture v1 = v0; + + auto p0 = QtPromise::resolve(QtConcurrent::run(fn)); + auto p1 = QtPromise::resolve(v0); + auto p2 = QtPromise::resolve(v1); + + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + + for (const auto& promise : {p0, p1, p2}) { + QCOMPARE(promise.isPending(), true); + } + for (const auto& promise : {p0, p1, p2}) { + QCOMPARE(waitForValue(promise, -1), 42); + } +} + +void tst_helpers_resolve::voidFuture() +{ + auto fn = [](){ }; + QFuture v0 = QtConcurrent::run(fn); + const QFuture v1 = v0; + + auto p0 = QtPromise::resolve(QtConcurrent::run(fn)); + auto p1 = QtPromise::resolve(v0); + auto p2 = QtPromise::resolve(v1); + + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + + for (const auto& promise : {p0, p1, p2}) { + QCOMPARE(promise.isPending(), true); + } + for (const auto& promise : {p0, p1, p2}) { + QCOMPARE(waitForValue(promise, -1, 42), 42); + } } diff --git a/tests/auto/qtpromise/qpromise/each/tst_each.cpp b/tests/auto/qtpromise/qpromise/each/tst_each.cpp index def7ea4..58c16af 100644 --- a/tests/auto/qtpromise/qpromise/each/tst_each.cpp +++ b/tests/auto/qtpromise/qpromise/each/tst_each.cpp @@ -34,14 +34,14 @@ struct SequenceTester static void exec() { QVector values; - auto p = QtPromise::qPromise(Sequence{42, 43, 44}).each([&](int v, int i) { + auto p = QtPromise::resolve(Sequence{42, 43, 44}).each([&](int v, int i) { values << i << v; }).each([&](int v, ...) { values << v; return QString("foo"); }).each([&](int v, ...) { values << v + 1; - return QPromise::resolve(QString("foo")).then([&](){ + return QtPromise::resolve(QString("foo")).then([&](){ values << -1; }); }).each([&](int v, ...) { diff --git a/tests/auto/qtpromise/qpromise/filter/tst_filter.cpp b/tests/auto/qtpromise/qpromise/filter/tst_filter.cpp index b42e694..71d769d 100644 --- a/tests/auto/qtpromise/qpromise/filter/tst_filter.cpp +++ b/tests/auto/qtpromise/qpromise/filter/tst_filter.cpp @@ -33,7 +33,7 @@ struct SequenceTester { static void exec() { - auto p = QtPromise::qPromise(Sequence{ + auto p = QtPromise::resolve(Sequence{ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }).filter([](int v, ...) { return v > 42 && v < 51; diff --git a/tests/auto/qtpromise/qpromise/map/tst_map.cpp b/tests/auto/qtpromise/qpromise/map/tst_map.cpp index 7ab5cb7..4ba37cd 100644 --- a/tests/auto/qtpromise/qpromise/map/tst_map.cpp +++ b/tests/auto/qtpromise/qpromise/map/tst_map.cpp @@ -34,12 +34,12 @@ struct SequenceTester { static void exec() { - auto p = QtPromise::qPromise(Sequence{42, 43, 44}).map([](int v, ...) { + auto p = QtPromise::resolve(Sequence{42, 43, 44}).map([](int v, ...) { return QString::number(v + 1); }).map([](const QString& v, int i) { - return QtPromise::qPromise(QString("%1:%2").arg(i).arg(v)); + return QtPromise::resolve(QString("%1:%2").arg(i).arg(v)); }).map([](const QString& v, ...) { - return QtPromise::qPromise((v + "!").toUtf8()); + return QtPromise::resolve((v + "!").toUtf8()); }).map([](const QByteArray& v, ...) { return QString::fromUtf8(v); }); @@ -53,7 +53,7 @@ struct SequenceTester void tst_qpromise_map::emptySequence() { - auto p = QtPromise::qPromise(QVector{}).map([](int v, ...) { + auto p = QtPromise::resolve(QVector{}).map([](int v, ...) { return v + 1; }); @@ -63,7 +63,7 @@ void tst_qpromise_map::emptySequence() void tst_qpromise_map::modifyValues() { - auto p = QtPromise::qPromise(QVector{42, 43, 44}).map([](int v, ...) { + auto p = QtPromise::resolve(QVector{42, 43, 44}).map([](int v, ...) { return v + 1; }); @@ -73,7 +73,7 @@ void tst_qpromise_map::modifyValues() void tst_qpromise_map::convertValues() { - auto p = QtPromise::qPromise(QVector{42, 43, 44}).map([](int v, ...) { + auto p = QtPromise::resolve(QVector{42, 43, 44}).map([](int v, ...) { return QString::number(v + 1); }); @@ -83,7 +83,7 @@ void tst_qpromise_map::convertValues() void tst_qpromise_map::delayedFulfilled() { - auto p = QtPromise::qPromise(QVector{42, 43, 44}).map([](int v, ...) { + auto p = QtPromise::resolve(QVector{42, 43, 44}).map([](int v, ...) { return QPromise([&](const QPromiseResolve& resolve) { QtPromisePrivate::qtpromise_defer([=]() { resolve(v + 1); @@ -97,7 +97,7 @@ void tst_qpromise_map::delayedFulfilled() void tst_qpromise_map::delayedRejected() { - auto p = QtPromise::qPromise(QVector{42, 43, 44}).map([](int v, ...) { + auto p = QtPromise::resolve(QVector{42, 43, 44}).map([](int v, ...) { return QPromise([&]( const QPromiseResolve& resolve, const QPromiseReject& reject) { @@ -116,7 +116,7 @@ void tst_qpromise_map::delayedRejected() void tst_qpromise_map::functorThrows() { - auto p = QtPromise::qPromise(QVector{42, 43, 44}).map([](int v, ...) { + auto p = QtPromise::resolve(QVector{42, 43, 44}).map([](int v, ...) { if (v == 43) { throw QString("foo"); } @@ -129,7 +129,7 @@ void tst_qpromise_map::functorThrows() void tst_qpromise_map::functorArguments() { - auto p1 = QtPromise::qPromise(QVector{42, 42, 42}).map([](int v, int i) { + auto p1 = QtPromise::resolve(QVector{42, 42, 42}).map([](int v, int i) { return v * i; }); @@ -139,8 +139,8 @@ void tst_qpromise_map::functorArguments() void tst_qpromise_map::preserveOrder() { - auto p = QtPromise::qPromise(QVector{250, 500, 100}).map([](int v, ...) { - return QtPromise::qPromise(v + 1).delay(v); + auto p = QtPromise::resolve(QVector{250, 500, 100}).map([](int v, ...) { + return QtPromise::resolve(v + 1).delay(v); }); Q_STATIC_ASSERT((std::is_same>>::value)); diff --git a/tests/auto/qtpromise/qpromise/qpromise.pro b/tests/auto/qtpromise/qpromise/qpromise.pro index e4b617d..a43dc53 100644 --- a/tests/auto/qtpromise/qpromise/qpromise.pro +++ b/tests/auto/qtpromise/qpromise/qpromise.pro @@ -8,6 +8,7 @@ SUBDIRS += \ finally \ map \ operators \ + resolve \ tap \ tapfail \ then \ diff --git a/tests/auto/qtpromise/qpromise/resolve/resolve.pro b/tests/auto/qtpromise/qpromise/resolve/resolve.pro new file mode 100644 index 0000000..26f9882 --- /dev/null +++ b/tests/auto/qtpromise/qpromise/resolve/resolve.pro @@ -0,0 +1,4 @@ +TARGET = tst_qpromise_resolve +SOURCES += $$PWD/tst_resolve.cpp + +include(../../qtpromise.pri) diff --git a/tests/auto/qtpromise/qpromise/resolve/tst_resolve.cpp b/tests/auto/qtpromise/qpromise/resolve/tst_resolve.cpp new file mode 100644 index 0000000..ce6a650 --- /dev/null +++ b/tests/auto/qtpromise/qpromise/resolve/tst_resolve.cpp @@ -0,0 +1,165 @@ +#include "../../shared/data.h" +#include "../../shared/utils.h" + +// QtPromise +#include + +// Qt +#include + +// STL +#include + +using namespace QtPromise; + +class tst_qpromise_resolve : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void value(); + void noValue(); + void moveRValue(); + void copyLValue(); + void qtSharedPtr(); + void stdSharedPtr(); +}; + +QTEST_MAIN(tst_qpromise_resolve) +#include "tst_resolve.moc" + +void tst_qpromise_resolve::value() +{ + int v0 = 42; + const int v1 = 42; + + auto p0 = QPromise::resolve(42); + auto p1 = QPromise::resolve(v0); + auto p2 = QPromise::resolve(v1); + + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + Q_STATIC_ASSERT((std::is_same>::value)); + + for (const auto& p : {p0, p1, p2}) { + QCOMPARE(p.isFulfilled(), true); + } + for (const auto& p : {p0, p1, p2}) { + QCOMPARE(waitForValue(p, -1), 42); + } +} + +void tst_qpromise_resolve::noValue() +{ + auto p = QPromise::resolve(); + + Q_STATIC_ASSERT((std::is_same>::value)); + + QCOMPARE(p.isFulfilled(), true); + QCOMPARE(waitForValue(p, -1, 42), 42); +} + +void tst_qpromise_resolve::moveRValue() +{ + Data::logs().reset(); + + { + auto p = QtPromise::resolve(Data(42)).wait(); + + Q_STATIC_ASSERT((std::is_same>::value)); + } + + QCOMPARE(Data::logs().ctor, 1); + QCOMPARE(Data::logs().copy, 0); + QCOMPARE(Data::logs().move, 1); + QCOMPARE(Data::logs().refs, 0); +} + +void tst_qpromise_resolve::copyLValue() +{ + Data::logs().reset(); + + { + Data value(42); + auto p = QtPromise::resolve(value).wait(); + + Q_STATIC_ASSERT((std::is_same>::value)); + } + + QCOMPARE(Data::logs().ctor, 1); + QCOMPARE(Data::logs().copy, 1); + QCOMPARE(Data::logs().move, 0); + QCOMPARE(Data::logs().refs, 0); +} + +// https://github.com/simonbrunel/qtpromise/issues/6 +void tst_qpromise_resolve::qtSharedPtr() +{ + Data::logs().reset(); + + QWeakPointer wptr; + + { + QSharedPointer sptr0(new Data(42)); + const QSharedPointer sptr1 = sptr0; + + auto p0 = QPromise>::resolve(QSharedPointer(new Data(42))); + auto p1 = QPromise>::resolve(sptr0); + auto p2 = QPromise>::resolve(sptr1); + + Q_STATIC_ASSERT((std::is_same>>::value)); + Q_STATIC_ASSERT((std::is_same>>::value)); + Q_STATIC_ASSERT((std::is_same>>::value)); + + QCOMPARE(waitForValue(p1, QSharedPointer()), sptr0); + QCOMPARE(waitForValue(p2, QSharedPointer()), sptr1); + + wptr = sptr0; + + QCOMPARE(wptr.isNull(), false); + QCOMPARE(Data::logs().refs, 2); + } + + QCOMPARE(wptr.isNull(), true); + + QCOMPARE(Data::logs().ctor, 2); + QCOMPARE(Data::logs().copy, 0); + QCOMPARE(Data::logs().move, 0); + QCOMPARE(Data::logs().refs, 0); +} + +// https://github.com/simonbrunel/qtpromise/issues/6 +void tst_qpromise_resolve::stdSharedPtr() +{ + Data::logs().reset(); + + std::weak_ptr wptr; + + { + std::shared_ptr sptr0(new Data(42)); + const std::shared_ptr sptr1 = sptr0; + + auto p0 = QPromise>::resolve(std::shared_ptr(new Data(42))); + auto p1 = QPromise>::resolve(sptr0); + auto p2 = QPromise>::resolve(sptr1); + + Q_STATIC_ASSERT((std::is_same>>::value)); + Q_STATIC_ASSERT((std::is_same>>::value)); + Q_STATIC_ASSERT((std::is_same>>::value)); + + QCOMPARE(waitForValue(p1, std::shared_ptr()), sptr0); + QCOMPARE(waitForValue(p2, std::shared_ptr()), sptr1); + + wptr = sptr0; + + QCOMPARE(wptr.use_count(), 4l); + QCOMPARE(Data::logs().refs, 2); + } + + QCOMPARE(wptr.use_count(), 0l); + + QCOMPARE(Data::logs().ctor, 2); + QCOMPARE(Data::logs().copy, 0); + QCOMPARE(Data::logs().move, 0); + QCOMPARE(Data::logs().refs, 0); +} diff --git a/tests/auto/qtpromise/qtpromise.pri b/tests/auto/qtpromise/qtpromise.pri index f3cc18a..7ab29e6 100644 --- a/tests/auto/qtpromise/qtpromise.pri +++ b/tests/auto/qtpromise/qtpromise.pri @@ -8,7 +8,7 @@ DEFINES += QT_DEPRECATED_WARNINGS # Additional warnings and make all warnings into errors # https://github.com/simonbrunel/qtpromise/issues/10 gcc:QMAKE_CXXFLAGS += -Werror -Wold-style-cast -msvc:QMAKE_CXXFLAGS -= -WX +msvc:QMAKE_CXXFLAGS += -WX coverage { gcc { @@ -21,6 +21,7 @@ coverage { } HEADERS += \ + $$PWD/shared/data.h \ $$PWD/shared/object.h \ $$PWD/shared/utils.h diff --git a/tests/auto/qtpromise/qtpromise.pro b/tests/auto/qtpromise/qtpromise.pro index f48c492..8aafbf6 100644 --- a/tests/auto/qtpromise/qtpromise.pro +++ b/tests/auto/qtpromise/qtpromise.pro @@ -1,6 +1,7 @@ TEMPLATE = subdirs SUBDIRS += \ benchmark \ + deprecations \ exceptions \ future \ helpers \ diff --git a/tests/auto/qtpromise/shared/data.h b/tests/auto/qtpromise/shared/data.h new file mode 100644 index 0000000..a708a80 --- /dev/null +++ b/tests/auto/qtpromise/shared/data.h @@ -0,0 +1,76 @@ +#ifndef QTPROMISE_TESTS_AUTO_SHARED_DATA_H +#define QTPROMISE_TESTS_AUTO_SHARED_DATA_H + +// STL +#include + +struct Logs { + int ctor = 0; + int copy = 0; + int move = 0; + int refs = 0; + + void reset() { + ctor = 0; + copy = 0; + move = 0; + refs = 0; + } +}; + +struct Logger +{ + Logger() { logs().ctor++; logs().refs++; } + Logger(const Logger&) { logs().copy++; logs().refs++; } + Logger(Logger&&) { logs().move++; logs().refs++; } + ~Logger() { logs().refs--; } + + Logger& operator=(const Logger&) { logs().copy++; return *this; } + Logger& operator=(Logger&&) { logs().move++; return *this; } + +public: // STATICS + static Logs& logs() { static Logs logs; return logs; } +}; + +struct Data : public Logger +{ + Data(int v) : Logger(), m_value(v) {} + int value() const { return m_value; } + + // MSVC 2013 doesn't support implicit generation of the move constructor and + // operator, so we need to explicitly define these methods and thus the copy + // constructor and operator also need to be explicitly defined (error C2280). + // https://stackoverflow.com/a/26581337 + + Data(const Data& other) + : Logger(other) + , m_value(other.m_value) + { } + + Data(Data&& other) : Logger(std::forward(other)) + { + std::swap(m_value, other.m_value); + } + + Data& operator=(const Data& other) + { + Logger::operator=(other); + m_value = other.m_value; + return *this; + } + + Data& operator=(Data&& other) + { + Logger::operator=(std::forward(other)); + std::swap(m_value, other.m_value); + return *this; + } + + bool operator==(const Data& other) const { return (m_value == other.m_value); } + bool operator!=(const Data& other) const { return (m_value != other.m_value); } + +private: + int m_value; +}; + +#endif // QTPROMISE_TESTS_AUTO_SHARED_DATA_H diff --git a/tests/auto/qtpromise/thread/tst_thread.cpp b/tests/auto/qtpromise/thread/tst_thread.cpp index b57e608..52624eb 100644 --- a/tests/auto/qtpromise/thread/tst_thread.cpp +++ b/tests/auto/qtpromise/thread/tst_thread.cpp @@ -102,7 +102,7 @@ void tst_thread::then() int value = -1; QThread* target = nullptr; - qPromise(QtConcurrent::run([&](const QPromise& p) { + QtPromise::resolve(QtConcurrent::run([&](const QPromise& p) { p.then([&](int res) { target = QThread::currentThread(); value = res; @@ -125,7 +125,7 @@ void tst_thread::then_void() int value = -1; QThread* target = nullptr; - qPromise(QtConcurrent::run([&](const QPromise& p) { + QtPromise::resolve(QtConcurrent::run([&](const QPromise& p) { p.then([&]() { target = QThread::currentThread(); value = 43; @@ -148,7 +148,7 @@ void tst_thread::fail() QString error; QThread* target = nullptr; - qPromise(QtConcurrent::run([&](const QPromise& p) { + QtPromise::resolve(QtConcurrent::run([&](const QPromise& p) { p.fail([&](const QString& err) { target = QThread::currentThread(); error = err; @@ -172,7 +172,7 @@ void tst_thread::finally() int value = -1; QThread* target = nullptr; - qPromise(QtConcurrent::run([&](const QPromise& p) { + QtPromise::resolve(QtConcurrent::run([&](const QPromise& p) { p.finally([&]() { target = QThread::currentThread(); value = 43;