| // |
| // Test boost::polymorphic_cast, boost::polymorphic_downcast and |
| // boost::polymorphic_pointer_cast, boost::polymorphic_pointer_downcast |
| // |
| // Copyright 1999 Beman Dawes |
| // Copyright 1999 Dave Abrahams |
| // Copyright 2014 Peter Dimov |
| // Copyright 2014 Boris Rasin, Antony Polukhin |
| // |
| // 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 |
| // |
| |
| #define BOOST_ENABLE_ASSERT_HANDLER |
| #include <boost/polymorphic_cast.hpp> |
| #include <boost/polymorphic_pointer_cast.hpp> |
| #include <boost/smart_ptr/shared_ptr.hpp> |
| #include <boost/smart_ptr/intrusive_ptr.hpp> |
| #include <boost/smart_ptr/intrusive_ref_counter.hpp> |
| #include <boost/core/lightweight_test.hpp> |
| #include <string> |
| #include <memory> |
| |
| static bool expect_assertion = false; |
| static int assertion_failed_count = 0; |
| |
| //assertion handler throws it to exit like assert, but to be able to catch it and stop |
| //usage: BOOST_TEST_THROWS( function_with_assert(), expected_assertion ); |
| struct expected_assertion {}; |
| |
| // BOOST_ASSERT custom handler |
| void boost::assertion_failed( char const * expr, char const * function, char const * file, long line ) |
| { |
| if( expect_assertion ) |
| { |
| ++assertion_failed_count; |
| throw expected_assertion(); |
| } |
| else |
| { |
| BOOST_ERROR( "unexpected assertion" ); |
| |
| BOOST_LIGHTWEIGHT_TEST_OSTREAM |
| << file << "(" << line << "): assertion '" << expr << "' failed in function '" |
| << function << "'" << std::endl; |
| } |
| } |
| |
| // |
| |
| struct Base : boost::intrusive_ref_counter<Base> |
| { |
| virtual ~Base() {} |
| virtual std::string kind() { return "Base"; } |
| }; |
| |
| struct Base2 |
| { |
| virtual ~Base2() {} |
| virtual std::string kind2() { return "Base2"; } |
| }; |
| |
| struct Derived : public Base, Base2 |
| { |
| virtual std::string kind() { return "Derived"; } |
| }; |
| |
| static void test_polymorphic_cast() |
| { |
| Base * base = new Derived; |
| |
| Derived * derived; |
| |
| try |
| { |
| derived = boost::polymorphic_cast<Derived*>( base ); |
| |
| BOOST_TEST( derived != 0 ); |
| |
| if( derived != 0 ) |
| { |
| BOOST_TEST_EQ( derived->kind(), "Derived" ); |
| } |
| } |
| catch( std::bad_cast const& ) |
| { |
| BOOST_ERROR( "boost::polymorphic_cast<Derived*>( base ) threw std::bad_cast" ); |
| } |
| |
| Base2 * base2; |
| |
| try |
| { |
| base2 = boost::polymorphic_cast<Base2*>( base ); // crosscast |
| |
| BOOST_TEST( base2 != 0 ); |
| |
| if( base2 != 0 ) |
| { |
| BOOST_TEST_EQ( base2->kind2(), "Base2" ); |
| } |
| } |
| catch( std::bad_cast const& ) |
| { |
| BOOST_ERROR( "boost::polymorphic_cast<Base2*>( base ) threw std::bad_cast" ); |
| } |
| |
| delete base; |
| } |
| |
| static void test_polymorphic_pointer_cast() |
| { |
| Base * base = new Derived; |
| |
| Derived * derived; |
| |
| try |
| { |
| derived = boost::polymorphic_pointer_cast<Derived>( base ); |
| |
| BOOST_TEST( derived != 0 ); |
| |
| if( derived != 0 ) |
| { |
| BOOST_TEST_EQ( derived->kind(), "Derived" ); |
| } |
| } |
| catch( std::bad_cast const& ) |
| { |
| BOOST_ERROR( "boost::polymorphic_pointer_cast<Derived>( base ) threw std::bad_cast" ); |
| } |
| |
| Base2 * base2; |
| |
| try |
| { |
| base2 = boost::polymorphic_pointer_cast<Base2>( base ); // crosscast |
| |
| BOOST_TEST( base2 != 0 ); |
| |
| if( base2 != 0 ) |
| { |
| BOOST_TEST_EQ( base2->kind2(), "Base2" ); |
| } |
| } |
| catch( std::bad_cast const& ) |
| { |
| BOOST_ERROR( "boost::polymorphic_pointer_cast<Base2>( base ) threw std::bad_cast" ); |
| } |
| |
| boost::shared_ptr<Base> sp_base( base ); |
| boost::shared_ptr<Base2> sp_base2; |
| try |
| { |
| sp_base2 = boost::polymorphic_pointer_cast<Base2>( sp_base ); // crosscast |
| |
| BOOST_TEST( sp_base2 != 0 ); |
| |
| if( sp_base2 != 0 ) |
| { |
| BOOST_TEST_EQ( sp_base2->kind2(), "Base2" ); |
| } |
| } |
| catch( std::bad_cast const& ) |
| { |
| BOOST_ERROR( "boost::polymorphic_pointer_cast<Base2>( sp_base ) threw std::bad_cast" ); |
| } |
| |
| // we do not `delete base;` because sahred_ptr is holding base |
| } |
| |
| static void test_polymorphic_downcast() |
| { |
| Base *base_pointer = new Derived; |
| |
| // test raw pointer cast |
| Derived *derived_pointer = boost::polymorphic_downcast<Derived *>(base_pointer); |
| |
| BOOST_TEST(derived_pointer != 0); |
| |
| if (derived_pointer != 0) |
| { |
| BOOST_TEST_EQ(derived_pointer->kind(), "Derived"); |
| } |
| |
| // test reference cast |
| Derived& derived_ref = boost::polymorphic_downcast<Derived&>(*base_pointer); |
| BOOST_TEST_EQ(derived_ref.kind(), "Derived"); |
| |
| delete base_pointer; |
| } |
| |
| static void test_polymorphic_pointer_downcast_builtin() |
| { |
| Base * base = new Derived; |
| |
| Derived * derived = boost::polymorphic_pointer_downcast<Derived>( base ); |
| |
| BOOST_TEST( derived != 0 ); |
| |
| if( derived != 0 ) |
| { |
| BOOST_TEST_EQ( derived->kind(), "Derived" ); |
| } |
| |
| // polymorphic_pointer_downcast can't do crosscasts |
| |
| delete base; |
| } |
| |
| static void test_polymorphic_pointer_downcast_boost_shared() |
| { |
| boost::shared_ptr<Base> base (new Derived); |
| |
| boost::shared_ptr<Derived> derived = boost::polymorphic_pointer_downcast<Derived>( base ); |
| |
| BOOST_TEST( derived != 0 ); |
| |
| if( derived != 0 ) |
| { |
| BOOST_TEST_EQ( derived->kind(), "Derived" ); |
| } |
| } |
| |
| static void test_polymorphic_pointer_downcast_intrusive() |
| { |
| boost::intrusive_ptr<Base> base (new Derived); |
| |
| boost::intrusive_ptr<Derived> derived = boost::polymorphic_pointer_downcast<Derived>( base ); |
| |
| BOOST_TEST( derived != 0 ); |
| |
| if( derived != 0 ) |
| { |
| BOOST_TEST_EQ( derived->kind(), "Derived" ); |
| } |
| } |
| |
| #ifndef BOOST_NO_CXX11_SMART_PTR |
| |
| static void test_polymorphic_pointer_downcast_std_shared() |
| { |
| std::shared_ptr<Base> base (new Derived); |
| |
| std::shared_ptr<Derived> derived = boost::polymorphic_pointer_downcast<Derived>( base ); |
| |
| BOOST_TEST( derived != 0 ); |
| |
| if( derived != 0 ) |
| { |
| BOOST_TEST_EQ( derived->kind(), "Derived" ); |
| } |
| } |
| |
| #endif |
| |
| static void test_polymorphic_cast_fail() |
| { |
| Base * base = new Base; |
| |
| BOOST_TEST_THROWS( boost::polymorphic_cast<Derived*>( base ), std::bad_cast ); |
| |
| delete base; |
| } |
| |
| static void test_polymorphic_pointer_cast_fail() |
| { |
| Base * base = new Base; |
| BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( base ), std::bad_cast ); |
| delete base; |
| |
| BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( boost::shared_ptr<Base>(new Base) ), std::bad_cast ); |
| |
| #ifndef BOOST_NO_CXX11_SMART_PTR |
| BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( std::shared_ptr<Base>(new Base) ), std::bad_cast ); |
| #endif |
| |
| BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( boost::intrusive_ptr<Base>(new Base) ), std::bad_cast ); |
| } |
| |
| static void test_polymorphic_downcast_fail() |
| { |
| Base * base_pointer = new Base; |
| |
| { |
| // test raw pointer cast |
| |
| int old_count = assertion_failed_count; |
| expect_assertion = true; |
| |
| BOOST_TEST_THROWS(boost::polymorphic_downcast<Derived *>(base_pointer), expected_assertion); // should assert |
| |
| BOOST_TEST_EQ(assertion_failed_count, old_count + 1); |
| expect_assertion = false; |
| } |
| { |
| // test reference cast |
| |
| int old_count = assertion_failed_count; |
| expect_assertion = true; |
| |
| BOOST_TEST_THROWS(boost::polymorphic_downcast<Derived &>(*base_pointer), expected_assertion); // should assert |
| |
| BOOST_TEST_EQ(assertion_failed_count, old_count + 1); |
| expect_assertion = false; |
| } |
| |
| delete base_pointer; |
| } |
| |
| static void test_polymorphic_pointer_downcast_builtin_fail() |
| { |
| Base * base = new Base; |
| |
| int old_count = assertion_failed_count; |
| expect_assertion = true; |
| |
| BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast<Derived>( base ), expected_assertion ); // should assert |
| |
| BOOST_TEST_EQ( assertion_failed_count, old_count + 1 ); |
| expect_assertion = false; |
| |
| delete base; |
| } |
| |
| static void test_polymorphic_pointer_downcast_boost_shared_fail() |
| { |
| boost::shared_ptr<Base> base (new Base); |
| |
| int old_count = assertion_failed_count; |
| expect_assertion = true; |
| |
| BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast<Derived>( base ), expected_assertion ); // should assert |
| |
| BOOST_TEST_EQ( assertion_failed_count, old_count + 1 ); |
| expect_assertion = false; |
| } |
| |
| #ifndef BOOST_NO_CXX11_SMART_PTR |
| |
| static void test_polymorphic_pointer_downcast_std_shared_fail() |
| { |
| std::shared_ptr<Base> base (new Base); |
| |
| int old_count = assertion_failed_count; |
| expect_assertion = true; |
| |
| BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast<Derived>( base ), expected_assertion ); // should assert |
| |
| BOOST_TEST_EQ( assertion_failed_count, old_count + 1 ); |
| expect_assertion = false; |
| } |
| |
| #endif |
| |
| static void test_polymorphic_pointer_downcast_intrusive_fail() |
| { |
| boost::intrusive_ptr<Base> base (new Base); |
| |
| int old_count = assertion_failed_count; |
| expect_assertion = true; |
| |
| BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast<Derived>( base ), expected_assertion); // should assert |
| |
| BOOST_TEST_EQ( assertion_failed_count, old_count + 1 ); |
| expect_assertion = false; |
| } |
| |
| int main() |
| { |
| test_polymorphic_cast(); |
| test_polymorphic_pointer_cast(); |
| test_polymorphic_downcast(); |
| test_polymorphic_pointer_downcast_builtin(); |
| test_polymorphic_pointer_downcast_boost_shared(); |
| test_polymorphic_pointer_downcast_intrusive(); |
| test_polymorphic_cast_fail(); |
| test_polymorphic_pointer_cast_fail(); |
| test_polymorphic_downcast_fail(); |
| test_polymorphic_pointer_downcast_builtin_fail(); |
| test_polymorphic_pointer_downcast_boost_shared_fail(); |
| test_polymorphic_pointer_downcast_intrusive_fail(); |
| |
| #ifndef BOOST_NO_CXX11_SMART_PTR |
| test_polymorphic_pointer_downcast_std_shared(); |
| test_polymorphic_pointer_downcast_std_shared_fail(); |
| #endif |
| |
| return boost::report_errors(); |
| } |