#include "asl/option.hpp" #include "asl/tests/test_types.hpp" #include "asl/testing/testing.hpp" class Base {}; class Derived : public Base {}; struct NonZero { int value; constexpr explicit NonZero(int x) : value(x) { ASL_ASSERT(x != 0); } constexpr explicit NonZero(asl::niche) : value(0) {} constexpr bool operator==(asl::niche) const { return value == 0; } }; static_assert(asl::has_niche); static_assert(!asl::has_niche); static_assert(sizeof(asl::option) > sizeof(int)); static_assert(sizeof(asl::option) == sizeof(NonZero)); static_assert(!asl::is_option); static_assert(asl::is_option>); static_assert(asl::is_option>); static_assert(asl::trivially_destructible>); static_assert(!asl::trivially_destructible>); static_assert(asl::copy_constructible>); static_assert(asl::copy_constructible>); static_assert(!asl::copy_constructible>); static_assert(!asl::copy_constructible>); static_assert(asl::move_constructible>); static_assert(asl::move_constructible>); static_assert(asl::move_constructible>); static_assert(!asl::move_constructible>); static_assert(asl::copy_assignable>); static_assert(asl::copy_assignable>); static_assert(!asl::copy_assignable>); static_assert(!asl::copy_assignable>); static_assert(asl::move_assignable>); static_assert(asl::move_assignable>); static_assert(asl::move_assignable>); static_assert(!asl::move_assignable>); static_assert(asl::assignable_from&, asl::option>); static_assert(!asl::assignable_from&, asl::option>); static_assert(asl::convertible_from, asl::option>); static_assert(!asl::convertible_from, asl::option>); class ExplicitConversion { public: explicit ExplicitConversion(int) {} }; class ImplicitConversion { public: ImplicitConversion(int) {} }; // NOLINT static_assert(!asl::convertible_from); static_assert(asl::convertible_from); static_assert(!asl::convertible_from, int>); static_assert(asl::convertible_from, int>); static_assert(!asl::convertible_from, asl::option>); static_assert(asl::convertible_from, asl::option>); static_assert(asl::trivially_copy_constructible>); static_assert(!asl::trivially_copy_constructible>); static_assert(asl::trivially_move_constructible>); static_assert(!asl::trivially_move_constructible>); static_assert(asl::trivially_copy_assignable>); static_assert(!asl::trivially_copy_assignable>); static_assert(asl::trivially_move_assignable>); static_assert(!asl::trivially_move_assignable>); ASL_TEST(make_null) { asl::option a; asl::option b = asl::nullopt; ASL_TEST_EXPECT(!a.has_value()); ASL_TEST_EXPECT(!b.has_value()); } ASL_TEST(make_value) { asl::option a = 48; ASL_TEST_EXPECT(a.has_value()); } ASL_TEST(reset) { asl::option b = 48; ASL_TEST_EXPECT(b.has_value()); b.reset(); ASL_TEST_EXPECT(!b.has_value()); } ASL_TEST(call_destructor) { bool destroyed = false; { DestructorObserver obs(&destroyed); asl::option opt(ASL_MOVE(obs)); ASL_TEST_EXPECT(!destroyed); asl::option opt2 = ASL_MOVE(opt); ASL_TEST_EXPECT(!destroyed); } ASL_TEST_EXPECT(destroyed); } ASL_TEST(call_destructor_on_reset) { bool destroyed = false; asl::option opt(&destroyed); ASL_TEST_EXPECT(!destroyed); opt.reset(); ASL_TEST_EXPECT(destroyed); } ASL_TEST(value) { asl::option a = 1; asl::option b = 2; asl::option c = a; ASL_TEST_EXPECT(a.value() == 1); ASL_TEST_EXPECT(b.value() == 2); ASL_TEST_EXPECT(c.value() == 1); c = b; ASL_TEST_EXPECT(c.value() == 2); } ASL_TEST(value_move) { bool destroyed = false; asl::option opt(&destroyed); ASL_TEST_EXPECT(!destroyed); { auto x = ASL_MOVE(opt).value(); ASL_TEST_EXPECT(!destroyed); } ASL_TEST_EXPECT(destroyed); } ASL_TEST(deduction_guide) { asl::option opt(45); ASL_TEST_EXPECT(opt.value() == 45); } ASL_TEST(convert_copy) { asl::option opt8 = uint8_t{8}; asl::option opt16 = opt8; ASL_TEST_ASSERT(opt16.has_value()); ASL_TEST_EXPECT(opt16.value() == 8); opt8 = uint8_t{10}; ASL_TEST_ASSERT(opt8.has_value()); ASL_TEST_EXPECT(opt8.value() == 10); opt16 = asl::nullopt; ASL_TEST_EXPECT(!opt16.has_value()); opt16 = opt8; ASL_TEST_ASSERT(opt16.has_value()); ASL_TEST_EXPECT(opt16.value() == 10); } ASL_TEST(convert_move) { asl::option opt8 = uint8_t{8}; asl::option opt16 = ASL_MOVE(opt8); ASL_TEST_ASSERT(opt16.has_value()); ASL_TEST_EXPECT(opt16.value() == 8); opt8 = ASL_MOVE(uint8_t{10}); ASL_TEST_ASSERT(opt8.has_value()); ASL_TEST_EXPECT(opt8.value() == 10); opt16 = asl::nullopt; ASL_TEST_EXPECT(!opt16.has_value()); opt16 = ASL_MOVE(opt8); ASL_TEST_ASSERT(opt16.has_value()); ASL_TEST_EXPECT(opt16.value() == 10); } ASL_TEST(value_or) { asl::option a = asl::nullopt; asl::option b = 2; ASL_TEST_EXPECT(a.value_or(5) == 5); ASL_TEST_EXPECT(b.value_or(5) == 2); } ASL_TEST(emplace) { asl::option a = asl::nullopt; a.emplace(42); ASL_TEST_ASSERT(a.has_value()); ASL_TEST_EXPECT(a.value() == 42); } ASL_TEST(emplace_destroys_previous) { bool b1 = false; bool b2 = false; { asl::option a{&b1}; ASL_TEST_EXPECT(!b1); a.emplace(&b2); ASL_TEST_EXPECT(b1); ASL_TEST_EXPECT(!b2); } ASL_TEST_EXPECT(b2); } ASL_TEST(and_then) { asl::option a = 5; asl::option b; auto fn = [](int x) -> asl::option { return static_cast(x) + 0.5F; }; auto a2 = a.and_then(fn); static_assert(asl::same_as>); ASL_TEST_ASSERT(a2.has_value()); ASL_TEST_EXPECT(a2.value() == 5.5F); auto b2 = b.and_then(fn); static_assert(asl::same_as>); ASL_TEST_ASSERT(!b2.has_value()); } ASL_TEST(transform) { asl::option a = 5; asl::option b; auto fn = [](int x) -> float { return static_cast(x) + 0.5F; }; auto a2 = a.transform(fn); static_assert(asl::same_as>); ASL_TEST_ASSERT(a2.has_value()); ASL_TEST_EXPECT(a2.value() == 5.5F); auto b2 = b.transform(fn); static_assert(asl::same_as>); ASL_TEST_ASSERT(!b2.has_value()); } ASL_TEST(or_else) { asl::option a = 5; asl::option b; auto fn = []() -> asl::option { return 12; }; auto a2 = a.or_else(fn); static_assert(asl::same_as>); ASL_TEST_ASSERT(a2.has_value()); ASL_TEST_EXPECT(a2.value() == 5); auto b2 = b.or_else(fn); static_assert(asl::same_as>); ASL_TEST_ASSERT(b2.has_value()); ASL_TEST_EXPECT(b2.value() == 12); } ASL_TEST(niche) { asl::option opt; ASL_TEST_EXPECT(!opt.has_value()); asl::option opt2(2); ASL_TEST_EXPECT(opt2.has_value()); ASL_TEST_EXPECT(opt2.value().value == 2); opt = opt2; ASL_TEST_EXPECT(opt2.has_value()); ASL_TEST_EXPECT(opt2.value().value == 2); opt.reset(); ASL_TEST_EXPECT(!opt.has_value()); }