From 18324d3f44dbb7c29ad4cc97c43f77b6be9b268e Mon Sep 17 00:00:00 2001 From: Simon Brunel Date: Sat, 2 Sep 2017 12:23:42 +0200 Subject: [PATCH] Implement QPromise::timeout(msec, error) --- src/qtpromise/qpromise.h | 3 ++ src/qtpromise/qpromise.inl | 20 ++++++++ src/qtpromise/qpromiseerror.h | 13 +++++ tests/auto/qpromise/tst_qpromise.cpp | 73 ++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+) diff --git a/src/qtpromise/qpromise.h b/src/qtpromise/qpromise.h index e83d23a..e80862a 100644 --- a/src/qtpromise/qpromise.h +++ b/src/qtpromise/qpromise.h @@ -46,6 +46,9 @@ public: template inline QPromise tap(THandler handler) const; + template + inline QPromise timeout(int msec, E&& error = E()) const; + inline QPromise delay(int msec) const; inline QPromise wait() const; diff --git a/src/qtpromise/qpromise.inl b/src/qtpromise/qpromise.inl index 2778254..e3bd45c 100644 --- a/src/qtpromise/qpromise.inl +++ b/src/qtpromise/qpromise.inl @@ -150,6 +150,26 @@ inline QPromise QPromiseBase::tap(THandler handler) const }); } +template +template +inline QPromise QPromiseBase::timeout(int msec, E&& error) const +{ + QPromise p = *this; + return QPromise([&]( + const QPromiseResolve& resolve, + const QPromiseReject& reject) { + + QTimer::singleShot(msec, [=]() { + // we don't need to verify the current promise state, reject() + // takes care of checking if the promise is already resolved, + // and thus will ignore this rejection. + reject(std::move(error)); + }); + + QtPromisePrivate::PromiseFulfill >::call(p, resolve, reject); + }); +} + template inline QPromise QPromiseBase::delay(int msec) const { diff --git a/src/qtpromise/qpromiseerror.h b/src/qtpromise/qpromiseerror.h index c84c9e8..8bfc160 100644 --- a/src/qtpromise/qpromiseerror.h +++ b/src/qtpromise/qpromiseerror.h @@ -4,6 +4,9 @@ // QtPromise #include "qpromiseglobal.h" +// Qt +#include + namespace QtPromise { class QPromiseError @@ -53,6 +56,16 @@ private: std::exception_ptr m_exception; }; +class QPromiseTimeoutException : public QException +{ +public: + void raise() const Q_DECL_OVERRIDE { throw *this; } + QPromiseTimeoutException* clone() const Q_DECL_OVERRIDE + { + return new QPromiseTimeoutException(*this); + } +}; + } // namespace QtPromise #endif // QTPROMISE_QPROMISEERROR_H diff --git a/tests/auto/qpromise/tst_qpromise.cpp b/tests/auto/qpromise/tst_qpromise.cpp index 4dbfbee..f20b989 100644 --- a/tests/auto/qpromise/tst_qpromise.cpp +++ b/tests/auto/qpromise/tst_qpromise.cpp @@ -49,6 +49,10 @@ private Q_SLOTS: void tapDelayedResolved(); void tapDelayedRejected(); + void timeoutFulfilled(); + void timeoutRejected(); + void timeoutReject(); + void delayFulfilled(); void delayRejected(); @@ -659,6 +663,75 @@ void tst_qpromise::tapDelayedRejected() 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;