Add error handling testing

This commit is contained in:
Denis Blank 2017-10-03 21:49:07 +02:00
parent 60c73a1a48
commit 4d964b0fe2
6 changed files with 188 additions and 78 deletions

View File

@ -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__

View File

@ -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),

View File

@ -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)...};
});
}

View File

@ -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 {

View File

@ -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()));
}

View File

@ -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() {