| /* |
| * Distributed under the Boost Software License, Version 1.0.(See accompanying |
| * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) |
| * |
| * See http://www.boost.org/libs/iostreams for documentation. |
| * |
| * Tests the function templates boost::iostreams::detail::execute_all and |
| * boost::iostreams::detail::execute_foreach |
| * |
| * File: libs/iostreams/test/execute_test.cpp |
| * Date: Thu Dec 06 13:21:54 MST 2007 |
| * Copyright: 2007-2008 CodeRage, LLC |
| * Author: Jonathan Turkanis |
| * Contact: turkanis at coderage dot com |
| */ |
| |
| #include <boost/iostreams/detail/execute.hpp> |
| #include <boost/test/test_tools.hpp> |
| #include <boost/test/unit_test.hpp> |
| |
| using namespace std; |
| using namespace boost; |
| using namespace boost::iostreams; |
| using namespace boost::iostreams::detail; |
| using boost::unit_test::test_suite; |
| |
| // Function object that sets a boolean flag and returns a value |
| // specified at construction |
| template<typename Result> |
| class operation { |
| public: |
| typedef Result result_type; |
| explicit operation(Result r, bool& executed) |
| : r_(r), executed_(executed) |
| { } |
| Result operator()() const |
| { |
| executed_ = true; |
| return r_; |
| } |
| private: |
| operation& operator=(const operation&); |
| Result r_; |
| bool& executed_; |
| }; |
| |
| // Specialization for void return |
| template<> |
| class operation<void> { |
| public: |
| typedef void result_type; |
| explicit operation(bool& executed) : executed_(executed) { } |
| void operator()() const { executed_ = true; } |
| private: |
| operation& operator=(const operation&); |
| bool& executed_; |
| }; |
| |
| // Simple exception class with error code built in to type |
| template<int Code> |
| struct error { }; |
| |
| // Function object that sets a boolean flag and throws an exception |
| template<int Code> |
| class thrower { |
| public: |
| typedef void result_type; |
| explicit thrower(bool& executed) : executed_(executed) { } |
| void operator()() const |
| { |
| executed_ = true; |
| throw error<Code>(); |
| } |
| private: |
| thrower& operator=(const thrower&); |
| bool& executed_; |
| }; |
| |
| // Function object for use by foreach_test |
| class foreach_func { |
| public: |
| typedef void result_type; |
| explicit foreach_func(int& count) : count_(count) { } |
| void operator()(int x) const |
| { |
| ++count_; |
| switch (x) { |
| case 0: throw error<0>(); |
| case 1: throw error<1>(); |
| case 2: throw error<2>(); |
| case 3: throw error<3>(); |
| case 4: throw error<4>(); |
| case 5: throw error<5>(); |
| case 6: throw error<6>(); |
| case 7: throw error<7>(); |
| case 8: throw error<8>(); |
| case 9: throw error<9>(); |
| default: |
| break; |
| } |
| } |
| private: |
| foreach_func& operator=(const foreach_func&); |
| int& count_; // Number of times operator() has been called |
| }; |
| |
| void success_test() |
| { |
| // Test returning an int |
| { |
| bool executed = false; |
| BOOST_CHECK(execute_all(operation<int>(9, executed)) == 9); |
| BOOST_CHECK(executed); |
| } |
| |
| // Test returning void |
| { |
| bool executed = false; |
| execute_all(operation<void>(executed)); |
| BOOST_CHECK(executed); |
| } |
| |
| // Test returning an int with one cleanup operation |
| { |
| bool executed = false, cleaned_up = false; |
| BOOST_CHECK( |
| execute_all( |
| operation<int>(9, executed), |
| operation<void>(cleaned_up) |
| ) == 9 |
| ); |
| BOOST_CHECK(executed && cleaned_up); |
| } |
| |
| // Test returning void with one cleanup operation |
| { |
| bool executed = false, cleaned_up = false; |
| execute_all( |
| operation<void>(executed), |
| operation<void>(cleaned_up) |
| ); |
| BOOST_CHECK(executed && cleaned_up); |
| } |
| |
| // Test returning an int with two cleanup operations |
| { |
| bool executed = false, cleaned_up1 = false, cleaned_up2 = false; |
| BOOST_CHECK( |
| execute_all( |
| operation<int>(9, executed), |
| operation<void>(cleaned_up1), |
| operation<void>(cleaned_up2) |
| ) == 9 |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2); |
| } |
| |
| // Test returning void with two cleanup operations |
| { |
| bool executed = false, cleaned_up1 = false, cleaned_up2 = false; |
| execute_all( |
| operation<void>(executed), |
| operation<void>(cleaned_up1), |
| operation<void>(cleaned_up2) |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2); |
| } |
| |
| // Test returning an int with three cleanup operations |
| { |
| bool executed = false, cleaned_up1 = false, |
| cleaned_up2 = false, cleaned_up3 = false; |
| BOOST_CHECK( |
| execute_all( |
| operation<int>(9, executed), |
| operation<void>(cleaned_up1), |
| operation<void>(cleaned_up2), |
| operation<void>(cleaned_up3) |
| ) == 9 |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); |
| } |
| |
| // Test returning void with three cleanup operations |
| { |
| bool executed = false, cleaned_up1 = false, |
| cleaned_up2 = false, cleaned_up3 = false; |
| execute_all( |
| operation<void>(executed), |
| operation<void>(cleaned_up1), |
| operation<void>(cleaned_up2), |
| operation<void>(cleaned_up3) |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); |
| } |
| } |
| |
| void operation_throws_test() |
| { |
| // Test primary operation throwing with no cleanup operations |
| { |
| bool executed = false; |
| BOOST_CHECK_THROW( |
| execute_all(thrower<0>(executed)), |
| error<0> |
| ); |
| BOOST_CHECK(executed); |
| } |
| |
| // Test primary operation throwing with one cleanup operation |
| { |
| bool executed = false, cleaned_up = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| thrower<0>(executed), |
| operation<void>(cleaned_up) |
| ), |
| error<0> |
| ); |
| BOOST_CHECK(executed && cleaned_up); |
| } |
| |
| // Test primary operation throwing with two cleanup operations |
| { |
| bool executed = false, cleaned_up1 = false, cleaned_up2 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| thrower<0>(executed), |
| operation<void>(cleaned_up1), |
| operation<void>(cleaned_up2) |
| ), |
| error<0> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2); |
| } |
| |
| // Test primary operation throwing with three cleanup operations |
| { |
| bool executed = false, cleaned_up1 = false, |
| cleaned_up2 = false, cleaned_up3 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| thrower<0>(executed), |
| operation<void>(cleaned_up1), |
| operation<void>(cleaned_up2), |
| operation<void>(cleaned_up3) |
| ), |
| error<0> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); |
| } |
| } |
| |
| void cleanup_throws_test() |
| { |
| // Test single cleanup operation that throws |
| { |
| bool executed = false, cleaned_up = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| operation<void>(executed), |
| thrower<1>(cleaned_up) |
| ), |
| error<1> |
| ); |
| BOOST_CHECK(executed && cleaned_up); |
| } |
| |
| // Test fist of two cleanup operations throwing |
| { |
| bool executed = false, cleaned_up1 = false, cleaned_up2 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| operation<void>(executed), |
| thrower<1>(cleaned_up1), |
| operation<void>(cleaned_up2) |
| ), |
| error<1> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2); |
| } |
| |
| // Test second of two cleanup operations throwing |
| { |
| bool executed = false, cleaned_up1 = false, cleaned_up2 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| operation<void>(executed), |
| operation<void>(cleaned_up1), |
| thrower<2>(cleaned_up2) |
| ), |
| error<2> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2); |
| } |
| |
| // Test first of three cleanup operations throwing |
| { |
| bool executed = false, cleaned_up1 = false, |
| cleaned_up2 = false, cleaned_up3 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| operation<void>(executed), |
| thrower<1>(cleaned_up1), |
| operation<void>(cleaned_up2), |
| operation<void>(cleaned_up3) |
| ), |
| error<1> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); |
| } |
| |
| // Test second of three cleanup operations throwing |
| { |
| bool executed = false, cleaned_up1 = false, |
| cleaned_up2 = false, cleaned_up3 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| operation<void>(executed), |
| operation<void>(cleaned_up1), |
| thrower<2>(cleaned_up2), |
| operation<void>(cleaned_up3) |
| ), |
| error<2> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); |
| } |
| |
| // Test third of three cleanup operations throwing |
| { |
| bool executed = false, cleaned_up1 = false, |
| cleaned_up2 = false, cleaned_up3 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| operation<void>(executed), |
| operation<void>(cleaned_up1), |
| operation<void>(cleaned_up2), |
| thrower<3>(cleaned_up3) |
| ), |
| error<3> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); |
| } |
| } |
| |
| void multiple_exceptions_test() |
| { |
| // Test primary operation and cleanup operation throwing |
| { |
| bool executed = false, cleaned_up = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| thrower<0>(executed), |
| thrower<1>(cleaned_up) |
| ), |
| error<0> |
| ); |
| BOOST_CHECK(executed && cleaned_up); |
| } |
| |
| // Test primary operation and first of two cleanup operations throwing |
| { |
| bool executed = false, cleaned_up1 = false, cleaned_up2 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| thrower<0>(executed), |
| thrower<1>(cleaned_up1), |
| operation<void>(cleaned_up2) |
| ), |
| error<0> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2); |
| } |
| |
| // Test primary operation and second of two cleanup operations throwing |
| { |
| bool executed = false, cleaned_up1 = false, cleaned_up2 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| thrower<0>(executed), |
| operation<void>(cleaned_up1), |
| thrower<2>(cleaned_up2) |
| ), |
| error<0> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2); |
| } |
| |
| // Test two cleanup operations throwing |
| { |
| bool executed = false, cleaned_up1 = false, cleaned_up2 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| operation<void>(executed), |
| thrower<1>(cleaned_up1), |
| thrower<2>(cleaned_up2) |
| ), |
| error<1> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2); |
| } |
| |
| // Test primary operation and first of three cleanup operations throwing |
| { |
| bool executed = false, cleaned_up1 = false, |
| cleaned_up2 = false, cleaned_up3 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| thrower<0>(executed), |
| thrower<1>(cleaned_up1), |
| operation<void>(cleaned_up2), |
| operation<void>(cleaned_up3) |
| ), |
| error<0> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); |
| } |
| |
| // Test primary operation and second of three cleanup operations throwing |
| { |
| bool executed = false, cleaned_up1 = false, |
| cleaned_up2 = false, cleaned_up3 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| thrower<0>(executed), |
| operation<void>(cleaned_up1), |
| thrower<2>(cleaned_up2), |
| operation<void>(cleaned_up3) |
| ), |
| error<0> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); |
| } |
| |
| // Test primary operation and third of three cleanup operations throwing |
| { |
| bool executed = false, cleaned_up1 = false, |
| cleaned_up2 = false, cleaned_up3 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| thrower<0>(executed), |
| operation<void>(cleaned_up1), |
| operation<void>(cleaned_up2), |
| thrower<3>(cleaned_up3) |
| ), |
| error<0> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); |
| } |
| |
| // Test first and second of three cleanup operations throwing |
| { |
| bool executed = false, cleaned_up1 = false, |
| cleaned_up2 = false, cleaned_up3 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| operation<void>(executed), |
| thrower<1>(cleaned_up1), |
| thrower<2>(cleaned_up2), |
| operation<void>(cleaned_up3) |
| ), |
| error<1> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); |
| } |
| |
| // Test first and third of three cleanup operations throwing |
| { |
| bool executed = false, cleaned_up1 = false, |
| cleaned_up2 = false, cleaned_up3 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| operation<void>(executed), |
| thrower<1>(cleaned_up1), |
| operation<void>(cleaned_up2), |
| thrower<3>(cleaned_up3) |
| ), |
| error<1> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); |
| } |
| |
| // Test second and third of three cleanup operations throwing |
| { |
| bool executed = false, cleaned_up1 = false, |
| cleaned_up2 = false, cleaned_up3 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| operation<void>(executed), |
| operation<void>(cleaned_up1), |
| thrower<2>(cleaned_up2), |
| thrower<3>(cleaned_up3) |
| ), |
| error<2> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); |
| } |
| |
| // Test three cleanup operations throwing |
| { |
| bool executed = false, cleaned_up1 = false, |
| cleaned_up2 = false, cleaned_up3 = false; |
| BOOST_CHECK_THROW( |
| execute_all( |
| operation<void>(executed), |
| thrower<1>(cleaned_up1), |
| thrower<2>(cleaned_up2), |
| thrower<3>(cleaned_up3) |
| ), |
| error<1> |
| ); |
| BOOST_CHECK(executed && cleaned_up1 && cleaned_up2 && cleaned_up3); |
| } |
| } |
| |
| #define ARRAY_SIZE(ar) (sizeof(ar) / sizeof(ar[0])) |
| |
| void foreach_test() |
| { |
| // Test case where neither of two operations throws |
| { |
| int count = 0; |
| int seq[] = {-1, -1}; |
| BOOST_CHECK_NO_THROW( |
| execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)) |
| ); |
| BOOST_CHECK(count == ARRAY_SIZE(seq)); |
| } |
| |
| // Test case where first of two operations throws |
| { |
| int count = 0; |
| int seq[] = {0, -1}; |
| BOOST_CHECK_THROW( |
| execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), |
| error<0> |
| ); |
| BOOST_CHECK(count == ARRAY_SIZE(seq)); |
| } |
| |
| // Test case where second of two operations throws |
| { |
| int count = 0; |
| int seq[] = {-1, 1}; |
| BOOST_CHECK_THROW( |
| execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), |
| error<1> |
| ); |
| BOOST_CHECK(count == ARRAY_SIZE(seq)); |
| } |
| |
| // Test case where both of two operations throw |
| { |
| int count = 0; |
| int seq[] = {0, 1}; |
| BOOST_CHECK_THROW( |
| execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), |
| error<0> |
| ); |
| BOOST_CHECK(count == ARRAY_SIZE(seq)); |
| } |
| |
| // Test case where none of three operations throws |
| { |
| int count = 0; |
| int seq[] = {-1, -1, -1}; |
| BOOST_CHECK_NO_THROW( |
| execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)) |
| ); |
| BOOST_CHECK(count == ARRAY_SIZE(seq)); |
| } |
| |
| // Test case where first of three operations throw |
| { |
| int count = 0; |
| int seq[] = {0, -1, -1}; |
| BOOST_CHECK_THROW( |
| execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), |
| error<0> |
| ); |
| BOOST_CHECK(count == ARRAY_SIZE(seq)); |
| } |
| |
| // Test case where second of three operations throw |
| { |
| int count = 0; |
| int seq[] = {-1, 1, -1}; |
| BOOST_CHECK_THROW( |
| execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), |
| error<1> |
| ); |
| BOOST_CHECK(count == ARRAY_SIZE(seq)); |
| } |
| |
| // Test case where third of three operations throw |
| { |
| int count = 0; |
| int seq[] = {-1, -1, 2}; |
| BOOST_CHECK_THROW( |
| execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), |
| error<2> |
| ); |
| BOOST_CHECK(count == ARRAY_SIZE(seq)); |
| } |
| |
| // Test case where first and second of three operations throw |
| { |
| int count = 0; |
| int seq[] = {0, 1, -1}; |
| BOOST_CHECK_THROW( |
| execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), |
| error<0> |
| ); |
| BOOST_CHECK(count == ARRAY_SIZE(seq)); |
| } |
| |
| // Test case where first and third of three operations throw |
| { |
| int count = 0; |
| int seq[] = {0, -1, 2}; |
| BOOST_CHECK_THROW( |
| execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), |
| error<0> |
| ); |
| BOOST_CHECK(count == ARRAY_SIZE(seq)); |
| } |
| |
| // Test case where second and third of three operations throw |
| { |
| int count = 0; |
| int seq[] = {-1, 1, 2}; |
| BOOST_CHECK_THROW( |
| execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), |
| error<1> |
| ); |
| BOOST_CHECK(count == ARRAY_SIZE(seq)); |
| } |
| |
| // Test case where three of three operations throw |
| { |
| int count = 0; |
| int seq[] = {0, 1, 2}; |
| BOOST_CHECK_THROW( |
| execute_foreach(seq, seq + ARRAY_SIZE(seq), foreach_func(count)), |
| error<0> |
| ); |
| BOOST_CHECK(count == ARRAY_SIZE(seq)); |
| } |
| } |
| |
| test_suite* init_unit_test_suite(int, char* []) |
| { |
| test_suite* test = BOOST_TEST_SUITE("execute test"); |
| test->add(BOOST_TEST_CASE(&success_test)); |
| test->add(BOOST_TEST_CASE(&operation_throws_test)); |
| test->add(BOOST_TEST_CASE(&cleanup_throws_test)); |
| test->add(BOOST_TEST_CASE(&multiple_exceptions_test)); |
| test->add(BOOST_TEST_CASE(&foreach_test)); |
| return test; |
| } |