/* * 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 facilities defined in the header * libs/iostreams/test/detail/operation_sequence.hpp * * File: libs/iostreams/test/operation_sequence_test.cpp * Date: Mon Dec 10 18:58:19 MST 2007 * Copyright: 2007-2008 CodeRage, LLC * Author: Jonathan Turkanis * Contact: turkanis at coderage dot com */ #include #include #include #include "detail/operation_sequence.hpp" using namespace std; using namespace boost; using namespace boost::iostreams::test; using boost::unit_test::test_suite; // Infrastructure for checking that operations are // executed in the correct order void operation_sequence_test() { // Test creating a duplicate operation { operation_sequence seq; operation op = seq.new_operation(1); BOOST_CHECK_THROW(seq.new_operation(1), runtime_error); } // Test reusing an operation id after first operation is destroyed { operation_sequence seq; seq.new_operation(1); BOOST_CHECK_NO_THROW(seq.new_operation(1)); } // Test creating operations with illegal error codes { operation_sequence seq; BOOST_CHECK_THROW(seq.new_operation(1, -100), runtime_error); BOOST_CHECK_THROW( seq.new_operation(1, BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR + 1), runtime_error ); } // Test two successful operations executed out of order { operation_sequence seq; operation op1 = seq.new_operation(1); operation op2 = seq.new_operation(2); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_NO_THROW(op2.execute()); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_NO_THROW(op1.execute()); BOOST_CHECK(seq.is_failure()); } // Test executing an operation twice without resetting the sequence { operation_sequence seq; operation op = seq.new_operation(1); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_NO_THROW(op.execute()); BOOST_CHECK(seq.is_success()); BOOST_CHECK_NO_THROW(op.execute()); BOOST_CHECK(seq.is_failure()); } // Test creating an operation after operation execution has commenced { operation_sequence seq; operation op1 = seq.new_operation(1); operation op2 = seq.new_operation(2); operation op3; BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_NO_THROW(op1.execute()); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_THROW(op3 = seq.new_operation(3), runtime_error); BOOST_CHECK_NO_THROW(op2.execute()); BOOST_CHECK(seq.is_success()); } // Test three successful operations with consecutive ids, executed in order { operation_sequence seq; operation op1 = seq.new_operation(1); operation op2 = seq.new_operation(2); operation op3 = seq.new_operation(3); // First pass BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op1.execute(); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op2.execute(); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op3.execute(); BOOST_CHECK(seq.is_success()); // Second pass seq.reset(); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op1.execute(); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op2.execute(); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op3.execute(); BOOST_CHECK(seq.is_success()); } // Test three successful operations with non-consecutive ids, // executed in order { operation_sequence seq; operation op2 = seq.new_operation(2); operation op3 = seq.new_operation(101); operation op1 = seq.new_operation(-43); // First pass BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op1.execute(); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op2.execute(); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op3.execute(); BOOST_CHECK(seq.is_success()); // Second pass seq.reset(); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op1.execute(); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op2.execute(); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op3.execute(); BOOST_CHECK(seq.is_success()); } // Test checking for success after one of three operations // has been destroyed { operation_sequence seq; operation op1 = seq.new_operation(1); operation op3 = seq.new_operation(3); { operation op2 = seq.new_operation(2); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op1.execute(); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op2.execute(); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op3.execute(); } BOOST_CHECK(seq.is_success()); } // Test executing an operation sequence twice, with one of the // operations replaced with a new operation with the same id // in the second pass { operation_sequence seq; operation op1 = seq.new_operation(1); operation op3 = seq.new_operation(3); // First pass { operation op2 = seq.new_operation(2); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op1.execute(); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op2.execute(); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op3.execute(); BOOST_CHECK(seq.is_success()); } // Second pass seq.reset(); { operation op2 = seq.new_operation(2); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op1.execute(); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op2.execute(); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); op3.execute(); BOOST_CHECK(seq.is_success()); } } // Test three operations executed in order, the first of which throws { operation_sequence seq; operation op1 = seq.new_operation(1, 1); operation op2 = seq.new_operation(2); operation op3 = seq.new_operation(3); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_THROW(op1.execute(), operation_error<1>); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_NO_THROW(op2.execute()); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_NO_THROW(op3.execute()); BOOST_CHECK(seq.is_success()); } // Test three operations executed in order, the second of which throws { operation_sequence seq; operation op1 = seq.new_operation(1); operation op2 = seq.new_operation(2, 2); operation op3 = seq.new_operation(3); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_NO_THROW(op1.execute()); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_THROW(op2.execute(), operation_error<2>); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_NO_THROW(op3.execute()); BOOST_CHECK(seq.is_success()); } // Test three operations executed in order, the third of which throws { operation_sequence seq; operation op1 = seq.new_operation(1); operation op2 = seq.new_operation(2); operation op3 = seq.new_operation(3, 3); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_NO_THROW(op1.execute()); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_NO_THROW(op2.execute()); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_THROW(op3.execute(), operation_error<3>); BOOST_CHECK(seq.is_success()); } // Test three operations executed in order, the first and // third of which throw { operation_sequence seq; operation op1 = seq.new_operation(1, 1); operation op2 = seq.new_operation(2); operation op3 = seq.new_operation(3, 3); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_THROW(op1.execute(), operation_error<1>); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_NO_THROW(op2.execute()); BOOST_CHECK(!seq.is_failure() && !seq.is_success()); BOOST_CHECK_THROW(op3.execute(), operation_error<3>); BOOST_CHECK(seq.is_success()); } } test_suite* init_unit_test_suite(int, char* []) { test_suite* test = BOOST_TEST_SUITE("execute test"); test->add(BOOST_TEST_CASE(&operation_sequence_test)); return test; }