// // 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 #include #include #include #include #include #include #include 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 { 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( base ); BOOST_TEST( derived != 0 ); if( derived != 0 ) { BOOST_TEST_EQ( derived->kind(), "Derived" ); } } catch( std::bad_cast const& ) { BOOST_ERROR( "boost::polymorphic_cast( base ) threw std::bad_cast" ); } Base2 * base2; try { base2 = boost::polymorphic_cast( 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( 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( 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( base ) threw std::bad_cast" ); } Base2 * base2; try { base2 = boost::polymorphic_pointer_cast( 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( base ) threw std::bad_cast" ); } boost::shared_ptr sp_base( base ); boost::shared_ptr sp_base2; try { sp_base2 = boost::polymorphic_pointer_cast( 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( sp_base ) threw std::bad_cast" ); } // we do not `delete base;` because sahred_ptr is holding base } static void test_polymorphic_downcast() { Base * base = new Derived; Derived * derived = boost::polymorphic_downcast( base ); BOOST_TEST( derived != 0 ); if( derived != 0 ) { BOOST_TEST_EQ( derived->kind(), "Derived" ); } // polymorphic_downcast can't do crosscasts delete base; } static void test_polymorphic_pointer_downcast_builtin() { Base * base = new Derived; Derived * derived = boost::polymorphic_pointer_downcast( 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 (new Derived); boost::shared_ptr derived = boost::polymorphic_pointer_downcast( 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 (new Derived); boost::intrusive_ptr derived = boost::polymorphic_pointer_downcast( 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 (new Derived); std::shared_ptr derived = boost::polymorphic_pointer_downcast( 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( base ), std::bad_cast ); delete base; } static void test_polymorphic_pointer_cast_fail() { Base * base = new Base; BOOST_TEST_THROWS( boost::polymorphic_pointer_cast( base ), std::bad_cast ); delete base; BOOST_TEST_THROWS( boost::polymorphic_pointer_cast( boost::shared_ptr(new Base) ), std::bad_cast ); #ifndef BOOST_NO_CXX11_SMART_PTR BOOST_TEST_THROWS( boost::polymorphic_pointer_cast( std::shared_ptr(new Base) ), std::bad_cast ); #endif BOOST_TEST_THROWS( boost::polymorphic_pointer_cast( boost::intrusive_ptr(new Base) ), std::bad_cast ); } static void test_polymorphic_downcast_fail() { Base * base = new Base; int old_count = assertion_failed_count; expect_assertion = true; BOOST_TEST_THROWS( boost::polymorphic_downcast( 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_builtin_fail() { Base * base = new Base; int old_count = assertion_failed_count; expect_assertion = true; BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast( 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 (new Base); int old_count = assertion_failed_count; expect_assertion = true; BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast( 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 (new Base); int old_count = assertion_failed_count; expect_assertion = true; BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast( 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 (new Base); int old_count = assertion_failed_count; expect_assertion = true; BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast( 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(); }