]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
b32b8144 FG |
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 | ||
7c673cae FG |
32 | // BOOST_ASSERT custom handler |
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; | |
b32b8144 | 38 | throw expected_assertion(); |
7c673cae FG |
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 | { | |
54 | virtual ~Base() {} | |
55 | virtual std::string kind() { return "Base"; } | |
56 | }; | |
57 | ||
58 | struct Base2 | |
59 | { | |
60 | virtual ~Base2() {} | |
61 | virtual std::string kind2() { return "Base2"; } | |
62 | }; | |
63 | ||
64 | struct Derived : public Base, Base2 | |
65 | { | |
66 | virtual std::string kind() { return "Derived"; } | |
67 | }; | |
68 | ||
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 | ||
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 | ||
173 | static void test_polymorphic_downcast() | |
174 | { | |
f67539c2 | 175 | Base *base_pointer = new Derived; |
7c673cae | 176 | |
f67539c2 TL |
177 | // test raw pointer cast |
178 | Derived *derived_pointer = boost::polymorphic_downcast<Derived *>(base_pointer); | |
7c673cae | 179 | |
f67539c2 | 180 | BOOST_TEST(derived_pointer != 0); |
7c673cae | 181 | |
f67539c2 | 182 | if (derived_pointer != 0) |
7c673cae | 183 | { |
f67539c2 | 184 | BOOST_TEST_EQ(derived_pointer->kind(), "Derived"); |
7c673cae FG |
185 | } |
186 | ||
f67539c2 TL |
187 | // test reference cast |
188 | Derived& derived_ref = boost::polymorphic_downcast<Derived&>(*base_pointer); | |
189 | BOOST_TEST_EQ(derived_ref.kind(), "Derived"); | |
7c673cae | 190 | |
f67539c2 | 191 | delete base_pointer; |
7c673cae FG |
192 | } |
193 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
282 | static void test_polymorphic_downcast_fail() | |
283 | { | |
f67539c2 | 284 | Base * base_pointer = new Base; |
7c673cae | 285 | |
f67539c2 TL |
286 | { |
287 | // test raw pointer cast | |
7c673cae | 288 | |
f67539c2 TL |
289 | int old_count = assertion_failed_count; |
290 | expect_assertion = true; | |
7c673cae | 291 | |
f67539c2 | 292 | BOOST_TEST_THROWS(boost::polymorphic_downcast<Derived *>(base_pointer), expected_assertion); // should assert |
7c673cae | 293 | |
f67539c2 TL |
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; | |
7c673cae FG |
310 | } |
311 | ||
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 | ||
b32b8144 | 319 | BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast<Derived>( base ), expected_assertion ); // should assert |
7c673cae FG |
320 | |
321 | BOOST_TEST_EQ( assertion_failed_count, old_count + 1 ); | |
322 | expect_assertion = false; | |
323 | ||
324 | delete base; | |
325 | } | |
326 | ||
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 | ||
b32b8144 | 334 | BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast<Derived>( base ), expected_assertion ); // should assert |
7c673cae FG |
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 | ||
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 | ||
b32b8144 | 349 | BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast<Derived>( base ), expected_assertion ); // should assert |
7c673cae FG |
350 | |
351 | BOOST_TEST_EQ( assertion_failed_count, old_count + 1 ); | |
352 | expect_assertion = false; | |
353 | } | |
354 | ||
355 | #endif | |
356 | ||
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 | ||
b32b8144 | 364 | BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast<Derived>( base ), expected_assertion); // should assert |
7c673cae FG |
365 | |
366 | BOOST_TEST_EQ( assertion_failed_count, old_count + 1 ); | |
367 | expect_assertion = false; | |
368 | } | |
369 | ||
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 | } |