// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc. // Distributed under 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) #ifdef BOOST_LEAF_TEST_SINGLE_HEADER # include "leaf.hpp" #else # include # include #endif #include "lightweight_test.hpp" namespace leaf = boost::leaf; static_assert(std::is_same::value_type>::value, "Bad value_type"); static_assert(std::is_same::value_type>::value, "Bad value_type"); static_assert(std::is_same::value_type>::value, "Bad value_type"); static_assert(std::is_same::value_type>::value, "Bad value_type"); static_assert(std::is_same::value_type>::value, "Bad value_type"); struct val { static int id_count; static int count; int id; float a = 0; int b = 0; val( float a, int b ) noexcept: id(++id_count), a(a), b(b) { ++count; } val() noexcept: id(++id_count) { ++count; } val( val const & x ) noexcept: id(x.id) { ++count; } val( val && x ) noexcept: id(x.id) { ++count; } ~val() noexcept { --count; } friend bool operator==( val const & a, val const & b ) noexcept { return a.id == b.id; } friend std::ostream & operator<<( std::ostream & os, val const & v ) noexcept { return os << v.id; } }; int val::count = 0; int val::id_count = 0; struct err { static int count; err() { ++count; } err( err const & ) { ++count; } err( err && ) { ++count; } ~err() { --count; } }; int err::count = 0; struct e_err { err value; }; bool eq_value( leaf::result & r, val v ) { leaf::result const & cr = r; val const & cv = v; return r.value() == v && cr.value() == cv && *r.operator->() == v && *cr.operator->() == cv && *r == v && *cr == cv; } int main() { { // value default -> move leaf::result r1; BOOST_TEST(r1); BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 1); leaf::result r2 = std::move(r1); BOOST_TEST(r2); BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 2); } BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 0); { // value move -> move leaf::result r1 = val(); BOOST_TEST(r1); BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 1); leaf::result r2 = std::move(r1); BOOST_TEST(r2); BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 2); } BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 0); { // value copy -> move val v; leaf::result r1 = v; BOOST_TEST(r1); BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 2); BOOST_TEST(eq_value(r1, v)); leaf::result r2 = std::move(r1); BOOST_TEST(r2); BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 3); BOOST_TEST(eq_value(r2, v)); } BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 0); { // value emplace -> move leaf::result r1 = { 42.0f, 42 }; BOOST_TEST(r1); BOOST_TEST_EQ(r1.value().a, 42.0f); BOOST_TEST_EQ(r1.value().b, 42); BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 1); leaf::result r2 = std::move(r1); BOOST_TEST(r2); BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 2); } BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 0); { // value default -> assign-move leaf::result r1; BOOST_TEST(r1); BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 1); leaf::result r2; r2=std::move(r1); BOOST_TEST(r2); BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 2); } BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 0); { // value move -> assign-move leaf::result r1 = val(); BOOST_TEST(r1); BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 1); leaf::result r2; r2=std::move(r1); BOOST_TEST(r2); BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 2); } BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 0); { // value copy -> assign-move val v; leaf::result r1 = v; BOOST_TEST(r1); BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 2); BOOST_TEST(eq_value(r1, v)); leaf::result r2; r2=std::move(r1); BOOST_TEST(r2); BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 3); BOOST_TEST(eq_value(r2, v)); } BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 0); { // value emplace -> assign-move leaf::result r1 = { 42.0f, 42 }; BOOST_TEST(r1); BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 1); leaf::result r2; r2=std::move(r1); BOOST_TEST(r2); BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 2); } BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 0); // ^^ value ^^ // vv error vv { // error move -> move leaf::context ctx; auto active_context = activate_context(ctx); leaf::result r1 = leaf::new_error( e_err { } ); BOOST_TEST(!r1); BOOST_TEST_EQ(err::count, 1); BOOST_TEST_EQ(val::count, 0); leaf::error_id r1e = r1.error(); leaf::result r2 = std::move(r1); leaf::error_id r2e = r2.error(); BOOST_TEST_EQ(r1e, r2e); BOOST_TEST(!r2); } BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 0); { // error copy -> move leaf::context ctx; auto active_context = activate_context(ctx); leaf::error_id err = leaf::new_error( e_err{ } ); leaf::result r1 = err; BOOST_TEST(!r1); BOOST_TEST_EQ(err::count, 1); BOOST_TEST_EQ(val::count, 0); leaf::error_id r1e = r1.error(); leaf::result r2 = std::move(r1); leaf::error_id r2e = r2.error(); BOOST_TEST_EQ(r1e, r2e); BOOST_TEST(!r2); } BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 0); { // error move -> assign move leaf::context ctx; ctx.activate(); leaf::result r1 = leaf::new_error( e_err { } ); ctx.deactivate(); BOOST_TEST(!r1); BOOST_TEST_EQ(err::count, 1); BOOST_TEST_EQ(val::count, 0); leaf::error_id r1e = r1.error(); leaf::result r2; r2=std::move(r1); leaf::error_id r2e = r2.error(); BOOST_TEST_EQ(r1e, r2e); BOOST_TEST(!r2); { val x; BOOST_TEST_EQ(ctx.handle_error(r2.error(), [&]{ return x; }), x); } BOOST_TEST_EQ(err::count, 1); BOOST_TEST_EQ(val::count, 0); } BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 0); { // error copy -> assign move leaf::context ctx; auto active_context = activate_context(ctx); leaf::error_id err = leaf::new_error( e_err{ } ); leaf::result r1 = err; BOOST_TEST(!r1); BOOST_TEST_EQ(err::count, 1); BOOST_TEST_EQ(val::count, 0); leaf::error_id r1e = r1.error(); leaf::result r2; r2=std::move(r1); leaf::error_id r2e = r2.error(); BOOST_TEST_EQ(r1e, r2e); BOOST_TEST(!r2); } BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 0); #if BOOST_LEAF_CFG_CAPTURE { // error move -> capture -> move leaf::result r1 = leaf::try_capture_all( []()->leaf::result { return leaf::new_error(e_err{ }); }); BOOST_TEST(!r1); BOOST_TEST_EQ(err::count, 1); BOOST_TEST_EQ(val::count, 0); leaf::error_id r1e = r1.error(); leaf::result r2 = std::move(r1); leaf::error_id r2e = r2.error(); BOOST_TEST_EQ(r1e, r2e); BOOST_TEST(!r2); BOOST_TEST(!r1); } BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 0); { // error copy -> capture -> move leaf::result r1 = leaf::try_capture_all( []()->leaf::result { leaf::error_id err = leaf::new_error( e_err{ } ); return leaf::result(err); }); BOOST_TEST(!r1); BOOST_TEST_EQ(err::count, 1); BOOST_TEST_EQ(val::count, 0); leaf::error_id r1e = r1.error(); leaf::result r2 = std::move(r1); leaf::error_id r2e = r2.error(); BOOST_TEST_EQ(r1e, r2e); BOOST_TEST(!r2); BOOST_TEST(!r1); } BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 0); { // error move -> capture -> assign-move leaf::result r1 = leaf::try_capture_all( []()->leaf::result { return leaf::new_error(e_err{ }); }); BOOST_TEST(!r1); BOOST_TEST_EQ(err::count, 1); BOOST_TEST_EQ(val::count, 0); leaf::error_id r1e = r1.error(); leaf::result r2; r2=std::move(r1); leaf::error_id r2e = r2.error(); BOOST_TEST_EQ(r1e, r2e); BOOST_TEST(!r2); BOOST_TEST(!r1); } BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 0); { // error copy -> capture -> assign-move leaf::result r1 = leaf::try_capture_all( []()->leaf::result { leaf::error_id err = leaf::new_error( e_err{ } ); return leaf::result(err); }); BOOST_TEST(!r1); BOOST_TEST_EQ(err::count, 1); BOOST_TEST_EQ(val::count, 0); leaf::error_id r1e = r1.error(); leaf::result r2; r2=std::move(r1); leaf::error_id r2e = r2.error(); BOOST_TEST_EQ(r1e, r2e); BOOST_TEST(!r2); BOOST_TEST(!r1); } BOOST_TEST_EQ(err::count, 0); BOOST_TEST_EQ(val::count, 0); #endif // #if BOOST_LEAF_CFG_CAPTURE // ^^ result ^^ //////////////////////////////////////// // vv result vv { // void default -> move leaf::result r1; BOOST_TEST(r1); r1.value(); BOOST_TEST(r1.operator->()); *r1; leaf::result r2 = std::move(r1); BOOST_TEST(r2); r2.value(); BOOST_TEST(r2.operator->()); *r2; } { // void default -> assign-move leaf::result r1; BOOST_TEST(r1); r1.value(); BOOST_TEST(r1.operator->()); *r1; leaf::result r2; r2=std::move(r1); BOOST_TEST(r2); r2.value(); BOOST_TEST(r2.operator->()); *r2; } // ^^ void default ^^ // vv void error vv { // void error move -> move leaf::context ctx; auto active_context = activate_context(ctx); leaf::result r1 = leaf::new_error( e_err { } ); BOOST_TEST(!r1); BOOST_TEST(!r1.operator->()); BOOST_TEST_EQ(err::count, 1); leaf::error_id r1e = r1.error(); leaf::result r2 = std::move(r1); leaf::error_id r2e = r2.error(); BOOST_TEST_EQ(r1e, r2e); BOOST_TEST(!r2); BOOST_TEST_EQ(r2.operator->(), nullptr); } BOOST_TEST_EQ(err::count, 0); { // void error copy -> move leaf::context ctx; auto active_context = activate_context(ctx); leaf::error_id err = leaf::new_error( e_err{ } ); leaf::result r1 = err; BOOST_TEST(!r1); BOOST_TEST(!r1.operator->()); BOOST_TEST_EQ(err::count, 1); leaf::error_id r1e = r1.error(); leaf::result r2 = std::move(r1); leaf::error_id r2e = r2.error(); BOOST_TEST_EQ(r1e, r2e); BOOST_TEST(!r2); BOOST_TEST_EQ(r2.operator->(), nullptr); } BOOST_TEST_EQ(err::count, 0); { // void error move -> assign move leaf::context ctx; ctx.activate(); leaf::result r1 = leaf::new_error( e_err { } ); ctx.deactivate(); BOOST_TEST(!r1); BOOST_TEST(!r1.operator->()); BOOST_TEST_EQ(err::count, 1); leaf::error_id r1e = r1.error(); leaf::result r2; r2=std::move(r1); leaf::error_id r2e = r2.error(); BOOST_TEST_EQ(r1e, r2e); BOOST_TEST(!r2); BOOST_TEST_EQ(r2.operator->(), nullptr); ctx.handle_error(r2.error(), []{ }); BOOST_TEST_EQ(err::count, 1); } BOOST_TEST_EQ(err::count, 0); { // void error copy -> assign move leaf::context ctx; auto active_context = activate_context(ctx); leaf::error_id err = leaf::new_error( e_err{ } ); leaf::result r1 = err; BOOST_TEST(!r1); BOOST_TEST(!r1.operator->()); BOOST_TEST_EQ(err::count, 1); leaf::error_id r1e = r1.error(); leaf::result r2; r2=std::move(r1); leaf::error_id r2e = r2.error(); BOOST_TEST_EQ(r1e, r2e); BOOST_TEST(!r2); BOOST_TEST_EQ(r2.operator->(), nullptr); } BOOST_TEST_EQ(err::count, 0); #if BOOST_LEAF_CFG_CAPTURE { // void error move -> capture -> move leaf::result r1 = leaf::try_capture_all( []()->leaf::result { return leaf::new_error(e_err{ }); }); BOOST_TEST(!r1); BOOST_TEST(!r1.operator->()); BOOST_TEST_EQ(err::count, 1); leaf::error_id r1e = r1.error(); leaf::result r2 = std::move(r1); leaf::error_id r2e = r2.error(); BOOST_TEST_EQ(r1e, r2e); BOOST_TEST(!r2); BOOST_TEST_EQ(r2.operator->(), nullptr); } BOOST_TEST_EQ(err::count, 0); { // void error copy -> capture -> move leaf::result r1 = leaf::try_capture_all( []()->leaf::result { leaf::error_id err = leaf::new_error( e_err{ } ); return leaf::result(err); }); BOOST_TEST(!r1); BOOST_TEST(!r1.operator->()); BOOST_TEST_EQ(err::count, 1); leaf::error_id r1e = r1.error(); leaf::result r2 = std::move(r1); leaf::error_id r2e = r2.error(); BOOST_TEST_EQ(r1e, r2e); BOOST_TEST(!r2); BOOST_TEST_EQ(r2.operator->(), nullptr); } BOOST_TEST_EQ(err::count, 0); { // void error move -> capture -> assign-move leaf::result r1 = leaf::try_capture_all( []()->leaf::result { return leaf::new_error(e_err{ }); }); BOOST_TEST(!r1); BOOST_TEST(!r1.operator->()); BOOST_TEST_EQ(err::count, 1); leaf::error_id r1e = r1.error(); leaf::result r2; r2=std::move(r1); leaf::error_id r2e = r2.error(); BOOST_TEST_EQ(r1e, r2e); BOOST_TEST(!r2); BOOST_TEST_EQ(r2.operator->(), nullptr); } BOOST_TEST_EQ(err::count, 0); { // void error copy -> capture -> assign-move leaf::result r1 = leaf::try_capture_all( []()->leaf::result { leaf::error_id err = leaf::new_error( e_err{ } ); return leaf::result(err); }); BOOST_TEST(!r1); BOOST_TEST(!r1.operator->()); BOOST_TEST_EQ(err::count, 1); leaf::error_id r1e = r1.error(); leaf::result r2; r2=std::move(r1); leaf::error_id r2e = r2.error(); BOOST_TEST_EQ(r1e, r2e); BOOST_TEST(!r2); BOOST_TEST_EQ(r2.operator->(), nullptr); } BOOST_TEST_EQ(err::count, 0); #endif // #if BOOST_LEAF_CFG_CAPTURE { leaf::result r = leaf::error_id(); BOOST_TEST(!r); BOOST_TEST_EQ(val::count, 0); BOOST_TEST_EQ(err::count, 0); } BOOST_TEST_EQ(val::count, 0); BOOST_TEST_EQ(err::count, 0); { leaf::result r = leaf::error_id(); BOOST_TEST(!r); BOOST_TEST_EQ(val::count, 0); BOOST_TEST_EQ(err::count, 0); } BOOST_TEST_EQ(val::count, 0); BOOST_TEST_EQ(err::count, 0); { leaf::result r; BOOST_TEST(r); leaf::result r1 = r.error(); BOOST_TEST_EQ(val::count, 0); BOOST_TEST(!r1); leaf::error_id id = r.error(); BOOST_TEST(!id); } BOOST_TEST_EQ(val::count, 0); { leaf::result r; BOOST_TEST(r); leaf::result r1 = r.error(); BOOST_TEST(!r1); leaf::error_id id = r.error(); BOOST_TEST(!id); BOOST_TEST_EQ(val::count, 1); } BOOST_TEST_EQ(val::count, 0); { leaf::result r; BOOST_TEST(r); leaf::result r1 = r.error(); BOOST_TEST(!r1); leaf::error_id id = r.error(); BOOST_TEST(!id); BOOST_TEST_EQ(val::count, 1); } BOOST_TEST_EQ(val::count, 0); #if BOOST_LEAF_CFG_STD_STRING { // Initialization forwarding constructor leaf::result r = "hello"; BOOST_TEST(r); BOOST_TEST_EQ(r.value(), "hello"); } #endif #if BOOST_LEAF_CFG_STD_STRING { // Initialization forwarding constructor leaf::result r; r = "hello"; BOOST_TEST(r); BOOST_TEST_EQ(r.value(), "hello"); } #endif return boost::report_errors(); }