1 /*
2  * Distributed under the Boost Software License, Version 1.0.(See accompanying
3  * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
4  *
5  * See http://www.boost.org/libs/iostreams for documentation.
6  *
7  * Tests the function templates boost::iostreams::detail::execute_all and
8  * boost::iostreams::detail::execute_foreach
9  *
10  * File:        libs/iostreams/test/execute_test.cpp
11  * Date:        Thu Dec 06 13:21:54 MST 2007
12  * Copyright:   2007-2008 CodeRage, LLC
13  * Author:      Jonathan Turkanis
14  * Contact:     turkanis at coderage dot com
15  */
16 
17 #include <boost/iostreams/detail/execute.hpp>
18 #include <boost/test/test_tools.hpp>
19 #include <boost/test/unit_test.hpp>
20 
21 using namespace std;
22 using namespace boost;
23 using namespace boost::iostreams;
24 using namespace boost::iostreams::detail;
25 using boost::unit_test::test_suite;
26 
27 // Function object that sets a boolean flag and returns a value
28 // specified at construction
29 template<typename Result>
30 class operation {
31 public:
32     typedef Result result_type;
operation(Result r,bool & executed)33     explicit operation(Result r, bool& executed)
34         : r_(r), executed_(executed)
35         { }
operator ()() const36     Result operator()() const
37     {
38         executed_ = true;
39         return r_;
40     }
41 private:
42     operation& operator=(const operation&);
43     Result  r_;
44     bool&   executed_;
45 };
46 
47 // Specialization for void return
48 template<>
49 class operation<void> {
50 public:
51     typedef void result_type;
operation(bool & executed)52     explicit operation(bool& executed) : executed_(executed) { }
operator ()() const53     void operator()() const { executed_ = true; }
54 private:
55     operation& operator=(const operation&);
56     bool& executed_;
57 };
58 
59 // Simple exception class with error code built in to type
60 template<int Code>
61 struct error { };
62 
63 // Function object that sets a boolean flag and throws an exception
64 template<int Code>
65 class thrower {
66 public:
67     typedef void result_type;
thrower(bool & executed)68     explicit thrower(bool& executed) : executed_(executed) { }
operator ()() const69     void operator()() const
70     {
71         executed_ = true;
72         throw error<Code>();
73     }
74 private:
75     thrower& operator=(const thrower&);
76     bool& executed_;
77 };
78 
79 // Function object for use by foreach_test
80 class foreach_func {
81 public:
82     typedef void result_type;
foreach_func(int & count)83     explicit foreach_func(int& count) : count_(count) { }
operator ()(int x) const84     void operator()(int x) const
85     {
86         ++count_;
87         switch (x) {
88         case 0: throw error<0>();
89         case 1: throw error<1>();
90         case 2: throw error<2>();
91         case 3: throw error<3>();
92         case 4: throw error<4>();
93         case 5: throw error<5>();
94         case 6: throw error<6>();
95         case 7: throw error<7>();
96         case 8: throw error<8>();
97         case 9: throw error<9>();
98         default:
99             break;
100         }
101     }
102 private:
103     foreach_func& operator=(const foreach_func&);
104     int&  count_; // Number of times operator() has been called
105 };
106 
success_test()107 void success_test()
108 {
109     // Test returning an int
110     {
111         bool executed = false;
112         BOOST_CHECK(execute_all(operation<int>(9, executed)) == 9);
113         BOOST_CHECK(executed);
114     }
115 
116     // Test returning void
117     {
118         bool executed = false;
119         execute_all(operation<void>(executed));
120         BOOST_CHECK(executed);
121     }
122 
123     // Test returning an int with one cleanup operation
124     {
125         bool executed = false, cleaned_up = false;
126         BOOST_CHECK(
127             execute_all(
128                 operation<int>(9, executed),
129                 operation<void>(cleaned_up)
130             ) == 9
131         );
132         BOOST_CHECK(executed && cleaned_up);
133     }
134 
135     // Test returning void with one cleanup operation
136     {
137         bool executed = false, cleaned_up = false;
138         execute_all(
139             operation<void>(executed),
140             operation<void>(cleaned_up)
141         );
142         BOOST_CHECK(executed && cleaned_up);
143     }
144 
145     // Test returning an int with two cleanup operations
146     {
147         bool executed = false, cleaned_up1 = false, cleaned_up2 = false;
148         BOOST_CHECK(
149             execute_all(
150                 operation<int>(9, executed),
151                 operation<void>(cleaned_up1),
152                 operation<void>(cleaned_up2)
153             ) == 9
154         );
155         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2);
156     }
157 
158     // Test returning void with two cleanup operations
159     {
160         bool executed = false, cleaned_up1 = false, cleaned_up2 = false;
161         execute_all(
162             operation<void>(executed),
163             operation<void>(cleaned_up1),
164             operation<void>(cleaned_up2)
165         );
166         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2);
167     }
168 
169     // Test returning an int with three cleanup operations
170     {
171         bool executed = false, cleaned_up1 = false,
172              cleaned_up2 = false, cleaned_up3 = false;
173         BOOST_CHECK(
174             execute_all(
175                 operation<int>(9, executed),
176                 operation<void>(cleaned_up1),
177                 operation<void>(cleaned_up2),
178                 operation<void>(cleaned_up3)
179             ) == 9
180         );
181         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
182     }
183 
184     // Test returning void with three cleanup operations
185     {
186         bool executed = false, cleaned_up1 = false,
187              cleaned_up2 = false, cleaned_up3 = false;
188         execute_all(
189             operation<void>(executed),
190             operation<void>(cleaned_up1),
191             operation<void>(cleaned_up2),
192             operation<void>(cleaned_up3)
193         );
194         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
195     }
196 }
197 
operation_throws_test()198 void operation_throws_test()
199 {
200     // Test primary operation throwing with no cleanup operations
201     {
202         bool executed = false;
203         BOOST_CHECK_THROW(
204             execute_all(thrower<0>(executed)),
205             error<0>
206         );
207         BOOST_CHECK(executed);
208     }
209 
210     // Test primary operation throwing with one cleanup operation
211     {
212         bool executed = false, cleaned_up = false;
213         BOOST_CHECK_THROW(
214             execute_all(
215                 thrower<0>(executed),
216                 operation<void>(cleaned_up)
217             ),
218             error<0>
219         );
220         BOOST_CHECK(executed && cleaned_up);
221     }
222 
223     // Test primary operation throwing with two cleanup operations
224     {
225         bool executed = false, cleaned_up1 = false, cleaned_up2 = false;
226         BOOST_CHECK_THROW(
227             execute_all(
228                 thrower<0>(executed),
229                 operation<void>(cleaned_up1),
230                 operation<void>(cleaned_up2)
231             ),
232             error<0>
233         );
234         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2);
235     }
236 
237     // Test primary operation throwing with three cleanup operations
238     {
239         bool executed = false, cleaned_up1 = false,
240              cleaned_up2 = false, cleaned_up3 = false;
241         BOOST_CHECK_THROW(
242             execute_all(
243                 thrower<0>(executed),
244                 operation<void>(cleaned_up1),
245                 operation<void>(cleaned_up2),
246                 operation<void>(cleaned_up3)
247             ),
248             error<0>
249         );
250         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
251     }
252 }
253 
cleanup_throws_test()254 void cleanup_throws_test()
255 {
256     // Test single cleanup operation that throws
257     {
258         bool executed = false, cleaned_up = false;
259         BOOST_CHECK_THROW(
260             execute_all(
261                 operation<void>(executed),
262                 thrower<1>(cleaned_up)
263             ),
264             error<1>
265         );
266         BOOST_CHECK(executed && cleaned_up);
267     }
268 
269     // Test fist of two cleanup operations throwing
270     {
271         bool executed = false, cleaned_up1 = false, cleaned_up2 = false;
272         BOOST_CHECK_THROW(
273             execute_all(
274                 operation<void>(executed),
275                 thrower<1>(cleaned_up1),
276                 operation<void>(cleaned_up2)
277             ),
278             error<1>
279         );
280         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2);
281     }
282 
283     // Test second of two cleanup operations throwing
284     {
285         bool executed = false, cleaned_up1 = false, cleaned_up2 = false;
286         BOOST_CHECK_THROW(
287             execute_all(
288                 operation<void>(executed),
289                 operation<void>(cleaned_up1),
290                 thrower<2>(cleaned_up2)
291             ),
292             error<2>
293         );
294         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2);
295     }
296 
297     // Test first of three cleanup operations throwing
298     {
299         bool executed = false, cleaned_up1 = false,
300              cleaned_up2 = false, cleaned_up3 = false;
301         BOOST_CHECK_THROW(
302             execute_all(
303                 operation<void>(executed),
304                 thrower<1>(cleaned_up1),
305                 operation<void>(cleaned_up2),
306                 operation<void>(cleaned_up3)
307             ),
308             error<1>
309         );
310         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
311     }
312 
313     // Test second of three cleanup operations throwing
314     {
315         bool executed = false, cleaned_up1 = false,
316              cleaned_up2 = false, cleaned_up3 = false;
317         BOOST_CHECK_THROW(
318             execute_all(
319                 operation<void>(executed),
320                 operation<void>(cleaned_up1),
321                 thrower<2>(cleaned_up2),
322                 operation<void>(cleaned_up3)
323             ),
324             error<2>
325         );
326         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
327     }
328 
329     // Test third of three cleanup operations throwing
330     {
331         bool executed = false, cleaned_up1 = false,
332              cleaned_up2 = false, cleaned_up3 = false;
333         BOOST_CHECK_THROW(
334             execute_all(
335                 operation<void>(executed),
336                 operation<void>(cleaned_up1),
337                 operation<void>(cleaned_up2),
338                 thrower<3>(cleaned_up3)
339             ),
340             error<3>
341         );
342         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
343     }
344 }
345 
multiple_exceptions_test()346 void multiple_exceptions_test()
347 {
348     // Test primary operation and cleanup operation throwing
349     {
350         bool executed = false, cleaned_up = false;
351         BOOST_CHECK_THROW(
352             execute_all(
353                 thrower<0>(executed),
354                 thrower<1>(cleaned_up)
355             ),
356             error<0>
357         );
358         BOOST_CHECK(executed && cleaned_up);
359     }
360 
361     // Test primary operation and first of two cleanup operations throwing
362     {
363         bool executed = false, cleaned_up1 = false, cleaned_up2 = false;
364         BOOST_CHECK_THROW(
365             execute_all(
366                 thrower<0>(executed),
367                 thrower<1>(cleaned_up1),
368                 operation<void>(cleaned_up2)
369             ),
370             error<0>
371         );
372         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2);
373     }
374 
375     // Test primary operation and second of two cleanup operations throwing
376     {
377         bool executed = false, cleaned_up1 = false, cleaned_up2 = false;
378         BOOST_CHECK_THROW(
379             execute_all(
380                 thrower<0>(executed),
381                 operation<void>(cleaned_up1),
382                 thrower<2>(cleaned_up2)
383             ),
384             error<0>
385         );
386         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2);
387     }
388 
389     // Test two cleanup operations throwing
390     {
391         bool executed = false, cleaned_up1 = false, cleaned_up2 = false;
392         BOOST_CHECK_THROW(
393             execute_all(
394                 operation<void>(executed),
395                 thrower<1>(cleaned_up1),
396                 thrower<2>(cleaned_up2)
397             ),
398             error<1>
399         );
400         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2);
401     }
402 
403     // Test primary operation and first of three cleanup operations throwing
404     {
405         bool executed = false, cleaned_up1 = false,
406              cleaned_up2 = false, cleaned_up3 = false;
407         BOOST_CHECK_THROW(
408             execute_all(
409                 thrower<0>(executed),
410                 thrower<1>(cleaned_up1),
411                 operation<void>(cleaned_up2),
412                 operation<void>(cleaned_up3)
413             ),
414             error<0>
415         );
416         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
417     }
418 
419     // Test primary operation and second of three cleanup operations throwing
420     {
421         bool executed = false, cleaned_up1 = false,
422              cleaned_up2 = false, cleaned_up3 = false;
423         BOOST_CHECK_THROW(
424             execute_all(
425                 thrower<0>(executed),
426                 operation<void>(cleaned_up1),
427                 thrower<2>(cleaned_up2),
428                 operation<void>(cleaned_up3)
429             ),
430             error<0>
431         );
432         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
433     }
434 
435     // Test primary operation and third of three cleanup operations throwing
436     {
437         bool executed = false, cleaned_up1 = false,
438              cleaned_up2 = false, cleaned_up3 = false;
439         BOOST_CHECK_THROW(
440             execute_all(
441                 thrower<0>(executed),
442                 operation<void>(cleaned_up1),
443                 operation<void>(cleaned_up2),
444                 thrower<3>(cleaned_up3)
445             ),
446             error<0>
447         );
448         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
449     }
450 
451     // Test first and second of three cleanup operations throwing
452     {
453         bool executed = false, cleaned_up1 = false,
454              cleaned_up2 = false, cleaned_up3 = false;
455         BOOST_CHECK_THROW(
456             execute_all(
457                 operation<void>(executed),
458                 thrower<1>(cleaned_up1),
459                 thrower<2>(cleaned_up2),
460                 operation<void>(cleaned_up3)
461             ),
462             error<1>
463         );
464         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
465     }
466 
467     // Test first and third of three cleanup operations throwing
468     {
469         bool executed = false, cleaned_up1 = false,
470              cleaned_up2 = false, cleaned_up3 = false;
471         BOOST_CHECK_THROW(
472             execute_all(
473                 operation<void>(executed),
474                 thrower<1>(cleaned_up1),
475                 operation<void>(cleaned_up2),
476                 thrower<3>(cleaned_up3)
477             ),
478             error<1>
479         );
480         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
481     }
482 
483     // Test second and third of three cleanup operations throwing
484     {
485         bool executed = false, cleaned_up1 = false,
486              cleaned_up2 = false, cleaned_up3 = false;
487         BOOST_CHECK_THROW(
488             execute_all(
489                 operation<void>(executed),
490                 operation<void>(cleaned_up1),
491                 thrower<2>(cleaned_up2),
492                 thrower<3>(cleaned_up3)
493             ),
494             error<2>
495         );
496         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
497     }
498 
499     // Test three cleanup operations throwing
500     {
501         bool executed = false, cleaned_up1 = false,
502              cleaned_up2 = false, cleaned_up3 = false;
503         BOOST_CHECK_THROW(
504             execute_all(
505                 operation<void>(executed),
506                 thrower<1>(cleaned_up1),
507                 thrower<2>(cleaned_up2),
508                 thrower<3>(cleaned_up3)
509             ),
510             error<1>
511         );
512         BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
513     }
514 }
515 
516 #define ARRAY_SIZE(ar) (sizeof(ar) / sizeof(ar[0]))
517 
foreach_test()518 void foreach_test()
519 {
520     // Test case where neither of two operations throws
521     {
522         int count = 0;
523         int seq[] = {-1, -1};
524         BOOST_CHECK_NO_THROW(
525             execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count))
526         );
527         BOOST_CHECK(count == ARRAY_SIZE(seq));
528     }
529 
530     // Test case where first of two operations throws
531     {
532         int count = 0;
533         int seq[] = {0, -1};
534         BOOST_CHECK_THROW(
535             execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
536             error<0>
537         );
538         BOOST_CHECK(count == ARRAY_SIZE(seq));
539     }
540 
541     // Test case where second of two operations throws
542     {
543         int count = 0;
544         int seq[] = {-1, 1};
545         BOOST_CHECK_THROW(
546             execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
547             error<1>
548         );
549         BOOST_CHECK(count == ARRAY_SIZE(seq));
550     }
551 
552     // Test case where both of two operations throw
553     {
554         int count = 0;
555         int seq[] = {0, 1};
556         BOOST_CHECK_THROW(
557             execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
558             error<0>
559         );
560         BOOST_CHECK(count == ARRAY_SIZE(seq));
561     }
562 
563     // Test case where none of three operations throws
564     {
565         int count = 0;
566         int seq[] = {-1, -1, -1};
567         BOOST_CHECK_NO_THROW(
568             execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count))
569         );
570         BOOST_CHECK(count == ARRAY_SIZE(seq));
571     }
572 
573     // Test case where first of three operations throw
574     {
575         int count = 0;
576         int seq[] = {0, -1, -1};
577         BOOST_CHECK_THROW(
578             execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
579             error<0>
580         );
581         BOOST_CHECK(count == ARRAY_SIZE(seq));
582     }
583 
584     // Test case where second of three operations throw
585     {
586         int count = 0;
587         int seq[] = {-1, 1, -1};
588         BOOST_CHECK_THROW(
589             execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
590             error<1>
591         );
592         BOOST_CHECK(count == ARRAY_SIZE(seq));
593     }
594 
595     // Test case where third of three operations throw
596     {
597         int count = 0;
598         int seq[] = {-1, -1, 2};
599         BOOST_CHECK_THROW(
600             execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
601             error<2>
602         );
603         BOOST_CHECK(count == ARRAY_SIZE(seq));
604     }
605 
606     // Test case where first and second of three operations throw
607     {
608         int count = 0;
609         int seq[] = {0, 1, -1};
610         BOOST_CHECK_THROW(
611             execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
612             error<0>
613         );
614         BOOST_CHECK(count == ARRAY_SIZE(seq));
615     }
616 
617     // Test case where first and third of three operations throw
618     {
619         int count = 0;
620         int seq[] = {0, -1, 2};
621         BOOST_CHECK_THROW(
622             execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
623             error<0>
624         );
625         BOOST_CHECK(count == ARRAY_SIZE(seq));
626     }
627 
628     // Test case where second and third of three operations throw
629     {
630         int count = 0;
631         int seq[] = {-1, 1, 2};
632         BOOST_CHECK_THROW(
633             execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
634             error<1>
635         );
636         BOOST_CHECK(count == ARRAY_SIZE(seq));
637     }
638 
639     // Test case where three of three operations throw
640     {
641         int count = 0;
642         int seq[] = {0, 1, 2};
643         BOOST_CHECK_THROW(
644             execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)),
645             error<0>
646         );
647         BOOST_CHECK(count == ARRAY_SIZE(seq));
648     }
649 }
650 
init_unit_test_suite(int,char * [])651 test_suite* init_unit_test_suite(int, char* [])
652 {
653     test_suite* test = BOOST_TEST_SUITE("execute test");
654     test->add(BOOST_TEST_CASE(&success_test));
655     test->add(BOOST_TEST_CASE(&operation_throws_test));
656     test->add(BOOST_TEST_CASE(&cleanup_throws_test));
657     test->add(BOOST_TEST_CASE(&multiple_exceptions_test));
658     test->add(BOOST_TEST_CASE(&foreach_test));
659     return test;
660 }
661