Add the unit tests for the failure handlers recovering and rethrowing

This commit is contained in:
Denis Blank 2018-11-26 03:02:49 +01:00
parent afe1a3298e
commit c5663bf1ad
5 changed files with 98 additions and 58 deletions

View File

@ -899,17 +899,20 @@ constexpr auto make_exceptional_continuable(Exception&& exception) {
template <typename... Args> template <typename... Args>
auto recover(Args&&... args) { auto recover(Args&&... args) {
return make_expected(std::forward<Args>(args)...); return make_result(std::forward<Args>(args)...);
} }
/// Returns a new exceptional result from the given exception
// NOLINTNEXTLINE(performance-unnecessary-value-param)
inline auto rethrow(exception_t exception) { inline auto rethrow(exception_t exception) {
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg) // NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
return make_exceptional_result(std::move(exception)); return exceptional_result{std::move(exception)};
} }
inline auto cancel() { inline auto cancel() {
return make_empty_result(); return empty_result{};
} }
/// \} /// \}
} // namespace cti } // namespace cti

View File

@ -52,11 +52,6 @@ namespace cti {
/// value so the real result gets invalidated when this object is passed to it. /// value so the real result gets invalidated when this object is passed to it.
struct empty_result {}; struct empty_result {};
/// Returns a new empty result
inline empty_result make_empty_result() {
return {};
}
/// A class which is convertible to any result and that definitly holds /// A class which is convertible to any result and that definitly holds
/// an exception which is then passed to the converted result object. /// an exception which is then passed to the converted result object.
class exceptional_result { class exceptional_result {
@ -101,13 +96,6 @@ public:
} }
}; };
/// Returns a new exceptional result from the given exception
// NOLINTNEXTLINE(performance-unnecessary-value-param)
inline exceptional_result make_exceptional_result(exception_t exception) {
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
return exceptional_result{std::move(exception)};
}
/// The result class can carry the three kinds of results an asynchronous /// The result class can carry the three kinds of results an asynchronous
/// operation can return: no result, a value or an exception. /// operation can return: no result, a value or an exception.
/// - *no result*: If the operation didn't finish /// - *no result*: If the operation didn't finish

View File

