mirror of
https://github.com/Naios/continuable.git
synced 2026-02-16 23:29:48 +08:00
Rework the expected_trait
* Add tests for the new expected public interface
This commit is contained in:
parent
c76fe9e973
commit
867ab38b8e
@ -35,6 +35,7 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <continuable/continuable-expected.hpp>
|
||||||
#include <continuable/continuable-primitives.hpp>
|
#include <continuable/continuable-primitives.hpp>
|
||||||
#include <continuable/detail/connection/connection-all.hpp>
|
#include <continuable/detail/connection/connection-all.hpp>
|
||||||
#include <continuable/detail/connection/connection-any.hpp>
|
#include <continuable/detail/connection/connection-any.hpp>
|
||||||
@ -898,15 +899,15 @@ constexpr auto make_exceptional_continuable(Exception&& exception) {
|
|||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
auto recover(Args&&... args) {
|
auto recover(Args&&... args) {
|
||||||
// TODO
|
return make_expected(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto rethrow(exception_t exception) {
|
inline auto rethrow(exception_t exception) {
|
||||||
// TODO
|
return make_exceptional_expected(std::move(exception));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline constexpr auto cancel() {
|
inline auto cancel() {
|
||||||
// TODO
|
return make_none_expected();
|
||||||
}
|
}
|
||||||
/// \}
|
/// \}
|
||||||
} // namespace cti
|
} // namespace cti
|
||||||
|
|||||||
@ -34,14 +34,71 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <continuable/continuable-primitives.hpp>
|
#include <continuable/continuable-primitives.hpp>
|
||||||
|
#include <continuable/detail/utility/expected-traits.hpp>
|
||||||
#include <continuable/detail/utility/flat-variant.hpp>
|
#include <continuable/detail/utility/flat-variant.hpp>
|
||||||
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
|
/// A class which is convertible to any expected and that definitly holds no
|
||||||
|
/// value so the real expected gets invalidated when
|
||||||
|
/// this object is passed to it
|
||||||
|
struct empty_expected {
|
||||||
|
empty_expected() = default;
|
||||||
|
empty_expected(empty_expected const&) = default;
|
||||||
|
empty_expected(empty_expected&&) = default;
|
||||||
|
empty_expected& operator=(empty_expected const&) = default;
|
||||||
|
empty_expected& operator=(empty_expected&&) = default;
|
||||||
|
~empty_expected() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A class which is convertible to any expected and that definitly holds
|
||||||
|
/// an exception which is then passed to the converted expected object.
|
||||||
|
class exceptional_expected {
|
||||||
|
exception_t exception_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
exceptional_expected() = delete;
|
||||||
|
exceptional_expected(exceptional_expected const&) = default;
|
||||||
|
exceptional_expected(exceptional_expected&&) = default;
|
||||||
|
exceptional_expected& operator=(exceptional_expected const&) = default;
|
||||||
|
exceptional_expected& operator=(exceptional_expected&&) = default;
|
||||||
|
~exceptional_expected() = default;
|
||||||
|
|
||||||
|
explicit exceptional_expected(exception_t exception)
|
||||||
|
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
|
||||||
|
: exception_(std::move(exception)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
exceptional_expected& operator=(exception_t exception) {
|
||||||
|
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
|
||||||
|
exception_ = std::move(exception);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_exception(exception_t exception) {
|
||||||
|
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
|
||||||
|
exception_ = std::move(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
exception_t& get_exception() & noexcept {
|
||||||
|
return exception_;
|
||||||
|
}
|
||||||
|
exception_t const& get_exception() const& noexcept {
|
||||||
|
return exception_;
|
||||||
|
}
|
||||||
|
exception_t&& get_exception() && noexcept {
|
||||||
|
return std::move(exception_);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// A class similar to the one in the expected proposal,
|
/// A class similar to the one in the expected proposal,
|
||||||
/// however it's capable of carrying an exception_t.
|
/// however it's capable of carrying an exception_t.
|
||||||
template <typename T>
|
template <typename... T>
|
||||||
class expected {
|
class expected {
|
||||||
detail::container::flat_variant<T, exception_t> variant_;
|
using trait = detail::expected_trait<T...>;
|
||||||
|
using value_t = typename trait::value_t;
|
||||||
|
|
||||||
|
detail::container::flat_variant<value_t, exception_t> variant_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit expected() = default;
|
explicit expected() = default;
|
||||||
@ -51,32 +108,39 @@ public:
|
|||||||
expected& operator=(expected&&) = default;
|
expected& operator=(expected&&) = default;
|
||||||
~expected() = default;
|
~expected() = default;
|
||||||
|
|
||||||
explicit expected(T value) : variant_(std::move(value)) {
|
explicit expected(T... values) : variant_(trait::wrap(std::move(values)...)) {
|
||||||
}
|
}
|
||||||
explicit expected(exception_t exception) : variant_(std::move(exception)) {
|
explicit expected(exception_t exception) : variant_(std::move(exception)) {
|
||||||
}
|
}
|
||||||
|
explicit expected(empty_expected){};
|
||||||
|
explicit expected(exceptional_expected exceptional_expected)
|
||||||
|
: variant_(std::move(exceptional_expected.get_exception())) {
|
||||||
|
}
|
||||||
|
|
||||||
expected& operator=(T value) {
|
expected& operator=(empty_expected) {
|
||||||
variant_ = std::move(value);
|
set_empty();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
expected& operator=(exception_t exception) {
|
expected& operator=(exceptional_expected exceptional_expected) {
|
||||||
variant_ = std::move(exception);
|
set_exception(std::move(exceptional_expected.get_exception()));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_value(T value) {
|
void set_empty() {
|
||||||
variant_ = std::move(value);
|
variant_.set_empty();
|
||||||
|
}
|
||||||
|
void set_value(T... values) {
|
||||||
|
variant_ = std::move(values...);
|
||||||
}
|
}
|
||||||
void set_exception(exception_t exception) {
|
void set_exception(exception_t exception) {
|
||||||
variant_ = std::move(exception);
|
variant_ = std::move(exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_empty() {
|
bool is_empty() const noexcept {
|
||||||
return variant_.is_empty();
|
return variant_.is_empty();
|
||||||
}
|
}
|
||||||
bool is_value() const noexcept {
|
bool is_value() const noexcept {
|
||||||
return variant_.template is<T>();
|
return variant_.template is<value_t>();
|
||||||
}
|
}
|
||||||
bool is_exception() const noexcept {
|
bool is_exception() const noexcept {
|
||||||
return variant_.template is<exception_t>();
|
return variant_.template is<exception_t>();
|
||||||
@ -86,26 +150,49 @@ public:
|
|||||||
return is_value();
|
return is_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
T& get_value() noexcept {
|
value_t& get_value() & noexcept {
|
||||||
return variant_.template cast<T>();
|
return variant_.template cast<value_t>();
|
||||||
}
|
}
|
||||||
T const& get_value() const noexcept {
|
value_t const& get_value() const& noexcept {
|
||||||
return variant_.template cast<T>();
|
return variant_.template cast<value_t>();
|
||||||
}
|
}
|
||||||
exception_t& get_exception() noexcept {
|
value_t&& get_value() && noexcept {
|
||||||
|
return std::move(variant_).template cast<value_t>();
|
||||||
|
}
|
||||||
|
exception_t& get_exception() & noexcept {
|
||||||
return variant_.template cast<exception_t>();
|
return variant_.template cast<exception_t>();
|
||||||
}
|
}
|
||||||
exception_t const& get_exception() const noexcept {
|
exception_t const& get_exception() const& noexcept {
|
||||||
return variant_.template cast<exception_t>();
|
return variant_.template cast<exception_t>();
|
||||||
}
|
}
|
||||||
|
exception_t&& get_exception() && noexcept {
|
||||||
|
return std::move(variant_).template cast<exception_t>();
|
||||||
|
}
|
||||||
|
|
||||||
T& operator*() noexcept {
|
value_t& operator*() & noexcept {
|
||||||
return get_value();
|
return get_value();
|
||||||
}
|
}
|
||||||
T const& operator*() const noexcept {
|
value_t const& operator*() const& noexcept {
|
||||||
return get_value();
|
return get_value();
|
||||||
}
|
}
|
||||||
|
value_t&& operator*() && noexcept {
|
||||||
|
return std::move(*this).get_value();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
constexpr auto make_expected(T&&... values) {
|
||||||
|
return expected<detail::traits::unrefcv_t<T>...>(std::forward<T>(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto make_exceptional_expected(exception_t exception) {
|
||||||
|
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
|
||||||
|
return exceptional_expected(std::move(exception));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto make_empty_expected() {
|
||||||
|
return empty_expected{};
|
||||||
|
}
|
||||||
} // namespace cti
|
} // namespace cti
|
||||||
|
|
||||||
#endif // CONTINUABLE_EXPECTED_HPP_INCLUDED
|
#endif // CONTINUABLE_EXPECTED_HPP_INCLUDED
|
||||||
|
|||||||
@ -342,7 +342,7 @@ inline auto make_error_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
|
||||||
// NOLINTNEXTLINE(hicpp-move-const-arg)
|
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
|
||||||
std::forward<decltype(callback)>(callback)(std::move(error));
|
std::forward<decltype(callback)>(callback)(std::move(error));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -352,7 +352,8 @@ inline auto make_error_invoker(
|
|||||||
// Errors are not partial invoked
|
// Errors are not partial invoked
|
||||||
std::forward<decltype(callback)>(callback)(
|
std::forward<decltype(callback)>(callback)(
|
||||||
exception_arg_t{},
|
exception_arg_t{},
|
||||||
std::move(error)); // NOLINT(hicpp-move-const-arg)
|
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
|
||||||
|
std::move(error));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -58,7 +58,9 @@ using std::experimental::coroutine_handle;
|
|||||||
/// for waiting on a continuable in a stackless coroutine.
|
/// for waiting on a continuable in a stackless coroutine.
|
||||||
template <typename Continuable>
|
template <typename Continuable>
|
||||||
class awaitable {
|
class awaitable {
|
||||||
using trait_t = container::expected_result_trait_t<Continuable>;
|
using hint_t = decltype(hints::hint_of(traits::identify<Continuable>{}));
|
||||||
|
using trait_t = expected_trait<hint_t>;
|
||||||
|
using value_t = expected_trait<hint_t>;
|
||||||
|
|
||||||
/// The continuable which is invoked upon suspension
|
/// The continuable which is invoked upon suspension
|
||||||
Continuable continuable_;
|
Continuable continuable_;
|
||||||
|
|||||||
@ -31,63 +31,41 @@
|
|||||||
#ifndef CONTINUABLE_DETAIL_EXPECTED_TRAITS_HPP_INCLUDED
|
#ifndef CONTINUABLE_DETAIL_EXPECTED_TRAITS_HPP_INCLUDED
|
||||||
#define CONTINUABLE_DETAIL_EXPECTED_TRAITS_HPP_INCLUDED
|
#define CONTINUABLE_DETAIL_EXPECTED_TRAITS_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <continuable/continuable-expected.hpp>
|
|
||||||
#include <continuable/detail/core/hints.hpp>
|
#include <continuable/detail/core/hints.hpp>
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
namespace container {
|
template <typename... T>
|
||||||
namespace detail {
|
struct expected_trait;
|
||||||
struct void_guard_tag {};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct expected_result_trait;
|
|
||||||
template <>
|
template <>
|
||||||
struct expected_result_trait<traits::identity<>> {
|
struct expected_trait<traits::identity<>> {
|
||||||
using expected_type = expected<void_guard_tag>;
|
struct value_t {};
|
||||||
|
|
||||||
static constexpr void_guard_tag wrap() noexcept {
|
static constexpr value_t wrap() noexcept {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
static void unwrap(expected_type&& e) {
|
|
||||||
assert(e.is_value());
|
|
||||||
(void)e;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct expected_result_trait<traits::identity<T>> {
|
struct expected_trait<T> {
|
||||||
using expected_type = expected<T>;
|
using value_t = T;
|
||||||
|
|
||||||
static auto wrap(T arg) {
|
static auto wrap(T arg) {
|
||||||
return std::move(arg);
|
return std::move(arg);
|
||||||
}
|
}
|
||||||
static auto unwrap(expected_type&& e) {
|
|
||||||
assert(e.is_value());
|
|
||||||
return std::move(e.get_value());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
template <typename First, typename Second, typename... Rest>
|
template <typename First, typename Second, typename... Rest>
|
||||||
struct expected_result_trait<traits::identity<First, Second, Rest...>> {
|
struct expected_trait<First, Second, Rest...> {
|
||||||
using expected_type = expected<std::tuple<First, Second, Rest...>>;
|
using value_t = std::tuple<First, Second, Rest...>;
|
||||||
|
|
||||||
static auto wrap(First first, Second second, Rest... rest) {
|
static auto wrap(First first, Second second, Rest... rest) {
|
||||||
return std::make_tuple(std::move(first), std::move(second),
|
return std::make_tuple(std::move(first), std::move(second),
|
||||||
std::move(rest)...);
|
std::move(rest)...);
|
||||||
}
|
}
|
||||||
static auto unwrap(expected_type&& e) {
|
|
||||||
assert(e.is_value());
|
|
||||||
return std::move(e.get_value());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <typename Continuable>
|
|
||||||
using expected_result_trait_t = detail::expected_result_trait<decltype(
|
|
||||||
hints::hint_of(traits::identify<Continuable>{}))>;
|
|
||||||
} // namespace container
|
|
||||||
} // namespace detail
|
|
||||||
} // namespace cti
|
} // namespace cti
|
||||||
|
|
||||||
#endif // CONTINUABLE_DETAIL_EXPECTED_TRAITS_HPP_INCLUDED
|
#endif // CONTINUABLE_DETAIL_EXPECTED_TRAITS_HPP_INCLUDED
|
||||||
|
|||||||
@ -267,6 +267,11 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_empty() {
|
||||||
|
weak_destroy();
|
||||||
|
set_slot(detail::empty_slot::value);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename V, std::size_t Index =
|
template <typename V, std::size_t Index =
|
||||||
traits::index_of_t<std::decay_t<V>, T...>::value>
|
traits::index_of_t<std::decay_t<V>, T...>::value>
|
||||||
bool is() const noexcept {
|
bool is() const noexcept {
|
||||||
@ -282,17 +287,24 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename V>
|
template <typename V>
|
||||||
V& cast() noexcept {
|
V& cast() & noexcept {
|
||||||
assert(is_slot(traits::index_of_t<std::decay_t<V>, T...>::value));
|
assert(is_slot(traits::index_of_t<std::decay_t<V>, T...>::value));
|
||||||
return *reinterpret_cast<std::decay_t<V>*>(&this->storage_);
|
return *reinterpret_cast<std::decay_t<V>*>(&this->storage_);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename V>
|
template <typename V>
|
||||||
V const& cast() const noexcept {
|
V const& cast() const& noexcept {
|
||||||
assert(is_slot(traits::index_of_t<std::decay_t<V>, T...>::value));
|
assert(is_slot(traits::index_of_t<std::decay_t<V>, T...>::value));
|
||||||
return *reinterpret_cast<std::decay_t<V> const*>(&this->storage_);
|
return *reinterpret_cast<std::decay_t<V> const*>(&this->storage_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename V>
|
||||||
|
V&& cast() && noexcept {
|
||||||
|
assert(is_slot(traits::index_of_t<std::decay_t<V>, T...>::value));
|
||||||
|
auto& value = *reinterpret_cast<std::decay_t<V> const*>(&this->storage_);
|
||||||
|
return std::move(value);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename C, typename V>
|
template <typename C, typename V>
|
||||||
static void visit_dispatch(flat_variant* me, V&& visitor) {
|
static void visit_dispatch(flat_variant* me, V&& visitor) {
|
||||||
|
|||||||
@ -51,6 +51,7 @@ foreach(STEP RANGE ${STEP_RANGE})
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-base-destruct.cpp
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-base-destruct.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-base-errors.cpp
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-base-errors.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-base-partial.cpp
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-base-partial.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-base-multipath.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-all-seq-ag-1.cpp
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-all-seq-ag-1.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-all-seq-ag-2.cpp
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-all-seq-ag-2.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-all-seq-op.cpp
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-all-seq-op.cpp
|
||||||
|
|||||||
30
test/unit-test/multi/test-continuable-base-multipath.cpp
Normal file
30
test/unit-test/multi/test-continuable-base-multipath.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files(the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions :
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <test-continuable.hpp>
|
||||||
|
|
||||||
|
TYPED_TEST(single_dimension_tests, are_recoverable) {
|
||||||
|
EXPECT_ASYNC_RESULT(this->supply().then([] () -> cti::expected<> {
|
||||||
|
return; // void
|
||||||
|
}));
|
||||||
|
}
|
||||||
@ -23,12 +23,12 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <continuable/continuable-expected.hpp>
|
||||||
#include <continuable/detail/core/types.hpp>
|
#include <continuable/detail/core/types.hpp>
|
||||||
#include <continuable/detail/utility/expected.hpp>
|
|
||||||
#include <test-continuable.hpp>
|
#include <test-continuable.hpp>
|
||||||
|
|
||||||
using cti::detail::container::expected;
|
|
||||||
using cti::exception_t;
|
using cti::exception_t;
|
||||||
|
using cti::expected;
|
||||||
|
|
||||||
static int const CANARY = 373671;
|
static int const CANARY = 373671;
|
||||||
|
|
||||||
@ -125,27 +125,6 @@ TYPED_TEST(expected_all_tests, is_error_move_assignable) {
|
|||||||
EXPECT_TRUE(e.is_exception());
|
EXPECT_TRUE(e.is_exception());
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(expected_all_tests, is_value_assignable) {
|
|
||||||
{
|
|
||||||
TypeParam e;
|
|
||||||
e = this->supply(CANARY);
|
|
||||||
|
|
||||||
EXPECT_TRUE(bool(e));
|
|
||||||
EXPECT_EQ(this->get(*e), CANARY);
|
|
||||||
EXPECT_TRUE(e.is_value());
|
|
||||||
EXPECT_FALSE(e.is_exception());
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
TypeParam e;
|
|
||||||
e = exception_t{};
|
|
||||||
|
|
||||||
EXPECT_FALSE(bool(e));
|
|
||||||
EXPECT_FALSE(e.is_value());
|
|
||||||
EXPECT_TRUE(e.is_exception());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(expected_copyable_tests, is_copy_constructible) {
|
TEST(expected_copyable_tests, is_copy_constructible) {
|
||||||
{
|
{
|
||||||
copyable_type const e_old(CANARY);
|
copyable_type const e_old(CANARY);
|
||||||
@ -190,6 +169,64 @@ TEST(expected_copyable_tests, is_copy_assignable) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(expected_all_tests, is_constructible_from_error_helper) {
|
||||||
|
cti::exceptional_expected e1(exception_t{});
|
||||||
|
{
|
||||||
|
auto e2 = e1;
|
||||||
|
}
|
||||||
|
auto e2 = std::move(e1);
|
||||||
|
|
||||||
|
TypeParam e(std::move(e2));
|
||||||
|
|
||||||
|
EXPECT_FALSE(bool(e));
|
||||||
|
EXPECT_FALSE(e.is_value());
|
||||||
|
EXPECT_TRUE(e.is_exception());
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(expected_all_tests, is_assignable_from_error_helper) {
|
||||||
|
cti::exceptional_expected e1(exception_t{});
|
||||||
|
{
|
||||||
|
auto e2 = e1;
|
||||||
|
}
|
||||||
|
auto e2 = std::move(e1);
|
||||||
|
|
||||||
|
TypeParam e;
|
||||||
|
e = std::move(e2);
|
||||||
|
|
||||||
|
EXPECT_FALSE(bool(e));
|
||||||
|
EXPECT_FALSE(e.is_value());
|
||||||
|
EXPECT_TRUE(e.is_exception());
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(expected_all_tests, is_constructible_from_empty_helper) {
|
||||||
|
cti::empty_expected e1;
|
||||||
|
{
|
||||||
|
auto e2 = e1;
|
||||||
|
}
|
||||||
|
auto e2 = std::move(e1);
|
||||||
|
|
||||||
|
TypeParam e(std::move(e2));
|
||||||
|
|
||||||
|
EXPECT_FALSE(bool(e));
|
||||||
|
EXPECT_FALSE(e.is_value());
|
||||||
|
EXPECT_TRUE(e.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(expected_all_tests, is_assignable_from_empty_helper) {
|
||||||
|
cti::empty_expected e1;
|
||||||
|
{
|
||||||
|
auto e2 = e1;
|
||||||
|
}
|
||||||
|
auto e2 = std::move(e1);
|
||||||
|
|
||||||
|
TypeParam e;
|
||||||
|
e = std::move(e2);
|
||||||
|
|
||||||
|
EXPECT_FALSE(bool(e));
|
||||||
|
EXPECT_FALSE(e.is_value());
|
||||||
|
EXPECT_TRUE(e.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
// This regression test shows a memory leak which happens when using the
|
// This regression test shows a memory leak which happens when using the
|
||||||
// expected class move constructed from another expected object.
|
// expected class move constructed from another expected object.
|
||||||
TEST(expected_single_test, test_leak_regression) {
|
TEST(expected_single_test, test_leak_regression) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user