• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Test boost::polymorphic_cast, boost::polymorphic_downcast and
3 // boost::polymorphic_pointer_cast, boost::polymorphic_pointer_downcast
4 //
5 // Copyright 1999 Beman Dawes
6 // Copyright 1999 Dave Abrahams
7 // Copyright 2014 Peter Dimov
8 // Copyright 2014 Boris Rasin, Antony Polukhin
9 //
10 // Distributed under the Boost Software License, Version 1.0.
11 //
12 // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
13 //
14 
15 #define BOOST_ENABLE_ASSERT_HANDLER
16 #include <boost/polymorphic_cast.hpp>
17 #include <boost/polymorphic_pointer_cast.hpp>
18 #include <boost/smart_ptr/shared_ptr.hpp>
19 #include <boost/smart_ptr/intrusive_ptr.hpp>
20 #include <boost/smart_ptr/intrusive_ref_counter.hpp>
21 #include <boost/core/lightweight_test.hpp>
22 #include <string>
23 #include <memory>
24 
25 static bool expect_assertion = false;
26 static int assertion_failed_count = 0;
27 
28 //assertion handler throws it to exit like assert, but to be able to catch it and stop
29 //usage: BOOST_TEST_THROWS( function_with_assert(), expected_assertion );
30 struct expected_assertion {};
31 
32 // BOOST_ASSERT custom handler
assertion_failed(char const * expr,char const * function,char const * file,long line)33 void boost::assertion_failed( char const * expr, char const * function, char const * file, long line )
34 {
35     if( expect_assertion )
36     {
37         ++assertion_failed_count;
38         throw expected_assertion();
39     }
40     else
41     {
42         BOOST_ERROR( "unexpected assertion" );
43 
44         BOOST_LIGHTWEIGHT_TEST_OSTREAM
45           << file << "(" << line << "): assertion '" << expr << "' failed in function '"
46           << function << "'" << std::endl;
47     }
48 }
49 
50 //
51 
52 struct Base : boost::intrusive_ref_counter<Base>
53 {
~BaseBase54     virtual ~Base() {}
kindBase55     virtual std::string kind() { return "Base"; }
56 };
57 
58 struct Base2
59 {
~Base2Base260     virtual ~Base2() {}
kind2Base261     virtual std::string kind2() { return "Base2"; }
62 };
63 
64 struct Derived : public Base, Base2
65 {
kindDerived66     virtual std::string kind() { return "Derived"; }
67 };
68 
test_polymorphic_cast()69 static void test_polymorphic_cast()
70 {
71     Base * base = new Derived;
72 
73     Derived * derived;
74 
75     try
76     {
77         derived = boost::polymorphic_cast<Derived*>( base );
78 
79         BOOST_TEST( derived != 0 );
80 
81         if( derived != 0 )
82         {
83             BOOST_TEST_EQ( derived->kind(), "Derived" );
84         }
85     }
86     catch( std::bad_cast const& )
87     {
88         BOOST_ERROR( "boost::polymorphic_cast<Derived*>( base ) threw std::bad_cast" );
89     }
90 
91     Base2 * base2;
92 
93     try
94     {
95         base2 = boost::polymorphic_cast<Base2*>( base ); // crosscast
96 
97         BOOST_TEST( base2 != 0 );
98 
99         if( base2 != 0 )
100         {
101             BOOST_TEST_EQ( base2->kind2(), "Base2" );
102         }
103     }
104     catch( std::bad_cast const& )
105     {
106         BOOST_ERROR( "boost::polymorphic_cast<Base2*>( base ) threw std::bad_cast" );
107     }
108 
109     delete base;
110 }
111 
test_polymorphic_pointer_cast()112 static void test_polymorphic_pointer_cast()
113 {
114     Base * base = new Derived;
115 
116     Derived * derived;
117 
118     try
119     {
120         derived = boost::polymorphic_pointer_cast<Derived>( base );
121 
122         BOOST_TEST( derived != 0 );
123 
124         if( derived != 0 )
125         {
126             BOOST_TEST_EQ( derived->kind(), "Derived" );
127         }
128     }
129     catch( std::bad_cast const& )
130     {
131         BOOST_ERROR( "boost::polymorphic_pointer_cast<Derived>( base ) threw std::bad_cast" );
132     }
133 
134     Base2 * base2;
135 
136     try
137     {
138         base2 = boost::polymorphic_pointer_cast<Base2>( base ); // crosscast
139 
140         BOOST_TEST( base2 != 0 );
141 
142         if( base2 != 0 )
143         {
144             BOOST_TEST_EQ( base2->kind2(), "Base2" );
145         }
146     }
147     catch( std::bad_cast const& )
148     {
149         BOOST_ERROR( "boost::polymorphic_pointer_cast<Base2>( base ) threw std::bad_cast" );
150     }
151 
152     boost::shared_ptr<Base> sp_base( base );
153     boost::shared_ptr<Base2> sp_base2;
154     try
155     {
156         sp_base2 = boost::polymorphic_pointer_cast<Base2>( sp_base ); // crosscast
157 
158         BOOST_TEST( sp_base2 != 0 );
159 
160         if( sp_base2 != 0 )
161         {
162             BOOST_TEST_EQ( sp_base2->kind2(), "Base2" );
163         }
164     }
165     catch( std::bad_cast const& )
166     {
167         BOOST_ERROR( "boost::polymorphic_pointer_cast<Base2>( sp_base ) threw std::bad_cast" );
168     }
169 
170     // we do not `delete base;` because sahred_ptr is holding base
171 }
172 
test_polymorphic_downcast()173 static void test_polymorphic_downcast()
174 {
175     Base *base_pointer = new Derived;
176 
177     // test raw pointer cast
178     Derived *derived_pointer = boost::polymorphic_downcast<Derived *>(base_pointer);
179 
180     BOOST_TEST(derived_pointer != 0);
181 
182     if (derived_pointer != 0)
183     {
184         BOOST_TEST_EQ(derived_pointer->kind(), "Derived");
185     }
186 
187     // test reference cast
188     Derived& derived_ref = boost::polymorphic_downcast<Derived&>(*base_pointer);
189     BOOST_TEST_EQ(derived_ref.kind(), "Derived");
190 
191     delete base_pointer;
192 }
193 
test_polymorphic_pointer_downcast_builtin()194 static void test_polymorphic_pointer_downcast_builtin()
195 {
196     Base * base = new Derived;
197 
198     Derived * derived = boost::polymorphic_pointer_downcast<Derived>( base );
199 
200     BOOST_TEST( derived != 0 );
201 
202     if( derived != 0 )
203     {
204         BOOST_TEST_EQ( derived->kind(), "Derived" );
205     }
206 
207     // polymorphic_pointer_downcast can't do crosscasts
208 
209     delete base;
210 }
211 
test_polymorphic_pointer_downcast_boost_shared()212 static void test_polymorphic_pointer_downcast_boost_shared()
213 {
214     boost::shared_ptr<Base> base (new Derived);
215 
216     boost::shared_ptr<Derived> derived = boost::polymorphic_pointer_downcast<Derived>( base );
217 
218     BOOST_TEST( derived != 0 );
219 
220     if( derived != 0 )
221     {
222         BOOST_TEST_EQ( derived->kind(), "Derived" );
223     }
224 }
225 
test_polymorphic_pointer_downcast_intrusive()226 static void test_polymorphic_pointer_downcast_intrusive()
227 {
228     boost::intrusive_ptr<Base> base (new Derived);
229 
230     boost::intrusive_ptr<Derived> derived = boost::polymorphic_pointer_downcast<Derived>( base );
231 
232     BOOST_TEST( derived != 0 );
233 
234     if( derived != 0 )
235     {
236         BOOST_TEST_EQ( derived->kind(), "Derived" );
237     }
238 }
239 
240 #ifndef BOOST_NO_CXX11_SMART_PTR
241 
test_polymorphic_pointer_downcast_std_shared()242 static void test_polymorphic_pointer_downcast_std_shared()
243 {
244     std::shared_ptr<Base> base (new Derived);
245 
246     std::shared_ptr<Derived> derived = boost::polymorphic_pointer_downcast<Derived>( base );
247 
248     BOOST_TEST( derived != 0 );
249 
250     if( derived != 0 )
251     {
252         BOOST_TEST_EQ( derived->kind(), "Derived" );
253     }
254 }
255 
256 #endif
257 
test_polymorphic_cast_fail()258 static void test_polymorphic_cast_fail()
259 {
260     Base * base = new Base;
261 
262     BOOST_TEST_THROWS( boost::polymorphic_cast<Derived*>( base ), std::bad_cast );
263 
264     delete base;
265 }
266 
test_polymorphic_pointer_cast_fail()267 static void test_polymorphic_pointer_cast_fail()
268 {
269     Base * base = new Base;
270     BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( base ), std::bad_cast );
271     delete base;
272 
273     BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( boost::shared_ptr<Base>(new Base) ), std::bad_cast );
274 
275 #ifndef BOOST_NO_CXX11_SMART_PTR
276     BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( std::shared_ptr<Base>(new Base) ), std::bad_cast );
277 #endif
278 
279     BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( boost::intrusive_ptr<Base>(new Base) ), std::bad_cast );
280 }
281 
test_polymorphic_downcast_fail()282 static void test_polymorphic_downcast_fail()
283 {
284     Base * base_pointer = new Base;
285 
286     {
287         // test raw pointer cast
288 
289         int old_count = assertion_failed_count;
290         expect_assertion = true;
291 
292         BOOST_TEST_THROWS(boost::polymorphic_downcast<Derived *>(base_pointer), expected_assertion); // should assert
293 
294         BOOST_TEST_EQ(assertion_failed_count, old_count + 1);
295         expect_assertion = false;
296     }
297     {
298         // test reference cast
299 
300         int old_count = assertion_failed_count;
301         expect_assertion = true;
302 
303         BOOST_TEST_THROWS(boost::polymorphic_downcast<Derived &>(*base_pointer), expected_assertion); // should assert
304 
305         BOOST_TEST_EQ(assertion_failed_count, old_count + 1);
306         expect_assertion = false;
307     }
308 
309     delete base_pointer;
310 }
311 
test_polymorphic_pointer_downcast_builtin_fail()312 static void test_polymorphic_pointer_downcast_builtin_fail()
313 {
314     Base * base = new Base;
315 
316     int old_count = assertion_failed_count;
317     expect_assertion = true;
318 
319     BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast<Derived>( base ), expected_assertion ); // should assert
320 
321     BOOST_TEST_EQ( assertion_failed_count, old_count + 1 );
322     expect_assertion = false;
323 
324     delete base;
325 }
326 
test_polymorphic_pointer_downcast_boost_shared_fail()327 static void test_polymorphic_pointer_downcast_boost_shared_fail()
328 {
329     boost::shared_ptr<Base> base (new Base);
330 
331     int old_count = assertion_failed_count;
332     expect_assertion = true;
333 
334     BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast<Derived>( base ), expected_assertion ); // should assert
335 
336     BOOST_TEST_EQ( assertion_failed_count, old_count + 1 );
337     expect_assertion = false;
338 }
339 
340 #ifndef BOOST_NO_CXX11_SMART_PTR
341 
test_polymorphic_pointer_downcast_std_shared_fail()342 static void test_polymorphic_pointer_downcast_std_shared_fail()
343 {
344     std::shared_ptr<Base> base (new Base);
345 
346     int old_count = assertion_failed_count;
347     expect_assertion = true;
348 
349     BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast<Derived>( base ), expected_assertion ); // should assert
350 
351     BOOST_TEST_EQ( assertion_failed_count, old_count + 1 );
352     expect_assertion = false;
353 }
354 
355 #endif
356 
test_polymorphic_pointer_downcast_intrusive_fail()357 static void test_polymorphic_pointer_downcast_intrusive_fail()
358 {
359     boost::intrusive_ptr<Base> base (new Base);
360 
361     int old_count = assertion_failed_count;
362     expect_assertion = true;
363 
364     BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast<Derived>( base ), expected_assertion); // should assert
365 
366     BOOST_TEST_EQ( assertion_failed_count, old_count + 1 );
367     expect_assertion = false;
368 }
369 
main()370 int main()
371 {
372     test_polymorphic_cast();
373     test_polymorphic_pointer_cast();
374     test_polymorphic_downcast();
375     test_polymorphic_pointer_downcast_builtin();
376     test_polymorphic_pointer_downcast_boost_shared();
377     test_polymorphic_pointer_downcast_intrusive();
378     test_polymorphic_cast_fail();
379     test_polymorphic_pointer_cast_fail();
380     test_polymorphic_downcast_fail();
381     test_polymorphic_pointer_downcast_builtin_fail();
382     test_polymorphic_pointer_downcast_boost_shared_fail();
383     test_polymorphic_pointer_downcast_intrusive_fail();
384 
385 #ifndef BOOST_NO_CXX11_SMART_PTR
386     test_polymorphic_pointer_downcast_std_shared();
387     test_polymorphic_pointer_downcast_std_shared_fail();
388 #endif
389 
390     return boost::report_errors();
391 }
392