mirror of
https://github.com/simonbrunel/qtpromise.git
synced 2025-07-01 23:11:47 +08:00
Promise creation from callback only (resolver)
Make sure that the promise state can only be changed by the promise producer (and not consumers) by removing the `fulfill` and `reject` methods from the instance members and introducing a new constructor accepting a resolver lambda. That also means that a promise can't anymore be default constructed. Add the static `QPromise<T>::resolve` and `QPromise<T>::reject` methods to create synchronously fulfilled or rejected promises, and fix the `qPromise` helper to handle deduced promises (e.g. `qPromise(QFuture<int>()) -> QPromise<int>`).
This commit is contained in:
@ -5,15 +5,13 @@
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
static const int ASYNC_DELAY = 256;
|
||||
using namespace QtPromisePrivate;
|
||||
|
||||
class tst_qpromise: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void finallyReturns();
|
||||
void finallyThrows();
|
||||
void finallyDelayedFulfilled();
|
||||
@ -26,75 +24,68 @@ QTEST_MAIN(tst_qpromise)
|
||||
|
||||
void tst_qpromise::finallyReturns()
|
||||
{
|
||||
{
|
||||
QPromise<int> p;
|
||||
{ // fulfilled
|
||||
QVector<int> values;
|
||||
auto next = p.finally([&values]() {
|
||||
auto next = QPromise<int>::resolve(42).finally([&]() {
|
||||
values << 8;
|
||||
return 16;
|
||||
return 16; // ignored!
|
||||
});
|
||||
|
||||
p.fulfill(42);
|
||||
next.then([&values](int r) {
|
||||
next.then([&](int r) {
|
||||
values << r;
|
||||
}).wait();
|
||||
|
||||
QVERIFY(p.isFulfilled());
|
||||
QVERIFY(next.isFulfilled());
|
||||
QCOMPARE(values, QVector<int>({8, 42}));
|
||||
}
|
||||
{
|
||||
QPromise<int> p;
|
||||
QVector<int> values;
|
||||
auto next = p.finally([&values]() {
|
||||
values << 8;
|
||||
return 16;
|
||||
{ // rejected
|
||||
QString error;
|
||||
int value = -1;
|
||||
auto next = QPromise<int>([](const QPromiseResolve<int>) {
|
||||
throw QString("foo");
|
||||
}).finally([&]() {
|
||||
value = 8;
|
||||
return 16; // ignored!
|
||||
});
|
||||
|
||||
p.reject(QString("foo"));
|
||||
next.then([&values](int r) {
|
||||
values << r;
|
||||
next.fail([&](const QString& err) {
|
||||
error = err;
|
||||
return 42;
|
||||
}).wait();
|
||||
|
||||
QVERIFY(p.isRejected());
|
||||
QVERIFY(next.isRejected());
|
||||
QCOMPARE(values, QVector<int>({8}));
|
||||
QCOMPARE(error, QString("foo"));
|
||||
QCOMPARE(value, 8);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_qpromise::finallyThrows()
|
||||
{
|
||||
{
|
||||
QPromise<int> p;
|
||||
{ // fulfilled
|
||||
QString error;
|
||||
auto next = p.finally([]() {
|
||||
auto next = QPromise<int>::resolve(42).finally([&]() {
|
||||
throw QString("bar");
|
||||
});
|
||||
|
||||
p.fulfill(42);
|
||||
next.fail([&error](const QString& err) {
|
||||
next.fail([&](const QString& err) {
|
||||
error = err;
|
||||
return 0;
|
||||
}).wait();
|
||||
|
||||
QVERIFY(p.isFulfilled());
|
||||
QVERIFY(next.isRejected());
|
||||
QCOMPARE(error, QString("bar"));
|
||||
}
|
||||
{
|
||||
QPromise<int> p;
|
||||
{ // rejected
|
||||
QString error;
|
||||
auto next = p.finally([]() {
|
||||
auto next = QPromise<int>::reject(QString("foo")).finally([&]() {
|
||||
throw QString("bar");
|
||||
});
|
||||
|
||||
p.reject(QString("foo"));
|
||||
next.fail([&error](const QString& err) {
|
||||
next.fail([&](const QString& err) {
|
||||
error = err;
|
||||
return 0;
|
||||
}).wait();
|
||||
|
||||
QVERIFY(p.isRejected());
|
||||
QVERIFY(next.isRejected());
|
||||
QCOMPARE(error, QString("bar"));
|
||||
}
|
||||
@ -102,97 +93,89 @@ void tst_qpromise::finallyThrows()
|
||||
|
||||
void tst_qpromise::finallyDelayedFulfilled()
|
||||
{
|
||||
{
|
||||
QPromise<int> p0;
|
||||
{ // fulfilled
|
||||
QVector<int> values;
|
||||
auto next = p0.finally([&values]() {
|
||||
QPromise<int> p1;
|
||||
QTimer::singleShot(ASYNC_DELAY, [p1, &values]() mutable {
|
||||
values << 64;
|
||||
p1.fulfill(16);
|
||||
auto next = QPromise<int>::resolve(42).finally([&]() {
|
||||
QPromise<int> p([&](const QPromiseResolve<int>& resolve) {
|
||||
qtpromise_defer([=, &values]() {
|
||||
values << 64;
|
||||
resolve(16); // ignored!
|
||||
});
|
||||
});
|
||||
|
||||
values << 8;
|
||||
return p1;
|
||||
return p;
|
||||
});
|
||||
|
||||
p0.fulfill(42);
|
||||
next.then([&values](int r) {
|
||||
next.then([&](int r) {
|
||||
values << r;
|
||||
}).wait();
|
||||
|
||||
QVERIFY(p0.isFulfilled());
|
||||
QVERIFY(next.isFulfilled());
|
||||
QCOMPARE(values, QVector<int>({8, 64, 42}));
|
||||
}
|
||||
{
|
||||
QPromise<int> p0;
|
||||
{ // rejected
|
||||
QString error;
|
||||
QVector<int> values;
|
||||
auto next = p0.finally([&values]() {
|
||||
QPromise<int> p1;
|
||||
QTimer::singleShot(ASYNC_DELAY, [p1, &values]() mutable {
|
||||
values << 64;
|
||||
p1.fulfill(16);
|
||||
auto next = QPromise<int>::reject(QString("foo")).finally([&]() {
|
||||
QPromise<int> p([&](const QPromiseResolve<int>& resolve) {
|
||||
qtpromise_defer([=, &values]() {
|
||||
values << 64;
|
||||
resolve(16); // ignored!
|
||||
});
|
||||
});
|
||||
|
||||
values << 8;
|
||||
return p1;
|
||||
return p;
|
||||
});
|
||||
|
||||
p0.reject(QString("foo"));
|
||||
next.then([&values](int r) {
|
||||
next.then([&](int r) {
|
||||
values << r;
|
||||
}, [&](const QString& err) {
|
||||
error = err;
|
||||
}).wait();
|
||||
|
||||
QVERIFY(p0.isRejected());
|
||||
QVERIFY(next.isRejected());
|
||||
QCOMPARE(error, QString("foo"));
|
||||
QCOMPARE(values, QVector<int>({8, 64}));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_qpromise::finallyDelayedRejected()
|
||||
{
|
||||
{
|
||||
QPromise<int> p0;
|
||||
{ // fulfilled
|
||||
QString error;
|
||||
auto next = p0.finally([]() {
|
||||
QPromise<int> p1;
|
||||
QTimer::singleShot(ASYNC_DELAY, [p1]() mutable {
|
||||
p1.reject(QString("bar"));
|
||||
auto next = QPromise<int>::resolve(42).finally([]() {
|
||||
return QPromise<int>([](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
|
||||
qtpromise_defer([=]() {
|
||||
reject(QString("bar"));
|
||||
});
|
||||
});
|
||||
|
||||
return p1;
|
||||
});
|
||||
|
||||
p0.fulfill(42);
|
||||
next.fail([&error](const QString& err) {
|
||||
next.fail([&](const QString& err) {
|
||||
error = err;
|
||||
return 0;
|
||||
}).wait();
|
||||
|
||||
QVERIFY(p0.isFulfilled());
|
||||
QVERIFY(next.isRejected());
|
||||
QCOMPARE(error, QString("bar"));
|
||||
}
|
||||
{
|
||||
QPromise<int> p0;
|
||||
{ // rejected
|
||||
QString error;
|
||||
auto next = p0.finally([]() {
|
||||
QPromise<int> p1;
|
||||
QTimer::singleShot(ASYNC_DELAY, [p1]() mutable {
|
||||
p1.reject(QString("bar"));
|
||||
auto next = QPromise<int>::reject(QString("foo")).finally([]() {
|
||||
return QPromise<int>([](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
|
||||
qtpromise_defer([=]() {
|
||||
reject(QString("bar"));
|
||||
});
|
||||
});
|
||||
|
||||
return p1;
|
||||
});
|
||||
|
||||
p0.reject(QString("foo"));
|
||||
next.fail([&error](const QString& err) {
|
||||
next.fail([&](const QString& err) {
|
||||
error = err;
|
||||
return 0;
|
||||
}).wait();
|
||||
|
||||
QVERIFY(p0.isRejected());
|
||||
QVERIFY(next.isRejected());
|
||||
QCOMPARE(error, QString("bar"));
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
using namespace QtPromisePrivate;
|
||||
|
||||
// https://promisesaplus.com/#requirements
|
||||
class tst_requirements: public QObject
|
||||
@ -37,115 +38,151 @@ QTEST_MAIN(tst_requirements)
|
||||
void tst_requirements::statePending()
|
||||
{
|
||||
// 2.1.1. When pending, a promise:
|
||||
// 2.1.1.1. may transition to either the fulfilled state
|
||||
{
|
||||
QPromise<> p;
|
||||
QPromise<int> p([&](const QPromiseResolve<int>& resolve) {
|
||||
qtpromise_defer([=]() { resolve(42); });
|
||||
});
|
||||
|
||||
QVERIFY(p.isPending());
|
||||
QVERIFY(!p.isFulfilled());
|
||||
QVERIFY(!p.isRejected());
|
||||
}
|
||||
|
||||
// 2.1.1.1. may transition to either the fulfilled state
|
||||
{
|
||||
QPromise<> p;
|
||||
p.fulfill();
|
||||
p.wait();
|
||||
|
||||
QVERIFY(!p.isPending());
|
||||
QVERIFY(p.isFulfilled());
|
||||
QVERIFY(!p.isRejected());
|
||||
}
|
||||
|
||||
// 2.1.1.1. ... or the rejected state
|
||||
{
|
||||
QPromise<> p;
|
||||
p.reject("foo");
|
||||
{
|
||||
QPromise<int> p([&](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
|
||||
qtpromise_defer([=]() { reject(QString("foo")); });
|
||||
});
|
||||
|
||||
QVERIFY(p.isPending());
|
||||
QVERIFY(!p.isFulfilled());
|
||||
QVERIFY(!p.isRejected());
|
||||
|
||||
p.wait();
|
||||
|
||||
QVERIFY(!p.isPending());
|
||||
QVERIFY(!p.isFulfilled());
|
||||
QVERIFY(p.isRejected());
|
||||
}
|
||||
}
|
||||
|
||||
void tst_requirements::stateFulfilled()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto log_value = [&values](int res) { values << res; };
|
||||
|
||||
QPromise<int> p;
|
||||
QVERIFY(p.isPending());
|
||||
QString error;
|
||||
int value = -1;
|
||||
|
||||
// 2.1.2. When fulfilled, a promise:
|
||||
p.fulfill(42).then(log_value).wait();
|
||||
QPromise<int> p([](
|
||||
const QPromiseResolve<int>& resolve,
|
||||
const QPromiseReject<int>& reject) {
|
||||
qtpromise_defer([=]() {
|
||||
// 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(QString("foo"));
|
||||
});
|
||||
});
|
||||
|
||||
QVERIFY(p.isPending());
|
||||
|
||||
p.then([&](int res) {
|
||||
value = res;
|
||||
}, [&](const QString& err) {
|
||||
error = err;
|
||||
}).wait();
|
||||
|
||||
QVERIFY(p.isFulfilled());
|
||||
QVERIFY(!p.isRejected());
|
||||
|
||||
// 2.1.2.1. must not transition to any other state.
|
||||
p.reject("foo").then(log_value).wait();
|
||||
QVERIFY(p.isFulfilled());
|
||||
QVERIFY(!p.isRejected());
|
||||
|
||||
// 2.1.2.2. must have a value, which must not change.
|
||||
p.fulfill(51).then(log_value).wait();
|
||||
QVERIFY(p.isFulfilled());
|
||||
QVERIFY(!p.isRejected());
|
||||
|
||||
QCOMPARE(values, QVector<int>({42, 42, 42}));
|
||||
QVERIFY(error.isEmpty());
|
||||
QCOMPARE(value, 42);
|
||||
}
|
||||
|
||||
void tst_requirements::stateRejected()
|
||||
{
|
||||
QStringList errors;
|
||||
auto log_error = [&errors](const QString& err) { errors << err; return -1; };
|
||||
|
||||
QPromise<int> p;
|
||||
QVERIFY(p.isPending());
|
||||
QString error;
|
||||
int value = -1;
|
||||
|
||||
// 2.1.3 When rejected, a promise:
|
||||
p.reject(QString("foo")).then(nullptr, log_error).wait();
|
||||
QPromise<int> p([](
|
||||
const QPromiseResolve<int>& resolve,
|
||||
const QPromiseReject<int>& reject) {
|
||||
qtpromise_defer([=]() {
|
||||
// 2.1.3.2. must have a reason, which must not change.
|
||||
reject(QString("foo"));
|
||||
reject(QString("bar"));
|
||||
|
||||
// 2.1.3.1. must not transition to any other state.
|
||||
resolve(42);
|
||||
});
|
||||
});
|
||||
|
||||
QVERIFY(p.isPending());
|
||||
|
||||
p.then([&](int res) {
|
||||
value = res;
|
||||
}, [&](const QString& err) {
|
||||
error = err;
|
||||
}).wait();
|
||||
|
||||
QVERIFY(!p.isFulfilled());
|
||||
QVERIFY(p.isRejected());
|
||||
|
||||
// 2.1.3.1. must not transition to any other state.
|
||||
p.fulfill(51).then(nullptr, log_error).wait();
|
||||
QVERIFY(!p.isFulfilled());
|
||||
QVERIFY(p.isRejected());
|
||||
|
||||
// 2.1.3.2. must have a reason, which must not change.
|
||||
p.reject(QString("bar")).then(nullptr, log_error).wait();
|
||||
QVERIFY(!p.isFulfilled());
|
||||
QVERIFY(p.isRejected());
|
||||
|
||||
QCOMPARE(errors, QStringList({"foo", "foo", "foo"}));
|
||||
QCOMPARE(error, QString("foo"));
|
||||
QCOMPARE(value, -1);
|
||||
}
|
||||
|
||||
void tst_requirements::thenArguments()
|
||||
{
|
||||
// Both onFulfilled and onRejected are given
|
||||
// 2.2.1. Both onFulfilled and onRejected are given
|
||||
{
|
||||
int value = 0;
|
||||
QPromise<int> p;
|
||||
p.fulfill(42).then([&value](int res) { value = res; }, [](const QString&){}).wait();
|
||||
QVERIFY(p.isFulfilled());
|
||||
QString error;
|
||||
int value = -1;
|
||||
QPromise<int>::resolve(42).then(
|
||||
[&](int res) { value = res; },
|
||||
[&](const QString& err) { error = err; }
|
||||
).wait();
|
||||
|
||||
QVERIFY(error.isEmpty());
|
||||
QCOMPARE(value, 42);
|
||||
}
|
||||
{
|
||||
QString error;
|
||||
QPromise<int> p;
|
||||
p.reject(QString("foo")).then([](int) {}, [&error](const QString& err){ error = err; }).wait();
|
||||
QVERIFY(p.isRejected());
|
||||
int value = -1;
|
||||
QPromise<int>::reject(QString("foo")).then(
|
||||
[&](int res) { value = res; },
|
||||
[&](const QString& err){ error = err; }
|
||||
).wait();
|
||||
|
||||
QCOMPARE(error, QString("foo"));
|
||||
QCOMPARE(value, -1);
|
||||
}
|
||||
|
||||
// 2.2.1. onFulfilled is an optional arguments:
|
||||
{
|
||||
QString error;
|
||||
QPromise<int> p;
|
||||
p.reject(QString("foo")).then(nullptr, [&error](const QString& err){ error = err; return 42; }).wait();
|
||||
QVERIFY(p.isRejected());
|
||||
QPromise<int>::reject(QString("foo")).then(
|
||||
nullptr,
|
||||
[&](const QString& err){ error = err; return 42; }
|
||||
).wait();
|
||||
|
||||
QCOMPARE(error, QString("foo"));
|
||||
}
|
||||
|
||||
// 2.2.1. onRejected is an optional arguments:
|
||||
{
|
||||
int value = 0;
|
||||
QPromise<int> p;
|
||||
p.fulfill(42).then([&value](int res) { value = res; }).wait();
|
||||
QVERIFY(p.isFulfilled());
|
||||
int value = -1;
|
||||
QPromise<int>::resolve(42).then(
|
||||
[&value](int res) { value = res; }
|
||||
).wait();
|
||||
|
||||
QCOMPARE(value, 42);
|
||||
}
|
||||
|
||||
@ -157,55 +194,57 @@ void tst_requirements::thenArguments()
|
||||
void tst_requirements::thenOnFulfilled()
|
||||
{
|
||||
// 2.2.2. If onFulfilled is a function:
|
||||
|
||||
QPromise<int> p0;
|
||||
QVector<int> values;
|
||||
auto p1 = p0.then([&values](int res) { values << res; }); // @TODO .wait(10)
|
||||
QPromise<int> p0([](const QPromiseResolve<int>& resolve) {
|
||||
qtpromise_defer([=]() {
|
||||
// 2.2.2.3. it must not be called more than once
|
||||
resolve(42);
|
||||
resolve(43);
|
||||
});
|
||||
});
|
||||
|
||||
auto p1 = p0.then([&](int res) { values << res; });
|
||||
|
||||
// 2.2.2.2. it must not be called before promise is fulfilled.
|
||||
QVERIFY(p0.isPending());
|
||||
QVERIFY(p1.isPending());
|
||||
QVERIFY(values.isEmpty());
|
||||
|
||||
p1.wait();
|
||||
|
||||
// 2.2.2.1. it must be called after promise is fulfilled,
|
||||
// with promise’s value as its first argument.
|
||||
p0.fulfill(42);
|
||||
p1.wait();
|
||||
QVERIFY(p0.isFulfilled());
|
||||
QVERIFY(p1.isFulfilled());
|
||||
QCOMPARE(values, QVector<int>({42}));
|
||||
|
||||
// 2.2.2.3. it must not be called more than once
|
||||
p0.fulfill(12);
|
||||
p1.wait();
|
||||
QCOMPARE(values, QVector<int>({42}));
|
||||
}
|
||||
|
||||
void tst_requirements::thenOnRejected()
|
||||
{
|
||||
// 2.2.3. If onRejected is a function:
|
||||
|
||||
QPromise<> p0;
|
||||
QStringList errors;
|
||||
auto p1 = p0.then(nullptr, [&errors](const QString& err) { errors << err; }); // @TODO .wait(10)
|
||||
QPromise<void> p0([](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) {
|
||||
qtpromise_defer([=]() {
|
||||
// 2.2.3.3. it must not be called more than once.
|
||||
reject(QString("foo"));
|
||||
reject(QString("bar"));
|
||||
});
|
||||
});
|
||||
|
||||
auto p1 = p0.then(nullptr, [&](const QString& err) { errors << err; });
|
||||
|
||||
// 2.2.3.2. it must not be called before promise is rejected.
|
||||
QVERIFY(p0.isPending());
|
||||
QVERIFY(p1.isPending());
|
||||
QVERIFY(errors.isEmpty());
|
||||
|
||||
p1.wait();
|
||||
|
||||
// 2.2.3.1. it must be called after promise is rejected,
|
||||
// with promise’s reason as its first argument.
|
||||
p0.reject(QString("foo"));
|
||||
p1.wait();
|
||||
QVERIFY(p0.isRejected());
|
||||
QVERIFY(p1.isFulfilled());
|
||||
QCOMPARE(errors, QStringList({"foo"}));
|
||||
|
||||
// 2.2.2.3. it must not be called more than once.
|
||||
p0.reject(12);
|
||||
p1.wait();
|
||||
QCOMPARE(errors, QStringList({"foo"}));
|
||||
}
|
||||
|
||||
void tst_requirements::thenAsynchronous()
|
||||
@ -214,14 +253,13 @@ void tst_requirements::thenAsynchronous()
|
||||
// stack contains only platform code (ie. executed asynchronously, after the event
|
||||
// loop turn in which then is called, and with a fresh stack).
|
||||
|
||||
int value = 0;
|
||||
QPromise<int> p0;
|
||||
p0.fulfill(42);
|
||||
int value = -1;
|
||||
auto p0 = QPromise<int>::resolve(42);
|
||||
QVERIFY(p0.isFulfilled());
|
||||
|
||||
auto p1 = p0.then([&value](int res){ value = res; });
|
||||
auto p1 = p0.then([&](int res){ value = res; });
|
||||
QVERIFY(p1.isPending());
|
||||
QCOMPARE(value, 0);
|
||||
QCOMPARE(value, -1);
|
||||
|
||||
p1.wait();
|
||||
QVERIFY(p1.isFulfilled());
|
||||
@ -235,32 +273,38 @@ void tst_requirements::thenMultipleCalls()
|
||||
// 2.2.6.1. If/when promise is fulfilled, all respective onFulfilled callbacks
|
||||
// must execute in the order of their originating calls to then:
|
||||
{
|
||||
QPromise<int> p;
|
||||
QVector<int> values;
|
||||
auto all = qPromiseAll(QVector<QPromise<void> >{
|
||||
p.then([&values](int r) { values << r + 1; }),
|
||||
p.then([&values](int r) { values << r + 2; }),
|
||||
p.then([&values](int r) { values << r + 3; })
|
||||
QPromise<int> p([](const QPromiseResolve<int>& resolve) {
|
||||
qtpromise_defer([=]() {
|
||||
resolve(42);
|
||||
});
|
||||
});
|
||||
|
||||
p.fulfill(42);
|
||||
all.wait();
|
||||
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; })
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(values, QVector<int>({43, 44, 45}));
|
||||
}
|
||||
|
||||
// 2.2.6.2. If/when promise is rejected, all respective onRejected callbacks
|
||||
// must execute in the order of their originating calls to then:
|
||||
{
|
||||
QPromise<int> p;
|
||||
QVector<int> values;
|
||||
auto all = qPromiseAll(QVector<QPromise<int> >{
|
||||
p.then(nullptr, [&values](int r) { values << r + 1; return r + 1; }),
|
||||
p.then(nullptr, [&values](int r) { values << r + 2; return r + 2; }),
|
||||
p.then(nullptr, [&values](int r) { values << r + 3; return r + 3; })
|
||||
QPromise<int> p([](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
|
||||
qtpromise_defer([=]() {
|
||||
reject(8);
|
||||
});
|
||||
});
|
||||
|
||||
p.reject(8);
|
||||
all.wait();
|
||||
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}));
|
||||
}
|
||||
}
|
||||
@ -269,8 +313,8 @@ void tst_requirements::thenHandlers()
|
||||
{
|
||||
// 2.2.7. then must return a promise: p2 = p1.then(onFulfilled, onRejected);
|
||||
{
|
||||
QPromise<int> p1;
|
||||
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));
|
||||
@ -283,19 +327,21 @@ void tst_requirements::thenHandlers()
|
||||
// p2 must be rejected with e as the reason.
|
||||
{
|
||||
QString reason;
|
||||
QPromise<int> p1;
|
||||
auto p2 = p1.fulfill(42).then([](){ throw QString("foo"); });
|
||||
p2.then(nullptr, [&reason](const QString& e) { reason = e; }).wait();
|
||||
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;
|
||||
QPromise<int> p1;
|
||||
auto p2 = p1.reject(QString("foo")).then(nullptr, [](){ throw QString("bar"); return 42; });
|
||||
p2.then(nullptr, [&reason](const QString& e) { reason = e; return 0; }).wait();
|
||||
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"));
|
||||
}
|
||||
@ -304,11 +350,12 @@ void tst_requirements::thenHandlers()
|
||||
// p2 must be fulfilled with the same value as promise1
|
||||
{
|
||||
QString value;
|
||||
QPromise<QString> p1;
|
||||
auto p2 = p1.fulfill("42").then(nullptr, [](){ return QString(); });
|
||||
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([&value](const QString& e) { value = e; }).wait();
|
||||
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