1 //Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc.
2 
3 //Distributed under the Boost Software License, Version 1.0. (See accompanying
4 //file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #include <boost/config.hpp>
7 
8 #if defined( BOOST_NO_EXCEPTIONS )
9 #   error This program requires exception handling.
10 #endif
11 
12 #include <boost/exception_ptr.hpp>
13 #include <boost/exception/get_error_info.hpp>
14 #include <boost/exception/errinfo_nested_exception.hpp>
15 #include <boost/detail/lightweight_test.hpp>
16 #include <boost/detail/workaround.hpp>
17 #include <string>
18 #include <ios>
19 
20 typedef boost::error_info<struct my_tag,int> my_info;
21 
22 template <class T>
23 struct
24 may_throw_on_copy
25     {
may_throw_on_copymay_throw_on_copy26     may_throw_on_copy():
27         throw_(false)
28         {
29         }
30 
may_throw_on_copymay_throw_on_copy31     may_throw_on_copy( may_throw_on_copy const & x ):
32         throw_(x.throw_)
33         {
34         if( throw_ )
35             throw T();
36         }
37 
38     bool throw_;
39     };
40 
41 struct
42 derives_nothing
43     {
44     int & count;
45 
46     explicit
derives_nothingderives_nothing47     derives_nothing( int & c ):
48         count(c)
49         {
50         ++count;
51         }
52 
derives_nothingderives_nothing53     derives_nothing( derives_nothing const & x ):
54         count(x.count)
55         {
56         ++count;
57         }
58 
~derives_nothingderives_nothing59     ~derives_nothing()
60         {
61         --count;
62         }
63     };
64 
65 struct
66 derives_std_exception:
67     std::exception
68     {
69     };
70 
71 struct
72 derives_std_boost_exception:
73     std::exception,
74     boost::exception
75     {
76     char const * const wh_;
77 
derives_std_boost_exceptionderives_std_boost_exception78     derives_std_boost_exception( char const * wh="derives_std_boost_exception" ):
79         wh_(wh)
80         {
81         }
82 
whatderives_std_boost_exception83     char const * what() const BOOST_NOEXCEPT_OR_NOTHROW
84         {
85         return wh_;
86         }
87     };
88 
89 struct
90 derives_boost_exception:
91     boost::exception
92     {
93     };
94 
95 template <class T>
96 void
test_std_exception()97 test_std_exception()
98     {
99     try
100         {
101         throw T();
102         }
103     catch(
104     ... )
105         {
106         boost::exception_ptr p = boost::current_exception();
107         BOOST_TEST(!(p==boost::exception_ptr()));
108         BOOST_TEST(p!=boost::exception_ptr());
109         BOOST_TEST(p);
110         try
111             {
112             rethrow_exception(p);
113             BOOST_TEST(false);
114             }
115         catch(
116         T & )
117             {
118             boost::exception_ptr p = boost::current_exception();
119             BOOST_TEST(!(p==boost::exception_ptr()));
120             BOOST_TEST(p!=boost::exception_ptr());
121             BOOST_TEST(p);
122             try
123                 {
124                 rethrow_exception(p);
125                 BOOST_TEST(false);
126                 }
127             catch(
128             T & )
129                 {
130                 }
131             catch(
132             ... )
133                 {
134                 BOOST_TEST(false);
135                 }
136             }
137         catch(
138         ... )
139             {
140             BOOST_TEST(false);
141             }
142         try
143             {
144             rethrow_exception(p);
145             BOOST_TEST(false);
146             }
147         catch(
148         boost::exception & x )
149             {
150 #ifndef BOOST_NO_RTTI
151             std::type_info const * const * t=boost::get_error_info<boost::original_exception_type>(x);
152             BOOST_TEST(t!=0 && *t!=0 && **t==typeid(T));
153             std::string s=diagnostic_information(x);
154             BOOST_TEST(!s.empty());
155 #endif
156             }
157         catch(
158         T & )
159             {
160             }
161         catch(
162         ... )
163             {
164             BOOST_TEST(false);
165             }
166         }
167     }
168 
169 template <class T>
170 void
test_std_exception_what()171 test_std_exception_what()
172     {
173     try
174         {
175         throw T("what");
176         }
177     catch(
178     ... )
179         {
180         boost::exception_ptr p = boost::current_exception();
181         BOOST_TEST(!(p==boost::exception_ptr()));
182         BOOST_TEST(p!=boost::exception_ptr());
183         BOOST_TEST(p);
184         try
185             {
186             rethrow_exception(p);
187             BOOST_TEST(false);
188             }
189         catch(
190         T & x )
191             {
192             BOOST_TEST(std::string(x.what()).find("what")!=std::string::npos);
193             boost::exception_ptr p = boost::current_exception();
194             BOOST_TEST(!(p==boost::exception_ptr()));
195             BOOST_TEST(p!=boost::exception_ptr());
196             BOOST_TEST(p);
197             try
198                 {
199                 rethrow_exception(p);
200                 BOOST_TEST(false);
201                 }
202             catch(
203             T & x )
204                 {
205                 BOOST_TEST(std::string(x.what()).find("what")!=std::string::npos);
206                 }
207             catch(
208             ... )
209                 {
210                 BOOST_TEST(false);
211                 }
212             }
213         catch(
214         ... )
215             {
216             BOOST_TEST(false);
217             }
218         try
219             {
220             rethrow_exception(p);
221             BOOST_TEST(false);
222             }
223         catch(
224         boost::exception & x )
225             {
226 #ifndef BOOST_NO_RTTI
227             std::type_info const * const * t=boost::get_error_info<boost::original_exception_type>(x);
228             BOOST_TEST(t!=0 && *t!=0 && **t==typeid(T));
229 #endif
230             }
231         catch(
232         T & )
233             {
234             }
235         catch(
236         ... )
237             {
238             BOOST_TEST(false);
239             }
240         }
241     }
242 
243 template <class Throw,class Catch>
244 void
test_throw_on_copy()245 test_throw_on_copy()
246     {
247     try
248         {
249         try
250             {
251             throw boost::enable_current_exception(may_throw_on_copy<Throw>());
252             }
253         catch(
254         may_throw_on_copy<Throw> & x )
255             {
256             x.throw_=true;
257             throw;
258             }
259         catch(
260         ... )
261             {
262             BOOST_TEST(false);
263             }
264         }
265     catch(
266     ... )
267         {
268         boost::exception_ptr p = boost::current_exception();
269         BOOST_TEST(!(p==boost::exception_ptr()));
270         BOOST_TEST(p!=boost::exception_ptr());
271         BOOST_TEST(p);
272         try
273             {
274             rethrow_exception(p);
275             BOOST_TEST(false);
276             }
277         catch(
278         Catch & )
279             {
280             boost::exception_ptr p = boost::current_exception();
281             BOOST_TEST(!(p==boost::exception_ptr()));
282             BOOST_TEST(p!=boost::exception_ptr());
283             BOOST_TEST(p);
284             try
285                 {
286                 boost::rethrow_exception(p);
287                 BOOST_TEST(false);
288                 }
289             catch(
290             Catch & )
291                 {
292                 }
293             catch(
294             ... )
295                 {
296                 BOOST_TEST(false);
297                 }
298             }
299         catch(
300         ... )
301             {
302             BOOST_TEST(false);
303             }
304         }
305     }
306 
307 int
main()308 main()
309     {
310     BOOST_TEST( boost::exception_ptr()==boost::exception_ptr() );
311     BOOST_TEST( !(boost::exception_ptr()!=boost::exception_ptr()) );
312     BOOST_TEST( !boost::exception_ptr() );
313 
314     int count=0;
315     try
316         {
317         throw boost::enable_current_exception(derives_nothing(count));
318         }
319     catch(
320     ... )
321         {
322         boost::exception_ptr p = boost::current_exception();
323         BOOST_TEST(!(p==boost::exception_ptr()));
324         BOOST_TEST(p!=boost::exception_ptr());
325         BOOST_TEST(p);
326         try
327             {
328             rethrow_exception(p);
329             BOOST_TEST(false);
330             }
331         catch(
332         derives_nothing & )
333             {
334             }
335         catch(
336         ... )
337             {
338             BOOST_TEST(false);
339             }
340         }
341     BOOST_TEST(count==0);
342 
343     try
344         {
345         throw boost::enable_current_exception(derives_std_exception());
346         }
347     catch(
348     ... )
349         {
350         boost::exception_ptr p = boost::current_exception();
351         BOOST_TEST(!(p==boost::exception_ptr()));
352         BOOST_TEST(p!=boost::exception_ptr());
353         BOOST_TEST(p);
354         try
355             {
356             rethrow_exception(p);
357             BOOST_TEST(false);
358             }
359         catch(
360         derives_std_exception & )
361             {
362             boost::exception_ptr p = boost::current_exception();
363             BOOST_TEST(!(p==boost::exception_ptr()));
364             BOOST_TEST(p!=boost::exception_ptr());
365             BOOST_TEST(p);
366             try
367                 {
368                 rethrow_exception(p);
369                 BOOST_TEST(false);
370                 }
371             catch(
372             derives_std_exception & )
373                 {
374                 }
375             catch(
376             ... )
377                 {
378                 BOOST_TEST(false);
379                 }
380             }
381         catch(
382         ... )
383             {
384             BOOST_TEST(false);
385             }
386         }
387 
388     try
389         {
390         throw derives_std_exception();
391         }
392     catch(
393     ... )
394         {
395         boost::exception_ptr p = boost::current_exception();
396         BOOST_TEST(!(p==boost::exception_ptr()));
397         BOOST_TEST(p!=boost::exception_ptr());
398         BOOST_TEST(p);
399         try
400             {
401             rethrow_exception(p);
402             BOOST_TEST(false);
403             }
404         catch(
405         derives_std_exception & )
406             {
407             //Yay! Non-intrusive cloning supported!
408             }
409         catch(
410         boost::unknown_exception & e )
411             {
412 #ifndef BOOST_NO_RTTI
413             std::type_info const * const * t=boost::get_error_info<boost::original_exception_type>(e);
414             BOOST_TEST(t!=0 && *t!=0 && **t==typeid(derives_std_exception));
415 #endif
416             }
417         catch(
418         ... )
419             {
420             BOOST_TEST(false);
421             }
422         }
423 
424     test_std_exception_what<std::domain_error>();
425     test_std_exception_what<std::invalid_argument>();
426     test_std_exception_what<std::length_error>();
427     test_std_exception_what<std::out_of_range>();
428     test_std_exception_what<std::logic_error>();
429     test_std_exception_what<std::range_error>();
430     test_std_exception_what<std::overflow_error>();
431     test_std_exception_what<std::underflow_error>();
432 #if !defined(_GLIBCXX_USE_CXX11_ABI) || !_GLIBCXX_USE_CXX11_ABI
433     test_std_exception_what<std::ios_base::failure>();
434 #endif
435     test_std_exception_what<std::runtime_error>();
436     test_std_exception<std::bad_alloc>();
437 #ifndef BOOST_NO_TYPEID
438     test_std_exception<std::bad_cast>();
439     test_std_exception<std::bad_typeid>();
440 #endif
441     test_std_exception<std::bad_exception>();
442     test_std_exception<std::exception>();
443 
444     try
445         {
446         throw derives_std_boost_exception() << my_info(42);
447         }
448     catch(
449     ... )
450         {
451         boost::exception_ptr p = boost::current_exception();
452         BOOST_TEST(!(p==boost::exception_ptr()));
453         BOOST_TEST(p!=boost::exception_ptr());
454         BOOST_TEST(p);
455         try
456             {
457             rethrow_exception(p);
458             BOOST_TEST(false);
459             }
460         catch(
461         derives_std_boost_exception & x )
462             {
463             //Yay! Non-intrusive cloning supported!
464             BOOST_TEST(boost::get_error_info<my_info>(x));
465             if( int const * p=boost::get_error_info<my_info>(x) )
466                 BOOST_TEST(*p==42);
467             }
468         catch(
469         boost::unknown_exception & x )
470             {
471             BOOST_TEST(boost::get_error_info<my_info>(x));
472             if( int const * p=boost::get_error_info<my_info>(x) )
473                 BOOST_TEST(*p==42);
474 #ifndef BOOST_NO_RTTI
475                 {
476             std::type_info const * const * t=boost::get_error_info<boost::original_exception_type>(x);
477             BOOST_TEST(t && *t && **t==typeid(derives_std_boost_exception));
478                 }
479 #endif
480             boost::exception_ptr p = boost::current_exception();
481             BOOST_TEST(!(p==boost::exception_ptr()));
482             BOOST_TEST(p!=boost::exception_ptr());
483             BOOST_TEST(p);
484             try
485                 {
486                 rethrow_exception(p);
487                 BOOST_TEST(false);
488                 }
489             catch(
490             boost::unknown_exception & x )
491                 {
492                 BOOST_TEST(boost::get_error_info<my_info>(x));
493                 if( int const * p=boost::get_error_info<my_info>(x) )
494                     BOOST_TEST(*p==42);
495 #ifndef BOOST_NO_RTTI
496                 std::type_info const * const * t=boost::get_error_info<boost::original_exception_type>(x);
497                 BOOST_TEST(t && *t && **t==typeid(derives_std_boost_exception));
498 #endif
499                 }
500             catch(
501             ... )
502                 {
503                 BOOST_TEST(false);
504                 }
505             }
506         catch(
507         ... )
508             {
509             BOOST_TEST(false);
510             }
511         }
512 
513     try
514         {
515         throw derives_boost_exception() << my_info(42);
516         }
517     catch(
518     ... )
519         {
520         boost::exception_ptr p = boost::current_exception();
521         BOOST_TEST(!(p==boost::exception_ptr()));
522         BOOST_TEST(p!=boost::exception_ptr());
523         BOOST_TEST(p);
524         try
525             {
526             rethrow_exception(p);
527             BOOST_TEST(false);
528             }
529         catch(
530         derives_boost_exception & x )
531             {
532             //Yay! Non-intrusive cloning supported!
533             BOOST_TEST(boost::get_error_info<my_info>(x));
534             if( int const * p=boost::get_error_info<my_info>(x) )
535                 BOOST_TEST(*p==42);
536             }
537         catch(
538         boost::unknown_exception & x )
539             {
540             BOOST_TEST(boost::get_error_info<my_info>(x));
541             if( int const * p=boost::get_error_info<my_info>(x) )
542                 BOOST_TEST(*p==42);
543 #ifndef BOOST_NO_RTTI
544                 {
545             std::type_info const * const * t=boost::get_error_info<boost::original_exception_type>(x);
546             BOOST_TEST(t && *t && **t==typeid(derives_boost_exception));
547                 }
548 #endif
549             boost::exception_ptr p = boost::current_exception();
550             BOOST_TEST(!(p==boost::exception_ptr()));
551             BOOST_TEST(p!=boost::exception_ptr());
552             BOOST_TEST(p);
553             try
554                 {
555                 rethrow_exception(p);
556                 BOOST_TEST(false);
557                 }
558             catch(
559             boost::unknown_exception & x )
560                 {
561                 BOOST_TEST(boost::get_error_info<my_info>(x));
562                 if( int const * p=boost::get_error_info<my_info>(x) )
563                     BOOST_TEST(*p==42);
564                 }
565             catch(
566             ... )
567                 {
568                 BOOST_TEST(false);
569                 }
570             }
571         catch(
572         ... )
573             {
574             BOOST_TEST(false);
575             }
576         }
577 
578     test_throw_on_copy<std::bad_alloc,std::bad_alloc>();
579     test_throw_on_copy<int,std::bad_exception>();
580 
581     try
582         {
583         throw boost::enable_current_exception(derives_std_boost_exception("what1"));
584         }
585     catch(
586     ... )
587         {
588         boost::exception_ptr p=boost::current_exception();
589             {
590         std::string s=diagnostic_information(p);
591         BOOST_TEST(s.find("what1")!=s.npos);
592             }
593         try
594             {
595             throw boost::enable_current_exception(derives_std_boost_exception("what2") << boost::errinfo_nested_exception(p) );
596             }
597         catch(
598         ... )
599             {
600             std::string s=boost::current_exception_diagnostic_information();
601             BOOST_TEST(s.find("what1")!=s.npos);
602             BOOST_TEST(s.find("what2")!=s.npos);
603             }
604         }
605     BOOST_TEST(!diagnostic_information(boost::exception_ptr()).empty());
606     return boost::report_errors();
607     }
608