From c4fc276f4af964ce586e009ea3d0c728bb660331 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= Date: Sun, 5 Apr 2015 01:05:55 +0200 Subject: Async: improve error handling and error propagation The error is now propagated to the top-most (user-owned) Future. When an error occurs, no further tasks are executed. The first error handler function in the chain is also called, if there's any. --- async/autotests/asynctest.cpp | 166 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 151 insertions(+), 15 deletions(-) (limited to 'async/autotests') diff --git a/async/autotests/asynctest.cpp b/async/autotests/asynctest.cpp index 65e604f..d709567 100644 --- a/async/autotests/asynctest.cpp +++ b/async/autotests/asynctest.cpp @@ -27,6 +27,8 @@ #include #include +#include + class AsyncTest : public QObject { Q_OBJECT @@ -62,6 +64,9 @@ private Q_SLOTS: void testProgressReporting(); void testErrorHandler(); + void testErrorPropagation(); + void testErrorHandlerAsync(); + void testErrorPropagationAsync(); void testChainingRunningJob(); void testChainingFinishedJob(); @@ -92,8 +97,25 @@ private: mTimer.start(200); } + AsyncSimulator(Async::Future &future, std::function&)> callback) + : mFuture(future) + , mCallback(callback) + { + QObject::connect(&mTimer, &QTimer::timeout, + [this]() { + mCallback(mFuture); + }); + QObject::connect(&mTimer, &QTimer::timeout, + [this]() { + delete this; + }); + mTimer.setSingleShot(true); + mTimer.start(200); + } + private: Async::Future mFuture; + std::function&)> mCallback; T mResult; QTimer mTimer; }; @@ -390,18 +412,14 @@ void AsyncTest::testAsyncReduce() }) .reduce>( [](const QList &list, Async::Future &future) { - QTimer *timer = new QTimer(); - QObject::connect(timer, &QTimer::timeout, - [list, &future]() { - int sum = 0; - for (int i : list) sum += i; - future.setValue(sum); - future.setFinished(); - }); - QObject::connect(timer, &QTimer::timeout, - timer, &QObject::deleteLater); - timer->setSingleShot(true); - timer->start(0); + new AsyncSimulator(future, + [list](Async::Future &future) { + int sum = 0; + for (int i : list) sum += i; + future.setValue(sum); + future.setFinished(); + } + ); }); Async::Future future = job.exec(); @@ -508,28 +526,146 @@ void AsyncTest::testProgressReporting() } void AsyncTest::testErrorHandler() +{ + + { + auto job = Async::start( + [](Async::Future &f) { + f.setError(1, "error"); + }); + + auto future = job.exec(); + QVERIFY(future.isFinished()); + QCOMPARE(future.errorCode(), 1); + QCOMPARE(future.errorMessage(), QString::fromLatin1("error")); + } + + { + int error = 0; + auto job = Async::start( + [](Async::Future &f) { + f.setError(1, "error"); + }, + [&error](int errorCode, const QString &errorMessage) { + error += errorCode; + } + ); + + auto future = job.exec(); + QVERIFY(future.isFinished()); + QCOMPARE(error, 1); + QCOMPARE(future.errorCode(), 1); + QCOMPARE(future.errorMessage(), QString::fromLatin1("error")); + } +} + +void AsyncTest::testErrorPropagation() { int error = 0; + bool called = false; auto job = Async::start( [](Async::Future &f) { f.setError(1, "error"); }) .then( - [](int v, Async::Future &f) { + [&called](int v, Async::Future &f) { + called = true; f.setFinished(); }, [&error](int errorCode, const QString &errorMessage) { - error = errorCode; + error += errorCode; } ); auto future = job.exec(); - future.waitForFinished(); + QVERIFY(future.isFinished()); + QCOMPARE(future.errorCode(), 1); + QCOMPARE(future.errorMessage(), QString::fromLatin1("error")); + QCOMPARE(called, false); QCOMPARE(error, 1); +} + +void AsyncTest::testErrorHandlerAsync() +{ + { + auto job = Async::start( + [](Async::Future &f) { + new AsyncSimulator(f, + [](Async::Future &f) { + f.setError(1, "error"); + } + ); + } + ); + + auto future = job.exec(); + future.waitForFinished(); + + QVERIFY(future.isFinished()); + QCOMPARE(future.errorCode(), 1); + QCOMPARE(future.errorMessage(), QString::fromLatin1("error")); + } + + { + int error = 0; + auto job = Async::start( + [](Async::Future &f) { + new AsyncSimulator(f, + [](Async::Future &f) { + f.setError(1, "error"); + } + ); + }, + [&error](int errorCode, const QString &errorMessage) { + error += errorCode; + } + ); + + auto future = job.exec(); + future.waitForFinished(); + + QVERIFY(future.isFinished()); + QCOMPARE(error, 1); + QCOMPARE(future.errorCode(), 1); + QCOMPARE(future.errorMessage(), QString::fromLatin1("error")); + } +} + +void AsyncTest::testErrorPropagationAsync() +{ + int error = 0; + bool called = false; + auto job = Async::start( + [](Async::Future &f) { + new AsyncSimulator(f, + [](Async::Future &f) { + f.setError(1, "error"); + } + ); + }) + .then( + [&called](int v, Async::Future &f) { + called = true; + f.setFinished(); + }, + [&error](int errorCode, const QString &errorMessage) { + error += errorCode; + } + ); + + auto future = job.exec(); + future.waitForFinished(); + QVERIFY(future.isFinished()); + QCOMPARE(future.errorCode(), 1); + QCOMPARE(future.errorMessage(), QString::fromLatin1("error")); + QCOMPARE(called, false); + QCOMPARE(error, 1); } + + void AsyncTest::testChainingRunningJob() { int check = 0; -- cgit v1.2.3