mirror of
https://github.com/simonbrunel/qtpromise.git
synced 2025-07-02 07:15:25 +08:00
Compare commits
8 Commits
wip/qtqmlp
...
feat/cast
Author | SHA1 | Date | |
---|---|---|---|
5523597e7c | |||
26a2110a14 | |||
fa987a5044 | |||
7b0cba5b9d | |||
2c8ed6e676 | |||
d128a5fa8d | |||
dcbb2ef860 | |||
50bae380be |
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,7 +8,6 @@ node_modules
|
||||
*.obj
|
||||
*.exe
|
||||
*.user
|
||||
*.qmlc
|
||||
Makefile*
|
||||
moc_*.cpp
|
||||
moc_*.h
|
||||
|
@ -30,7 +30,3 @@ script:
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash) -f coverage.info
|
||||
|
||||
|
||||
# gitbook install .
|
||||
# gitbook build . dist/docs
|
||||
|
@ -11,6 +11,7 @@
|
||||
* [.isPending](qtpromise/qpromise/ispending.md)
|
||||
* [.isRejected](qtpromise/qpromise/isrejected.md)
|
||||
* [.tap](qtpromise/qpromise/tap.md)
|
||||
* [.tapFail](qtpromise/qpromise/tapfail.md)
|
||||
* [.then](qtpromise/qpromise/then.md)
|
||||
* [.timeout](qtpromise/qpromise/timeout.md)
|
||||
* [.wait](qtpromise/qpromise/wait.md)
|
||||
|
@ -10,6 +10,7 @@
|
||||
* [`QPromise<T>::isPending`](qpromise/ispending.md)
|
||||
* [`QPromise<T>::isRejected`](qpromise/isrejected.md)
|
||||
* [`QPromise<T>::tap`](qpromise/tap.md)
|
||||
* [`QPromise<T>::tapFail`](qpromise/tapfail.md)
|
||||
* [`QPromise<T>::then`](qpromise/then.md)
|
||||
* [`QPromise<T>::timeout`](qpromise/timeout.md)
|
||||
* [`QPromise<T>::wait`](qpromise/wait.md)
|
||||
|
@ -4,7 +4,9 @@
|
||||
[static] QPromise<T>::all(Sequence<QPromise<T>> promises) -> QPromise<QVector<T>>
|
||||
```
|
||||
|
||||
Returns a `QPromise<QVector<T>>` that fulfills when **all** `promises` of (the same) type `T` have been fulfilled. The `output` value is a vector containing **all** the values of `promises`, in the same order. If any of the given `promises` fail, `output` immediately rejects with the error of the promise that rejected, whether or not the other promises are resolved.
|
||||
Returns a `QPromise<QVector<T>>` that fulfills when **all** `promises` of (the same) type `T` have been fulfilled. The `output` value is a vector containing all the values of `promises`, in the same order, i.e., at the respective positions to the original sequence, regardless of completion order.
|
||||
|
||||
If any of the given `promises` fail, `output` immediately rejects with the error of the promise that rejected, whether or not the other promises are resolved.
|
||||
|
||||
`Sequence` is any STL compatible container (eg. `QVector`, `QList`, `std::vector`, etc.)
|
||||
|
||||
|
21
docs/qtpromise/qpromise/tapfail.md
Normal file
21
docs/qtpromise/qpromise/tapfail.md
Normal file
@ -0,0 +1,21 @@
|
||||
## `QPromise<T>::tapFail`
|
||||
|
||||
```
|
||||
QPromise<T>::tapFail(Function handler) -> QPromise<T>
|
||||
```
|
||||
|
||||
This `handler` allows to observe errors of the `input` promise without handling them - similar to [`finally`](finally.md) but **only** called on rejections. The `output` promise has the same type as the `input` one but also the same value or error. However, if `handler` throws, `output` is rejected with the new exception.
|
||||
|
||||
```cpp
|
||||
QPromise<int> input = {...}
|
||||
auto output = input.tapFail([](Error err) {
|
||||
log(err);
|
||||
}).then([](int res) {
|
||||
return process(res);
|
||||
}).fail([](Error err) {
|
||||
handle(err);
|
||||
return -1;
|
||||
});
|
||||
```
|
||||
|
||||
If `handler` returns a promise (or QFuture), the `output` promise is delayed until the returned promise is resolved and under the same conditions: the delayed value is ignored, the error transmitted to the `output` promise.
|
@ -1,6 +0,0 @@
|
||||
#ifndef QTQMLPROMISE_MODULE_H
|
||||
#define QTQMLPROMISE_MODULE_H
|
||||
|
||||
#include "../src/qtqmlpromise/qjspromise.h"
|
||||
|
||||
#endif // ifndef QTQMLPROMISE_MODULE_H
|
@ -1,11 +1,3 @@
|
||||
INCLUDEPATH += $$PWD/include $$PWD/src
|
||||
DEPENDPATH += $$PWD/include $$PWD/src
|
||||
CONFIG += c++11
|
||||
|
||||
qtpromise-qml {
|
||||
QML_IMPORT_PATH += $$shadowed($$PWD)/qml
|
||||
|
||||
# To avoid carrying an extra library dependency, the QJSPromise definition is
|
||||
# embedded in the QML plugin, so we need to link against the plugin itself.
|
||||
LIBS += -L$$shadowed($$PWD)/qml/QtPromise -l$$qtLibraryTarget(qtpromiseplugin)
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = \
|
||||
src \
|
||||
tests
|
||||
|
||||
tests.depends = src
|
||||
_qt_creator_ {
|
||||
SUBDIRS += src
|
||||
}
|
||||
|
||||
OTHER_FILES = \
|
||||
package/features/*.prf \
|
||||
|
@ -1,25 +0,0 @@
|
||||
TEMPLATE = lib
|
||||
CONFIG += plugin exceptions
|
||||
QT += qml
|
||||
|
||||
IMPORT_VERSION = 1.0
|
||||
DEFINES += QTQMLPROMISE_LIBRARY
|
||||
|
||||
TARGET = $$qtLibraryTarget(qtpromiseplugin)
|
||||
DESTDIR = $$shadowed($$PWD/../../qml/QtPromise)
|
||||
|
||||
include(../qtqmlpromise/qtqmlpromise.pri)
|
||||
include(../../qtpromise.pri)
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/plugin.cpp
|
||||
|
||||
QMLFILES += \
|
||||
$$PWD/plugins.qmltypes \
|
||||
$$PWD/qmldir
|
||||
|
||||
RESOURCES += $$PWD/imports.qrc
|
||||
|
||||
qmlfiles.files = $$QMLFILES
|
||||
qmlfiles.path = $$DESTDIR
|
||||
COPIES += qmlfiles
|
@ -1,5 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="/QtPromise">
|
||||
<file>qtqmlpromise.js</file>
|
||||
</qresource>
|
||||
</RCC>
|
@ -1,76 +0,0 @@
|
||||
// QtPromise
|
||||
#include <QtQmlPromise>
|
||||
|
||||
// Qt
|
||||
#include <QQmlEngine>
|
||||
#include <QQmlExtensionPlugin>
|
||||
|
||||
static const char* kJSPromisePrivateNamespace = "__qtpromise_private__";
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class QtQmlPromiseObject : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QtQmlPromiseObject(QJSEngine* engine)
|
||||
: QObject(engine)
|
||||
, m_engine(engine)
|
||||
{
|
||||
Q_ASSERT(engine);
|
||||
}
|
||||
|
||||
Q_INVOKABLE QJSValue create(const QJSValue& resolver, const QJSValue& prototype)
|
||||
{
|
||||
QJSValue value = m_engine->toScriptValue(QJSPromise(m_engine, resolver));
|
||||
value.setPrototype(prototype);
|
||||
return value;
|
||||
}
|
||||
|
||||
Q_INVOKABLE QtPromise::QJSPromise resolve(QJSValue value)
|
||||
{
|
||||
return QJSPromise::resolve(std::move(value));
|
||||
}
|
||||
|
||||
Q_INVOKABLE QtPromise::QJSPromise reject(QJSValue error)
|
||||
{
|
||||
return QJSPromise::reject(std::move(error));
|
||||
}
|
||||
|
||||
Q_INVOKABLE QtPromise::QJSPromise all(QJSValue input)
|
||||
{
|
||||
return QJSPromise::all(m_engine, std::move(input));
|
||||
}
|
||||
|
||||
private:
|
||||
QJSEngine* m_engine;
|
||||
};
|
||||
|
||||
class QtQmlPromisePlugin : public QQmlExtensionPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
|
||||
|
||||
public:
|
||||
void registerTypes(const char* uri) Q_DECL_OVERRIDE
|
||||
{
|
||||
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtPromise"));
|
||||
Q_UNUSED(uri);
|
||||
|
||||
qRegisterMetaType<QJSPromise>();
|
||||
}
|
||||
|
||||
void initializeEngine(QQmlEngine* engine, const char* uri) Q_DECL_OVERRIDE
|
||||
{
|
||||
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtPromise"));
|
||||
Q_UNUSED(uri);
|
||||
|
||||
QJSValue global = engine->globalObject();
|
||||
QJSValue object = engine->newQObject(new QtQmlPromiseObject(engine));
|
||||
global.setProperty(kJSPromisePrivateNamespace, object);
|
||||
}
|
||||
|
||||
}; // class QtQmlPromisePlugin
|
||||
|
||||
#include "plugin.moc"
|
@ -1,5 +0,0 @@
|
||||
import QtQuick.tooling 1.2
|
||||
|
||||
Module {
|
||||
dependencies: []
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
module QtPromise
|
||||
plugin qtpromiseplugin
|
||||
typeinfo plugins.qmltypes
|
||||
classname QtQmlPromisePlugin
|
||||
Promise 1.0 qrc:///QtPromise/qtqmlpromise.js
|
@ -1,16 +0,0 @@
|
||||
.pragma library
|
||||
|
||||
(function(global) {
|
||||
var private = global.__qtpromise_private__;
|
||||
delete global.__qtpromise_private__;
|
||||
|
||||
var Promise = global.Promise = function(resolver) {
|
||||
return private.create(function(proxy) {
|
||||
resolver(proxy.resolve, proxy.reject);
|
||||
}, this);
|
||||
};
|
||||
|
||||
['all', 'reject', 'resolve'].forEach(function(method) {
|
||||
Promise[method] = private[method];
|
||||
});
|
||||
})(this);
|
@ -3,6 +3,7 @@
|
||||
|
||||
// QtPromise
|
||||
#include "qpromise_p.h"
|
||||
#include "qpromiseerror.h"
|
||||
#include "qpromiseglobal.h"
|
||||
|
||||
// Qt
|
||||
@ -22,6 +23,9 @@ public:
|
||||
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count != 1, int>::type = 0>
|
||||
inline QPromiseBase(F resolver);
|
||||
|
||||
template <typename U>
|
||||
inline QPromiseBase(const QPromise<U>& other);
|
||||
|
||||
QPromiseBase(const QPromiseBase<T>& other): m_d(other.m_d) {}
|
||||
QPromiseBase(const QPromise<T>& other): m_d(other.m_d) {}
|
||||
QPromiseBase(QPromiseBase<T>&& other) Q_DECL_NOEXCEPT { swap(other); }
|
||||
@ -59,6 +63,9 @@ public:
|
||||
template <typename THandler>
|
||||
inline QPromise<T> tap(THandler handler) const;
|
||||
|
||||
template <typename THandler>
|
||||
inline QPromise<T> tapFail(THandler handler) const;
|
||||
|
||||
template <typename E = QPromiseTimeoutException>
|
||||
inline QPromise<T> timeout(int msec, E&& error = E()) const;
|
||||
|
||||
@ -70,11 +77,10 @@ public: // STATIC
|
||||
inline static QPromise<T> reject(E&& error);
|
||||
|
||||
protected:
|
||||
friend struct QtPromisePrivate::PromiseFulfill<QPromise<T> >;
|
||||
friend class QPromiseResolve<T>;
|
||||
friend class QPromiseReject<T>;
|
||||
friend struct QtPromisePrivate::PromiseFulfill<QPromise<T>>;
|
||||
friend class QtPromisePrivate::PromiseResolver<T>;
|
||||
|
||||
QExplicitlySharedDataPointer<QtPromisePrivate::PromiseData<T> > m_d;
|
||||
QExplicitlySharedDataPointer<QtPromisePrivate::PromiseData<T>> m_d;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -86,11 +92,14 @@ public:
|
||||
|
||||
public: // STATIC
|
||||
template <template <typename, typename...> class Sequence = QVector, typename ...Args>
|
||||
inline static QPromise<QVector<T> > all(const Sequence<QPromise<T>, Args...>& promises);
|
||||
inline static QPromise<QVector<T>> all(const Sequence<QPromise<T>, Args...>& promises);
|
||||
|
||||
inline static QPromise<T> resolve(const T& value);
|
||||
inline static QPromise<T> resolve(T&& value);
|
||||
|
||||
template <typename U>
|
||||
operator QPromise<U>();
|
||||
|
||||
private:
|
||||
friend class QPromiseBase<T>;
|
||||
};
|
||||
@ -102,6 +111,9 @@ public:
|
||||
template <typename F>
|
||||
QPromise(F&& resolver): QPromiseBase<void>(std::forward<F>(resolver)) { }
|
||||
|
||||
template <typename T>
|
||||
QPromise(const QPromise<T>& other);
|
||||
|
||||
public: // STATIC
|
||||
template <template <typename, typename...> class Sequence = QVector, typename ...Args>
|
||||
inline static QPromise<void> all(const Sequence<QPromise<void>, Args...>& promises);
|
||||
|
@ -9,95 +9,82 @@ template <class T>
|
||||
class QPromiseResolve
|
||||
{
|
||||
public:
|
||||
QPromiseResolve(QPromise<T> p)
|
||||
: m_promise(new QPromise<T>(std::move(p)))
|
||||
QPromiseResolve(QtPromisePrivate::PromiseResolver<T> resolver)
|
||||
: m_resolver(std::move(resolver))
|
||||
{ }
|
||||
|
||||
template <typename V>
|
||||
void operator()(V&& value) const
|
||||
{
|
||||
Q_ASSERT(!m_promise.isNull());
|
||||
if (m_promise->isPending()) {
|
||||
m_promise->m_d->resolve(std::forward<V>(value));
|
||||
m_promise->m_d->dispatch();
|
||||
}
|
||||
m_resolver.resolve(std::forward<V>(value));
|
||||
}
|
||||
|
||||
private:
|
||||
QSharedPointer<QPromise<T> > m_promise;
|
||||
};
|
||||
|
||||
template <>
|
||||
class QPromiseResolve<void>
|
||||
{
|
||||
public:
|
||||
QPromiseResolve(QPromise<void> p)
|
||||
: m_promise(new QPromise<void>(std::move(p)))
|
||||
{ }
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
Q_ASSERT(!m_promise.isNull());
|
||||
if (m_promise->isPending()) {
|
||||
m_promise->m_d->resolve();
|
||||
m_promise->m_d->dispatch();
|
||||
}
|
||||
m_resolver.resolve();
|
||||
}
|
||||
|
||||
private:
|
||||
QSharedPointer<QPromise<void> > m_promise;
|
||||
mutable QtPromisePrivate::PromiseResolver<T> m_resolver;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class QPromiseReject
|
||||
{
|
||||
public:
|
||||
QPromiseReject(QPromise<T> p)
|
||||
: m_promise(new QPromise<T>(std::move(p)))
|
||||
QPromiseReject(QtPromisePrivate::PromiseResolver<T> resolver)
|
||||
: m_resolver(std::move(resolver))
|
||||
{ }
|
||||
|
||||
template <typename E>
|
||||
void operator()(E&& error) const
|
||||
{
|
||||
Q_ASSERT(!m_promise.isNull());
|
||||
if (m_promise->isPending()) {
|
||||
m_promise->m_d->reject(std::forward<E>(error));
|
||||
m_promise->m_d->dispatch();
|
||||
}
|
||||
m_resolver.reject(std::forward<E>(error));
|
||||
}
|
||||
|
||||
private:
|
||||
QSharedPointer<QPromise<T> > m_promise;
|
||||
mutable QtPromisePrivate::PromiseResolver<T> m_resolver;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 1, int>::type>
|
||||
inline QPromiseBase<T>::QPromiseBase(F resolver)
|
||||
inline QPromiseBase<T>::QPromiseBase(F callback)
|
||||
: m_d(new QtPromisePrivate::PromiseData<T>())
|
||||
{
|
||||
QPromiseResolve<T> resolve(*this);
|
||||
QPromiseReject<T> reject(*this);
|
||||
QtPromisePrivate::PromiseResolver<T> resolver(*this);
|
||||
|
||||
try {
|
||||
resolver(resolve);
|
||||
callback(QPromiseResolve<T>(resolver));
|
||||
} catch (...) {
|
||||
reject(std::current_exception());
|
||||
resolver.reject(std::current_exception());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count != 1, int>::type>
|
||||
inline QPromiseBase<T>::QPromiseBase(F resolver)
|
||||
inline QPromiseBase<T>::QPromiseBase(F callback)
|
||||
: m_d(new QtPromisePrivate::PromiseData<T>())
|
||||
{
|
||||
QtPromisePrivate::PromiseResolver<T> resolver(*this);
|
||||
|
||||
try {
|
||||
callback(QPromiseResolve<T>(resolver), QPromiseReject<T>(resolver));
|
||||
} catch (...) {
|
||||
resolver.reject(std::current_exception());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
inline QPromiseBase<T>::QPromiseBase(const QPromise<U>& other)
|
||||
: m_d(new QtPromisePrivate::PromiseData<T>())
|
||||
{
|
||||
using namespace QtPromisePrivate;
|
||||
|
||||
QPromiseResolve<T> resolve(*this);
|
||||
QPromiseReject<T> reject(*this);
|
||||
|
||||
try {
|
||||
resolver(resolve, reject);
|
||||
} catch (...) {
|
||||
reject(std::current_exception());
|
||||
}
|
||||
PromiseFulfill<QPromise<U> >::call(other, PromiseCast<U, T>::apply(resolve), reject);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -158,6 +145,16 @@ inline QPromise<T> QPromiseBase<T>::tap(THandler handler) const
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename THandler>
|
||||
inline QPromise<T> QPromiseBase<T>::tapFail(THandler handler) const
|
||||
{
|
||||
QPromise<T> p = *this;
|
||||
return p.then([](){}, handler).then([=]() {
|
||||
return p;
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename E>
|
||||
inline QPromise<T> QPromiseBase<T>::timeout(int msec, E&& error) const
|
||||
@ -174,7 +171,7 @@ inline QPromise<T> QPromiseBase<T>::timeout(int msec, E&& error) const
|
||||
reject(std::move(error));
|
||||
});
|
||||
|
||||
QtPromisePrivate::PromiseFulfill<QPromise<T> >::call(p, resolve, reject);
|
||||
QtPromisePrivate::PromiseFulfill<QPromise<T>>::call(p, resolve, reject);
|
||||
});
|
||||
}
|
||||
|
||||
@ -211,19 +208,19 @@ inline QPromise<T> QPromiseBase<T>::reject(E&& error)
|
||||
|
||||
template <typename T>
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
inline QPromise<QVector<T> > QPromise<T>::all(const Sequence<QPromise<T>, Args...>& promises)
|
||||
inline QPromise<QVector<T>> QPromise<T>::all(const Sequence<QPromise<T>, Args...>& promises)
|
||||
{
|
||||
const int count = (int)promises.size();
|
||||
const int count = static_cast<int>(promises.size());
|
||||
if (count == 0) {
|
||||
return QPromise<QVector<T> >::resolve({});
|
||||
return QPromise<QVector<T>>::resolve({});
|
||||
}
|
||||
|
||||
return QPromise<QVector<T> >([=](
|
||||
const QPromiseResolve<QVector<T> >& resolve,
|
||||
const QPromiseReject<QVector<T> >& reject) {
|
||||
return QPromise<QVector<T>>([=](
|
||||
const QPromiseResolve<QVector<T>>& resolve,
|
||||
const QPromiseReject<QVector<T>>& reject) {
|
||||
|
||||
QSharedPointer<int> remaining(new int(count));
|
||||
QSharedPointer<QVector<T> > results(new QVector<T>(count));
|
||||
QSharedPointer<QVector<T>> results(new QVector<T>(count));
|
||||
|
||||
int i = 0;
|
||||
for (const auto& promise: promises) {
|
||||
@ -260,10 +257,25 @@ inline QPromise<T> QPromise<T>::resolve(T&& value)
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
QPromise<T>::operator QPromise<U>()
|
||||
{
|
||||
return QPromise<U>::resolve(U());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
QPromise<void>::QPromise(const QPromise<T>& other)
|
||||
: QPromiseBase<void>([&](const QPromiseResolve<void>& resolve, const QPromiseReject<void>& reject) {
|
||||
QtPromisePrivate::PromiseFulfill<QPromise<T> >::call(other, resolve, reject);
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
inline QPromise<void> QPromise<void>::all(const Sequence<QPromise<void>, Args...>& promises)
|
||||
{
|
||||
const int count = (int)promises.size();
|
||||
const int count = static_cast<int>(promises.size());
|
||||
if (count == 0) {
|
||||
return QPromise<void>::resolve();
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
#define QTPROMISE_QPROMISE_P_H
|
||||
|
||||
// QtPromise
|
||||
#include "qpromiseerror.h"
|
||||
#include "qpromiseglobal.h"
|
||||
|
||||
// Qt
|
||||
@ -34,9 +33,10 @@ namespace QtPromisePrivate {
|
||||
template <typename F>
|
||||
static void qtpromise_defer(F&& f, const QPointer<QThread>& thread)
|
||||
{
|
||||
using FType = typename std::decay<F>::type;
|
||||
|
||||
struct Event : public QEvent
|
||||
{
|
||||
using FType = typename std::decay<F>::type;
|
||||
Event(FType&& f) : QEvent(QEvent::None), m_f(std::move(f)) { }
|
||||
Event(const FType& f) : QEvent(QEvent::None), m_f(f) { }
|
||||
~Event() { m_f(); }
|
||||
@ -72,35 +72,71 @@ static void qtpromise_defer(F&& f)
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct PromiseDeduce
|
||||
class PromiseValue
|
||||
{
|
||||
using Type = QtPromise::QPromise<Unqualified<T> >;
|
||||
public:
|
||||
PromiseValue() { }
|
||||
PromiseValue(const T& data) : m_data(new T(data)) { }
|
||||
PromiseValue(T&& data) : m_data(new T(std::move(data))) { }
|
||||
bool isNull() const { return m_data.isNull(); }
|
||||
const T& data() const { return *m_data; }
|
||||
|
||||
private:
|
||||
QSharedPointer<T> m_data;
|
||||
};
|
||||
|
||||
class PromiseError
|
||||
{
|
||||
public:
|
||||
template <typename T>
|
||||
PromiseError(const T& value)
|
||||
{
|
||||
try {
|
||||
throw value;
|
||||
} catch (...) {
|
||||
m_data = std::current_exception();
|
||||
}
|
||||
}
|
||||
|
||||
PromiseError() { }
|
||||
PromiseError(const std::exception_ptr& exception) : m_data(exception) { }
|
||||
void rethrow() const { std::rethrow_exception(m_data); }
|
||||
bool isNull() const { return m_data == nullptr; }
|
||||
|
||||
private:
|
||||
// NOTE(SB) std::exception_ptr is already a shared pointer
|
||||
std::exception_ptr m_data;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PromiseDeduce<QtPromise::QPromise<T> >
|
||||
struct PromiseDeduce
|
||||
{
|
||||
using Type = QtPromise::QPromise<Unqualified<T>>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PromiseDeduce<QtPromise::QPromise<T>>
|
||||
: public PromiseDeduce<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct PromiseFulfill
|
||||
{
|
||||
static void call(
|
||||
T&& value,
|
||||
const QtPromise::QPromiseResolve<T>& resolve,
|
||||
const QtPromise::QPromiseReject<T>&)
|
||||
template <typename TResolve, typename TReject>
|
||||
static void call(T&& value, const TResolve& resolve, const TReject&)
|
||||
{
|
||||
resolve(std::move(value));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PromiseFulfill<QtPromise::QPromise<T> >
|
||||
struct PromiseFulfill<QtPromise::QPromise<T>>
|
||||
{
|
||||
template <typename TResolve, typename TReject>
|
||||
static void call(
|
||||
const QtPromise::QPromise<T>& promise,
|
||||
const QtPromise::QPromiseResolve<T>& resolve,
|
||||
const QtPromise::QPromiseReject<T>& reject)
|
||||
const TResolve& resolve,
|
||||
const TReject& reject)
|
||||
{
|
||||
if (promise.isFulfilled()) {
|
||||
resolve(promise.m_d->value());
|
||||
@ -117,11 +153,11 @@ struct PromiseFulfill<QtPromise::QPromise<T> >
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PromiseFulfill<QtPromise::QPromise<void> >
|
||||
struct PromiseFulfill<QtPromise::QPromise<void>>
|
||||
{
|
||||
template <typename TPromise, typename TResolve, typename TReject>
|
||||
template <typename TResolve, typename TReject>
|
||||
static void call(
|
||||
const TPromise& promise,
|
||||
const QtPromise::QPromise<void>& promise,
|
||||
const TResolve& resolve,
|
||||
const TReject& reject)
|
||||
{
|
||||
@ -305,12 +341,12 @@ struct PromiseCatcher
|
||||
using ResType = typename std::result_of<THandler(TArg)>::type;
|
||||
|
||||
template <typename TResolve, typename TReject>
|
||||
static std::function<void(const QtPromise::QPromiseError&)> create(
|
||||
static std::function<void(const PromiseError&)> create(
|
||||
const THandler& handler,
|
||||
const TResolve& resolve,
|
||||
const TReject& reject)
|
||||
{
|
||||
return [=](const QtPromise::QPromiseError& error) {
|
||||
return [=](const PromiseError& error) {
|
||||
try {
|
||||
error.rethrow();
|
||||
} catch (const TArg& error) {
|
||||
@ -328,12 +364,12 @@ struct PromiseCatcher<T, THandler, void>
|
||||
using ResType = typename std::result_of<THandler()>::type;
|
||||
|
||||
template <typename TResolve, typename TReject>
|
||||
static std::function<void(const QtPromise::QPromiseError&)> create(
|
||||
static std::function<void(const PromiseError&)> create(
|
||||
const THandler& handler,
|
||||
const TResolve& resolve,
|
||||
const TReject& reject)
|
||||
{
|
||||
return [=](const QtPromise::QPromiseError& error) {
|
||||
return [=](const PromiseError& error) {
|
||||
try {
|
||||
error.rethrow();
|
||||
} catch (...) {
|
||||
@ -347,12 +383,12 @@ template <typename T>
|
||||
struct PromiseCatcher<T, std::nullptr_t, void>
|
||||
{
|
||||
template <typename TResolve, typename TReject>
|
||||
static std::function<void(const QtPromise::QPromiseError&)> create(
|
||||
static std::function<void(const PromiseError&)> create(
|
||||
std::nullptr_t,
|
||||
const TResolve&,
|
||||
const TReject& reject)
|
||||
{
|
||||
return [=](const QtPromise::QPromiseError& error) {
|
||||
return [=](const PromiseError& error) {
|
||||
// 2.2.7.4. If onRejected is not a function and promise1 is rejected,
|
||||
// promise2 must be rejected with the same reason as promise1
|
||||
reject(error);
|
||||
@ -360,15 +396,75 @@ struct PromiseCatcher<T, std::nullptr_t, void>
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
struct PromiseCast
|
||||
{
|
||||
template <typename F>
|
||||
static auto apply(const F& resolve)
|
||||
{
|
||||
return [=](const QSharedPointer<T>& value) {
|
||||
resolve(static_cast<T>(*value));
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PromiseCast<T, void>
|
||||
{
|
||||
template <typename F>
|
||||
static auto apply(const F& resolve)
|
||||
{
|
||||
return [=](const QSharedPointer<T>&) {
|
||||
resolve();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
template <typename T>
|
||||
struct PromiseCast<T, QVariant>
|
||||
{
|
||||
static QtPromise::QPromise<QVariant> cast(
|
||||
const QtPromise::QPromiseBase<T>& input)
|
||||
{
|
||||
return input.then([](const T& res) {
|
||||
return QVariant::fromValue(res);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
template <typename U>
|
||||
struct PromiseCast<QVariant, U>
|
||||
{
|
||||
static QtPromise::QPromise<U> cast(
|
||||
const QtPromise::QPromiseBase<QVariant>& input)
|
||||
{
|
||||
return input.then([](const QVariant& res) {
|
||||
return res.value<U>();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PromiseCast<void, QVariant>
|
||||
{
|
||||
static QtPromise::QPromise<void> cast(
|
||||
const QtPromise::QPromiseBase<QVariant>& input)
|
||||
{
|
||||
return input.then([]() {
|
||||
});
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
template <typename T> class PromiseData;
|
||||
|
||||
template <typename T, typename F>
|
||||
class PromiseDataBase : public QSharedData
|
||||
{
|
||||
public:
|
||||
using Error = QtPromise::QPromiseError;
|
||||
using Handler = std::pair<QPointer<QThread>, std::function<F> >;
|
||||
using Catcher = std::pair<QPointer<QThread>, std::function<void(const Error&)> >;
|
||||
using Handler = std::pair<QPointer<QThread>, std::function<F>>;
|
||||
using Catcher = std::pair<QPointer<QThread>, std::function<void(const PromiseError&)>>;
|
||||
|
||||
virtual ~PromiseDataBase() {}
|
||||
|
||||
@ -394,29 +490,22 @@ public:
|
||||
m_handlers.append({QThread::currentThread(), std::move(handler)});
|
||||
}
|
||||
|
||||
void addCatcher(std::function<void(const Error&)> catcher)
|
||||
void addCatcher(std::function<void(const PromiseError&)> catcher)
|
||||
{
|
||||
QWriteLocker lock(&m_lock);
|
||||
m_catchers.append({QThread::currentThread(), std::move(catcher)});
|
||||
}
|
||||
|
||||
void reject(Error error)
|
||||
template <typename E>
|
||||
void reject(E&& error)
|
||||
{
|
||||
Q_ASSERT(isPending());
|
||||
Q_ASSERT(m_error.isNull());
|
||||
m_error.reset(new Error(std::move(error)));
|
||||
m_error = PromiseError(std::forward<E>(error));
|
||||
setSettled();
|
||||
}
|
||||
|
||||
void reject(const QSharedPointer<Error>& error)
|
||||
{
|
||||
Q_ASSERT(isPending());
|
||||
Q_ASSERT(m_error.isNull());
|
||||
m_error = error;
|
||||
this->setSettled();
|
||||
}
|
||||
|
||||
const QSharedPointer<Error>& error() const
|
||||
const PromiseError& error() const
|
||||
{
|
||||
Q_ASSERT(isRejected());
|
||||
return m_error;
|
||||
@ -445,13 +534,13 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
QSharedPointer<Error> error = m_error;
|
||||
PromiseError error(m_error);
|
||||
Q_ASSERT(!error.isNull());
|
||||
|
||||
for (const auto& catcher: catchers) {
|
||||
const auto& fn = catcher.second;
|
||||
qtpromise_defer([=]() {
|
||||
fn(*error);
|
||||
fn(error);
|
||||
}, catcher.first);
|
||||
}
|
||||
}
|
||||
@ -472,7 +561,7 @@ private:
|
||||
bool m_settled = false;
|
||||
QVector<Handler> m_handlers;
|
||||
QVector<Catcher> m_catchers;
|
||||
QSharedPointer<Error> m_error;
|
||||
PromiseError m_error;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -481,31 +570,16 @@ class PromiseData : public PromiseDataBase<T, void(const T&)>
|
||||
using Handler = typename PromiseDataBase<T, void(const T&)>::Handler;
|
||||
|
||||
public:
|
||||
void resolve(T&& value)
|
||||
template <typename V>
|
||||
void resolve(V&& value)
|
||||
{
|
||||
Q_ASSERT(this->isPending());
|
||||
Q_ASSERT(m_value.isNull());
|
||||
m_value.reset(new T(std::move(value)));
|
||||
m_value = PromiseValue<T>(std::forward<V>(value));
|
||||
this->setSettled();
|
||||
}
|
||||
|
||||
void resolve(const T& value)
|
||||
{
|
||||
Q_ASSERT(this->isPending());
|
||||
Q_ASSERT(m_value.isNull());
|
||||
m_value.reset(new T(value));
|
||||
this->setSettled();
|
||||
}
|
||||
|
||||
void resolve(const QSharedPointer<T>& value)
|
||||
{
|
||||
Q_ASSERT(this->isPending());
|
||||
Q_ASSERT(m_value.isNull());
|
||||
m_value = value;
|
||||
this->setSettled();
|
||||
}
|
||||
|
||||
const QSharedPointer<T>& value() const
|
||||
const PromiseValue<T>& value() const
|
||||
{
|
||||
Q_ASSERT(this->isFulfilled());
|
||||
return m_value;
|
||||
@ -513,19 +587,19 @@ public:
|
||||
|
||||
void notify(const QVector<Handler>& handlers) Q_DECL_OVERRIDE
|
||||
{
|
||||
QSharedPointer<T> value(m_value);
|
||||
PromiseValue<T> value(m_value);
|
||||
Q_ASSERT(!value.isNull());
|
||||
|
||||
for (const auto& handler: handlers) {
|
||||
const auto& fn = handler.second;
|
||||
qtpromise_defer([=]() {
|
||||
fn(*value);
|
||||
fn(value.data());
|
||||
}, handler.first);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QSharedPointer<T> m_value;
|
||||
PromiseValue<T> m_value;
|
||||
};
|
||||
|
||||
template <>
|
||||
@ -548,6 +622,68 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class PromiseResolver
|
||||
{
|
||||
public:
|
||||
PromiseResolver(QtPromise::QPromise<T> promise)
|
||||
: m_d(new Data())
|
||||
{
|
||||
m_d->promise = new QtPromise::QPromise<T>(std::move(promise));
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void reject(E&& error)
|
||||
{
|
||||
auto promise = m_d->promise;
|
||||
if (promise) {
|
||||
Q_ASSERT(promise->isPending());
|
||||
promise->m_d->reject(std::forward<E>(error));
|
||||
promise->m_d->dispatch();
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
void resolve(V&& value)
|
||||
{
|
||||
auto promise = m_d->promise;
|
||||
if (promise) {
|
||||
Q_ASSERT(promise->isPending());
|
||||
promise->m_d->resolve(std::forward<V>(value));
|
||||
promise->m_d->dispatch();
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
void resolve()
|
||||
{
|
||||
auto promise = m_d->promise;
|
||||
if (promise) {
|
||||
Q_ASSERT(promise->isPending());
|
||||
promise->m_d->resolve();
|
||||
promise->m_d->dispatch();
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct Data : public QSharedData
|
||||
{
|
||||
QtPromise::QPromise<T>* promise = nullptr;
|
||||
};
|
||||
|
||||
QExplicitlySharedDataPointer<Data> m_d;
|
||||
|
||||
void release()
|
||||
{
|
||||
Q_ASSERT(m_d->promise);
|
||||
Q_ASSERT(!m_d->promise->isPending());
|
||||
delete m_d->promise;
|
||||
m_d->promise = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace QtPromise
|
||||
|
||||
#endif // ifndef QTPROMISE_QPROMISE_H
|
||||
#endif // ifndef QTPROMISE_QPROMISE_P_H
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define QTPROMISE_QPROMISEERROR_H
|
||||
|
||||
// QtPromise
|
||||
#include "qpromise_p.h"
|
||||
#include "qpromiseglobal.h"
|
||||
|
||||
// Qt
|
||||
@ -9,53 +10,6 @@
|
||||
|
||||
namespace QtPromise {
|
||||
|
||||
class QPromiseError
|
||||
{
|
||||
public:
|
||||
template <typename T>
|
||||
QPromiseError(const T& value)
|
||||
{
|
||||
try {
|
||||
throw value;
|
||||
} catch (...) {
|
||||
m_exception = std::current_exception();
|
||||
}
|
||||
}
|
||||
|
||||
QPromiseError(const std::exception_ptr& exception)
|
||||
: m_exception(exception)
|
||||
{ }
|
||||
|
||||
QPromiseError(const QPromiseError& error)
|
||||
: m_exception(error.m_exception)
|
||||
{ }
|
||||
|
||||
QPromiseError(QPromiseError&& other)
|
||||
: m_exception(nullptr)
|
||||
{
|
||||
swap(other);
|
||||
}
|
||||
|
||||
QPromiseError& operator=(QPromiseError other)
|
||||
{
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(QPromiseError& other)
|
||||
{
|
||||
qSwap(m_exception, other.m_exception);
|
||||
}
|
||||
|
||||
void rethrow() const
|
||||
{
|
||||
std::rethrow_exception(m_exception);
|
||||
}
|
||||
|
||||
private:
|
||||
std::exception_ptr m_exception;
|
||||
};
|
||||
|
||||
class QPromiseTimeoutException : public QException
|
||||
{
|
||||
public:
|
||||
@ -66,6 +20,12 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// QPromiseError is provided for backward compatibility and will be
|
||||
// removed in the next major version: it wasn't intended to be used
|
||||
// directly and thus should not be part of the public API.
|
||||
// TODO Remove QPromiseError at version 1.0
|
||||
using QPromiseError = QtPromisePrivate::PromiseError;
|
||||
|
||||
} // namespace QtPromise
|
||||
|
||||
#endif // QTPROMISE_QPROMISEERROR_H
|
||||
|
@ -22,12 +22,12 @@ public:
|
||||
namespace QtPromisePrivate {
|
||||
|
||||
template <typename T>
|
||||
struct PromiseDeduce<QFuture<T> >
|
||||
struct PromiseDeduce<QFuture<T>>
|
||||
: public PromiseDeduce<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct PromiseFulfill<QFuture<T> >
|
||||
struct PromiseFulfill<QFuture<T>>
|
||||
{
|
||||
static void call(
|
||||
const QFuture<T>& future,
|
||||
@ -62,7 +62,7 @@ struct PromiseFulfill<QFuture<T> >
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PromiseFulfill<QFuture<void> >
|
||||
struct PromiseFulfill<QFuture<void>>
|
||||
{
|
||||
static void call(
|
||||
const QFuture<void>& future,
|
||||
|
@ -85,7 +85,7 @@ struct ArgsOf<TReturn(T::*)(Args...) const volatile> : public ArgsTraits<Args...
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<std::function<T> > : public ArgsOf<T>
|
||||
struct ArgsOf<std::function<T>> : public ArgsOf<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
|
@ -27,7 +27,7 @@ static inline QPromise<void> qPromise()
|
||||
}
|
||||
|
||||
template <typename T, template <typename, typename...> class Sequence = QVector, typename ...Args>
|
||||
static inline QPromise<QVector<T> > qPromiseAll(const Sequence<QPromise<T>, Args...>& promises)
|
||||
static inline QPromise<QVector<T>> qPromiseAll(const Sequence<QPromise<T>, Args...>& promises)
|
||||
{
|
||||
return QPromise<T>::all(promises);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
TEMPLATE = aux
|
||||
CONFIG += c++11 force_qt thread warn_on
|
||||
TEMPLATE = lib
|
||||
CONFIG += c++11 qt thread warn_on
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
include(qtpromise.pri)
|
||||
|
@ -1,175 +0,0 @@
|
||||
// QtQmlPromise
|
||||
#include "qjspromise.h"
|
||||
#include "qjspromise_p.h"
|
||||
|
||||
// Qt
|
||||
#include <QJSValueIterator>
|
||||
#include <QJSEngine>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
namespace {
|
||||
|
||||
QJSValue toJSArray(QJSEngine* engine, const QVector<QJSValue>& values)
|
||||
{
|
||||
Q_ASSERT(engine);
|
||||
|
||||
const int count = values.count();
|
||||
QJSValue array = engine->newArray(count);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
array.setProperty(i, values[i]);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
QJSValue newError(const QJSValue& source, const T& value)
|
||||
{
|
||||
QJSEngine* engine = source.engine();
|
||||
QJSValue error = engine->evaluate("throw new Error('')");
|
||||
error.setProperty("message", engine->toScriptValue(value));
|
||||
return error;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
QJSPromise::QJSPromise()
|
||||
: m_promise(QPromise<QJSValue>::resolve(QJSValue()))
|
||||
{ }
|
||||
|
||||
QJSPromise::QJSPromise(QPromise<QJSValue>&& promise)
|
||||
: m_promise(std::move(promise))
|
||||
{
|
||||
}
|
||||
|
||||
QJSPromise::QJSPromise(QJSEngine* engine, QJSValue resolver)
|
||||
: m_promise([=](
|
||||
const QPromiseResolve<QJSValue>& resolve,
|
||||
const QPromiseReject<QJSValue>& reject) mutable {
|
||||
|
||||
// resolver is part of the Promise wrapper in qtqmlpromise.js
|
||||
Q_ASSERT(resolver.isCallable());
|
||||
Q_ASSERT(engine);
|
||||
|
||||
auto proxy = QtPromisePrivate::JSPromiseResolver(resolve, reject);
|
||||
auto ret = resolver.call(QJSValueList() << engine->toScriptValue(proxy));
|
||||
if (ret.isError()) {
|
||||
throw ret;
|
||||
}
|
||||
})
|
||||
{ }
|
||||
|
||||
QJSPromise QJSPromise::then(QJSValue fulfilled, QJSValue rejected) const
|
||||
{
|
||||
const bool fulfillable = fulfilled.isCallable();
|
||||
const bool rejectable = rejected.isCallable();
|
||||
|
||||
if (!fulfillable && !rejectable) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto _rejected = [=]() mutable {
|
||||
QJSValue error;
|
||||
|
||||
try {
|
||||
throw;
|
||||
} catch (const QJSValue& err) {
|
||||
error = err;
|
||||
} catch (const QVariant& err) {
|
||||
error = newError(rejected, err);
|
||||
} catch (const std::exception& e) {
|
||||
error = newError(rejected, QString(e.what()));
|
||||
} catch (...) {
|
||||
error = newError(rejected, QString("Unknown error"));
|
||||
}
|
||||
|
||||
return rejected.call({error});
|
||||
};
|
||||
|
||||
if (!fulfillable) {
|
||||
return m_promise.then(nullptr, _rejected);
|
||||
}
|
||||
|
||||
auto _fulfilled = [=](const QJSValue& res) mutable {
|
||||
return fulfilled.call(QJSValueList() << res);
|
||||
};
|
||||
|
||||
if (!rejectable) {
|
||||
return m_promise.then(_fulfilled);
|
||||
}
|
||||
|
||||
return m_promise.then(_fulfilled, _rejected);
|
||||
}
|
||||
|
||||
QJSPromise QJSPromise::fail(QJSValue handler) const
|
||||
{
|
||||
return then(QJSValue(), handler);
|
||||
}
|
||||
|
||||
QJSPromise QJSPromise::finally(QJSValue handler) const
|
||||
{
|
||||
return m_promise.finally([=]() mutable {
|
||||
return handler.call();
|
||||
});
|
||||
}
|
||||
|
||||
QJSPromise QJSPromise::tap(QJSValue handler) const
|
||||
{
|
||||
return m_promise.tap([=](const QJSValue& res) mutable {
|
||||
return handler.call(QJSValueList() << res);
|
||||
});
|
||||
}
|
||||
|
||||
QJSPromise QJSPromise::delay(int msec) const
|
||||
{
|
||||
return m_promise.delay(msec);
|
||||
}
|
||||
|
||||
QJSPromise QJSPromise::wait() const
|
||||
{
|
||||
return m_promise.wait();
|
||||
}
|
||||
|
||||
QJSPromise QJSPromise::resolve(QJSValue&& value)
|
||||
{
|
||||
return QPromise<QJSValue>::resolve(std::forward<QJSValue>(value));
|
||||
}
|
||||
|
||||
QJSPromise QJSPromise::reject(QJSValue&& error)
|
||||
{
|
||||
return QPromise<QJSValue>::reject(std::forward<QJSValue>(error));
|
||||
}
|
||||
|
||||
QJSPromise QJSPromise::all(QJSEngine* engine, QJSValue&& input)
|
||||
{
|
||||
Q_ASSERT(engine);
|
||||
|
||||
if (!input.isArray()) {
|
||||
// TODO TYPEERROR!
|
||||
return QPromise<QJSValue>::reject("foobar");
|
||||
}
|
||||
|
||||
Q_ASSERT(input.hasProperty("length"));
|
||||
const int count = input.property("length").toInt();
|
||||
if (!count) {
|
||||
return QPromise<QJSValue>::resolve(QJSValue(input));
|
||||
}
|
||||
|
||||
QList<QPromise<QJSValue> > promises;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
QJSValue value = input.property(i);
|
||||
const QVariant variant = value.toVariant();
|
||||
if (variant.userType() == qMetaTypeId<QJSPromise>()) {
|
||||
promises << variant.value<QJSPromise>().m_promise;
|
||||
} else {
|
||||
promises << QPromise<QJSValue>::resolve(std::move(value));
|
||||
}
|
||||
}
|
||||
|
||||
return QPromise<QJSValue>::all(promises)
|
||||
.then([engine](const QVector<QJSValue>& results) {
|
||||
return toJSArray(engine, results);
|
||||
});
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
#ifndef QTQMLPROMISE_QJSPROMISE_H
|
||||
#define QTQMLPROMISE_QJSPROMISE_H
|
||||
|
||||
// QtQmlPromise
|
||||
#include "qtqmlpromiseglobal.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QJSValue>
|
||||
|
||||
namespace QtPromise {
|
||||
|
||||
class QTQMLPROMISE_EXPORT QJSPromise
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
QJSPromise();
|
||||
QJSPromise(QJSEngine* engine, QJSValue resolver);
|
||||
QJSPromise(QPromise<QJSValue>&& promise);
|
||||
|
||||
Q_INVOKABLE bool isFulfilled() const { return m_promise.isFulfilled(); }
|
||||
Q_INVOKABLE bool isRejected() const { return m_promise.isRejected(); }
|
||||
Q_INVOKABLE bool isPending() const{ return m_promise.isPending(); }
|
||||
|
||||
Q_INVOKABLE QtPromise::QJSPromise then(QJSValue fulfilled, QJSValue rejected = QJSValue()) const;
|
||||
Q_INVOKABLE QtPromise::QJSPromise fail(QJSValue handler) const;
|
||||
Q_INVOKABLE QtPromise::QJSPromise finally(QJSValue handler) const;
|
||||
Q_INVOKABLE QtPromise::QJSPromise tap(QJSValue handler) const;
|
||||
Q_INVOKABLE QtPromise::QJSPromise delay(int msec) const;
|
||||
Q_INVOKABLE QtPromise::QJSPromise wait() const;
|
||||
|
||||
public: // STATICS
|
||||
static QJSPromise resolve(QJSValue&& value);
|
||||
static QJSPromise reject(QJSValue&& error);
|
||||
static QJSPromise all(QJSEngine* engine, QJSValue&& input);
|
||||
|
||||
private:
|
||||
friend struct QtPromisePrivate::PromiseFulfill<QJSValue>;
|
||||
|
||||
QPromise<QJSValue> m_promise;
|
||||
|
||||
}; // class QJSPromise
|
||||
|
||||
} // namespace QtPromise
|
||||
|
||||
Q_DECLARE_TYPEINFO(QtPromise::QJSPromise, Q_MOVABLE_TYPE);
|
||||
Q_DECLARE_METATYPE(QtPromise::QJSPromise)
|
||||
|
||||
#endif // ifndef QTQMLPROMISE_QJSPROMISE_H
|
@ -1,71 +0,0 @@
|
||||
#ifndef QTQMLPROMISE_QJSPROMISE_P_H
|
||||
#define QTQMLPROMISE_QJSPROMISE_P_H
|
||||
|
||||
// QtQmlPromise
|
||||
#include "qjspromise.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QJSValue>
|
||||
|
||||
namespace QtPromisePrivate {
|
||||
|
||||
template <>
|
||||
struct PromiseFulfill<QJSValue>
|
||||
{
|
||||
static void call(
|
||||
const QJSValue& value,
|
||||
const QtPromise::QPromiseResolve<QJSValue>& resolve,
|
||||
const QtPromise::QPromiseReject<QJSValue>& reject)
|
||||
{
|
||||
using namespace QtPromise;
|
||||
|
||||
if (value.isObject()) {
|
||||
const QVariant variant = value.toVariant();
|
||||
if (variant.userType() == qMetaTypeId<QJSPromise>()) {
|
||||
const auto promise = variant.value<QJSPromise>().m_promise;
|
||||
PromiseFulfill<QPromise<QJSValue> >::call(promise, resolve, reject);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (value.isError()) {
|
||||
reject(value);
|
||||
} else {
|
||||
resolve(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class JSPromiseResolver
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
JSPromiseResolver() {}
|
||||
JSPromiseResolver(
|
||||
const QtPromise::QPromiseResolve<QJSValue>& resolve,
|
||||
const QtPromise::QPromiseReject<QJSValue>& reject)
|
||||
: m_d(new Data{resolve, reject})
|
||||
{ }
|
||||
|
||||
Q_INVOKABLE void resolve(QJSValue value = QJSValue()) { m_d->resolve(std::move(value)); }
|
||||
Q_INVOKABLE void reject(QJSValue error = QJSValue()) { m_d->reject(std::move(error)); }
|
||||
|
||||
private:
|
||||
struct Data
|
||||
{
|
||||
QtPromise::QPromiseResolve<QJSValue> resolve;
|
||||
QtPromise::QPromiseReject<QJSValue> reject;
|
||||
}; // struct Data
|
||||
|
||||
QSharedPointer<Data> m_d;
|
||||
};
|
||||
|
||||
} // namespace QtPromisePrivate
|
||||
|
||||
Q_DECLARE_METATYPE(QtPromisePrivate::JSPromiseResolver)
|
||||
|
||||
#endif // ifndef QTQMLPROMISE_QJSPROMISE_P_H
|
@ -1,7 +0,0 @@
|
||||
HEADERS += \
|
||||
$$PWD/qjspromise.h \
|
||||
$$PWD/qjspromise_p.h \
|
||||
$$PWD/qtqmlpromiseglobal.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/qjspromise.cpp
|
@ -1,8 +0,0 @@
|
||||
TEMPLATE = aux
|
||||
CONFIG += c++11 force_qt thread warn_on
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
DEFINES += QTQMLPROMISE_LIBRARY
|
||||
QT += qml
|
||||
|
||||
include($$PWD/../../qtpromise.pri)
|
||||
include($$PWD/qtqmlpromise.pri)
|
@ -1,16 +0,0 @@
|
||||
#ifndef QTQMLPROMISE_QTQMLPROMISEGLOBAL_H
|
||||
#define QTQMLPROMISE_QTQMLPROMISEGLOBAL_H
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// QtCore
|
||||
#include <QtGlobal>
|
||||
|
||||
#ifdef QTQMLPROMISE_LIBRARY
|
||||
# define QTQMLPROMISE_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define QTQMLPROMISE_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
#endif // ifndef QTQMLPROMISE_QTQMLPROMISEGLOBAL_H
|
@ -1,5 +1,2 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS += \
|
||||
imports \
|
||||
qtpromise \
|
||||
qtqmlpromise
|
||||
SUBDIRS = qtpromise
|
||||
|
@ -1,4 +1,2 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS += \
|
||||
qtpromise \
|
||||
qtqmlpromise
|
||||
SUBDIRS += qtpromise
|
||||
|
@ -56,7 +56,7 @@ void tst_future::fulfilled()
|
||||
return 42;
|
||||
}));
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
QCOMPARE(p.isPending(), true);
|
||||
|
||||
p.then([&](int res) {
|
||||
@ -72,7 +72,7 @@ void tst_future::fulfilled_void()
|
||||
int result = -1;
|
||||
auto p = qPromise(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);
|
||||
|
||||
p.then([&]() {
|
||||
@ -91,7 +91,7 @@ void tst_future::rejected()
|
||||
return 42;
|
||||
}));
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
QCOMPARE(p.isPending(), true);
|
||||
|
||||
p.fail([&](const MyException& e) {
|
||||
@ -110,7 +110,7 @@ void tst_future::rejected_void()
|
||||
throw MyException("foo");
|
||||
}));
|
||||
|
||||
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);
|
||||
|
||||
@ -130,7 +130,7 @@ void tst_future::unhandled()
|
||||
return 42;
|
||||
}));
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
|
||||
@ -153,7 +153,7 @@ void tst_future::unhandled_void()
|
||||
throw QString("foo");
|
||||
}));
|
||||
|
||||
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);
|
||||
|
||||
p.fail([&](const QString& err) {
|
||||
@ -307,7 +307,7 @@ void tst_future::finally()
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(output), QPromise<int> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(output), QPromise<int>>::value));
|
||||
|
||||
QCOMPARE(input.isFulfilled(), true);
|
||||
QCOMPARE(output.isPending(), true);
|
||||
@ -330,7 +330,7 @@ void tst_future::finallyRejected()
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(output), QPromise<int> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(output), QPromise<int>>::value));
|
||||
|
||||
QCOMPARE(input.isFulfilled(), true);
|
||||
QCOMPARE(output.isPending(), true);
|
||||
|
@ -33,7 +33,7 @@ void tst_helpers::resolve()
|
||||
int value = -1;
|
||||
auto p = QtPromise::qPromise(42);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
|
||||
@ -49,7 +49,7 @@ void tst_helpers::resolve_void()
|
||||
int value = -1;
|
||||
auto p = QtPromise::qPromise();
|
||||
|
||||
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);
|
||||
|
||||
@ -70,7 +70,7 @@ void tst_helpers::resolve_promise()
|
||||
});
|
||||
}));
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
|
||||
@ -93,7 +93,7 @@ void tst_helpers::resolve_promise_void()
|
||||
});
|
||||
}));
|
||||
|
||||
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);
|
||||
|
||||
@ -115,9 +115,9 @@ void tst_helpers::allFulfilled()
|
||||
});
|
||||
});
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<int> >{p0, p2, p1});
|
||||
auto p = qPromiseAll(QVector<QPromise<int>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int> > >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
@ -144,9 +144,9 @@ void tst_helpers::allFulfilled_void()
|
||||
});
|
||||
});
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<void> >{p0, p2, p1});
|
||||
auto p = qPromiseAll(QVector<QPromise<void>>{p0, p2, p1});
|
||||
|
||||
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(p0.isFulfilled(), true);
|
||||
@ -169,9 +169,9 @@ void tst_helpers::allRejected()
|
||||
});
|
||||
});
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<int> >{p0, p2, p1});
|
||||
auto p = qPromiseAll(QVector<QPromise<int>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int> > >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
@ -199,9 +199,9 @@ void tst_helpers::allRejected_void()
|
||||
});
|
||||
});
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<void> >{p0, p2, p1});
|
||||
auto p = qPromiseAll(QVector<QPromise<void>>{p0, p2, p1});
|
||||
|
||||
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(p0.isFulfilled(), true);
|
||||
@ -220,9 +220,9 @@ void tst_helpers::allRejected_void()
|
||||
|
||||
void tst_helpers::allEmpty()
|
||||
{
|
||||
auto p = qPromiseAll(QVector<QPromise<int> >());
|
||||
auto p = qPromiseAll(QVector<QPromise<int>>());
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int> > >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
|
||||
@ -236,9 +236,9 @@ void tst_helpers::allEmpty()
|
||||
|
||||
void tst_helpers::allEmpty_void()
|
||||
{
|
||||
auto p = qPromiseAll(QVector<QPromise<void> >());
|
||||
auto p = qPromiseAll(QVector<QPromise<void>>());
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ struct SequenceTester
|
||||
};
|
||||
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
struct SequenceTester<Sequence<QPromise<int>, Args...> >
|
||||
struct SequenceTester<Sequence<QPromise<int>, Args...>>
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
@ -47,13 +47,13 @@ struct SequenceTester<Sequence<QPromise<int>, Args...> >
|
||||
|
||||
auto p = QPromise<int>::all(promises);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int> > >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 46, 43, 44}));
|
||||
}
|
||||
};
|
||||
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
struct SequenceTester<Sequence<QPromise<void>, Args...> >
|
||||
struct SequenceTester<Sequence<QPromise<void>, Args...>>
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
@ -69,7 +69,7 @@ struct SequenceTester<Sequence<QPromise<void>, Args...> >
|
||||
|
||||
auto p = QPromise<void>::all(promises);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
||||
};
|
||||
@ -78,26 +78,26 @@ struct SequenceTester<Sequence<QPromise<void>, Args...> >
|
||||
|
||||
void tst_qpromise_all::qList()
|
||||
{
|
||||
SequenceTester<QList<QPromise<int> > >::exec();
|
||||
SequenceTester<QList<QPromise<void> > >::exec();
|
||||
SequenceTester<QList<QPromise<int>>>::exec();
|
||||
SequenceTester<QList<QPromise<void>>>::exec();
|
||||
}
|
||||
|
||||
// QVector::push_back/append isn't supported since it requires a default
|
||||
// constructor (see https://github.com/simonbrunel/qtpromise/issues/3)
|
||||
//void tst_qpromise_all::qVector()
|
||||
//{
|
||||
// SequenceTester<QVector<QPromise<int> > >::exec();
|
||||
// SequenceTester<QVector<QPromise<void> > >::exec();
|
||||
// SequenceTester<QVector<QPromise<int>>>::exec();
|
||||
// SequenceTester<QVector<QPromise<void>>>::exec();
|
||||
//}
|
||||
|
||||
void tst_qpromise_all::stdList()
|
||||
{
|
||||
SequenceTester<std::list<QPromise<int> > >::exec();
|
||||
SequenceTester<std::list<QPromise<void> > >::exec();
|
||||
SequenceTester<std::list<QPromise<int>>>::exec();
|
||||
SequenceTester<std::list<QPromise<void>>>::exec();
|
||||
}
|
||||
|
||||
void tst_qpromise_all::stdVector()
|
||||
{
|
||||
SequenceTester<std::vector<QPromise<int> > >::exec();
|
||||
SequenceTester<std::vector<QPromise<void> > >::exec();
|
||||
SequenceTester<std::vector<QPromise<int>>>::exec();
|
||||
SequenceTester<std::vector<QPromise<void>>>::exec();
|
||||
}
|
||||
|
4
tests/auto/qtpromise/qpromise/cast/cast.pro
Normal file
4
tests/auto/qtpromise/qpromise/cast/cast.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = tst_qpromise_cast
|
||||
SOURCES += $$PWD/tst_cast.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
135
tests/auto/qtpromise/qpromise/cast/tst_cast.cpp
Normal file
135
tests/auto/qtpromise/qpromise/cast/tst_cast.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
// Tests
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_qpromise_cast : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void typeToVoid();
|
||||
|
||||
|
||||
//void castToVoidOperator();
|
||||
//void typeToVariant(); // QPromise<T>.cast<QVariant>()
|
||||
//void variantToType();
|
||||
//void voidToVariant(); // QPromise<void>.cast<QVariant>()
|
||||
//void variantToVoid();
|
||||
|
||||
//void jsonValueToJsonObject();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qpromise_cast)
|
||||
#include "tst_cast.moc"
|
||||
|
||||
void tst_qpromise_cast::typeToVoid()
|
||||
{
|
||||
QPromise<void> p0 = QPromise<int>::resolve(42);
|
||||
QPromise<void> p1 = QPromise<QString>::resolve(QString("foo"));
|
||||
QVERIFY(p0.isFulfilled());
|
||||
QVERIFY(p1.isFulfilled());
|
||||
}
|
||||
|
||||
//void tst_qpromise_cast::castToVoidOperator()
|
||||
//{
|
||||
//auto p0 = QPromise<int>::resolve(42);
|
||||
//QPromise<double> p1(p0);
|
||||
//QPromise<void> p2(p0);
|
||||
//auto p4 = QPromise<QString>::resolve("foo");
|
||||
//
|
||||
//p0.then([](int res) { qDebug() << res; });
|
||||
//p1.then([](double res) { qDebug() << res; });
|
||||
//p2.then([]() { qDebug() << "done"; });
|
||||
//
|
||||
//foo().then([]() {
|
||||
// qDebug() << "done";
|
||||
//}).wait();
|
||||
//
|
||||
//QPromise<QVariant>::all({p0, p1, p4}).then([](const QVector<QVariant>& res) {
|
||||
// qDebug() << "all done!" << res;
|
||||
//}).wait();
|
||||
//}
|
||||
|
||||
/*
|
||||
namespace {
|
||||
|
||||
template <typename T, typename U>
|
||||
void test_qpromise_cast(const T& t, const U& u)
|
||||
{
|
||||
auto p = QPromise<T>::resolve(t).cast<U>();
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<U> >::value));
|
||||
QCOMPARE(waitForValue(p, U()), u);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
void test_qpromise_cast(const U& u)
|
||||
{
|
||||
auto p = QPromise<void>::resolve().cast<U>();
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<U> >::value));
|
||||
QCOMPARE(waitForValue(p, U()), u);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
void tst_qpromise_cast::typeToVariant()
|
||||
{
|
||||
test_qpromise_cast(42, QVariant(42));
|
||||
test_qpromise_cast(4.2, QVariant(4.2));
|
||||
test_qpromise_cast(true, QVariant(true));
|
||||
test_qpromise_cast(QString("foo"), QVariant(QString("foo")));
|
||||
test_qpromise_cast(QUrl("http://x.y.z"), QVariant(QUrl("http://x.y.z")));
|
||||
test_qpromise_cast(QSize(128, 256), QVariant(QSize(128, 256)));
|
||||
test_qpromise_cast(QDate(2018, 1, 1), QVariant(QDate(2018, 1, 1)));
|
||||
test_qpromise_cast(QJsonValue("foo"), QVariant(QJsonValue("foo")));
|
||||
test_qpromise_cast(QStringList{"foo", "bar"}, QVariant(QStringList{"foo", "bar"}));
|
||||
test_qpromise_cast(QList<QVariant>{"foo", 42}, QVariant(QList<QVariant>{"foo", 42}));
|
||||
test_qpromise_cast(QMap<QString, QVariant>{{"foo", 42}}, QVariant(QVariantMap{{"foo", 42}}));
|
||||
}
|
||||
|
||||
void tst_qpromise_cast::voidToVariant()
|
||||
{
|
||||
test_qpromise_cast(QVariant());
|
||||
}
|
||||
|
||||
void tst_qpromise_cast::variantToType()
|
||||
{
|
||||
// invalid
|
||||
// int
|
||||
// QString
|
||||
// QColor
|
||||
// QList
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void tst_qpromise_cast::jsonValueToJsonObject()
|
||||
{
|
||||
{ // QJsonValue(Null) -> QJsonObject
|
||||
auto p = QPromise<QJsonValue>::resolve(QJsonValue()).cast<QJsonObject>();
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QJsonObject> >::value));
|
||||
const QJsonObject res = waitForValue(p, QJsonObject());
|
||||
QVERIFY(res.isEmpty());
|
||||
}
|
||||
{ // QJsonValue(int) -> QJsonObject
|
||||
auto p = QPromise<QJsonValue>::resolve(QJsonValue(42)).cast<QJsonObject>();
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QJsonObject> >::value));
|
||||
const QJsonObject res = waitForValue(p, QJsonObject());
|
||||
QVERIFY(res.isEmpty());
|
||||
}
|
||||
{ // QJsonValue(QJsonObject) -> QJsonObject
|
||||
const QJsonObject object{{"magic", 42}};
|
||||
auto p = QPromise<QJsonValue>::resolve(QJsonValue(object)).cast<QJsonObject>();
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QJsonObject> >::value));
|
||||
const QJsonObject res = waitForValue(p, QJsonObject());
|
||||
QCOMPARE(res.value("magic"), 42);
|
||||
}
|
||||
}
|
||||
*/
|
@ -7,6 +7,9 @@
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
// STL
|
||||
#include <memory>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_qpromise_construct : public QObject
|
||||
@ -30,6 +33,8 @@ private Q_SLOTS:
|
||||
void rejectSync_void();
|
||||
void rejectAsync();
|
||||
void rejectAsync_void();
|
||||
void connectAndResolve();
|
||||
void connectAndReject();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qpromise_construct)
|
||||
@ -228,3 +233,77 @@ void tst_qpromise_construct::rejectThrowTwoArgs_void()
|
||||
QCOMPARE(waitForValue(p, -1, 42), -1);
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/6
|
||||
void tst_qpromise_construct::connectAndResolve()
|
||||
{
|
||||
QScopedPointer<QObject> object(new QObject());
|
||||
|
||||
std::weak_ptr<int> wptr;
|
||||
|
||||
{
|
||||
auto p = QPromise<std::shared_ptr<int>>([&](
|
||||
const QPromiseResolve<std::shared_ptr<int>>& resolve,
|
||||
const QPromiseReject<std::shared_ptr<int>>& reject) {
|
||||
|
||||
connect(object.data(), &QObject::objectNameChanged,
|
||||
[=, &wptr](const QString& name) {
|
||||
std::shared_ptr<int> sptr(new int(42));
|
||||
|
||||
wptr = sptr;
|
||||
|
||||
if (name == "foobar") {
|
||||
resolve(sptr);
|
||||
} else {
|
||||
reject(42);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
|
||||
object->setObjectName("foobar");
|
||||
|
||||
QCOMPARE(waitForValue(p, std::shared_ptr<int>()), wptr.lock());
|
||||
QCOMPARE(wptr.use_count(), 1l); // "p" still holds a reference
|
||||
}
|
||||
|
||||
QCOMPARE(wptr.use_count(), 0l);
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/6
|
||||
void tst_qpromise_construct::connectAndReject()
|
||||
{
|
||||
QScopedPointer<QObject> object(new QObject());
|
||||
|
||||
std::weak_ptr<int> wptr;
|
||||
|
||||
{
|
||||
auto p = QPromise<int>([&](
|
||||
const QPromiseResolve<int>& resolve,
|
||||
const QPromiseReject<int>& reject) {
|
||||
|
||||
connect(object.data(), &QObject::objectNameChanged,
|
||||
[=, &wptr](const QString& name) {
|
||||
std::shared_ptr<int> sptr(new int(42));
|
||||
|
||||
wptr = sptr;
|
||||
|
||||
if (name == "foobar") {
|
||||
reject(sptr);
|
||||
} else {
|
||||
resolve(42);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
|
||||
object->setObjectName("foobar");
|
||||
|
||||
QCOMPARE(waitForError(p, std::shared_ptr<int>()), wptr.lock());
|
||||
QCOMPARE(wptr.use_count(), 1l); // "p" still holds a reference
|
||||
}
|
||||
|
||||
QCOMPARE(wptr.use_count(), 0l);
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ void tst_qpromise_finally::fulfilledSync()
|
||||
return 16; // ignored!
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
QCOMPARE(waitForValue(p, -1), 42);
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(value, 8);
|
||||
@ -53,7 +53,7 @@ void tst_qpromise_finally::fulfilledSync_void()
|
||||
return 16; // ignored!
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(value, 8);
|
||||
@ -65,7 +65,7 @@ void tst_qpromise_finally::fulfilledThrows()
|
||||
throw QString("bar");
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("bar"));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
}
|
||||
@ -76,7 +76,7 @@ void tst_qpromise_finally::fulfilledThrows_void()
|
||||
throw QString("bar");
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("bar"));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
}
|
||||
@ -123,7 +123,7 @@ void tst_qpromise_finally::rejectedSync()
|
||||
return 16; // ignored!
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
QCOMPARE(value, 8);
|
||||
@ -137,7 +137,7 @@ void tst_qpromise_finally::rejectedSync_void()
|
||||
return 16; // ignored!
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
QCOMPARE(value, 8);
|
||||
@ -149,7 +149,7 @@ void tst_qpromise_finally::rejectedThrows()
|
||||
throw QString("bar");
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("bar"));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
}
|
||||
@ -160,7 +160,7 @@ void tst_qpromise_finally::rejectedThrows_void()
|
||||
throw QString("bar");
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("bar"));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
}
|
||||
|
@ -1,12 +1,15 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS += \
|
||||
all \
|
||||
cast \
|
||||
construct \
|
||||
delay \
|
||||
fail \
|
||||
finally \
|
||||
operators \
|
||||
reject \
|
||||
resolve \
|
||||
tap \
|
||||
tapfail \
|
||||
then \
|
||||
timeout
|
||||
|
4
tests/auto/qtpromise/qpromise/reject/reject.pro
Normal file
4
tests/auto/qtpromise/qpromise/reject/reject.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = tst_qpromise_reject
|
||||
SOURCES += $$PWD/tst_reject.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
74
tests/auto/qtpromise/qpromise/reject/tst_reject.cpp
Normal file
74
tests/auto/qtpromise/qpromise/reject/tst_reject.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
// Tests
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
// STL
|
||||
#include <memory>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_qpromise_reject : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void rejectWithValue();
|
||||
void rejectWithQSharedPtr();
|
||||
void rejectWithStdSharedPtr();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qpromise_reject)
|
||||
#include "tst_reject.moc"
|
||||
|
||||
void tst_qpromise_reject::rejectWithValue()
|
||||
{
|
||||
auto p = QPromise<int>::reject(42);
|
||||
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
QCOMPARE(waitForError(p, -1), 42);
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/6
|
||||
void tst_qpromise_reject::rejectWithQSharedPtr()
|
||||
{
|
||||
QWeakPointer<int> wptr;
|
||||
|
||||
{
|
||||
QSharedPointer<int> sptr(new int(42));
|
||||
auto p = QPromise<int>::reject(sptr);
|
||||
|
||||
QCOMPARE(waitForError(p, QSharedPointer<int>()), sptr);
|
||||
|
||||
wptr = sptr;
|
||||
sptr.reset();
|
||||
|
||||
QCOMPARE(wptr.isNull(), false); // "p" still holds a reference
|
||||
}
|
||||
|
||||
QCOMPARE(wptr.isNull(), true);
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/6
|
||||
void tst_qpromise_reject::rejectWithStdSharedPtr()
|
||||
{
|
||||
std::weak_ptr<int> wptr;
|
||||
|
||||
{
|
||||
std::shared_ptr<int> sptr(new int(42));
|
||||
auto p = QPromise<int>::reject(sptr);
|
||||
|
||||
QCOMPARE(waitForError(p, std::shared_ptr<int>()), sptr);
|
||||
|
||||
wptr = sptr;
|
||||
sptr.reset();
|
||||
|
||||
QCOMPARE(wptr.use_count(), 1l); // "p" still holds a reference
|
||||
}
|
||||
|
||||
QCOMPARE(wptr.use_count(), 0l);
|
||||
}
|
@ -7,6 +7,9 @@
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
// STL
|
||||
#include <memory>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_qpromise_resolve : public QObject
|
||||
@ -14,14 +17,16 @@ class tst_qpromise_resolve : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void value();
|
||||
void empty_void();
|
||||
void resolveWithValue();
|
||||
void resolveWithNoValue();
|
||||
void resolveWithQSharedPtr();
|
||||
void resolveWithStdSharedPtr();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qpromise_resolve)
|
||||
#include "tst_resolve.moc"
|
||||
|
||||
void tst_qpromise_resolve::value()
|
||||
void tst_qpromise_resolve::resolveWithValue()
|
||||
{
|
||||
const int value = 42;
|
||||
auto p0 = QPromise<int>::resolve(value);
|
||||
@ -33,9 +38,49 @@ void tst_qpromise_resolve::value()
|
||||
QCOMPARE(waitForValue(p1, -1), 43);
|
||||
}
|
||||
|
||||
void tst_qpromise_resolve::empty_void()
|
||||
void tst_qpromise_resolve::resolveWithNoValue()
|
||||
{
|
||||
auto p = QPromise<void>::resolve();
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/6
|
||||
void tst_qpromise_resolve::resolveWithQSharedPtr()
|
||||
{
|
||||
QWeakPointer<int> wptr;
|
||||
|
||||
{
|
||||
QSharedPointer<int> sptr(new int(42));
|
||||
auto p = QPromise<QSharedPointer<int>>::resolve(sptr);
|
||||
|
||||
QCOMPARE(waitForValue(p, QSharedPointer<int>()), sptr);
|
||||
|
||||
wptr = sptr;
|
||||
sptr.reset();
|
||||
|
||||
QCOMPARE(wptr.isNull(), false); // "p" still holds a reference
|
||||
}
|
||||
|
||||
QCOMPARE(wptr.isNull(), true);
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/6
|
||||
void tst_qpromise_resolve::resolveWithStdSharedPtr()
|
||||
{
|
||||
std::weak_ptr<int> wptr;
|
||||
|
||||
{
|
||||
std::shared_ptr<int> sptr(new int(42));
|
||||
auto p = QPromise<std::shared_ptr<int>>::resolve(sptr);
|
||||
|
||||
QCOMPARE(waitForValue(p, std::shared_ptr<int>()), sptr);
|
||||
|
||||
wptr = sptr;
|
||||
sptr.reset();
|
||||
|
||||
QCOMPARE(wptr.use_count(), 1l); // "p" still holds a reference
|
||||
}
|
||||
|
||||
QCOMPARE(wptr.use_count(), 0l);
|
||||
}
|
||||
|
4
tests/auto/qtpromise/qpromise/tapfail/tapfail.pro
Normal file
4
tests/auto/qtpromise/qpromise/tapfail/tapfail.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = tst_qpromise_tapfail
|
||||
SOURCES += $$PWD/tst_tapfail.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
159
tests/auto/qtpromise/qpromise/tapfail/tst_tapfail.cpp
Normal file
159
tests/auto/qtpromise/qpromise/tapfail/tst_tapfail.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
// Tests
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_qpromise_tapfail : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void fulfilled();
|
||||
void fulfilled_void();
|
||||
void rejected();
|
||||
void rejected_void();
|
||||
void throws();
|
||||
void throws_void();
|
||||
void delayedResolved();
|
||||
void delayedRejected();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qpromise_tapfail)
|
||||
#include "tst_tapfail.moc"
|
||||
|
||||
void tst_qpromise_tapfail::fulfilled()
|
||||
{
|
||||
int value = -1;
|
||||
auto p = QPromise<int>::resolve(42).tapFail([&]() {
|
||||
value = 43;
|
||||
});
|
||||
|
||||
QCOMPARE(waitForValue(p, 42), 42);
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(value, -1);
|
||||
}
|
||||
|
||||
void tst_qpromise_tapfail::fulfilled_void()
|
||||
{
|
||||
int value = -1;
|
||||
auto p = QPromise<void>::resolve().tapFail([&]() {
|
||||
value = 43;
|
||||
});
|
||||
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(value, -1);
|
||||
}
|
||||
|
||||
void tst_qpromise_tapfail::rejected()
|
||||
{
|
||||
QStringList errors;
|
||||
|
||||
auto p0 = QPromise<int>::reject(QString("foo"))
|
||||
.tapFail([&](const QString& err) {
|
||||
errors << "1:" + err;
|
||||
});
|
||||
|
||||
auto p1 = p0
|
||||
.fail([&](const QString& err) {
|
||||
errors << "2:" + err;
|
||||
return 43;
|
||||
});
|
||||
|
||||
QCOMPARE(waitForError(p0, QString()), QString("foo"));
|
||||
QCOMPARE(waitForValue(p1, -1), 43);
|
||||
QCOMPARE(p0.isRejected(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(errors, QStringList() << "1:foo" << "2:foo");
|
||||
}
|
||||
|
||||
void tst_qpromise_tapfail::rejected_void()
|
||||
{
|
||||
QStringList errors;
|
||||
|
||||
auto p0 = QPromise<void>::reject(QString("foo"))
|
||||
.tapFail([&](const QString& err) {
|
||||
errors << "1:" + err;
|
||||
});
|
||||
|
||||
auto p1 = p0
|
||||
.fail([&](const QString& err) {
|
||||
errors << "2:" + err;
|
||||
});
|
||||
|
||||
QCOMPARE(waitForError(p0, QString()), QString("foo"));
|
||||
QCOMPARE(waitForValue(p1, -1, 43), 43);
|
||||
QCOMPARE(p0.isRejected(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(errors, QStringList() << "1:foo" << "2:foo");
|
||||
}
|
||||
|
||||
void tst_qpromise_tapfail::throws()
|
||||
{
|
||||
auto p = QPromise<int>::reject(QString("foo"))
|
||||
.tapFail([&]() {
|
||||
throw QString("bar");
|
||||
});
|
||||
|
||||
QCOMPARE(waitForError(p, QString()), QString("bar"));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
}
|
||||
|
||||
void tst_qpromise_tapfail::throws_void()
|
||||
{
|
||||
auto p = QPromise<void>::reject(QString("foo"))
|
||||
.tapFail([&]() {
|
||||
throw QString("bar");
|
||||
});
|
||||
|
||||
QCOMPARE(waitForError(p, QString()), QString("bar"));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
}
|
||||
|
||||
void tst_qpromise_tapfail::delayedResolved()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QPromise<int>::reject(QString("foo"))
|
||||
.tapFail([&]() {
|
||||
QPromise<void> p([&](const QPromiseResolve<void>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=, &values]() {
|
||||
values << 3;
|
||||
resolve(); // ignored!
|
||||
});
|
||||
});
|
||||
|
||||
values << 2;
|
||||
return p;
|
||||
});
|
||||
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(values, QVector<int>({2, 3}));
|
||||
}
|
||||
|
||||
void tst_qpromise_tapfail::delayedRejected()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QPromise<int>::reject(QString("foo"))
|
||||
.tapFail([&]() {
|
||||
QPromise<void> p([&](
|
||||
const QPromiseResolve<void>&,
|
||||
const QPromiseReject<void>& reject){
|
||||
QtPromisePrivate::qtpromise_defer([=, &values]() {
|
||||
values << 3;
|
||||
reject(QString("bar"));
|
||||
});
|
||||
});
|
||||
|
||||
values << 2;
|
||||
return p;
|
||||
});
|
||||
|
||||
QCOMPARE(waitForError(p, QString()), QString("bar"));
|
||||
QCOMPARE(values, QVector<int>({2, 3}));
|
||||
}
|
@ -56,7 +56,7 @@ void tst_qpromise_then::resolveAsync()
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||
QCOMPARE(waitForValue(p, QString()), QString("foo42"));
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
}
|
||||
@ -91,7 +91,7 @@ void tst_qpromise_then::rejectAsync()
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo42"));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
}
|
||||
@ -105,7 +105,7 @@ void tst_qpromise_then::skipResult()
|
||||
value = 43;
|
||||
}).wait();
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
QCOMPARE(value, 43);
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,15 @@
|
||||
TEMPLATE = app
|
||||
CONFIG += testcase
|
||||
CONFIG += testcase warn_on
|
||||
QT += testlib
|
||||
QT -= gui
|
||||
|
||||
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
|
||||
|
||||
coverage {
|
||||
gcc {
|
||||
message("Code coverage enabled (gcov)")
|
||||
|
@ -279,7 +279,7 @@ void tst_requirements::thenMultipleCalls()
|
||||
});
|
||||
});
|
||||
|
||||
qPromiseAll(QVector<QPromise<void> >{
|
||||
qPromiseAll(QVector<QPromise<void>>{
|
||||
p.then([&](int r) { values << r + 1; }),
|
||||
p.then([&](int r) { values << r + 2; }),
|
||||
p.then([&](int r) { values << r + 3; })
|
||||
@ -298,7 +298,7 @@ void tst_requirements::thenMultipleCalls()
|
||||
});
|
||||
});
|
||||
|
||||
qPromiseAll(QVector<QPromise<int> >{
|
||||
qPromiseAll(QVector<QPromise<int>>{
|
||||
p.then(nullptr, [&](int r) { values << r + 1; return r + 1; }),
|
||||
p.then(nullptr, [&](int r) { values << r + 2; return r + 2; }),
|
||||
p.then(nullptr, [&](int r) { values << r + 3; return r + 3; })
|
||||
@ -314,9 +314,9 @@ void tst_requirements::thenHandlers()
|
||||
{
|
||||
auto handler = [](){ return 42; };
|
||||
auto p1 = QPromise<int>::resolve(42);
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1.then(handler, nullptr)), QPromise<int> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1.then(nullptr, handler)), QPromise<int> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1.then(handler, handler)), QPromise<int> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1.then(handler, nullptr)), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1.then(nullptr, handler)), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1.then(handler, handler)), QPromise<int>>::value));
|
||||
}
|
||||
|
||||
// 2.2.7.1. If either onFulfilled or onRejected returns a value x, run the
|
||||
@ -351,7 +351,7 @@ void tst_requirements::thenHandlers()
|
||||
QString value;
|
||||
auto p1 = QPromise<QString>::resolve("42");
|
||||
auto p2 = p1.then(nullptr, [](){ return QString(); });
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<QString> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<QString>>::value));
|
||||
p2.then([&](const QString& e) { value = e; }).wait();
|
||||
|
||||
QVERIFY(p1.isFulfilled());
|
||||
|
@ -28,159 +28,159 @@ QTEST_MAIN(tst_thread)
|
||||
void tst_thread::resolve()
|
||||
{
|
||||
int value = -1;
|
||||
size_t target = 0;
|
||||
size_t source = 0;
|
||||
QThread* target = nullptr;
|
||||
QThread* source = nullptr;
|
||||
|
||||
QPromise<int>([&](const QPromiseResolve<int>& resolve) {
|
||||
QtConcurrent::run([=, &source]() {
|
||||
source = (size_t)QThread::currentThread();
|
||||
source = QThread::currentThread();
|
||||
resolve(42);
|
||||
});
|
||||
}).then([&](int res) {
|
||||
target = (size_t)QThread::currentThread();
|
||||
target = QThread::currentThread();
|
||||
value = res;
|
||||
}).wait();
|
||||
|
||||
QVERIFY(source != 0);
|
||||
QVERIFY(source != nullptr);
|
||||
QVERIFY(source != target);
|
||||
QCOMPARE(target, (size_t)QThread::currentThread());
|
||||
QCOMPARE(target, QThread::currentThread());
|
||||
QCOMPARE(value, 42);
|
||||
}
|
||||
|
||||
void tst_thread::resolve_void()
|
||||
{
|
||||
int value = -1;
|
||||
size_t target = 0;
|
||||
size_t source = 0;
|
||||
QThread* target = nullptr;
|
||||
QThread* source = nullptr;
|
||||
|
||||
QPromise<void>([&](const QPromiseResolve<void>& resolve) {
|
||||
QtConcurrent::run([=, &source]() {
|
||||
source = (size_t)QThread::currentThread();
|
||||
source = QThread::currentThread();
|
||||
resolve();
|
||||
});
|
||||
}).then([&]() {
|
||||
target = (size_t)QThread::currentThread();
|
||||
target = QThread::currentThread();
|
||||
value = 43;
|
||||
}).wait();
|
||||
|
||||
QVERIFY(source != 0);
|
||||
QVERIFY(source != nullptr);
|
||||
QVERIFY(source != target);
|
||||
QCOMPARE(target, (size_t)QThread::currentThread());
|
||||
QCOMPARE(target, QThread::currentThread());
|
||||
QCOMPARE(value, 43);
|
||||
}
|
||||
|
||||
void tst_thread::reject()
|
||||
{
|
||||
QString error;
|
||||
size_t target = 0;
|
||||
size_t source = 0;
|
||||
QThread* target = nullptr;
|
||||
QThread* source = nullptr;
|
||||
|
||||
QPromise<int>([&](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
|
||||
QtConcurrent::run([=, &source]() {
|
||||
source = (size_t)QThread::currentThread();
|
||||
source = QThread::currentThread();
|
||||
reject(QString("foo"));
|
||||
});
|
||||
}).fail([&](const QString& err) {
|
||||
target = (size_t)QThread::currentThread();
|
||||
target = QThread::currentThread();
|
||||
error = err;
|
||||
return -1;
|
||||
}).wait();
|
||||
|
||||
QVERIFY(source != 0);
|
||||
QVERIFY(source != nullptr);
|
||||
QVERIFY(source != target);
|
||||
QCOMPARE(target, (size_t)QThread::currentThread());
|
||||
QCOMPARE(target, QThread::currentThread());
|
||||
QCOMPARE(error, QString("foo"));
|
||||
}
|
||||
|
||||
void tst_thread::then()
|
||||
{
|
||||
size_t source;
|
||||
QThread* source = nullptr;
|
||||
QPromise<int> p([&](const QPromiseResolve<int>& resolve) {
|
||||
source = (size_t)QThread::currentThread();
|
||||
source = QThread::currentThread();
|
||||
resolve(42);
|
||||
});
|
||||
|
||||
size_t target;
|
||||
int value = -1;
|
||||
QThread* target = nullptr;
|
||||
qPromise(QtConcurrent::run([&](const QPromise<int>& p) {
|
||||
p.then([&](int res) {
|
||||
target = (size_t)QThread::currentThread();
|
||||
target = QThread::currentThread();
|
||||
value = res;
|
||||
}).wait();
|
||||
}, p)).wait();
|
||||
|
||||
QVERIFY(target != 0);
|
||||
QVERIFY(target != nullptr);
|
||||
QVERIFY(source != target);
|
||||
QCOMPARE(source, (size_t)QThread::currentThread());
|
||||
QCOMPARE(source, QThread::currentThread());
|
||||
QCOMPARE(value, 42);
|
||||
}
|
||||
|
||||
void tst_thread::then_void()
|
||||
{
|
||||
size_t source;
|
||||
QThread* source = nullptr;
|
||||
QPromise<void> p([&](const QPromiseResolve<void>& resolve) {
|
||||
source = (size_t)QThread::currentThread();
|
||||
source = QThread::currentThread();
|
||||
resolve();
|
||||
});
|
||||
|
||||
size_t target;
|
||||
int value = -1;
|
||||
QThread* target = nullptr;
|
||||
qPromise(QtConcurrent::run([&](const QPromise<void>& p) {
|
||||
p.then([&]() {
|
||||
target = (size_t)QThread::currentThread();
|
||||
target = QThread::currentThread();
|
||||
value = 43;
|
||||
}).wait();
|
||||
}, p)).wait();
|
||||
|
||||
QVERIFY(target != 0);
|
||||
QVERIFY(target != nullptr);
|
||||
QVERIFY(source != target);
|
||||
QCOMPARE(source, (size_t)QThread::currentThread());
|
||||
QCOMPARE(source, QThread::currentThread());
|
||||
QCOMPARE(value, 43);
|
||||
}
|
||||
|
||||
void tst_thread::fail()
|
||||
{
|
||||
size_t source;
|
||||
QThread* source = nullptr;
|
||||
QPromise<int> p([&](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
|
||||
source = (size_t)QThread::currentThread();
|
||||
source = QThread::currentThread();
|
||||
reject(QString("foo"));
|
||||
});
|
||||
|
||||
size_t target;
|
||||
QString error;
|
||||
QThread* target = nullptr;
|
||||
qPromise(QtConcurrent::run([&](const QPromise<int>& p) {
|
||||
p.fail([&](const QString& err) {
|
||||
target = (size_t)QThread::currentThread();
|
||||
target = QThread::currentThread();
|
||||
error = err;
|
||||
return -1;
|
||||
}).wait();
|
||||
}, p)).wait();
|
||||
|
||||
QVERIFY(target != 0);
|
||||
QVERIFY(target != nullptr);
|
||||
QVERIFY(source != target);
|
||||
QCOMPARE(source, (size_t)QThread::currentThread());
|
||||
QCOMPARE(source, QThread::currentThread());
|
||||
QCOMPARE(error, QString("foo"));
|
||||
}
|
||||
|
||||
void tst_thread::finally()
|
||||
{
|
||||
size_t source;
|
||||
QThread* source = nullptr;
|
||||
QPromise<int> p([&](const QPromiseResolve<int>& resolve) {
|
||||
source = (size_t)QThread::currentThread();
|
||||
source = QThread::currentThread();
|
||||
resolve(42);
|
||||
});
|
||||
|
||||
size_t target;
|
||||
int value = -1;
|
||||
QThread* target = nullptr;
|
||||
qPromise(QtConcurrent::run([&](const QPromise<int>& p) {
|
||||
p.finally([&]() {
|
||||
target = (size_t)QThread::currentThread();
|
||||
target = QThread::currentThread();
|
||||
value = 43;
|
||||
}).wait();
|
||||
}, p)).wait();
|
||||
|
||||
QVERIFY(target != 0);
|
||||
QVERIFY(target != nullptr);
|
||||
QVERIFY(source != target);
|
||||
QCOMPARE(source, (size_t)QThread::currentThread());
|
||||
QCOMPARE(source, QThread::currentThread());
|
||||
QCOMPARE(value, 43);
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
TARGET = tst_qtqmlpromise_extension
|
||||
SOURCES += $$PWD/tst_extension.cpp
|
||||
OTHER_FILES += $$PWD/*.qml
|
||||
|
||||
include(../qtqmlpromise.pri)
|
@ -1,10 +0,0 @@
|
||||
#include <QtQuickTest/quicktest.h>
|
||||
|
||||
static void initialize()
|
||||
{
|
||||
qputenv("QML2_IMPORT_PATH", QTPROMISE_IMPORTPATH);
|
||||
}
|
||||
|
||||
Q_COREAPP_STARTUP_FUNCTION(initialize)
|
||||
|
||||
QUICK_TEST_MAIN(extension)
|
@ -1,39 +0,0 @@
|
||||
import QtQuick 2.3
|
||||
import QtPromise 1.0
|
||||
import QtTest 1.0
|
||||
|
||||
TestCase {
|
||||
name: "Extension"
|
||||
|
||||
function test_global() {
|
||||
compare(typeof __qtpromise_private__, 'undefined');
|
||||
compare(typeof Promise, 'function');
|
||||
compare(typeof Promise.resolve, 'function');
|
||||
compare(typeof Promise.reject, 'function');
|
||||
}
|
||||
|
||||
function test_instance() {
|
||||
var p = new Promise(function() {});
|
||||
compare(Object.prototype.toString(p), '[object Object]');
|
||||
compare(p instanceof Promise, true);
|
||||
compare(typeof p, 'object');
|
||||
}
|
||||
|
||||
function test_prototype() {
|
||||
var p = new Promise(function() {});
|
||||
|
||||
[
|
||||
'delay',
|
||||
'fail',
|
||||
'finally',
|
||||
'isFulfilled',
|
||||
'isRejected',
|
||||
'isPending',
|
||||
'tap',
|
||||
'then',
|
||||
'wait',
|
||||
].forEach(function(name) {
|
||||
compare(typeof p[name], 'function');
|
||||
});
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
TEMPLATE = app
|
||||
CONFIG += qmltestcase
|
||||
CONFIG += qtpromise-qml
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
QTPROMISE_IMPORTPATH = $$shadowed($$PWD/../../../qml)
|
||||
DEFINES += QTPROMISE_IMPORTPATH=\"\\\"$$QTPROMISE_IMPORTPATH\\\"\"
|
||||
|
||||
include(../../../qtpromise.pri)
|
@ -1,4 +0,0 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS += \
|
||||
extension \
|
||||
requirements
|
@ -1,5 +0,0 @@
|
||||
TARGET = tst_qtqmlpromise_requirements
|
||||
SOURCES += $$PWD/tst_requirements.cpp
|
||||
OTHER_FILES += $$PWD/*.qml
|
||||
|
||||
include(../qtqmlpromise.pri)
|
@ -1,10 +0,0 @@
|
||||
#include <QtQuickTest/quicktest.h>
|
||||
|
||||
static void initialize()
|
||||
{
|
||||
qputenv("QML2_IMPORT_PATH", QTPROMISE_IMPORTPATH);
|
||||
}
|
||||
|
||||
Q_COREAPP_STARTUP_FUNCTION(initialize)
|
||||
|
||||
QUICK_TEST_MAIN(requirements)
|
@ -1,384 +0,0 @@
|
||||
import QtQuick 2.3
|
||||
import QtPromise 1.0
|
||||
import QtTest 1.0
|
||||
|
||||
// https://promisesaplus.com/#requirements
|
||||
TestCase {
|
||||
name: "Requirements"
|
||||
|
||||
// 2.1. Promise States
|
||||
|
||||
// 2.1.1 When pending, a promise:
|
||||
function test_pendingFulfilled() {
|
||||
// 2.1.1.1. may transition to either the fulfilled state
|
||||
var p = new Promise(function(resolve) {
|
||||
Qt.callLater(function() {
|
||||
resolve(42);
|
||||
});
|
||||
});
|
||||
|
||||
compare(p.isPending(), true);
|
||||
compare(p.isFulfilled(), false);
|
||||
compare(p.isRejected(), false);
|
||||
|
||||
p.wait();
|
||||
|
||||
compare(p.isPending(), false);
|
||||
compare(p.isFulfilled(), true);
|
||||
compare(p.isRejected(), false);
|
||||
}
|
||||
|
||||
// 2.1.1 When pending, a promise:
|
||||
function test_pendingRejected() {
|
||||
// 2.1.1.1. ... or the rejected state
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
Qt.callLater(function() {
|
||||
reject(new Error(42));
|
||||
});
|
||||
});
|
||||
|
||||
compare(p.isPending(), true);
|
||||
compare(p.isFulfilled(), false);
|
||||
compare(p.isRejected(), false);
|
||||
|
||||
p.wait();
|
||||
|
||||
compare(p.isPending(), false);
|
||||
compare(p.isFulfilled(), false);
|
||||
compare(p.isRejected(), true);
|
||||
}
|
||||
|
||||
// 2.1.2. When fulfilled, a promise:
|
||||
function test_fulfilled() {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
Qt.callLater(function() {
|
||||
// 2.1.2.2. must have a value, which must not change.
|
||||
resolve(42);
|
||||
resolve(43);
|
||||
|
||||
// 2.1.2.1. must not transition to any other state.
|
||||
reject(new Error("foo"));
|
||||
});
|
||||
});
|
||||
|
||||
compare(p.isPending(), true);
|
||||
|
||||
var value = -1;
|
||||
var error = null;
|
||||
|
||||
p.then(function(res) {
|
||||
value = res;
|
||||
}, function(err) {
|
||||
error = err;
|
||||
}).wait();
|
||||
|
||||
compare(p.isFulfilled(), true);
|
||||
compare(p.isRejected(), false);
|
||||
compare(error, null);
|
||||
compare(value, 42);
|
||||
}
|
||||
|
||||
// 2.1.3 When rejected, a promise:
|
||||
function test_rejected() {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
Qt.callLater(function() {
|
||||
// 2.1.3.2. must have a reason, which must not change.
|
||||
reject(new Error("foo"));
|
||||
reject(new Error("bar"));
|
||||
|
||||
// 2.1.3.1. must not transition to any other state.
|
||||
resolve(42);
|
||||
});
|
||||
});
|
||||
|
||||
compare(p.isPending(), true);
|
||||
|
||||
var value = -1;
|
||||
var error = null;
|
||||
|
||||
p.then(function(res) {
|
||||
value = res;
|
||||
}, function(err) {
|
||||
error = err;
|
||||
}).wait();
|
||||
|
||||
compare(p.isFulfilled(), false);
|
||||
compare(p.isRejected(), true);
|
||||
compare(error instanceof Error, true);
|
||||
compare(error.message, 'foo');
|
||||
compare(value, -1);
|
||||
}
|
||||
|
||||
// 2.2. The then Method
|
||||
|
||||
// 2.2.1. Both onFulfilled and onRejected are given (resolve)
|
||||
function test_thenArgsBothResolve() {
|
||||
var error = null;
|
||||
var value = -1;
|
||||
|
||||
Promise.resolve(42).then(
|
||||
function(res) { value = res; },
|
||||
function(err) { error = err; }
|
||||
).wait();
|
||||
|
||||
compare(error, null);
|
||||
compare(value, 42);
|
||||
}
|
||||
|
||||
// 2.2.1. Both onFulfilled and onRejected are given (reject)
|
||||
function test_thenArgsBothReject() {
|
||||
var error = null;
|
||||
var value = -1;
|
||||
|
||||
Promise.reject(new Error('foo')).then(
|
||||
function(res) { value = res; },
|
||||
function(err) { error = err; }
|
||||
).wait();
|
||||
|
||||
compare(error instanceof Error, true);
|
||||
compare(error.message, 'foo');
|
||||
compare(value, -1);
|
||||
}
|
||||
|
||||
// 2.2.1. onFulfilled is an optional arguments:
|
||||
function test_thenArgsSecond() {
|
||||
var error = null;
|
||||
|
||||
Promise.reject(new Error('foo')).then(
|
||||
null,
|
||||
function(err) { error = err; }
|
||||
).wait();
|
||||
|
||||
compare(error instanceof Error, true);
|
||||
compare(error.message, 'foo');
|
||||
}
|
||||
|
||||
// 2.2.1. onRejected is an optional arguments:
|
||||
function test_thenArgsFirst() {
|
||||
var value = -1;
|
||||
|
||||
Promise.resolve(42).then(
|
||||
function(res) { value = res; }
|
||||
).wait();
|
||||
|
||||
compare(value, 42);
|
||||
}
|
||||
|
||||
// 2.2.1.1. If onFulfilled is not a function, it must be ignored.
|
||||
function test_thenArgsFirstInvalid() {
|
||||
var value = -1;
|
||||
|
||||
Promise.resolve(42).then('invalid').then(
|
||||
function(res) { value = res; }
|
||||
).wait();
|
||||
|
||||
compare(value, 42);
|
||||
}
|
||||
|
||||
// 2.2.1.2. If onRejected is not a function, it must be ignored.
|
||||
function test_thenArgsSecondInvalid() {
|
||||
var error = -1;
|
||||
|
||||
Promise.reject(new Error('foo')).then(
|
||||
null,
|
||||
'invalid'
|
||||
).then(
|
||||
null,
|
||||
function(err) { error = err; }
|
||||
).wait();
|
||||
|
||||
compare(error instanceof Error, true);
|
||||
compare(error.message, 'foo');
|
||||
}
|
||||
|
||||
// 2.2.2. If onFulfilled is a function:
|
||||
function test_thenOnFulfilled() {
|
||||
var p0 = new Promise(function(resolve) {
|
||||
Qt.callLater(function() {
|
||||
// 2.2.2.3. it must not be called more than once
|
||||
resolve(42);
|
||||
resolve(43);
|
||||
});
|
||||
});
|
||||
|
||||
var values = [];
|
||||
var p1 = p0.then(function(res) {
|
||||
values.push(res);
|
||||
});
|
||||
|
||||
// 2.2.2.2. it must not be called before promise is fulfilled.
|
||||
compare(p0.isPending(), true);
|
||||
compare(p1.isPending(), true);
|
||||
compare(values.length, 0);
|
||||
|
||||
p1.wait();
|
||||
|
||||
// 2.2.2.1. it must be called after promise is fulfilled,
|
||||
// with promise’s value as its first argument.
|
||||
compare(p0.isFulfilled(), true);
|
||||
compare(p1.isFulfilled(), true);
|
||||
compare(values, [42]);
|
||||
}
|
||||
|
||||
// 2.2.3. If onRejected is a function:
|
||||
function test_thenOnRejected() {
|
||||
var p0 = new Promise(function(resolve, reject) {
|
||||
Qt.callLater(function() {
|
||||
// 2.2.2.3. it must not be called more than once
|
||||
reject(new Error('foo'));
|
||||
reject(new Error('bar'));
|
||||
});
|
||||
});
|
||||
|
||||
var errors = [];
|
||||
var p1 = p0.then(null, function(res) {
|
||||
errors.push(res);
|
||||
});
|
||||
|
||||
// 2.2.3.2. it must not be called before promise is rejected.
|
||||
compare(p0.isPending(), true);
|
||||
compare(p1.isPending(), true);
|
||||
compare(errors.length, 0);
|
||||
|
||||
p1.wait();
|
||||
|
||||
// 2.2.3.1. it must be called after promise is rejected,
|
||||
// with promise’s reason as its first argument.
|
||||
compare(p0.isRejected(), true);
|
||||
compare(p1.isFulfilled(), true);
|
||||
compare(errors.length, 1);
|
||||
compare(errors[0] instanceof Error, true);
|
||||
compare(errors[0].message, 'foo');
|
||||
}
|
||||
|
||||
// 2.2.4. onFulfilled or onRejected must not be called until the execution context
|
||||
// stack contains only platform code (ie. executed asynchronously, after the event
|
||||
// loop turn in which then is called, and with a fresh stack).
|
||||
function test_thenAsynchronous()
|
||||
{
|
||||
var value = -1;
|
||||
var p0 = Promise.resolve(42);
|
||||
var p1 = p0.then(function(res){ value = res; });
|
||||
|
||||
compare(p0.isFulfilled(), true);
|
||||
compare(p1.isPending(), true);
|
||||
compare(value, -1);
|
||||
|
||||
p1.wait();
|
||||
|
||||
compare(p1.isFulfilled(), true);
|
||||
compare(value, 42);
|
||||
}
|
||||
|
||||
// 2.2.5 onFulfilled and onRejected must be called as functions (i.e. with no this value).
|
||||
function test_thenThisArg() {
|
||||
var scopes = [];
|
||||
|
||||
Promise.resolve(42).then(function() { scopes.push(this); }).wait();
|
||||
Promise.reject(new Error('foo')).then(null, function() { scopes.push(this); }).wait();
|
||||
|
||||
// Qt doesn't allow to call JS function with undefined "this"
|
||||
// Let's adopt the sloppy mode (this === the global object).
|
||||
var global = (function() { return this; })();
|
||||
compare(scopes, [global, global]);
|
||||
}
|
||||
|
||||
// 2.2.6. then may be called multiple times on the same promise:
|
||||
|
||||
// 2.2.6.1. If/when promise is fulfilled, all respective onFulfilled callbacks
|
||||
// must execute in the order of their originating calls to then:
|
||||
function test_thenMultipleCalls() {
|
||||
var values = [];
|
||||
var p = new Promise(function(resolve) {
|
||||
Qt.callLater(function() {
|
||||
resolve(42);
|
||||
});
|
||||
});
|
||||
|
||||
Promise.all([
|
||||
p.then(function(res) { return res + 1; }),
|
||||
p.then(function(res) { return res + 2; }),
|
||||
p.then(function(res) { return res + 3; })
|
||||
]).then(function(res) {
|
||||
values = res;
|
||||
}).wait();
|
||||
|
||||
compare(values, [43, 44, 45]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void tst_requirements::thenMultipleCalls()
|
||||
{
|
||||
// 2.2.6.2. If/when promise is rejected, all respective onRejected callbacks
|
||||
// must execute in the order of their originating calls to then:
|
||||
{
|
||||
QVector<int> values;
|
||||
QPromise<int> p([](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
|
||||
qtpromise_defer([=]() {
|
||||
reject(8);
|
||||
});
|
||||
});
|
||||
|
||||
qPromiseAll(QVector<QPromise<int> >{
|
||||
p.then(nullptr, [&](int r) { values << r + 1; return r + 1; }),
|
||||
p.then(nullptr, [&](int r) { values << r + 2; return r + 2; }),
|
||||
p.then(nullptr, [&](int r) { values << r + 3; return r + 3; })
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(values, QVector<int>({9, 10, 11}));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_requirements::thenHandlers()
|
||||
{
|
||||
// 2.2.7. then must return a promise: p2 = p1.then(onFulfilled, onRejected);
|
||||
{
|
||||
auto handler = [](){ return 42; };
|
||||
auto p1 = QPromise<int>::resolve(42);
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1.then(handler, nullptr)), QPromise<int> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1.then(nullptr, handler)), QPromise<int> >::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1.then(handler, handler)), QPromise<int> >::value));
|
||||
}
|
||||
|
||||
// 2.2.7.1. If either onFulfilled or onRejected returns a value x, run the
|
||||
// Promise Resolution Procedure [[Resolve]](p2, x) -> See 2.3.
|
||||
|
||||
// 2.2.7.2. If either onFulfilled or onRejected throws an exception e,
|
||||
// p2 must be rejected with e as the reason.
|
||||
{
|
||||
QString reason;
|
||||
auto p1 = QPromise<int>::resolve(42);
|
||||
auto p2 = p1.then([](){ throw QString("foo"); });
|
||||
p2.then(nullptr, [&](const QString& e) { reason = e; }).wait();
|
||||
|
||||
QVERIFY(p1.isFulfilled());
|
||||
QVERIFY(p2.isRejected());
|
||||
QCOMPARE(reason, QString("foo"));
|
||||
}
|
||||
{
|
||||
QString reason;
|
||||
auto p1 = QPromise<int>::reject(QString("foo"));
|
||||
auto p2 = p1.then(nullptr, [](){ throw QString("bar"); return 42; });
|
||||
p2.then(nullptr, [&](const QString& e) { reason = e; return 0; }).wait();
|
||||
|
||||
QVERIFY(p1.isRejected());
|
||||
QVERIFY(p2.isRejected());
|
||||
QCOMPARE(reason, QString("bar"));
|
||||
}
|
||||
|
||||
// 2.2.7.3. If onFulfilled is not a function and promise1 is fulfilled,
|
||||
// p2 must be fulfilled with the same value as promise1
|
||||
{
|
||||
QString value;
|
||||
auto p1 = QPromise<QString>::resolve("42");
|
||||
auto p2 = p1.then(nullptr, [](){ return QString(); });
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<QString> >::value));
|
||||
p2.then([&](const QString& e) { value = e; }).wait();
|
||||
|
||||
QVERIFY(p1.isFulfilled());
|
||||
QVERIFY(p2.isFulfilled());
|
||||
QCOMPARE(value, QString("42"));
|
||||
}
|
||||
}
|
||||
*/
|
Reference in New Issue
Block a user