// Copyright (c) 2018-2025 Jean-Louis Leroy // 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) #include #include #include #include #include #include #include #define BOOST_TEST_MODULE openmethod #include #include #include "test_util.hpp" using boost::mp11::mp_list; using std::cout; using namespace boost::openmethod; using namespace boost::openmethod::detail; namespace using_polymorphic_classes { struct Animal { virtual ~Animal() { } }; struct Dog : Animal {}; BOOST_OPENMETHOD_CLASSES(Animal, Dog); namespace BOOST_OPENMETHOD_GENSYM { BOOST_OPENMETHOD(poke, (const virtual_ptr&, std::ostream&), void); BOOST_OPENMETHOD_OVERRIDE( poke, (const virtual_ptr&, std::ostream& os), void) { os << "bark"; } static_assert(sizeof(virtual_ptr) == 2 * sizeof(void*)); BOOST_AUTO_TEST_CASE(test_virtual_ptr_by_ref) { boost::openmethod::initialize(); { boost::test_tools::output_test_stream os; Dog dog; virtual_ptr vptr(dog); poke(vptr, os); } { // Using deduction guide. boost::test_tools::output_test_stream os; Animal&& animal = Dog(); auto vptr = virtual_ptr(animal); poke(vptr, os); BOOST_CHECK(os.is_equal("bark")); } { // Using conversion ctor. boost::test_tools::output_test_stream os; Animal&& animal = Dog(); poke(animal, os); BOOST_CHECK(os.is_equal("bark")); } } } // namespace BOOST_OPENMETHOD_GENSYM namespace BOOST_OPENMETHOD_GENSYM { BOOST_OPENMETHOD(poke, (virtual_ptr, std::ostream&), void); BOOST_OPENMETHOD_OVERRIDE(poke, (virtual_ptr, std::ostream& os), void) { os << "bark"; } BOOST_AUTO_TEST_CASE(test_virtual_shared_by_value) { boost::openmethod::initialize(); { boost::test_tools::output_test_stream os; shared_virtual_ptr animal = make_shared_virtual(); poke(animal, os); BOOST_CHECK(os.is_equal("bark")); } } } // namespace BOOST_OPENMETHOD_GENSYM namespace BOOST_OPENMETHOD_GENSYM { BOOST_OPENMETHOD( poke, (const shared_virtual_ptr&, std::ostream&), void); BOOST_OPENMETHOD_OVERRIDE( poke, (const shared_virtual_ptr&, std::ostream& os), void) { os << "bark"; } BOOST_AUTO_TEST_CASE(test_virtual_shared_by_const_reference) { boost::openmethod::initialize(); { boost::test_tools::output_test_stream os; shared_virtual_ptr animal = make_shared_virtual(); poke(animal, os); BOOST_CHECK(os.is_equal("bark")); } } } // namespace BOOST_OPENMETHOD_GENSYM namespace BOOST_OPENMETHOD_GENSYM { BOOST_OPENMETHOD(poke, (unique_virtual_ptr, std::ostream&), void); BOOST_OPENMETHOD_OVERRIDE( poke, (unique_virtual_ptr, std::ostream& os), void) { os << "bark"; } BOOST_AUTO_TEST_CASE(test_virtual_unique) { boost::openmethod::initialize(); { boost::test_tools::output_test_stream os; poke(make_unique_virtual(), os); BOOST_CHECK(os.is_equal("bark")); } } } // namespace BOOST_OPENMETHOD_GENSYM } // namespace using_polymorphic_classes namespace using_non_polymorphic_classes { struct Animal {}; struct Dog : Animal {}; BOOST_OPENMETHOD_CLASSES(Animal, Dog); BOOST_OPENMETHOD(poke, (virtual_ptr, std::ostream&), void); BOOST_OPENMETHOD_OVERRIDE(poke, (virtual_ptr, std::ostream& os), void) { os << "bark"; } BOOST_AUTO_TEST_CASE(test_virtual_ptr_non_polymorphic) { boost::openmethod::initialize(); { boost::test_tools::output_test_stream os; Dog dog; auto vptr = virtual_ptr::final(dog); poke(vptr, os); BOOST_CHECK(os.is_equal("bark")); } } } // namespace using_non_polymorphic_classes struct Player { virtual ~Player() { } }; struct Warrior : Player {}; struct Wizard : Player {}; struct Bear : Player {}; struct Object { virtual ~Object() { } }; struct Axe : Object {}; template auto poke_bear(VirtualBearPtr) { return std::string("growl"); } template auto fight_bear(VirtualWarriorPtr, VirtualAxePtr, VirtualBearPtr) { return "kill bear"; } template struct indirect_test_registry : test_registry_::template with {}; template using policy_types = boost::mp11::mp_list, indirect_test_registry>; struct BOOST_OPENMETHOD_ID(poke); struct BOOST_OPENMETHOD_ID(fight); namespace BOOST_OPENMETHOD_GENSYM { BOOST_AUTO_TEST_CASE_TEMPLATE( test_virtual_ptr, Registry, policy_types<__COUNTER__>) { BOOST_OPENMETHOD_REGISTER( use_classes); using poke = method< BOOST_OPENMETHOD_ID(poke), auto(virtual_ptr)->std::string, Registry>; BOOST_OPENMETHOD_REGISTER(typename poke::template override< poke_bear>>); initialize(); using vptr_player = virtual_ptr; static_assert(detail::is_virtual_ptr); using vptr_bear = virtual_ptr; Player player; auto virtual_player = vptr_player::final(player); BOOST_TEST(&*virtual_player == &player); BOOST_TEST( (virtual_player.vptr() == Registry::template static_vptr)); Bear bear; BOOST_TEST((&*vptr_bear::final(bear)) == &bear); BOOST_TEST(( vptr_bear::final(bear).vptr() == Registry::template static_vptr)); BOOST_TEST( (vptr_player(bear).vptr() == Registry::template static_vptr)); vptr_bear virtual_bear_ptr(bear); struct upcast { static void fn(vptr_player) { } }; upcast::fn(virtual_bear_ptr); } } // namespace BOOST_OPENMETHOD_GENSYM namespace test_virtual_ptr_dispatch { BOOST_AUTO_TEST_CASE_TEMPLATE( test_virtual_ptr_dispatch, Registry, policy_types<__COUNTER__>) { BOOST_OPENMETHOD_REGISTER( use_classes); using poke = method< BOOST_OPENMETHOD_ID(poke), auto(virtual_ptr)->std::string, Registry>; BOOST_OPENMETHOD_REGISTER(typename poke::template override< poke_bear>>); using fight = method< BOOST_OPENMETHOD_ID(fight), auto( virtual_ptr, virtual_ptr, virtual_ptr) ->std::string, Registry>; BOOST_OPENMETHOD_REGISTER( typename fight::template override, virtual_ptr, virtual_ptr>>); initialize(); Bear bear; BOOST_TEST(poke::fn(virtual_ptr(bear)) == "growl"); Warrior warrior; Axe axe; BOOST_TEST( fight::fn( virtual_ptr(warrior), virtual_ptr(axe), virtual_ptr(bear)) == "kill bear"); } } // namespace test_virtual_ptr_dispatch namespace test_shared_virtual_ptr_dispatch { BOOST_AUTO_TEST_CASE_TEMPLATE( test_virtual_ptr_dispatch, Registry, policy_types<__COUNTER__>) { BOOST_OPENMETHOD_REGISTER( use_classes); using poke = method< BOOST_OPENMETHOD_ID(poke), auto(shared_virtual_ptr)->std::string, Registry>; BOOST_OPENMETHOD_REGISTER(typename poke::template override< poke_bear>>); using fight = method< BOOST_OPENMETHOD_ID(fight), auto( shared_virtual_ptr, shared_virtual_ptr, shared_virtual_ptr) ->std::string, Registry>; BOOST_OPENMETHOD_REGISTER(typename fight::template override, shared_virtual_ptr, shared_virtual_ptr>>); initialize(); auto bear = make_shared_virtual(); auto warrior = make_shared_virtual(); auto axe = make_shared_virtual(); BOOST_TEST(poke::fn(bear) == "growl"); BOOST_TEST(fight::fn(warrior, axe, bear) == "kill bear"); } } // namespace test_shared_virtual_ptr_dispatch