first commit

This commit is contained in:
stuce-bot 2025-06-30 20:47:33 +02:00
commit 5893b00dd2
1669 changed files with 1982740 additions and 0 deletions

View file

@ -0,0 +1,19 @@
#include <gtest/gtest.h>
// #include <stdexcept>
// #define TL_ASSERT(cond) if (!(cond)) { throw std::runtime_error(std::string("assertion failure")); }
#include <m5_utility/stl/expected.hpp>
#if 0
TEST(Expected, Assertions) {
m5::stl::expected<int,int> o1 = 42;
EXPECT_ANY_THROW(o1.error());
m5::stl::expected<int,int> o2 {m5::stl::unexpect, 0};
EXPECT_ANY_THROW(*o2);
struct foo { int bar; };
m5::stl::expected<struct foo,int> o3 {m5::stl::unexpect, 0};
EXPECT_ANY_THROW(o3->bar);
}
#endif

View file

@ -0,0 +1,86 @@
#include <gtest/gtest.h>
#include <m5_utility/stl/expected.hpp>
TEST(Expected, Assignment)
{
m5::stl::expected<int, int> e1 = 42;
m5::stl::expected<int, int> e2 = 17;
m5::stl::expected<int, int> e3 = 21;
m5::stl::expected<int, int> e4 = m5::stl::make_unexpected(42);
m5::stl::expected<int, int> e5 = m5::stl::make_unexpected(17);
m5::stl::expected<int, int> e6 = m5::stl::make_unexpected(21);
e1 = e2;
EXPECT_TRUE(e1);
EXPECT_TRUE(*e1 == 17);
EXPECT_TRUE(e2);
EXPECT_TRUE(*e2 == 17);
e1 = std::move(e2);
EXPECT_TRUE(e1);
EXPECT_TRUE(*e1 == 17);
EXPECT_TRUE(e2);
EXPECT_TRUE(*e2 == 17);
e1 = 42;
EXPECT_TRUE(e1);
EXPECT_TRUE(*e1 == 42);
auto unex = m5::stl::make_unexpected(12);
e1 = unex;
EXPECT_TRUE(!e1);
EXPECT_TRUE(e1.error() == 12);
e1 = m5::stl::make_unexpected(42);
EXPECT_TRUE(!e1);
EXPECT_TRUE(e1.error() == 42);
e1 = e3;
EXPECT_TRUE(e1);
EXPECT_TRUE(*e1 == 21);
e4 = e5;
EXPECT_TRUE(!e4);
EXPECT_TRUE(e4.error() == 17);
e4 = std::move(e6);
EXPECT_TRUE(!e4);
EXPECT_TRUE(e4.error() == 21);
e4 = e1;
EXPECT_TRUE(e4);
EXPECT_TRUE(*e4 == 21);
}
TEST(Expected, AssignmentDeletion)
{
struct has_all {
has_all() = default;
has_all(const has_all &) = default;
has_all(has_all &&) noexcept = default;
has_all &operator=(const has_all &) = default;
};
m5::stl::expected<has_all, has_all> e1 = {};
m5::stl::expected<has_all, has_all> e2 = {};
e1 = e2;
struct except_move {
except_move() = default;
except_move(const except_move &) = default;
except_move(except_move &&) noexcept(false)
{
}
except_move &operator=(const except_move &) = default;
};
// m5::stl::expected<except_move, except_move> e3 = {};
// m5::stl::expected<except_move, except_move> e4 = {};
// e3 = e4; //should not compile
}

View file

