diff --git a/tests/auto/qpromise/tst_qpromise.cpp b/tests/auto/qpromise/tst_qpromise.cpp index a69629c..2bbf752 100644 --- a/tests/auto/qpromise/tst_qpromise.cpp +++ b/tests/auto/qpromise/tst_qpromise.cpp @@ -12,9 +12,29 @@ class tst_qpromise: public QObject Q_OBJECT private Q_SLOTS: + void resolveSync(); + void resolveSync_void(); + void resolveDelayed(); + void rejectSync(); + void rejectDelayed(); + void rejectThrows(); + + void thenReturns(); + void thenThrows(); + void thenNullPtr(); + void thenSkipResult(); + void thenDelayedResolved(); + void thenDelayedRejected(); + + void failSameType(); + void failBaseClass(); + void failCatchAll(); + void finallyReturns(); + void finallyReturns_void(); void finallyThrows(); - void finallyDelayedFulfilled(); + void finallyThrows_void(); + void finallyDelayedResolved(); void finallyDelayedRejected(); }; // class tst_qpromise @@ -22,39 +42,371 @@ private Q_SLOTS: QTEST_MAIN(tst_qpromise) #include "tst_qpromise.moc" +template +T waitForValue(const QPromise& promise, const T& initial) +{ + T value(initial); + promise.then([&](const T& res) { + value = res; + }).wait(); + return value; +} + +template +T waitForValue(const QPromise& promise, const T& initial, const T& expected) +{ + T value(initial); + promise.then([&]() { + value = expected; + }).wait(); + return value; +} + +template +E waitForError(const QPromise& promise, const E& initial) +{ + E error(initial); + promise.fail([&](const E& err) { + error = err; + return T(); + }).wait(); + return error; +} + +template +E waitForError(const QPromise& promise, const E& initial) +{ + E error(initial); + promise.fail([&](const E& err) { + error = err; + }).wait(); + return error; +} + +void tst_qpromise::resolveSync() +{ + { // resolver(resolve) + QPromise p([](const QPromiseResolve& resolve) { + resolve(42); + }); + + QCOMPARE(p.isFulfilled(), true); + QCOMPARE(waitForError(p, QString()), QString()); + QCOMPARE(waitForValue(p, -1), 42); + } + { // resolver(resolve, reject) + QPromise p([](const QPromiseResolve& resolve, const QPromiseReject&) { + resolve(42); + }); + + QCOMPARE(p.isFulfilled(), true); + QCOMPARE(waitForError(p, QString()), QString()); + QCOMPARE(waitForValue(p, -1), 42); + } +} + +void tst_qpromise::resolveSync_void() +{ + { // resolver(resolve) + QPromise p([](const QPromiseResolve& resolve) { + resolve(); + }); + + QCOMPARE(p.isFulfilled(), true); + QCOMPARE(waitForError(p, QString()), QString()); + QCOMPARE(waitForValue(p, -1, 42), 42); + } + { // resolver(resolve, reject) + QPromise p([](const QPromiseResolve& resolve, const QPromiseReject&) { + resolve(); + }); + + QCOMPARE(p.isFulfilled(), true); + QCOMPARE(waitForError(p, QString()), QString()); + QCOMPARE(waitForValue(p, -1, 42), 42); + } +} + +void tst_qpromise::resolveDelayed() +{ + { // resolver(resolve) + QPromise p([](const QPromiseResolve& resolve) { + QtPromisePrivate::qtpromise_defer([=]() { + resolve(42); + }); + }); + + QCOMPARE(p.isPending(), true); + QCOMPARE(waitForError(p, QString()), QString()); + QCOMPARE(waitForValue(p, -1), 42); + QCOMPARE(p.isFulfilled(), true); + } + { // resolver(resolve, reject) + QPromise p([](const QPromiseResolve& resolve, const QPromiseReject&) { + QtPromisePrivate::qtpromise_defer([=]() { + resolve(42); + }); + }); + + QCOMPARE(p.isPending(), true); + QCOMPARE(waitForError(p, QString()), QString()); + QCOMPARE(waitForValue(p, -1), 42); + QCOMPARE(p.isFulfilled(), true); + } +} + +void tst_qpromise::rejectSync() +{ + QPromise p([](const QPromiseResolve&, const QPromiseReject& reject) { + reject(QString("foo")); + }); + + QCOMPARE(p.isRejected(), true); + QCOMPARE(waitForValue(p, -1), -1); + QCOMPARE(waitForError(p, QString()), QString("foo")); +} + +void tst_qpromise::rejectDelayed() +{ + QPromise p([](const QPromiseResolve&, const QPromiseReject& reject) { + QtPromisePrivate::qtpromise_defer([=]() { + reject(QString("foo")); + }); + }); + + QCOMPARE(p.isPending(), true); + QCOMPARE(waitForValue(p, -1), -1); + QCOMPARE(waitForError(p, QString()), QString("foo")); + QCOMPARE(p.isRejected(), true); +} + +void tst_qpromise::rejectThrows() +{ + { // resolver(resolve) + QPromise p([](const QPromiseResolve&) { + throw QString("foo"); + }); + + QCOMPARE(p.isRejected(), true); + QCOMPARE(waitForValue(p, -1), -1); + QCOMPARE(waitForError(p, QString()), QString("foo")); + } + { // resolver(resolve, reject) + QPromise p([](const QPromiseResolve&, const QPromiseReject&) { + throw QString("foo"); + }); + + QCOMPARE(p.isRejected(), true); + QCOMPARE(waitForValue(p, -1), -1); + QCOMPARE(waitForError(p, QString()), QString("foo")); + } +} + +void tst_qpromise::thenReturns() +{ + auto p = QPromise::resolve(42); + + QVariantList values; + p.then([&](int res) { + values << res; + return QString::number(res+1); + }).then([&](const QString& res) { + values << res; + }).then([&]() { + values << 44; + }).wait(); + + QCOMPARE(values, QVariantList({42, QString("43"), 44})); +} + +void tst_qpromise::thenThrows() +{ + auto input = QPromise::resolve(42); + auto output = input.then([](int res) { + throw QString("foo%1").arg(res); + return 42; + }); + + QString error; + output.then([&](int res) { + error += "bar" + QString::number(res); + }).fail([&](const QString& err) { + error += err; + }).wait(); + + QCOMPARE(input.isFulfilled(), true); + QCOMPARE(output.isRejected(), true); + QCOMPARE(error, QString("foo42")); +} + +void tst_qpromise::thenNullPtr() +{ + { // resolved + auto p = QPromise::resolve(42).then(nullptr); + + QCOMPARE(waitForValue(p, -1), 42); + QCOMPARE(p.isFulfilled(), true); + } + { // rejected + auto p = QPromise::reject(QString("foo")).then(nullptr); + + QCOMPARE(waitForError(p, QString()), QString("foo")); + QCOMPARE(p.isRejected(), true); + } +} + +void tst_qpromise::thenSkipResult() +{ + auto p = QPromise::resolve(42); + + int value = -1; + p.then([&]() { + value = 43; + }).wait(); + + Q_STATIC_ASSERT((std::is_same >::value)); + QCOMPARE(value, 43); +} + +void tst_qpromise::thenDelayedResolved() +{ + auto p = QPromise::resolve(42).then([](int res) { + return QPromise([=](const QPromiseResolve& resolve) { + QtPromisePrivate::qtpromise_defer([=]() { + resolve(QString("foo%1").arg(res)); + }); + }); + }); + + Q_STATIC_ASSERT((std::is_same >::value)); + QCOMPARE(waitForValue(p, QString()), QString("foo42")); +} + +void tst_qpromise::thenDelayedRejected() +{ + auto p = QPromise::resolve(42).then([](int res) { + return QPromise([=](const QPromiseResolve&, const QPromiseReject& reject) { + QtPromisePrivate::qtpromise_defer([=]() { + reject(QString("foo%1").arg(res)); + }); + }); + }); + + Q_STATIC_ASSERT((std::is_same >::value)); + QCOMPARE(waitForError(p, QString()), QString("foo42")); +} + +void tst_qpromise::failSameType() +{ + // http://en.cppreference.com/w/cpp/error/exception + auto p = QPromise::reject(std::out_of_range("foo")); + + QString error; + p.fail([&](const std::domain_error& e) { + error += QString(e.what()) + "0"; + return -1; + }).fail([&](const std::out_of_range& e) { + error += QString(e.what()) + "1"; + return -1; + }).fail([&](const std::exception& e) { + error += QString(e.what()) + "2"; + return -1; + }).wait(); + + QCOMPARE(error, QString("foo1")); +} + +void tst_qpromise::failBaseClass() +{ + // http://en.cppreference.com/w/cpp/error/exception + auto p = QPromise::reject(std::out_of_range("foo")); + + QString error; + p.fail([&](const std::runtime_error& e) { + error += QString(e.what()) + "0"; + return -1; + }).fail([&](const std::logic_error& e) { + error += QString(e.what()) + "1"; + return -1; + }).fail([&](const std::exception& e) { + error += QString(e.what()) + "2"; + return -1; + }).wait(); + + QCOMPARE(error, QString("foo1")); +} + +void tst_qpromise::failCatchAll() +{ + auto p = QPromise::reject(std::out_of_range("foo")); + + QString error; + p.fail([&](const std::runtime_error& e) { + error += QString(e.what()) + "0"; + return -1; + }).fail([&]() { + error += "bar"; + return -1; + }).fail([&](const std::exception& e) { + error += QString(e.what()) + "2"; + return -1; + }).wait(); + + QCOMPARE(error, QString("bar")); +} + void tst_qpromise::finallyReturns() { { // fulfilled - QVector values; - auto next = QPromise::resolve(42).finally([&]() { - values << 8; - return 16; // ignored! - }); - - next.then([&](int r) { - values << r; - }).wait(); - - QVERIFY(next.isFulfilled()); - QCOMPARE(values, QVector({8, 42})); - } - { // rejected - QString error; int value = -1; - auto next = QPromise([](const QPromiseResolve) { - throw QString("foo"); - }).finally([&]() { + auto p = QPromise::resolve(42).finally([&]() { value = 8; return 16; // ignored! }); - next.fail([&](const QString& err) { - error = err; - return 42; - }).wait(); + Q_STATIC_ASSERT((std::is_same >::value)); + QCOMPARE(waitForValue(p, -1), 42); + QCOMPARE(p.isFulfilled(), true); + QCOMPARE(value, 8); + } + { // rejected + int value = -1; + auto p = QPromise::reject(QString("foo")).finally([&]() { + value = 8; + return 16; // ignored! + }); - QVERIFY(next.isRejected()); - QCOMPARE(error, QString("foo")); + Q_STATIC_ASSERT((std::is_same >::value)); + QCOMPARE(waitForError(p, QString()), QString("foo")); + QCOMPARE(p.isRejected(), true); + QCOMPARE(value, 8); + } +} + +void tst_qpromise::finallyReturns_void() +{ + { // fulfilled + int value = -1; + auto p = QPromise::resolve().finally([&]() { + value = 8; + return 16; // ignored! + }); + + Q_STATIC_ASSERT((std::is_same >::value)); + QCOMPARE(waitForValue(p, -1, 42), 42); + QCOMPARE(p.isFulfilled(), true); + QCOMPARE(value, 8); + } + { // rejected + int value = -1; + auto p = QPromise::reject(QString("foo")).finally([&]() { + value = 8; + return 16; // ignored! + }); + + Q_STATIC_ASSERT((std::is_same >::value)); + QCOMPARE(waitForError(p, QString()), QString("foo")); + QCOMPARE(p.isRejected(), true); QCOMPARE(value, 8); } } @@ -62,40 +414,52 @@ void tst_qpromise::finallyReturns() void tst_qpromise::finallyThrows() { { // fulfilled - QString error; - auto next = QPromise::resolve(42).finally([&]() { + auto p = QPromise::resolve(42).finally([&]() { throw QString("bar"); }); - next.fail([&](const QString& err) { - error = err; - return 0; - }).wait(); - - QVERIFY(next.isRejected()); - QCOMPARE(error, QString("bar")); + Q_STATIC_ASSERT((std::is_same >::value)); + QCOMPARE(waitForError(p, QString()), QString("bar")); + QCOMPARE(p.isRejected(), true); } { // rejected - QString error; - auto next = QPromise::reject(QString("foo")).finally([&]() { + auto p = QPromise::reject(QString("foo")).finally([&]() { throw QString("bar"); }); - next.fail([&](const QString& err) { - error = err; - return 0; - }).wait(); - - QVERIFY(next.isRejected()); - QCOMPARE(error, QString("bar")); + Q_STATIC_ASSERT((std::is_same >::value)); + QCOMPARE(waitForError(p, QString()), QString("bar")); + QCOMPARE(p.isRejected(), true); } } -void tst_qpromise::finallyDelayedFulfilled() +void tst_qpromise::finallyThrows_void() +{ + { // fulfilled + auto p = QPromise::resolve().finally([&]() { + throw QString("bar"); + }); + + Q_STATIC_ASSERT((std::is_same >::value)); + QCOMPARE(waitForError(p, QString()), QString("bar")); + QCOMPARE(p.isRejected(), true); + } + { // rejected + auto p = QPromise::reject(QString("foo")).finally([&]() { + throw QString("bar"); + }); + + Q_STATIC_ASSERT((std::is_same >::value)); + QCOMPARE(waitForError(p, QString()), QString("bar")); + QCOMPARE(p.isRejected(), true); + } +} + +void tst_qpromise::finallyDelayedResolved() { { // fulfilled QVector values; - auto next = QPromise::resolve(42).finally([&]() { + auto p = QPromise::resolve(42).finally([&]() { QPromise p([&](const QPromiseResolve& resolve) { qtpromise_defer([=, &values]() { values << 64; @@ -107,17 +471,13 @@ void tst_qpromise::finallyDelayedFulfilled() return p; }); - next.then([&](int r) { - values << r; - }).wait(); - - QVERIFY(next.isFulfilled()); - QCOMPARE(values, QVector({8, 64, 42})); + QCOMPARE(waitForValue(p, -1), 42); + QCOMPARE(p.isFulfilled(), true); + QCOMPARE(values, QVector({8, 64})); } { // rejected - QString error; QVector values; - auto next = QPromise::reject(QString("foo")).finally([&]() { + auto p = QPromise::reject(QString("foo")).finally([&]() { QPromise p([&](const QPromiseResolve& resolve) { qtpromise_defer([=, &values]() { values << 64; @@ -129,14 +489,12 @@ void tst_qpromise::finallyDelayedFulfilled() return p; }); - next.then([&](int r) { + p.then([&](int r) { values << r; - }, [&](const QString& err) { - error = err; }).wait(); - QVERIFY(next.isRejected()); - QCOMPARE(error, QString("foo")); + QCOMPARE(waitForError(p, QString()), QString("foo")); + QCOMPARE(p.isRejected(), true); QCOMPARE(values, QVector({8, 64})); } } @@ -144,8 +502,7 @@ void tst_qpromise::finallyDelayedFulfilled() void tst_qpromise::finallyDelayedRejected() { { // fulfilled - QString error; - auto next = QPromise::resolve(42).finally([]() { + auto p = QPromise::resolve(42).finally([]() { return QPromise([](const QPromiseResolve&, const QPromiseReject& reject) { qtpromise_defer([=]() { reject(QString("bar")); @@ -153,17 +510,11 @@ void tst_qpromise::finallyDelayedRejected() }); }); - next.fail([&](const QString& err) { - error = err; - return 0; - }).wait(); - - QVERIFY(next.isRejected()); - QCOMPARE(error, QString("bar")); + QCOMPARE(waitForError(p, QString()), QString("bar")); + QCOMPARE(p.isRejected(), true); } { // rejected - QString error; - auto next = QPromise::reject(QString("foo")).finally([]() { + auto p = QPromise::reject(QString("foo")).finally([]() { return QPromise([](const QPromiseResolve&, const QPromiseReject& reject) { qtpromise_defer([=]() { reject(QString("bar")); @@ -171,12 +522,7 @@ void tst_qpromise::finallyDelayedRejected() }); }); - next.fail([&](const QString& err) { - error = err; - return 0; - }).wait(); - - QVERIFY(next.isRejected()); - QCOMPARE(error, QString("bar")); + QCOMPARE(waitForError(p, QString()), QString("bar")); + QCOMPARE(p.isRejected(), true); } }