diff --git a/README.md b/README.md
index 935e4c9..b3cbda7 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# QtPromise
-[![qpm](https://img.shields.io/github/release/simonbrunel/qtpromise.svg?style=flat-square&label=qpm&colorB=4CAF50)](http://www.qpm.io/packages/com.github.simonbrunel.qtpromise/index.html) [![Travis](https://img.shields.io/travis/simonbrunel/qtpromise.svg?style=flat-square)](https://travis-ci.org/simonbrunel/qtpromise) [![coverage](https://img.shields.io/codecov/c/github/simonbrunel/qtpromise.svg?style=flat-square)](https://codecov.io/gh/simonbrunel/qtpromise)
+[![qpm](https://img.shields.io/github/release/simonbrunel/qtpromise.svg?style=flat-square&label=qpm&colorB=4CAF50)](http://www.qpm.io/packages/com.github.simonbrunel.qtpromise/index.html) [![Travis](https://img.shields.io/travis/simonbrunel/qtpromise/master.svg?style=flat-square)](https://travis-ci.org/simonbrunel/qtpromise) [![coverage](https://img.shields.io/codecov/c/github/simonbrunel/qtpromise.svg?style=flat-square)](https://codecov.io/gh/simonbrunel/qtpromise)
[Promises/A+](https://promisesaplus.com/) implementation for [Qt/C++](https://www.qt.io/).
diff --git a/tests/auto/qtpromise/qpromise/construct/construct.pro b/tests/auto/qtpromise/qpromise/construct/construct.pro
new file mode 100644
index 0000000..83b8095
--- /dev/null
+++ b/tests/auto/qtpromise/qpromise/construct/construct.pro
@@ -0,0 +1,4 @@
+TARGET = tst_qpromise_construct
+SOURCES += $$PWD/tst_construct.cpp
+
+include(../../qtpromise.pri)
diff --git a/tests/auto/qtpromise/qpromise/construct/tst_construct.cpp b/tests/auto/qtpromise/qpromise/construct/tst_construct.cpp
new file mode 100644
index 0000000..c4ffc80
--- /dev/null
+++ b/tests/auto/qtpromise/qpromise/construct/tst_construct.cpp
@@ -0,0 +1,230 @@
+// Tests
+#include "../../shared/utils.h"
+
+// QtPromise
+#include
+
+// Qt
+#include
+
+using namespace QtPromise;
+
+class tst_qpromise_construct : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void resolveSyncOneArg();
+ void resolveSyncOneArg_void();
+ void resolveSyncTwoArgs();
+ void resolveSyncTwoArgs_void();
+ void resolveAsyncOneArg();
+ void resolveAsyncOneArg_void();
+ void resolveAsyncTwoArgs();
+ void resolveAsyncTwoArgs_void();
+ void rejectThrowOneArg();
+ void rejectThrowOneArg_void();
+ void rejectThrowTwoArgs();
+ void rejectThrowTwoArgs_void();
+ void rejectSync();
+ void rejectSync_void();
+ void rejectAsync();
+ void rejectAsync_void();
+};
+
+QTEST_MAIN(tst_qpromise_construct)
+#include "tst_construct.moc"
+
+void tst_qpromise_construct::resolveSyncOneArg()
+{
+ QPromise p([](const QPromiseResolve& resolve) {
+ resolve(42);
+ });
+
+ QCOMPARE(p.isFulfilled(), true);
+ QCOMPARE(waitForError(p, QString()), QString());
+ QCOMPARE(waitForValue(p, -1), 42);
+}
+
+void tst_qpromise_construct::resolveSyncOneArg_void()
+{
+ QPromise p([](const QPromiseResolve& resolve) {
+ resolve();
+ });
+
+ QCOMPARE(p.isFulfilled(), true);
+ QCOMPARE(waitForError(p, QString()), QString());
+ QCOMPARE(waitForValue(p, -1, 42), 42);
+}
+
+void tst_qpromise_construct::resolveSyncTwoArgs()
+{
+ 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_construct::resolveSyncTwoArgs_void()
+{
+ 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_construct::resolveAsyncOneArg()
+{
+ 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);
+}
+
+void tst_qpromise_construct::resolveAsyncOneArg_void()
+{
+ QPromise p([](const QPromiseResolve& resolve) {
+ QtPromisePrivate::qtpromise_defer([=]() {
+ resolve();
+ });
+ });
+
+ QCOMPARE(p.isPending(), true);
+ QCOMPARE(waitForError(p, QString()), QString());
+ QCOMPARE(waitForValue(p, -1, 42), 42);
+ QCOMPARE(p.isFulfilled(), true);
+}
+
+void tst_qpromise_construct::resolveAsyncTwoArgs()
+{
+ 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_construct::resolveAsyncTwoArgs_void()
+{
+ QPromise p([](const QPromiseResolve& resolve, const QPromiseReject&) {
+ QtPromisePrivate::qtpromise_defer([=]() {
+ resolve();
+ });
+ });
+
+ QCOMPARE(p.isPending(), true);
+ QCOMPARE(waitForError(p, QString()), QString());
+ QCOMPARE(waitForValue(p, -1, 42), 42);
+ QCOMPARE(p.isFulfilled(), true);
+}
+
+void tst_qpromise_construct::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_construct::rejectSync_void()
+{
+ QPromise p([](const QPromiseResolve&, const QPromiseReject& reject) {
+ reject(QString("foo"));
+ });
+
+ QCOMPARE(p.isRejected(), true);
+ QCOMPARE(waitForValue(p, -1, 42), -1);
+ QCOMPARE(waitForError(p, QString()), QString("foo"));
+}
+
+void tst_qpromise_construct::rejectAsync()
+{
+ 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_construct::rejectAsync_void()
+{
+ QPromise p([](const QPromiseResolve&, const QPromiseReject& reject) {
+ QtPromisePrivate::qtpromise_defer([=]() {
+ reject(QString("foo"));
+ });
+ });
+
+ QCOMPARE(p.isPending(), true);
+ QCOMPARE(waitForValue(p, -1, 42), -1);
+ QCOMPARE(waitForError(p, QString()), QString("foo"));
+ QCOMPARE(p.isRejected(), true);
+}
+
+void tst_qpromise_construct::rejectThrowOneArg()
+{
+ QPromise p([](const QPromiseResolve&) {
+ throw QString("foo");
+ });
+
+ QCOMPARE(p.isRejected(), true);
+ QCOMPARE(waitForValue(p, -1), -1);
+ QCOMPARE(waitForError(p, QString()), QString("foo"));
+}
+
+void tst_qpromise_construct::rejectThrowOneArg_void()
+{
+ QPromise p([](const QPromiseResolve&) {
+ throw QString("foo");
+ });
+
+ QCOMPARE(p.isRejected(), true);
+ QCOMPARE(waitForValue(p, -1, 42), -1);
+ QCOMPARE(waitForError(p, QString()), QString("foo"));
+}
+
+void tst_qpromise_construct::rejectThrowTwoArgs()
+{
+ 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_construct::rejectThrowTwoArgs_void()
+{
+ QPromise p([](const QPromiseResolve&, const QPromiseReject&) {
+ throw QString("foo");
+ });
+
+ QCOMPARE(p.isRejected(), true);
+ QCOMPARE(waitForValue(p, -1, 42), -1);
+ QCOMPARE(waitForError(p, QString()), QString("foo"));
+}
diff --git a/tests/auto/qtpromise/qpromise/delay/delay.pro b/tests/auto/qtpromise/qpromise/delay/delay.pro
new file mode 100644
index 0000000..bc905c8
--- /dev/null
+++ b/tests/auto/qtpromise/qpromise/delay/delay.pro
@@ -0,0 +1,4 @@
+TARGET = tst_qpromise_delay
+SOURCES += $$PWD/tst_delay.cpp
+
+include(../../qtpromise.pri)
diff --git a/tests/auto/qtpromise/qpromise/delay/tst_delay.cpp b/tests/auto/qtpromise/qpromise/delay/tst_delay.cpp
new file mode 100644
index 0000000..5a35aec
--- /dev/null
+++ b/tests/auto/qtpromise/qpromise/delay/tst_delay.cpp
@@ -0,0 +1,55 @@
+// Tests
+#include "../../shared/utils.h"
+
+// QtPromise
+#include
+
+// Qt
+#include
+
+using namespace QtPromise;
+
+class tst_qpromise_delay : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void fulfilled();
+ void rejected();
+};
+
+QTEST_MAIN(tst_qpromise_delay)
+#include "tst_delay.moc"
+
+void tst_qpromise_delay::fulfilled()
+{
+ QElapsedTimer timer;
+ qint64 elapsed = -1;
+
+ timer.start();
+
+ auto p = QPromise::resolve(42).delay(1000).finally([&]() {
+ elapsed = timer.elapsed();
+ });
+
+ QCOMPARE(waitForValue(p, -1), 42);
+ QCOMPARE(p.isFulfilled(), true);
+ QVERIFY(elapsed >= 1000 * 0.95); // Qt::CoarseTimer (default) Coarse timers try to
+ QVERIFY(elapsed <= 1000 * 1.05); // keep accuracy within 5% of the desired interval.
+}
+
+void tst_qpromise_delay::rejected()
+{
+ QElapsedTimer timer;
+ qint64 elapsed = -1;
+
+ timer.start();
+
+ auto p = QPromise::reject(QString("foo")).delay(1000).finally([&]() {
+ elapsed = timer.elapsed();
+ });
+
+ QCOMPARE(waitForError(p, QString()), QString("foo"));
+ QCOMPARE(p.isRejected(), true);
+ QVERIFY(elapsed < 5);
+}
diff --git a/tests/auto/qtpromise/qpromise/fail/fail.pro b/tests/auto/qtpromise/qpromise/fail/fail.pro
new file mode 100644
index 0000000..db8fea3
--- /dev/null
+++ b/tests/auto/qtpromise/qpromise/fail/fail.pro
@@ -0,0 +1,4 @@
+TARGET = tst_qpromise_fail
+SOURCES += $$PWD/tst_fail.cpp
+
+include(../../qtpromise.pri)
diff --git a/tests/auto/qtpromise/qpromise/fail/tst_fail.cpp b/tests/auto/qtpromise/qpromise/fail/tst_fail.cpp
new file mode 100644
index 0000000..3477c2c
--- /dev/null
+++ b/tests/auto/qtpromise/qpromise/fail/tst_fail.cpp
@@ -0,0 +1,83 @@
+// Tests
+#include "../../shared/utils.h"
+
+// QtPromise
+#include
+
+// Qt
+#include
+
+using namespace QtPromise;
+
+class tst_qpromise_fail : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void sameType();
+ void baseClass();
+ void catchAll();
+ // TODO: sync / async
+};
+
+QTEST_MAIN(tst_qpromise_fail)
+#include "tst_fail.moc"
+
+void tst_qpromise_fail::sameType()
+{
+ // 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_fail::baseClass()
+{
+ // 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_fail::catchAll()
+{
+ 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"));
+}
diff --git a/tests/auto/qtpromise/qpromise/finally/finally.pro b/tests/auto/qtpromise/qpromise/finally/finally.pro
new file mode 100644
index 0000000..6cd4893
--- /dev/null
+++ b/tests/auto/qtpromise/qpromise/finally/finally.pro
@@ -0,0 +1,4 @@
+TARGET = tst_qpromise_finally
+SOURCES += $$PWD/tst_finally.cpp
+
+include(../../qtpromise.pri)
diff --git a/tests/auto/qtpromise/qpromise/finally/tst_finally.cpp b/tests/auto/qtpromise/qpromise/finally/tst_finally.cpp
new file mode 100644
index 0000000..024a509
--- /dev/null
+++ b/tests/auto/qtpromise/qpromise/finally/tst_finally.cpp
@@ -0,0 +1,204 @@
+// Tests
+#include "../../shared/utils.h"
+
+// QtPromise
+#include
+
+// Qt
+#include
+
+using namespace QtPromise;
+
+class tst_qpromise_finally : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void fulfilledSync();
+ void fulfilledSync_void();
+ void fulfilledThrows();
+ void fulfilledThrows_void();
+ void fulfilledAsyncResolve();
+ void fulfilledAsyncReject();
+ void rejectedSync();
+ void rejectedSync_void();
+ void rejectedThrows();
+ void rejectedThrows_void();
+ void rejectedAsyncResolve();
+ void rejectedAsyncReject();
+};
+
+QTEST_MAIN(tst_qpromise_finally)
+#include "tst_finally.moc"
+
+void tst_qpromise_finally::fulfilledSync()
+{
+ int value = -1;
+ auto p = QPromise::resolve(42).finally([&]() {
+ value = 8;
+ return 16; // ignored!
+ });
+
+ Q_STATIC_ASSERT((std::is_same >::value));
+ QCOMPARE(waitForValue(p, -1), 42);
+ QCOMPARE(p.isFulfilled(), true);
+ QCOMPARE(value, 8);
+}
+
+void tst_qpromise_finally::fulfilledSync_void()
+{
+ 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);
+}
+
+void tst_qpromise_finally::fulfilledThrows()
+{
+ auto p = QPromise::resolve(42).finally([&]() {
+ throw QString("bar");
+ });
+
+ Q_STATIC_ASSERT((std::is_same >::value));
+ QCOMPARE(waitForError(p, QString()), QString("bar"));
+ QCOMPARE(p.isRejected(), true);
+}
+
+void tst_qpromise_finally::fulfilledThrows_void()
+{
+ 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);
+}
+
+void tst_qpromise_finally::fulfilledAsyncResolve()
+{
+ QVector values;
+ auto p = QPromise::resolve(42).finally([&]() {
+ QPromise p([&](const QPromiseResolve& resolve) {
+ QtPromisePrivate::qtpromise_defer([=, &values]() {
+ values << 64;
+ resolve(16); // ignored!
+ });
+ });
+
+ values << 8;
+ return p;
+ });
+
+ QCOMPARE(waitForValue(p, -1), 42);
+ QCOMPARE(p.isFulfilled(), true);
+ QCOMPARE(values, QVector({8, 64}));
+}
+
+void tst_qpromise_finally::fulfilledAsyncReject()
+{
+ auto p = QPromise::resolve(42).finally([]() {
+ return QPromise([](const QPromiseResolve&, const QPromiseReject& reject) {
+ QtPromisePrivate::qtpromise_defer([=]() {
+ reject(QString("bar"));
+ });
+ });
+ });
+
+ QCOMPARE(waitForError(p, QString()), QString("bar"));
+ QCOMPARE(p.isRejected(), true);
+}
+
+void tst_qpromise_finally::rejectedSync()
+{
+ 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);
+}
+
+void tst_qpromise_finally::rejectedSync_void()
+{
+ 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);
+}
+
+void tst_qpromise_finally::rejectedThrows()
+{
+ 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_finally::rejectedThrows_void()
+{
+ 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_finally::rejectedAsyncResolve()
+{
+ QVector values;
+ auto p = QPromise::reject(QString("foo")).finally([&]() {
+ QPromise p([&](const QPromiseResolve& resolve) {
+ QtPromisePrivate::qtpromise_defer([=, &values]() {
+ values << 64;
+ resolve(16); // ignored!
+ });
+ });
+
+ values << 8;
+ return p;
+ });
+
+ p.then([&](int r) {
+ values << r;
+ }).wait();
+
+ QCOMPARE(waitForError(p, QString()), QString("foo"));
+ QCOMPARE(p.isRejected(), true);
+ QCOMPARE(values, QVector({8, 64}));
+}
+
+void tst_qpromise_finally::rejectedAsyncReject()
+{
+ auto p = QPromise::reject(QString("foo")).finally([]() {
+ return QPromise([](const QPromiseResolve&, const QPromiseReject& reject) {
+ QtPromisePrivate::qtpromise_defer([=]() {
+ reject(QString("bar"));
+ });
+ });
+ });
+
+ QCOMPARE(waitForError(p, QString()), QString("bar"));
+ QCOMPARE(p.isRejected(), true);
+}
diff --git a/tests/auto/qtpromise/qpromise/qpromise.pro b/tests/auto/qtpromise/qpromise/qpromise.pro
index 0fb2a2f..7eb2f1f 100644
--- a/tests/auto/qtpromise/qpromise/qpromise.pro
+++ b/tests/auto/qtpromise/qpromise/qpromise.pro
@@ -1,4 +1,9 @@
-TARGET = tst_qpromise
-SOURCES += $$PWD/tst_qpromise.cpp
-
-include(../qtpromise.pri)
+TEMPLATE = subdirs
+SUBDIRS += \
+ construct \
+ delay \
+ fail \
+ finally \
+ tap \
+ then \
+ timeout
diff --git a/tests/auto/qtpromise/qpromise/tap/tap.pro b/tests/auto/qtpromise/qpromise/tap/tap.pro
new file mode 100644
index 0000000..71958f8
--- /dev/null
+++ b/tests/auto/qtpromise/qpromise/tap/tap.pro
@@ -0,0 +1,4 @@
+TARGET = tst_qpromise_tap
+SOURCES += $$PWD/tst_tap.cpp
+
+include(../../qtpromise.pri)
diff --git a/tests/auto/qtpromise/qpromise/tap/tst_tap.cpp b/tests/auto/qtpromise/qpromise/tap/tst_tap.cpp
new file mode 100644
index 0000000..6061f9f
--- /dev/null
+++ b/tests/auto/qtpromise/qpromise/tap/tst_tap.cpp
@@ -0,0 +1,145 @@
+// Tests
+#include "../../shared/utils.h"
+
+// QtPromise
+#include
+
+// Qt
+#include
+
+using namespace QtPromise;
+
+class tst_qpromise_tap : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void fulfilledSync();
+ void fulfilledSync_void();
+ void fulfilledThrows();
+ void fulfilledThrows_void();
+ void fulfilledAsyncResolve();
+ void fulfilledAsyncReject();
+ void rejectedSync();
+ void rejectedSync_void();
+};
+
+QTEST_MAIN(tst_qpromise_tap)
+#include "tst_tap.moc"
+
+void tst_qpromise_tap::fulfilledSync()
+{
+ int value = -1;
+ auto p = QPromise::resolve(42).tap([&](int res) {
+ value = res + 1;
+ return 8;
+ });
+
+ QCOMPARE(waitForValue(p, 42), 42);
+ QCOMPARE(p.isFulfilled(), true);
+ QCOMPARE(value, 43);
+}
+
+void tst_qpromise_tap::fulfilledSync_void()
+{
+ int value = -1;
+ auto p = QPromise::resolve().tap([&]() {
+ value = 43;
+ return 8;
+ });
+
+ QCOMPARE(waitForValue(p, -1, 42), 42);
+ QCOMPARE(p.isFulfilled(), true);
+ QCOMPARE(value, 43);
+}
+
+void tst_qpromise_tap::fulfilledThrows()
+{
+ auto p = QPromise::resolve(42).tap([&](int) {
+ throw QString("foo");
+ });
+
+ QCOMPARE(waitForError(p, QString()), QString("foo"));
+ QCOMPARE(p.isRejected(), true);
+}
+
+void tst_qpromise_tap::fulfilledThrows_void()
+{
+ auto p = QPromise::resolve().tap([&]() {
+ throw QString("foo");
+ });
+
+ QCOMPARE(waitForError(p, QString()), QString("foo"));
+ QCOMPARE(p.isRejected(), true);
+}
+
+void tst_qpromise_tap::fulfilledAsyncResolve()
+{
+ QVector values;
+ auto p = QPromise::resolve(1).tap([&](int) {
+ QPromise p([&](const QPromiseResolve& resolve) {
+ QtPromisePrivate::qtpromise_defer([=, &values]() {
+ values << 3;
+ resolve(4); // ignored!
+ });
+ });
+
+ values << 2;
+ return p;
+ });
+
+ p.then([&](int r) {
+ values << r;
+ }).wait();
+
+ QCOMPARE(p.isFulfilled(), true);
+ QCOMPARE(values, QVector({2, 3, 1}));
+}
+
+void tst_qpromise_tap::fulfilledAsyncReject()
+{
+ QVector values;
+ auto p = QPromise::resolve(1).tap([&](int) {
+ QPromise p([&](const QPromiseResolve&, const QPromiseReject& reject) {
+ QtPromisePrivate::qtpromise_defer([=, &values]() {
+ values << 3;
+ reject(QString("foo"));
+ });
+ });
+
+ values << 2;
+ return p;
+ });
+
+ p.then([&](int r) {
+ values << r;
+ }).wait();
+
+ QCOMPARE(waitForError(p, QString()), QString("foo"));
+ QCOMPARE(p.isRejected(), true);
+ QCOMPARE(values, QVector({2, 3}));
+}
+
+void tst_qpromise_tap::rejectedSync()
+{
+ int value = -1;
+ auto p = QPromise::reject(QString("foo")).tap([&](int res) {
+ value = res + 1;
+ });
+
+ QCOMPARE(waitForError(p, QString()), QString("foo"));
+ QCOMPARE(p.isRejected(), true);
+ QCOMPARE(value, -1);
+}
+
+void tst_qpromise_tap::rejectedSync_void()
+{
+ int value = -1;
+ auto p = QPromise::reject(QString("foo")).tap([&]() {
+ value = 43;
+ });
+
+ QCOMPARE(waitForError(p, QString()), QString("foo"));
+ QCOMPARE(p.isRejected(), true);
+ QCOMPARE(value, -1);
+}
diff --git a/tests/auto/qtpromise/qpromise/then/then.pro b/tests/auto/qtpromise/qpromise/then/then.pro
new file mode 100644
index 0000000..b82d33e
--- /dev/null
+++ b/tests/auto/qtpromise/qpromise/then/then.pro
@@ -0,0 +1,4 @@
+TARGET = tst_qpromise_then
+SOURCES += $$PWD/tst_then.cpp
+
+include(../../qtpromise.pri)
diff --git a/tests/auto/qtpromise/qpromise/then/tst_then.cpp b/tests/auto/qtpromise/qpromise/then/tst_then.cpp
new file mode 100644
index 0000000..3d5bf03
--- /dev/null
+++ b/tests/auto/qtpromise/qpromise/then/tst_then.cpp
@@ -0,0 +1,126 @@
+// Tests
+#include "../../shared/utils.h"
+
+// QtPromise
+#include
+
+// Qt
+#include
+
+using namespace QtPromise;
+
+class tst_qpromise_then : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void resolveSync();
+ void resolveAsync();
+ void rejectSync();
+ void rejectAsync();
+ void skipResult();
+ void noHandler();
+};
+
+QTEST_MAIN(tst_qpromise_then)
+#include "tst_then.moc"
+
+void tst_qpromise_then::resolveSync()
+{
+ QVariantList values;
+
+ auto input = QPromise::resolve(42);
+ auto output = input.then([&](int res) {
+ values << res;
+ return QString::number(res+1);
+ });
+
+ output.then([&](const QString& res) {
+ values << res;
+ }).then([&]() {
+ values << 44;
+ }).wait();
+
+ QCOMPARE(values, QVariantList({42, QString("43"), 44}));
+ QCOMPARE(input.isFulfilled(), true);
+ QCOMPARE(output.isFulfilled(), true);
+}
+
+void tst_qpromise_then::resolveAsync()
+{
+ 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"));
+ QCOMPARE(p.isFulfilled(), true);
+}
+
+void tst_qpromise_then::rejectSync()
+{
+ 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(error, QString("foo42"));
+ QCOMPARE(input.isFulfilled(), true);
+ QCOMPARE(output.isRejected(), true);
+}
+
+void tst_qpromise_then::rejectAsync()
+{
+ 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"));
+ QCOMPARE(p.isRejected(), true);
+}
+
+void tst_qpromise_then::skipResult()
+{
+ 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_then::noHandler()
+{
+ { // 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);
+ }
+}
diff --git a/tests/auto/qtpromise/qpromise/timeout/timeout.pro b/tests/auto/qtpromise/qpromise/timeout/timeout.pro
new file mode 100644
index 0000000..c3ce03a
--- /dev/null
+++ b/tests/auto/qtpromise/qpromise/timeout/timeout.pro
@@ -0,0 +1,4 @@
+TARGET = tst_qpromise_timeout
+SOURCES += $$PWD/tst_timeout.cpp
+
+include(../../qtpromise.pri)
diff --git a/tests/auto/qtpromise/qpromise/timeout/tst_timeout.cpp b/tests/auto/qtpromise/qpromise/timeout/tst_timeout.cpp
new file mode 100644
index 0000000..bf43c61
--- /dev/null
+++ b/tests/auto/qtpromise/qpromise/timeout/tst_timeout.cpp
@@ -0,0 +1,92 @@
+// Tests
+#include "../../shared/utils.h"
+
+// QtPromise
+#include
+
+// Qt
+#include
+
+using namespace QtPromise;
+
+class tst_qpromise_timeout : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void fulfilled();
+ void rejected();
+ void timeout();
+};
+
+QTEST_MAIN(tst_qpromise_timeout)
+#include "tst_timeout.moc"
+
+void tst_qpromise_timeout::fulfilled()
+{
+ QElapsedTimer timer;
+ qint64 elapsed = -1;
+
+ timer.start();
+
+ auto p = QPromise([](const QPromiseResolve& resolve) {
+ QTimer::singleShot(1000, [=]() {
+ resolve(42);
+ });
+ }).timeout(2000).finally([&]() {
+ elapsed = timer.elapsed();
+ });
+
+ QCOMPARE(waitForValue(p, -1), 42);
+ QCOMPARE(p.isFulfilled(), true);
+ QVERIFY(elapsed < 2000);
+}
+
+void tst_qpromise_timeout::rejected()
+{
+ QElapsedTimer timer;
+ qint64 elapsed = -1;
+
+ timer.start();
+
+ auto p = QPromise([](const QPromiseResolve&, const QPromiseReject& reject) {
+ QTimer::singleShot(1000, [=]() {
+ reject(QString("foo"));
+ });
+ }).timeout(2000).finally([&]() {
+ elapsed = timer.elapsed();
+ });
+
+
+ QCOMPARE(waitForError(p, QString()), QString("foo"));
+ QCOMPARE(p.isRejected(), true);
+ QVERIFY(elapsed < 2000);
+}
+
+void tst_qpromise_timeout::timeout()
+{
+ QElapsedTimer timer;
+ qint64 elapsed = -1;
+ bool failed = false;
+
+ timer.start();
+
+ auto p = QPromise([](const QPromiseResolve& resolve) {
+ QTimer::singleShot(4000, [=]() {
+ resolve(42);
+ });
+ }).timeout(2000).finally([&]() {
+ elapsed = timer.elapsed();
+ });
+
+ p.fail([&](const QPromiseTimeoutException&) {
+ failed = true;
+ return -1;
+ }).wait();
+
+ QCOMPARE(waitForValue(p, -1), -1);
+ QCOMPARE(p.isRejected(), true);
+ QCOMPARE(failed, true);
+ QVERIFY(elapsed >= 2000 * 0.95); // Qt::CoarseTimer (default) Coarse timers try to
+ QVERIFY(elapsed <= 2000 * 1.05); // keep accuracy within 5% of the desired interval.
+}
diff --git a/tests/auto/qtpromise/qpromise/tst_qpromise.cpp b/tests/auto/qtpromise/qpromise/tst_qpromise.cpp
deleted file mode 100644
index f20b989..0000000
--- a/tests/auto/qtpromise/qpromise/tst_qpromise.cpp
+++ /dev/null
@@ -1,766 +0,0 @@
-// QtPromise
-#include
-
-// Qt
-#include
-#include
-
-using namespace QtPromise;
-using namespace QtPromisePrivate;
-
-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 finallyFulfilled();
- void finallyFulfilled_void();
- void finallyRejected();
- void finallyRejected_void();
- void finallyThrows();
- void finallyThrows_void();
- void finallyDelayedResolved();
- void finallyDelayedRejected();
-
- void tapFulfilled();
- void tapFulfilled_void();
- void tapRejected();
- void tapRejected_void();
- void tapThrows();
- void tapThrows_void();
- void tapDelayedResolved();
- void tapDelayedRejected();
-
- void timeoutFulfilled();
- void timeoutRejected();
- void timeoutReject();
-
- void delayFulfilled();
- void delayRejected();
-
-}; // class tst_qpromise
-
-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::finallyFulfilled()
-{
- int value = -1;
- auto p = QPromise::resolve(42).finally([&]() {
- value = 8;
- return 16; // ignored!
- });
-
- Q_STATIC_ASSERT((std::is_same >::value));
- QCOMPARE(waitForValue(p, -1), 42);
- QCOMPARE(p.isFulfilled(), true);
- QCOMPARE(value, 8);
-}
-
-void tst_qpromise::finallyFulfilled_void()
-{
- 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);
-}
-
-void tst_qpromise::finallyRejected()
-{
- 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);
-}
-
-void tst_qpromise::finallyRejected_void()
-{
- 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);
-}
-
-void tst_qpromise::finallyThrows()
-{
- { // fulfilled
- auto p = QPromise::resolve(42).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::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 p = QPromise::resolve(42).finally([&]() {
- QPromise p([&](const QPromiseResolve& resolve) {
- qtpromise_defer([=, &values]() {
- values << 64;
- resolve(16); // ignored!
- });
- });
-
- values << 8;
- return p;
- });
-
- QCOMPARE(waitForValue(p, -1), 42);
- QCOMPARE(p.isFulfilled(), true);
- QCOMPARE(values, QVector({8, 64}));
- }
- { // rejected
- QVector values;
- auto p = QPromise::reject(QString("foo")).finally([&]() {
- QPromise p([&](const QPromiseResolve& resolve) {
- qtpromise_defer([=, &values]() {
- values << 64;
- resolve(16); // ignored!
- });
- });
-
- values << 8;
- return p;
- });
-
- p.then([&](int r) {
- values << r;
- }).wait();
-
- QCOMPARE(waitForError(p, QString()), QString("foo"));
- QCOMPARE(p.isRejected(), true);
- QCOMPARE(values, QVector({8, 64}));
- }
-}
-
-void tst_qpromise::finallyDelayedRejected()
-{
- { // fulfilled
- auto p = QPromise::resolve(42).finally([]() {
- return QPromise([](const QPromiseResolve&, const QPromiseReject& reject) {
- qtpromise_defer([=]() {
- reject(QString("bar"));
- });
- });
- });
-
- QCOMPARE(waitForError(p, QString()), QString("bar"));
- QCOMPARE(p.isRejected(), true);
- }
- { // rejected
- auto p = QPromise::reject(QString("foo")).finally([]() {
- return QPromise([](const QPromiseResolve&, const QPromiseReject& reject) {
- qtpromise_defer([=]() {
- reject(QString("bar"));
- });
- });
- });
-
- QCOMPARE(waitForError(p, QString()), QString("bar"));
- QCOMPARE(p.isRejected(), true);
- }
-}
-
-void tst_qpromise::tapFulfilled()
-{
- int value = -1;
- auto p = QPromise::resolve(42).tap([&](int res) {
- value = res + 1;
- return 8;
- });
-
- QCOMPARE(waitForValue(p, 42), 42);
- QCOMPARE(p.isFulfilled(), true);
- QCOMPARE(value, 43);
-}
-
-void tst_qpromise::tapFulfilled_void()
-{
- int value = -1;
- auto p = QPromise::resolve().tap([&]() {
- value = 43;
- return 8;
- });
-
- QCOMPARE(waitForValue(p, -1, 42), 42);
- QCOMPARE(p.isFulfilled(), true);
- QCOMPARE(value, 43);
-}
-
-void tst_qpromise::tapRejected()
-{
- int value = -1;
- auto p = QPromise::reject(QString("foo")).tap([&](int res) {
- value = res + 1;
- });
-
- QCOMPARE(waitForError(p, QString()), QString("foo"));
- QCOMPARE(p.isRejected(), true);
- QCOMPARE(value, -1);
-}
-
-void tst_qpromise::tapRejected_void()
-{
- int value = -1;
- auto p = QPromise::reject(QString("foo")).tap([&]() {
- value = 43;
- });
-
- QCOMPARE(waitForError(p, QString()), QString("foo"));
- QCOMPARE(p.isRejected(), true);
- QCOMPARE(value, -1);
-}
-
-void tst_qpromise::tapThrows()
-{
- auto p = QPromise::resolve(42).tap([&](int) {
- throw QString("foo");
- });
-
- QCOMPARE(waitForError(p, QString()), QString("foo"));
- QCOMPARE(p.isRejected(), true);
-}
-
-void tst_qpromise::tapThrows_void()
-{
- auto p = QPromise::resolve().tap([&]() {
- throw QString("foo");
- });
-
- QCOMPARE(waitForError(p, QString()), QString("foo"));
- QCOMPARE(p.isRejected(), true);
-}
-
-void tst_qpromise::tapDelayedResolved()
-{
- QVector values;
- auto p = QPromise::resolve(1).tap([&](int) {
- QPromise p([&](const QPromiseResolve& resolve) {
- qtpromise_defer([=, &values]() {
- values << 3;
- resolve(4); // ignored!
- });
- });
-
- values << 2;
- return p;
- });
-
- p.then([&](int r) {
- values << r;
- }).wait();
-
- QCOMPARE(p.isFulfilled(), true);
- QCOMPARE(values, QVector({2, 3, 1}));
-}
-
-void tst_qpromise::tapDelayedRejected()
-{
- QVector values;
- auto p = QPromise::resolve(1).tap([&](int) {
- QPromise p([&](const QPromiseResolve&, const QPromiseReject& reject) {
- qtpromise_defer([=, &values]() {
- values << 3;
- reject(QString("foo"));
- });
- });
-
- values << 2;
- return p;
- });
-
- p.then([&](int r) {
- values << r;
- }).wait();
-
- QCOMPARE(waitForError(p, QString()), QString("foo"));
- QCOMPARE(p.isRejected(), true);
- QCOMPARE(values, QVector({2, 3}));
-}
-
-void tst_qpromise::timeoutFulfilled()
-{
- QElapsedTimer timer;
- qint64 elapsed = -1;
-
- timer.start();
-
- auto p = QPromise([](const QPromiseResolve& resolve) {
- QTimer::singleShot(1000, [=]() {
- resolve(42);
- });
- }).timeout(2000).finally([&]() {
- elapsed = timer.elapsed();
- });
-
- QCOMPARE(waitForValue(p, -1), 42);
- QCOMPARE(p.isFulfilled(), true);
- QVERIFY(elapsed < 2000);
-}
-
-void tst_qpromise::timeoutRejected()
-{
- QElapsedTimer timer;
- qint64 elapsed = -1;
-
- timer.start();
-
- auto p = QPromise([](const QPromiseResolve&, const QPromiseReject& reject) {
- QTimer::singleShot(1000, [=]() {
- reject(QString("foo"));
- });
- }).timeout(2000).finally([&]() {
- elapsed = timer.elapsed();
- });
-
-
- QCOMPARE(waitForError(p, QString()), QString("foo"));
- QCOMPARE(p.isRejected(), true);
- QVERIFY(elapsed < 2000);
-}
-
-void tst_qpromise::timeoutReject()
-{
- QElapsedTimer timer;
- qint64 elapsed = -1;
- bool failed = false;
-
- timer.start();
-
- auto p = QPromise([](const QPromiseResolve& resolve) {
- QTimer::singleShot(4000, [=]() {
- resolve(42);
- });
- }).timeout(2000).finally([&]() {
- elapsed = timer.elapsed();
- });
-
- p.fail([&](const QPromiseTimeoutException&) {
- failed = true;
- return -1;
- }).wait();
-
- QCOMPARE(waitForValue(p, -1), -1);
- QCOMPARE(p.isRejected(), true);
- QCOMPARE(failed, true);
- QVERIFY(elapsed >= 2000 * 0.95); // Qt::CoarseTimer (default) Coarse timers try to
- QVERIFY(elapsed <= 2000 * 1.05); // keep accuracy within 5% of the desired interval.
-}
-
-void tst_qpromise::delayFulfilled()
-{
- QElapsedTimer timer;
- qint64 elapsed = -1;
-
- timer.start();
-
- auto p = QPromise::resolve(42).delay(1000).finally([&]() {
- elapsed = timer.elapsed();
- });
-
- QCOMPARE(waitForValue(p, -1), 42);
- QCOMPARE(p.isFulfilled(), true);
- QVERIFY(elapsed >= 1000 * 0.95); // Qt::CoarseTimer (default) Coarse timers try to
- QVERIFY(elapsed <= 1000 * 1.05); // keep accuracy within 5% of the desired interval.
-}
-
-void tst_qpromise::delayRejected()
-{
- QElapsedTimer timer;
- qint64 elapsed = -1;
-
- timer.start();
-
- auto p = QPromise::reject(QString("foo")).delay(1000).finally([&]() {
- elapsed = timer.elapsed();
- });
-
- QCOMPARE(waitForError(p, QString()), QString("foo"));
- QCOMPARE(p.isRejected(), true);
- QVERIFY(elapsed < 5);
-}
diff --git a/tests/auto/qtpromise/qtpromise.pri b/tests/auto/qtpromise/qtpromise.pri
index ad49341..b39b4ca 100644
--- a/tests/auto/qtpromise/qtpromise.pri
+++ b/tests/auto/qtpromise/qtpromise.pri
@@ -15,4 +15,7 @@ coverage {
}
}
+HEADERS += \
+ $$PWD/shared/utils.h
+
include(../../../qtpromise.pri)
diff --git a/tests/auto/qtpromise/requirements/tst_requirements.cpp b/tests/auto/qtpromise/requirements/tst_requirements.cpp
index 5253865..0e8a5a4 100644
--- a/tests/auto/qtpromise/requirements/tst_requirements.cpp
+++ b/tests/auto/qtpromise/requirements/tst_requirements.cpp
@@ -5,7 +5,6 @@
#include
using namespace QtPromise;
-using namespace QtPromisePrivate;
// https://promisesaplus.com/#requirements
class tst_requirements : public QObject
@@ -41,7 +40,7 @@ void tst_requirements::statePending()
// 2.1.1.1. may transition to either the fulfilled state
{
QPromise p([&](const QPromiseResolve& resolve) {
- qtpromise_defer([=]() { resolve(42); });
+ QtPromisePrivate::qtpromise_defer([=]() { resolve(42); });
});
QVERIFY(p.isPending());
@@ -58,7 +57,7 @@ void tst_requirements::statePending()
// 2.1.1.1. ... or the rejected state
{
QPromise p([&](const QPromiseResolve&, const QPromiseReject