1 //Copyright (c) 2006-2015 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/get_error_info.hpp>
13 #include <boost/exception/info_tuple.hpp>
14 #include <boost/exception_ptr.hpp>
15 #include <boost/detail/lightweight_test.hpp>
16 #include <boost/detail/workaround.hpp>
17 
18 struct throws_on_copy;
19 struct non_printable { };
20 
21 struct
22 user_data
23     {
24     int & count;
25 
26     explicit
user_datauser_data27     user_data( int & count ):
28         count(count)
29         {
30         ++count;
31         }
32 
user_datauser_data33     user_data( user_data const & x ):
34         count(x.count)
35         {
36         ++count;
37         }
38 
~user_datauser_data39     ~user_data()
40         {
41         --count;
42         }
43     };
44 
45 typedef boost::error_info<struct tag_test_1,int> test_1;
46 typedef boost::error_info<struct tag_test_2,unsigned int> test_2;
47 typedef boost::error_info<struct tag_test_3,float> test_3;
48 typedef boost::error_info<struct tag_test_4,throws_on_copy> test_4;
49 typedef boost::error_info<struct tag_test_5,std::string> test_5;
50 typedef boost::error_info<struct tag_test_6,non_printable> test_6;
51 typedef boost::error_info<struct tag_user_data,user_data> test_7;
52 
53 struct
54 test_exception:
55     boost::exception
56     {
57     };
58 
59 struct
60 throws_on_copy
61     {
throws_on_copythrows_on_copy62     throws_on_copy()
63         {
64         }
65 
throws_on_copythrows_on_copy66     throws_on_copy( throws_on_copy const & )
67         {
68         throw test_exception();
69         }
70     };
71 
72 void
basic_test()73 basic_test()
74     {
75     try
76         {
77         test_exception x;
78         add_info(add_info(add_info(x,test_1(1)),test_2(2u)),test_3(3.14159f));
79         throw x;
80         }
81     catch(
82     test_exception & x )
83         {
84         ++*boost::get_error_info<test_1>(x);
85         ++*boost::get_error_info<test_2>(x);
86         ++*boost::get_error_info<test_3>(x);
87         BOOST_TEST(*boost::get_error_info<test_1>(x)==2);
88         BOOST_TEST(*boost::get_error_info<test_2>(x)==3u);
89         BOOST_TEST(*boost::get_error_info<test_3>(x)==4.14159f);
90         BOOST_TEST(!boost::get_error_info<test_4>(x));
91         }
92     try
93         {
94         test_exception x;
95         add_info(add_info(add_info(x,test_1(1)),test_2(2u)),test_3(3.14159f));
96         throw x;
97         }
98     catch(
99     test_exception const & x )
100         {
101         BOOST_TEST(*boost::get_error_info<test_1>(x)==1);
102         BOOST_TEST(*boost::get_error_info<test_2>(x)==2u);
103         BOOST_TEST(*boost::get_error_info<test_3>(x)==3.14159f);
104         BOOST_TEST(!boost::get_error_info<test_4>(x));
105         }
106     }
107 
108 void
exception_safety_test()109 exception_safety_test()
110     {
111     test_exception x;
112     try
113         {
114         add_info(x,test_4(throws_on_copy()));
115         BOOST_TEST(false);
116         }
117     catch(
118     test_exception & )
119         {
120         BOOST_TEST(!boost::get_error_info<test_4>(x));
121         }
122     }
123 
124 void
throw_empty()125 throw_empty()
126     {
127     throw test_exception();
128     }
129 
130 void
throw_test_1(char const * value)131 throw_test_1( char const * value )
132     {
133     throw add_info(test_exception(),test_5(std::string(value)));
134     }
135 
136 void
throw_test_2()137 throw_test_2()
138     {
139     throw add_info(test_exception(),test_6(non_printable()));
140     }
141 
142 void
throw_catch_add_file_name(char const * name)143 throw_catch_add_file_name( char const * name )
144     {
145     try
146         {
147         throw_empty();
148         BOOST_TEST(false);
149         }
150     catch(
151     boost::exception & x )
152         {
153         add_info(x,test_5(std::string(name)));
154         throw;
155         }
156     }
157 
158 void
test_empty()159 test_empty()
160     {
161     try
162         {
163         throw_empty();
164         BOOST_TEST(false);
165         }
166     catch(
167     boost::exception & x )
168         {
169 #ifndef BOOST_NO_RTTI
170         BOOST_TEST( dynamic_cast<test_exception *>(&x) );
171 #endif
172         BOOST_TEST( !boost::get_error_info<test_1>(x) );
173         }
174     catch(
175     ... )
176         {
177         BOOST_TEST(false);
178         }
179 
180     try
181         {
182         throw_empty();
183         BOOST_TEST(false);
184         }
185     catch(
186     test_exception & x )
187         {
188 #ifndef BOOST_NO_RTTI
189         BOOST_TEST( dynamic_cast<boost::exception const *>(&x)!=0 );
190 #endif
191         }
192     catch(
193     ... )
194         {
195         BOOST_TEST(false);
196         }
197     }
198 
199 void
test_basic_throw_catch()200 test_basic_throw_catch()
201     {
202     try
203         {
204         throw_test_1("test");
205         BOOST_ASSERT(false);
206         }
207     catch(
208     boost::exception & x )
209         {
210         BOOST_TEST(*boost::get_error_info<test_5>(x)==std::string("test"));
211         }
212     catch(
213     ... )
214         {
215         BOOST_TEST(false);
216         }
217 
218     try
219         {
220         throw_test_2();
221         BOOST_ASSERT(false);
222         }
223     catch(
224     boost::exception & x )
225         {
226         BOOST_TEST(boost::get_error_info<test_6>(x));
227         }
228     catch(
229     ... )
230         {
231         BOOST_TEST(false);
232         }
233     }
234 
235 void
test_catch_add_info()236 test_catch_add_info()
237     {
238     try
239         {
240         throw_catch_add_file_name("test");
241         BOOST_TEST(false);
242         }
243     catch(
244     boost::exception & x )
245         {
246         BOOST_TEST(*boost::get_error_info<test_5>(x)==std::string("test"));
247         }
248     catch(
249     ... )
250         {
251         BOOST_TEST(false);
252         }
253     }
254 
255 void
test_add_tuple()256 test_add_tuple()
257     {
258     typedef boost::tuple<> tuple_test_;
259     typedef boost::tuple<test_1> tuple_test_1;
260     typedef boost::tuple<test_1,test_2> tuple_test_12;
261     typedef boost::tuple<test_1,test_2,test_3> tuple_test_123;
262     typedef boost::tuple<test_1,test_2,test_3,test_5> tuple_test_1235;
263     try
264         {
265         throw add_info(test_exception(),tuple_test_());
266         }
267     catch(
268     test_exception & )
269         {
270         }
271     catch(
272     ... )
273         {
274         BOOST_TEST(false);
275         }
276     try
277         {
278         throw add_info(test_exception(),tuple_test_1(42));
279         }
280     catch(
281     test_exception & x )
282         {
283         BOOST_TEST( *boost::get_error_info<test_1>(x)==42 );
284         }
285     catch(
286     ... )
287         {
288         BOOST_TEST(false);
289         }
290     try
291         {
292         throw add_info(test_exception(),tuple_test_12(42,42u));
293         }
294     catch(
295     test_exception & x )
296         {
297         BOOST_TEST( *boost::get_error_info<test_1>(x)==42 );
298         BOOST_TEST( *boost::get_error_info<test_2>(x)==42u );
299         }
300     catch(
301     ... )
302         {
303         BOOST_TEST(false);
304         }
305     try
306         {
307         throw add_info(test_exception(),tuple_test_123(42,42u,42.0f));
308         }
309     catch(
310     test_exception & x )
311         {
312         BOOST_TEST( *boost::get_error_info<test_1>(x)==42 );
313         BOOST_TEST( *boost::get_error_info<test_2>(x)==42u );
314         BOOST_TEST( *boost::get_error_info<test_3>(x)==42.0f );
315         }
316     catch(
317     ... )
318         {
319         BOOST_TEST(false);
320         }
321     try
322         {
323         throw add_info(test_exception(),tuple_test_1235(42,42u,42.0f,std::string("42")));
324         }
325     catch(
326     test_exception & x )
327         {
328         BOOST_TEST( *boost::get_error_info<test_1>(x)==42 );
329         BOOST_TEST( *boost::get_error_info<test_2>(x)==42u );
330         BOOST_TEST( *boost::get_error_info<test_3>(x)==42.0f );
331         BOOST_TEST( *boost::get_error_info<test_5>(x)=="42" );
332         }
333     catch(
334     ... )
335         {
336         BOOST_TEST(false);
337         }
338     }
339 
340 void
test_lifetime1()341 test_lifetime1()
342     {
343     int count=0;
344     try
345         {
346         throw add_info(test_exception(),test_7(user_data(count)));
347         }
348     catch(
349     boost::exception & x )
350         {
351         BOOST_TEST(count==1);
352         BOOST_TEST( boost::get_error_info<test_7>(x) );
353         }
354     catch(
355     ... )
356         {
357         BOOST_TEST(false);
358         }
359     BOOST_TEST(!count);
360     }
361 
362 void
test_lifetime2()363 test_lifetime2()
364     {
365     int count=0;
366         {
367         boost::exception_ptr ep;
368         test_exception e; add_info(e,test_7(user_data(count)));
369         ep=boost::copy_exception(e);
370         BOOST_TEST(count>0);
371         }
372     BOOST_TEST(!count);
373     }
374 
375 bool
is_const(int const *)376 is_const( int const * )
377     {
378     return true;
379     }
380 
381 bool
is_const(int *)382 is_const( int * )
383     {
384     return false;
385     }
386 
387 void
test_const()388 test_const()
389     {
390     test_exception e;
391     boost::exception const & c(e);
392     boost::exception & m(e);
393     BOOST_TEST(is_const(boost::get_error_info<test_1>(c)));
394     BOOST_TEST(!is_const(boost::get_error_info<test_1>(m)));
395     }
396 
397 int
main()398 main()
399     {
400     basic_test();
401     exception_safety_test();
402     test_empty();
403     test_basic_throw_catch();
404     test_catch_add_info();
405     test_add_tuple();
406     test_lifetime1();
407     test_lifetime2();
408     test_const();
409     return boost::report_errors();
410     }
411