// Copyright 2018-2022 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 # include #endif #include "lightweight_test.hpp" namespace leaf = boost::leaf; struct val { static int id_count; static int count; int id; val(): id(++id_count) { ++count; } val( val const & x ): id(x.id) { ++count; } val( val && x ): id(x.id) { ++count; } ~val() { --count; } friend bool operator==( val const & a, val const & b ) { return a.id==b.id; } friend std::ostream & operator<<( std::ostream & os, val const & v ) { 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 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); using context_type = leaf::leaf_detail::polymorphic_context_impl>; #if BOOST_LEAF_CFG_CAPTURE { // value default -> capture -> move leaf::result r1 = leaf::capture( std::make_shared(), []{ return leaf::result(); } ); 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 -> capture -> move leaf::result r1 = leaf::capture( std::make_shared(), []{ return leaf::result(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 -> capture -> move leaf::result r1 = leaf::capture( std::make_shared(), []{ val v; return leaf::result(v); } ); 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 default -> capture -> assign-move leaf::result r1 = leaf::capture( std::make_shared(), []{ return leaf::result(); } ); 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 -> capture -> assign-move leaf::result r1 = leaf::capture( std::make_shared(), []{ return leaf::result(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 -> capture -> assign-move leaf::result r1 = leaf::capture( std::make_shared(), []{ val v; return leaf::result(v); } ); 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); #endif // ^^ value ^^ // vv error vv { // error move -> move context_type 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 context_type 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 context_type 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(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 context_type 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::capture( std::make_shared(), []{ return leaf::result( 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::capture( std::make_shared(), []{ 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::capture( std::make_shared(), []{ return leaf::result( 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::capture( std::make_shared(), []{ 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 // ^^ result ^^ ///////////////////////////////////////////////////////////// // vv result vv { // void default -> move leaf::result r1; BOOST_TEST(r1); r1.value(); BOOST_TEST(r1.operator->() != 0); *r1; leaf::result r2 = std::move(r1); BOOST_TEST(r2); r2.value(); BOOST_TEST(r2.operator->() != 0); *r2; } { // void default -> assign-move leaf::result r1; BOOST_TEST(r1); r1.value(); BOOST_TEST(r1.operator->() != 0); *r1; leaf::result r2; r2=std::move(r1); BOOST_TEST(r2); r2.value(); BOOST_TEST(r2.operator->() != 0); *r2; } #if BOOST_LEAF_CFG_CAPTURE { // void default -> capture -> move leaf::result r1 = leaf::capture( std::make_shared(), []{ return leaf::result(); } ); BOOST_TEST(r1); r1.value(); BOOST_TEST(r1.operator->() != 0); *r1; leaf::result r2 = std::move(r1); BOOST_TEST(r2); r2.value(); BOOST_TEST(r2.operator->() != 0); *r2; } { // void default -> capture -> assign-move leaf::result r1 = leaf::capture( std::make_shared(), []{ return leaf::result(); } ); BOOST_TEST(r1); r1.value(); BOOST_TEST(r1.operator->() != 0); *r1; leaf::result r2; r2=std::move(r1); BOOST_TEST(r2); r2.value(); BOOST_TEST(r2.operator->() != 0); *r2; } #endif // ^^ void default ^^ // vv void error vv { // void error move -> move context_type ctx; auto active_context = activate_context(ctx); leaf::result r1 = leaf::new_error( e_err { } ); BOOST_TEST(!r1); BOOST_TEST(r1.operator->() == 0); 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(r2.operator->() == 0); } BOOST_TEST_EQ(err::count, 0); { // void error copy -> move context_type 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->() == 0); 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(r2.operator->() == 0); } BOOST_TEST_EQ(err::count, 0); { // void error move -> assign move context_type ctx; ctx.activate(); leaf::result r1 = leaf::new_error( e_err { } ); ctx.deactivate(); BOOST_TEST(!r1); BOOST_TEST(r1.operator->() == 0); 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(r2.operator->() == 0); ctx.handle_error(r2.error(), []{ }); BOOST_TEST_EQ(err::count, 1); } BOOST_TEST_EQ(err::count, 0); { // void error copy -> assign move context_type 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->() == 0); 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(r2.operator->() == 0); } BOOST_TEST_EQ(err::count, 0); #if BOOST_LEAF_CFG_CAPTURE { // void error move -> capture -> move leaf::result r1 = leaf::capture( std::make_shared(), []{ return leaf::result( leaf::new_error( e_err { } ) ); } ); BOOST_TEST(!r1); BOOST_TEST(r1.operator->() == 0); 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(r2.operator->() == 0); } BOOST_TEST_EQ(err::count, 0); { // void error copy -> capture -> move leaf::result r1 = leaf::capture( std::make_shared(), []{ leaf::error_id err = leaf::new_error( e_err{ } ); return leaf::result(err); } ); BOOST_TEST(!r1); BOOST_TEST(r1.operator->() == 0); 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(r2.operator->() == 0); } BOOST_TEST_EQ(err::count, 0); { // void error move -> capture -> assign-move leaf::result r1 = leaf::capture( std::make_shared(), []{ return leaf::result( leaf::new_error( e_err { } ) ); } ); BOOST_TEST(!r1); BOOST_TEST(r1.operator->() == 0); 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(r2.operator->() == 0); } BOOST_TEST_EQ(err::count, 0); { // void error copy -> capture -> assign-move leaf::result r1 = leaf::capture( std::make_shared(), []{ leaf::error_id err = leaf::new_error( e_err{ } ); return leaf::result(err); } ); BOOST_TEST(!r1); BOOST_TEST(r1.operator->() == 0); 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(r2.operator->() == 0); } BOOST_TEST_EQ(err::count, 0); #endif { 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(); }