bbd4e31869
Merged from develop branch as CDash reports all green
2016 lines
54 KiB
C++
2016 lines
54 KiB
C++
//! \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 <utility>
|
|
|
|
#include <boost/outcome/iostream_support.hpp>
|
|
#include <boost/outcome/std_result.hpp>
|
|
|
|
#define QUICKCPPLIB_BOOST_UNIT_TEST_CUSTOM_MAIN_DEFINED
|
|
#include <boost/test/unit_test.hpp>
|
|
#include <boost/test/unit_test_monitor.hpp>
|
|
|
|
#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<T, E>` using `checked<T, E>`.
|
|
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 <class T, class E> using expected_result = BOOST_OUTCOME_V2_NAMESPACE::checked<T, E>;
|
|
template <class T, class E> struct enable_default_constructor : public expected_result<T, E>
|
|
{
|
|
using base = expected_result<T, E>;
|
|
using base::base;
|
|
constexpr enable_default_constructor()
|
|
: base{BOOST_OUTCOME_V2_NAMESPACE::in_place_type<T>}
|
|
{
|
|
}
|
|
};
|
|
template <class T, class E> using select_expected_base = std::conditional_t<std::is_default_constructible<T>::value, enable_default_constructor<T, E>, expected_result<T, E>>;
|
|
} // namespace detail
|
|
template <class T, class E> class expected : public detail::select_expected_base<T, E>
|
|
{
|
|
static_assert(!std::is_same<T, E>::value, "T and E cannot be the same in this expected implementation");
|
|
using base = detail::select_expected_base<T, E>;
|
|
|
|
public:
|
|
// Inherit base's constructors
|
|
using base::base;
|
|
expected() = default;
|
|
|
|
// Expected takes in_place not in_place_type
|
|
template <class... Args>
|
|
constexpr explicit expected(in_place_t /*unused*/, Args &&... args)
|
|
: base{BOOST_OUTCOME_V2_NAMESPACE::in_place_type<T>, std::forward<Args>(args)...}
|
|
{
|
|
}
|
|
|
|
// Expected always accepts a T even if ambiguous
|
|
BOOST_OUTCOME_TEMPLATE(class U)
|
|
BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(std::is_constructible<T, U>::value))
|
|
constexpr expected(U &&v) // NOLINT
|
|
: base{BOOST_OUTCOME_V2_NAMESPACE::in_place_type<T>, std::forward<U>(v)}
|
|
{
|
|
}
|
|
|
|
// Expected has an emplace() modifier
|
|
template <class... Args> void emplace(Args &&... args) { *static_cast<base *>(this) = base{BOOST_OUTCOME_V2_NAMESPACE::in_place_type<T>, std::forward<Args>(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 E> class expected<void, E> : public BOOST_OUTCOME_V2_NAMESPACE::result<void, E, BOOST_OUTCOME_V2_NAMESPACE::policy::throw_bad_result_access<E, void>>
|
|
{
|
|
using base = BOOST_OUTCOME_V2_NAMESPACE::result<void, E, BOOST_OUTCOME_V2_NAMESPACE::policy::throw_bad_result_access<E, void>>;
|
|
|
|
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 <class E> using unexpected = BOOST_OUTCOME_V2_NAMESPACE::failure_type<E>;
|
|
template <class E> unexpected<E> make_unexpected(E &&arg) { return BOOST_OUTCOME_V2_NAMESPACE::failure<E>(std::forward<E>(arg)); }
|
|
template <class E, class... Args> unexpected<E> make_unexpected(Args &&... args) { return BOOST_OUTCOME_V2_NAMESPACE::failure<E>(std::forward<Args>(args)...); }
|
|
template <class E> using bad_expected_access = BOOST_OUTCOME_V2_NAMESPACE::bad_result_access_with<E>;
|
|
//! [expected_implementation]
|
|
|
|
// Not actually part of the Expected proposal, but needed to pass the test
|
|
template <typename T> using exception_or = expected<T, std::exception_ptr>;
|
|
} // namespace stde
|
|
|
|
template <class T> using expected_sc = stde::expected<T, std::error_code>;
|
|
|
|
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 <class T> 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<int> 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<bool>(e));
|
|
}
|
|
|
|
|
|
void except_default_constructor_error_code()
|
|
{
|
|
// From value constructor.
|
|
stde::expected<int, std::error_code> e;
|
|
BOOST_TEST(e.has_value());
|
|
BOOST_TEST(e);
|
|
BOOST_TEST(static_cast<bool>(e));
|
|
}
|
|
|
|
void except_default_constructor_constexpr()
|
|
{
|
|
// From value constructor.
|
|
BOOST_CONSTEXPR stde::expected<int, long> 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<T &>(), std::declval<T &>())), "");
|
|
static_assert(std::is_nothrow_copy_constructible<E>::value, "");
|
|
// static_assert(noexcept(stde::adl::swap_impl(std::declval<E &>(), std::declval<E &>())), "");
|
|
|
|
static_assert(std::is_nothrow_copy_constructible<expected_sc<int>>::value, "");
|
|
static_assert(std::is_nothrow_copy_assignable<expected_sc<int>>::value, "");
|
|
static_assert(std::is_nothrow_move_constructible<expected_sc<int>>::value, "");
|
|
static_assert(std::is_nothrow_move_assignable<expected_sc<int>>::value, "");
|
|
|
|
// From value constructor.
|
|
expected_sc<int> 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<bool>(e));
|
|
}
|
|
|
|
void expected_from_value2()
|
|
{
|
|
// From value constructor.
|
|
expected_sc<int> e(5);
|
|
e = {};
|
|
BOOST_TEST(e.has_value());
|
|
BOOST_TEST_EQ(e.value(), 0);
|
|
}
|
|
|
|
void expected_from_cnv_value()
|
|
{
|
|
OracleVal v;
|
|
expected_sc<Oracle> 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<Oracle> 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<NDCE> 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<expected_sc<NDC>>::value, "");
|
|
static_assert(std::is_nothrow_copy_assignable<expected_sc<NDC>>::value, "");
|
|
static_assert(std::is_nothrow_move_constructible<expected_sc<NDC>>::value, "");
|
|
static_assert(std::is_nothrow_move_assignable<expected_sc<NDC>>::value, "");
|
|
expected_sc<NDC> e{1};
|
|
BOOST_TEST(e.has_value());
|
|
}
|
|
|
|
void except_constructor_Date()
|
|
{
|
|
static_assert(std::is_nothrow_move_constructible<expected_sc<Date>>::value, "");
|
|
static_assert(std::is_nothrow_move_assignable<expected_sc<Date>>::value, "");
|
|
expected_sc<Date> e{Date{1}};
|
|
BOOST_TEST(e.has_value());
|
|
}
|
|
|
|
void except_constructor_TExcept()
|
|
{
|
|
static_assert(!std::is_nothrow_move_constructible<expected_sc<TExcept>>::value, "");
|
|
static_assert(!std::is_nothrow_move_assignable<expected_sc<TExcept>>::value, "");
|
|
expected_sc<TExcept> e{TExcept{1}};
|
|
BOOST_TEST(e.has_value());
|
|
}
|
|
|
|
void expected_from_in_place_value()
|
|
{
|
|
OracleVal v;
|
|
expected_sc<Oracle> 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<Oracle> 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<int> 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<bool>(e), false);
|
|
}
|
|
#endif
|
|
|
|
void expected_from_copy_value()
|
|
{
|
|
// From copy constructor.
|
|
expected_sc<int> ef(5);
|
|
expected_sc<int> 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<bool>(e));
|
|
}
|
|
|
|
#if 0
|
|
void expected_from_copy_exception()
|
|
{
|
|
// From stde::unexpected constructor.
|
|
stde::exception_or<int> ef(stde::make_unexpected(test_exception()));
|
|
stde::exception_or<int> e(ef);
|
|
BOOST_TEST_THROWS(e.value(), test_exception);
|
|
BOOST_TEST_EQ(e.has_value(), false);
|
|
BOOST_TEST_EQ(static_cast<bool>(e), false);
|
|
}
|
|
#endif
|
|
|
|
void expected_from_in_place()
|
|
{
|
|
// From stde::in_place constructor.
|
|
expected_sc<std::string> 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<bool>(e));
|
|
}
|
|
|
|
#if 0
|
|
void expected_from_exception_ptr()
|
|
{
|
|
// From exception_ptr constructor.
|
|
stde::exception_or<int> 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<bool>(e), false);
|
|
}
|
|
#endif
|
|
|
|
void expected_from_moved_value()
|
|
{
|
|
// From move value constructor.
|
|
std::string value = "my value";
|
|
expected_sc<std::string> 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<bool>(e));
|
|
}
|
|
|
|
void expected_from_catch_block()
|
|
{
|
|
// From catch block
|
|
try
|
|
{
|
|
throw test_exception();
|
|
}
|
|
catch(...)
|
|
{
|
|
stde::exception_or<int> 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<bool>(e), false);
|
|
}
|
|
}
|
|
|
|
|
|
void make_expected_E_from_value()
|
|
{
|
|
// auto e = stde::make_expected<std::string>( 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<const int>(i);
|
|
(void) e;
|
|
// static_assert(std::is_same<decltype(e), stde::success<const int>>::value, "");
|
|
#endif
|
|
}
|
|
void make_expected_from_U_value()
|
|
{
|
|
expected_sc<int> e = expected_sc<int>(short(5));
|
|
static_assert(std::is_same<decltype(e), expected_sc<int>>{}, "");
|
|
BOOST_TEST_EQ(e.has_value(), true);
|
|
}
|
|
void make_expected_from_U_value2()
|
|
{
|
|
expected_sc<std::string> e = expected_sc<std::string>("aa");
|
|
static_assert(std::is_same<decltype(e), expected_sc<std::string>>{}, "");
|
|
BOOST_TEST_EQ(e.has_value(), true);
|
|
}
|
|
|
|
void expected_from_value_error_condition()
|
|
{
|
|
// From value constructor.
|
|
stde::expected<int, std::error_condition> 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<bool>(e));
|
|
}
|
|
|
|
void expected_from_error_error_condition()
|
|
{
|
|
// From stde::unexpected constructor.
|
|
stde::expected<int, std::error_condition> e(stde::make_unexpected<std::error_condition>(std::make_error_condition(std::errc::invalid_argument)));
|
|
auto error_from_except_check = [](const stde::bad_expected_access<std::error_condition> &except) { return std::errc(except.error().value()) == std::errc::invalid_argument; };
|
|
try
|
|
{
|
|
(void) e.value();
|
|
}
|
|
catch(stde::bad_expected_access<std::error_condition> &ex)
|
|
{
|
|
BOOST_TEST(error_from_except_check(ex));
|
|
}
|
|
BOOST_TEST_EQ(e.has_value(), false);
|
|
BOOST_TEST_EQ(static_cast<bool>(e), false);
|
|
}
|
|
|
|
|
|
void expected_from_error_convertible()
|
|
{
|
|
{
|
|
stde::expected<int, short> e1 = stde::make_unexpected<short>(1);
|
|
stde::expected<int, long> e2(e1);
|
|
BOOST_TEST_EQ(e2.has_value(), false);
|
|
BOOST_TEST_EQ(static_cast<bool>(e2), false);
|
|
BOOST_TEST_EQ(e2.error(), 1);
|
|
}
|
|
{
|
|
stde::expected<void, short> e1 = stde::make_unexpected<short>(1);
|
|
stde::expected<void, int> e2(e1);
|
|
BOOST_TEST_EQ(e2.has_value(), false);
|
|
BOOST_TEST_EQ(static_cast<bool>(e2), false);
|
|
BOOST_TEST_EQ(e2.error(), 1);
|
|
}
|
|
}
|
|
|
|
void except_valid_constexpr_int()
|
|
{
|
|
// From value constructor.
|
|
BOOST_CONSTEXPR stde::expected<int, long> e;
|
|
BOOST_CONSTEXPR bool b = e.has_value();
|
|
BOOST_TEST(b);
|
|
}
|
|
void except_value_constexpr_int()
|
|
{
|
|
// From value constructor.
|
|
BOOST_CONSTEXPR stde::expected<int, long> e(1);
|
|
BOOST_CONSTEXPR int x = e.value();
|
|
BOOST_TEST_EQ(x, 1);
|
|
}
|
|
|
|
void expected_from_value3()
|
|
{
|
|
expected_sc<int> 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<bool>(e));
|
|
}
|
|
|
|
void expected_from_copy_expected()
|
|
{
|
|
expected_sc<int> e(5);
|
|
expected_sc<int> 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<bool>(e));
|
|
}
|
|
|
|
void expected_from_moved_expected()
|
|
{
|
|
expected_sc<std::string> e("e");
|
|
expected_sc<std::string> 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<bool>(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<bool>(e2));
|
|
}
|
|
|
|
void expected_from_in_place2()
|
|
{
|
|
// From stde::in_place constructor.
|
|
expected_sc<std::string> 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<bool>(e));
|
|
}
|
|
|
|
void expected_from_move_value()
|
|
{
|
|
expected_sc<std::string> 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<bool>(e));
|
|
}
|
|
|
|
|
|
void expected_from_in_place3()
|
|
{
|
|
// From stde::in_place factory.
|
|
// auto e = stde::make_expected<std::string>("stde::in_place");
|
|
auto e = expected_sc<std::string>("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<bool>(e));
|
|
}
|
|
void expected_from_in_place_error()
|
|
{
|
|
// From stde::in_place factory.
|
|
auto e = stde::expected<std::string, std::error_condition>("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<bool>(e));
|
|
}
|
|
|
|
void expected_from_exception_catch()
|
|
{
|
|
// From catch block
|
|
try
|
|
{
|
|
throw test_exception();
|
|
}
|
|
catch(...)
|
|
{
|
|
stde::exception_or<int> 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<bool>(e), false);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
void expected_from_error()
|
|
{
|
|
// From stde::unexpected constructor.
|
|
auto e = stde::make_expected_from_error<int>(std::make_error_condition(std::errc::invalid_argument));
|
|
auto error_from_except_check = [](const stde::bad_expected_access<std::error_condition> &except) { return std::errc(except.error().value()) == std::errc::invalid_argument; };
|
|
try
|
|
{
|
|
(void) e.value();
|
|
}
|
|
catch(stde::bad_expected_access<std::error_condition> &ex)
|
|
{
|
|
BOOST_TEST(error_from_except_check(ex));
|
|
}
|
|
BOOST_TEST_EQ(e.has_value(), false);
|
|
BOOST_TEST_EQ(static_cast<bool>(e), false);
|
|
}
|
|
|
|
void expected_from_error_U()
|
|
{
|
|
// From stde::unexpected constructor.
|
|
auto e = stde::make_expected_from_error<int, short>(42);
|
|
static_assert(std::is_same<decltype(e), stde::expected<int, short>>{}, "");
|
|
BOOST_TEST_EQ(e.has_value(), false);
|
|
BOOST_TEST_EQ(static_cast<bool>(e), false);
|
|
}
|
|
|
|
void expected_from_exception2()
|
|
{
|
|
// From stde::unexpected constructor.
|
|
auto e = stde::make_expected_from_exception<int>(test_exception());
|
|
// auto e = expected_sc<int>(stde::unexpected<>(test_exception()));
|
|
BOOST_TEST_THROWS(e.value(), test_exception );
|
|
BOOST_TEST_EQ(e.has_value(), false);
|
|
BOOST_TEST_EQ(static_cast<bool>(e), false);
|
|
}
|
|
|
|
void expected_from_exception_ptr2()
|
|
{
|
|
// From exception_ptr constructor.
|
|
auto e = stde::exception_or<int>(stde::make_unexpected(test_exception()));
|
|
BOOST_TEST_THROWS(e.value(), test_exception );
|
|
BOOST_TEST_EQ(e.has_value(), false);
|
|
BOOST_TEST_EQ(static_cast<bool>(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<int> 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<bool>(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<bool>(e), true);
|
|
|
|
#if 0
|
|
BOOST_TEST_THROWS(stde::make_expected_from_call<std::error_condition>(throwing_fun), test_exception);
|
|
|
|
BOOST_TEST_NO_THROW(stde::make_expected_from_call<std::error_condition>(nothrowing_fun));
|
|
stde::expected<int, std::error_condition> e2 = stde::make_expected_from_call<std::error_condition>(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<bool>(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<void> 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<bool>(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<bool>(e), true);
|
|
|
|
BOOST_TEST_THROWS(stde::make_expected_from_call<std::error_condition>(void_throwing_fun), test_exception);
|
|
|
|
try {
|
|
stde::make_expected_from_call<std::error_condition>(do_nothing_fun);
|
|
BOOST_TEST(true);
|
|
}
|
|
catch (...)
|
|
{
|
|
BOOST_TEST(false);
|
|
}
|
|
stde::expected<void, std::error_condition> e2 = stde::make_expected_from_call<std::error_condition>(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<bool>(e2), true);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
void expected_swap_value()
|
|
{
|
|
// From value constructor.
|
|
expected_sc<int> e(5);
|
|
expected_sc<int> 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<int> e = stde::make_unexpected(std::invalid_argument("e"));
|
|
stde::exception_or<int> 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<int> e(5);
|
|
expected_sc<int> 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<NoDefaultConstructible>::value, "");
|
|
static_assert(!std::is_default_constructible<expected_sc<NoDefaultConstructible>>::value, "");
|
|
|
|
static_assert(!std::is_copy_constructible<NoCopyConstructible>::value, "");
|
|
static_assert(!std::is_constructible<expected_sc<NoCopyConstructible>, NoCopyConstructible const &>::value, "");
|
|
static_assert(!std::is_constructible<stde::exception_or<NoCopyConstructible>, stde::exception_or<NoCopyConstructible> const &>::value, "");
|
|
static_assert(!std::is_copy_constructible<stde::exception_or<NoCopyConstructible>>::value, "");
|
|
|
|
#if 0
|
|
// fixme
|
|
{
|
|
NoMoveConstructible nmc;
|
|
// NoMoveConstructible nmc2 = std::move(nmc); // FAILS as expected
|
|
|
|
expected_sc<NoMoveConstructible> 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<NoMoveConstructible> x = std::move(nmc); // DOESN'T FAIL as copy is selected instead
|
|
(void) x;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
static_assert(!std::is_move_constructible<NoMoveConstructible>::value, "");
|
|
static_assert(!std::is_constructible<expected_sc<NoMoveConstructible>, NoMoveConstructible &&>::value, "");
|
|
static_assert(std::is_move_constructible<expected_sc<NoMoveConstructible>>::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<int,std::error_condition>();};
|
|
//
|
|
// //BOOST_TEST_THROWS(throw_lambda(), test_exception);
|
|
// }
|
|
//}
|
|
|
|
|
|
|
|
////////////////////////////////////
|
|
BOOST_AUTO_TEST_SUITE(expected_map)
|
|
|
|
void expected_map()
|
|
{
|
|
auto fun = [](bool b) -> expected_sc<int>
|
|
{
|
|
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<int> 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<void>(stde::make_unexpected(test_exception()));
|
|
};
|
|
|
|
auto launch_except = []() -> void
|
|
{
|
|
throw test_exception();
|
|
};
|
|
|
|
auto do_nothing = []() {};
|
|
|
|
expected_sc<void> 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<int>
|
|
{
|
|
if (b)
|
|
return stde::make_expected(5);
|
|
else
|
|
return stde::make_unexpected(test_exception());
|
|
};
|
|
|
|
auto add_five = [](int sum) -> expected_sc<int>
|
|
{
|
|
return stde::make_expected(sum + 5);
|
|
};
|
|
|
|
auto launch_except = [](int sum) -> expected_sc<int>
|
|
{
|
|
throw test_exception();
|
|
};
|
|
|
|
expected_sc<int> 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<void>(stde::make_unexpected(test_exception()));
|
|
};
|
|
|
|
auto launch_except = []() -> expected_sc<void>
|
|
{
|
|
throw test_exception();
|
|
};
|
|
|
|
auto do_nothing = []() {
|
|
return stde::make_expected();
|
|
};
|
|
|
|
expected_sc<void> 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<int>
|
|
{
|
|
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>) -> int
|
|
{
|
|
throw test_exception();
|
|
};
|
|
|
|
expected_sc<int> 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<bool> 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<void>
|
|
{
|
|
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<void> 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<int>(5);
|
|
else
|
|
return expected_sc<int>(stde::make_unexpected(test_exception()));
|
|
};
|
|
|
|
auto add_five = [](int sum) -> expected_sc<int>
|
|
{
|
|
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<int>(stde::make_unexpected(p));
|
|
};
|
|
|
|
auto recover_error_failure = [](std::exception_ptr p) -> expected_sc<int>
|
|
{
|
|
return expected_sc<int>(stde::make_unexpected(test_exception()));
|
|
};
|
|
|
|
auto recover_error_throws = [](std::exception_ptr p) -> expected_sc<int>
|
|
{
|
|
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<void>(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<void>(boost::stde::make_unexpected(p));
|
|
};
|
|
|
|
auto recover_error_failure = [](std::exception_ptr p) -> expected_sc<void>
|
|
{
|
|
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<int, string> ei = 0;
|
|
stde::expected<int, string> ej = 1;
|
|
stde::expected<int, string> 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<string, int> ep{ stde::make_unexpected(-1) }; // unexpected value, requires Movable<E>
|
|
stde::expected<string, int> eq = { stde::make_unexpected(-1) }; // unexpected value, requires Movable<E>
|
|
|
|
expected_sc<string> es{ s }; // requires Copyable<T>
|
|
expected_sc<string> et = s; // requires Copyable<T>
|
|
expected_sc<string> ev = string{ "STR" }; // requires Movable<T>
|
|
|
|
expected_sc<string> ew; // unexpected value
|
|
expected_sc<string> ex{}; // unexpected value
|
|
expected_sc<string> ey = {}; // unexpected value
|
|
expected_sc<string> ez = expected_sc<string>{}; // unexpected value
|
|
}
|
|
|
|
{
|
|
stde::expected<Guard, int> eg; // unexpected value
|
|
stde::expected<Guard, int> eh{}; // unexpected value
|
|
stde::expected<Guard, int> ei{ stde::in_place }; // calls Guard{} in place
|
|
stde::expected<Guard, int> ej{ stde::in_place, "arg" }; // calls Guard{"arg"} in place
|
|
}
|
|
|
|
{
|
|
stde::expected<int, string> ei{ unexpect }; // unexpected value, calls string{} in place
|
|
stde::expected<int, string> ej{ unexpect, "arg" }; // unexpected value, calls string{"arg"} in place
|
|
}
|
|
}
|
|
void proposal_make_unexpected_fact()
|
|
{
|
|
using namespace std;
|
|
{
|
|
stde::expected<string, int> opt1 = stde::make_unexpected(1);
|
|
stde::expected<string, int> opt2 = { unexpect, 1 };
|
|
|
|
opt1 = stde::make_unexpected(1);
|
|
opt2 = { unexpect, 1 };
|
|
}
|
|
}
|
|
void proposal_error_exception_ts()
|
|
{
|
|
using namespace std;
|
|
{
|
|
stde::expected<int, error_exception<std::error_code, std::system_error> > 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,std::system_error>, std::error_code)
|
|
BOOST_TEST(e.error() == (error_exception<std::error_code, std::system_error>(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<int, error_exception<std::error_code, std::system_error> > 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,std::system_error>, std::error_code)
|
|
BOOST_TEST(e2.error() == (error_exception<std::error_code, std::system_error>(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<int> e = make_ensured_read(1);
|
|
BOOST_TEST(e == 1);
|
|
}
|
|
{
|
|
ensured_read<int> e = make_ensured_read(1);
|
|
stde::unexpected<ensured_read<int>> ue1 = stde::make_unexpected(std::move(e));
|
|
BOOST_TEST(ue1.value() == 1);
|
|
}
|
|
// {
|
|
// stde::make_unexpected(make_ensured_read(1));
|
|
// // calls to terminate.
|
|
// }
|
|
// {
|
|
// stde::expected<int, ensured_read<int> > e = stde::make_unexpected(make_ensured_read(1));
|
|
// // calls to terminate.
|
|
// }
|
|
{
|
|
stde::expected<int, ensured_read<int> > e{ 1 };
|
|
BOOST_TEST(e.value() == 1);
|
|
}
|
|
{
|
|
stde::expected<int, ensured_read<int> > e = stde::make_unexpected(make_ensured_read(1));
|
|
BOOST_TEST(e.error() == 1);
|
|
}
|
|
{
|
|
stde::expected<int, ensured_read<int> > e{ unexpect, 1 };
|
|
BOOST_TEST(e.error() == 1);
|
|
}
|
|
{
|
|
ensured_read<std::exception_ptr> e = make_ensured_read(std::make_exception_ptr(1));
|
|
BOOST_TEST_THROWS(std::rethrow_exception(e.value()), int);
|
|
}
|
|
{
|
|
stde::expected<int, ensured_read<std::exception_ptr> > 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<unsigned, int> e0{ 0 };
|
|
stde::expected<unsigned, int> e1{ 1 };
|
|
stde::expected<unsigned, int> 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<void, int> e0{ boost::expect };
|
|
stde::expected<void, int> 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<string> e0{ s };
|
|
const expected_sc<string> 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<OverloadedAddressOf> e2{ o };
|
|
const expected_sc<OverloadedAddressOf> 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<int> i{ 1 }, j{ 2 };
|
|
BOOST_TEST(i.val == 1);
|
|
BOOST_TEST(!i.moved);
|
|
BOOST_TEST(j.val == 2);
|
|
BOOST_TEST(!j.moved);
|
|
|
|
MoveAware<int> 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<MoveAware<int>> oi{ 1 }, oj{ 2 };
|
|
BOOST_TEST(oi);
|
|
BOOST_TEST(!oi->moved);
|
|
BOOST_TEST(oj);
|
|
BOOST_TEST(!oj->moved);
|
|
|
|
expected_sc<MoveAware<int>> 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<int> value{ new int };
|
|
*value = 100;
|
|
return value;
|
|
};
|
|
const auto return_void = [](std::unique_ptr<int> value) {
|
|
BOOST_TEST(value != nullptr);
|
|
BOOST_TEST(*value == 100);
|
|
};
|
|
const auto return_expected = [](std::unique_ptr<int> value) {
|
|
BOOST_TEST(value != nullptr);
|
|
BOOST_TEST(*value == 100);
|
|
return expected_sc<void>{boost::expect};
|
|
};
|
|
const auto return_int = [](std::unique_ptr<int> value) {
|
|
BOOST_TEST(value != nullptr);
|
|
BOOST_TEST(*value == 100);
|
|
return 200;
|
|
};
|
|
|
|
BOOST_TEST(expected<std::unique_ptr<int>>{make_int()}.map(return_void));
|
|
BOOST_TEST(expected<std::unique_ptr<int>>{make_int()}.map(return_expected));
|
|
BOOST_TEST(expected<std::unique_ptr<int>>{make_int()}.map(return_int));
|
|
}
|
|
void movesem_move_only_value2()
|
|
{
|
|
const auto make_int = []() {
|
|
std::unique_ptr<int> value{ new int };
|
|
*value = 100;
|
|
return value;
|
|
};
|
|
const auto return_expected_void = [](std::unique_ptr<int> value) {
|
|
BOOST_TEST(value != nullptr);
|
|
BOOST_TEST(*value == 100);
|
|
return stde::make_expected();
|
|
};
|
|
const auto return_expected = [](std::unique_ptr<int> value) {
|
|
BOOST_TEST(value != nullptr);
|
|
BOOST_TEST(*value == 100);
|
|
return expected_sc<void>{boost::expect};
|
|
};
|
|
BOOST_TEST(expected<std::unique_ptr<int>>{make_int()}.bind(return_expected_void));
|
|
BOOST_TEST(expected<std::unique_ptr<int>>{make_int()}.bind(return_expected));
|
|
}
|
|
void movesem_copy_move_ctor_optional_int()
|
|
{
|
|
expected_sc<int> oi;
|
|
expected_sc<int> oj = oi;
|
|
|
|
BOOST_TEST(oj);
|
|
BOOST_TEST(oj == oi);
|
|
BOOST_TEST(bool(oj));
|
|
|
|
oi = 1;
|
|
expected_sc<int> ok = oi;
|
|
BOOST_TEST(!!ok);
|
|
BOOST_TEST(bool(ok));
|
|
BOOST_TEST(ok == oi);
|
|
BOOST_TEST(ok != oj);
|
|
BOOST_TEST(*ok == 1);
|
|
|
|
expected_sc<int> 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<stde::expected<int, int>> oi1 = stde::make_unexpected(-1);
|
|
BOOST_TEST(!oi1);
|
|
|
|
{
|
|
expected_sc<expected_sc<int>> oi2{ stde::expect };
|
|
BOOST_TEST(bool(oi2));
|
|
BOOST_TEST((*oi2));
|
|
//std::cout << typeid(**oi2).name() << std::endl;
|
|
}
|
|
|
|
{
|
|
expected_sc<stde::expected<int, int>> oi2{ stde::expect, stde::make_unexpected(-1) };
|
|
BOOST_TEST(bool(oi2));
|
|
BOOST_TEST(!*oi2);
|
|
}
|
|
|
|
{
|
|
stde::expected<stde::expected<int>> oi2{ stde::expected<int>{} };
|
|
BOOST_TEST(bool(oi2));
|
|
BOOST_TEST(*oi2);
|
|
}
|
|
|
|
stde::expected<int> oi;
|
|
auto ooi = stde::make_expected(oi);
|
|
static_assert(std::is_same<expected<expected<int>>, decltype(ooi)>::value, "");
|
|
|
|
}
|
|
BOOST_AUTO_TEST_SUITE_END()
|
|
|
|
void process() {}
|
|
void process(int) {}
|
|
void processNil() {}
|
|
|
|
BOOST_AUTO_TEST_SUITE(Examples)
|
|
//////////////////////////////
|
|
|
|
void example1()
|
|
{
|
|
stde::expected<int> oi; // create disengaged object
|
|
stde::expected<int> oj = { unexpect }; // alternative syntax
|
|
oi = oj; // assign disengaged object
|
|
stde::expected<int> 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<int> 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<int> om{ 1 }; // om is engaged; its contained value is 1
|
|
stde::expected<int> 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<int> 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<int> oi = 1;
|
|
int i = oi.value_or(0);
|
|
BOOST_TEST(i == 1);
|
|
|
|
oi = { unexpect };
|
|
BOOST_TEST(oi.value_or(3) == 3);
|
|
|
|
stde::expected<std::string> 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<int> 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<int> e = stde::make_unexpected(ec);
|
|
static_assert(!e.has_value(), "");
|
|
static_assert(e.error() == ec, "");
|
|
}
|
|
{
|
|
constexpr stde::expected<OracleVal> 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<OracleVal> 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
|