diff options
author | Sona Kurazyan <sona.kurazyan@qt.io> | 2020-03-30 10:46:00 +0200 |
---|---|---|
committer | Sona Kurazyan <sona.kurazyan@qt.io> | 2020-04-01 21:51:13 +0200 |
commit | 0f78e85421de113d73edf0d58b34e12ad188417c (patch) | |
tree | 08d12c70cb555c6514d2ad202b79389f9b50f8c4 /tests/auto/corelib/thread | |
parent | 495f958b9ac5c45196e743fcba300fcfd25b90a3 (diff) |
Add support of failure handler callbacks to QFuture
Added QFuture::onFailed() method, which allows attaching handlers for
exceptions that may occur in QFuture continuation chains.
Task-number: QTBUG-81588
Change-Id: Iadeee99e3a7573207f6ca9f650ff9f7b6faa2cf7
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'tests/auto/corelib/thread')
-rw-r--r-- | tests/auto/corelib/thread/qfuture/tst_qfuture.cpp | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp index 4e20741055..1caa386638 100644 --- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp +++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp @@ -104,6 +104,8 @@ private slots: #ifndef QT_NO_EXCEPTIONS void thenOnExceptionFuture(); void thenThrows(); + void onFailed(); + void onFailedTestCallables(); #endif void takeResults(); void takeResult(); @@ -2149,6 +2151,337 @@ void tst_QFuture::thenThrows() } } +void tst_QFuture::onFailed() +{ + // Ready exception void future + { + int checkpoint = 0; + auto future = createExceptionFuture().then([&] { checkpoint = 1; }).onFailed([&] { + checkpoint = 2; + }); + + try { + future.waitForFinished(); + } catch (...) { + checkpoint = 3; + } + QCOMPARE(checkpoint, 2); + } + + // std::exception handler + { + QFutureInterface<int> promise; + + int checkpoint = 0; + auto then = promise.future() + .then([&](int res) { + throw std::exception(); + return res; + }) + .then([&](int res) { return res + 1; }) + .onFailed([&](const QException &) { + checkpoint = 1; + return -1; + }) + .onFailed([&](const std::exception &) { + checkpoint = 2; + return -1; + }) + .onFailed([&] { + checkpoint = 3; + return -1; + }); + + promise.reportStarted(); + promise.reportResult(1); + promise.reportFinished(); + + int res = 0; + try { + res = then.result(); + } catch (...) { + checkpoint = 4; + } + QCOMPARE(checkpoint, 2); + QCOMPARE(res, -1); + } + + // then() throws an exception derived from QException + { + QFutureInterface<int> promise; + + int checkpoint = 0; + auto then = promise.future() + .then([&](int res) { + throw DerivedException(); + return res; + }) + .then([&](int res) { return res + 1; }) + .onFailed([&](const QException &) { + checkpoint = 1; + return -1; + }) + .onFailed([&](const std::exception &) { + checkpoint = 2; + return -1; + }) + .onFailed([&] { + checkpoint = 3; + return -1; + }); + + promise.reportStarted(); + promise.reportResult(1); + promise.reportFinished(); + + int res = 0; + try { + res = then.result(); + } catch (...) { + checkpoint = 4; + } + QCOMPARE(checkpoint, 1); + QCOMPARE(res, -1); + } + + // then() throws a custom exception + { + QFutureInterface<int> promise; + + int checkpoint = 0; + auto then = promise.future() + .then([&](int res) { + throw TestException(); + return res; + }) + .then([&](int res) { return res + 1; }) + .onFailed([&](const QException &) { + checkpoint = 1; + return -1; + }) + .onFailed([&](const std::exception &) { + checkpoint = 2; + return -1; + }) + .onFailed([&] { + checkpoint = 3; + return -1; + }); + + promise.reportStarted(); + promise.reportResult(1); + promise.reportFinished(); + + int res = 0; + try { + res = then.result(); + } catch (...) { + checkpoint = 4; + } + QCOMPARE(checkpoint, 3); + QCOMPARE(res, -1); + } + + // Custom exception handler + { + struct TestException + { + }; + + QFutureInterface<int> promise; + + int checkpoint = 0; + auto then = promise.future() + .then([&](int res) { + throw TestException(); + return res; + }) + .then([&](int res) { return res + 1; }) + .onFailed([&](const QException &) { + checkpoint = 1; + return -1; + }) + .onFailed([&](const TestException &) { + checkpoint = 2; + return -1; + }) + .onFailed([&] { + checkpoint = 3; + return -1; + }); + + promise.reportStarted(); + promise.reportResult(1); + promise.reportFinished(); + + int res = 0; + try { + res = then.result(); + } catch (...) { + checkpoint = 4; + } + QCOMPARE(checkpoint, 2); + QCOMPARE(res, -1); + } + + // Handle all exceptions + { + QFutureInterface<int> promise; + + int checkpoint = 0; + auto then = promise.future() + .then([&](int res) { + throw QException(); + return res; + }) + .then([&](int res) { return res + 1; }) + .onFailed([&] { + checkpoint = 1; + return -1; + }) + .onFailed([&](const QException &) { + checkpoint = 2; + return -1; + }); + + promise.reportStarted(); + promise.reportResult(1); + promise.reportFinished(); + + int res = 0; + try { + res = then.result(); + } catch (...) { + checkpoint = 3; + } + QCOMPARE(checkpoint, 1); + QCOMPARE(res, -1); + } + + // Handler throws exception + { + QFutureInterface<int> promise; + + int checkpoint = 0; + auto then = promise.future() + .then([&](int res) { + throw QException(); + return res; + }) + .then([&](int res) { return res + 1; }) + .onFailed([&](const QException &) { + checkpoint = 1; + throw QException(); + return -1; + }) + .onFailed([&] { + checkpoint = 2; + return -1; + }); + + promise.reportStarted(); + promise.reportResult(1); + promise.reportFinished(); + + int res = 0; + try { + res = then.result(); + } catch (...) { + checkpoint = 3; + } + QCOMPARE(checkpoint, 2); + QCOMPARE(res, -1); + } + + // No handler for exception + { + QFutureInterface<int> promise; + + int checkpoint = 0; + auto then = promise.future() + .then([&](int res) { + throw QException(); + return res; + }) + .then([&](int res) { return res + 1; }) + .onFailed([&](const std::exception &) { + checkpoint = 1; + throw std::exception(); + return -1; + }) + .onFailed([&](QException &) { + checkpoint = 2; + return -1; + }); + + promise.reportStarted(); + promise.reportResult(1); + promise.reportFinished(); + + int res = 0; + try { + res = then.result(); + } catch (...) { + checkpoint = 3; + } + QCOMPARE(checkpoint, 3); + QCOMPARE(res, 0); + } +} + +template<class Callable> +bool runForCallable(Callable &&handler) +{ + QFuture<int> future = createExceptionResultFuture() + .then([&](int) { return 1; }) + .onFailed(std::forward<Callable>(handler)); + + int res = 0; + try { + res = future.result(); + } catch (...) { + return false; + } + return res == -1; +} + +int foo() +{ + return -1; +} + +void tst_QFuture::onFailedTestCallables() +{ + QVERIFY(runForCallable([&] { return -1; })); + QVERIFY(runForCallable(foo)); + QVERIFY(runForCallable(&foo)); + + std::function<int()> func = foo; + QVERIFY(runForCallable(func)); + + struct Functor1 + { + int operator()() { return -1; } + static int foo() { return -1; } + }; + QVERIFY(runForCallable(Functor1())); + QVERIFY(runForCallable(Functor1::foo)); + + struct Functor2 + { + int operator()() const { return -1; } + static int foo() { return -1; } + }; + QVERIFY(runForCallable(Functor2())); + + struct Functor3 + { + int operator()() const noexcept { return -1; } + static int foo() { return -1; } + }; + QVERIFY(runForCallable(Functor3())); +} + #endif // QT_NO_EXCEPTIONS void tst_QFuture::testSingleResult(const UniquePtr &p) |