//! \file test_expected.cpp // Copyright Pierre Talbot 2013. // Copyright Vicente J. Botet Escriba 2013,2014. // Use, modification and distribution are subject to the // Boost Software License, Version 1.0. //(See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // Notes by ned: // Original is at https://github.com/viboes/std-make/blob/master/test/expected/expected_pass.cpp // This edition modified to use result with throw_bad_result_access policy // Quite a lot of the test suite I had to disable, not because our Expected implementation is // incorrect, but because the reference test suite is testing an Expected quite far away from // the latest WG21 proposal paper, and we're implementing that latest edition. #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 7 #include #include #include #define QUICKCPPLIB_BOOST_UNIT_TEST_CUSTOM_MAIN_DEFINED #include #include #define JASEL_NORETURN #ifndef BOOST_TEST #define BOOST_TEST(expr) BOOST_CHECK(expr) #endif #ifndef BOOST_TEST_EQ #define BOOST_TEST_EQ(a, b) BOOST_CHECK_EQUAL((a), (b)) #endif #ifndef BOOST_TEST_THROWS #define BOOST_TEST_THROWS(expr, ex) BOOST_CHECK_THROW((expr), ex) #endif #ifndef BOOST_CONSTEXPR #define BOOST_CONSTEXPR constexpr #endif #ifdef _MSC_VER #pragma warning(disable : 4127) // conditional expression is constant #pragma warning(disable : 4244) // conversion from int to short #endif namespace stde { #if __cplusplus >= 201700 || _HAS_CXX17 using in_place_t = std::in_place_t; using std::in_place; #else struct in_place_t { explicit in_place_t() = default; }; constexpr in_place_t in_place{}; #endif //! [expected_implementation] /* Here is a fairly conforming implementation of P0323R3 `expected` using `checked`. It passes the reference test suite for P0323R3 at https://github.com/viboes/std-make/blob/master/test/expected/expected_pass.cpp with modifications only to move the test much closer to the P0323R3 Expected, as the reference test suite is for a much older proposed Expected. Known differences from P0323R3 in this implementation: - `T` and `E` cannot be the same type. - No variant storage is implemented. */ namespace detail { template using expected_result = BOOST_OUTCOME_V2_NAMESPACE::checked; template struct enable_default_constructor : public expected_result { using base = expected_result; using base::base; constexpr enable_default_constructor() : base{BOOST_OUTCOME_V2_NAMESPACE::in_place_type} { } }; template using select_expected_base = std::conditional_t::value, enable_default_constructor, expected_result>; } // namespace detail template class expected : public detail::select_expected_base { static_assert(!std::is_same::value, "T and E cannot be the same in this expected implementation"); using base = detail::select_expected_base; public: // Inherit base's constructors using base::base; expected() = default; // Expected takes in_place not in_place_type template constexpr explicit expected(in_place_t /*unused*/, Args &&... args) : base{BOOST_OUTCOME_V2_NAMESPACE::in_place_type, std::forward(args)...} { } // Expected always accepts a T even if ambiguous BOOST_OUTCOME_TEMPLATE(class U) BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(std::is_constructible::value)) constexpr expected(U &&v) // NOLINT : base{BOOST_OUTCOME_V2_NAMESPACE::in_place_type, std::forward(v)} { } // Expected has an emplace() modifier template void emplace(Args &&... args) { *static_cast(this) = base{BOOST_OUTCOME_V2_NAMESPACE::in_place_type, std::forward(args)...}; } // Expected has a narrow operator* and operator-> constexpr const T &operator*() const & { return base::assume_value(); } constexpr T &operator*() & { return base::assume_value(); } constexpr const T &&operator*() const && { return base::assume_value(); } constexpr T &&operator*() && { return base::assume_value(); } constexpr const T *operator->() const { return &base::assume_value(); } constexpr T *operator->() { return &base::assume_value(); } // Expected has a narrow error() observer constexpr const E &error() const & { return base::assume_error(); } constexpr E &error() & { return base::assume_error(); } constexpr const E &&error() const && { return base::assume_error(); } constexpr E &error() && { return base::assume_error(); } }; template class expected : public BOOST_OUTCOME_V2_NAMESPACE::result> { using base = BOOST_OUTCOME_V2_NAMESPACE::result>; public: // Inherit base constructors using base::base; // Expected has a narrow operator* and operator-> constexpr void operator*() const { base::assume_value(); } constexpr void operator->() const { base::assume_value(); } }; template using unexpected = BOOST_OUTCOME_V2_NAMESPACE::failure_type; template unexpected make_unexpected(E &&arg) { return BOOST_OUTCOME_V2_NAMESPACE::failure(std::forward(arg)); } template unexpected make_unexpected(Args &&... args) { return BOOST_OUTCOME_V2_NAMESPACE::failure(std::forward(args)...); } template using bad_expected_access = BOOST_OUTCOME_V2_NAMESPACE::bad_result_access_with; //! [expected_implementation] // Not actually part of the Expected proposal, but needed to pass the test template using exception_or = expected; } // namespace stde template using expected_sc = stde::expected; struct NoDefaultConstructible { NoDefaultConstructible() = delete; NoDefaultConstructible(int /*unused*/) {} // NOLINT }; struct NoCopyConstructible { NoCopyConstructible() = default; NoCopyConstructible(NoCopyConstructible const &) = delete; NoCopyConstructible(NoCopyConstructible &&) noexcept = default; }; struct NoMoveConstructible { NoMoveConstructible() = default; NoMoveConstructible(NoMoveConstructible const &) noexcept = default; NoMoveConstructible(NoMoveConstructible &&) = delete; NoMoveConstructible &operator=(NoMoveConstructible const &) noexcept = default; NoMoveConstructible &operator=(NoMoveConstructible &&) = delete; }; enum State { sDefaultConstructed, sValueCopyConstructed, sValueMoveConstructed, sCopyConstructed, sMoveConstructed, sMoveAssigned, sCopyAssigned, sValueCopyAssigned, sValueMoveAssigned, sMovedFrom, sValueConstructed }; struct OracleVal { State s{sValueConstructed}; int i; constexpr OracleVal(int i_ = 0) // NOLINT : i(i_) { } }; struct Oracle { State s{sDefaultConstructed}; OracleVal val; Oracle() = default; Oracle(const OracleVal &v) // NOLINT : s(sValueCopyConstructed), val(v) { } Oracle(OracleVal &&v) noexcept : s(sValueMoveConstructed), val(v) { v.s = sMovedFrom; } // NOLINT Oracle(const Oracle &o) : s(sCopyConstructed) , val(o.val) { } Oracle(Oracle &&o) noexcept : s(sMoveConstructed), val(std::move(o.val)) { o.s = sMovedFrom; } // NOLINT Oracle &operator=(const OracleVal &v) { s = sValueCopyConstructed; val = v; return *this; } Oracle &operator=(OracleVal &&v) noexcept { s = sValueMoveConstructed; val = std::move(v); // NOLINT v.s = sMovedFrom; return *this; } Oracle &operator=(const Oracle &o) { s = sCopyConstructed; val = o.val; return *this; } Oracle &operator=(Oracle &&o) noexcept { s = sMoveConstructed; val = std::move(o.val); // NOLINT o.s = sMovedFrom; return *this; } }; struct Guard { std::string val; Guard() = default; explicit Guard(std::string s, int /*unused*/ = 0) : val(std::move(s)) { } Guard(const Guard &) = delete; Guard(Guard &&) = delete; void operator=(const Guard &) = delete; void operator=(Guard &&) = delete; }; struct ExplicitStr { std::string s; explicit ExplicitStr(const char *chp) : s(chp) { } }; struct Date { int i; Date() = delete; Date(int i_) noexcept : i{i_} {} // NOLINT Date(Date &&d) noexcept : i(d.i) { d.i = 0; } Date(const Date &) = delete; Date &operator=(const Date &) = delete; Date &operator=(Date &&d) noexcept { i = d.i; d.i = 0; return *this; } }; struct TExcept { int i; TExcept() = delete; TExcept(int i_) // NOLINT : i{i_} { } TExcept(TExcept &&d) : i(d.i) { d.i = 0; } TExcept(const TExcept &) = delete; TExcept &operator=(const TExcept &) = delete; TExcept &operator=(TExcept &&d) { i = d.i; d.i = 0; return *this; } }; template struct MoveAware { T val; bool moved; MoveAware(T val_) // NOLINT : val(val_), moved(false) { } MoveAware(MoveAware const &) = delete; MoveAware(MoveAware &&rhs) : val(rhs.val) , moved(rhs.moved) { rhs.moved = true; } MoveAware &operator=(MoveAware const &) = delete; MoveAware &operator=(MoveAware &&rhs) { val = (rhs.val); moved = (rhs.moved); rhs.moved = true; return *this; } }; struct OverloadedAddressOf { OverloadedAddressOf() = default; OverloadedAddressOf *operator&() const { return nullptr; } }; // using namespace boost; // using namespace boost::functional; class test_exception : public std::exception { }; int throwing_fun() { throw test_exception(); } int nothrowing_fun() { return 4; } JASEL_NORETURN void void_throwing_fun() { throw test_exception(); } void do_nothing_fun() { } void except_default_constructor() { // From value constructor. expected_sc e{}; try { int i = e.value(); (void) i; BOOST_TEST(true); } catch(...) { BOOST_TEST(false); }; BOOST_TEST(e.has_value()); BOOST_TEST(e); BOOST_TEST(static_cast(e)); } void except_default_constructor_error_code() { // From value constructor. stde::expected e; BOOST_TEST(e.has_value()); BOOST_TEST(e); BOOST_TEST(static_cast(e)); } void except_default_constructor_constexpr() { // From value constructor. BOOST_CONSTEXPR stde::expected e; BOOST_TEST(e.has_value()); } void expected_from_value() { // using T = int; using E = std::error_code; // static_assert(noexcept(stde::adl::swap_impl(std::declval(), std::declval())), ""); static_assert(std::is_nothrow_copy_constructible::value, ""); // static_assert(noexcept(stde::adl::swap_impl(std::declval(), std::declval())), ""); static_assert(std::is_nothrow_copy_constructible>::value, ""); static_assert(std::is_nothrow_copy_assignable>::value, ""); static_assert(std::is_nothrow_move_constructible>::value, ""); static_assert(std::is_nothrow_move_assignable>::value, ""); // From value constructor. expected_sc e(5); // BOOST_REQUIRE_NO_THROW(e.value()); BOOST_TEST_EQ(e.value(), 5); BOOST_TEST_EQ(*e, 5); BOOST_TEST(e.has_value()); BOOST_TEST(static_cast(e)); } void expected_from_value2() { // From value constructor. expected_sc e(5); e = {}; BOOST_TEST(e.has_value()); BOOST_TEST_EQ(e.value(), 0); } void expected_from_cnv_value() { OracleVal v; expected_sc e(v); // BOOST_REQUIRE_NO_THROW(e.value()); BOOST_TEST(!!e); BOOST_TEST(e.has_value()); BOOST_TEST(bool(e)); BOOST_TEST_EQ(e.value().s, sValueCopyConstructed); BOOST_TEST_EQ(v.s, sValueConstructed); expected_sc e2(std::move(v)); // NOLINT // BOOST_REQUIRE_NO_THROW(e2.value()); BOOST_TEST(!!e2); BOOST_TEST(e2.has_value()); BOOST_TEST(bool(e2)); BOOST_TEST_EQ(e2.value().s, sValueMoveConstructed); BOOST_TEST_EQ(v.s, sMovedFrom); } struct NDCE // no default constructor { // (no default date exists) explicit NDCE(int /*unused*/) {} }; void except_constructor_NDCE() { expected_sc e{NDCE{1}}; BOOST_TEST(e.has_value()); } struct NDC // no default constructor { // (no default date exists) NDC(int /*unused*/) {} // NOLINT }; void except_constructor_NDC() { static_assert(std::is_nothrow_copy_constructible>::value, ""); static_assert(std::is_nothrow_copy_assignable>::value, ""); static_assert(std::is_nothrow_move_constructible>::value, ""); static_assert(std::is_nothrow_move_assignable>::value, ""); expected_sc e{1}; BOOST_TEST(e.has_value()); } void except_constructor_Date() { static_assert(std::is_nothrow_move_constructible>::value, ""); static_assert(std::is_nothrow_move_assignable>::value, ""); expected_sc e{Date{1}}; BOOST_TEST(e.has_value()); } void except_constructor_TExcept() { static_assert(!std::is_nothrow_move_constructible>::value, ""); static_assert(!std::is_nothrow_move_assignable>::value, ""); expected_sc e{TExcept{1}}; BOOST_TEST(e.has_value()); } void expected_from_in_place_value() { OracleVal v; expected_sc e{stde::in_place, v}; // BOOST_REQUIRE_NO_THROW(e.value()); BOOST_TEST(!!e); BOOST_TEST(e.has_value()); BOOST_TEST(bool(e)); BOOST_TEST_EQ(e.value().s, sValueCopyConstructed); BOOST_TEST_EQ(v.s, sValueConstructed); expected_sc e2{stde::in_place, std::move(v)}; // NOLINT // BOOST_REQUIRE_NO_THROW(e2.value()); BOOST_TEST(!!e2); BOOST_TEST(e2.has_value()); BOOST_TEST(bool(e2)); BOOST_TEST_EQ(e2.value().s, sValueMoveConstructed); BOOST_TEST_EQ(v.s, sMovedFrom); } #if 0 void expected_from_exception() { // From stde::unexpected constructor. stde::exception_or e(stde::make_unexpected(test_exception())); BOOST_TEST_THROWS(e.value(), test_exception); BOOST_TEST_EQ(e.has_value(), false); BOOST_TEST_EQ(static_cast(e), false); } #endif void expected_from_copy_value() { // From copy constructor. expected_sc ef(5); expected_sc e(ef); // BOOST_REQUIRE_NO_THROW(e.value()); BOOST_TEST_EQ(e.value(), 5); BOOST_TEST_EQ(*e, 5); BOOST_TEST(e.has_value()); BOOST_TEST(static_cast(e)); } #if 0 void expected_from_copy_exception() { // From stde::unexpected constructor. stde::exception_or ef(stde::make_unexpected(test_exception())); stde::exception_or e(ef); BOOST_TEST_THROWS(e.value(), test_exception); BOOST_TEST_EQ(e.has_value(), false); BOOST_TEST_EQ(static_cast(e), false); } #endif void expected_from_in_place() { // From stde::in_place constructor. expected_sc e(stde::in_place, "stde::in_place"); // BOOST_REQUIRE_NO_THROW(e.value()); BOOST_TEST_EQ(e.value(), "stde::in_place"); BOOST_TEST_EQ(*e, "stde::in_place"); BOOST_TEST(e.has_value()); BOOST_TEST(static_cast(e)); } #if 0 void expected_from_exception_ptr() { // From exception_ptr constructor. stde::exception_or e(stde::make_unexpected(std::make_exception_ptr(test_exception()))); BOOST_TEST_THROWS(e.value(), test_exception); BOOST_TEST_EQ(e.has_value(), false); BOOST_TEST_EQ(static_cast(e), false); } #endif void expected_from_moved_value() { // From move value constructor. std::string value = "my value"; expected_sc e = std::move(value); // BOOST_REQUIRE_NO_THROW(e.value()); BOOST_TEST_EQ(e.value(), "my value"); BOOST_TEST_EQ(*e, "my value"); BOOST_TEST(e.has_value()); BOOST_TEST(static_cast(e)); } void expected_from_catch_block() { // From catch block try { throw test_exception(); } catch(...) { stde::exception_or e(stde::make_unexpected(std::current_exception())); BOOST_TEST_THROWS(e.value(), std::exception); BOOST_TEST_EQ(e.has_value(), false); BOOST_TEST_EQ(static_cast(e), false); } } void make_expected_E_from_value() { // auto e = stde::make_expected( 5 ); // BOOST_TEST_EQ(e.has_value(), false); } void make_expected_const_from_value() { #if defined __clang__ && __clang_major__ >= 4 && __cplusplus > 201402L const int i = 0; auto e = expected_sc(i); (void) e; // static_assert(std::is_same>::value, ""); #endif } void make_expected_from_U_value() { expected_sc e = expected_sc(short(5)); static_assert(std::is_same>{}, ""); BOOST_TEST_EQ(e.has_value(), true); } void make_expected_from_U_value2() { expected_sc e = expected_sc("aa"); static_assert(std::is_same>{}, ""); BOOST_TEST_EQ(e.has_value(), true); } void expected_from_value_error_condition() { // From value constructor. stde::expected e(5); // BOOST_REQUIRE_NO_THROW(e.value()); BOOST_TEST_EQ(e.value(), 5); BOOST_TEST_EQ(*e, 5); BOOST_TEST(e.has_value()); BOOST_TEST(static_cast(e)); } void expected_from_error_error_condition() { // From stde::unexpected constructor. stde::expected e(stde::make_unexpected(std::make_error_condition(std::errc::invalid_argument))); auto error_from_except_check = [](const stde::bad_expected_access &except) { return std::errc(except.error().value()) == std::errc::invalid_argument; }; try { (void) e.value(); } catch(stde::bad_expected_access &ex) { BOOST_TEST(error_from_except_check(ex)); } BOOST_TEST_EQ(e.has_value(), false); BOOST_TEST_EQ(static_cast(e), false); } void expected_from_error_convertible() { { stde::expected e1 = stde::make_unexpected(1); stde::expected e2(e1); BOOST_TEST_EQ(e2.has_value(), false); BOOST_TEST_EQ(static_cast(e2), false); BOOST_TEST_EQ(e2.error(), 1); } { stde::expected e1 = stde::make_unexpected(1); stde::expected e2(e1); BOOST_TEST_EQ(e2.has_value(), false); BOOST_TEST_EQ(static_cast(e2), false); BOOST_TEST_EQ(e2.error(), 1); } } void except_valid_constexpr_int() { // From value constructor. BOOST_CONSTEXPR stde::expected e; BOOST_CONSTEXPR bool b = e.has_value(); BOOST_TEST(b); } void except_value_constexpr_int() { // From value constructor. BOOST_CONSTEXPR stde::expected e(1); BOOST_CONSTEXPR int x = e.value(); BOOST_TEST_EQ(x, 1); } void expected_from_value3() { expected_sc e(5); BOOST_TEST_EQ(e.value(), 5); // From value assignment. e = 8; // BOOST_REQUIRE_NO_THROW(e.value()); BOOST_TEST_EQ(e.value(), 8); BOOST_TEST_EQ(*e, 8); BOOST_TEST(e.has_value()); BOOST_TEST(static_cast(e)); } void expected_from_copy_expected() { expected_sc e(5); expected_sc e2(8); // From value assignment. e = e2; // BOOST_REQUIRE_NO_THROW(e.value()); BOOST_TEST_EQ(e.value(), 8); BOOST_TEST_EQ(*e, 8); BOOST_TEST(e.has_value()); BOOST_TEST(static_cast(e)); } void expected_from_moved_expected() { expected_sc e("e"); expected_sc e2("e2"); // From value assignment. e = std::move(e2); // BOOST_REQUIRE_NO_THROW(e.value()); BOOST_TEST_EQ(e.value(), "e2"); BOOST_TEST_EQ(*e, "e2"); BOOST_TEST(e.has_value()); BOOST_TEST(static_cast(e)); // BOOST_REQUIRE_NO_THROW(e2.value()); #ifndef __GLIBBOOST_OUTCOME_C__ BOOST_TEST_EQ(e2.value(), ""); BOOST_TEST_EQ(*e2, ""); #endif BOOST_TEST(e2.has_value()); BOOST_TEST(static_cast(e2)); } void expected_from_in_place2() { // From stde::in_place constructor. expected_sc e(stde::in_place, "stde::in_place"); BOOST_TEST_EQ(e.value(), "stde::in_place"); // From emplace method. e.emplace("emplace method"); // BOOST_REQUIRE_NO_THROW(e.value()); BOOST_TEST_EQ(e.value(), "emplace method"); BOOST_TEST_EQ(*e, "emplace method"); BOOST_TEST(e.has_value()); BOOST_TEST(static_cast(e)); } void expected_from_move_value() { expected_sc e("v"); std::string value = "my value"; // From assignment operator. e = std::move(value); // BOOST_REQUIRE_NO_THROW(e.value()); BOOST_TEST_EQ(e.value(), "my value"); BOOST_TEST_EQ(*e, "my value"); BOOST_TEST(e.has_value()); BOOST_TEST(static_cast(e)); } void expected_from_in_place3() { // From stde::in_place factory. // auto e = stde::make_expected("stde::in_place"); auto e = expected_sc("stde::in_place"); // BOOST_REQUIRE_NO_THROW(e.value()); BOOST_TEST_EQ(e.value(), "stde::in_place"); BOOST_TEST_EQ(*e, "stde::in_place"); BOOST_TEST(e.has_value()); BOOST_TEST(static_cast(e)); } void expected_from_in_place_error() { // From stde::in_place factory. auto e = stde::expected("stde::in_place"); // BOOST_REQUIRE_NO_THROW(e.value()); BOOST_TEST_EQ(e.value(), "stde::in_place"); BOOST_TEST_EQ(*e, "stde::in_place"); BOOST_TEST(e.has_value()); BOOST_TEST(static_cast(e)); } void expected_from_exception_catch() { // From catch block try { throw test_exception(); } catch(...) { stde::exception_or e = stde::make_unexpected(std::current_exception()); BOOST_TEST_THROWS(e.value(), std::exception); BOOST_TEST_EQ(e.has_value(), false); BOOST_TEST_EQ(static_cast(e), false); } } #if 0 void expected_from_error() { // From stde::unexpected constructor. auto e = stde::make_expected_from_error(std::make_error_condition(std::errc::invalid_argument)); auto error_from_except_check = [](const stde::bad_expected_access &except) { return std::errc(except.error().value()) == std::errc::invalid_argument; }; try { (void) e.value(); } catch(stde::bad_expected_access &ex) { BOOST_TEST(error_from_except_check(ex)); } BOOST_TEST_EQ(e.has_value(), false); BOOST_TEST_EQ(static_cast(e), false); } void expected_from_error_U() { // From stde::unexpected constructor. auto e = stde::make_expected_from_error(42); static_assert(std::is_same>{}, ""); BOOST_TEST_EQ(e.has_value(), false); BOOST_TEST_EQ(static_cast(e), false); } void expected_from_exception2() { // From stde::unexpected constructor. auto e = stde::make_expected_from_exception(test_exception()); // auto e = expected_sc(stde::unexpected<>(test_exception())); BOOST_TEST_THROWS(e.value(), test_exception ); BOOST_TEST_EQ(e.has_value(), false); BOOST_TEST_EQ(static_cast(e), false); } void expected_from_exception_ptr2() { // From exception_ptr constructor. auto e = stde::exception_or(stde::make_unexpected(test_exception())); BOOST_TEST_THROWS(e.value(), test_exception ); BOOST_TEST_EQ(e.has_value(), false); BOOST_TEST_EQ(static_cast(e), false); } void make_expected_from_call_fun() { try { stde::make_expected_from_call(throwing_fun); BOOST_TEST(true); } catch(...) { BOOST_TEST(false); } stde::exception_or e = stde::make_expected_from_call(throwing_fun); BOOST_TEST_THROWS(e.value(), std::exception ); BOOST_TEST_EQ(e.has_value(), false); BOOST_TEST_EQ(static_cast(e), false); e = stde::make_expected_from_call(nothrowing_fun); try { (void) e.value(); BOOST_TEST(true); } catch(...) { BOOST_TEST(false); } BOOST_TEST_EQ(e.value(), 4); BOOST_TEST_EQ(*e, 4); BOOST_TEST_EQ(e.has_value(), true); BOOST_TEST_EQ(static_cast(e), true); #if 0 BOOST_TEST_THROWS(stde::make_expected_from_call(throwing_fun), test_exception); BOOST_TEST_NO_THROW(stde::make_expected_from_call(nothrowing_fun)); stde::expected e2 = stde::make_expected_from_call(nothrowing_fun); BOOST_TEST_NO_THROW(e2.value()); BOOST_TEST_EQ(e2.value(), 4); BOOST_TEST_EQ(*e2, 4); BOOST_TEST_EQ(e2.has_value(), true); BOOST_TEST_EQ(static_cast(e2), true); #endif } void make_expected_from_call_void_fun() { #if 0 BOOST_TEST_NO_THROW(stde::make_expected_from_call(void_throwing_fun)); expected_sc e = stde::make_expected_from_call(void_throwing_fun); BOOST_TEST_THROWS(e.value(), std::exception); BOOST_TEST_EQ(e.has_value(), false); BOOST_TEST_EQ(static_cast(e), false); e = stde::make_expected_from_call(do_nothing_fun); BOOST_TEST_NO_THROW(e.value()); BOOST_TEST_EQ(e.has_value(), true); BOOST_TEST_EQ(static_cast(e), true); BOOST_TEST_THROWS(stde::make_expected_from_call(void_throwing_fun), test_exception); try { stde::make_expected_from_call(do_nothing_fun); BOOST_TEST(true); } catch (...) { BOOST_TEST(false); } stde::expected e2 = stde::make_expected_from_call(do_nothing_fun); try { (void)e2.value(); BOOST_TEST(true); } catch (...) { BOOST_TEST(false); } //BOOST_TEST_NO_THROW(e2.value()); BOOST_TEST_EQ(e2.has_value(), true); BOOST_TEST_EQ(static_cast(e2), true); #endif } #endif void expected_swap_value() { // From value constructor. expected_sc e(5); expected_sc e2(8); e.swap(e2); BOOST_TEST_EQ(e.value(), 8); BOOST_TEST_EQ(e2.value(), 5); e2.swap(e); BOOST_TEST_EQ(e.value(), 5); BOOST_TEST_EQ(e2.value(), 8); } #if 0 void expected_swap_exception() { // From value constructor. stde::exception_or e = stde::make_unexpected(std::invalid_argument("e")); stde::exception_or e2 = stde::make_unexpected(std::invalid_argument("e2")); e.swap(e2); auto equal_to_e = [](const std::invalid_argument &except) { return std::string(except.what()) == "e"; }; auto equal_to_e2 = [](const std::invalid_argument &except) { return std::string(except.what()) == "e2"; }; try { (void) e.value(); BOOST_TEST(true); } catch(std::invalid_argument &ex) { BOOST_TEST(equal_to_e2(ex)); } try { (void) e2.value(); BOOST_TEST(true); } catch(std::invalid_argument &ex) { BOOST_TEST(equal_to_e(ex)); } e2.swap(e); try { (void) e.value(); BOOST_TEST(true); } catch(std::invalid_argument &ex) { BOOST_TEST(equal_to_e(ex)); } try { (void) e2.value(); BOOST_TEST(true); } catch(std::invalid_argument &ex) { BOOST_TEST(equal_to_e2(ex)); } } #endif void expected_swap_function_value() { // From value constructor. expected_sc e(5); expected_sc e2(8); swap(e, e2); BOOST_TEST_EQ(e.value(), 8); BOOST_TEST_EQ(e2.value(), 5); swap(e, e2); BOOST_TEST_EQ(e.value(), 5); BOOST_TEST_EQ(e2.value(), 8); } #ifdef QUICKCPPLIB_BOOST_UNIT_TEST_HPP int main() #else BOOST_AUTO_TEST_CASE(expected_pass) #endif { static_assert(!std::is_default_constructible::value, ""); static_assert(!std::is_default_constructible>::value, ""); static_assert(!std::is_copy_constructible::value, ""); static_assert(!std::is_constructible, NoCopyConstructible const &>::value, ""); static_assert(!std::is_constructible, stde::exception_or const &>::value, ""); static_assert(!std::is_copy_constructible>::value, ""); #if 0 // fixme { NoMoveConstructible nmc; // NoMoveConstructible nmc2 = std::move(nmc); // FAILS as expected expected_sc x{std::move(nmc)}; // DOESN'T FAIL as copy is selected instead (void) x; } // fixme #if defined __clang__ && __clang_major__ >= 4 && __cplusplus > 201402L { NoMoveConstructible nmc; // NoMoveConstructible nmc2 = std::move(nmc); // FAILS as expected expected_sc x = std::move(nmc); // DOESN'T FAIL as copy is selected instead (void) x; } #endif #endif static_assert(!std::is_move_constructible::value, ""); static_assert(!std::is_constructible, NoMoveConstructible &&>::value, ""); static_assert(std::is_move_constructible>::value, ""); except_default_constructor(); except_default_constructor_error_code(); except_default_constructor_constexpr(); expected_from_value(); expected_from_value2(); expected_from_cnv_value(); except_constructor_NDCE(); except_constructor_NDC(); except_constructor_Date(); expected_from_in_place_value(); // expected_from_exception(); expected_from_copy_value(); // expected_from_copy_exception(); expected_from_in_place(); // expected_from_exception_ptr(); expected_from_moved_value(); expected_from_catch_block(); make_expected_E_from_value(); make_expected_const_from_value(); make_expected_from_U_value2(); expected_from_value_error_condition(); expected_from_error_error_condition(); expected_from_error_convertible(); except_valid_constexpr_int(); except_value_constexpr_int(); expected_from_value3(); expected_from_copy_expected(); expected_from_moved_expected(); expected_from_in_place2(); expected_from_move_value(); expected_from_in_place3(); expected_from_in_place_error(); expected_from_exception_catch(); // expected_from_error(); // expected_from_error_U(); // expected_from_exception2(); // expected_from_exception_ptr2(); // make_expected_from_call_fun(); // make_expected_from_call_void_fun(); expected_swap_value(); // expected_swap_exception(); expected_swap_function_value(); #ifdef QUICKCPPLIB_BOOST_UNIT_TEST_HPP return QUICKCPPLIB_NAMESPACE::unit_test::current_test_case()->fails != 0; #endif } #if 0 /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// //void expected_from_error_catch_exception) //{ // // From catch block // try // { // throw test_exception(); // } // catch(...) // { // auto throw_lambda = [](){ return stde::make_expected_from_error();}; // // //BOOST_TEST_THROWS(throw_lambda(), test_exception); // } //} //////////////////////////////////// BOOST_AUTO_TEST_SUITE(expected_map) void expected_map() { auto fun = [](bool b) -> expected_sc { if (b) return stde::make_expected(5); else return stde::make_unexpected(test_exception()); }; auto add_five = [](int sum) -> int { return sum + 5; }; auto launch_except = [](int sum) -> int { throw test_exception(); }; expected_sc e = fun(true).map(add_five); BOOST_TEST_NO_THROW(e.value()); BOOST_TEST_EQ(*e, 10); e = fun(true).map(add_five).map(add_five); BOOST_TEST_NO_THROW(e.value()); BOOST_TEST_EQ(*e, 15); e = fun(false).map(add_five).map(add_five); BOOST_TEST_THROWS(e.value(), test_exception); BOOST_TEST_THROWS(fun(true).map(launch_except), test_exception); } void expected_void_map() { auto fun = [](bool b) { if (b) return stde::make_expected(); else return expected_sc(stde::make_unexpected(test_exception())); }; auto launch_except = []() -> void { throw test_exception(); }; auto do_nothing = []() {}; expected_sc e = fun(true).map(do_nothing); BOOST_TEST_NO_THROW(e.value()); e = fun(false).map(do_nothing); BOOST_TEST_THROWS(e.value(), test_exception); BOOST_TEST_THROWS(fun(true).map(launch_except), test_exception); } BOOST_AUTO_TEST_SUITE_END() //////////////////////////////////// BOOST_AUTO_TEST_SUITE(expected_bind) void expected_bind() { auto fun = [](bool b) -> expected_sc { if (b) return stde::make_expected(5); else return stde::make_unexpected(test_exception()); }; auto add_five = [](int sum) -> expected_sc { return stde::make_expected(sum + 5); }; auto launch_except = [](int sum) -> expected_sc { throw test_exception(); }; expected_sc e = fun(true).bind(add_five); BOOST_TEST_NO_THROW(e.value()); BOOST_TEST_EQ(*e, 10); e = fun(true).bind(add_five).bind(add_five); BOOST_TEST_NO_THROW(e.value()); BOOST_TEST_EQ(*e, 15); e = fun(false).bind(add_five).bind(add_five); BOOST_TEST_THROWS(e.value(), test_exception); BOOST_TEST_THROWS(fun(true).bind(launch_except), test_exception); } void expected_void_bind() { auto fun = [](bool b) { if (b) return stde::make_expected(); else return expected_sc(stde::make_unexpected(test_exception())); }; auto launch_except = []() -> expected_sc { throw test_exception(); }; auto do_nothing = []() { return stde::make_expected(); }; expected_sc e = fun(true).bind(do_nothing); BOOST_TEST_NO_THROW(e.value()); e = fun(false).bind(do_nothing); BOOST_TEST_THROWS(e.value(), test_exception); BOOST_TEST_THROWS(fun(true).bind(launch_except), test_exception); } BOOST_AUTO_TEST_SUITE_END() //////////////////////////////////// BOOST_AUTO_TEST_SUITE(expected_then) void expected_non_void_then() { auto fun = [](bool b) -> expected_sc { if (b) return stde::make_expected(5); else return stde::make_unexpected(test_exception()); }; auto add_five = [](int sum) -> int { return sum + 5; }; auto six = []() -> int { return 6; }; auto pair = [](int a) -> bool { return (a % 2) == 0; }; auto launch_except = [](int sum) -> int { throw test_exception(); }; auto then_launch_except = [](expected) -> int { throw test_exception(); }; expected_sc e = fun(true).then(if_valued(add_five)); BOOST_TEST_NO_THROW(e.value()); BOOST_TEST_EQ(*e, 10); e = fun(true).then(if_valued(ident(six))); BOOST_TEST_NO_THROW(e.value()); BOOST_TEST_EQ(*e, 6); e = fun(false).then(if_unexpected(ident(six))); BOOST_TEST_NO_THROW(e.value()); BOOST_TEST_EQ(*e, 6); expected_sc e1 = fun(true).then(if_valued(pair)); BOOST_TEST_NO_THROW(e1.value()); BOOST_TEST_EQ(*e1, false); e = fun(true).then(if_valued(add_five)).then(if_valued(add_five)); BOOST_TEST_NO_THROW(e.value()); BOOST_TEST_EQ(*e, 15); e = fun(false).then(if_valued(add_five)).then(if_valued(add_five)); BOOST_TEST_THROWS(e.value(), test_exception); BOOST_TEST_THROWS(fun(true).then(if_valued(launch_except)), test_exception); e = fun(false).then(catch_all(then_launch_except)); BOOST_TEST_THROWS(e.value(), test_exception); } void expected_void_then() { auto fun = [](bool b) -> expected_sc { if (b) return stde::make_expected(); else return stde::make_unexpected(test_exception()); }; auto launch_except = []() { throw test_exception(); }; auto do_nothing = []() {}; BOOST_TEST(true); expected_sc e = fun(true).then(if_valued(do_nothing)); BOOST_TEST_NO_THROW(e.value()); e = fun(false).then(if_valued(do_nothing)); BOOST_TEST_THROWS(e.value(), test_exception); BOOST_TEST_THROWS(fun(true).then(if_valued(launch_except)), test_exception); } BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(expected_recover) void expected_recover() { auto fun = [](bool b) { if (b) return expected_sc(5); else return expected_sc(stde::make_unexpected(test_exception())); }; auto add_five = [](int sum) -> expected_sc { return stde::make_expected(sum + 5); }; auto recover_error = [](std::exception_ptr p) { return stde::make_expected(0); }; auto recover_error_silent_failure = [](std::exception_ptr p) { return expected_sc(stde::make_unexpected(p)); }; auto recover_error_failure = [](std::exception_ptr p) -> expected_sc { return expected_sc(stde::make_unexpected(test_exception())); }; auto recover_error_throws = [](std::exception_ptr p) -> expected_sc { throw test_exception(); }; BOOST_TEST_EQ(fun(false).catch_error(recover_error).has_value(), true); BOOST_TEST_EQ(fun(false).catch_error(recover_error).value(), 0); BOOST_TEST_EQ(fun(true).catch_error(recover_error).value(), 5); BOOST_TEST_EQ(fun(false).catch_error(recover_error_silent_failure).has_value(), false); BOOST_TEST_EQ(fun(false).catch_error(recover_error_failure).has_value(), false); BOOST_TEST_EQ(fun(true).bind(add_five).value(), 10); BOOST_TEST_EQ(fun(true).bind(add_five).catch_error(recover_error).value(), 10); BOOST_TEST_EQ(fun(true).bind(add_five).catch_error(recover_error_silent_failure).value(), 10); BOOST_TEST_EQ(fun(true).bind(add_five).catch_error(recover_error_failure).value(), 10); BOOST_TEST_EQ(fun(false).catch_error(recover_error).bind(add_five).value(), 5); BOOST_TEST_EQ(fun(false).catch_error(recover_error).bind(add_five).bind(add_five).value(), 10); BOOST_TEST_EQ(fun(false).catch_error(recover_error_failure).bind(add_five).has_value(), false); BOOST_TEST_EQ(fun(false).bind(add_five).catch_error(recover_error_failure).bind(add_five).has_value(), false); BOOST_TEST_EQ(fun(false).bind(add_five).catch_error(recover_error_silent_failure).bind(add_five).has_value(), false); BOOST_TEST_THROWS(fun(false).catch_error(recover_error_throws), test_exception); } void expected_void_recover() { auto fun = [](bool b) { if (b) return stde::make_expected(); else return expected_sc(boost::stde::make_unexpected(test_exception())); }; auto do_nothing = []() { return stde::make_expected(); }; auto recover_error = [](std::exception_ptr p) { return stde::make_expected(); }; auto recover_error_silent_failure = [](std::exception_ptr p) { return expected_sc(boost::stde::make_unexpected(p)); }; auto recover_error_failure = [](std::exception_ptr p) -> expected_sc { throw test_exception(); }; // The catch_error doesn't alter the stde::expected if it's valid. BOOST_TEST_EQ(fun(true).catch_error(recover_error_failure).has_value(), true); // Simple catch_error tests. BOOST_TEST_EQ(fun(false).catch_error(recover_error).has_value(), true); BOOST_TEST_THROWS(fun(false).catch_error(recover_error_failure), test_exception); BOOST_TEST_EQ(fun(false).catch_error(recover_error_silent_failure).has_value(), false); // With a bind between. BOOST_TEST_THROWS(fun(false).bind(do_nothing).catch_error(recover_error_failure), test_exception); } BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(proposal) void proposal_concept() { using namespace std; { stde::expected ei = 0; stde::expected ej = 1; stde::expected ek = stde::make_unexpected(string()); ei = 1; ej = stde::make_unexpected(string());; ek = 0; ei = stde::make_unexpected(string());; ej = 0; ek = 1; } } void proposal_init() { using namespace std; { string s{ "STR" }; stde::expected ep{ stde::make_unexpected(-1) }; // unexpected value, requires Movable stde::expected eq = { stde::make_unexpected(-1) }; // unexpected value, requires Movable expected_sc es{ s }; // requires Copyable expected_sc et = s; // requires Copyable expected_sc ev = string{ "STR" }; // requires Movable expected_sc ew; // unexpected value expected_sc ex{}; // unexpected value expected_sc ey = {}; // unexpected value expected_sc ez = expected_sc{}; // unexpected value } { stde::expected eg; // unexpected value stde::expected eh{}; // unexpected value stde::expected ei{ stde::in_place }; // calls Guard{} in place stde::expected ej{ stde::in_place, "arg" }; // calls Guard{"arg"} in place } { stde::expected ei{ unexpect }; // unexpected value, calls string{} in place stde::expected ej{ unexpect, "arg" }; // unexpected value, calls string{"arg"} in place } } void proposal_make_unexpected_fact() { using namespace std; { stde::expected opt1 = stde::make_unexpected(1); stde::expected opt2 = { unexpect, 1 }; opt1 = stde::make_unexpected(1); opt2 = { unexpect, 1 }; } } void proposal_error_exception_ts() { using namespace std; { stde::expected > e = stde::make_unexpected(make_error_code(errc::invalid_argument)); #if !defined BOOST_MSVC || BOOST_MSVC >= 1900 BOOST_TEST(e.error() == make_error_code(errc::invalid_argument)); #else // VS2013 doesn't match operator==(boost::error_exception, std::error_code) BOOST_TEST(e.error() == (error_exception(make_error_code(errc::invalid_argument)))); #endif try { e.value(); BOOST_TEST(false); } catch (std::system_error const& ex) { } catch (...) { BOOST_TEST(false); } stde::expected > e2 = stde::make_unexpected(e.error()); #if !defined BOOST_MSVC || BOOST_MSVC >= 1900 BOOST_TEST(e2.error() == make_error_code(errc::invalid_argument)); #else // VS2013 doesn't match operator==(boost::error_exception, std::error_code) BOOST_TEST(e2.error() == (error_exception(make_error_code(errc::invalid_argument)))); #endif try { e2.value(); BOOST_TEST(false); } catch (std::system_error const& ex) { } catch (...) { BOOST_TEST(false); } } } void proposal_ensured_read_ts() { using namespace std; { ensured_read e = make_ensured_read(1); BOOST_TEST(e == 1); } { ensured_read e = make_ensured_read(1); stde::unexpected> ue1 = stde::make_unexpected(std::move(e)); BOOST_TEST(ue1.value() == 1); } // { // stde::make_unexpected(make_ensured_read(1)); // // calls to terminate. // } // { // stde::expected > e = stde::make_unexpected(make_ensured_read(1)); // // calls to terminate. // } { stde::expected > e{ 1 }; BOOST_TEST(e.value() == 1); } { stde::expected > e = stde::make_unexpected(make_ensured_read(1)); BOOST_TEST(e.error() == 1); } { stde::expected > e{ unexpect, 1 }; BOOST_TEST(e.error() == 1); } { ensured_read e = make_ensured_read(std::make_exception_ptr(1)); BOOST_TEST_THROWS(std::rethrow_exception(e.value()), int); } { stde::expected > e = stde::make_unexpected(make_ensured_read(std::make_exception_ptr(1))); BOOST_TEST_THROWS(std::rethrow_exception(e.error().value()), int); } } void proposal_relational_operators() { using namespace std; { stde::expected e0{ 0 }; stde::expected e1{ 1 }; stde::expected eN{ unexpect, -1 }; BOOST_TEST(eN < e0); BOOST_TEST(e0 < e1); BOOST_TEST(!(e0 < eN)); BOOST_TEST(eN <= e0); BOOST_TEST(e0 <= e1); BOOST_TEST(e0 > eN); BOOST_TEST(e1 > e0); BOOST_TEST(e0 >= eN); BOOST_TEST(e1 >= e0); BOOST_TEST(!(eN < eN)); BOOST_TEST(!(e1 < e1)); BOOST_TEST(eN <= eN); BOOST_TEST(e1 <= e1); BOOST_TEST(eN != e0); BOOST_TEST(e0 != e1); BOOST_TEST(eN == eN); BOOST_TEST(e0 == e0); ////// BOOST_TEST(eN == stde::make_unexpected(-1)); BOOST_TEST(e0 != stde::make_unexpected(1)); BOOST_TEST(eN != 1u); BOOST_TEST(e1 == 1u); BOOST_TEST(eN < 1u); BOOST_TEST(eN <= 1u); BOOST_TEST(1u > eN); BOOST_TEST(!(1u < eN)); BOOST_TEST(1u >= eN); BOOST_TEST(stde::make_unexpected(1) < e0); BOOST_TEST(stde::make_unexpected(1) <= e0); BOOST_TEST(!(stde::make_unexpected(1) > e0)); BOOST_TEST(!(stde::make_unexpected(1) >= e0)); BOOST_TEST(!(e0 < stde::make_unexpected(1))); BOOST_TEST(!(e0 <= stde::make_unexpected(1))); BOOST_TEST(e0 > stde::make_unexpected(1)); BOOST_TEST(e0 >= stde::make_unexpected(1)); } { stde::expected e0{ boost::expect }; stde::expected eN{ unexpect, -1 }; BOOST_TEST(!(e0 < e0)); BOOST_TEST(eN < e0); BOOST_TEST(!(e0 < eN)); BOOST_TEST(!(eN < eN)); BOOST_TEST(e0 <= e0); BOOST_TEST(eN <= e0); BOOST_TEST(!(e0 <= eN)); BOOST_TEST(eN <= eN); BOOST_TEST(!(e0 > e0)); BOOST_TEST(e0 > eN); BOOST_TEST(!(eN > e0)); BOOST_TEST(!(eN > eN)); BOOST_TEST(e0 >= e0); BOOST_TEST(e0 >= eN); BOOST_TEST(!(eN >= e0)); BOOST_TEST(eN >= eN); BOOST_TEST(!(e0 != e0)); BOOST_TEST(eN != e0); BOOST_TEST(e0 != eN); BOOST_TEST(!(eN != eN)); BOOST_TEST(e0 == e0); BOOST_TEST(!(eN == e0)); BOOST_TEST(!(e0 == eN)); BOOST_TEST(eN == eN); ////// BOOST_TEST(eN == stde::make_unexpected(-1)); BOOST_TEST(e0 != stde::make_unexpected(1)); BOOST_TEST(stde::make_unexpected(1) < e0); BOOST_TEST(stde::make_unexpected(1) <= e0); BOOST_TEST(!(stde::make_unexpected(1) > e0)); BOOST_TEST(!(stde::make_unexpected(1) >= e0)); BOOST_TEST(!(stde::make_unexpected(1) < eN)); BOOST_TEST(!(stde::make_unexpected(1) <= eN)); BOOST_TEST(stde::make_unexpected(1) > eN); BOOST_TEST(stde::make_unexpected(1) >= eN); BOOST_TEST(!(eN < stde::make_unexpected(-1))); BOOST_TEST(eN <= stde::make_unexpected(-1)); BOOST_TEST(!(eN > stde::make_unexpected(-1))); BOOST_TEST(eN >= stde::make_unexpected(-1)); } } void proposal_dereference_operators() { using namespace std; { const string s{ "STR" }; expected_sc e0{ s }; const expected_sc e1{ s }; BOOST_TEST(*e0.operator->() == s); BOOST_TEST(*e1.operator->() == s); // Test with class which has operator&() overloaded const OverloadedAddressOf o{}; BOOST_TEST(&o == nullptr); expected_sc e2{ o }; const expected_sc e3{ o }; BOOST_TEST(e2.operator->() != nullptr); BOOST_TEST(e3.operator->() != nullptr); } } BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(movesem) ////////////////////////////// void movesem_moved_from_state() { // first, test mock: MoveAware i{ 1 }, j{ 2 }; BOOST_TEST(i.val == 1); BOOST_TEST(!i.moved); BOOST_TEST(j.val == 2); BOOST_TEST(!j.moved); MoveAware k = std::move(i); BOOST_TEST(k.val == 1); BOOST_TEST(!k.moved); BOOST_TEST(i.val == 1); BOOST_TEST(i.moved); k = std::move(j); BOOST_TEST(k.val == 2); BOOST_TEST(!k.moved); BOOST_TEST(j.val == 2); BOOST_TEST(j.moved); // now, test stde::expected expected_sc> oi{ 1 }, oj{ 2 }; BOOST_TEST(oi); BOOST_TEST(!oi->moved); BOOST_TEST(oj); BOOST_TEST(!oj->moved); expected_sc> ok{ std::move(oi) }; BOOST_TEST(ok); BOOST_TEST(!ok->moved); BOOST_TEST(oi); BOOST_TEST(oi->moved); ok = std::move(oj); BOOST_TEST(ok); BOOST_TEST(!ok->moved); BOOST_TEST(oj); BOOST_TEST(oj->moved); } void movesem_move_only_value() { const auto make_int = []() { std::unique_ptr value{ new int }; *value = 100; return value; }; const auto return_void = [](std::unique_ptr value) { BOOST_TEST(value != nullptr); BOOST_TEST(*value == 100); }; const auto return_expected = [](std::unique_ptr value) { BOOST_TEST(value != nullptr); BOOST_TEST(*value == 100); return expected_sc{boost::expect}; }; const auto return_int = [](std::unique_ptr value) { BOOST_TEST(value != nullptr); BOOST_TEST(*value == 100); return 200; }; BOOST_TEST(expected>{make_int()}.map(return_void)); BOOST_TEST(expected>{make_int()}.map(return_expected)); BOOST_TEST(expected>{make_int()}.map(return_int)); } void movesem_move_only_value2() { const auto make_int = []() { std::unique_ptr value{ new int }; *value = 100; return value; }; const auto return_expected_void = [](std::unique_ptr value) { BOOST_TEST(value != nullptr); BOOST_TEST(*value == 100); return stde::make_expected(); }; const auto return_expected = [](std::unique_ptr value) { BOOST_TEST(value != nullptr); BOOST_TEST(*value == 100); return expected_sc{boost::expect}; }; BOOST_TEST(expected>{make_int()}.bind(return_expected_void)); BOOST_TEST(expected>{make_int()}.bind(return_expected)); } void movesem_copy_move_ctor_optional_int() { expected_sc oi; expected_sc oj = oi; BOOST_TEST(oj); BOOST_TEST(oj == oi); BOOST_TEST(bool(oj)); oi = 1; expected_sc ok = oi; BOOST_TEST(!!ok); BOOST_TEST(bool(ok)); BOOST_TEST(ok == oi); BOOST_TEST(ok != oj); BOOST_TEST(*ok == 1); expected_sc ol = std::move(oi); BOOST_TEST(!!ol); BOOST_TEST(bool(ol)); BOOST_TEST(ol == oi); BOOST_TEST(ol != oj); BOOST_TEST(*ol == 1); } void movesem_expected_expected() { expected_sc> oi1 = stde::make_unexpected(-1); BOOST_TEST(!oi1); { expected_sc> oi2{ stde::expect }; BOOST_TEST(bool(oi2)); BOOST_TEST((*oi2)); //std::cout << typeid(**oi2).name() << std::endl; } { expected_sc> oi2{ stde::expect, stde::make_unexpected(-1) }; BOOST_TEST(bool(oi2)); BOOST_TEST(!*oi2); } { stde::expected> oi2{ stde::expected{} }; BOOST_TEST(bool(oi2)); BOOST_TEST(*oi2); } stde::expected oi; auto ooi = stde::make_expected(oi); static_assert(std::is_same>, decltype(ooi)>::value, ""); } BOOST_AUTO_TEST_SUITE_END() void process() {} void process(int) {} void processNil() {} BOOST_AUTO_TEST_SUITE(Examples) ////////////////////////////// void example1() { stde::expected oi; // create disengaged object stde::expected oj = { unexpect }; // alternative syntax oi = oj; // assign disengaged object stde::expected ok = oj; // ok is disengaged if (oi) BOOST_TEST(false); // 'if oi is engaged...' if (!oi) BOOST_TEST(true); // 'if oi is disengaged...' BOOST_TEST(oi == ok); // two disengaged optionals compare equal /////////////////////////////////////////////////////////////////////////// stde::expected ol{ 1 }; // ol is engaged; its contained value is 1 ok = 2; // ok becomes engaged; its contained value is 2 oj = ol; // oj becomes engaged; its contained value is 1 BOOST_TEST(oi != ol); // disengaged != engaged BOOST_TEST(ok != ol); // different contained values BOOST_TEST(oj == ol); // same contained value //BOOST_TEST(oi < ol); // disengaged < engaged //BOOST_TEST(ol < ok); // less by contained value ///////////////////////////////////////////////////////////////////////////// stde::expected om{ 1 }; // om is engaged; its contained value is 1 stde::expected on = om; // on is engaged; its contained value is 1 om = 2; // om is engaged; its contained value is 2 BOOST_TEST(on != om); // on still contains 3. They are not pointers ///////////////////////////////////////////////////////////////////////////// int i = *ol; // i obtains the value contained in ol BOOST_TEST(i == 1); *ol = 9; // the object contained in ol becomes 9 BOOST_TEST(*ol == 9); BOOST_TEST(ol == stde::make_expected(9)); /////////////////////////////////// int p = 1; stde::expected op = p; BOOST_TEST(*op == 1); p = 2; BOOST_TEST(*op == 1); // value contained in op is separated from p //////////////////////////////// if (ol) process(*ol); // use contained value if present else process(); // proceed without contained value if (!om) processNil(); else process(*om); ///////////////////////////////////////// process(ol.value_or(0)); // use 0 if ol is disengaged //////////////////////////////////////////// ok = { unexpect }; // if ok was engaged calls T's dtor oj = {}; // assigns a temporary disengaged stde::expected } ////////////////////////////////////////////////// void ValueOr() { stde::expected oi = 1; int i = oi.value_or(0); BOOST_TEST(i == 1); oi = { unexpect }; BOOST_TEST(oi.value_or(3) == 3); stde::expected os{ "AAA" }; BOOST_TEST(os.value_or("BBB") == "AAA"); os = {}; BOOST_TEST(os); BOOST_TEST(os.value() == ""); BOOST_TEST(os.value_or(std::string("BBB")) == ""); { constexpr stde::expected e = 1; static_assert(e.has_value(), ""); static_assert(*e == 1, ""); static_assert(e.value() == 1, ""); } { constexpr std::error_code ec = std::make_error_code(std::errc(1)); constexpr stde::expected e = stde::make_unexpected(ec); static_assert(!e.has_value(), ""); static_assert(e.error() == ec, ""); } { constexpr stde::expected e = 1; static_assert(e.has_value(), ""); static_assert(*e == 1, ""); static_assert(e.value() == 1, ""); } { constexpr std::error_code ec = std::make_error_code(std::errc(1)); constexpr stde::expected e = stde::make_unexpected(ec); static_assert(!e.has_value(), ""); static_assert(e.error() == ec, ""); } } ////////////////////////////////////////////////// BOOST_AUTO_TEST_SUITE_END() #endif #else int main(void) { return 0; } #endif