]>
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 | { | |
175 | Base * base = new Derived; | |
176 | ||
177 | Derived * derived = boost::polymorphic_downcast<Derived*>( base ); | |
178 | ||
179 | BOOST_TEST( derived != 0 ); | |
180 | ||
181 | if( derived != 0 ) | |
182 | { | |
183 | BOOST_TEST_EQ( derived->kind(), "Derived" ); | |
184 | } | |
185 | ||
186 | // polymorphic_downcast can't do crosscasts | |
187 | ||
188 | delete base; | |
189 | } | |
190 | ||
191 | static void test_polymorphic_pointer_downcast_builtin() | |
192 | { | |
193 | Base * base = new Derived; | |
194 | ||
195 | Derived * derived = boost::polymorphic_pointer_downcast<Derived>( base ); | |
196 | ||
197 | BOOST_TEST( derived != 0 ); | |
198 | ||
199 | if( derived != 0 ) | |
200 | { | |
201 | BOOST_TEST_EQ( derived->kind(), "Derived" ); | |
202 | } | |
203 | ||
204 | // polymorphic_pointer_downcast can't do crosscasts | |
205 | ||
206 | delete base; | |
207 | } | |
208 | ||
209 | static void test_polymorphic_pointer_downcast_boost_shared() | |
210 | { | |
211 | boost::shared_ptr<Base> base (new Derived); | |
212 | ||
213 | boost::shared_ptr<Derived> derived = boost::polymorphic_pointer_downcast<Derived>( base ); | |
214 | ||
215 | BOOST_TEST( derived != 0 ); | |
216 | ||
217 | if( derived != 0 ) | |
218 | { | |
219 | BOOST_TEST_EQ( derived->kind(), "Derived" ); | |
220 | } | |
221 | } | |
222 | ||
223 | static void test_polymorphic_pointer_downcast_intrusive() | |
224 | { | |
225 | boost::intrusive_ptr<Base> base (new Derived); | |
226 | ||
227 | boost::intrusive_ptr<Derived> derived = boost::polymorphic_pointer_downcast<Derived>( base ); | |
228 | ||
229 | BOOST_TEST( derived != 0 ); | |
230 | ||
231 | if( derived != 0 ) | |
232 | { | |
233 | BOOST_TEST_EQ( derived->kind(), "Derived" ); | |
234 | } | |
235 | } | |
236 | ||
237 | #ifndef BOOST_NO_CXX11_SMART_PTR | |
238 | ||
239 | static void test_polymorphic_pointer_downcast_std_shared() | |
240 | { | |
241 | std::shared_ptr<Base> base (new Derived); | |
242 | ||
243 | std::shared_ptr<Derived> derived = boost::polymorphic_pointer_downcast<Derived>( base ); | |
244 | ||
245 | BOOST_TEST( derived != 0 ); | |
246 | ||
247 | if( derived != 0 ) | |
248 | { | |
249 | BOOST_TEST_EQ( derived->kind(), "Derived" ); | |
250 | } | |
251 | } | |
252 | ||
253 | #endif | |
254 | ||
255 | static void test_polymorphic_cast_fail() | |
256 | { | |
257 | Base * base = new Base; | |
258 | ||
259 | BOOST_TEST_THROWS( boost::polymorphic_cast<Derived*>( base ), std::bad_cast ); | |
260 | ||
261 | delete base; | |
262 | } | |
263 | ||
264 | static void test_polymorphic_pointer_cast_fail() | |
265 | { | |
266 | Base * base = new Base; | |
267 | BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( base ), std::bad_cast ); | |
268 | delete base; | |
269 | ||
270 | BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( boost::shared_ptr<Base>(new Base) ), std::bad_cast ); | |
271 | ||
272 | #ifndef BOOST_NO_CXX11_SMART_PTR | |
273 | BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( std::shared_ptr<Base>(new Base) ), std::bad_cast ); | |
274 | #endif | |
275 | ||
276 | BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( boost::intrusive_ptr<Base>(new Base) ), std::bad_cast ); | |
277 | } | |
278 | ||
279 | static void test_polymorphic_downcast_fail() | |
280 | { | |
281 | Base * base = new Base; | |
282 | ||
283 | int old_count = assertion_failed_count; | |
284 | expect_assertion = true; | |
285 | ||
b32b8144 | 286 | BOOST_TEST_THROWS( boost::polymorphic_downcast<Derived*>( base ), expected_assertion ); // should assert |
7c673cae FG |
287 | |
288 | BOOST_TEST_EQ( assertion_failed_count, old_count + 1 ); | |
289 | expect_assertion = false; | |
290 | ||
291 | delete base; | |
292 | } | |
293 | ||
294 | static void test_polymorphic_pointer_downcast_builtin_fail() | |
295 | { | |
296 | Base * base = new Base; | |
297 | ||
298 | int old_count = assertion_failed_count; | |
299 | expect_assertion = true; | |
300 | ||
b32b8144 | 301 | BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast<Derived>( base ), expected_assertion ); // should assert |
7c673cae FG |
302 | |
303 | BOOST_TEST_EQ( assertion_failed_count, old_count + 1 ); | |
304 | expect_assertion = false; | |
305 | ||
306 | delete base; | |
307 | } | |
308 | ||
309 | static void test_polymorphic_pointer_downcast_boost_shared_fail() | |
310 | { | |
311 | boost::shared_ptr<Base> base (new Base); | |
312 | ||
313 | int old_count = assertion_failed_count; | |
314 | expect_assertion = true; | |
315 | ||
b32b8144 | 316 | BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast<Derived>( base ), expected_assertion ); // should assert |
7c673cae FG |
317 | |
318 | BOOST_TEST_EQ( assertion_failed_count, old_count + 1 ); | |
319 | expect_assertion = false; | |
320 | } | |
321 | ||
322 | #ifndef BOOST_NO_CXX11_SMART_PTR | |
323 | ||
324 | static void test_polymorphic_pointer_downcast_std_shared_fail() | |
325 | { | |
326 | std::shared_ptr<Base> base (new Base); | |
327 | ||
328 | int old_count = assertion_failed_count; | |
329 | expect_assertion = true; | |
330 | ||
b32b8144 | 331 | BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast<Derived>( base ), expected_assertion ); // should assert |
7c673cae FG |
332 | |
333 | BOOST_TEST_EQ( assertion_failed_count, old_count + 1 ); | |
334 | expect_assertion = false; | |
335 | } | |
336 | ||
337 | #endif | |
338 | ||
339 | static void test_polymorphic_pointer_downcast_intrusive_fail() | |
340 | { | |
341 | boost::intrusive_ptr<Base> base (new Base); | |
342 | ||
343 | int old_count = assertion_failed_count; | |
344 | expect_assertion = true; | |
345 | ||
b32b8144 | 346 | BOOST_TEST_THROWS( boost::polymorphic_pointer_downcast<Derived>( base ), expected_assertion); // should assert |
7c673cae FG |
347 | |
348 | BOOST_TEST_EQ( assertion_failed_count, old_count + 1 ); | |
349 | expect_assertion = false; | |
350 | } | |
351 | ||
352 | int main() | |
353 | { | |
354 | test_polymorphic_cast(); | |
355 | test_polymorphic_pointer_cast(); | |
356 | test_polymorphic_downcast(); | |
357 | test_polymorphic_pointer_downcast_builtin(); | |
358 | test_polymorphic_pointer_downcast_boost_shared(); | |
359 | test_polymorphic_pointer_downcast_intrusive(); | |
360 | test_polymorphic_cast_fail(); | |
361 | test_polymorphic_pointer_cast_fail(); | |
362 | test_polymorphic_downcast_fail(); | |
363 | test_polymorphic_pointer_downcast_builtin_fail(); | |
364 | test_polymorphic_pointer_downcast_boost_shared_fail(); | |
365 | test_polymorphic_pointer_downcast_intrusive_fail(); | |
366 | ||
367 | #ifndef BOOST_NO_CXX11_SMART_PTR | |
368 | test_polymorphic_pointer_downcast_std_shared(); | |
369 | test_polymorphic_pointer_downcast_std_shared_fail(); | |
370 | #endif | |
371 | ||
372 | return boost::report_errors(); | |
373 | } |