@ -0,0 +1,218 @@
#include <gtest/gtest.h>
#include <m5_utility/stl/expected.hpp>
#include <string>
// Old versions of GCC don't have the correct trait names. Could fix them up if needs be.
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__))
// nothing for now
#else
TEST(Expected, Triviality)
{
EXPECT_TRUE((std::is_trivially_copy_constructible<m5::stl::expected<int, int> >::value));
EXPECT_TRUE((std::is_trivially_copy_assignable<m5::stl::expected<int, int> >::value));
EXPECT_TRUE((std::is_trivially_move_constructible<m5::stl::expected<int, int> >::value));
EXPECT_TRUE((std::is_trivially_move_assignable<m5::stl::expected<int, int> >::value));
EXPECT_TRUE((std::is_trivially_destructible<m5::stl::expected<int, int> >::value));
EXPECT_TRUE((std::is_trivially_copy_constructible<m5::stl::expected<void, int> >::value));
EXPECT_TRUE((std::is_trivially_move_constructible<m5::stl::expected<void, int> >::value));
EXPECT_TRUE((std::is_trivially_destructible<m5::stl::expected<void, int> >::value));
{
struct T {
T(const T&) = default;
T(T&&) = default;
T& operator=(const T&) = default;
T& operator=(T&&) = default;
~T() = default;
};
EXPECT_TRUE((std::is_trivially_copy_constructible<m5::stl::expected<T, int> >::value));
EXPECT_TRUE((std::is_trivially_copy_assignable<m5::stl::expected<T, int> >::value));
EXPECT_TRUE((std::is_trivially_move_constructible<m5::stl::expected<T, int> >::value));
EXPECT_TRUE((std::is_trivially_move_assignable<m5::stl::expected<T, int> >::value));
EXPECT_TRUE((std::is_trivially_destructible<m5::stl::expected<T, int> >::value));
}
{
struct T {
T(const T&)
{
}
T(T&&)
{
}
T& operator=(const T&)
{
return *this;
}
T& operator=(T&&)
{
return *this;
}
~T()
{
}
};
EXPECT_TRUE(!(std::is_trivially_copy_constructible<m5::stl::expected<T, int> >::value));
EXPECT_TRUE(!(std::is_trivially_copy_assignable<m5::stl::expected<T, int> >::value));
EXPECT_TRUE(!(std::is_trivially_move_constructible<m5::stl::expected<T, int> >::value));
EXPECT_TRUE(!(std::is_trivially_move_assignable<m5::stl::expected<T, int> >::value));
EXPECT_TRUE(!(std::is_trivially_destructible<m5::stl::expected<T, int> >::value));
}
}
TEST(Expected, Deletion)
{
EXPECT_TRUE((std::is_copy_constructible<m5::stl::expected<int, int> >::value));
EXPECT_TRUE((std::is_copy_assignable<m5::stl::expected<int, int> >::value));
EXPECT_TRUE((std::is_move_constructible<m5::stl::expected<int, int> >::value));
EXPECT_TRUE((std::is_move_assignable<m5::stl::expected<int, int> >::value));
EXPECT_TRUE((std::is_destructible<m5::stl::expected<int, int> >::value));
{
struct T {
T() = default;
};
EXPECT_TRUE((std::is_default_constructible<m5::stl::expected<T, int> >::value));
}
{
struct T {
T(int)
{
}
};
EXPECT_TRUE(!(std::is_default_constructible<m5::stl::expected<T, int> >::value));
}
{
struct T {
T(const T&) = default;
T(T&&) = default;
T& operator=(const T&) = default;
T& operator=(T&&) = default;
~T() = default;
};
EXPECT_TRUE((std::is_copy_constructible<m5::stl::expected<T, int> >::value));
EXPECT_TRUE((std::is_copy_assignable<m5::stl::expected<T, int> >::value));
EXPECT_TRUE((std::is_move_constructible<m5::stl::expected<T, int> >::value));
EXPECT_TRUE((std::is_move_assignable<m5::stl::expected<T, int> >::value));
EXPECT_TRUE((std::is_destructible<m5::stl::expected<T, int> >::value));
}
{
struct T {
T(const T&) = delete;
T(T&&) = delete;
T& operator=(const T&) = delete;
T& operator=(T&&) = delete;
};
EXPECT_TRUE(!(std::is_copy_constructible<m5::stl::expected<T, int> >::value));
EXPECT_TRUE(!(std::is_copy_assignable<m5::stl::expected<T, int> >::value));
EXPECT_TRUE((!std::is_move_constructible<m5::stl::expected<T, int> >::value));
EXPECT_TRUE(!(std::is_move_assignable<m5::stl::expected<T, int> >::value));
}
{
struct T {
T(const T&) = delete;
T(T&&) = default;
T& operator=(const T&) = delete;
T& operator=(T&&) = default;
};
EXPECT_TRUE(!(std::is_copy_constructible<m5::stl::expected<T, int> >::value));
EXPECT_TRUE(!(std::is_copy_assignable<m5::stl::expected<T, int> >::value));
EXPECT_TRUE((std::is_move_constructible<m5::stl::expected<T, int> >::value));
EXPECT_TRUE((std::is_move_assignable<m5::stl::expected<T, int> >::value));
}
{
struct T {
T(const T&) = default;
T(T&&) = delete;
T& operator=(const T&) = default;
T& operator=(T&&) = delete;
};
EXPECT_TRUE((std::is_copy_constructible<m5::stl::expected<T, int> >::value));
EXPECT_TRUE((std::is_copy_assignable<m5::stl::expected<T, int> >::value));
}
{
m5::stl::expected<int, int> e;
EXPECT_TRUE(std::is_default_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_copy_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_move_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_copy_assignable<decltype(e)>::value);
EXPECT_TRUE(std::is_move_assignable<decltype(e)>::value);
EXPECT_TRUE(TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
EXPECT_TRUE(TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
#if !defined(TL_EXPECTED_GCC49)
EXPECT_TRUE(std::is_trivially_move_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_trivially_move_assignable<decltype(e)>::value);
#endif
}
{
m5::stl::expected<int, std::string> e;
EXPECT_TRUE(std::is_default_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_copy_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_move_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_copy_assignable<decltype(e)>::value);
EXPECT_TRUE(std::is_move_assignable<decltype(e)>::value);
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
#if !defined(TL_EXPECTED_GCC49)
EXPECT_TRUE(!std::is_trivially_move_constructible<decltype(e)>::value);
EXPECT_TRUE(!std::is_trivially_move_assignable<decltype(e)>::value);
#endif
}
{
m5::stl::expected<std::string, int> e;
EXPECT_TRUE(std::is_default_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_copy_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_move_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_copy_assignable<decltype(e)>::value);
EXPECT_TRUE(std::is_move_assignable<decltype(e)>::value);
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
#if !defined(TL_EXPECTED_GCC49)
EXPECT_TRUE(!std::is_trivially_move_constructible<decltype(e)>::value);
EXPECT_TRUE(!std::is_trivially_move_assignable<decltype(e)>::value);
#endif
}
{
m5::stl::expected<std::string, std::string> e;
EXPECT_TRUE(std::is_default_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_copy_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_move_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_copy_assignable<decltype(e)>::value);
EXPECT_TRUE(std::is_move_assignable<decltype(e)>::value);
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
#if !defined(TL_EXPECTED_GCC49)
EXPECT_TRUE(!std::is_trivially_move_constructible<decltype(e)>::value);
EXPECT_TRUE(!std::is_trivially_move_assignable<decltype(e)>::value);
#endif
}
}
#endif

View file

@ -0,0 +1,7 @@
#include <gtest/gtest.h>
#include <m5_utility/stl/expected.hpp>
TEST(Expected, Constexpr)
{
// TODO
}

View file

@ -0,0 +1,136 @@
#include <gtest/gtest.h>
#include <m5_utility/stl/expected.hpp>
#include <type_traits>
#include <vector>
#include <string>
struct takes_init_and_variadic {
std::vector<int> v;
std::tuple<int, int> t;
template <class... Args>
takes_init_and_variadic(std::initializer_list<int> l, Args &&...args) : v(l), t(std::forward<Args>(args)...)
{
}
};
TEST(Expected, Constructors)
{
{
m5::stl::expected<int, int> e;
EXPECT_TRUE(e);
EXPECT_TRUE(e == 0);
}
{
m5::stl::expected<int, int> e = m5::stl::make_unexpected(0);
EXPECT_TRUE(!e);
EXPECT_TRUE(e.error() == 0);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 0);
EXPECT_TRUE(!e);
EXPECT_TRUE(e.error() == 0);
}
{
m5::stl::expected<int, int> e(m5::stl::in_place, 42);
EXPECT_TRUE(e);
EXPECT_TRUE(e == 42);
}
{
m5::stl::expected<std::vector<int>, int> e(m5::stl::in_place, {0, 1});
EXPECT_TRUE(e);
EXPECT_TRUE((*e)[0] == 0);
EXPECT_TRUE((*e)[1] == 1);
}
{
m5::stl::expected<std::tuple<int, int>, int> e(m5::stl::in_place, 0, 1);
EXPECT_TRUE(e);
EXPECT_TRUE(std::get<0>(*e) == 0);
EXPECT_TRUE(std::get<1>(*e) == 1);
}
{
m5::stl::expected<takes_init_and_variadic, int> e(m5::stl::in_place, {0, 1}, 2, 3);
EXPECT_TRUE(e);
EXPECT_TRUE(e->v[0] == 0);
EXPECT_TRUE(e->v[1] == 1);
EXPECT_TRUE(std::get<0>(e->t) == 2);
EXPECT_TRUE(std::get<1>(e->t) == 3);
}
{
m5::stl::expected<int, int> e;
EXPECT_TRUE(std::is_default_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_copy_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_move_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_copy_assignable<decltype(e)>::value);
EXPECT_TRUE(std::is_move_assignable<decltype(e)>::value);
EXPECT_TRUE(TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
EXPECT_TRUE(TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
#if !defined(TL_EXPECTED_GCC49)
EXPECT_TRUE(std::is_trivially_move_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_trivially_move_assignable<decltype(e)>::value);
#endif
}
{
m5::stl::expected<int, std::string> e;
EXPECT_TRUE(std::is_default_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_copy_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_move_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_copy_assignable<decltype(e)>::value);
EXPECT_TRUE(std::is_move_assignable<decltype(e)>::value);
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
#if !defined(TL_EXPECTED_GCC49)
EXPECT_TRUE(!std::is_trivially_move_constructible<decltype(e)>::value);
EXPECT_TRUE(!std::is_trivially_move_assignable<decltype(e)>::value);
#endif
}
{
m5::stl::expected<std::string, int> e;
EXPECT_TRUE(std::is_default_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_copy_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_move_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_copy_assignable<decltype(e)>::value);
EXPECT_TRUE(std::is_move_assignable<decltype(e)>::value);
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
#if !defined(TL_EXPECTED_GCC49)
EXPECT_TRUE(!std::is_trivially_move_constructible<decltype(e)>::value);
EXPECT_TRUE(!std::is_trivially_move_assignable<decltype(e)>::value);
#endif
}
{
m5::stl::expected<std::string, std::string> e;
EXPECT_TRUE(std::is_default_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_copy_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_move_constructible<decltype(e)>::value);
EXPECT_TRUE(std::is_copy_assignable<decltype(e)>::value);
EXPECT_TRUE(std::is_move_assignable<decltype(e)>::value);
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
#if !defined(TL_EXPECTED_GCC49)
EXPECT_TRUE(!std::is_trivially_move_constructible<decltype(e)>::value);
EXPECT_TRUE(!std::is_trivially_move_assignable<decltype(e)>::value);
#endif
}
{
m5::stl::expected<void, int> e;
EXPECT_TRUE(e);
}
{
m5::stl::expected<void, int> e(m5::stl::unexpect, 42);
EXPECT_TRUE(!e);
EXPECT_TRUE(e.error() == 42);
}
}

View file

@ -0,0 +1,51 @@
#include <gtest/gtest.h>
#include <m5_utility/stl/expected.hpp>
#include <memory>
#include <vector>
#include <tuple>
namespace {
struct takes_init_and_variadic {
std::vector<int> v;
std::tuple<int, int> t;
template <class... Args>
takes_init_and_variadic(std::initializer_list<int> l, Args &&...args) : v(l), t(std::forward<Args>(args)...)
{
}
};
} // namespace
TEST(Expected, Emplace)
{
{
m5::stl::expected<std::unique_ptr<int>, int> e;
e.emplace(new int{42});
EXPECT_TRUE(e);
EXPECT_TRUE(**e == 42);
}
{
m5::stl::expected<std::vector<int>, int> e;
e.emplace({0, 1});
EXPECT_TRUE(e);
EXPECT_TRUE((*e)[0] == 0);
EXPECT_TRUE((*e)[1] == 1);
}
{
m5::stl::expected<std::tuple<int, int>, int> e;
e.emplace(2, 3);
EXPECT_TRUE(e);
EXPECT_TRUE(std::get<0>(*e) == 2);
EXPECT_TRUE(std::get<1>(*e) == 3);
}
{
m5::stl::expected<::takes_init_and_variadic, int> e = m5::stl::make_unexpected(0);
e.emplace({0, 1}, 2, 3);
EXPECT_TRUE(e);
EXPECT_TRUE(e->v[0] == 0);
EXPECT_TRUE(e->v[1] == 1);
EXPECT_TRUE(std::get<0>(e->t) == 2);
EXPECT_TRUE(std::get<1>(e->t) == 3);
}
}

View file

@ -0,0 +1,832 @@
#include <gtest/gtest.h>
#include <m5_utility/stl/expected.hpp>
#define TOKENPASTE(x, y) x##y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
#undef STATIC_REQUIRE
#define STATIC_REQUIRE(e) \
constexpr bool TOKENPASTE2(rqure, __LINE__) = e; \
(void)TOKENPASTE2(rqure, __LINE__); \
EXPECT_TRUE(e);
TEST(Expected, MapExtensions)
{
auto mul2 = [](int a) { return a * 2; };
auto ret_void = [](int a) { (void)a; };
{
m5::stl::expected<int, int> e = 21;
auto ret = e.map(mul2);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = e.map(mul2);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).map(mul2);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).map(mul2);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.map(mul2);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.map(mul2);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).map(mul2);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).map(mul2);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
m5::stl::expected<int, int> e = 21;
auto ret = e.map(ret_void);
EXPECT_TRUE(ret);
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = e.map(ret_void);
EXPECT_TRUE(ret);
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
}
{
m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).map(ret_void);
EXPECT_TRUE(ret);
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).map(ret_void);
EXPECT_TRUE(ret);
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.map(ret_void);
EXPECT_TRUE(!ret);
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.map(ret_void);
EXPECT_TRUE(!ret);
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).map(ret_void);
EXPECT_TRUE(!ret);
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).map(ret_void);
EXPECT_TRUE(!ret);
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
}
// mapping functions which return references
{
m5::stl::expected<int, int> e(42);
auto ret = e.map([](int& i) -> int& { return i; });
EXPECT_TRUE(ret);
EXPECT_TRUE(ret == 42);
}
}
TEST(Expected, MapErrorExtensions)
{
auto mul2 = [](int a) { return a * 2; };
auto ret_void = [](int a) { (void)a; };
{
m5::stl::expected<int, int> e = 21;
auto ret = e.map_error(mul2);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 21);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = e.map_error(mul2);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 21);
}
{
m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).map_error(mul2);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 21);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).map_error(mul2);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 21);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.map_error(mul2);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 42);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.map_error(mul2);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 42);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).map_error(mul2);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 42);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).map_error(mul2);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 42);
}
{
m5::stl::expected<int, int> e = 21;
auto ret = e.map_error(ret_void);
EXPECT_TRUE(ret);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = e.map_error(ret_void);
EXPECT_TRUE(ret);
}
{
m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).map_error(ret_void);
EXPECT_TRUE(ret);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).map_error(ret_void);
EXPECT_TRUE(ret);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.map_error(ret_void);
EXPECT_TRUE(!ret);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.map_error(ret_void);
EXPECT_TRUE(!ret);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).map_error(ret_void);
EXPECT_TRUE(!ret);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).map_error(ret_void);
EXPECT_TRUE(!ret);
}
}
TEST(Expected, AndThenExtensions)
{
auto succeed = [](int a) {
(void)a;
return m5::stl::expected<int, int>(21 * 2);
};
auto fail = [](int a) {
(void)a;
return m5::stl::expected<int, int>(m5::stl::unexpect, 17);
};
{
m5::stl::expected<int, int> e = 21;
auto ret = e.and_then(succeed);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = e.and_then(succeed);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).and_then(succeed);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).and_then(succeed);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
m5::stl::expected<int, int> e = 21;
auto ret = e.and_then(fail);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 17);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = e.and_then(fail);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 17);
}
{
m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).and_then(fail);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 17);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).and_then(fail);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 17);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.and_then(succeed);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.and_then(succeed);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).and_then(succeed);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).and_then(succeed);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.and_then(fail);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.and_then(fail);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).and_then(fail);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).and_then(fail);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
}
TEST(Expected, or_else)
{
using eptr = std::unique_ptr<int>;
auto succeed = [](int a) {
(void)a;
return m5::stl::expected<int, int>(21 * 2);
};
auto succeedptr = [](eptr e) {
(void)e;
return m5::stl::expected<int, eptr>(21 * 2);
};
auto fail = [](int a) {
(void)a;
return m5::stl::expected<int, int>(m5::stl::unexpect, 17);
};
auto failptr = [](eptr e) {
*e = 17;
return m5::stl::expected<int, eptr>(m5::stl::unexpect, std::move(e));
};
auto failvoid = [](int) {};
auto failvoidptr = [](const eptr&) { /* don't consume */ };
auto consumeptr = [](eptr) {};
auto make_u_int = [](int n) { return std::unique_ptr<int>(new int(n)); };
{
m5::stl::expected<int, int> e = 21;
auto ret = e.or_else(succeed);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 21);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = e.or_else(succeed);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 21);
}
{
m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).or_else(succeed);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 21);
}
{
m5::stl::expected<int, eptr> e = 21;
auto ret = std::move(e).or_else(succeedptr);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 21);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).or_else(succeed);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 21);
}
{
m5::stl::expected<int, int> e = 21;
auto ret = e.or_else(fail);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 21);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = e.or_else(fail);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 21);
}
{
m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).or_else(fail);
EXPECT_TRUE(ret);
EXPECT_TRUE(ret == 21);
}
{
m5::stl::expected<int, eptr> e = 21;
auto ret = std::move(e).or_else(failptr);
EXPECT_TRUE(ret);
EXPECT_TRUE(ret == 21);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).or_else(fail);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 21);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.or_else(succeed);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.or_else(succeed);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).or_else(succeed);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
m5::stl::expected<int, eptr> e(m5::stl::unexpect, make_u_int(21));
auto ret = std::move(e).or_else(succeedptr);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).or_else(succeed);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.or_else(fail);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 17);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.or_else(failvoid);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.or_else(fail);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 17);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.or_else(failvoid);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).or_else(fail);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 17);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).or_else(failvoid);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
m5::stl::expected<int, eptr> e(m5::stl::unexpect, make_u_int(21));
auto ret = std::move(e).or_else(failvoidptr);
EXPECT_TRUE(!ret);
EXPECT_TRUE(*ret.error() == 21);
}
{
m5::stl::expected<int, eptr> e(m5::stl::unexpect, make_u_int(21));
auto ret = std::move(e).or_else(consumeptr);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == nullptr);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).or_else(fail);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 17);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).or_else(failvoid);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
}
TEST(Expected, TransformExtensions)
{
auto mul2 = [](int a) { return a * 2; };
auto ret_void = [](int a) { (void)a; };
{
m5::stl::expected<int, int> e = 21;
auto ret = e.transform(mul2);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = e.transform(mul2);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).transform(mul2);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).transform(mul2);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 42);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.transform(mul2);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.transform(mul2);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).transform(mul2);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).transform(mul2);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 21);
}
{
m5::stl::expected<int, int> e = 21;
auto ret = e.transform(ret_void);
EXPECT_TRUE(ret);
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = e.transform(ret_void);
EXPECT_TRUE(ret);
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
}
{
m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).transform(ret_void);
EXPECT_TRUE(ret);
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).transform(ret_void);
EXPECT_TRUE(ret);
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.transform(ret_void);
EXPECT_TRUE(!ret);
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.transform(ret_void);
EXPECT_TRUE(!ret);
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).transform(ret_void);
EXPECT_TRUE(!ret);
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).transform(ret_void);
EXPECT_TRUE(!ret);
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
}
// mapping functions which return references
{
m5::stl::expected<int, int> e(42);
auto ret = e.transform([](int& i) -> int& { return i; });
EXPECT_TRUE(ret);
EXPECT_TRUE(ret == 42);
}
}
TEST(Expected, TransformErrorExtensions)
{
auto mul2 = [](int a) { return a * 2; };
auto ret_void = [](int a) { (void)a; };
{
m5::stl::expected<int, int> e = 21;
auto ret = e.transform_error(mul2);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 21);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = e.transform_error(mul2);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 21);
}
{
m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).transform_error(mul2);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 21);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).transform_error(mul2);
EXPECT_TRUE(ret);
EXPECT_TRUE(*ret == 21);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.transform_error(mul2);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 42);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.transform_error(mul2);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 42);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).transform_error(mul2);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 42);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).transform_error(mul2);
EXPECT_TRUE(!ret);
EXPECT_TRUE(ret.error() == 42);
}
{
m5::stl::expected<int, int> e = 21;
auto ret = e.transform_error(ret_void);
EXPECT_TRUE(ret);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = e.transform_error(ret_void);
EXPECT_TRUE(ret);
}
{
m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).transform_error(ret_void);
EXPECT_TRUE(ret);
}
{
const m5::stl::expected<int, int> e = 21;
auto ret = std::move(e).transform_error(ret_void);
EXPECT_TRUE(ret);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.transform_error(ret_void);
EXPECT_TRUE(!ret);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = e.transform_error(ret_void);
EXPECT_TRUE(!ret);
}
{
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).transform_error(ret_void);
EXPECT_TRUE(!ret);
}
{
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
auto ret = std::move(e).transform_error(ret_void);
EXPECT_TRUE(!ret);
}
}
struct S {
int x;
};
struct F {
int x;
};
TEST(Expected, issue14)
{
auto res = m5::stl::expected<S, F>{m5::stl::unexpect, F{}};
res.map_error([](F f) { (void)f; });
}
TEST(Expected, issue32)
{
int i = 0;
m5::stl::expected<void, int> a;
a.map([&i] { i = 42; });
EXPECT_TRUE(i == 42);
auto x = a.map([] { return 42; });
EXPECT_TRUE(*x == 42);
}

