summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/thread
diff options
context:
space:
mode:
authorSona Kurazyan <sona.kurazyan@qt.io>2020-03-30 10:46:00 +0200
committerSona Kurazyan <sona.kurazyan@qt.io>2020-04-01 21:51:13 +0200
commit0f78e85421de113d73edf0d58b34e12ad188417c (patch)
tree08d12c70cb555c6514d2ad202b79389f9b50f8c4 /tests/auto/corelib/thread
parent495f958b9ac5c45196e743fcba300fcfd25b90a3 (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.cpp333
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)