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.
This commit is contained in:
Simon Brunel 2019-02-25 20:03:19 +01:00
parent 1f30224578
commit 963ec621e1
34 changed files with 880 additions and 253 deletions

View File

@ -51,7 +51,7 @@ module.exports = {
'qtpromise/helpers/each', 'qtpromise/helpers/each',
'qtpromise/helpers/filter', 'qtpromise/helpers/filter',
'qtpromise/helpers/map', 'qtpromise/helpers/map',
'qtpromise/helpers/qpromise', 'qtpromise/helpers/resolve',
'qtpromise/helpers/qpromiseall' 'qtpromise/helpers/qpromiseall'
] ]
}, },

View File

@ -31,7 +31,7 @@
* [`QtPromise::each`](helpers/each.md) * [`QtPromise::each`](helpers/each.md)
* [`QtPromise::filter`](helpers/filter.md) * [`QtPromise::filter`](helpers/filter.md)
* [`QtPromise::map`](helpers/map.md) * [`QtPromise::map`](helpers/map.md)
* [`qPromise`](helpers/qpromise.md) * [`QtPromise::resolve`](helpers/resolve.md)
* [`qPromiseAll`](helpers/qpromiseall.md) * [`qPromiseAll`](helpers/qpromiseall.md)
## Exceptions ## Exceptions
@ -39,3 +39,7 @@
* [`QPromiseCanceledException`](exceptions/canceled.md) * [`QPromiseCanceledException`](exceptions/canceled.md)
* [`QPromiseTimeoutException`](exceptions/timeout.md) * [`QPromiseTimeoutException`](exceptions/timeout.md)
* [`QPromiseUndefinedException`](exceptions/undefined.md) * [`QPromiseUndefinedException`](exceptions/undefined.md)
## Deprecations
* `QtPromise::qPromise`: use [`QtPromise::resolve`](helpers/resolve.md) instead (since 0.5.0)

View File