View file

@ -0,0 +1,256 @@
#include <gtest/gtest.h>
#include <m5_utility/stl/expected.hpp>
#include <string>
#include <memory>
using std::string;
m5::stl::expected<int, string> getInt3(int val)
{
return val;
}
m5::stl::expected<int, string> getInt2(int val)
{
return val;
}
m5::stl::expected<int, string> getInt1()
{
return getInt2(5).and_then(getInt3);
}
TEST(Expected, Issue1)
{
getInt1();
}
m5::stl::expected<int, int> operation1()
{
return 42;
}
m5::stl::expected<std::string, int> operation2(int const val)
{
(void)val;
return "Bananas";
}
TEST(Expected, Issue17)
{
auto const intermediate_result = operation1();
intermediate_result.and_then(operation2);
}
struct a { /* empty */
};
struct b : a { /* empty */
};
auto doit() -> m5::stl::expected<std::unique_ptr<b>, int>
{
return m5::stl::make_unexpected(0);
}
TEST(Expected, Issue23)
{
m5::stl::expected<std::unique_ptr<a>, int> msg = doit();
EXPECT_TRUE(!msg.has_value());
}
TEST(Expected, Issue26)
{
m5::stl::expected<a, int> exp = m5::stl::expected<b, int>(m5::stl::unexpect, 0);
EXPECT_TRUE(!exp.has_value());
}
struct foo {
foo() = default;
foo(const foo &) = delete;
foo(foo &&) noexcept {};
};
TEST(Expected, Issue29)
{
std::vector<foo> v;
v.emplace_back();
m5::stl::expected<std::vector<foo>, int> ov = std::move(v);
EXPECT_TRUE(ov->size() == 1);
}
m5::stl::expected<int, std::string> error()
{
return m5::stl::make_unexpected(std::string("error1 "));
}
std::string maperror(std::string s)
{
return s + "maperror ";
}
TEST(Expected, Issue30)
{
error().map_error(maperror);
}
struct i31 {
int i;
};
TEST(Expected, Issue31)
{
const m5::stl::expected<i31, int> a = i31{42};
(void)a->i;
m5::stl::expected<void, std::string> result;
m5::stl::expected<void, std::string> result2 = result;
result2 = result;
}
TEST(Expected, Issue33)
{
m5::stl::expected<void, int> res{m5::stl::unexpect, 0};
EXPECT_TRUE(!res);
res = res.map_error([](int i) {
(void)i;
return 42;
});
EXPECT_TRUE(res.error() == 42);
}
m5::stl::expected<void, std::string> voidWork()
{
return {};
}
m5::stl::expected<int, std::string> work2()
{
return 42;
}
void errorhandling(std::string)
{
}
TEST(Expected, Issue34)
{
m5::stl::expected<int, std::string> result = voidWork().and_then(work2);
result.map_error([&](std::string result) { errorhandling(result); });
}
struct non_copyable {
non_copyable(non_copyable &&) = default;
non_copyable(non_copyable const &) = delete;
non_copyable() = default;
};
TEST(Expected, Issue42)
{
m5::stl::expected<non_copyable, int>{}.map([](non_copyable) {});
}
TEST(Expected, Issue43)
{
auto result = m5::stl::expected<void, std::string>{};
result = m5::stl::make_unexpected(std::string{"foo"});
}
#if !(__GNUC__ <= 5)
#include <memory>
using MaybeDataPtr = m5::stl::expected<int, std::unique_ptr<int>>;
MaybeDataPtr test(int i) noexcept
{
return std::move(i);
}
MaybeDataPtr test2(int i) noexcept
{
return std::move(i);
}
TEST(Expected, Issue49)
{
auto m = test(10).and_then(test2);
}
#endif
m5::stl::expected<int, std::unique_ptr<std::string>> func()
{
return 1;
}
TEST(Expected, Issue61)
{
EXPECT_TRUE(func().value() == 1);
}
struct move_tracker {
int moved = 0;
move_tracker() = default;
move_tracker(move_tracker const &other) noexcept {};
move_tracker(move_tracker &&orig) noexcept : moved(orig.moved + 1)
{
}
move_tracker &operator=(move_tracker const &other) noexcept
{
return *this;
}
move_tracker &operator=(move_tracker &&orig) noexcept
{
moved = orig.moved + 1;
return *this;
}
};
TEST(Expected, Issue122)
{
m5::stl::expected<move_tracker, int> res;
res.emplace();
EXPECT_TRUE(res.value().moved == 0);
}
#ifdef __cpp_deduction_guides
TEST(Expected, Issue89)
{
auto s = m5::stl::unexpected("Some string");
EXPECT_TRUE(s.value() == std::string("Some string"));
}
#endif
namespace {
struct SS {
int i = 0;
int j = 0;
SS(int i) : i(i)
{
}
SS(int i, int j) : i(i), j(j)
{
}
};
} // namespace
TEST(Expected, Issue107)
{
m5::stl::expected<int, SS> ex1(m5::stl::unexpect, 2);
m5::stl::expected<int, SS> ex2(m5::stl::unexpect, 2, 2);
EXPECT_TRUE(ex1.error().i == 2);
EXPECT_TRUE(ex1.error().j == 0);
EXPECT_TRUE(ex2.error().i == 2);
EXPECT_TRUE(ex2.error().j == 2);
}
TEST(Expected, Issue129)
{
m5::stl::expected<std::unique_ptr<int>, int> x1{std::unique_ptr<int>(new int(4))};
m5::stl::expected<std::unique_ptr<int>, int> y1{std::unique_ptr<int>(new int(2))};
x1 = std::move(y1);
EXPECT_TRUE(**x1 == 2);
}

