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; |
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 | } |
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; |
52 | explicit operation(bool& executed) : executed_(executed) { } |
53 | 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; |
68 | explicit thrower(bool& executed) : executed_(executed) { } |
69 | 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; |
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 | } |
102 | private: |
103 | foreach_func& operator=(const foreach_func&); |
104 | int& count_; // Number of times operator() has been called |
105 | }; |
106 | |
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(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 | |
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 | |
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 | |
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 | |
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 | |
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 | |