@ -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: 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 ```cpp
auto output = qPromise(future) auto output = QtPromise::resolve(future)
.fail([](const QPromiseCanceledException&) { .fail([](const QPromiseCanceledException&) {
// `future` has been canceled! // `future` has been canceled!
}); });

View File

@ -56,7 +56,7 @@ The following method `uncompress` data in a separate thread and returns a [promi
```cpp ```cpp
QPromise<Entries> uncompress(const QByteArray& data) QPromise<Entries> uncompress(const QByteArray& data)
{ {
return qPromise(QtConcurrent::run([](const QByteArray& data) { return QtPromise::resolve(QtConcurrent::run([](const QByteArray& data) {
Entries entries; Entries entries;
// {...} uncompress data and parse content. // {...} uncompress data and parse content.

View File

@ -1,21 +0,0 @@
---
title: qPromise
---
# qPromise
*Since: 0.1.0*
```
qPromise(T value) -> QPromise<R>
```
Similar to the [`QPromise<T>::resolve`](../qpromise/resolve.md) static method, creates a promise resolved from a given `value` without the extra typing:
```cpp
auto promise = qPromise(); // QPromise<void>
auto promise = qPromise(42); // QPromise<int>
auto promise = qPromise(QString("foo")); // QPromise<QString>
```
This method also allows to convert `QFuture<T>` to `QPromise<T>` delayed until the `QFuture` is finished ([read more](../qtconcurrent.md#convert)).

View File

@ -0,0 +1,21 @@
---
title: resolve
---
# QtPromise::resolve
*Since: 0.5.0*
```
QtPromise::resolve(T value) -> QPromise<R>
```
Similar to the [`QPromise<T>::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<void>
auto promise = QtPromise::resolve(42); // QPromise<int>
auto promise = QtPromise::resolve(QString("foo")); // QPromise<QString>
```
This method also allows to convert `QFuture<T>` to `QPromise<T>`, delayed until the `QFuture` is finished ([read more](../qtconcurrent.md#convert)).

View File

@ -25,4 +25,4 @@ QPromise<int> compute(const QString& type)
} }
``` ```
See also: [`qPromise`](../helpers/qpromise.md) See also: [`QtPromise::resolve`](../helpers/resolve.md)

View File

@ -15,7 +15,7 @@ This method holds the execution of the remaining code until the `input` promise
```cpp ```cpp
int result = -1; int result = -1;
QPromise<int> input = qPromise(QtConcurrent::run([]() { QPromise<int> input = QtPromise::resolve(QtConcurrent::run([]() {
return 42; return 42;
})).tap([&](int res) { })).tap([&](int res) {
result = res; result = res;

View File

@ -4,7 +4,7 @@ QtPromise integrates with [QtConcurrent](https://doc.qt.io/qt-5/qtconcurrent-ind
## <a name="qtconcurrent-convert"></a> Convert ## <a name="qtconcurrent-convert"></a> Convert
Converting `QFuture<T>` to `QPromise<T>` is done using the [`qPromise`](helpers/qpromise.md) helper: Converting `QFuture<T>` to `QPromise<T>` is done using the [`QtPromise::resolve`](helpers/resolve.md) helper:
```cpp ```cpp
QFuture<int> future = QtConcurrent::run([]() { QFuture<int> future = QtConcurrent::run([]() {
@ -12,13 +12,13 @@ QFuture<int> future = QtConcurrent::run([]() {
return 42; return 42;
}); });
QPromise<int> promise = qPromise(future); QPromise<int> promise = QtPromise::resolve(future);
``` ```
or simply: or simply:
```cpp ```cpp
auto promise = qPromise(QtConcurrent::run([]() { auto promise = QtPromise::resolve(QtConcurrent::run([]() {
// {...} // {...}
})); }));
``` ```

View File

@ -279,9 +279,7 @@ inline QPromise<void> QPromise<void>::all(const Sequence<QPromise<void>, Args...
inline QPromise<void> QPromise<void>::resolve() inline QPromise<void> QPromise<void>::resolve()
{ {
return QPromise<void>([](const QPromiseResolve<void>& resolve) { return QtPromise::resolve();
resolve();
});
} }
} // namespace QtPromise } // namespace QtPromise

View File

@ -110,9 +110,24 @@ private:
template <typename T> template <typename T>
struct PromiseDeduce struct PromiseDeduce
{ {
using Type = QtPromise::QPromise<Unqualified<T>>; using Type = QtPromise::QPromise<T>;
}; };
template <typename T>
struct PromiseDeduce<T&>
: public PromiseDeduce<T>
{ };
template <typename T>
struct PromiseDeduce<const T>
: public PromiseDeduce<T>
{ };
template <typename T>
struct PromiseDeduce<const volatile T>
: public PromiseDeduce<T>
{ };
template <typename T> template <typename T>
struct PromiseDeduce<QtPromise::QPromise<T>> struct PromiseDeduce<QtPromise::QPromise<T>>
: public PromiseDeduce<T> : public PromiseDeduce<T>
@ -128,22 +143,21 @@ struct PromiseFunctor
template <typename T> template <typename T>
struct PromiseFulfill struct PromiseFulfill
{ {
static void call( template <typename V, typename TResolve, typename TReject>
T&& value, static void call(V&& value, const TResolve& resolve, const TReject&)
const QtPromise::QPromiseResolve<T>& resolve,
const QtPromise::QPromiseReject<T>&)
{ {
resolve(std::move(value)); resolve(std::forward<V>(value));
} }
}; };
template <typename T> template <typename T>
struct PromiseFulfill<QtPromise::QPromise<T>> struct PromiseFulfill<QtPromise::QPromise<T>>
{ {
template <typename TResolve, typename TReject>
static void call( static void call(
const QtPromise::QPromise<T>& promise, const QtPromise::QPromise<T>& promise,
const QtPromise::QPromiseResolve<T>& resolve, const TResolve& resolve,
const QtPromise::QPromiseReject<T>& reject) const TReject& reject)
{ {
if (promise.isFulfilled()) { if (promise.isFulfilled()) {
resolve(promise.m_d->value()); resolve(promise.m_d->value());

View File

@ -7,21 +7,34 @@
namespace QtPromise { namespace QtPromise {
template <typename T> template <typename T>
static inline typename QtPromisePrivate::PromiseDeduce<T>::Type qPromise(T&& value) static inline typename QtPromisePrivate::PromiseDeduce<T>::Type
resolve(T&& value)
{ {
using namespace QtPromisePrivate; using namespace QtPromisePrivate;
using Promise = typename PromiseDeduce<T>::Type; using PromiseType = typename PromiseDeduce<T>::Type;
return Promise([&]( using ValueType = typename PromiseType::Type;
const QPromiseResolve<typename Promise::Type>& resolve, using ResolveType = QPromiseResolve<ValueType>;
const QPromiseReject<typename Promise::Type>& reject) { using RejectType = QPromiseReject<ValueType>;
PromiseFulfill<T>::call(std::forward<T>(value), resolve, reject);
return PromiseType([&](ResolveType&& resolve, RejectType&& reject) {
PromiseFulfill<Unqualified<T>>::call(
std::forward<T>(value),
std::forward<ResolveType>(resolve),
std::forward<RejectType>(reject));
}); });
} }
static inline QPromise<void> qPromise() template <typename T>
static inline QPromise<T>
resolve(QPromise<T> value)
{ {
return QPromise<void>([]( return std::move(value);
const QPromiseResolve<void>& resolve) { }
static inline QPromise<void>
resolve()
{
return QPromise<void>([](const QPromiseResolve<void>& resolve) {
resolve(); resolve();
}); });
} }
@ -153,6 +166,17 @@ static inline QPromise<Sequence> filter(const Sequence& values, Functor fn)
}); });
} }
// DEPRECATIONS (remove at version 1)
template <typename... Args>
Q_DECL_DEPRECATED_X("Use QtPromise::resolve instead")
static inline auto
qPromise(Args&&... args)
-> decltype(QtPromise::resolve(std::forward<Args>(args)...))
{
return QtPromise::resolve(std::forward<Args>(args)...);
}
} // namespace QtPromise } // namespace QtPromise
#endif // QTPROMISE_QPROMISEHELPERS_H #endif // QTPROMISE_QPROMISEHELPERS_H

View File

@ -1,3 +1,5 @@
#include "../shared/data.h"
// QtPromise // QtPromise
#include <QtPromise> #include <QtPromise>
@ -20,7 +22,6 @@ class tst_benchmark : public QObject
private Q_SLOTS: private Q_SLOTS:
void valueResolve(); void valueResolve();
void valueResolveStatic();
void valueReject(); void valueReject();
void valueThen(); void valueThen();
void valueFinally(); void valueFinally();
@ -34,72 +35,6 @@ private Q_SLOTS:
QTEST_MAIN(tst_benchmark) QTEST_MAIN(tst_benchmark)
#include "tst_benchmark.moc" #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<Data>(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<Data>(other));
qSwap(m_value, other.m_value);
return *this;
}
private:
int m_value;
};
void tst_benchmark::valueResolve() void tst_benchmark::valueResolve()
{ {
{ // should move the value when resolved by rvalue { // 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<Data>::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<Data>::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() void tst_benchmark::valueReject()
{ {
{ // should not create any data if rejected { // should not create any data if rejected

View File

@ -0,0 +1,5 @@
include(../qtpromise.pri)
DEFINES -= QT_DEPRECATED_WARNINGS
gcc:QMAKE_CXXFLAGS += -Wno-deprecated-declarations
msvc:QMAKE_CXXFLAGS -= -wd4996

View File

@ -0,0 +1,3 @@
TEMPLATE = subdirs
SUBDIRS += \
helpers

View File

@ -0,0 +1,3 @@
TEMPLATE = subdirs
SUBDIRS += \
qpromise

View File

@ -0,0 +1,5 @@
QT += concurrent
TARGET = tst_deprecations_helpers_qpromise
SOURCES += $$PWD/tst_qpromise.cpp
include(../../deprecations.pri)

View File

@ -0,0 +1,268 @@
#include "../../../shared/data.h"
#include "../../../shared/utils.h"
// QtPromise
#include <QtPromise>
// Qt
#include <QtConcurrent>
#include <QtTest>
// STL
#include <memory>
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<decltype(p0), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::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<decltype(p), QPromise<void>>::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<decltype(p), QPromise<Data>>::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<decltype(p), QPromise<Data>>::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<Data> wptr;
{
QSharedPointer<Data> sptr0(new Data(42));
const QSharedPointer<Data> sptr1 = sptr0;
auto p0 = qPromise(QSharedPointer<Data>(new Data(42)));
auto p1 = qPromise(sptr0);
auto p2 = qPromise(sptr1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<QSharedPointer<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<QSharedPointer<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<QSharedPointer<Data>>>::value));
QCOMPARE(waitForValue(p1, QSharedPointer<Data>()), sptr0);
QCOMPARE(waitForValue(p2, QSharedPointer<Data>()), 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<Data> wptr;
{
std::shared_ptr<Data> sptr0(new Data(42));
const std::shared_ptr<Data> sptr1 = sptr0;
auto p0 = qPromise(std::shared_ptr<Data>(new Data(42)));
auto p1 = qPromise(sptr0);
auto p2 = qPromise(sptr1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<std::shared_ptr<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<std::shared_ptr<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<std::shared_ptr<Data>>>::value));
QCOMPARE(waitForValue(p1, std::shared_ptr<Data>()), sptr0);
QCOMPARE(waitForValue(p2, std::shared_ptr<Data>()), 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<int>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){
resolve(42);
});
};
QPromise<int> v0(resolver);
const QPromise<int> v1 = v0;
auto p0 = qPromise(QPromise<int>(resolver));
auto p1 = qPromise(v0);
auto p2 = qPromise(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::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<void>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){
resolve();
});
};
QPromise<void> v0(resolver);
const QPromise<void> v1 = v0;
auto p0 = qPromise(QPromise<void>(resolver));
auto p1 = qPromise(v0);
auto p2 = qPromise(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<void>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<void>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<void>>::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<int> v0 = QtConcurrent::run(fn);
const QFuture<int> v1 = v0;
auto p0 = qPromise(QtConcurrent::run(fn));
auto p1 = qPromise(v0);
auto p2 = qPromise(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::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<void> v0 = QtConcurrent::run(fn);
const QFuture<void> v1 = v0;
auto p0 = qPromise(QtConcurrent::run(fn));
auto p1 = qPromise(v0);
auto p2 = qPromise(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<void>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<void>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<void>>::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);
}
}

View File

@ -29,7 +29,7 @@ namespace {
template <class E> template <class E>
void verify() void verify()
{ {
auto p = qPromise(QtConcurrent::run([]() { throw E(); })); auto p = QtPromise::resolve(QtConcurrent::run([]() { throw E(); }));
QCOMPARE(p.isPending(), true); QCOMPARE(p.isPending(), true);
QCOMPARE(waitForRejected<E>(p), true); QCOMPARE(waitForRejected<E>(p), true);
QCOMPARE(p.isRejected(), true); QCOMPARE(p.isRejected(), true);

View File

@ -52,7 +52,7 @@ QTEST_MAIN(tst_future)
void tst_future::fulfilled() void tst_future::fulfilled()
{ {
int result = -1; int result = -1;
auto p = qPromise(QtConcurrent::run([]() { auto p = QtPromise::resolve(QtConcurrent::run([]() {
return 42; return 42;
})); }));
@ -70,7 +70,7 @@ void tst_future::fulfilled()
void tst_future::fulfilled_void() void tst_future::fulfilled_void()
{ {
int result = -1; int result = -1;
auto p = qPromise(QtConcurrent::run([]() { })); auto p = QtPromise::resolve(QtConcurrent::run([]() { }));
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value)); Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
QCOMPARE(p.isPending(), true); QCOMPARE(p.isPending(), true);
@ -86,7 +86,7 @@ void tst_future::fulfilled_void()
void tst_future::rejected() void tst_future::rejected()
{ {
QString error; QString error;
auto p = qPromise(QtConcurrent::run([]() { auto p = QtPromise::resolve(QtConcurrent::run([]() {
throw MyException("foo"); throw MyException("foo");
return 42; return 42;
})); }));
@ -106,7 +106,7 @@ void tst_future::rejected()
void tst_future::rejected_void() void tst_future::rejected_void()
{ {
QString error; QString error;
auto p = qPromise(QtConcurrent::run([]() { auto p = QtPromise::resolve(QtConcurrent::run([]() {
throw MyException("foo"); throw MyException("foo");
})); }));
@ -125,7 +125,7 @@ void tst_future::rejected_void()
void tst_future::unhandled() void tst_future::unhandled()
{ {
QString error; QString error;
auto p = qPromise(QtConcurrent::run([]() { auto p = QtPromise::resolve(QtConcurrent::run([]() {
throw QString("foo"); throw QString("foo");
return 42; return 42;
})); }));
@ -149,7 +149,7 @@ void tst_future::unhandled()
void tst_future::unhandled_void() void tst_future::unhandled_void()
{ {
QString error; QString error;
auto p = qPromise(QtConcurrent::run([]() { auto p = QtPromise::resolve(QtConcurrent::run([]() {
throw QString("foo"); throw QString("foo");
})); }));
@ -169,7 +169,7 @@ void tst_future::unhandled_void()
void tst_future::canceled() void tst_future::canceled()
{ {
QString error; QString error;
auto p = qPromise(QFuture<int>()); // Constructs an empty, canceled future. auto p = QtPromise::resolve(QFuture<int>()); // Constructs an empty, canceled future.
QCOMPARE(p.isPending(), true); QCOMPARE(p.isPending(), true);
@ -185,7 +185,7 @@ void tst_future::canceled()
void tst_future::canceled_void() void tst_future::canceled_void()
{ {
QString error; QString error;
auto p = qPromise(QFuture<void>()); // Constructs an empty, canceled future. auto p = QtPromise::resolve(QFuture<void>()); // Constructs an empty, canceled future.
QCOMPARE(p.isPending(), true); QCOMPARE(p.isPending(), true);
@ -200,7 +200,7 @@ void tst_future::canceled_void()
void tst_future::canceledFromThread() void tst_future::canceledFromThread()
{ {
QString error; QString error;
auto p = qPromise(QtConcurrent::run([]() { auto p = QtPromise::resolve(QtConcurrent::run([]() {
throw QPromiseCanceledException(); throw QPromiseCanceledException();
})); }));
@ -217,7 +217,7 @@ void tst_future::canceledFromThread()
void tst_future::then() void tst_future::then()
{ {
QString result; QString result;
auto input = qPromise(42); auto input = QtPromise::resolve(42);
auto output = input.then([](int res) { auto output = input.then([](int res) {
return QtConcurrent::run([=]() { return QtConcurrent::run([=]() {
return QString("foo%1").arg(res); return QString("foo%1").arg(res);
@ -238,7 +238,7 @@ void tst_future::then()
void tst_future::then_void() void tst_future::then_void()
{ {
QString result; QString result;
auto input = qPromise(); auto input = QtPromise::resolve();
auto output = input.then([&]() { auto output = input.then([&]() {
return QtConcurrent::run([&]() { return QtConcurrent::run([&]() {
result = "foo"; result = "foo";
@ -300,7 +300,7 @@ void tst_future::fail_void()
void tst_future::finally() void tst_future::finally()
{ {
auto input = qPromise(42); auto input = QtPromise::resolve(42);
auto output = input.finally([]() { auto output = input.finally([]() {
return QtConcurrent::run([]() { return QtConcurrent::run([]() {
return QString("foo"); return QString("foo");
@ -323,7 +323,7 @@ void tst_future::finally()
void tst_future::finallyRejected() void tst_future::finallyRejected()
{ {
auto input = qPromise(42); auto input = QtPromise::resolve(42);
auto output = input.finally([]() { auto output = input.finally([]() {
return QtConcurrent::run([]() { return QtConcurrent::run([]() {
throw MyException("foo"); throw MyException("foo");

View File

@ -37,13 +37,13 @@ struct SequenceTester
static void exec() static void exec()
{ {
Sequence promises{ Sequence promises{
QtPromise::qPromise(42), QtPromise::resolve(42),
QtPromise::qPromise(43), QtPromise::resolve(43),
QtPromise::qPromise(44) QtPromise::resolve(44)
}; };
promises.push_back(QtPromise::qPromise(45)); promises.push_back(QtPromise::resolve(45));
promises.insert(++promises.begin(), QtPromise::qPromise(46)); promises.insert(++promises.begin(), QtPromise::resolve(46));
promises.pop_back(); promises.pop_back();
auto p = QtPromise::qPromiseAll(promises); auto p = QtPromise::qPromiseAll(promises);
@ -60,13 +60,13 @@ struct SequenceTester<Sequence<QPromise<void>, Args...>>
static void exec() static void exec()
{ {
Sequence<QPromise<void>, Args...> promises{ Sequence<QPromise<void>, Args...> promises{
QtPromise::qPromise(), QtPromise::resolve(),
QtPromise::qPromise(), QtPromise::resolve(),
QtPromise::qPromise() QtPromise::resolve()
}; };
promises.push_back(QtPromise::qPromise()); promises.push_back(QtPromise::resolve());
promises.insert(++promises.begin(), QtPromise::qPromise()); promises.insert(++promises.begin(), QtPromise::resolve());
promises.pop_back(); promises.pop_back();
auto p = QtPromise::qPromiseAll(promises); auto p = QtPromise::qPromiseAll(promises);
@ -99,8 +99,8 @@ void tst_helpers_all::emptySequence_void()
void tst_helpers_all::allPromisesSucceed() void tst_helpers_all::allPromisesSucceed()
{ {
auto p0 = QtPromise::qPromise(42); auto p0 = QtPromise::resolve(42);
auto p1 = QtPromise::qPromise(44); auto p1 = QtPromise::resolve(44);
auto p2 = QPromise<int>([](const QPromiseResolve<int>& resolve) { auto p2 = QPromise<int>([](const QPromiseResolve<int>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=](){
resolve(43); resolve(43);
@ -120,8 +120,8 @@ void tst_helpers_all::allPromisesSucceed()
void tst_helpers_all::allPromisesSucceed_void() void tst_helpers_all::allPromisesSucceed_void()
{ {
auto p0 = QtPromise::qPromise(); auto p0 = QtPromise::resolve();
auto p1 = QtPromise::qPromise(); auto p1 = QtPromise::resolve();
auto p2 = QPromise<void>([](const QPromiseResolve<void>& resolve) { auto p2 = QPromise<void>([](const QPromiseResolve<void>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=](){
resolve(); resolve();
@ -141,8 +141,8 @@ void tst_helpers_all::allPromisesSucceed_void()
void tst_helpers_all::atLeastOnePromiseReject() void tst_helpers_all::atLeastOnePromiseReject()
{ {
auto p0 = QtPromise::qPromise(42); auto p0 = QtPromise::resolve(42);
auto p1 = QtPromise::qPromise(44); auto p1 = QtPromise::resolve(44);
auto p2 = QPromise<int>([](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) { auto p2 = QPromise<int>([](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=](){
reject(QString("foo")); reject(QString("foo"));
@ -162,8 +162,8 @@ void tst_helpers_all::atLeastOnePromiseReject()
void tst_helpers_all::atLeastOnePromiseReject_void() void tst_helpers_all::atLeastOnePromiseReject_void()
{ {
auto p0 = QtPromise::qPromise(); auto p0 = QtPromise::resolve();
auto p1 = QtPromise::qPromise(); auto p1 = QtPromise::resolve();
auto p2 = QPromise<void>([](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) { auto p2 = QPromise<void>([](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=](){
reject(QString("foo")); reject(QString("foo"));
@ -183,9 +183,9 @@ void tst_helpers_all::atLeastOnePromiseReject_void()
void tst_helpers_all::preserveOrder() void tst_helpers_all::preserveOrder()
{ {
auto p0 = QtPromise::qPromise(42).delay(500); auto p0 = QtPromise::resolve(42).delay(500);
auto p1 = QtPromise::qPromise(43).delay(100); auto p1 = QtPromise::resolve(43).delay(100);
auto p2 = QtPromise::qPromise(44).delay(250); auto p2 = QtPromise::resolve(44).delay(250);
auto p = QtPromise::qPromiseAll(QVector<QPromise<int>>{p0, p1, p2}); auto p = QtPromise::qPromiseAll(QVector<QPromise<int>>{p0, p1, p2});

View File

@ -64,7 +64,7 @@ void tst_helpers_attempt::futureResult()
void tst_helpers_attempt::promiseResult() void tst_helpers_attempt::promiseResult()
{ {
auto p = QtPromise::attempt([]() { auto p = QtPromise::attempt([]() {
return QtPromise::qPromise(42).delay(200); return QtPromise::resolve(42).delay(200);
}); });
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value)); Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));

View File

@ -1,3 +1,4 @@
QT += concurrent
TARGET = tst_helpers_resolve TARGET = tst_helpers_resolve
SOURCES += $$PWD/tst_resolve.cpp SOURCES += $$PWD/tst_resolve.cpp

View File

@ -1,9 +1,11 @@
#include "../../shared/data.h"
#include "../../shared/utils.h" #include "../../shared/utils.h"
// QtPromise // QtPromise
#include <QtPromise> #include <QtPromise>
// Qt // Qt
#include <QtConcurrent>
#include <QtTest> #include <QtTest>
// STL // STL
@ -16,109 +18,251 @@ class tst_helpers_resolve : public QObject
Q_OBJECT Q_OBJECT
private Q_SLOTS: private Q_SLOTS:
void resolveWithValue(); void value();
void resolveWithNoValue(); void noValue();
void resolveWithTypedPromise(); void moveRValue();
void resolveWithVoidPromise(); void copyLValue();
void resolveWithQSharedPtr(); void qtSharedPtr();
void resolveWithStdSharedPtr(); void stdSharedPtr();
void typedPromise();
void voidPromise();
void typedFuture();
void voidFuture();
}; };
QTEST_MAIN(tst_helpers_resolve) QTEST_MAIN(tst_helpers_resolve)
#include "tst_resolve.moc" #include "tst_resolve.moc"
void tst_helpers_resolve::resolveWithValue() void tst_helpers_resolve::value()
{ {
const int value = 42; int v0 = 42;
auto p0 = QPromise<int>::resolve(value); const int v1 = 42;
auto p1 = QPromise<int>::resolve(43);
auto p0 = QtPromise::resolve(42);
auto p1 = QtPromise::resolve(v0);
auto p2 = QtPromise::resolve(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value)); Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value)); Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
QCOMPARE(p0.isFulfilled(), true); Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::value));
QCOMPARE(p1.isFulfilled(), true);
QCOMPARE(waitForValue(p0, -1), 42); for (const auto& p : {p0, p1, p2}) {
QCOMPARE(waitForValue(p1, -1), 43); 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<void>::resolve(); auto p = QtPromise::resolve();
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value)); Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
QCOMPARE(p.isFulfilled(), true); QCOMPARE(p.isFulfilled(), true);
QCOMPARE(waitForValue(p, -1, 42), 42); QCOMPARE(waitForValue(p, -1, 42), 42);
} }
void tst_helpers_resolve::resolveWithTypedPromise() void tst_helpers_resolve::moveRValue()
{ {
auto p = QtPromise::qPromise( Data::logs().reset();
QPromise<QString>([](const QPromiseResolve<QString>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){
resolve("foo");
});
}));
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value)); {
auto p = QtPromise::resolve(Data(42)).wait();
QCOMPARE(p.isPending(), true); Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Data>>::value));
QCOMPARE(waitForValue(p, QString()), QString("foo"));
} }
void tst_helpers_resolve::resolveWithVoidPromise() QCOMPARE(Data::logs().ctor, 1);
QCOMPARE(Data::logs().copy, 0);
QCOMPARE(Data::logs().move, 1);
QCOMPARE(Data::logs().refs, 0);
}
void tst_helpers_resolve::copyLValue()
{ {
int check; Data::logs().reset();
auto p = QtPromise::qPromise(
QPromise<void>([&](const QPromiseResolve<void>& resolve) {
QtPromisePrivate::qtpromise_defer([=, &check](){
check = 8;
resolve();
});
}));
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value)); {
Data value(42);
auto p = QtPromise::resolve(value).wait();
QCOMPARE(p.isPending(), true); Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Data>>::value));
QCOMPARE(waitForValue(p, -1, 42), 42); }
QCOMPARE(check, 8);
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 // https://github.com/simonbrunel/qtpromise/issues/6
void tst_helpers_resolve::resolveWithQSharedPtr() void tst_helpers_resolve::qtSharedPtr()
{ {
QWeakPointer<int> wptr; Data::logs().reset();
QWeakPointer<Data> wptr;
{ {
QSharedPointer<int> sptr(new int(42)); QSharedPointer<Data> sptr0(new Data(42));
auto p = QPromise<QSharedPointer<int>>::resolve(sptr); const QSharedPointer<Data> sptr1 = sptr0;
QCOMPARE(waitForValue(p, QSharedPointer<int>()), sptr); auto p0 = QtPromise::resolve(QSharedPointer<Data>(new Data(42)));
auto p1 = QtPromise::resolve(sptr0);
auto p2 = QtPromise::resolve(sptr1);
wptr = sptr; Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<QSharedPointer<Data>>>::value));
sptr.reset(); Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<QSharedPointer<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<QSharedPointer<Data>>>::value));
QCOMPARE(wptr.isNull(), false); // "p" still holds a reference QCOMPARE(waitForValue(p1, QSharedPointer<Data>()), sptr0);
QCOMPARE(waitForValue(p2, QSharedPointer<Data>()), sptr1);
wptr = sptr0;
QCOMPARE(wptr.isNull(), false);
QCOMPARE(Data::logs().refs, 2);
} }
QCOMPARE(wptr.isNull(), true); 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 // https://github.com/simonbrunel/qtpromise/issues/6
void tst_helpers_resolve::resolveWithStdSharedPtr() void tst_helpers_resolve::stdSharedPtr()
{ {
std::weak_ptr<int> wptr; Data::logs().reset();
std::weak_ptr<Data> wptr;
{ {
std::shared_ptr<int> sptr(new int(42)); std::shared_ptr<Data> sptr0(new Data(42));
auto p = QPromise<std::shared_ptr<int>>::resolve(sptr); const std::shared_ptr<Data> sptr1 = sptr0;
QCOMPARE(waitForValue(p, std::shared_ptr<int>()), sptr); auto p0 = QtPromise::resolve(std::shared_ptr<Data>(new Data(42)));
auto p1 = QtPromise::resolve(sptr0);
auto p2 = QtPromise::resolve(sptr1);
wptr = sptr; Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<std::shared_ptr<Data>>>::value));
sptr.reset(); Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<std::shared_ptr<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<std::shared_ptr<Data>>>::value));
QCOMPARE(wptr.use_count(), 1l); // "p" still holds a reference QCOMPARE(waitForValue(p1, std::shared_ptr<Data>()), sptr0);
QCOMPARE(waitForValue(p2, std::shared_ptr<Data>()), sptr1);
wptr = sptr0;
QCOMPARE(wptr.use_count(), 4l);
QCOMPARE(Data::logs().refs, 2);
} }
QCOMPARE(wptr.use_count(), 0l); 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<int>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){
resolve(42);
});
};
QPromise<int> v0(resolver);
const QPromise<int> v1 = v0;
auto p0 = QtPromise::resolve(QPromise<int>(resolver));
auto p1 = QtPromise::resolve(v0);
auto p2 = QtPromise::resolve(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::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<void>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){
resolve();
});
};
QPromise<void> v0(resolver);
const QPromise<void> v1 = v0;
auto p0 = QtPromise::resolve(QPromise<void>(resolver));
auto p1 = QtPromise::resolve(v0);
auto p2 = QtPromise::resolve(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<void>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<void>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<void>>::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<int> v0 = QtConcurrent::run(fn);
const QFuture<int> 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<decltype(p0), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::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<void> v0 = QtConcurrent::run(fn);
const QFuture<void> 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<decltype(p0), QPromise<void>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<void>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<void>>::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);
}
} }

View File

@ -34,14 +34,14 @@ struct SequenceTester
static void exec() static void exec()
{ {
QVector<int> values; QVector<int> 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; values << i << v;
}).each([&](int v, ...) { }).each([&](int v, ...) {
values << v; values << v;
return QString("foo"); return QString("foo");
}).each([&](int v, ...) { }).each([&](int v, ...) {
values << v + 1; values << v + 1;
return QPromise<QString>::resolve(QString("foo")).then([&](){ return QtPromise::resolve(QString("foo")).then([&](){
values << -1; values << -1;
}); });
}).each([&](int v, ...) { }).each([&](int v, ...) {

View File

@ -33,7 +33,7 @@ struct SequenceTester
{ {
static void exec() static void exec()
{ {
auto p = QtPromise::qPromise(Sequence{ auto p = QtPromise::resolve(Sequence{
42, 43, 44, 45, 46, 47, 48, 49, 50, 51 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
}).filter([](int v, ...) { }).filter([](int v, ...) {
return v > 42 && v < 51; return v > 42 && v < 51;

View File

@ -34,12 +34,12 @@ struct SequenceTester
{ {
static void exec() 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); return QString::number(v + 1);
}).map([](const QString& v, int i) { }).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, ...) { }).map([](const QString& v, ...) {
return QtPromise::qPromise((v + "!").toUtf8()); return QtPromise::resolve((v + "!").toUtf8());
}).map([](const QByteArray& v, ...) { }).map([](const QByteArray& v, ...) {
return QString::fromUtf8(v); return QString::fromUtf8(v);
}); });
@ -53,7 +53,7 @@ struct SequenceTester
void tst_qpromise_map::emptySequence() void tst_qpromise_map::emptySequence()
{ {
auto p = QtPromise::qPromise(QVector<int>{}).map([](int v, ...) { auto p = QtPromise::resolve(QVector<int>{}).map([](int v, ...) {
return v + 1; return v + 1;
}); });
@ -63,7 +63,7 @@ void tst_qpromise_map::emptySequence()
void tst_qpromise_map::modifyValues() void tst_qpromise_map::modifyValues()
{ {
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) { auto p = QtPromise::resolve(QVector<int>{42, 43, 44}).map([](int v, ...) {
return v + 1; return v + 1;
}); });
@ -73,7 +73,7 @@ void tst_qpromise_map::modifyValues()
void tst_qpromise_map::convertValues() void tst_qpromise_map::convertValues()
{ {
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) { auto p = QtPromise::resolve(QVector<int>{42, 43, 44}).map([](int v, ...) {
return QString::number(v + 1); return QString::number(v + 1);
}); });
@ -83,7 +83,7 @@ void tst_qpromise_map::convertValues()
void tst_qpromise_map::delayedFulfilled() void tst_qpromise_map::delayedFulfilled()
{ {
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) { auto p = QtPromise::resolve(QVector<int>{42, 43, 44}).map([](int v, ...) {
return QPromise<int>([&](const QPromiseResolve<int>& resolve) { return QPromise<int>([&](const QPromiseResolve<int>& resolve) {
QtPromisePrivate::qtpromise_defer([=]() { QtPromisePrivate::qtpromise_defer([=]() {
resolve(v + 1); resolve(v + 1);
@ -97,7 +97,7 @@ void tst_qpromise_map::delayedFulfilled()
void tst_qpromise_map::delayedRejected() void tst_qpromise_map::delayedRejected()
{ {
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) { auto p = QtPromise::resolve(QVector<int>{42, 43, 44}).map([](int v, ...) {
return QPromise<int>([&]( return QPromise<int>([&](
const QPromiseResolve<int>& resolve, const QPromiseResolve<int>& resolve,
const QPromiseReject<int>& reject) { const QPromiseReject<int>& reject) {
@ -116,7 +116,7 @@ void tst_qpromise_map::delayedRejected()
void tst_qpromise_map::functorThrows() void tst_qpromise_map::functorThrows()
{ {
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) { auto p = QtPromise::resolve(QVector<int>{42, 43, 44}).map([](int v, ...) {
if (v == 43) { if (v == 43) {
throw QString("foo"); throw QString("foo");
} }
@ -129,7 +129,7 @@ void tst_qpromise_map::functorThrows()
void tst_qpromise_map::functorArguments() void tst_qpromise_map::functorArguments()
{ {
auto p1 = QtPromise::qPromise(QVector<int>{42, 42, 42}).map([](int v, int i) { auto p1 = QtPromise::resolve(QVector<int>{42, 42, 42}).map([](int v, int i) {
return v * i; return v * i;
}); });
@ -139,8 +139,8 @@ void tst_qpromise_map::functorArguments()
void tst_qpromise_map::preserveOrder() void tst_qpromise_map::preserveOrder()
{ {
auto p = QtPromise::qPromise(QVector<int>{250, 500, 100}).map([](int v, ...) { auto p = QtPromise::resolve(QVector<int>{250, 500, 100}).map([](int v, ...) {
return QtPromise::qPromise(v + 1).delay(v); return QtPromise::resolve(v + 1).delay(v);
}); });
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value)); Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));

View File

@ -8,6 +8,7 @@ SUBDIRS += \
finally \ finally \
map \ map \
operators \ operators \
resolve \
tap \ tap \
tapfail \ tapfail \
then \ then \

View File

@ -0,0 +1,4 @@
TARGET = tst_qpromise_resolve
SOURCES += $$PWD/tst_resolve.cpp
include(../../qtpromise.pri)

View File

@ -0,0 +1,165 @@
#include "../../shared/data.h"
#include "../../shared/utils.h"
// QtPromise
#include <QtPromise>
// Qt
#include <QtTest>
// STL
#include <memory>
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<int>::resolve(42);
auto p1 = QPromise<int>::resolve(v0);
auto p2 = QPromise<int>::resolve(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::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<void>::resolve();
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::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<decltype(p), QPromise<Data>>::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<decltype(p), QPromise<Data>>::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<Data> wptr;
{
QSharedPointer<Data> sptr0(new Data(42));
const QSharedPointer<Data> sptr1 = sptr0;
auto p0 = QPromise<QSharedPointer<Data>>::resolve(QSharedPointer<Data>(new Data(42)));
auto p1 = QPromise<QSharedPointer<Data>>::resolve(sptr0);
auto p2 = QPromise<QSharedPointer<Data>>::resolve(sptr1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<QSharedPointer<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<QSharedPointer<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<QSharedPointer<Data>>>::value));
QCOMPARE(waitForValue(p1, QSharedPointer<Data>()), sptr0);
QCOMPARE(waitForValue(p2, QSharedPointer<Data>()), 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<Data> wptr;
{
std::shared_ptr<Data> sptr0(new Data(42));
const std::shared_ptr<Data> sptr1 = sptr0;
auto p0 = QPromise<std::shared_ptr<Data>>::resolve(std::shared_ptr<Data>(new Data(42)));
auto p1 = QPromise<std::shared_ptr<Data>>::resolve(sptr0);
auto p2 = QPromise<std::shared_ptr<Data>>::resolve(sptr1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<std::shared_ptr<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<std::shared_ptr<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<std::shared_ptr<Data>>>::value));
QCOMPARE(waitForValue(p1, std::shared_ptr<Data>()), sptr0);
QCOMPARE(waitForValue(p2, std::shared_ptr<Data>()), 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);
}

View File

@ -8,7 +8,7 @@ DEFINES += QT_DEPRECATED_WARNINGS
# Additional warnings and make all warnings into errors # Additional warnings and make all warnings into errors
# https://github.com/simonbrunel/qtpromise/issues/10 # https://github.com/simonbrunel/qtpromise/issues/10
gcc:QMAKE_CXXFLAGS += -Werror -Wold-style-cast gcc:QMAKE_CXXFLAGS += -Werror -Wold-style-cast
msvc:QMAKE_CXXFLAGS -= -WX msvc:QMAKE_CXXFLAGS += -WX
coverage { coverage {
gcc { gcc {
@ -21,6 +21,7 @@ coverage {
} }
HEADERS += \ HEADERS += \
$$PWD/shared/data.h \
$$PWD/shared/object.h \ $$PWD/shared/object.h \
$$PWD/shared/utils.h $$PWD/shared/utils.h

View File

@ -1,6 +1,7 @@
TEMPLATE = subdirs TEMPLATE = subdirs
SUBDIRS += \ SUBDIRS += \
benchmark \ benchmark \
deprecations \
exceptions \ exceptions \
future \ future \
helpers \ helpers \

View File

@ -0,0 +1,76 @@
#ifndef QTPROMISE_TESTS_AUTO_SHARED_DATA_H
#define QTPROMISE_TESTS_AUTO_SHARED_DATA_H
// STL
#include <utility>
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<Data>(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<Data>(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

View File

@ -102,7 +102,7 @@ void tst_thread::then()
int value = -1; int value = -1;
QThread* target = nullptr; QThread* target = nullptr;
qPromise(QtConcurrent::run([&](const QPromise<int>& p) { QtPromise::resolve(QtConcurrent::run([&](const QPromise<int>& p) {
p.then([&](int res) { p.then([&](int res) {
target = QThread::currentThread(); target = QThread::currentThread();
value = res; value = res;
@ -125,7 +125,7 @@ void tst_thread::then_void()
int value = -1; int value = -1;
QThread* target = nullptr; QThread* target = nullptr;
qPromise(QtConcurrent::run([&](const QPromise<void>& p) { QtPromise::resolve(QtConcurrent::run([&](const QPromise<void>& p) {
p.then([&]() { p.then([&]() {
target = QThread::currentThread(); target = QThread::currentThread();
value = 43; value = 43;
@ -148,7 +148,7 @@ void tst_thread::fail()
QString error; QString error;
QThread* target = nullptr; QThread* target = nullptr;
qPromise(QtConcurrent::run([&](const QPromise<int>& p) { QtPromise::resolve(QtConcurrent::run([&](const QPromise<int>& p) {
p.fail([&](const QString& err) { p.fail([&](const QString& err) {
target = QThread::currentThread(); target = QThread::currentThread();
error = err; error = err;
@ -172,7 +172,7 @@ void tst_thread::finally()
int value = -1; int value = -1;
QThread* target = nullptr; QThread* target = nullptr;
qPromise(QtConcurrent::run([&](const QPromise<int>& p) { QtPromise::resolve(QtConcurrent::run([&](const QPromise<int>& p) {
p.finally([&]() { p.finally([&]() {
target = QThread::currentThread(); target = QThread::currentThread();
value = 43; value = 43;