mirror of
https://github.com/simonbrunel/qtpromise.git
synced 2024-11-25 12:11:28 +08:00
Implement QPromise::tapFail(handler)
This commit is contained in:
parent
d279fb4391
commit
50bae380be
@ -11,6 +11,7 @@
|
|||||||
* [.isPending](qtpromise/qpromise/ispending.md)
|
* [.isPending](qtpromise/qpromise/ispending.md)
|
||||||
* [.isRejected](qtpromise/qpromise/isrejected.md)
|
* [.isRejected](qtpromise/qpromise/isrejected.md)
|
||||||
* [.tap](qtpromise/qpromise/tap.md)
|
* [.tap](qtpromise/qpromise/tap.md)
|
||||||
|
* [.tapFail](qtpromise/qpromise/tapfail.md)
|
||||||
* [.then](qtpromise/qpromise/then.md)
|
* [.then](qtpromise/qpromise/then.md)
|
||||||
* [.timeout](qtpromise/qpromise/timeout.md)
|
* [.timeout](qtpromise/qpromise/timeout.md)
|
||||||
* [.wait](qtpromise/qpromise/wait.md)
|
* [.wait](qtpromise/qpromise/wait.md)
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
* [`QPromise<T>::isPending`](qpromise/ispending.md)
|
* [`QPromise<T>::isPending`](qpromise/ispending.md)
|
||||||
* [`QPromise<T>::isRejected`](qpromise/isrejected.md)
|
* [`QPromise<T>::isRejected`](qpromise/isrejected.md)
|
||||||
* [`QPromise<T>::tap`](qpromise/tap.md)
|
* [`QPromise<T>::tap`](qpromise/tap.md)
|
||||||
|
* [`QPromise<T>::tapFail`](qpromise/tapfail.md)
|
||||||
* [`QPromise<T>::then`](qpromise/then.md)
|
* [`QPromise<T>::then`](qpromise/then.md)
|
||||||
* [`QPromise<T>::timeout`](qpromise/timeout.md)
|
* [`QPromise<T>::timeout`](qpromise/timeout.md)
|
||||||
* [`QPromise<T>::wait`](qpromise/wait.md)
|
* [`QPromise<T>::wait`](qpromise/wait.md)
|
||||||
|
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.
|
@ -59,6 +59,9 @@ public:
|
|||||||
template <typename THandler>
|
template <typename THandler>
|
||||||
inline QPromise<T> tap(THandler handler) const;
|
inline QPromise<T> tap(THandler handler) const;
|
||||||
|
|
||||||
|
template <typename THandler>
|
||||||
|
inline QPromise<T> tapFail(THandler handler) const;
|
||||||
|
|
||||||
template <typename E = QPromiseTimeoutException>
|
template <typename E = QPromiseTimeoutException>
|
||||||
inline QPromise<T> timeout(int msec, E&& error = E()) const;
|
inline QPromise<T> timeout(int msec, E&& error = E()) const;
|
||||||
|
|
||||||
|
@ -158,6 +158,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 T>
|
||||||
template <typename E>
|
template <typename E>
|
||||||
inline QPromise<T> QPromiseBase<T>::timeout(int msec, E&& error) const
|
inline QPromise<T> QPromiseBase<T>::timeout(int msec, E&& error) const
|
||||||
|
@ -8,5 +8,6 @@ SUBDIRS += \
|
|||||||
operators \
|
operators \
|
||||||
resolve \
|
resolve \
|
||||||
tap \
|
tap \
|
||||||
|
tapfail \
|
||||||
then \
|
then \
|
||||||
timeout
|
timeout
|
||||||
|
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}));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user