mirror of
https://github.com/Naios/continuable.git
synced 2025-12-06 16:56:44 +08:00
Add error handling testing
This commit is contained in:
parent
60c73a1a48
commit
4d964b0fe2
@ -42,6 +42,13 @@
|
||||
#define ASSERT_ASYNC_COMPLETION(CONTINUABLE) \
|
||||
cti::detail::testing::assert_async_completion(CONTINUABLE);
|
||||
|
||||
/// Asserts that the final callback of the given continuable was called
|
||||
/// with any exceptional result.
|
||||
///
|
||||
/// \since version 2.0.0
|
||||
#define ASSERT_ASYNC_EXCEPTION_COMPLETION(CONTINUABLE) \
|
||||
cti::detail::testing::assert_async_exception_completion(CONTINUABLE);
|
||||
|
||||
/// Asserts that the final callback of the given continuable is never called
|
||||
/// with any result.
|
||||
///
|
||||
@ -85,6 +92,18 @@
|
||||
#define ASSERT_ASYNC_BINARY_VALIDATION(VALIDATOR, ...) \
|
||||
cti::detail::testing::assert_async_binary_validation(VALIDATOR, __VA_ARGS__);
|
||||
|
||||
/// Asserts that the continuation was resolved through an error and forwards
|
||||
/// it's error result to the given validator which can then do assertions on the
|
||||
/// error result.
|
||||
///
|
||||
/// \note This macro is mainly present for building other assertions
|
||||
/// relying on custom validation logic.
|
||||
///
|
||||
/// \since version 2.0.0
|
||||
#define ASSERT_ASYNC_BINARY_EXCEPTION_VALIDATION(VALIDATOR, ...) \
|
||||
cti::detail::testing::assert_async_binary_exception_validation(VALIDATOR, \
|
||||
__VA_ARGS__);
|
||||
|
||||
/// Expects that the continuable is finished with the given result
|
||||
///
|
||||
/// ```cpp
|
||||
@ -99,6 +118,13 @@
|
||||
ASSERT_ASYNC_BINARY_VALIDATION(cti::detail::testing::expecting_eq_check(), \
|
||||
__VA_ARGS__)
|
||||
|
||||
/// Asserts that the continuable is finished with the given exception
|
||||
///
|
||||
/// \since version 2.0.0
|
||||
#define EXPECT_ASYNC_EXCEPTION_RESULT(...) \
|
||||
ASSERT_ASYNC_BINARY_EXCEPTION_VALIDATION( \
|
||||
cti::detail::testing::expecting_eq_check(), __VA_ARGS__)
|
||||
|
||||
/// Asserts that the continuable is finished with the given result
|
||||
///
|
||||
/// ```cpp
|
||||
@ -130,11 +156,11 @@
|
||||
cti::detail::testing::assert_async_types( \
|
||||
CONTINUABLE, cti::detail::traits::identity<__VA_ARGS__>{})
|
||||
|
||||
/// Asserts that the continuable is finished with the given error
|
||||
/// TODO
|
||||
/// Asserts that the continuable is finished with the given exception
|
||||
///
|
||||
/// \since version 2.0.0
|
||||
#define ASSERT_ASYNC_ERROR(...) \
|
||||
ASSERT_ASYNC_BINARY_VALIDATION(cti::detail::testing::asserting_eq_check(), \
|
||||
__VA_ARGS__)
|
||||
#define ASSERT_ASYNC_EXCEPTION_RESULT(...) \
|
||||
ASSERT_ASYNC_BINARY_EXCEPTION_VALIDATION( \
|
||||
cti::detail::testing::asserting_eq_check(), __VA_ARGS__)
|
||||
|
||||
#endif // CONTINUABLE_TESTING_HPP_INCLUDED__
|
||||
|
||||
@ -31,9 +31,15 @@
|
||||
#ifndef CONTINUABLE_DETAIL_TESTING_HPP_INCLUDED__
|
||||
#define CONTINUABLE_DETAIL_TESTING_HPP_INCLUDED__
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <continuable/continuable-base.hpp>
|
||||
#include <continuable/detail/api.hpp>
|
||||
#include <continuable/detail/traits.hpp>
|
||||
#include <continuable/detail/types.hpp>
|
||||
#include <continuable/detail/util.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
@ -41,12 +47,36 @@ namespace testing {
|
||||
template <typename C>
|
||||
void assert_async_completion(C&& continuable) {
|
||||
auto called = std::make_shared<bool>(false);
|
||||
std::forward<C>(continuable).then([called](auto&&... args) {
|
||||
std::forward<C>(continuable)
|
||||
.then([called](auto&&... args) {
|
||||
ASSERT_FALSE(*called);
|
||||
*called = true;
|
||||
|
||||
// Workaround for our known GCC bug.
|
||||
util::unused(std::forward<decltype(args)>(args)...);
|
||||
})
|
||||
.fail([](cti::error_type /*error*/) {
|
||||
// ...
|
||||
FAIL();
|
||||
});
|
||||
|
||||
ASSERT_TRUE(*called);
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
void assert_async_exception_completion(C&& continuable) {
|
||||
auto called = std::make_shared<bool>(false);
|
||||
std::forward<C>(continuable)
|
||||
.then([](auto&&... args) {
|
||||
// Workaround for our known GCC bug.
|
||||
util::unused(std::forward<decltype(args)>(args)...);
|
||||
|
||||
// ...
|
||||
FAIL();
|
||||
})
|
||||
.fail([called](cti::error_type /*error*/) {
|
||||
ASSERT_FALSE(*called);
|
||||
*called = true;
|
||||
});
|
||||
|
||||
ASSERT_TRUE(*called);
|
||||
@ -54,10 +84,15 @@ void assert_async_completion(C&& continuable) {
|
||||
|
||||
template <typename C>
|
||||
void assert_async_never_completed(C&& continuable) {
|
||||
std::forward<C>(continuable).then([](auto&&... args) {
|
||||
std::forward<C>(continuable)
|
||||
.then([](auto&&... args) {
|
||||
// Workaround for our known GCC bug.
|
||||
util::unused(std::forward<decltype(args)>(args)...);
|
||||
|
||||
FAIL();
|
||||
})
|
||||
.fail([](cti::error_type /*error*/) {
|
||||
// ...
|
||||
FAIL();
|
||||
});
|
||||
}
|
||||
@ -94,6 +129,43 @@ void assert_async_binary_validation(V&& validator, C&& continuable,
|
||||
});
|
||||
}
|
||||
|
||||
/// Expects that the continuable is finished with the given arguments
|
||||
template <typename V, typename C, typename Args>
|
||||
void assert_async_binary_exception_validation(V&& validator, C&& continuable,
|
||||
Args&& expected) {
|
||||
auto called = std::make_shared<bool>(false);
|
||||
std::forward<C>(continuable)
|
||||
.then([](auto&&... args) {
|
||||
// Workaround for our known GCC bug.
|
||||
util::unused(std::forward<decltype(args)>(args)...);
|
||||
|
||||
// ...
|
||||
FAIL();
|
||||
})
|
||||
.fail([
|
||||
called, validator = std::forward<decltype(validator)>(validator),
|
||||
expected = std::forward<decltype(expected)>(expected)
|
||||
](types::error_type error) {
|
||||
ASSERT_FALSE(*called);
|
||||
*called = true;
|
||||
|
||||
#if !defined(CONTINUABLE_WITH_CUSTOM_ERROR_TYPE) && \
|
||||
!defined(CONTINUABLE_WITH_NO_EXCEPTIONS)
|
||||
try {
|
||||
std::rethrow_exception(error);
|
||||
} catch (std::decay_t<decltype(expected)> const& exception) {
|
||||
validator(exception, expected);
|
||||
} catch (...) {
|
||||
FAIL();
|
||||
}
|
||||
#else
|
||||
validator(error, expected);
|
||||
#endif
|
||||
});
|
||||
|
||||
ASSERT_TRUE(*called);
|
||||
}
|
||||
|
||||
inline auto expecting_eq_check() {
|
||||
return [](auto&& expected, auto&& actual) {
|
||||
EXPECT_EQ(std::forward<decltype(expected)>(expected),
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
#define CONTINUABLE_DETAIL_TRAITS_HPP_INCLUDED__
|
||||
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@ -347,8 +348,8 @@ constexpr void static_for_each_in(Sequenceable&& sequenceable,
|
||||
unpack(
|
||||
std::forward<Sequenceable>(sequenceable), [&](auto&&... entries) mutable {
|
||||
// Apply the consume function to every entry inside the pack
|
||||
(void)std::initializer_list<int>{0,
|
||||
((void)handler(std::forward<decltype(entries)>(entries)), 0)...};
|
||||
(void)std::initializer_list<int>{
|
||||
0, ((void)handler(std::forward<decltype(entries)>(entries)), 0)...};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
#ifndef CONTINUABLE_DETAIL_UTIL_HPP_INCLUDED__
|
||||
#define CONTINUABLE_DETAIL_UTIL_HPP_INCLUDED__
|
||||
|
||||
#include <cassert>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@ -45,14 +46,7 @@ namespace detail {
|
||||
namespace util {
|
||||
/// Helper to trick compilers about that a parameter pack is used
|
||||
template <typename... T>
|
||||
void unused(T&&... args) {
|
||||
auto use = [](auto&& type) mutable {
|
||||
(void)type;
|
||||
return 0;
|
||||
};
|
||||
auto deduce = {0, use(std::forward<decltype(args)>(args))...};
|
||||
(void)deduce;
|
||||
(void)use;
|
||||
void unused(T&&...) {
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
@ -21,10 +21,53 @@
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <continuable/detail/features.hpp>
|
||||
|
||||
#include "test-continuable.hpp"
|
||||
|
||||
TYPED_TEST(single_dimension_tests, are_using_errors) {
|
||||
/*ASSERT_ASYNC_ERROR(this->supply().then([] {
|
||||
return; // void
|
||||
}));*/
|
||||
#if !defined(CONTINUABLE_WITH_NO_EXCEPTIONS)
|
||||
struct test_exception : std::exception {
|
||||
explicit test_exception() {
|
||||
}
|
||||
|
||||
bool operator==(test_exception const&) const noexcept {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static auto get_test_exception_proto() {
|
||||
return test_exception{};
|
||||
}
|
||||
|
||||
static auto supply_test_exception() {
|
||||
try {
|
||||
throw get_test_exception_proto();
|
||||
} catch (...) {
|
||||
return std::current_exception();
|
||||
}
|
||||
}
|
||||
#else
|
||||
struct my_error_category : std::error_category {
|
||||
const char* name() const override noexcept {return "generic name"}
|
||||
|
||||
std::string message(int) const override {
|
||||
return "generic"
|
||||
}
|
||||
};
|
||||
|
||||
static auto get_test_exception_proto() {
|
||||
static const my_error_category cat;
|
||||
return std::error_condition(123, cat);
|
||||
}
|
||||
|
||||
static auto supply_test_exception() {
|
||||
return get_test_exception_proto();
|
||||
}
|
||||
#endif
|
||||
|
||||
TYPED_TEST(single_dimension_tests, are_using_errors) {
|
||||
ASSERT_ASYNC_EXCEPTION_COMPLETION(
|
||||
this->supply_exception(supply_test_exception()));
|
||||
}
|
||||
|
||||
@ -24,57 +24,15 @@
|
||||
#ifndef TEST_CONTINUABLE_HPP__
|
||||
#define TEST_CONTINUABLE_HPP__
|
||||
|
||||
#if UNIT_TEST_STEP >= 3
|
||||
#define THIRD_PARTY_TESTS
|
||||
#endif
|
||||
|
||||
#ifdef THIRD_PARTY_TESTS
|
||||
// #if _MSC_VER
|
||||
// #pragma warning(push, 0)
|
||||
// #endif
|
||||
#endif // THIRD_PARTY_TESTS
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "continuable/continuable-base.hpp"
|
||||
#include "continuable/continuable-testing.hpp"
|
||||
#include "continuable/continuable.hpp"
|
||||
#include "gtest/gtest.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#ifdef THIRD_PARTY_TESTS
|
||||
|
||||
#include "cxx_function/cxx_function.hpp"
|
||||
|
||||
template <typename T>
|
||||
using cxx_function_fn = cxx_function::function<T>;
|
||||
|
||||
template <typename... Args>
|
||||
using cxx_trait_of =
|
||||
cti::continuable_trait<cxx_function_fn, cxx_function_fn, Args...>;
|
||||
|
||||
template <typename... Args>
|
||||
using cxx_continuable = typename cxx_trait_of<Args...>::continuable;
|
||||
|
||||
template <typename T>
|
||||
using cxx_function_unique_fn = cxx_function::unique_function<T>;
|
||||
|
||||
template <typename... Args>
|
||||
using unique_cxx_trait_of =
|
||||
cti::continuable_trait<cxx_function_unique_fn, cxx_function_unique_fn,
|
||||
Args...>;
|
||||
|
||||
template <typename... Args>
|
||||
using cxx_unique_continuable =
|
||||
typename unique_cxx_trait_of<Args...>::continuable;
|
||||
#endif // THIRD_PARTY_TESTS
|
||||
|
||||
template <typename... Args>
|
||||
using std_trait_of =
|
||||
cti::continuable_trait<std::function, std::function, Args...>;
|
||||
|
||||
template <typename... Args>
|
||||
using std_continuable = typename std_trait_of<Args...>::continuable;
|
||||
#include <continuable/continuable-base.hpp>
|
||||
#include <continuable/continuable-testing.hpp>
|
||||
#include <continuable/continuable.hpp>
|
||||
|
||||
using cti::detail::traits::identity;
|
||||
|
||||
@ -96,6 +54,13 @@ auto supplier_of(Args&&... args) {
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Arg>
|
||||
auto exception_supplier_of(Arg&& arg) {
|
||||
return [arg = std::forward<Arg>(arg)](auto&& promise) mutable {
|
||||
promise.set_exception(std::move(arg));
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Provider>
|
||||
class continuation_provider : public ::testing::Test, public Provider {
|
||||
public:
|
||||
@ -115,6 +80,15 @@ public:
|
||||
return this->make(arg_types, hint_types,
|
||||
supplier_of(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template <typename Arg>
|
||||
auto supply_exception(Arg&& arg) {
|
||||
identity<> arg_types;
|
||||
auto hint_types = to_hint(arg_types);
|
||||
|
||||
return this->make(arg_types, hint_types,
|
||||
exception_supplier_of(std::forward<Arg>(arg)));
|
||||
}
|
||||
};
|
||||
|
||||
inline auto empty_caller() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user