diff --git a/CHANGELOG.md b/CHANGELOG.md
index 24b73d1f..c5a54828 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@ Version 170:
* Add ssl_stream to experimental
* Add test::error to experimental
* Add test::fail_count to experimental
+* Add test::stream to experimental
--------------------------------------------------------------------------------
diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml
index 7acdb932..f93a756d 100644
--- a/doc/qbk/quickref.xml
+++ b/doc/qbk/quickref.xml
@@ -303,6 +303,7 @@
flat_streamssl_streamtest::fail_count
+ test::stream
diff --git a/test/extras/include/boost/beast/test/stream.hpp b/include/boost/beast/experimental/test/impl/stream.ipp
similarity index 55%
rename from test/extras/include/boost/beast/test/stream.hpp
rename to include/boost/beast/experimental/test/impl/stream.ipp
index 975a3069..ef32964c 100644
--- a/test/extras/include/boost/beast/test/stream.hpp
+++ b/include/boost/beast/experimental/test/impl/stream.ipp
@@ -7,375 +7,147 @@
// Official repository: https://github.com/boostorg/beast
//
-#ifndef BOOST_BEAST_TEST_STREAM_HPP
-#define BOOST_BEAST_TEST_STREAM_HPP
+#ifndef BOOST_BEAST_TEST_IMPL_STREAM_IPP
+#define BOOST_BEAST_TEST_IMPL_STREAM_IPP
-#include
#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
namespace boost {
namespace beast {
namespace test {
-/** A bidirectional in-memory communication channel
-
- An instance of this class provides a client and server
- endpoint that are automatically connected to each other
- similarly to a connected socket.
-
- Test pipes are used to facilitate writing unit tests
- where the behavior of the transport is tightly controlled
- to help illuminate all code paths (for code coverage)
-*/
-class stream
+inline
+stream::
+~stream()
{
- struct read_op
{
- virtual ~read_op() = default;
- virtual void operator()() = 0;
- };
-
- template
- class read_op_impl;
-
- enum class status
+ std::unique_lock lock{in_->m};
+ in_->op.reset();
+ }
+ auto out = out_.lock();
+ if(out)
{
- ok,
- eof,
- reset
- };
-
- struct state
- {
- friend class stream;
-
- std::mutex m;
- flat_buffer b;
- std::condition_variable cv;
- std::unique_ptr op;
- boost::asio::io_context& ioc;
- status code = status::ok;
- fail_count* fc = nullptr;
- std::size_t nread = 0;
- std::size_t nwrite = 0;
- std::size_t read_max =
- (std::numeric_limits::max)();
- std::size_t write_max =
- (std::numeric_limits::max)();
-
- ~state()
+ std::unique_lock lock{out->m};
+ if(out->code == status::ok)
{
- BOOST_ASSERT(! op);
- }
-
- explicit
- state(
- boost::asio::io_context& ioc_,
- fail_count* fc_)
- : ioc(ioc_)
- , fc(fc_)
- {
- }
-
- void
- on_write()
- {
- if(op)
- {
- std::unique_ptr op_ = std::move(op);
- op_->operator()();
- }
- else
- {
- cv.notify_all();
- }
- }
- };
-
- std::shared_ptr in_;
- std::weak_ptr out_;
-
-public:
- using buffer_type = flat_buffer;
-
- /// The type of the lowest layer.
- using lowest_layer_type = stream;
-
- /// Destructor
- ~stream()
- {
- {
- std::unique_lock lock{in_->m};
- in_->op.reset();
- }
- auto out = out_.lock();
- if(out)
- {
- std::unique_lock lock{out->m};
- if(out->code == status::ok)
- {
- out->code = status::reset;
- out->on_write();
- }
+ out->code = status::reset;
+ out->on_write();
}
}
+}
- /// Constructor
- stream(stream&& other)
- {
- auto in = std::make_shared(
- other.in_->ioc, other.in_->fc);
- in_ = std::move(other.in_);
- out_ = std::move(other.out_);
- other.in_ = in;
- }
+inline
+stream::
+stream(stream&& other)
+{
+ auto in = std::make_shared(
+ other.in_->ioc, other.in_->fc);
+ in_ = std::move(other.in_);
+ out_ = std::move(other.out_);
+ other.in_ = in;
+}
- /// Assignment
- stream&
- operator=(stream&& other)
- {
- auto in = std::make_shared(
- other.in_->ioc, other.in_->fc);
- in_ = std::move(other.in_);
- out_ = std::move(other.out_);
- other.in_ = in;
- return *this;
- }
+inline
+stream&
+stream::
+operator=(stream&& other)
+{
+ auto in = std::make_shared(
+ other.in_->ioc, other.in_->fc);
+ in_ = std::move(other.in_);
+ out_ = std::move(other.out_);
+ other.in_ = in;
+ return *this;
+}
- /// Constructor
- explicit
- stream(boost::asio::io_context& ioc)
- : in_(std::make_shared(ioc, nullptr))
- {
- }
+inline
+stream::
+stream(boost::asio::io_context& ioc)
+ : in_(std::make_shared(ioc, nullptr))
+{
+}
- /// Constructor
- stream(
- boost::asio::io_context& ioc,
- fail_count& fc)
- : in_(std::make_shared(ioc, &fc))
- {
- }
+inline
+stream::
+stream(
+ boost::asio::io_context& ioc,
+ fail_count& fc)
+ : in_(std::make_shared(ioc, &fc))
+{
+}
- /// Constructor
- stream(
- boost::asio::io_context& ioc,
- string_view s)
- : in_(std::make_shared(ioc, nullptr))
- {
- using boost::asio::buffer;
- using boost::asio::buffer_copy;
- in_->b.commit(buffer_copy(
- in_->b.prepare(s.size()),
- buffer(s.data(), s.size())));
- }
+inline
+stream::
+stream(
+ boost::asio::io_context& ioc,
+ string_view s)
+ : in_(std::make_shared(ioc, nullptr))
+{
+ using boost::asio::buffer;
+ using boost::asio::buffer_copy;
+ in_->b.commit(buffer_copy(
+ in_->b.prepare(s.size()),
+ buffer(s.data(), s.size())));
+}
- /// Constructor
- stream(
- boost::asio::io_context& ioc,
- fail_count& fc,
- string_view s)
- : in_(std::make_shared(ioc, &fc))
- {
- using boost::asio::buffer;
- using boost::asio::buffer_copy;
- in_->b.commit(buffer_copy(
- in_->b.prepare(s.size()),
- buffer(s.data(), s.size())));
- }
+inline
+stream::
+stream(
+ boost::asio::io_context& ioc,
+ fail_count& fc,
+ string_view s)
+ : in_(std::make_shared(ioc, &fc))
+{
+ using boost::asio::buffer;
+ using boost::asio::buffer_copy;
+ in_->b.commit(buffer_copy(
+ in_->b.prepare(s.size()),
+ buffer(s.data(), s.size())));
+}
- /// Establish a connection
- void
- connect(stream& remote)
- {
- BOOST_ASSERT(! out_.lock());
- BOOST_ASSERT(! remote.out_.lock());
- out_ = remote.in_;
- remote.out_ = in_;
- }
+inline
+void
+stream::
+connect(stream& remote)
+{
+ BOOST_ASSERT(! out_.lock());
+ BOOST_ASSERT(! remote.out_.lock());
+ out_ = remote.in_;
+ remote.out_ = in_;
+}
+inline
+string_view
+stream::
+str() const
+{
+ auto const bs = in_->b.data();
+ if(boost::asio::buffer_size(bs) == 0)
+ return {};
+ auto const b = buffers_front(bs);
+ return {reinterpret_cast(b.data()), b.size()};
+}
- /// The type of the executor associated with the object.
- using executor_type =
- boost::asio::io_context::executor_type;
+inline
+void
+stream::
+append(string_view s)
+{
+ using boost::asio::buffer;
+ using boost::asio::buffer_copy;
+ std::lock_guard lock{in_->m};
+ in_->b.commit(buffer_copy(
+ in_->b.prepare(s.size()),
+ buffer(s.data(), s.size())));
+}
- /// Return the executor associated with the object.
- boost::asio::io_context::executor_type
- get_executor() noexcept
- {
- return in_->ioc.get_executor();
- };
-
- /** Get a reference to the lowest layer
-
- This function returns a reference to the lowest layer
- in a stack of stream layers.
-
- @return A reference to the lowest layer in the stack of
- stream layers.
- */
- lowest_layer_type&
- lowest_layer()
- {
- return *this;
- }
-
- /** Get a reference to the lowest layer
-
- This function returns a reference to the lowest layer
- in a stack of stream layers.
-
- @return A reference to the lowest layer in the stack of
- stream layers. Ownership is not transferred to the caller.
- */
- lowest_layer_type const&
- lowest_layer() const
- {
- return *this;
- }
-
- /// Set the maximum number of bytes returned by read_some
- void
- read_size(std::size_t n)
- {
- in_->read_max = n;
- }
-
- /// Set the maximum number of bytes returned by write_some
- void
- write_size(std::size_t n)
- {
- in_->write_max = n;
- }
-
- /// Direct input buffer access
- buffer_type&
- buffer()
- {
- return in_->b;
- }
-
- /// Returns a string view representing the pending input data
- string_view
- str() const
- {
- auto const bs = in_->b.data();
- if(boost::asio::buffer_size(bs) == 0)
- return {};
- auto const b = buffers_front(bs);
- return {reinterpret_cast(b.data()), b.size()};
- }
-
- /// Appends a string to the pending input data
- void
- append(string_view s)
- {
- using boost::asio::buffer;
- using boost::asio::buffer_copy;
- std::lock_guard lock{in_->m};
- in_->b.commit(buffer_copy(
- in_->b.prepare(s.size()),
- buffer(s.data(), s.size())));
- }
-
- /// Clear the pending input area
- void
- clear()
- {
- std::lock_guard lock{in_->m};
- in_->b.consume(in_->b.size());
- }
-
- /// Return the number of reads
- std::size_t
- nread() const
- {
- return in_->nread;
- }
-
- /// Return the number of writes
- std::size_t
- nwrite() const
- {
- return in_->nwrite;
- }
-
- /** Close the stream.
-
- The other end of the connection will see
- `error::eof` after reading all the remaining data.
- */
- void
- close();
-
- /** Close the other end of the stream.
-
- This end of the connection will see
- `error::eof` after reading all the remaining data.
- */
- void
- close_remote();
-
- template
- std::size_t
- read_some(MutableBufferSequence const& buffers);
-
- template
- std::size_t
- read_some(MutableBufferSequence const& buffers,
- error_code& ec);
-
- template
- BOOST_ASIO_INITFN_RESULT_TYPE(
- ReadHandler, void(error_code, std::size_t))
- async_read_some(MutableBufferSequence const& buffers,
- ReadHandler&& handler);
-
- template
- std::size_t
- write_some(ConstBufferSequence const& buffers);
-
- template
- std::size_t
- write_some(
- ConstBufferSequence const& buffers, error_code&);
-
- template
- BOOST_ASIO_INITFN_RESULT_TYPE(
- WriteHandler, void(error_code, std::size_t))
- async_write_some(ConstBufferSequence const& buffers,
- WriteHandler&& handler);
-
- friend
- void
- teardown(websocket::role_type,
- stream& s, boost::system::error_code& ec);
-
- template
- friend
- void
- async_teardown(websocket::role_type role,
- stream& s, TeardownHandler&& handler);
-};
-
-//------------------------------------------------------------------------------
+inline
+void
+stream::
+clear()
+{
+ std::lock_guard lock{in_->m};
+ in_->b.consume(in_->b.size());
+}
inline
void
@@ -532,7 +304,7 @@ async_read_some(
}
else
{
- in_->op.reset(new read_op_implop.reset(new read_op{*in_, buffers,
std::move(init.completion_handler)});
@@ -645,9 +417,9 @@ async_write_some(ConstBufferSequence const& buffers,
inline
void
teardown(
- websocket::role_type,
- stream& s,
- boost::system::error_code& ec)
+websocket::role_type,
+stream& s,
+boost::system::error_code& ec)
{
if( s.in_->fc &&
s.in_->fc->fail(ec))
@@ -666,9 +438,9 @@ template
inline
void
async_teardown(
- websocket::role_type,
- stream& s,
- TeardownHandler&& handler)
+websocket::role_type,
+stream& s,
+TeardownHandler&& handler)
{
error_code ec;
if( s.in_->fc &&
@@ -691,7 +463,7 @@ async_teardown(
//------------------------------------------------------------------------------
template
-class stream::read_op_impl : public stream::read_op
+class stream::read_op : public stream::read_op_base
{
class lambda
{
@@ -769,7 +541,7 @@ class stream::read_op_impl : public stream::read_op
public:
template
- read_op_impl(state& s, Buffers const& b, DeducedHandler&& h)
+ read_op(state& s, Buffers const& b, DeducedHandler&& h)
: fn_(s, b, std::forward(h))
{
}
@@ -781,7 +553,6 @@ public:
}
};
-/// Create and return a connected stream
inline
stream
connect(stream& to)
@@ -791,7 +562,6 @@ connect(stream& to)
return from;
}
-/// Create and return a connected stream
template
stream
connect(stream& to, Arg1&& arg1, ArgN&&... argn)
diff --git a/include/boost/beast/experimental/test/stream.hpp b/include/boost/beast/experimental/test/stream.hpp
new file mode 100644
index 00000000..005f8116
--- /dev/null
+++ b/include/boost/beast/experimental/test/stream.hpp
@@ -0,0 +1,538 @@
+//
+// Copyright (c) 2016-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)
+//
+// Official repository: https://github.com/boostorg/beast
+//
+
+#ifndef BOOST_BEAST_TEST_STREAM_HPP
+#define BOOST_BEAST_TEST_STREAM_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace boost {
+namespace beast {
+namespace test {
+
+/** A two-way socket useful for unit testing
+
+ An instance of this class simulates a traditional socket,
+ while also providing features useful for unit testing.
+ Each endpoint maintains an independent buffer called
+ the input area. Writes from one endpoint append data
+ to the peer's pending input area. When an endpoint performs
+ a read and data is present in the input area, the data is
+ delivered to the blocking or asynchronous operation. Otherwise
+ the operation is blocked or deferred until data is made
+ available, or until the endpoints become disconnected.
+
+ These streams may be used anywhere an algorithm accepts a
+ reference to a synchronous or asynchronous read or write
+ stream. It is possible to use a test stream in a call to
+ `boost::asio::read_until`, or in a call to
+ @ref boost::beast::http::async_write for example.
+
+ As with Boost.Asio I/O objects, a @ref stream constructs
+ with a reference to the `boost::asio::io_context` to use for
+ handling asynchronous I/O. For asynchronous operations, the
+ stream follows the same rules as a traditional asio socket
+ with respect to how completion handlers for asynchronous
+ operations are performed.
+
+ To facilitate testing, these streams support some additional
+ features:
+
+ @li The input area, represented by a @ref flat_buffer, may
+ be directly accessed by the caller to inspect the contents
+ before or after the remote endpoint writes data. This allows
+ a unit test to verify that the received data matches.
+
+ @li Data may be manually appended to the input area. This data
+ will delivered in the next call to
+ @ref stream::read_some or @ref stream::async_read_some.
+ This allows predefined test vectors to be set up for testing
+ read algorithms.
+
+ @li The stream may be constructed with a @ref fail count. The
+ stream will eventually fail with a predefined error after a
+ certain number of operations, where the number of operations
+ is controlled by the test. When a test loops over a range of
+ operation counts, it is possible to exercise every possible
+ point of failure in the algorithm being tested. When used
+ correctly the technique allows the tests to reach a high
+ percentage of code coverage.
+
+ @par Thread Safety
+ @e Distinct @e objects: Safe.@n
+ @e Shared @e objects: Unsafe.
+ The application must also ensure that all asynchronous
+ operations are performed within the same implicit or explicit strand.
+
+ @par Concepts
+ @li @b SyncReadStream
+ @li @b SyncWriteStream
+ @li @b AsyncReadStream
+ @li @b AsyncWriteStream
+*/
+class stream
+{
+ struct read_op_base
+ {
+ virtual ~read_op_base() = default;
+ virtual void operator()() = 0;
+ };
+
+ template
+ class read_op;
+
+ enum class status
+ {
+ ok,
+ eof,
+ reset
+ };
+
+ struct state
+ {
+ friend class stream;
+
+ std::mutex m;
+ flat_buffer b;
+ std::condition_variable cv;
+ std::unique_ptr op;
+ boost::asio::io_context& ioc;
+ status code = status::ok;
+ fail_count* fc = nullptr;
+ std::size_t nread = 0;
+ std::size_t nwrite = 0;
+ std::size_t read_max =
+ (std::numeric_limits::max)();
+ std::size_t write_max =
+ (std::numeric_limits::max)();
+
+ ~state()
+ {
+ BOOST_ASSERT(! op);
+ }
+
+ explicit
+ state(
+ boost::asio::io_context& ioc_,
+ fail_count* fc_)
+ : ioc(ioc_)
+ , fc(fc_)
+ {
+ }
+
+ void
+ on_write()
+ {
+ if(op)
+ {
+ std::unique_ptr op_ = std::move(op);
+ op_->operator()();
+ }
+ else
+ {
+ cv.notify_all();
+ }
+ }
+ };
+
+ std::shared_ptr in_;
+ std::weak_ptr out_;
+
+public:
+ using buffer_type = flat_buffer;
+
+ /// The type of the lowest layer.
+ using lowest_layer_type = stream;
+
+ /** Destructor
+
+ If an asynchronous read operation is pending, it will
+ simply be discarded with no notification to the completion
+ handler.
+
+ If a connection is established while the stream is destroyed,
+ the peer will see the error `boost::asio::error::connection_reset`
+ when performing any reads or writes.
+ */
+ ~stream();
+
+ /** Move Constructor
+
+ Moving the stream while asynchronous operations are pending
+ results in undefined behavior.
+ */
+ stream(stream&& other);
+
+ /** Move Assignment
+
+ Moving the stream while asynchronous operations are pending
+ results in undefined behavior.
+ */
+ stream&
+ operator=(stream&& other);
+
+ /** Construct a stream
+
+ The stream will be created in a disconnected state.
+
+ @param ioc The `io_context` object that the stream will use to
+ dispatch handlers for any asynchronous operations.
+ */
+ explicit
+ stream(boost::asio::io_context& ioc);
+
+ /** Construct a stream
+
+ The stream will be created in a disconnected state.
+
+ @param ioc The `io_context` object that the stream will use to
+ dispatch handlers for any asynchronous operations.
+
+ @param fc The @ref fail_count to associate with the stream.
+ Each I/O operation performed on the stream will increment the
+ fail count. When the fail count reaches its internal limit,
+ a simulated failure error will be raised.
+ */
+ stream(
+ boost::asio::io_context& ioc,
+ fail_count& fc);
+
+ /** Construct a stream
+
+ The stream will be created in a disconnected state.
+
+ @param ioc The `io_context` object that the stream will use to
+ dispatch handlers for any asynchronous operations.
+
+ @param s A string which will be appended to the input area, not
+ including the null terminator.
+ */
+ stream(
+ boost::asio::io_context& ioc,
+ string_view s);
+
+ /** Construct a stream
+
+ The stream will be created in a disconnected state.
+
+ @param ioc The `io_context` object that the stream will use to
+ dispatch handlers for any asynchronous operations.
+
+ @param fc The @ref fail_count to associate with the stream.
+ Each I/O operation performed on the stream will increment the
+ fail count. When the fail count reaches its internal limit,
+ a simulated failure error will be raised.
+
+ @param s A string which will be appended to the input area, not
+ including the null terminator.
+ */
+ stream(
+ boost::asio::io_context& ioc,
+ fail_count& fc,
+ string_view s);
+
+ /// Establish a connection
+ void
+ connect(stream& remote);
+
+ /// The type of the executor associated with the object.
+ using executor_type =
+ boost::asio::io_context::executor_type;
+
+ /// Return the executor associated with the object.
+ boost::asio::io_context::executor_type
+ get_executor() noexcept
+ {
+ return in_->ioc.get_executor();
+ };
+
+ /** Get a reference to the lowest layer
+
+ This function returns a reference to the lowest layer
+ in a stack of stream layers.
+
+ @return A reference to the lowest layer in the stack of
+ stream layers.
+ */
+ lowest_layer_type&
+ lowest_layer()
+ {
+ return *this;
+ }
+
+ /** Get a reference to the lowest layer
+
+ This function returns a reference to the lowest layer
+ in a stack of stream layers.
+
+ @return A reference to the lowest layer in the stack of
+ stream layers. Ownership is not transferred to the caller.
+ */
+ lowest_layer_type const&
+ lowest_layer() const
+ {
+ return *this;
+ }
+
+ /// Set the maximum number of bytes returned by read_some
+ void
+ read_size(std::size_t n)
+ {
+ in_->read_max = n;
+ }
+
+ /// Set the maximum number of bytes returned by write_some
+ void
+ write_size(std::size_t n)
+ {
+ in_->write_max = n;
+ }
+
+ /// Direct input buffer access
+ buffer_type&
+ buffer()
+ {
+ return in_->b;
+ }
+
+ /// Returns a string view representing the pending input data
+ string_view
+ str() const;
+
+ /// Appends a string to the pending input data
+ void
+ append(string_view s);
+
+ /// Clear the pending input area
+ void
+ clear();
+
+ /// Return the number of reads
+ std::size_t
+ nread() const
+ {
+ return in_->nread;
+ }
+
+ /// Return the number of writes
+ std::size_t
+ nwrite() const
+ {
+ return in_->nwrite;
+ }
+
+ /** Close the stream.
+
+ The other end of the connection will see
+ `error::eof` after reading all the remaining data.
+ */
+ void
+ close();
+
+ /** Close the other end of the stream.
+
+ This end of the connection will see
+ `error::eof` after reading all the remaining data.
+ */
+ void
+ close_remote();
+
+ /** Read some data from the stream.
+
+ This function is used to read data from the stream. The function call will
+ block until one or more bytes of data has been read successfully, or until
+ an error occurs.
+
+ @param buffers The buffers into which the data will be read.
+
+ @returns The number of bytes read.
+
+ @throws boost::system::system_error Thrown on failure.
+
+ @note The `read_some` operation may not read all of the requested number of
+ bytes. Consider using the function `boost::asio::read` if you need to ensure
+ that the requested amount of data is read before the blocking operation
+ completes.
+ */
+ template
+ std::size_t
+ read_some(MutableBufferSequence const& buffers);
+
+ /** Read some data from the stream.
+
+ This function is used to read data from the stream. The function call will
+ block until one or more bytes of data has been read successfully, or until
+ an error occurs.
+
+ @param buffers The buffers into which the data will be read.
+
+ @param ec Set to indicate what error occurred, if any.
+
+ @returns The number of bytes read.
+
+ @note The `read_some` operation may not read all of the requested number of
+ bytes. Consider using the function `boost::asio::read` if you need to ensure
+ that the requested amount of data is read before the blocking operation
+ completes.
+ */
+ template
+ std::size_t
+ read_some(MutableBufferSequence const& buffers,
+ error_code& ec);
+
+ /** Start an asynchronous read.
+
+ This function is used to asynchronously read one or more bytes of data from
+ the stream. The function call always returns immediately.
+
+ @param buffers The buffers into which the data will be read. Although the
+ buffers object may be copied as necessary, ownership of the underlying
+ buffers is retained by the caller, which must guarantee that they remain
+ valid until the handler is called.
+
+ @param handler The handler to be called when the read operation completes.
+ Copies will be made of the handler as required. The equivalent function
+ signature of the handler must be:
+ @code void handler(
+ const boost::system::error_code& error, // Result of operation.
+ std::size_t bytes_transferred // Number of bytes read.
+ ); @endcode
+
+ @note The `read_some` operation may not read all of the requested number of
+ bytes. Consider using the function `boost::asio::async_read` if you need
+ to ensure that the requested amount of data is read before the asynchronous
+ operation completes.
+ */
+ template
+ BOOST_ASIO_INITFN_RESULT_TYPE(
+ ReadHandler, void(error_code, std::size_t))
+ async_read_some(MutableBufferSequence const& buffers,
+ ReadHandler&& handler);
+
+ /** Write some data to the stream.
+
+ This function is used to write data on the stream. The function call will
+ block until one or more bytes of data has been written successfully, or
+ until an error occurs.
+
+ @param buffers The data to be written.
+
+ @returns The number of bytes written.
+
+ @throws boost::system::system_error Thrown on failure.
+
+ @note The `write_some` operation may not transmit all of the data to the
+ peer. Consider using the function `boost::asio::write` if you need to
+ ensure that all data is written before the blocking operation completes.
+ */
+ template
+ std::size_t
+ write_some(ConstBufferSequence const& buffers);
+
+ /** Write some data to the stream.
+
+ This function is used to write data on the stream. The function call will
+ block until one or more bytes of data has been written successfully, or
+ until an error occurs.
+
+ @param buffers The data to be written.
+
+ @param ec Set to indicate what error occurred, if any.
+
+ @returns The number of bytes written.
+
+ @note The `write_some` operation may not transmit all of the data to the
+ peer. Consider using the function `boost::asio::write` if you need to
+ ensure that all data is written before the blocking operation completes.
+ */
+ template
+ std::size_t
+ write_some(
+ ConstBufferSequence const& buffers, error_code&);
+
+ /** Start an asynchronous write.
+
+ This function is used to asynchronously write one or more bytes of data to
+ the stream. The function call always returns immediately.
+
+ @param buffers The data to be written to the stream. Although the buffers
+ object may be copied as necessary, ownership of the underlying buffers is
+ retained by the caller, which must guarantee that they remain valid until
+ the handler is called.
+
+ @param handler The handler to be called when the write operation completes.
+ Copies will be made of the handler as required. The equivalent function
+ signature of the handler must be:
+ @code void handler(
+ const boost::system::error_code& error, // Result of operation.
+ std::size_t bytes_transferred // Number of bytes written.
+ ); @endcode
+
+ @note The `async_write_some` operation may not transmit all of the data to
+ the peer. Consider using the function `boost::asio::async_write` if you need
+ to ensure that all data is written before the asynchronous operation completes.
+ */
+ template
+ BOOST_ASIO_INITFN_RESULT_TYPE(
+ WriteHandler, void(error_code, std::size_t))
+ async_write_some(ConstBufferSequence const& buffers,
+ WriteHandler&& handler);
+
+#ifndef BOOST_BEAST_DOXYGEN
+ friend
+ void
+ teardown(
+ websocket::role_type,
+ stream& s,
+ boost::system::error_code& ec);
+
+ template
+ friend
+ void
+ async_teardown(
+ websocket::role_type role,
+ stream& s,
+ TeardownHandler&& handler);
+#endif
+};
+
+/// Create and return a connected stream
+stream
+connect(stream& to);
+
+/// Create and return a connected stream
+template
+stream
+connect(stream& to, Arg1&& arg1, ArgN&&... argn);
+
+} // test
+} // beast
+} // boost
+
+#include
+
+#endif
diff --git a/test/beast/core/bind_handler.cpp b/test/beast/core/bind_handler.cpp
index 203c4bdb..54b223e0 100644
--- a/test/beast/core/bind_handler.cpp
+++ b/test/beast/core/bind_handler.cpp
@@ -11,7 +11,7 @@
#include
#include
-#include
+#include
#include
#include
#include
diff --git a/test/beast/core/buffered_read_stream.cpp b/test/beast/core/buffered_read_stream.cpp
index 3d45c45b..d8f7337c 100644
--- a/test/beast/core/buffered_read_stream.cpp
+++ b/test/beast/core/buffered_read_stream.cpp
@@ -11,7 +11,7 @@
#include
#include
-#include
+#include
#include
#include
#include
diff --git a/test/beast/experimental/CMakeLists.txt b/test/beast/experimental/CMakeLists.txt
index 801b9f93..795df861 100644
--- a/test/beast/experimental/CMakeLists.txt
+++ b/test/beast/experimental/CMakeLists.txt
@@ -20,6 +20,7 @@ add_executable (tests-beast-experimental
error.cpp
flat_stream.cpp
ssl_stream.cpp
+ stream.cpp
)
set_property(TARGET tests-beast-experimental PROPERTY FOLDER "tests")
diff --git a/test/beast/experimental/Jamfile b/test/beast/experimental/Jamfile
index fd53dae4..040b0a1c 100644
--- a/test/beast/experimental/Jamfile
+++ b/test/beast/experimental/Jamfile
@@ -11,6 +11,7 @@ local SOURCES =
error.cpp
flat_stream.cpp
ssl_stream.cpp
+ stream.cpp
;
local RUN_TESTS ;
diff --git a/test/beast/experimental/stream.cpp b/test/beast/experimental/stream.cpp
new file mode 100644
index 00000000..12a9a1b6
--- /dev/null
+++ b/test/beast/experimental/stream.cpp
@@ -0,0 +1,11 @@
+//
+// Copyright (c) 2016-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)
+//
+// Official repository: https://github.com/boostorg/beast
+//
+
+// Test that header file is self-contained.
+#include
diff --git a/test/beast/http/dynamic_body.cpp b/test/beast/http/dynamic_body.cpp
index eccb9ad7..720cb9c8 100644
--- a/test/beast/http/dynamic_body.cpp
+++ b/test/beast/http/dynamic_body.cpp
@@ -16,7 +16,7 @@
#include
#include
#include
-#include
+#include
#include
namespace boost {
diff --git a/test/beast/http/read.cpp b/test/beast/http/read.cpp
index aea30169..afb619aa 100644
--- a/test/beast/http/read.cpp
+++ b/test/beast/http/read.cpp
@@ -18,7 +18,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
diff --git a/test/beast/http/write.cpp b/test/beast/http/write.cpp
index e3a07ffc..4e2c49b9 100644
--- a/test/beast/http/write.cpp
+++ b/test/beast/http/write.cpp
@@ -19,7 +19,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
diff --git a/test/beast/websocket/test.hpp b/test/beast/websocket/test.hpp
index ecdb88a0..8fe69b17 100644
--- a/test/beast/websocket/test.hpp
+++ b/test/beast/websocket/test.hpp
@@ -15,7 +15,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
diff --git a/test/doc/core_examples.cpp b/test/doc/core_examples.cpp
index 65a985cc..115c47e4 100644
--- a/test/doc/core_examples.cpp
+++ b/test/doc/core_examples.cpp
@@ -11,7 +11,7 @@
#include
#include
-#include
+#include
#include
#include
diff --git a/test/doc/http_examples.cpp b/test/doc/http_examples.cpp
index b95e0a25..8527d9d8 100644
--- a/test/doc/http_examples.cpp
+++ b/test/doc/http_examples.cpp
@@ -18,7 +18,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
diff --git a/test/extras/include/boost/beast/test/websocket.hpp b/test/extras/include/boost/beast/test/websocket.hpp
index 09685624..21c1783b 100644
--- a/test/extras/include/boost/beast/test/websocket.hpp
+++ b/test/extras/include/boost/beast/test/websocket.hpp
@@ -12,7 +12,7 @@
#include
#include
-#include
+#include
#include
#include
#include