#include "catch.hpp" #include "optional.hpp" #define TOKENPASTE(x, y) x##y #define TOKENPASTE2(x, y) TOKENPASTE(x, y) #define STATIC_REQUIRE(e) \ constexpr bool TOKENPASTE2(rqure, __LINE__) = e; \ REQUIRE(e); constexpr int get_int(int) { return 42; } constexpr tl::optional get_opt_int(int) { return 42; } // What is Clang Format up to?! TEST_CASE("Monadic operations", "[monadic]"){SECTION("map"){// lhs is empty tl::optional o1; auto o1r = o1.map([](int i) { return i + 2; }); STATIC_REQUIRE((std::is_same>::value)); REQUIRE(!o1r); // lhs has value tl::optional o2 = 40; auto o2r = o2.map([](int i) { return i + 2; }); STATIC_REQUIRE((std::is_same>::value)); REQUIRE(o2r.value() == 42); struct rval_call_map { double operator()(int) && { return 42.0; }; }; // ensure that function object is forwarded tl::optional o3 = 42; auto o3r = o3.map(rval_call_map{}); STATIC_REQUIRE((std::is_same>::value)); REQUIRE(o3r.value() == 42); // ensure that lhs is forwarded tl::optional o4 = 40; auto o4r = std::move(o4).map([](int &&i) { return i + 2; }); STATIC_REQUIRE((std::is_same>::value)); REQUIRE(o4r.value() == 42); // ensure that lhs is const-propagated const tl::optional o5 = 40; auto o5r = o5.map([](const int &i) { return i + 2; }); STATIC_REQUIRE((std::is_same>::value)); REQUIRE(o5r.value() == 42); // test applicative functor tl::optional o6 = 40; auto f6 = tl::make_optional([](const int &i) { return i + 2; }); auto o6r = o6.map(f6); STATIC_REQUIRE((std::is_same>::value)); REQUIRE(o6r.value() == 42); // test void return tl::optional o7 = 40; auto f7 = tl::make_optional([](const int &i) { return; }); auto o7r = o7.map(f7); STATIC_REQUIRE((std::is_same>::value)); REQUIRE(o6r.has_value()); // test each overload in turn tl::optional o8 = 42; auto o8r = o8.map([](int){return 42;}); REQUIRE(*o8r == 42); tl::optional o9 = 42; auto o9r = o9.map([](int){return;}); REQUIRE(o9r); tl::optional o10 = 42; auto o10r = o10.map(tl::make_optional([](int){return 42;})); REQUIRE(*o10r == 42); tl::optional o11 = 42; auto o11r = o11.map(tl::make_optional([](int){return;})); REQUIRE(o11r); tl::optional o12 = 42; auto o12r = std::move(o12).map([](int){return 42;}); REQUIRE(*o12r == 42); tl::optional o13 = 42; auto o13r = std::move(o13).map([](int){return;}); REQUIRE(o13r); tl::optional o14 = 42; auto o14r = std::move(o14).map(tl::make_optional([](int){return 42;})); REQUIRE(*o14r == 42); tl::optional o15 = 42; auto o15r = std::move(o15).map(tl::make_optional([](int){return;})); REQUIRE(o15r); const tl::optional o16 = 42; auto o16r = o16.map([](int){return 42;}); REQUIRE(*o16r == 42); const tl::optional o17 = 42; auto o17r = o17.map([](int){return;}); REQUIRE(o17r); const tl::optional o18 = 42; auto o18r = o18.map(tl::make_optional([](int){return 42;})); REQUIRE(*o18r == 42); const tl::optional o19 = 42; auto o19r = o19.map(tl::make_optional([](int){return;})); REQUIRE(o19r); const tl::optional o20 = 42; auto o20r = std::move(o20).map([](int){return 42;}); REQUIRE(*o20r == 42); const tl::optional o21 = 42; auto o21r = std::move(o21).map([](int){return;}); REQUIRE(o21r); const tl::optional o22 = 42; auto o22r = std::move(o22).map(tl::make_optional([](int){return 42;})); REQUIRE(*o22r == 42); const tl::optional o23 = 42; auto o23r = std::move(o23).map(tl::make_optional([](int){return;})); REQUIRE(o23r); tl::optional o24 = tl::nullopt; auto o24r = o24.map([](int){return 42;}); REQUIRE(!o24r); tl::optional o25 = tl::nullopt; auto o25r = o25.map([](int){return;}); REQUIRE(!o25r); tl::optional o26 = tl::nullopt; auto o26r = o26.map(tl::make_optional([](int){return 42;})); REQUIRE(!o26r); tl::optional o27 = tl::nullopt; auto o27r = o27.map(tl::make_optional([](int){return;})); REQUIRE(!o27r); tl::optional o28 = tl::nullopt; auto o28r = std::move(o28).map([](int){return 42;}); REQUIRE(!o28r); tl::optional o29 = tl::nullopt; auto o29r = std::move(o29).map([](int){return;}); REQUIRE(!o29r); tl::optional o30 = tl::nullopt; auto o30r = std::move(o30).map(tl::make_optional([](int){return 42;})); REQUIRE(!o30r); tl::optional o31 = tl::nullopt; auto o31r = std::move(o31).map(tl::make_optional([](int){return;})); REQUIRE(!o31r); const tl::optional o32 = tl::nullopt; auto o32r = o32.map([](int){return 42;}); REQUIRE(!o32r); const tl::optional o33 = tl::nullopt; auto o33r = o33.map([](int){return;}); REQUIRE(!o33r); const tl::optional o34 = tl::nullopt; auto o34r = o34.map(tl::make_optional([](int){return 42;})); REQUIRE(!o34r); const tl::optional o35 = tl::nullopt; auto o35r = o35.map(tl::make_optional([](int){return;})); REQUIRE(!o35r); const tl::optional o36 = tl::nullopt; auto o36r = std::move(o36).map([](int){return 42;}); REQUIRE(!o36r); const tl::optional o37 = tl::nullopt; auto o37r = std::move(o37).map([](int){return;}); REQUIRE(!o37r); const tl::optional o38 = tl::nullopt; auto o38r = std::move(o38).map(tl::make_optional([](int){return 42;})); REQUIRE(!o38r); const tl::optional o39 = tl::nullopt; auto o39r = std::move(o39).map(tl::make_optional([](int){return;})); REQUIRE(!o39r); } SECTION("map constexpr") { // test each overload in turn constexpr tl::optional o16 = 42; constexpr auto o16r = o16.map(get_int); STATIC_REQUIRE(*o16r == 42); constexpr tl::optional o18 = 42; constexpr auto opt_int = tl::make_optional(get_int); constexpr auto o18r = o18.map(opt_int); STATIC_REQUIRE(*o18r == 42); constexpr tl::optional o20 = 42; constexpr auto o20r = std::move(o20).map(get_int); STATIC_REQUIRE(*o20r == 42); constexpr tl::optional o22 = 42; constexpr auto o22r = std::move(o22).map(opt_int); STATIC_REQUIRE(*o22r == 42); constexpr tl::optional o32 = tl::nullopt; constexpr auto o32r = o32.map(get_int); STATIC_REQUIRE(!o32r); constexpr tl::optional o34 = tl::nullopt; constexpr auto o34r = o34.map(opt_int); STATIC_REQUIRE(!o34r); constexpr tl::optional o36 = tl::nullopt; constexpr auto o36r = std::move(o36).map(get_int); STATIC_REQUIRE(!o36r); constexpr tl::optional o38 = tl::nullopt; constexpr auto o38r = std::move(o38).map(opt_int); STATIC_REQUIRE(!o38r); } SECTION("bind") { // lhs is empty tl::optional o1; auto o1r = o1.bind([](int i) { return tl::optional{42}; }); STATIC_REQUIRE((std::is_same>::value)); REQUIRE(!o1r); // lhs has value tl::optional o2 = 12; auto o2r = o2.bind([](int i) { return tl::optional{42}; }); STATIC_REQUIRE((std::is_same>::value)); REQUIRE(o2r.value() == 42.f); // lhs is empty, rhs returns empty tl::optional o3; auto o3r = o3.bind([](int i) { return tl::optional{}; }); STATIC_REQUIRE((std::is_same>::value)); REQUIRE(!o3r); // rhs returns empty tl::optional o4 = 12; auto o4r = o4.bind([](int i) { return tl::optional{}; }); STATIC_REQUIRE((std::is_same>::value)); REQUIRE(!o4r); struct rval_call_bind { tl::optional operator()(int) && { return tl::optional(42.0); }; }; // ensure that function object is forwarded tl::optional o5 = 42; auto o5r = o5.bind(rval_call_bind{}); STATIC_REQUIRE((std::is_same>::value)); REQUIRE(o5r.value() == 42); // ensure that lhs is forwarded tl::optional o6 = 42; auto o6r = std::move(o6).bind([](int &&i) { return tl::optional(i); }); STATIC_REQUIRE((std::is_same>::value)); REQUIRE(o6r.value() == 42); // ensure that function object is const-propagated const tl::optional o7 = 42; auto o7r = o7.bind([](const int &i) { return tl::optional(i); }); STATIC_REQUIRE((std::is_same>::value)); REQUIRE(o7r.value() == 42); // test each overload in turn tl::optional o8 = 42; auto o8r = o8.bind([](int i) { return tl::make_optional(42); }); REQUIRE(*o8r == 42); tl::optional o9 = 42; auto o9r = std::move(o9).bind([](int i) { return tl::make_optional(42); }); REQUIRE(*o9r == 42); const tl::optional o10 = 42; auto o10r = o10.bind([](int i) { return tl::make_optional(42); }); REQUIRE(*o10r == 42); const tl::optional o11 = 42; auto o11r = std::move(o11).bind([](int i) { return tl::make_optional(42); }); REQUIRE(*o11r == 42); tl::optional o12 = 42; auto o12r = o12.bind([](int i) { return tl::make_optional(42); }, []{return;}); REQUIRE(*o12r == 42); tl::optional o13 = 42; auto o13r = std::move(o13).bind([](int i) { return tl::make_optional(42); }, []{return;}); REQUIRE(*o13r == 42); const tl::optional o14 = 42; auto o14r = o14.bind([](int i) { return tl::make_optional(42); }, []{return;}); REQUIRE(*o14r == 42); const tl::optional o15 = 42; auto o15r = std::move(o15).bind([](int i) { return tl::make_optional(42); }, []{return;}); REQUIRE(*o15r == 42); tl::optional o16 = tl::nullopt; auto o16r = o16.bind([](int i) { return tl::make_optional(42); }); REQUIRE(!o16r); tl::optional o17 = tl::nullopt; auto o17r = std::move(o17).bind([](int i) { return tl::make_optional(42); }); REQUIRE(!o17r); const tl::optional o18 = tl::nullopt; auto o18r = o18.bind([](int i) { return tl::make_optional(42); }); REQUIRE(!o18r); const tl::optional o19 = tl::nullopt; auto o19r = std::move(o19).bind([](int i) { return tl::make_optional(42); }); REQUIRE(!o19r); tl::optional o20 = tl::nullopt; bool c20 = false; auto o20r = o20.bind([](int i) { return tl::make_optional(42); }, [&]{c20 = true;}); REQUIRE(!o20r); REQUIRE(!c20); tl::optional o21 = tl::nullopt; bool c21 = false; auto o21r = std::move(o21).bind([](int i) { return tl::make_optional(42); }, [&]{c21 = true;}); REQUIRE(!o21r); REQUIRE(!c21); const tl::optional o22 = tl::nullopt; bool c22 = false; auto o22r = o22.bind([](int i) { return tl::make_optional(42); }, [&]{c22 = true;}); REQUIRE(!o22r); REQUIRE(!c22); const tl::optional o23 = tl::nullopt; bool c23 = false; auto o23r = std::move(o23).bind([](int i) { return tl::make_optional(42); }, [&]{c23 = true;}); REQUIRE(!o23r); REQUIRE(!c23); tl::optional o24 = 42; bool c24 = false; auto o24r = o24.bind([](int i) { return tl::optional{tl::nullopt}; }, [&]{c24 = true;}); REQUIRE(!o24r); REQUIRE(c24); tl::optional o25 = 42; bool c25 = false; auto o25r = std::move(o25).bind([](int i) { return tl::optional{tl::nullopt}; }, [&]{c25 = true;}); REQUIRE(!o25r); REQUIRE(c25); const tl::optional o26 = 42; bool c26 = false; auto o26r = o26.bind([](int i) { return tl::optional{tl::nullopt};}, [&]{c26 = true;}); REQUIRE(!o26r); REQUIRE(c26); const tl::optional o27 = 42; bool c27 = false; auto o27r = std::move(o27).bind([](int i) { return tl::optional{tl::nullopt};}, [&]{c27 = true;}); REQUIRE(!o27r); REQUIRE(c27); } SECTION("constexpr bind") { constexpr tl::optional o10 = 42; constexpr auto o10r = o10.bind(get_opt_int); REQUIRE(*o10r == 42); constexpr tl::optional o11 = 42; constexpr auto o11r = std::move(o11).bind(get_opt_int); REQUIRE(*o11r == 42); constexpr tl::optional o18 = tl::nullopt; constexpr auto o18r = o18.bind(get_opt_int); REQUIRE(!o18r); constexpr tl::optional o19 = tl::nullopt; constexpr auto o19r = std::move(o19).bind(get_opt_int); REQUIRE(!o19r); } } ;