View file

@ -0,0 +1,7 @@
#include <gtest/gtest.h>
#include <m5_utility/stl/expected.hpp>
TEST(Expected, Noexcept)
{
// TODO
}

View file

@ -0,0 +1,44 @@
#include <gtest/gtest.h>
#include <m5_utility/stl/expected.hpp>
struct move_detector {
move_detector() = default;
move_detector(move_detector &&rhs)
{
rhs.been_moved = true;
}
bool been_moved = false;
};
TEST(Expected, Observers)
{
m5::stl::expected<int, int> o1 = 42;
m5::stl::expected<int, int> o2{m5::stl::unexpect, 0};
const m5::stl::expected<int, int> o3 = 42;
EXPECT_TRUE(*o1 == 42);
EXPECT_TRUE(*o1 == o1.value());
EXPECT_TRUE(o2.value_or(42) == 42);
EXPECT_TRUE(o2.error() == 0);
EXPECT_TRUE(o3.value() == 42);
auto success = std::is_same<decltype(o1.value()), int &>::value;
EXPECT_TRUE(success);
success = std::is_same<decltype(o3.value()), const int &>::value;
EXPECT_TRUE(success);
success = std::is_same<decltype(std::move(o1).value()), int &&>::value;
EXPECT_TRUE(success);
#ifndef TL_EXPECTED_NO_CONSTRR
success = std::is_same<decltype(std::move(o3).value()), const int &&>::value;
EXPECT_TRUE(success);
#endif
m5::stl::expected<move_detector, int> o4{m5::stl::in_place};
move_detector o5 = std::move(o4).value();
EXPECT_TRUE(o4->been_moved);
EXPECT_TRUE(!o5.been_moved);
// Add by GOB
EXPECT_TRUE(o1.error_or(52) == 52);
EXPECT_TRUE(o2.error_or(52) == 0);
}