@ -409,7 +409,7 @@ struct result_handler_base<handle_results::yes, Base,
} }
}; };
inline auto make_error_invoker( inline auto make_exception_invoker(
std::integral_constant<handle_errors, handle_errors::plain>) noexcept { std::integral_constant<handle_errors, handle_errors::plain>) noexcept {
return [](auto&& callback, exception_t&& error) { return [](auto&& callback, exception_t&& error) {
// Errors are not partial invoked // Errors are not partial invoked
@ -417,7 +417,7 @@ inline auto make_error_invoker(
std::forward<decltype(callback)>(callback)(std::move(error)); std::forward<decltype(callback)>(callback)(std::move(error));
}; };
} }
inline auto make_error_invoker( inline auto make_exception_invoker(
std::integral_constant<handle_errors, handle_errors::forward>) noexcept { std::integral_constant<handle_errors, handle_errors::forward>) noexcept {
return [](auto&& callback, exception_t&& error) { return [](auto&& callback, exception_t&& error) {
// Errors are not partial invoked // Errors are not partial invoked
@ -432,7 +432,7 @@ template <handle_errors HandleErrors /* = plain or forward*/, typename Base>
struct error_handler_base { struct error_handler_base {
void operator()(exception_arg_t, exception_t error) && { void operator()(exception_arg_t, exception_t error) && {
// Just invoke the error handler, cancel the calling hierarchy after // Just invoke the error handler, cancel the calling hierarchy after
auto invoker = make_error_invoker( auto invoker = make_exception_invoker(
std::integral_constant<handle_errors, HandleErrors>{}); std::integral_constant<handle_errors, HandleErrors>{});
// Invoke the error handler // Invoke the error handler
@ -578,7 +578,6 @@ constexpr auto
next_hint_of(std::integral_constant<handle_results, handle_results::no>, next_hint_of(std::integral_constant<handle_results, handle_results::no>,
traits::identity<T> /*callback*/, traits::identity<T> /*callback*/,
hints::signature_hint_tag<Args...> current) { hints::signature_hint_tag<Args...> current) {
// TODO
return current; return current;
} }

View File

@ -30,13 +30,13 @@ static int const CANARY = 382947;
TYPED_TEST(single_dimension_tests, multipath_result_is_forwardable) { TYPED_TEST(single_dimension_tests, multipath_result_is_forwardable) {
EXPECT_ASYNC_RESULT(this->supply().then([](auto&&... canaries) -> result<> { EXPECT_ASYNC_RESULT(this->supply().then([](auto&&... canaries) -> result<> {
// //
return make_result(std::forward<decltype(canaries)>(canaries)...); return recover(std::forward<decltype(canaries)>(canaries)...);
})); }));
EXPECT_ASYNC_RESULT( EXPECT_ASYNC_RESULT(
this->supply(CANARY).then([](auto&&... canaries) -> result<int> { this->supply(CANARY).then([](auto&&... canaries) -> result<int> {
// //
return make_result(std::forward<decltype(canaries)>(canaries)...); return recover(std::forward<decltype(canaries)>(canaries)...);
}), }),
CANARY); CANARY);
@ -44,7 +44,7 @@ TYPED_TEST(single_dimension_tests, multipath_result_is_forwardable) {
this->supply(1, CANARY, 3) this->supply(1, CANARY, 3)
.then([](auto&&... canaries) -> result<int, int, int> { .then([](auto&&... canaries) -> result<int, int, int> {
// //
return make_result(std::forward<decltype(canaries)>(canaries)...); return recover(std::forward<decltype(canaries)>(canaries)...);
}), }),
1, CANARY, 3); 1, CANARY, 3);
} }
@ -53,53 +53,106 @@ TYPED_TEST(single_dimension_tests, multipath_result_is_throwable) {
ASSERT_ASYNC_EXCEPTION_COMPLETION( ASSERT_ASYNC_EXCEPTION_COMPLETION(
this->supply().then([]() -> exceptional_result { this->supply().then([]() -> exceptional_result {
// //
return make_exceptional_result(supply_test_exception()); return rethrow(supply_test_exception());
})); }));
ASSERT_ASYNC_EXCEPTION_COMPLETION(this->supply().then([]() -> result<> { ASSERT_ASYNC_EXCEPTION_COMPLETION(this->supply().then([]() -> result<> {
// //
return make_exceptional_result(supply_test_exception()); return rethrow(supply_test_exception());
})); }));
} }
TYPED_TEST(single_dimension_tests, multipath_result_is_cancelable) { TYPED_TEST(single_dimension_tests, multipath_result_is_cancelable) {
ASSERT_ASYNC_INCOMPLETION(this->supply().then([]() -> empty_result { ASSERT_ASYNC_INCOMPLETION(this->supply().then([]() -> empty_result {
// //
return make_empty_result(); return cancel();
})); }));
ASSERT_ASYNC_INCOMPLETION(this->supply().then([]() -> result<> { ASSERT_ASYNC_INCOMPLETION(this->supply().then([]() -> result<> {
// //
return make_empty_result(); return cancel();
})); }));
} }
TYPED_TEST(single_dimension_tests, multipath_exception_is_recoverable) { TYPED_TEST(single_dimension_tests, multipath_exception_is_recoverable) {
/*EXPECT_ASYNC_RESULT(this->supply_exception(supply_test_exception()) EXPECT_ASYNC_RESULT(
.fail([](exception_t) -> result<> { this->supply_exception(supply_test_exception(), identity<>{})
// .fail([](exception_t) -> result<> {
return make_result(); //
})); return recover();
}));
EXPECT_ASYNC_RESULT(this->supply_exception(supply_test_exception()) EXPECT_ASYNC_RESULT(
.fail([](exception_t) -> result<int> { this->supply_exception(supply_test_exception(), identity<int>{})
// .fail([](exception_t) -> result<int> {
return make_result(CANARY); //
}), return recover(CANARY);
CANARY); }),
CANARY);
EXPECT_ASYNC_RESULT(this->supply_exception(supply_test_exception()) EXPECT_ASYNC_RESULT(
.fail([](exception_t) -> result<int, int, int> { this->supply_exception(supply_test_exception(), identity<int, int, int>{})
// .fail([](exception_t) -> result<int, int, int> {
return make_result(1, CANARY, 3); //
}), return recover(1, CANARY, 3);
1, CANARY, 3);*/ }),
1, CANARY, 3);
} }
TYPED_TEST(single_dimension_tests, multipath_exception_is_forwardable) { TYPED_TEST(single_dimension_tests, multipath_exception_is_forwardable) {
// TODO ASSERT_ASYNC_EXCEPTION_COMPLETION(
this->supply_exception(supply_test_exception(), identity<int>{})
.fail([](exception_t exception) -> exceptional_result {
//
return rethrow(exception);
}));
ASSERT_ASYNC_EXCEPTION_COMPLETION(
this->supply_exception(supply_test_exception(), identity<int>{})
.fail([](exception_t exception) -> result<int> {
//
return rethrow(exception);
}));
} }
TYPED_TEST(single_dimension_tests, multipath_exception_is_cancelable) { TYPED_TEST(single_dimension_tests, multipath_exception_is_cancelable) {
// TODO ASSERT_ASYNC_INCOMPLETION(
this->supply_exception(supply_test_exception(), identity<int>{})
.fail([](exception_t) -> empty_result {
//
return cancel();
})
.fail([] {
//
FAIL();
}));
ASSERT_ASYNC_INCOMPLETION(
this->supply_exception(supply_test_exception(), identity<int>{})
.fail([](exception_t) -> result<int> {
//
return cancel();
})
.fail([] {
//
FAIL();
}));
}
TYPED_TEST(single_dimension_tests, multipath_exception_is_autocanceled) {
bool caught = false;
ASSERT_ASYNC_INCOMPLETION(this->supply_exception(supply_test_exception())
.fail([&](exception_t) {
EXPECT_FALSE(caught);
caught = true;
})
.then([] {
// ...
FAIL();
})
.fail([](exception_t) {
// ...
FAIL();
}));
ASSERT_TRUE(caught);
} }

View File

@ -48,7 +48,7 @@ auto to_hint(identity<Args...> hint) {
template <typename... Args> template <typename... Args>
auto supplier_of(Args&&... args) { auto supplier_of(Args&&... args) {
return [values = std::make_tuple(std::forward<Args>(args)...)]( return [values = std::make_tuple(std::forward<Args>(args)...)](
auto&& promise) mutable { auto&& promise) mutable {
cti::detail::traits::unpack( cti::detail::traits::unpack(
[&](auto&&... passed) { [&](auto&&... passed) {
promise.set_value(std::forward<decltype(passed)>(passed)...); promise.set_value(std::forward<decltype(passed)>(passed)...);
@ -84,12 +84,9 @@ public:
supplier_of(std::forward<Args>(args)...)); supplier_of(std::forward<Args>(args)...));
} }
template <typename Arg> template <typename Arg, typename Hint = identity<>>
auto supply_exception(Arg&& arg) { auto supply_exception(Arg&& arg, Hint hint = {}) {
identity<> arg_types; return this->make(hint, to_hint(hint),
auto hint_types = to_hint(arg_types);
return this->make(arg_types, hint_types,
exception_supplier_of(std::forward<Arg>(arg))); exception_supplier_of(std::forward<Arg>(arg)));
} }
}; };
@ -112,12 +109,12 @@ struct provide_copyable {
struct provide_unique { struct provide_unique {
template <typename... Args, typename... Hint, typename T> template <typename... Args, typename... Hint, typename T>
auto make(identity<Args...>, identity<Hint...>, T&& callback) { auto make(identity<Args...>, identity<Hint...>, T&& callback) {
return cti::make_continuable<Hint...>([ return cti::make_continuable<Hint...>(
callback = std::forward<T>(callback), guard = std::make_unique<int>(0) [callback = std::forward<T>(callback),
](auto&&... args) mutable { guard = std::make_unique<int>(0)](auto&&... args) mutable {
(void)(*guard); (void)(*guard);
return std::move(callback)(std::forward<decltype(args)>(args)...); return std::move(callback)(std::forward<decltype(args)>(args)...);
}); });
} }
}; };