// // Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) // // 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) // #ifndef BEAST_TEST_FAIL_STREAM_HPP #define BEAST_TEST_FAIL_STREAM_HPP #include #include #include #include #include #include #include namespace beast { namespace test { /** A stream wrapper that fails. On the Nth operation, the stream will fail with the specified error code, or the default error code of invalid_argument. */ template class fail_stream { boost::optional fc_; fail_counter* pfc_; NextLayer next_layer_; public: using next_layer_type = typename std::remove_reference::type; using lowest_layer_type = typename get_lowest_layer::type; fail_stream(fail_stream&&) = delete; fail_stream(fail_stream const&) = delete; fail_stream& operator=(fail_stream&&) = delete; fail_stream& operator=(fail_stream const&) = delete; template explicit fail_stream(std::size_t n, Args&&... args) : fc_(n) , pfc_(&*fc_) , next_layer_(std::forward(args)...) { } template explicit fail_stream(fail_counter& fc, Args&&... args) : pfc_(&fc) , next_layer_(std::forward(args)...) { } next_layer_type& next_layer() { return next_layer_; } lowest_layer_type& lowest_layer() { return next_layer_.lowest_layer(); } lowest_layer_type const& lowest_layer() const { return next_layer_.lowest_layer(); } boost::asio::io_service& get_io_service() { return next_layer_.get_io_service(); } template std::size_t read_some(MutableBufferSequence const& buffers) { pfc_->fail(); return next_layer_.read_some(buffers); } template std::size_t read_some(MutableBufferSequence const& buffers, error_code& ec) { if(pfc_->fail(ec)) return 0; return next_layer_.read_some(buffers, ec); } template async_return_type< ReadHandler, void(error_code, std::size_t)> async_read_some(MutableBufferSequence const& buffers, ReadHandler&& handler) { error_code ec; if(pfc_->fail(ec)) { async_completion init{handler}; next_layer_.get_io_service().post( bind_handler(init.completion_handler, ec, 0)); return init.result.get(); } return next_layer_.async_read_some(buffers, std::forward(handler)); } template std::size_t write_some(ConstBufferSequence const& buffers) { pfc_->fail(); return next_layer_.write_some(buffers); } template std::size_t write_some(ConstBufferSequence const& buffers, error_code& ec) { if(pfc_->fail(ec)) return 0; return next_layer_.write_some(buffers, ec); } template async_return_type< WriteHandler, void(error_code, std::size_t)> async_write_some(ConstBufferSequence const& buffers, WriteHandler&& handler) { error_code ec; if(pfc_->fail(ec)) { async_completion init{handler}; next_layer_.get_io_service().post( bind_handler(init.completion_handler, ec, 0)); return init.result.get(); } return next_layer_.async_write_some(buffers, std::forward(handler)); } friend void teardown(websocket::teardown_tag, fail_stream& stream, boost::system::error_code& ec) { if(stream.pfc_->fail(ec)) return; beast::websocket_helpers::call_teardown(stream.next_layer(), ec); } template friend void async_teardown(websocket::teardown_tag, fail_stream& stream, TeardownHandler&& handler) { error_code ec; if(stream.pfc_->fail(ec)) { stream.get_io_service().post( bind_handler(std::move(handler), ec)); return; } beast::websocket_helpers::call_async_teardown( stream.next_layer(), std::forward(handler)); } }; } // test } // beast #endif