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
21using namespace std;
22using namespace boost;
23using namespace boost::iostreams;
24using namespace boost::iostreams::detail;
25using boost::unit_test::test_suite;
26
27// Function object that sets a boolean flag and returns a value
28// specified at construction
29template<typename Result>
30class operation {
31public:
32 typedef Result result_type;
33 explicit operation(Result r, bool& executed)
34 : r_(r), executed_(executed)
35 { }
36 Result operator()() const
37 {
38 executed_ = true;
39 return r_;
40 }
41private:
42 operation& operator=(const operation&);
43 Result r_;
44 bool& executed_;
45};
46
47// Specialization for void return
48template<>
49class operation<void> {
50public:
51 typedef void result_type;
52 explicit operation(bool& executed) : executed_(executed) { }
53 void operator()() const { executed_ = true; }
54private:
55 operation& operator=(const operation&);
56 bool& executed_;
57};
58
59// Simple exception class with error code built in to type
60template<int Code>
61struct error { };
62
63// Function object that sets a boolean flag and throws an exception
64template<int Code>
65class thrower {
66public:
67 typedef void result_type;
68 explicit thrower(bool& executed) : executed_(executed) { }
69 void operator()() const
70 {
71 executed_ = true;
72 throw error<Code>();
73 }
74private:
75 thrower& operator=(const thrower&);
76 bool& executed_;
77};
78
79// Function object for use by foreach_test
80class foreach_func {
81public:
82 typedef void result_type;
83 explicit foreach_func(int& count) : count_(count) { }
84 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 }
102private:
103 foreach_func& operator=(const foreach_func&);
104 int& count_; // Number of times operator() has been called
105};
106
107void 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(op: 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 op: operation<void>(executed),
140 c0: 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 op: operation<void>(executed),
163 c0: operation<void>(cleaned_up1),
164 c1: 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 op: operation<void>(executed),
190 c0: operation<void>(cleaned_up1),
191 c1: operation<void>(cleaned_up2),
192 c2: operation<void>(cleaned_up3)
193 );
194 BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3);
195 }
196}
197
198void 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
254void 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
346void 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
518void 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
651test_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

source code of boost/libs/iostreams/test/execute_test.cpp