123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- /*
- *
- * 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.
- *
- * Defines the classes operation_sequence and operation, in the namespace
- * boost::iostreams::test, for verifying that all elements of a sequence of
- * operations are executed, and that they are executed in the correct order.
- *
- * File: libs/iostreams/test/detail/operation_sequence.hpp
- * Date: Mon Dec 10 18:58:19 MST 2007
- * Copyright: 2007-2008 CodeRage, LLC
- * Author: Jonathan Turkanis
- * Contact: turkanis at coderage dot com
- */
- #ifndef BOOST_IOSTREAMS_TEST_OPERATION_SEQUENCE_HPP_INCLUDED
- #define BOOST_IOSTREAMS_TEST_OPERATION_SEQUENCE_HPP_INCLUDED
- #include <boost/config.hpp> // make sure size_t is in namespace std
- #include <cstddef>
- #include <climits>
- #include <map>
- #include <stdexcept>
- #include <string>
- #include <utility> // pair
- #include <vector>
- #include <boost/lexical_cast.hpp>
- #include <boost/preprocessor/iteration/local.hpp>
- #include <boost/shared_ptr.hpp>
- #include <boost/test/test_tools.hpp>
- #include <boost/weak_ptr.hpp>
- #ifndef BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR
- # define BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR 20
- #endif
- #define BOOST_CHECK_OPERATION_SEQUENCE(seq) \
- BOOST_CHECK_MESSAGE(seq.is_success(), seq.message()) \
- /**/
- namespace boost { namespace iostreams { namespace test {
- // Simple exception class with error code built in to type
- template<int Code>
- struct operation_error { };
- class operation_sequence;
- // Represent an operation in a sequence of operations to be executed
- class operation {
- public:
- friend class operation_sequence;
- operation() : pimpl_() { }
- void execute();
- private:
- static void remove_operation(operation_sequence& seq, int id);
- struct impl {
- impl(operation_sequence& seq, int id, int error_code = -1)
- : seq(seq), id(id), error_code(error_code)
- { }
- ~impl() { remove_operation(seq, id); }
- impl& operator=(const impl&); // Suppress VC warning 4512
- operation_sequence& seq;
- int id;
- int error_code;
- };
- friend struct impl;
- operation(operation_sequence& seq, int id, int error_code = -1)
- : pimpl_(new impl(seq, id, error_code))
- { }
- shared_ptr<impl> pimpl_;
- };
- // Represents a sequence of operations to be executed in a particular order
- class operation_sequence {
- public:
- friend class operation;
- operation_sequence() { reset(); }
- //
- // Returns a new operation.
- // Parameters:
- //
- // id - The operation id, determining the position
- // of the new operation in the operation sequence
- // error_code - If supplied, indicates that the new
- // operation will throw operation_error<error_code>
- // when executed. Must be an integer between 0 and
- // BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR,
- // inclusive.
- //
- operation new_operation(int id, int error_code = INT_MAX);
- bool is_success() const { return success_; }
- bool is_failure() const { return failed_; }
- std::string message() const;
- void reset();
- private:
- void execute(int id);
- void remove_operation(int id);
- operation_sequence(const operation_sequence&);
- operation_sequence& operator=(const operation_sequence&);
- typedef weak_ptr<operation::impl> ptr_type;
- typedef std::map<int, ptr_type> map_type;
- map_type operations_;
- std::vector<int> log_;
- std::size_t total_executed_;
- int last_executed_;
- bool success_;
- bool failed_;
- };
- //--------------Implementation of operation-----------------------------------//
- void operation::execute()
- {
- pimpl_->seq.execute(pimpl_->id);
- switch (pimpl_->error_code) {
- // Implementation with one or more cleanup operations
- #define BOOST_PP_LOCAL_MACRO(n) \
- case n: throw operation_error<n>(); \
- /**/
- #define BOOST_PP_LOCAL_LIMITS (1, BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR)
- #include BOOST_PP_LOCAL_ITERATE()
- #undef BOOST_PP_LOCAL_MACRO
- default:
- break;
- }
- }
- inline void operation::remove_operation(operation_sequence& seq, int id)
- {
- seq.remove_operation(id);
- }
- //--------------Implementation of operation_sequence--------------------------//
- inline operation operation_sequence::new_operation(int id, int error_code)
- {
- using namespace std;
- if ( error_code < 0 ||
- (error_code > BOOST_IOSTREAMS_TEST_MAX_OPERATION_ERROR &&
- error_code != INT_MAX) )
- {
- throw runtime_error( string("The error code ") +
- lexical_cast<string>(error_code) +
- " is out of range" );
- }
- if (last_executed_ != INT_MIN)
- throw runtime_error( "Operations in progress; call reset() "
- "before creating more operations" );
- map_type::const_iterator it = operations_.find(id);
- if (it != operations_.end())
- throw runtime_error( string("The operation ") +
- lexical_cast<string>(id) +
- " already exists" );
- operation op(*this, id, error_code);
- operations_.insert(make_pair(id, ptr_type(op.pimpl_)));
- return op;
- }
- inline std::string operation_sequence::message() const
- {
- using namespace std;
- if (success_)
- return "success";
- std::string msg = failed_ ?
- "operations occurred out of order: " :
- "operation sequence is incomplete: ";
- typedef vector<int>::size_type size_type;
- for (size_type z = 0, n = log_.size(); z < n; ++z) {
- msg += lexical_cast<string>(log_[z]);
- if (z < n - 1)
- msg += ',';
- }
- return msg;
- }
- inline void operation_sequence::reset()
- {
- log_.clear();
- total_executed_ = 0;
- last_executed_ = INT_MIN;
- success_ = false;
- failed_ = false;
- }
- inline void operation_sequence::execute(int id)
- {
- log_.push_back(id);
- if (!failed_ && last_executed_ < id) {
- if (++total_executed_ == operations_.size())
- success_ = true;
- last_executed_ = id;
- } else {
- success_ = false;
- failed_ = true;
- }
- }
- inline void operation_sequence::remove_operation(int id)
- {
- using namespace std;
- map_type::iterator it = operations_.find(id);
- if (it == operations_.end())
- throw runtime_error( string("No such operation: ") +
- lexical_cast<string>(id) );
- operations_.erase(it);
- }
- } } } // End namespace boost::iostreams::test.
- #endif // #ifndef BOOST_IOSTREAMS_TEST_OPERATION_SEQUENCE_HPP_INCLUDED
|