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_stream ssl_stream test::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