View file

@ -0,0 +1,18 @@
#include <gtest/gtest.h>
#include <m5_utility/stl/expected.hpp>
TEST(Expected, RelationalOperators)
{
m5::stl::expected<int, int> o1 = 42;
m5::stl::expected<int, int> o2{m5::stl::unexpect, 0};
const m5::stl::expected<int, int> o3 = 42;
EXPECT_TRUE(o1 == o1);
EXPECT_TRUE(o1 != o2);
EXPECT_TRUE(o1 == o3);
EXPECT_TRUE(o3 == o3);
m5::stl::expected<void, int> o6;
EXPECT_TRUE(o6 == o6);
}

View file

@ -0,0 +1,126 @@
#include <gtest/gtest.h>
#include <m5_utility/stl/expected.hpp>
struct no_throw {
no_throw(std::string i) : i(i)
{
}
std::string i;
};
struct canthrow_move {
canthrow_move(std::string i) : i(i)
{
}
canthrow_move(canthrow_move const &) = default;
canthrow_move(canthrow_move &&other) noexcept(false) : i(other.i)
{
}
canthrow_move &operator=(canthrow_move &&) = default;
std::string i;
};
bool should_throw = false;
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
struct willthrow_move {
willthrow_move(std::string i) : i(i)
{
}
willthrow_move(willthrow_move const &) = default;
willthrow_move(willthrow_move &&other) : i(other.i)
{
if (should_throw) throw 0;
}
willthrow_move &operator=(willthrow_move &&) = default;
std::string i;
};
#endif // TL_EXPECTED_EXCEPTIONS_ENABLED
static_assert(m5::stl::detail::is_swappable<no_throw>::value, "");
template <class T1, class T2>
void swap_test()
{
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
std::string s2 = "zyxwvutsrqponmlkjihgfedcba";
m5::stl::expected<T1, T2> a{s1};
m5::stl::expected<T1, T2> b{s2};
swap(a, b);
EXPECT_TRUE(a->i == s2);
EXPECT_TRUE(b->i == s1);
a = s1;
b = m5::stl::unexpected<T2>(s2);
swap(a, b);
EXPECT_TRUE(a.error().i == s2);
EXPECT_TRUE(b->i == s1);
a = m5::stl::unexpected<T2>(s1);
b = s2;
swap(a, b);
EXPECT_TRUE(a->i == s2);
EXPECT_TRUE(b.error().i == s1);
a = m5::stl::unexpected<T2>(s1);
b = m5::stl::unexpected<T2>(s2);
swap(a, b);
EXPECT_TRUE(a.error().i == s2);
EXPECT_TRUE(b.error().i == s1);
a = s1;
b = s2;
a.swap(b);
EXPECT_TRUE(a->i == s2);
EXPECT_TRUE(b->i == s1);
a = s1;
b = m5::stl::unexpected<T2>(s2);
a.swap(b);
EXPECT_TRUE(a.error().i == s2);
EXPECT_TRUE(b->i == s1);
a = m5::stl::unexpected<T2>(s1);
b = s2;
a.swap(b);
EXPECT_TRUE(a->i == s2);
EXPECT_TRUE(b.error().i == s1);
a = m5::stl::unexpected<T2>(s1);
b = m5::stl::unexpected<T2>(s2);
a.swap(b);
EXPECT_TRUE(a.error().i == s2);
EXPECT_TRUE(b.error().i == s1);
}
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
TEST(Expected, swap)
{
{
SCOPED_TRACE("no_throw no-throw");
swap_test<no_throw, no_throw>();
}
{
SCOPED_TRACE("no_throw canthrow");
swap_test<no_throw, canthrow_move>();
}
{
SCOPED_TRACE("canthrow no_throw");
swap_test<canthrow_move, no_throw>();
}
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
std::string s2 = "zyxwvutsrqponmlkjihgfedcbaxxx";
m5::stl::expected<no_throw, willthrow_move> a{s1};
m5::stl::expected<no_throw, willthrow_move> b{m5::stl::unexpect, s2};
should_throw = 1;
#ifdef _MSC_VER
// this seems to break catch on GCC and Clang
EXPECT_TRUE_THROWS(swap(a, b));
#endif
EXPECT_TRUE(a->i == s1);
EXPECT_TRUE(b.error().i == s2);
}
#endif // TL_EXPECTED_EXCEPTIONS_ENABLED