// 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 #include #include #include #include #include "test_util.hpp" #define BOOST_TEST_MODULE openmethod #include using namespace boost::openmethod; namespace animals { struct Animal { explicit Animal(std::string str) { name = std::move(str); } Animal(const Animal&) = delete; Animal(Animal&&) = default; virtual ~Animal() { } std::string name; }; struct Property { std::string owner = "Bill"; }; struct Dog : Property, Animal { using Animal::Animal; }; struct Cat : Property, virtual Animal { using Animal::Animal; }; } // namespace animals // ----------------------------------------------------------------------------- // pass virtual args by lvalue references namespace TEST_NS { using test_registry = test_registry_<__COUNTER__>; using namespace animals; BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat, test_registry); BOOST_OPENMETHOD(name, (virtual_), std::string, test_registry); BOOST_OPENMETHOD_OVERRIDE(name, (const Cat& cat), std::string) { return cat.owner + "'s cat " + cat.name; } BOOST_OPENMETHOD_OVERRIDE(name, (const Dog& dog), std::string) { return dog.owner + "'s dog " + dog.name; } BOOST_AUTO_TEST_CASE(cast_args_lvalue_refs) { initialize(); Dog spot("Spot"); BOOST_TEST(name(spot) == "Bill's dog Spot"); Cat felix("Felix"); BOOST_TEST(name(felix) == "Bill's cat Felix"); } } // namespace TEST_NS namespace TEST_NS { using test_registry = test_registry_<__COUNTER__>; using namespace animals; } // namespace TEST_NS // ----------------------------------------------------------------------------- // pass virtual args by rvalue references namespace TEST_NS { using test_registry = test_registry_<__COUNTER__>; using namespace animals; BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat, test_registry); BOOST_OPENMETHOD( teleport, (virtual_), std::unique_ptr, test_registry); BOOST_OPENMETHOD_OVERRIDE(teleport, (Cat && cat), std::unique_ptr) { return std::make_unique(std::move(cat)); } BOOST_OPENMETHOD_OVERRIDE(teleport, (Dog && dog), std::unique_ptr) { return std::make_unique(std::move(dog)); } BOOST_AUTO_TEST_CASE(cast_args_rvalue_refs) { initialize(); { Dog spot("Spot"); auto animal = teleport(std::move(spot)); BOOST_TEST(animal->name == "Spot"); BOOST_TEST(spot.name == ""); } { Cat felix("Felix"); auto animal = teleport(std::move(felix)); BOOST_TEST(animal->name == "Felix"); BOOST_TEST(felix.name == ""); } } } // namespace TEST_NS // ----------------------------------------------------------------------------- // pass virtual args by pointer namespace TEST_NS { using test_registry = test_registry_<__COUNTER__>; using namespace animals; BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat, test_registry); BOOST_OPENMETHOD(name, (virtual_), std::string, test_registry); BOOST_OPENMETHOD_OVERRIDE(name, (const Cat* cat), std::string) { return cat->owner + "'s cat " + cat->name; } BOOST_OPENMETHOD_OVERRIDE(name, (const Dog* dog), std::string) { return dog->owner + "'s dog " + dog->name; } BOOST_AUTO_TEST_CASE(cast_args_pointer) { initialize(); Dog spot("Spot"); BOOST_TEST(name(&spot) == "Bill's dog Spot"); Cat felix("Felix"); BOOST_TEST(name(&felix) == "Bill's cat Felix"); } } // namespace TEST_NS namespace TEST_NS { // ----------------------------------------------------------------------------- // pass virtual args by shared_ptr by value using test_registry = test_registry_<__COUNTER__>; using namespace animals; BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat, test_registry); BOOST_OPENMETHOD( name, (virtual_>), std::string, test_registry); BOOST_OPENMETHOD_OVERRIDE(name, (std::shared_ptr cat), std::string) { return cat->owner + "'s cat " + cat->name; } BOOST_OPENMETHOD_OVERRIDE(name, (std::shared_ptr dog), std::string) { return dog->owner + "'s dog " + dog->name; } BOOST_AUTO_TEST_CASE(cast_args_shared_ptr_by_value) { initialize(); auto spot = std::make_shared("Spot"); BOOST_TEST(name(spot) == "Bill's dog Spot"); auto felix = std::make_shared("Felix"); BOOST_TEST(name(felix) == "Bill's cat Felix"); } } // namespace TEST_NS namespace TEST_NS { using test_registry = test_registry_<__COUNTER__>; using namespace animals; } // namespace TEST_NS namespace TEST_NS { // ----------------------------------------------------------------------------- // pass virtual args by shared_ptr by ref using test_registry = test_registry_<__COUNTER__>; using namespace animals; BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat, test_registry); BOOST_OPENMETHOD( name, (virtual_&>), std::string, test_registry); BOOST_OPENMETHOD_OVERRIDE( name, (const std::shared_ptr& cat), std::string) { return cat->owner + "'s cat " + cat->name; } BOOST_OPENMETHOD_OVERRIDE( name, (const std::shared_ptr& dog), std::string) { return dog->owner + "'s dog " + dog->name; } BOOST_AUTO_TEST_CASE(cast_args_shared_ptr_by_ref) { initialize(); auto spot = std::make_shared("Spot"); BOOST_TEST(name(spot) == "Bill's dog Spot"); auto felix = std::make_shared("Felix"); BOOST_TEST(name(felix) == "Bill's cat Felix"); } } // namespace TEST_NS namespace TEST_NS { // ----------------------------------------------------------------------------- // pass virtual args by unique_ptr using test_registry = test_registry_<__COUNTER__>; using namespace animals; BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat, test_registry); BOOST_OPENMETHOD( name, (virtual_>), std::string, test_registry); BOOST_OPENMETHOD_OVERRIDE(name, (std::unique_ptr cat), std::string) { return cat->owner + "'s cat " + cat->name; } BOOST_OPENMETHOD_OVERRIDE(name, (std::unique_ptr dog), std::string) { return dog->owner + "'s dog " + dog->name; } BOOST_AUTO_TEST_CASE(cast_args_unique_ptr) { initialize(); auto spot = std::make_unique("Spot"); BOOST_TEST(name(std::move(spot)) == "Bill's dog Spot"); BOOST_TEST(spot.get() == nullptr); auto felix = std::make_unique("Felix"); BOOST_TEST(name(std::move(felix)) == "Bill's cat Felix"); BOOST_TEST(felix.get() == nullptr); } } // namespace TEST_NS namespace TEST_NS { using namespace test_matrices; using test_registry = test_registry_<__COUNTER__>; BOOST_OPENMETHOD_CLASSES(matrix, dense_matrix, diagonal_matrix, test_registry); BOOST_OPENMETHOD( times, (virtual_, virtual_), string_pair, test_registry); BOOST_OPENMETHOD( times, (double, virtual_), string_pair, test_registry); BOOST_OPENMETHOD( times, (virtual_, double), string_pair, test_registry); BOOST_OPENMETHOD_OVERRIDE(times, (const matrix&, const matrix&), string_pair) { return string_pair(MATRIX_MATRIX, NONE); } BOOST_OPENMETHOD_OVERRIDE( times, (const diagonal_matrix&, const diagonal_matrix&), string_pair) { return string_pair(DIAGONAL_DIAGONAL, MATRIX_MATRIX); } BOOST_OPENMETHOD_OVERRIDE(times, (double, const matrix&), string_pair) { return string_pair(SCALAR_MATRIX, NONE); } BOOST_OPENMETHOD_OVERRIDE( times, (double, const diagonal_matrix&), string_pair) { return string_pair(SCALAR_DIAGONAL, SCALAR_MATRIX); } BOOST_OPENMETHOD_OVERRIDE( times, (const diagonal_matrix&, double), string_pair) { return string_pair(DIAGONAL_SCALAR, MATRIX_SCALAR); } BOOST_OPENMETHOD_OVERRIDE(times, (const matrix&, double), string_pair) { return string_pair(MATRIX_SCALAR, NONE); } BOOST_AUTO_TEST_CASE(simple) { auto report = initialize().report; BOOST_TEST(report.not_implemented == 0u); BOOST_TEST(report.ambiguous == 0u); { // pass by const ref const matrix& dense = dense_matrix(); const matrix& diag = diagonal_matrix(); BOOST_TEST(times(dense, dense) == string_pair(MATRIX_MATRIX, NONE)); BOOST_TEST( times(diag, diag) == string_pair(DIAGONAL_DIAGONAL, MATRIX_MATRIX)); BOOST_TEST(times(diag, dense) == string_pair(MATRIX_MATRIX, NONE)); BOOST_TEST(times(2, dense) == string_pair(SCALAR_MATRIX, NONE)); BOOST_TEST(times(dense, 2) == string_pair(MATRIX_SCALAR, NONE)); BOOST_TEST( times(diag, 2) == string_pair(DIAGONAL_SCALAR, MATRIX_SCALAR)); } if constexpr (std::is_same_v) { BOOST_TEST( !detail::vptr_vector_vptrs.empty()); test_registry::finalize(); static_assert(detail::has_finalize_aux< void, test_registry::policy, std::tuple<>>::value); BOOST_TEST( detail::vptr_vector_vptrs.empty()); } } } // namespace TEST_NS namespace test_next_fn { struct Animal { virtual ~Animal() { } }; struct Dog : Animal {}; struct Bulldog : Dog {}; BOOST_OPENMETHOD_CLASSES(Animal, Dog, Bulldog); struct BOOST_OPENMETHOD_ID(poke); using poke = method)->std::string>; auto poke_dog(Dog&) -> std::string { return "bark"; } BOOST_OPENMETHOD_REGISTER(poke::override); auto poke_bulldog(Bulldog& dog) -> std::string { return poke::next(dog) + " and bite back"; } BOOST_OPENMETHOD_REGISTER(poke::override); BOOST_AUTO_TEST_CASE(test_next_fn) { initialize(); std::unique_ptr snoopy = std::make_unique(); BOOST_TEST(poke::fn(*snoopy) == "bark"); std::unique_ptr hector = std::make_unique(); BOOST_TEST(poke::fn(*hector) == "bark and bite back"); } } // namespace test_next_fn namespace across_namespaces { namespace animals { class Animal { public: virtual ~Animal() { } }; BOOST_OPENMETHOD(poke, (virtual_), std::string); } // namespace animals namespace more_animals { class Dog : public animals::Animal {}; BOOST_OPENMETHOD_CLASSES(Dog, animals::Animal); BOOST_OPENMETHOD_OVERRIDE(poke, (const Dog&), std::string) { return "bark"; } } // namespace more_animals BOOST_AUTO_TEST_CASE(across_namespaces) { const animals::Animal& animal = more_animals::Dog(); BOOST_TEST("bark" == poke(animal)); } } // namespace across_namespaces namespace test_comma_in_return_type { using test_registry = test_registry_<__COUNTER__>; struct Test { virtual ~Test(){}; }; BOOST_OPENMETHOD_CLASSES(Test, test_registry); BOOST_OPENMETHOD(foo, (virtual_), std::pair, test_registry); BOOST_OPENMETHOD_OVERRIDE(foo, (Test&), std::pair) { return {1, 2}; } BOOST_AUTO_TEST_CASE(comma_in_return_type) { initialize(); Test test; BOOST_CHECK(foo(test) == std::pair(1, 2)); } } // namespace test_comma_in_return_type