diff --git a/Builds/VisualStudio2015/RippleD.vcxproj b/Builds/VisualStudio2015/RippleD.vcxproj
index 748d05d439..b91e4be582 100644
--- a/Builds/VisualStudio2015/RippleD.vcxproj
+++ b/Builds/VisualStudio2015/RippleD.vcxproj
@@ -236,26 +236,14 @@
-
-
-
-
-
-
-
-
-
-
-
-
@@ -306,8 +294,6 @@
-
-
@@ -352,6 +338,8 @@
+
+
@@ -394,8 +382,6 @@
-
-
@@ -428,6 +414,8 @@
+
+
diff --git a/Builds/VisualStudio2015/RippleD.vcxproj.filters b/Builds/VisualStudio2015/RippleD.vcxproj.filters
index f954ba6a4c..cb63157e0f 100644
--- a/Builds/VisualStudio2015/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2015/RippleD.vcxproj.filters
@@ -537,24 +537,9 @@
.
-
- extras\beast\unit_test
-
extras\beast\unit_test
-
- extras\beast\unit_test
-
-
- extras\beast\unit_test
-
-
- extras\beast\unit_test
-
-
- extras\beast\unit_test
-
extras\beast\unit_test\detail
@@ -564,9 +549,6 @@
extras\beast\unit_test
-
- extras\beast\unit_test
-
extras\beast\unit_test
@@ -642,9 +624,6 @@
include\beast\core\detail
-
- include\beast\core\detail
-
include\beast\core\detail
@@ -711,6 +690,9 @@
include\beast\http
+
+ include\beast\http
+
include\beast\http\detail
@@ -774,9 +756,6 @@
include\beast\http
-
- include\beast\http
-
include\beast\http
@@ -825,6 +804,9 @@
include\beast\websocket\impl
+
+ include\beast\websocket\impl
+
include\beast\websocket\impl
diff --git a/src/beast/.travis.yml b/src/beast/.travis.yml
index 4feaf6a82a..04f04d4df6 100644
--- a/src/beast/.travis.yml
+++ b/src/beast/.travis.yml
@@ -34,8 +34,8 @@ packages: &gcc5_pkgs
- autotools-dev
- libc6-dbg
-packages: &clang36_pkgs
- - clang-3.6
+packages: &clang38_pkgs
+ - clang-3.8
- g++-5
- python-software-properties
- libssl-dev
@@ -53,56 +53,57 @@ packages: &clang36_pkgs
matrix:
include:
# GCC/Debug
+ # - compiler: gcc
+ # env: GCC_VER=5 VARIANT=debug ADDRESS_MODEL=64
+ # addons: &ao_gcc5
+ # apt:
+ # sources: ['ubuntu-toolchain-r-test']
+ # packages: *gcc5_pkgs
+
+ # # GCC/Release
+ # - compiler: gcc
+ # env: GCC_VER=5 VARIANT=release ADDRESS_MODEL=64
+ # addons: *ao_gcc5
+
+ # Coverage
- compiler: gcc
- env: GCC_VER=5 VARIANT=debug ADDRESS_MODEL=64
+ env: GCC_VER=5 VARIANT=coverage ADDRESS_MODEL=64
addons: &ao_gcc5
apt:
sources: ['ubuntu-toolchain-r-test']
packages: *gcc5_pkgs
- # - compiler: gcc
- # env: GCC_VER=5 VARIANT=debug ADDRESS_MODEL=32
- # addons: *ao_gcc5
+ # # Clang/Debug
+ # - compiler: clang
+ # env: GCC_VER=5 VARIANT=debug CLANG_VER=3.8 ADDRESS_MODEL=64
+ # addons: &ao_clang38
+ # apt:
+ # sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.8']
+ # packages: *clang38_pkgs
- # GCC/Release
- - compiler: gcc
- env: GCC_VER=5 VARIANT=release ADDRESS_MODEL=64
- addons: *ao_gcc5
+ # # Clang/Release
+ # - compiler: clang
+ # env: GCC_VER=5 VARIANT=release CLANG_VER=3.8 ADDRESS_MODEL=64
+ # addons: *ao_clang38
- # # - compiler: gcc
- # # env: GCC_VER=5 VARIANT=release ADDRESS_MODEL=32
- # # addons: *ao_gcc5
-
- # Clang/Debug
+ # Clang/AddressSanitizer
- compiler: clang
- env: GCC_VER=5 VARIANT=debug CLANG_VER=3.6 ADDRESS_MODEL=64
- addons: &ao_clang36
+ env: GCC_VER=5 VARIANT=asan CLANG_VER=3.8 ADDRESS_MODEL=64
+ addons: &ao_clang38
apt:
- sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6']
- packages: *clang36_pkgs
+ sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.8']
+ packages: *clang38_pkgs
- # # - compiler: clang
- # # env: GCC_VER=5 VARIANT=debug CLANG_VER=3.6 ADDRESS_MODEL=32
- # # addons: *ao_clang36
+ # Clang/MemorySanitizer
+ # VFALCO Generates false positives unless libc++ is compiled with msan turned on
+ #- compiler: clang
+ # env: GCC_VER=5 VARIANT=msan CLANG_VER=3.8 ADDRESS_MODEL=64 MSAN_OPTIONS=poison_in_dtor=1,sanitize-memory-track-origins=2
+ # addons: *ao_clang38
- # Clang/Release
+ # Clang/UndefinedBehaviourSanitizer
- compiler: clang
- env: GCC_VER=5 VARIANT=release CLANG_VER=3.6 ADDRESS_MODEL=64
- addons: *ao_clang36
-
- # # - compiler: clang
- # # env: GCC_VER=5 VARIANT=release CLANG_VER=3.6 ADDRESS_MODEL=32
- # # addons: *ao_clang36
-
- # Coverage
- - compiler: gcc
- env: GCC_VER=5 VARIANT=coverage ADDRESS_MODEL=64
- addons: *ao_gcc5
-
- # ASAN
- - compiler: gcc
- env: GCC_VER=5 VARIANT=asan ADDRESS_MODEL=64
- addons: *ao_gcc5
+ env: GCC_VER=5 VARIANT=usan CLANG_VER=3.8 ADDRESS_MODEL=64
+ addons: *ao_clang38
cache:
directories:
diff --git a/src/beast/Jamroot b/src/beast/Jamroot
index 5013bd0058..f0f9f097c3 100644
--- a/src/beast/Jamroot
+++ b/src/beast/Jamroot
@@ -61,6 +61,22 @@ variant asan
"-fsanitize=address"
;
+variant msan
+ :
+ debug
+ :
+ "-fsanitize=memory -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 -fsanitize-memory-use-after-dtor"
+ "-fsanitize=memory"
+ ;
+
+variant usan
+ :
+ debug
+ :
+ "-fsanitize=undefined -fno-omit-frame-pointer"
+ "-fsanitize=undefined"
+ ;
+
project beast
: requirements
.
@@ -90,7 +106,7 @@ project beast
SOLARIS:__EXTENSIONS__
SOLARIS:socket
SOLARIS:nsl
- NT:_WIN32_WINNT=0x0501
+ NT:_WIN32_WINNT=0x0601
NT,cw:ws2_32
NT,cw:mswsock
NT,gcc:ws2_32
diff --git a/src/beast/README.md b/src/beast/README.md
index f5eaaeaad6..87612d41aa 100644
--- a/src/beast/README.md
+++ b/src/beast/README.md
@@ -2,7 +2,8 @@
[](https://travis-ci.org/vinniefalco/Beast) [![codecov]
(https://codecov.io/gh/vinniefalco/Beast/branch/master/graph/badge.svg)](https://codecov.io/gh/vinniefalco/Beast) [![Documentation]
-(https://img.shields.io/badge/documentation-master-brightgreen.svg)](http://vinniefalco.github.io/beast/)
+(https://img.shields.io/badge/documentation-master-brightgreen.svg)](http://vinniefalco.github.io/beast/) [![License]
+(https://img.shields.io/badge/license-boost-brightgreen.svg)](LICENSE_1_0.txt)
Beast provides implementations of the HTTP and WebSocket protocols
built on top of Boost.Asio and other parts of boost.
diff --git a/src/beast/TODO.txt b/src/beast/TODO.txt
index f830acf700..c848551631 100644
--- a/src/beast/TODO.txt
+++ b/src/beast/TODO.txt
@@ -32,6 +32,13 @@ WebSocket:
* Don't try to read requests into empty_body
* Give callers control over the http request/response used during handshake
* Investigate poor autobahn results in Debug builds
+* Fall through composed operation switch cases
+* Replace stream::error_ with stream::state_, example states: ok, error, abort_io
+ Need a cancel state so waking up a ping stored in invokable knows to call the
+ final handler with operation_aborted
+* Use close_code::no_code instead of close_code::none
+* Make request_type, response_type public APIs,
+ use in stream member function signatures
HTTP:
* Define Parser concept in HTTP
diff --git a/src/beast/doc/beast.qbk b/src/beast/doc/beast.qbk
index ffb0b52f7c..1b8cd35246 100644
--- a/src/beast/doc/beast.qbk
+++ b/src/beast/doc/beast.qbk
@@ -22,7 +22,6 @@
[template mdash[] '''— ''']
[template indexterm1[term1] ''''''[term1]'''''']
[template indexterm2[term1 term2] ''''''[term1]''''''[term2]'''''']
-[template ticket[number]''''''#[number]'''''']
[def __POSIX__ /POSIX/]
[def __Windows__ /Windows/]
[def __accept__ [@http://www.opengroup.org/onlinepubs/000095399/functions/accept.html `accept()`]]
@@ -191,8 +190,15 @@ supporting its development.
[include websocket.qbk]
[section:types Type Requirements]
-[include core_types.qbk]
-[include http_types.qbk]
+[include types/Body.qbk]
+[include types/BufferSequence.qbk]
+[include types/Field.qbk]
+[include types/FieldSequence.qbk]
+[include types/Parser.qbk]
+[include types/Reader.qbk]
+[include types/Streambuf.qbk]
+[include types/Streams.qbk]
+[include types/Writer.qbk]
[endsect]
[include design.qbk]
diff --git a/src/beast/doc/quickref.xml b/src/beast/doc/quickref.xml
index 20562e03f6..8aec05241c 100644
--- a/src/beast/doc/quickref.xml
+++ b/src/beast/doc/quickref.xml
@@ -41,14 +41,19 @@
Type Traits
+ is_Body
is_Parser
+ is_ReadableBody
+ is_WritableBody
Functions
+ async_parse
async_read
async_write
+ parse
prepare
read
write
@@ -62,6 +67,7 @@
Body
Field
FieldSequence
+ Parser
Reader
Writer
@@ -70,16 +76,20 @@
Classes
close_reason
+ ping_data
stream
+ reason_string
Options
auto_fragment_size
decorate
keep_alive
+ mask_buffer_size
+ message_type
+ pong_callback
read_buffer_size
read_message_max
- write_buffer_size
@@ -91,6 +101,7 @@
Constants
close_code
+ error
opcode
@@ -163,10 +174,10 @@
Concepts
BufferSequence
- AsyncStream
- Stream
+ AsyncStream
+ Stream
Streambuf
- SyncStream
+ SyncStream
diff --git a/src/beast/doc/reference.xsl b/src/beast/doc/reference.xsl
index f57b329160..0824f07747 100644
--- a/src/beast/doc/reference.xsl
+++ b/src/beast/doc/reference.xsl
@@ -1528,7 +1528,7 @@
- class ``[link beast.types.stream.AsyncStream [*AsyncStream]]``
+ class ``[link beast.types.streams.AsyncStream [*AsyncStream]]``
class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]``
@@ -1556,13 +1556,13 @@
class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]``
- class ``[link beast.types.stream.Stream [*Stream]]``
+ class ``[link beast.types.streams.Stream [*Stream]]``
class ``[link beast.types.Streambuf [*Streambuf]]``
- class ``[link beast.types.stream.SyncStream [*SyncStream]]``
+ class ``[link beast.types.streams.SyncStream [*SyncStream]]``
class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]``
diff --git a/src/beast/doc/types/Body.qbk b/src/beast/doc/types/Body.qbk
new file mode 100644
index 0000000000..95c91417a0
--- /dev/null
+++ b/src/beast/doc/types/Body.qbk
@@ -0,0 +1,50 @@
+[/
+ Copyright (c) 2013-2016 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)
+]
+
+[section:Body Body]
+
+In this table:
+
+* `X` is a type meeting the requirements of [*`Body`].
+
+[table Body requirements
+[[operation] [type] [semantics, pre/post-conditions]]
+[
+ [`X::value_type`]
+ []
+ [
+ The type of the `message::body` member.
+ If this is not movable or not copyable, the containing message
+ will be not movable or not copyable.
+ ]
+]
+[
+ [`X:value_type{}`]
+ []
+ [`DefaultConstructible`]
+]
+[
+ [`Body::reader`]
+ []
+ [
+ If present, a type meeting the requirements of
+ [link beast.types.Reader [*`Reader`]].
+ Provides an implementation to parse the body.
+ ]
+]
+[
+ [`Body::writer`]
+ []
+ [
+ If present, a type meeting the requirements of
+ [link beast.types.Writer [*`Writer`]].
+ Provides an implementation to serialize the body.
+ ]
+]
+]
+
+[endsect]
diff --git a/src/beast/doc/types/BufferSequence.qbk b/src/beast/doc/types/BufferSequence.qbk
new file mode 100644
index 0000000000..04457281b6
--- /dev/null
+++ b/src/beast/doc/types/BufferSequence.qbk
@@ -0,0 +1,15 @@
+[/
+ Copyright (c) 2013-2016 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)
+]
+
+[section:BufferSequence BufferSequence]
+
+A `BufferSequence` is a type meeting either of the following requirements:
+
+* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*`ConstBufferSequence`]]
+* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*`MutableBufferSequence`]]
+
+[endsect]
diff --git a/src/beast/doc/types/Field.qbk b/src/beast/doc/types/Field.qbk
new file mode 100644
index 0000000000..e5d8b22c6f
--- /dev/null
+++ b/src/beast/doc/types/Field.qbk
@@ -0,0 +1,41 @@
+[/
+ Copyright (c) 2013-2016 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)
+]
+
+[section:Field Field]
+
+A [*`Field`] represents a single HTTP header field/value pair.
+
+In this table:
+
+* `X` denotes a type meeting the requirements of [*`Field`].
+* `a` denotes a value of type `X`.
+
+[table Field requirements
+
+[[operation][type][semantics, pre/post-conditions]]
+[
+ [`a.name()`]
+ [`boost::string_ref`]
+ [
+ This function returns a value implicitly convertible to
+ `boost::string_ref` containing the case-insensitive field
+ name, without leading or trailing white space.
+ ]
+]
+[
+ [`a.value()`]
+ [`boost::string_ref`]
+ [
+ This function returns a value implicitly convertible to
+ `boost::string_ref` containing the value for the field. The
+ value is considered canonical if there is no leading or
+ trailing whitespace.
+ ]
+]
+]
+
+[endsect]
diff --git a/src/beast/doc/types/FieldSequence.qbk b/src/beast/doc/types/FieldSequence.qbk
new file mode 100644
index 0000000000..c0cd123bff
--- /dev/null
+++ b/src/beast/doc/types/FieldSequence.qbk
@@ -0,0 +1,51 @@
+[/
+ Copyright (c) 2013-2016 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)
+]
+
+[section:FieldSequence FieldSequence]
+
+A [*`FieldSequence`] is an iterable container whose value type meets
+the requirements of [link beast.types.Field [*`Field`]].
+
+In this table:
+
+* `X` denotes a type that meets the requirements of [*`FieldSequence`].
+
+* `a` is a value of type `X`.
+
+[table FieldSequence requirements
+[[operation][type][semantics, pre/post-conditions]]
+[
+ [`X::value_type`]
+ []
+ [
+ A type that meets the requirements of `Field`.
+ ]
+]
+[
+ [`X::const_iterator`]
+ []
+ [
+ A type that meets the requirements of `ForwardIterator`.
+ ]
+]
+[
+ [`a.begin()`]
+ [`X::const_iterator`]
+ [
+ Returns an iterator to the beginning of the field sequence.
+ ]
+]
+[
+ [`a.end()`]
+ [`X::const_iterator`]
+ [
+ Returns an iterator to the end of the field sequence.
+ ]
+]
+]
+
+[endsect]
diff --git a/src/beast/doc/types/Parser.qbk b/src/beast/doc/types/Parser.qbk
new file mode 100644
index 0000000000..0690f23f64
--- /dev/null
+++ b/src/beast/doc/types/Parser.qbk
@@ -0,0 +1,58 @@
+[/
+ Copyright (c) 2013-2016 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)
+]
+
+[section:Parser Parser]
+
+A [*`Parser`] is used to deserialize HTTP/1 messages from [link beast.types.streams streams].
+Objects of this type are used with [link beast.ref.http__parse http::parse] and
+[link beast.ref.http__async_parse http::async_parse].
+
+In this table:
+
+* `X` denotes a type meeting the requirements of [*`Parser`].
+
+* `a` denotes a value of type `X`.
+
+* `b` is a value meeting the requirements of [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConvertibleToConstBuffer.html [*`ConvertibleToConstBuffer`]].
+
+* `ec` is a value of type [link beast.ref.error_code `error_code&`].
+
+[table Parser requirements
+[[operation] [type] [semantics, pre/post-conditions]]
+[
+ [`a.complete()`]
+ [`bool`]
+ [
+ Returns `true` when a complete HTTP/1 message has been parsed.
+ ]
+]
+[
+ [`a.write(b, ec)`]
+ [`std::size_t`]
+ [
+ Parses the octets in the specified input buffer sequentially until
+ an error occurs, the end of the buffer is reached, or a complete
+ HTTP/1 message has been parsed. If an error occurs, `ec` is set
+ to the error code and parsing stops. This function returns the
+ number of bytes consumed from the input buffer.
+ ]
+]
+[
+ [`a.write_eof(ec)`]
+ [`void`]
+ [
+ Indicates to the parser that no more octets will be available.
+ Typically this function is called when the end of stream is reached.
+ For example, if a call to `boost::asio::ip::tcp::socket::read_some`
+ generates a `boost::asio::error::eof` error. Some HTTP/1 messages
+ determine the end of the message body by an end of file marker or
+ closing of the connection.
+ ]
+]
+]
+
+[endsect]
diff --git a/src/beast/doc/types/Reader.qbk b/src/beast/doc/types/Reader.qbk
new file mode 100644
index 0000000000..a94db4d0bb
--- /dev/null
+++ b/src/beast/doc/types/Reader.qbk
@@ -0,0 +1,54 @@
+[/
+ Copyright (c) 2013-2016 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)
+]
+
+[section:Reader Reader]
+
+Parser implementations will construct the corresponding `reader` object
+during the parse. This customization point allows the Body to determine
+the strategy for storing incoming message body data.
+
+In this table:
+
+* `X` denotes a type meeting the requirements of [*`Reader`].
+
+* `a` denotes a value of type `X`.
+
+* `p` is any pointer.
+
+* `n` is a value convertible to `std::size_t`.
+
+* `ec` is a value of type `error_code&`.
+
+* `m` denotes a value of type `message const&` where
+ `std::is_same:value == true`
+
+
+[table Reader requirements
+[[operation] [type] [semantics, pre/post-conditions]]
+[
+ [`X a(m);`]
+ []
+ [
+ `a` is constructible from `m`. The lifetime of `m` is
+ guaranteed to end no earlier than after `a` is destroyed.
+ ]
+]
+[
+ [`a.write(p, n, ec)`]
+ [`void`]
+ [
+ Deserializes the input sequence into the body.
+ If `ec` is set, the deserialization is aborted and the error
+ is returned to the caller.
+ ]
+]
+]
+
+[note Definitions for required `Reader` member functions should be declared
+inline so the generated code becomes part of the implementation. ]
+
+[endsect]
diff --git a/src/beast/doc/core_types.qbk b/src/beast/doc/types/Streambuf.qbk
similarity index 50%
rename from src/beast/doc/core_types.qbk
rename to src/beast/doc/types/Streambuf.qbk
index 1efe460b44..60bf88ed27 100644
--- a/src/beast/doc/core_types.qbk
+++ b/src/beast/doc/types/Streambuf.qbk
@@ -5,54 +5,32 @@
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
]
-
-
-[section:BufferSequence BufferSequence]
-
-A `BufferSequence` is a type meeting either of the following requirements:
-
-* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*`ConstBufferSequence`]]
-* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*`MutableBufferSequence`]]
-
-[endsect]
-
-
-
-[section:stream Streams]
-
-Stream types represent objects capable of performing synchronous or
-asynchronous I/O. They are based on concepts from `boost::asio`.
-
-[heading:Stream Stream]
-
-A type modeling [*`Stream`] meets either or both of the following requirements:
-
-* [link beast.types.stream.AsyncStream [*`AsyncStream`]]
-* [link beast.types.stream.SyncStream [*`SyncStream`]]
-
-[heading:AsyncStream AsyncStream]
-
-A type modeling [*`AsyncStream`] meets the following requirements:
-
-* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html [*`AsyncReadStream`]]
-* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*`AsyncWriteStream`]]
-
-[heading:SyncStream SyncStream]
-
-A type modeling [*`SyncStream`] meets the following requirements:
-
-* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html [*`SyncReadStream`]]
-* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html [*`SyncWriteStream`]]
-
-[endsect]
-
-
-
[section:Streambuf Streambuf]
+A [*`Streambuf`] represents a logical octet sequence divided in two sections,
+the input sequence and the output sequence. Octets are written to the output
+sequence, then moved to the input sequence where they are available for
+reading. When some or all of the input sequence is no longer needed, it may
+be consumed.
+
+The interface to this concept is intended to permit the following
+implementation strategies:
+
+* A single contiguous octet array, which is reallocated as necessary to
+ accommodate changes in the size of the octet sequence.
+
+* A sequence of one or more octet arrays, where each array is of the same
+ size. Additional octet array objects are appended to the sequence to
+ accommodate changes in the size of the octet sequence.
+
+* A sequence of one or more octet arrays of varying sizes. Additional octet
+ array objects are appended to the sequence to accommodate changes in the
+ size of the character sequence. This is the implementation approached
+ currently offered by [link beast.ref.basic_streambuf `basic_streambuf`].
+
In the table below:
-* `X` denotes a class
+* `X` denotes a class meeting the requirements of [*`Streambuf`]
* `a` denotes a value of type `X`
* `n` denotes a value convertible to `std::size_t`
* `U`, `T` denote unspecified types.
@@ -62,12 +40,12 @@ In the table below:
[
[`X::const_buffers_type`]
[`T`]
- [`T` meets the requirements for `ConstBufferSequence`.]
+ [`T` meets the requirements for [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConstBufferSequence.html `ConstBufferSequence`].]
]
[
[`X::mutable_buffers_type`]
[`U`]
- [`U` meets the requirements for `MutableBufferSequence`.]
+ [`U` meets the requirements for [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/MutableBufferSequence.html `MutableBufferSequence`].]
]
[
[`a.commit(n)`]
@@ -98,7 +76,7 @@ In the table below:
[
[`a.max_size()`]
[`std::size_t`]
- [Returns the maximum size of the `Streambuf`.]
+ [Returns the maximum size of the stream buffer.]
]
[
[`read_size_helper(a, n)`]
diff --git a/src/beast/doc/types/Streams.qbk b/src/beast/doc/types/Streams.qbk
new file mode 100644
index 0000000000..fb0920a106
--- /dev/null
+++ b/src/beast/doc/types/Streams.qbk
@@ -0,0 +1,34 @@
+[/
+ Copyright (c) 2013-2016 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)
+]
+
+[section:streams Streams]
+
+Stream types represent objects capable of performing synchronous or
+asynchronous I/O. They are based on concepts from `boost::asio`.
+
+[heading:Stream Stream]
+
+A type modeling [*`Stream`] meets either or both of the following requirements:
+
+* [*`AsyncStream`]
+* [*`SyncStream`]
+
+[heading:AsyncStream AsyncStream]
+
+A type modeling [*`AsyncStream`] meets the following requirements:
+
+* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncReadStream.html [*`AsyncReadStream`]]
+* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*`AsyncWriteStream`]]
+
+[heading:SyncStream SyncStream]
+
+A type modeling [*`SyncStream`] meets the following requirements:
+
+* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/SyncReadStream.html [*`SyncReadStream`]]
+* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/SyncWriteStream.html [*`SyncWriteStream`]]
+
+[endsect]
diff --git a/src/beast/doc/http_types.qbk b/src/beast/doc/types/Writer.qbk
similarity index 60%
rename from src/beast/doc/http_types.qbk
rename to src/beast/doc/types/Writer.qbk
index bf5f6a349a..f27565272f 100644
--- a/src/beast/doc/http_types.qbk
+++ b/src/beast/doc/types/Writer.qbk
@@ -5,199 +5,6 @@
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
]
-
-
-[section:Body Body]
-
-In this table:
-
-* `X` is a type meeting the requirements of [*`Body`].
-
-[table Body requirements
-[[operation] [type] [semantics, pre/post-conditions]]
-[
- [`X::value_type`]
- []
- [
- The type of the `message::body` member.
- If this is not movable or not copyable, the containing message
- will be not movable or not copyable.
- ]
-]
-[
- [`X:value_type{}`]
- []
- [`DefaultConstructible`]
-]
-[
- [`Body::reader`]
- []
- [
- If present, a type meeting the requirements of
- [link beast.types.Reader [*`Reader`]].
- Provides an implementation to parse the body.
- ]
-]
-[
- [`Body::writer`]
- []
- [
- If present, a type meeting the requirements of
- [link beast.types.Writer [*`Writer`]].
- Provides an implementation to serialize the body.
- ]
-]
-]
-
-[endsect]
-
-
-
-[section:BufferSequence BufferSequence]
-
-A `BufferSequence` is a type meeting either of the following requirements:
-
-* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*`ConstBufferSequence`]]
-* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*`MutableBufferSequence`]]
-
-[endsect]
-
-
-
-[section:Field Field]
-
-A [*`Field`] represents a single HTTP header field/value pair.
-
-In this table:
-
-* `X` denotes a type meeting the requirements of [*`Field`].
-* `a` denotes a value of type `X`.
-
-[table Field requirements
-
-[[operation][type][semantics, pre/post-conditions]]
-[
- [`a.name()`]
- [`boost::string_ref`]
- [
- This function returns a value implicitly convertible to
- `boost::string_ref` containing the case-insensitve field
- name, without leading or trailing white space.
- ]
-]
-[
- [`a.value()`]
- [`boost::string_ref`]
- [
- This function returns a value implicitly convertible to
- `boost::string_ref` containing the value for the field. The
- value is considered canonical if there is no leading or
- trailing whitespace.
- ]
-]
-]
-
-[endsect]
-
-
-
-[section:FieldSequence FieldSequence]
-
-A [*`FieldSequence`] is an iterable container whose value type meets
-the requirements of [link beast.types.Field [*`Field`]].
-
-In this table:
-
-* `X` denotes a type that meets the requirements of [*`FieldSequence`].
-
-* `a` is a value of type `X`.
-
-[table FieldSequence requirements
-[[operation][type][semantics, pre/post-conditions]]
-[
- [`X::value_type`]
- []
- [
- A type that meets the requirements of `Field`.
- ]
-]
-[
- [`X::const_iterator`]
- []
- [
- A type that meets the requirements of `ForwardIterator`.
- ]
-]
-[
- [`a.begin()`]
- [`X::const_iterator`]
- [
- Returns an iterator to the beginning of the field sequence.
- ]
-]
-[
- [`a.end()`]
- [`X::const_iterator`]
- [
- Returns an iterator to the end of the field sequence.
- ]
-]
-]
-
-[endsect]
-
-
-
-[section:Reader Reader]
-
-Parser implementations will construct the corresponding `reader` object
-during the parse. This customization point allows the Body to determine
-the strategy for storing incoming message body data.
-
-In this table:
-
-* `X` denotes a type meeting the requirements of [*`Reader`].
-
-* `a` denotes a value of type `X`.
-
-* `p` is any pointer.
-
-* `n` is a value convertible to `std::size_t`.
-
-* `ec` is a value of type `error_code&`.
-
-* `m` denotes a value of type `message const&` where
- `std::is_same:value == true`
-
-
-[table Reader requirements
-[[operation] [type] [semantics, pre/post-conditions]]
-[
- [`X a(m);`]
- []
- [
- `a` is constructible from `m`. The lifetime of `m` is
- guaranteed to end no earlier than after `a` is destroyed.
- ]
-]
-[
- [`a.write(p, n, ec)`]
- [`void`]
- [
- Deserializes the input sequence into the body.
- If `ec` is set, the deserialization is aborted and the error
- is returned to the caller.
- ]
-]
-]
-
-[note Definitions for required `Reader` member functions should be declared
-inline so the generated code becomes part of the implementation. ]
-
-[endsect]
-
-
-
[section:Writer Writer]
A `Writer` serializes the message body. The implementation creates an instance
@@ -370,4 +177,3 @@ public:
```
[endsect]
-
diff --git a/src/beast/doc/websocket.qbk b/src/beast/doc/websocket.qbk
index 80eb0b580e..617deb2a5b 100644
--- a/src/beast/doc/websocket.qbk
+++ b/src/beast/doc/websocket.qbk
@@ -46,13 +46,15 @@ model, handler allocation, and handler invocation hooks. Calls to
Beast.WebSocket asynchronous initiation functions allow callers the choice
of using a completion handler, stackful or stackless coroutines, futures,
or user defined customizations (for example, Boost.Fiber). The
-implementation uses handler invocation hooks (`asio_handler_invoke`),
+implementation uses handler invocation hooks
+([@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]),
providing execution guarantees on composed operations in a manner
-identical to Boost.Asio. The implementation also uses handler allocation
-hooks (`asio_handler_allocate`) when allocating memory internally for
-composed operations.
+identical to Boost.Asio. The implementation also uses handler allocation hooks
+([@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`])
+when allocating memory internally for composed operations.
-There is no need for inheritance or virtual members in `websocket::stream`.
+There is no need for inheritance or virtual members in a
+[link beast.ref.websocket__stream `beast::websocket::stream`].
All operations are templated and transparent to the compiler, allowing for
maximum inlining and optimization.
@@ -67,43 +69,47 @@ both Boost.Asio and the WebSocket protocol specification described in
[section:creating Creating the socket]
The interface to Beast's WebSocket implementation is a single template
-class [link beast.ref.websocket__stream `websocket::stream`] which wraps a
-"next layer" object. The next layer object must meet the requirements of
-`SyncReadStream` and `SyncWriteStream` if synchronous operations are performed,
-`AsyncReadStream` and `AsyncWriteStream` is asynchronous operations are
-performed, or both. Arguments supplied during construction are passed to
-next layer's constructor. Here we declare two websockets which have ownership
-of the next layer:
+class [link beast.ref.websocket__stream `beast::websocket::stream`] which
+wraps a "next layer" object. The next layer object must meet the requirements
+of [link beast.types.streams.SyncStream [*`SyncReadStream`]] if synchronous
+operations are performed, or
+[link beast.types.streams.AsyncStream [*`AsyncStream`]] if asynchronous
+operations are performed, or both. Arguments supplied during construction are
+passed to next layer's constructor. Here we declare two websockets which have
+ownership of the next layer:
```
-io_service ios;
-websocket::stream ws(ios);
+boost::asio::io_service ios;
+beast::websocket::stream ws(ios);
-ssl::context ctx(ssl::context::sslv23);
-websocket::stream> wss(ios, ctx);
+boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
+beast::websocket::stream<
+ boost::asio::ssl::stream> wss(ios, ctx);
```
For servers that can handshake in multiple protocols, it may be desired
to wrap an object that already exists. This socket can be moved in:
```
- tcp::socket&& sock;
+ boost::asio::ip::tcp::socket&& sock;
...
- websocket::stream ws(std::move(sock));
+ beast::websocket::stream<
+ boost::asio::ip::tcp::socket> ws(std::move(sock));
```
Or, the wrapper can be constructed with a non-owning reference. In
this case, the caller is responsible for managing the lifetime of the
underlying socket being wrapped:
```
- tcp::socket sock;
+ boost::asio::ip::tcp::socket sock;
...
- websocket::stream ws(sock);
+ beast::websocket::stream ws(sock);
```
The layer being wrapped can be accessed through the websocket's "next layer",
permitting callers to interact directly with its interface.
```
- ssl::context ctx(ssl::context::sslv23);
- websocket::stream> ws(ios, ctx);
+ boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
+ beast::websocket::stream<
+ boost::asio::ssl::stream> ws(ios, ctx);
...
ws.next_layer().shutdown(); // ssl::stream shutdown
```
@@ -122,17 +128,18 @@ Connections are established by using the interfaces which already exist
for the next layer. For example, making an outgoing connection:
```
std::string const host = "mywebapp.com";
- io_service ios;
- tcp::resolver r(ios);
- websocket::stream ws(ios);
- connect(ws.next_layer(), r.resolve(tcp::resolver::query{host, "ws"}));
+ boost::asio::io_service ios;
+ boost::asio::ip::tcp::resolver r(ios);
+ beast::websocket::stream ws(ios);
+ boost::asio::connect(ws.next_layer(),
+ r.resolve(boost::asio::ip::tcp::resolver::query{host, "ws"}));
```
Accepting an incoming connection:
```
-void do_accept(tcp::acceptor& acceptor)
+void do_accept(boost::asio::ip::tcp::acceptor& acceptor)
{
- websocket::stream ws(acceptor.get_io_service());
+ beast::websocket::stream ws(acceptor.get_io_service());
acceptor.accept(ws.next_layer());
}
```
@@ -149,26 +156,26 @@ A WebSocket session begins when one side sends the HTTP Upgrade request
for websocket, and the other side sends an appropriate HTTP response
indicating that the request was accepted and that the connection has
been upgraded. The HTTP Upgrade request must include the Host HTTP field,
-and the URI of the resource to request. `hanshake` is used to send the
+and the URI of the resource to request. `handshake` is used to send the
request with the required host and resource strings.
```
- websocket::stream ws(ios);
+ beast::websocket::stream ws(ios);
...
- ws.set_option(websocket::keep_alive(true));
- ws.handshake("ws.mywebapp.com:80", "/cgi-bin/bitcoin-prices");
+ ws.set_option(beast::websocket::keep_alive(true));
+ ws.handshake("ws.example.com:80", "/cgi-bin/bitcoin-prices");
```
-The `websocket::stream` automatically handles receiving and processing
-the HTTP response to the handshake request. The call to handshake is
-successful if a HTTP response is received with the 101 "Switching Protocols"
-status code. On failure, an error is returned or an exception is thrown.
-Depending on the keep alive setting, the socket may remain open for a
-subsequent handshake attempt
+The [link beast.ref.websocket__stream `beast::websocket::stream`] automatically
+handles receiving and processing the HTTP response to the handshake request.
+The call to handshake is successful if a HTTP response is received with the
+101 "Switching Protocols" status code. On failure, an error is returned or an
+exception is thrown. Depending on the keep alive setting, the socket may remain
+open for a subsequent handshake attempt
Performing a handshake for an incoming websocket upgrade request operates
similarly. If the handshake fails, an error is returned or exception thrown:
```
- websocket::stream ws(ios);
+ beast::websocket::stream ws(ios);
...
ws.accept();
```
@@ -178,12 +185,12 @@ on the connection, or might have already received an entire HTTP request
containing the upgrade request. Overloads of `accept` allow callers to
pass in this additional buffered handshake data.
```
-void do_accept(tcp::socket& sock)
+void do_accept(boost::asio::ip::tcp::socket& sock)
{
boost::asio::streambuf sb;
- read_until(sock, sb, "\r\n\r\n");
+ boost::asio::read_until(sock, sb, "\r\n\r\n");
...
- websocket::stream ws(sock);
+ beast::websocket::stream ws(sock);
ws.accept(sb.data());
...
}
@@ -192,12 +199,12 @@ void do_accept(tcp::socket& sock)
Alternatively, the caller can pass an entire HTTP request if it was
obtained elsewhere:
```
-void do_accept(tcp::socket& sock)
+void do_accept(boost::asio::ip::tcp::socket& sock)
{
boost::asio::streambuf sb;
- http::request request;
- http::read(sock, request);
- if(http::is_upgrade(request))
+ beast::http::request request;
+ beast::http::read(sock, request);
+ if(beast::http::is_upgrade(request))
{
websocket::stream ws(sock);
ws.accept(request);
@@ -206,8 +213,6 @@ void do_accept(tcp::socket& sock)
}
```
-[note Identifiers in the `http` namespace are part of Beast.HTTP. ]
-
[endsect]
@@ -218,20 +223,21 @@ After the WebSocket handshake is accomplished, callers may send and receive
messages using the message oriented interface. This interface requires that
all of the buffers representing the message are known ahead of time:
```
-void echo(websocket::stream& ws)
+void echo(beast::websocket::stream& ws)
{
- streambuf sb;
- websocket::opcode::value op;
+ beast::streambuf sb;
+ beast::websocket::opcode::value op;
ws.read(sb);
- ws.set_option(websocket::message_type(op));
- websocket::write(ws, sb.data());
+ ws.set_option(beast::websocket::message_type(op));
+ ws.write(sb.data());
sb.consume(sb.size());
}
```
-[important Calls to `set_option` must be made from the same implicit
-or explicit strand as that used to perform other operations. ]
+[important Calls to [link beast.ref.websocket__stream.set_option `set_option`]
+must be made from the same implicit or explicit strand as that used to perform
+other operations. ]
[endsect]
@@ -249,18 +255,19 @@ message ahead of time:
For these cases, the frame oriented interface may be used. This
example reads and echoes a complete message using this interface:
```
-void echo(websocket::stream& ws)
+void echo(beast::websocket::stream& ws)
{
- streambuf sb;
- websocket::frame_info fi;
+ beast::streambuf sb;
+ beast::websocket::frame_info fi;
for(;;)
{
ws.read_frame(fi, sb);
if(fi.fin)
break;
}
- ws.set_option(websocket::message_type(fi.op));
- consuming_buffers cb(sb.data());
+ ws.set_option(beast::websocket::message_type(fi.op));
+ beast::consuming_buffers<
+ beast::streambuf::const_buffers_type> cb(sb.data());
for(;;)
{
using boost::asio::buffer_size;
@@ -287,10 +294,11 @@ void echo(websocket::stream& ws)
During read operations, the implementation automatically reads and processes
WebSocket control frames such as ping, pong, and close. Pings are replied
-to as soon as possible, pongs are noted. The receipt of a close frame
-initiates the WebSocket close procedure, eventually resulting in the
-error code `websocket::error::closed` being delivered to the caller in
-a subsequent read operation, assuming no other error takes place.
+to as soon as possible, pongs are delivered to the pong callback. The receipt
+of a close frame initiates the WebSocket close procedure, eventually resulting
+in the error code [link beast.ref.websocket__error `error::closed`] being
+delivered to the caller in a subsequent read operation, assuming no other error
+takes place.
To ensure timely delivery of control frames, large messages are broken up
into smaller sized frames. The implementation chooses the size and number
@@ -298,19 +306,49 @@ of the frames making up the message. The automatic fragment size option
gives callers control over the size of these frames:
```
...
- ws.set_option(websocket::auto_fragment_size(8192));
+ ws.set_option(beast::websocket::auto_fragment_size(8192));
```
The WebSocket protocol defines a procedure and control message for initiating
a close of the session. Handling of close initiated by the remote end of the
connection is performed automatically. To manually initiate a close, use
-`websocket::stream::close`:
+[link beast.ref.websocket__stream.close `close`]:
```
ws.close();
```
-[note To receive the `websocket::error::closed` error, a read operation
-is required. ]
+[note To receive the [link beast.ref.websocket__error `error::closed`]
+error, a read operation is required. ]
+
+[endsect]
+
+
+
+[section:pongs Pong messages]
+
+To receive pong control frames, callers may register a "pong callback" using
+[link beast.ref.websocket__stream.set_option `set_option`]:
+
+the following signature:
+```
+ void on_pong(ping_data const& payload);
+ ...
+ ws.set_option(pong_callback{&on_pong});
+```
+
+When a pong callback is registered, any pongs received through either
+synchronous read functions or asynchronous read functions will invoke the
+pong callback, passing the payload in the pong message as the argument.
+
+Unlike regular completion handlers used in calls to asynchronous initiation
+functions, the pong callback only needs to be set once. The callback is not
+reset when a pong is received. The same callback is used for both synchronous
+and asynchronous reads. The pong callback is passive; in order to receive
+pongs, a synchronous or asynchronous stream read function must be active.
+
+[note When an asynchronous read function receives a pong, the the pong callback
+is invoked in the same manner as that used to invoke the final completion
+handler of the corresponding read function.]
[endsect]
@@ -320,7 +358,8 @@ is required. ]
Because calls to read data may return a variable amount of bytes, the
interface to calls that read data require an object that meets the requirements
-of `Streambuf`. This concept is modeled on `boost::asio::basic_streambuf`.
+of [link beast.types.Streambuf [*`Streambuf`]]. This concept is modeled on
+[@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/basic_streambuf.html `boost::asio::basic_streambuf`].
The implementation does not perform queueing or buffering of messages. If
desired, these features should be provided by callers. The impact of this
@@ -331,6 +370,7 @@ of the underlying TCP/IP connection.
[endsect]
+
[section:async Asynchronous interface]
Asynchronous versions are available for all functions:
@@ -361,12 +401,14 @@ void echo(websocket::stream& ws,
-[section:io_service io_service]
+[section:io_service The io_service]
-The creation and operation of the `boost::asio::io_service` associated with
-the underlying stream is left to the callers, permitting any implementation
-strategy including one that does not require threads for environments where
-threads are unavailable. Beast.WSProto itself does not use or require threads.
+The creation and operation of the
+[@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/io_service.html `boost::asio::io_service`]
+associated with the underlying stream is left to the callers, permitting any
+implementation strategy including one that does not require threads for
+environments where threads are unavailable. Beast.WebSocket itself does not
+use or require threads.
[endsect]
@@ -374,13 +416,13 @@ threads are unavailable. Beast.WSProto itself does not use or require threads.
[section:safety Thread Safety]
-Like a regular asio socket, a `websocket::stream` is not thread safe. Callers
-are responsible for synchronizing operations on the socket using an implicit
-or explicit strand, as per the Asio documentation. The asynchronous interface
-supports one active read and one active write simultaneously. Undefined
-behavior results if two or more reads or two or more writes are attempted
-concurrently. Caller initiated WebSocket ping, pong, and close operations
-each count as an active write.
+Like a regular asio socket, a [link beast.ref.websocket__stream `stream`] is
+not thread safe. Callers are responsible for synchronizing operations on the
+socket using an implicit or explicit strand, as per the Asio documentation.
+The asynchronous interface supports one active read and one active write
+simultaneously. Undefined behavior results if two or more reads or two or
+more writes are attempted concurrently. Caller initiated WebSocket ping, pong,
+and close operations each count as an active write.
The implementation uses composed asynchronous operations internally; a high
level read can cause both reads and writes to take place on the underlying
diff --git a/src/beast/extras/beast/test/fail_stream.hpp b/src/beast/extras/beast/test/fail_stream.hpp
index 594bc7098e..2bbfaf1e14 100644
--- a/src/beast/extras/beast/test/fail_stream.hpp
+++ b/src/beast/extras/beast/test/fail_stream.hpp
@@ -157,25 +157,35 @@ public:
return next_layer_.async_write_some(buffers,
std::forward(handler));
}
+
+ friend
+ void
+ teardown(fail_stream& stream,
+ boost::system::error_code& ec)
+ {
+ if(stream.pfc_->fail(ec))
+ return;
+ websocket_helpers::call_teardown(stream.next_layer(), ec);
+ }
+
+ template
+ friend
+ void
+ async_teardown(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;
+ }
+ websocket_helpers::call_async_teardown(
+ stream.next_layer(), std::forward(handler));
+ }
};
-template
-void
-teardown(fail_stream& stream,
- boost::system::error_code& ec)
-{
- websocket_helpers::call_teardown(stream.next_layer(), ec);
-}
-
-template
-void
-async_teardown(fail_stream& stream,
- TeardownHandler&& handler)
-{
- websocket_helpers::call_async_teardown(
- stream.next_layer(), std::forward(handler));
-}
-
} // test
} // beast
diff --git a/src/beast/extras/beast/unit_test/abstract_ostream.hpp b/src/beast/extras/beast/unit_test/abstract_ostream.hpp
deleted file mode 100644
index 8a41841a61..0000000000
--- a/src/beast/extras/beast/unit_test/abstract_ostream.hpp
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// Copyright (c) 2013-2016 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_UNIT_TEST_ABSTRACT_OSTREAM_HPP
-#define BEAST_UNIT_TEST_ABSTRACT_OSTREAM_HPP
-
-#include
-
-namespace beast {
-
-/** An abstract ostream for `char`. */
-using abstract_ostream = basic_abstract_ostream ;
-
-} // beast
-
-#endif
diff --git a/src/beast/extras/beast/unit_test/basic_abstract_ostream.hpp b/src/beast/extras/beast/unit_test/basic_abstract_ostream.hpp
deleted file mode 100644
index 6a3a7222b3..0000000000
--- a/src/beast/extras/beast/unit_test/basic_abstract_ostream.hpp
+++ /dev/null
@@ -1,85 +0,0 @@
-//
-// Copyright (c) 2013-2016 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_UNIT_TEST_BASIC_ABSTRACT_OSTREAM_HPP
-#define BEAST_UNIT_TEST_BASIC_ABSTRACT_OSTREAM_HPP
-
-#include
-#include
-#include
-#include
-
-namespace beast {
-
-/** Abstraction for an output stream similar to std::basic_ostream. */
-template <
- class CharT,
- class Traits = std::char_traits
->
-class basic_abstract_ostream
-{
-public:
- using string_type = std::basic_string ;
- using scoped_stream_type = basic_scoped_ostream ;
-
- basic_abstract_ostream() = default;
-
- virtual
- ~basic_abstract_ostream() = default;
-
- basic_abstract_ostream (basic_abstract_ostream const&) = default;
- basic_abstract_ostream& operator= (
- basic_abstract_ostream const&) = default;
-
- /** Returns `true` if the stream is active.
- Inactive streams do not produce output.
- */
- /** @{ */
- virtual
- bool
- active() const
- {
- return true;
- }
-
- explicit
- operator bool() const
- {
- return active();
- }
- /** @} */
-
- /** Called to output each string. */
- virtual
- void
- write (string_type const& s) = 0;
-
- scoped_stream_type
- operator<< (std::ostream& manip (std::ostream&))
- {
- return scoped_stream_type (manip,
- [this](string_type const& s)
- {
- this->write (s);
- });
- }
-
- template
- scoped_stream_type
- operator<< (T const& t)
- {
- return scoped_stream_type (t,
- [this](string_type const& s)
- {
- this->write (s);
- });
- }
-};
-
-} // beast
-
-#endif
diff --git a/src/beast/extras/beast/unit_test/basic_scoped_ostream.hpp b/src/beast/extras/beast/unit_test/basic_scoped_ostream.hpp
deleted file mode 100644
index c8283a521b..0000000000
--- a/src/beast/extras/beast/unit_test/basic_scoped_ostream.hpp
+++ /dev/null
@@ -1,136 +0,0 @@
-//
-// Copyright (c) 2013-2016 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_UNIT_TEST_BASIC_SCOPED_OSTREAM_HPP
-#define BEAST_UNIT_TEST_BASIC_SCOPED_OSTREAM_HPP
-
-#include
-#include
-#include
-
-// gcc libstd++ doesn't have move constructors for basic_ostringstream
-// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
-//
-#ifndef BEAST_NO_STDLIB_STREAM_MOVE
-# ifdef __GLIBCXX__
-# define BEAST_NO_STDLIB_STREAM_MOVE 1
-# else
-# define BEAST_NO_STDLIB_STREAM_MOVE 0
-# endif
-#endif
-
-namespace beast {
-
-template <
- class CharT,
- class Traits
->
-class basic_abstract_ostream;
-
-/** Scoped output stream that forwards to a functor upon destruction. */
-template <
- class CharT,
- class Traits = std::char_traits ,
- class Allocator = std::allocator
->
-class basic_scoped_ostream
-{
-private:
- using handler_t = std::function const&)>;
-
- using stream_type = std::basic_ostringstream <
- CharT, Traits, Allocator>;
-
- handler_t m_handler;
-
-#if BEAST_NO_STDLIB_STREAM_MOVE
- std::unique_ptr m_ss;
-
- stream_type& stream()
- {
- return *m_ss;
- }
-
-#else
- stream_type m_ss;
-
- stream_type& stream()
- {
- return m_ss;
- }
-
-#endif
-
-public:
- using string_type = std::basic_string ;
-
- // Disallow copy since that would duplicate the output
- basic_scoped_ostream (basic_scoped_ostream const&) = delete;
- basic_scoped_ostream& operator= (basic_scoped_ostream const) = delete;
-
- template
- explicit basic_scoped_ostream (Handler&& handler)
- : m_handler (std::forward (handler))
- #if BEAST_NO_STDLIB_STREAM_MOVE
- , m_ss (new stream_type())
- #endif
- {
- }
-
- template
- basic_scoped_ostream (T const& t, Handler&& handler)
- : m_handler (std::forward (handler))
- #if BEAST_NO_STDLIB_STREAM_MOVE
- , m_ss (new stream_type())
- #endif
- {
- stream() << t;
- }
-
- basic_scoped_ostream (basic_abstract_ostream <
- CharT, Traits>& ostream)
- : m_handler (
- [&](string_type const& s)
- {
- ostream.write (s);
- })
- {
- }
-
- basic_scoped_ostream (basic_scoped_ostream&& other)
- : m_handler (std::move (other.m_handler))
- , m_ss (std::move (other.m_ss))
- {
- }
-
- ~basic_scoped_ostream()
- {
- auto const& s (stream().str());
- if (! s.empty())
- m_handler (s);
- }
-
- basic_scoped_ostream&
- operator<< (std::ostream& manip (std::ostream&))
- {
- stream() << manip;
- return *this;
- }
-
- template
- basic_scoped_ostream&
- operator<< (T const& t)
- {
- stream() << t;
- return *this;
- }
-};
-
-} // beast
-
-#endif
diff --git a/src/beast/extras/beast/unit_test/basic_std_ostream.hpp b/src/beast/extras/beast/unit_test/basic_std_ostream.hpp
deleted file mode 100644
index 62b21966ab..0000000000
--- a/src/beast/extras/beast/unit_test/basic_std_ostream.hpp
+++ /dev/null
@@ -1,60 +0,0 @@
-//
-// Copyright (c) 2013-2016 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_UNIT_TEST_BASIC_STD_OSTREAM_HPP
-#define BEAST_UNIT_TEST_BASIC_STD_OSTREAM_HPP
-
-#include
-#include
-
-namespace beast {
-
-/** Wraps an existing std::basic_ostream as an abstract_ostream. */
-template <
- class CharT,
- class Traits = std::char_traits
->
-class basic_std_ostream
- : public basic_abstract_ostream
-{
-private:
- using typename basic_abstract_ostream ::string_type;
-
- std::reference_wrapper m_stream;
-
-public:
- explicit basic_std_ostream (
- std::basic_ostream & stream)
- : m_stream (stream)
- {
- }
-
- void
- write (string_type const& s) override
- {
- m_stream.get() << s << std::endl;
- }
-};
-
-using std_ostream = basic_std_ostream ;
-
-//------------------------------------------------------------------------------
-
-/** Returns a basic_std_ostream using template argument deduction. */
-template <
- class CharT,
- class Traits = std::char_traits
->
-basic_std_ostream
-make_std_ostream (std::basic_ostream & stream)
-{
- return basic_std_ostream (stream);
-}
-
-} // beast
-
-#endif
diff --git a/src/beast/extras/beast/unit_test/debug_ostream.hpp b/src/beast/extras/beast/unit_test/debug_ostream.hpp
deleted file mode 100644
index 60d19f8ef2..0000000000
--- a/src/beast/extras/beast/unit_test/debug_ostream.hpp
+++ /dev/null
@@ -1,78 +0,0 @@
-//
-// Copyright (c) 2013-2016 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_UNIT_TEST_DEBUG_OSTREAM_HPP
-#define BEAST_UNIT_TEST_DEBUG_OSTREAM_HPP
-
-#include
-#include
-
-#ifdef _MSC_VER
-# ifndef WIN32_LEAN_AND_MEAN // VC_EXTRALEAN
-# define WIN32_LEAN_AND_MEAN
-#include
-# undef WIN32_LEAN_AND_MEAN
-# else
-#include
-# endif
-# ifdef min
-# undef min
-# endif
-# ifdef max
-# undef max
-# endif
-#endif
-
-namespace beast {
-
-#ifdef _MSC_VER
-/** A basic_abstract_ostream that redirects output to an attached debugger. */
-class debug_ostream
- : public abstract_ostream
-{
-private:
- bool m_debugger;
-
-public:
- debug_ostream()
- : m_debugger (IsDebuggerPresent() != FALSE)
- {
- // Note that the check for an attached debugger is made only
- // during construction time, for efficiency. A stream created before
- // the debugger is attached will not have output redirected.
- }
-
- void
- write (string_type const& s) override
- {
- if (m_debugger)
- {
- OutputDebugStringA ((s + "\n").c_str());
- return;
- }
-
- std::cout << s << std::endl;
- }
-};
-
-#else
-class debug_ostream
- : public abstract_ostream
-{
-public:
- void
- write (string_type const& s) override
- {
- std::cout << s << std::endl;
- }
-};
-
-#endif
-
-} // beast
-
-#endif
diff --git a/src/beast/extras/beast/unit_test/dstream.hpp b/src/beast/extras/beast/unit_test/dstream.hpp
new file mode 100644
index 0000000000..2bd8e59032
--- /dev/null
+++ b/src/beast/extras/beast/unit_test/dstream.hpp
@@ -0,0 +1,144 @@
+//
+// Copyright (c) 2013-2016 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_UNIT_TEST_DSTREAM_HPP
+#define BEAST_UNIT_TEST_DSTREAM_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef _MSC_VER
+# ifndef NOMINMAX
+# define NOMINMAX 1
+# endif
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include
+# undef WIN32_LEAN_AND_MEAN
+# undef NOMINMAX
+#endif
+
+namespace beast {
+namespace unit_test {
+
+namespace detail {
+
+#ifdef _MSC_VER
+
+template
+class dstream_buf
+ : public std::basic_stringbuf
+{
+ bool dbg_;
+
+ template
+ void write(T const*) = delete;
+
+ void write(char const* s)
+ {
+ if(dbg_)
+ OutputDebugStringA(s);
+ else
+ std::cout << s;
+ }
+
+ void write(wchar_t const* s)
+ {
+ if(dbg_)
+ OutputDebugStringW(s);
+ else
+ std::wcout << s;
+ }
+
+public:
+ dstream_buf()
+ : dbg_(IsDebuggerPresent() != FALSE)
+ {
+ }
+
+ ~dstream_buf()
+ {
+ sync();
+ }
+
+ int
+ sync() override
+ {
+ write(this->str().c_str());
+ this->str("");
+ return 0;
+ }
+};
+
+#else
+
+template
+class dstream_buf
+ : public std::basic_stringbuf
+{
+ template
+ void write(T const*) = delete;
+
+ void write(char const* s)
+ {
+ std::cout << s;
+ }
+
+ void write(wchar_t const* s)
+ {
+ std::wcout << s;
+ }
+
+public:
+ ~dstream_buf()
+ {
+ sync();
+ }
+
+ int
+ sync() override
+ {
+ write(this->str().c_str());
+ this->str("");
+ return 0;
+ }
+};
+
+#endif
+
+} // detail
+
+/// A std::ostream that redirects output to the debugger if attached.
+template<
+ class CharT,
+ class Traits = std::char_traits,
+ class Allocator = std::allocator
+>
+class basic_dstream
+ : private boost::base_from_member<
+ detail::dstream_buf>
+ , public std::basic_ostream
+{
+public:
+ basic_dstream()
+ : std::basic_ostream(&this->member)
+ {
+ }
+};
+
+using dstream = basic_dstream;
+using dwstream = basic_dstream;
+
+} // test
+} // beast
+
+#endif
diff --git a/src/beast/extras/beast/unit_test/global_suites.hpp b/src/beast/extras/beast/unit_test/global_suites.hpp
index c1f8525210..f6e1ab2cf1 100644
--- a/src/beast/extras/beast/unit_test/global_suites.hpp
+++ b/src/beast/extras/beast/unit_test/global_suites.hpp
@@ -15,7 +15,8 @@ namespace unit_test {
namespace detail {
-template
+/// Holds test suites registered during static initialization.
+inline
suite_list&
global_suites()
{
@@ -23,26 +24,20 @@ global_suites()
return s;
}
-template
+template
struct insert_suite
{
- template
- insert_suite (char const* name, char const* module,
- char const* library, bool manual);
+ insert_suite(char const* name, char const* module,
+ char const* library, bool manual)
+ {
+ global_suites().insert(
+ name, module, library, manual);
+ }
};
-template
-template
-insert_suite::insert_suite (char const* name,
- char const* module, char const* library, bool manual)
-{
- global_suites().insert (
- name, module, library, manual);
-}
-
} // detail
-/** Holds suites registered during static initialization. */
+/// Holds test suites registered during static initialization.
inline
suite_list const&
global_suites()
diff --git a/src/beast/extras/beast/unit_test/main.cpp b/src/beast/extras/beast/unit_test/main.cpp
index 8cdf803ed9..d461ea83b3 100644
--- a/src/beast/extras/beast/unit_test/main.cpp
+++ b/src/beast/extras/beast/unit_test/main.cpp
@@ -6,12 +6,13 @@
//
#include
+#include
#include
#include
#include
#include
-#include
#include
+#include
#include
#include
@@ -25,11 +26,10 @@
# endif
#endif
-#include
-
namespace beast {
namespace unit_test {
+static
std::string
prefix(suite_info const& s)
{
@@ -38,32 +38,34 @@ prefix(suite_info const& s)
return " ";
}
-template
+static
void
-print(Log& log, suite_list const& c)
+print(std::ostream& os, suite_list const& c)
{
std::size_t manual = 0;
for(auto const& s : c)
{
- log <<
- prefix (s) <<
- s.full_name();
+ os << prefix (s) << s.full_name() << '\n';
if(s.manual())
++manual;
}
- log <<
+ os <<
amount(c.size(), "suite") << " total, " <<
- amount(manual, "manual suite")
+ amount(manual, "manual suite") <<
+ '\n'
;
}
-template
+// Print the list of suites
+// Used with the --print command line option
+static
void
-print(Log& log)
+print(std::ostream& os)
{
- log << "------------------------------------------";
- print(log, global_suites());
- log << "------------------------------------------";
+ os << "------------------------------------------\n";
+ print(os, global_suites());
+ os << "------------------------------------------" <<
+ std::endl;
}
} // unit_test
@@ -97,11 +99,11 @@ int main(int ac, char const* av[])
po::store(po::parse_command_line(ac, av, desc), vm);
po::notify(vm);
- beast::debug_ostream log;
+ dstream log;
if(vm.count("help"))
{
- log << desc;
+ log << desc << std::endl;
}
else if(vm.count("print"))
{
diff --git a/src/beast/extras/beast/unit_test/print.hpp b/src/beast/extras/beast/unit_test/print.hpp
deleted file mode 100644
index 0651e64bb9..0000000000
--- a/src/beast/extras/beast/unit_test/print.hpp
+++ /dev/null
@@ -1,67 +0,0 @@
-//
-// Copyright (c) 2013-2016 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_UNIT_TEST_PRINT_H_INCLUDED
-#define BEAST_UNIT_TEST_PRINT_H_INCLUDED
-
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-namespace beast {
-namespace unit_test {
-
-/** Write test results to the specified output stream. */
-/** @{ */
-template
-void
-print (results const& r, abstract_ostream& stream)
-{
- for (auto const& s : r)
- {
- for (auto const& c : s)
- {
- stream <<
- s.name() <<
- (c.name().empty() ? "" : ("." + c.name()));
-
- std::size_t i (1);
- for (auto const& t : c.tests)
- {
- if (! t.pass)
- stream <<
- "#" << i <<
- " failed: " << t.reason;
- ++i;
- }
- }
- }
-
- stream <<
- amount (r.size(), "suite") << ", " <<
- amount (r.cases(), "case") << ", " <<
- amount (r.total(), "test") << " total, " <<
- amount (r.failed(), "failure")
- ;
-}
-
-template
-void
-print (results const& r, std::ostream& stream = std::cout)
-{
- auto s (make_std_ostream (stream));
- print (r, s);
-}
-
-} // unit_test
-} // beast
-
-#endif
diff --git a/src/beast/extras/beast/unit_test/reporter.hpp b/src/beast/extras/beast/unit_test/reporter.hpp
index b5e27ef454..2d155946c9 100644
--- a/src/beast/extras/beast/unit_test/reporter.hpp
+++ b/src/beast/extras/beast/unit_test/reporter.hpp
@@ -10,8 +10,6 @@
#include
#include
-#include
-#include
#include
#include
#include
@@ -30,7 +28,7 @@ namespace detail {
/** A simple test runner that writes everything to a stream in real time.
The totals are output when the object is destroyed.
*/
-template
+template
class reporter : public runner
{
private:
@@ -42,7 +40,11 @@ private:
std::size_t total = 0;
std::size_t failed = 0;
- case_results (std::string const& name_ = "");
+ explicit
+ case_results(std::string name_ = "")
+ : name(std::move(name_))
+ {
+ }
};
struct suite_results
@@ -51,14 +53,16 @@ private:
std::size_t cases = 0;
std::size_t total = 0;
std::size_t failed = 0;
- typename clock_type::time_point start =
- clock_type::now();
+ typename clock_type::time_point start = clock_type::now();
explicit
- suite_results (std::string const& name_ = "");
+ suite_results(std::string const& name_ = "")
+ : name(std::move(name_))
+ {
+ }
void
- add (case_results const& r);
+ add(case_results const& r);
};
struct results
@@ -76,35 +80,30 @@ private:
std::size_t total = 0;
std::size_t failed = 0;
std::vector top;
- typename clock_type::time_point start =
- clock_type::now();
+ typename clock_type::time_point start = clock_type::now();
void
add (suite_results const& r);
};
- boost::optional std_ostream_;
- std::reference_wrapper stream_;
+ std::ostream& os_;
results results_;
suite_results suite_results_;
case_results case_results_;
public:
- reporter (reporter const&) = delete;
- reporter& operator= (reporter const&) = delete;
+ reporter(reporter const&) = delete;
+ reporter& operator=(reporter const&) = delete;
~reporter();
explicit
- reporter (std::ostream& stream = std::cout);
-
- explicit
- reporter (beast::abstract_ostream& stream);
+ reporter(std::ostream& os = std::cout);
private:
static
std::string
- fmtdur (typename clock_type::duration const& d);
+ fmtdur(typename clock_type::duration const& d);
virtual
void
@@ -137,42 +136,27 @@ private:
//------------------------------------------------------------------------------
-template
-reporter<_>::case_results::case_results (
- std::string const& name_)
- : name (name_)
-{
-}
-
-template
-reporter<_>::suite_results::suite_results (
- std::string const& name_)
- : name (name_)
-{
-}
-
-template
+template
void
-reporter<_>::suite_results::add (case_results const& r)
+reporter<_>::
+suite_results::add(case_results const& r)
{
++cases;
total += r.total;
failed += r.failed;
}
-template
+template
void
-reporter<_>::results::add (
- suite_results const& r)
+reporter<_>::
+results::add(suite_results const& r)
{
++suites;
total += r.total;
cases += r.cases;
failed += r.failed;
-
- auto const elapsed =
- clock_type::now() - r.start;
- if (elapsed >= std::chrono::seconds(1))
+ auto const elapsed = clock_type::now() - r.start;
+ if (elapsed >= std::chrono::seconds{1})
{
auto const iter = std::lower_bound(top.begin(),
top.end(), elapsed,
@@ -196,50 +180,40 @@ reporter<_>::results::add (
//------------------------------------------------------------------------------
-template
-reporter<_>::reporter (
- std::ostream& stream)
- : std_ostream_ (std::ref (stream))
- , stream_ (*std_ostream_)
+template
+reporter<_>::
+reporter(std::ostream& os)
+ : os_(os)
{
}
-template
+template
reporter<_>::~reporter()
{
- if (results_.top.size() > 0)
+ if(results_.top.size() > 0)
{
- stream_.get() << "Longest suite times:";
- for (auto const& i : results_.top)
- stream_.get() << std::setw(8) <<
- fmtdur(i.second) << " " << i.first;
+ os_ << "Longest suite times:\n";
+ for(auto const& i : results_.top)
+ os_ << std::setw(8) <<
+ fmtdur(i.second) << " " << i.first << '\n';
}
- auto const elapsed =
- clock_type::now() - results_.start;
- stream_.get() <<
+ auto const elapsed = clock_type::now() - results_.start;
+ os_ <<
fmtdur(elapsed) << ", " <<
- amount (results_.suites, "suite") << ", " <<
- amount (results_.cases, "case") << ", " <<
- amount (results_.total, "test") << " total, " <<
- amount (results_.failed, "failure");
+ amount{results_.suites, "suite"} << ", " <<
+ amount{results_.cases, "case"} << ", " <<
+ amount{results_.total, "test"} << " total, " <<
+ amount{results_.failed, "failure"} <<
+ std::endl;
}
-template
-reporter<_>::reporter (
- abstract_ostream& stream)
- : stream_ (stream)
-{
-}
-
-template
+template
std::string
-reporter<_>::fmtdur (
- typename clock_type::duration const& d)
+reporter<_>::fmtdur(typename clock_type::duration const& d)
{
using namespace std::chrono;
- auto const ms =
- duration_cast(d);
- if (ms < seconds(1))
+ auto const ms = duration_cast(d);
+ if (ms < seconds{1})
return std::to_string(ms.count()) + "ms";
std::stringstream ss;
ss << std::fixed << std::setprecision(1) <<
@@ -247,67 +221,68 @@ reporter<_>::fmtdur (
return ss.str();
}
-template
+template
void
-reporter<_>::on_suite_begin (
- suite_info const& info)
+reporter<_>::
+on_suite_begin(suite_info const& info)
{
- suite_results_ = suite_results (info.full_name());
+ suite_results_ = suite_results{info.full_name()};
}
-template
+template
void
reporter<_>::on_suite_end()
{
- results_.add (suite_results_);
+ results_.add(suite_results_);
}
-template
+template
void
-reporter<_>::on_case_begin (
- std::string const& name)
+reporter<_>::
+on_case_begin(std::string const& name)
{
case_results_ = case_results (name);
-
- stream_.get() <<
+ os_ <<
suite_results_.name <<
(case_results_.name.empty() ?
- "" : (" " + case_results_.name));
+ "" : (" " + case_results_.name)) << std::endl;
}
-template
+template
void
-reporter<_>::on_case_end()
+reporter<_>::
+on_case_end()
{
- suite_results_.add (case_results_);
+ suite_results_.add(case_results_);
}
-template
+template
void
-reporter<_>::on_pass()
+reporter<_>::
+on_pass()
{
++case_results_.total;
}
-template
+template
void
-reporter<_>::on_fail (
- std::string const& reason)
+reporter<_>::
+on_fail(std::string const& reason)
{
++case_results_.failed;
++case_results_.total;
- stream_.get() <<
- "#" << case_results_.total <<
- " failed" <<
- (reason.empty() ? "" : ": ") << reason;
+ os_ <<
+ "#" << case_results_.total << " failed" <<
+ (reason.empty() ? "" : ": ") << reason << std::endl;
}
-template
+template
void
-reporter<_>::on_log (
- std::string const& s)
+reporter<_>::
+on_log(std::string const& s)
{
- stream_.get() << s;
+ os_ << s;
+ os_.flush();
}
} // detail
diff --git a/src/beast/extras/beast/unit_test/runner.hpp b/src/beast/extras/beast/unit_test/runner.hpp
index 1ff085df8e..038985659d 100644
--- a/src/beast/extras/beast/unit_test/runner.hpp
+++ b/src/beast/extras/beast/unit_test/runner.hpp
@@ -9,9 +9,9 @@
#define BEAST_UNIT_TEST_RUNNER_H_INCLUDED
#include
-#include
#include
#include
+#include
#include
namespace beast {
@@ -23,28 +23,6 @@ namespace unit_test {
*/
class runner
{
-private:
- // Reroutes log output to the runner
- class stream_t : public abstract_ostream
- {
- private:
- runner& owner_;
-
- public:
- stream_t() = delete;
- stream_t& operator= (stream_t const&) = delete;
-
- template
- stream_t (runner& owner);
-
- void
- write (string_type const& s) override
- {
- owner_.log (s);
- }
- };
-
- stream_t stream_;
std::string arg_;
bool default_ = false;
bool failed_ = false;
@@ -52,21 +30,20 @@ private:
std::recursive_mutex mutex_;
public:
+ runner() = default;
virtual ~runner() = default;
- runner (runner const&) = default;
- runner& operator= (runner const&) = default;
-
- template
- runner();
+ runner(runner const&) = delete;
+ runner& operator=(runner const&) = delete;
/** Set the argument string.
+
The argument string is available to suites and
allows for customization of the test. Each suite
defines its own syntax for the argumnet string.
The same argument is passed to all suites.
*/
void
- arg (std::string const& s)
+ arg(std::string const& s)
{
arg_ = s;
}
@@ -81,7 +58,7 @@ public:
/** Run the specified suite.
@return `true` if any conditions failed.
*/
- template
+ template
bool
run (suite_info const& s);
@@ -124,69 +101,63 @@ public:
bool
run_each_if (SequenceContainer const& c, Pred pred = Pred{});
-private:
+protected:
//
// Overrides
//
- /** Called when a new suite starts. */
+ /// Called when a new suite starts.
virtual
void
- on_suite_begin (suite_info const&)
+ on_suite_begin(suite_info const&)
{
}
- /** Called when a suite ends. */
+ /// Called when a suite ends.
virtual
void
on_suite_end()
{
}
- /** Called when a new case starts. */
+ /// Called when a new case starts.
virtual
void
- on_case_begin (std::string const&)
+ on_case_begin(std::string const&)
{
}
- /** Called when a new case ends. */
+ /// Called when a new case ends.
virtual
void
on_case_end()
{
}
- /** Called for each passing condition. */
+ /// Called for each passing condition.
virtual
void
- on_pass ()
+ on_pass()
{
}
- /** Called for each failing condition. */
+ /// Called for each failing condition.
virtual
void
- on_fail (std::string const&)
+ on_fail(std::string const&)
{
}
- /** Called when a test logs output. */
+ /// Called when a test logs output.
virtual
void
- on_log (std::string const&)
+ on_log(std::string const&)
{
}
private:
friend class suite;
- abstract_ostream&
- stream()
- {
- return stream_;
- }
-
// Start a new testcase.
template
void
@@ -207,20 +178,6 @@ private:
//------------------------------------------------------------------------------
-template
-runner::stream_t::stream_t (runner& owner)
- : owner_ (owner)
-{
-}
-
-//------------------------------------------------------------------------------
-
-template
-runner::runner()
- : stream_ (*this)
-{
-}
-
template
bool
runner::run (suite_info const& s)
diff --git a/src/beast/extras/beast/unit_test/suite.hpp b/src/beast/extras/beast/unit_test/suite.hpp
index 6ffa6eb227..476c0b0aac 100644
--- a/src/beast/extras/beast/unit_test/suite.hpp
+++ b/src/beast/extras/beast/unit_test/suite.hpp
@@ -9,15 +9,23 @@
#define BEAST_UNIT_TEST_SUITE_HPP
#include
-#include
+#include
#include
+#include
namespace beast {
namespace unit_test {
class thread;
+enum abort_t
+{
+ no_abort_on_fail,
+ abort_on_fail
+};
+
/** A testsuite class.
+
Derived classes execute a series of testcases, where each testcase is
a series of pass/fail tests. To provide a unit test using this class,
derive from it and use the BEAST_DEFINE_UNIT_TEST macro in a
@@ -25,13 +33,6 @@ class thread;
*/
class suite
{
-public:
- enum abort_t
- {
- no_abort_on_fail,
- abort_on_fail
- };
-
private:
bool abort_ = false;
bool aborted_ = false;
@@ -44,95 +45,100 @@ private:
char const*
what() const noexcept override
{
- return "suite aborted";
+ return "test suite aborted";
}
};
-public:
- // Memberspace
- class log_t
+ template
+ class log_buf
+ : public std::basic_stringbuf
{
- private:
- friend class suite;
- suite* suite_ = nullptr;
+ suite& suite_;
public:
- log_t () = default;
+ explicit
+ log_buf(suite& self)
+ : suite_(self)
+ {
+ }
- template
- abstract_ostream::scoped_stream_type
- operator<< (T const& t);
+ ~log_buf()
+ {
+ sync();
+ }
- /** Returns the raw stream used for output. */
- abstract_ostream&
- stream();
+ int
+ sync() override
+ {
+ auto const& s = this->str();
+ if(s.size() > 0)
+ suite_.runner_->on_log(s);
+ this->str("");
+ return 0;
+ }
+ };
+
+ template<
+ class CharT,
+ class Traits = std::char_traits,
+ class Allocator = std::allocator
+ >
+ class log_os : public std::basic_ostream
+ {
+ log_buf buf_;
+
+ public:
+ explicit
+ log_os(suite& self)
+ : std::basic_ostream(&buf_)
+ , buf_(self)
+ {
+ }
};
-private:
class scoped_testcase;
- // Memberspace
class testcase_t
{
- private:
- friend class suite;
- suite* suite_ = nullptr;
+ suite& suite_;
std::stringstream ss_;
public:
- testcase_t() = default;
+ explicit
+ testcase_t(suite& self)
+ : suite_(self)
+ {
+ }
/** Open a new testcase.
- A testcase is a series of evaluated test conditions. A test suite
- may have multiple test cases. A test is associated with the last
- opened testcase. When the test first runs, a default unnamed
- case is opened. Tests with only one case may omit the call
- to testcase.
- @param abort If `true`, the suite will be stopped on first failure.
+
+ A testcase is a series of evaluated test conditions. A test
+ suite may have multiple test cases. A test is associated with
+ the last opened testcase. When the test first runs, a default
+ unnamed case is opened. Tests with only one case may omit the
+ call to testcase.
+
+ @param abort Determines if suite continues running after a failure.
*/
void
- operator() (std::string const& name,
+ operator()(std::string const& name,
abort_t abort = no_abort_on_fail);
- /** Stream style composition of testcase names. */
- /** @{ */
scoped_testcase
- operator() (abort_t abort);
+ operator()(abort_t abort);
template
scoped_testcase
- operator<< (T const& t);
- /** @} */
+ operator<<(T const& t);
};
public:
- /** Type for scoped stream logging.
- To use this type, declare a local variable of the type
- on the stack in derived class member function and construct
- it from log.stream();
+ /** Logging output stream.
- @code
-
- scoped_stream ss (log.stream();
-
- ss << "Hello" << std::endl;
- ss << "world" << std::endl;
-
- @endcode
-
- Streams constructed in this fashion will not have the line
- ending automatically appended.
-
- Thread safety:
-
- The scoped_stream may only be used by one thread.
- Multiline output sent to the stream will be atomically
- written to the underlying abstract_Ostream
+ Text sent to the log output stream will be forwarded to
+ the output stream associated with the runner.
*/
- using scoped_stream = abstract_ostream::scoped_stream_type;
-
- /** Memberspace for logging. */
- log_t log;
+ log_os log;
/** Memberspace for declaring test cases. */
testcase_t testcase;
@@ -145,6 +151,12 @@ public:
return *p_this_suite();
}
+ suite()
+ : log(*this)
+ , testcase(*this)
+ {
+ }
+
/** Invokes the test using the specified runner.
Data members are set up here instead of the constructor as a
convenience to writing the derived class to avoid repetition of
@@ -272,84 +284,51 @@ private:
//------------------------------------------------------------------------------
-template
-inline
-abstract_ostream::scoped_stream_type
-suite::log_t::operator<< (T const& t)
-{
- return suite_->runner_->stream() << t;
-}
-
-/** Returns the raw stream used for output. */
-inline
-abstract_ostream&
-suite::log_t::stream()
-{
- return suite_->runner_->stream();
-}
-
-//------------------------------------------------------------------------------
-
// Helper for streaming testcase names
class suite::scoped_testcase
{
private:
- suite* suite_;
- std::stringstream* ss_;
+ suite& suite_;
+ std::stringstream& ss_;
public:
- ~scoped_testcase();
+ scoped_testcase& operator=(scoped_testcase const&) = delete;
- scoped_testcase (suite* s, std::stringstream* ss);
+ ~scoped_testcase()
+ {
+ auto const& name = ss_.str();
+ if(! name.empty())
+ suite_.runner_->testcase (name);
+ }
- template
- scoped_testcase (suite* s, std::stringstream* ss, T const& t);
+ scoped_testcase(suite& self, std::stringstream& ss)
+ : suite_(self)
+ , ss_(ss)
+ {
+ ss_.clear();
+ ss_.str({});
+ }
- scoped_testcase& operator= (scoped_testcase const&) = delete;
+ template
+ scoped_testcase(suite& self,
+ std::stringstream& ss, T const& t)
+ : suite_(self)
+ , ss_(ss)
+ {
+ ss_.clear();
+ ss_.str({});
+ ss_ << t;
+ }
- template
+ template
scoped_testcase&
- operator<< (T const& t);
+ operator<<(T const& t)
+ {
+ ss_ << t;
+ return *this;
+ }
};
-inline
-suite::scoped_testcase::~scoped_testcase()
-{
- auto const& name (ss_->str());
- if (! name.empty())
- suite_->runner_->testcase (name);
-}
-
-inline
-suite::scoped_testcase::scoped_testcase (suite* s, std::stringstream* ss)
- : suite_ (s)
- , ss_ (ss)
-{
- ss_->clear();
- ss_->str({});
-
-}
-
-template
-inline
-suite::scoped_testcase::scoped_testcase (suite* s, std::stringstream* ss, T const& t)
- : suite_ (s)
- , ss_ (ss)
-{
- ss_->clear();
- ss_->str({});
- *ss_ << t;
-}
-
-template
-inline
-suite::scoped_testcase&
-suite::scoped_testcase::operator<< (T const& t)
-{
- *ss_ << t;
- return *this;
-}
-
//------------------------------------------------------------------------------
inline
@@ -357,16 +336,16 @@ void
suite::testcase_t::operator() (std::string const& name,
abort_t abort)
{
- suite_->abort_ = abort == abort_on_fail;
- suite_->runner_->testcase (name);
+ suite_.abort_ = abort == abort_on_fail;
+ suite_.runner_->testcase (name);
}
inline
suite::scoped_testcase
suite::testcase_t::operator() (abort_t abort)
{
- suite_->abort_ = abort == abort_on_fail;
- return { suite_, &ss_ };
+ suite_.abort_ = abort == abort_on_fail;
+ return { suite_, ss_ };
}
template
@@ -374,7 +353,7 @@ inline
suite::scoped_testcase
suite::testcase_t::operator<< (T const& t)
{
- return { suite_, &ss_, t };
+ return { suite_, ss_, t };
}
//------------------------------------------------------------------------------
@@ -511,8 +490,6 @@ void
suite::run (runner& r)
{
runner_ = &r;
- log.suite_ = this;
- testcase.suite_ = this;
try
{
diff --git a/src/beast/extras/beast/unit_test/suite_info.hpp b/src/beast/extras/beast/unit_test/suite_info.hpp
index 530ac008a1..428d81ee13 100644
--- a/src/beast/extras/beast/unit_test/suite_info.hpp
+++ b/src/beast/extras/beast/unit_test/suite_info.hpp
@@ -8,6 +8,7 @@
#ifndef BEAST_UNIT_TEST_SUITE_INFO_HPP
#define BEAST_UNIT_TEST_SUITE_INFO_HPP
+#include
#include
#include
#include
@@ -20,19 +21,28 @@ class runner;
/** Associates a unit test type with metadata. */
class suite_info
{
-private:
- using run_type = std::function ;
+ using run_type = std::function;
std::string name_;
std::string module_;
std::string library_;
- bool m_manual;
- run_type m_run;
+ bool manual_;
+ run_type run_;
public:
- template
- suite_info (std::string const& name, std::string const& module,
- std::string const& library, bool manual, run_type run);
+ suite_info(
+ std::string name,
+ std::string module,
+ std::string library,
+ bool manual,
+ run_type run)
+ : name_(std::move(name))
+ , module_(std::move(module))
+ , library_(std::move(library))
+ , manual_(manual)
+ , run_(std::move(run))
+ {
+ }
std::string const&
name() const
@@ -52,61 +62,58 @@ public:
return library_;
}
- /** Returns `true` if this suite only runs manually. */
+ /// Returns `true` if this suite only runs manually.
bool
manual() const
{
- return m_manual;
+ return manual_;
}
- /** Return the canonical suite name as a string. */
- template
+ /// Return the canonical suite name as a string.
std::string
- full_name() const;
-
- /** Run a new instance of the associated test suite. */
- void
- run (runner& r) const
+ full_name() const
{
- m_run (r);
+ return library_ + "." + module_ + "." + name_;
+ }
+
+ /// Run a new instance of the associated test suite.
+ void
+ run(runner& r) const
+ {
+ run_ (r);
+ }
+
+ friend
+ bool
+ operator<(suite_info const& lhs, suite_info const& rhs)
+ {
+ return
+ std::tie(lhs.library_, lhs.module_, lhs.name_) <
+ std::tie(rhs.library_, rhs.module_, rhs.name_);
}
};
//------------------------------------------------------------------------------
-template
-suite_info::suite_info (std::string const& name, std::string const& module,
- std::string const& library, bool manual, run_type run)
- : name_ (name)
- , module_ (module)
- , library_ (library)
- , m_manual (manual)
- , m_run (std::move (run))
-{
-}
-
-template
-std::string
-suite_info::full_name() const
-{
- return library_ + "." + module_ + "." + name_;
-}
-
-inline
-bool
-operator< (suite_info const& lhs, suite_info const& rhs)
-{
- return lhs.full_name() < rhs.full_name();
-}
-
-/** Convenience for producing suite_info for a given test type. */
-template
+/// Convenience for producing suite_info for a given test type.
+template
suite_info
-make_suite_info (std::string const& name, std::string const& module,
- std::string const& library, bool manual)
+make_suite_info(
+ std::string name,
+ std::string module,
+ std::string library,
+ bool manual)
{
- return suite_info(name, module, library, manual,
- [](runner& r) { return Suite{}(r); });
+ return suite_info(
+ std::move(name),
+ std::move(module),
+ std::move(library),
+ manual,
+ [](runner& r)
+ {
+ Suite{}(r);
+ }
+ );
}
} // unit_test
diff --git a/src/beast/extras/beast/unit_test/suite_list.hpp b/src/beast/extras/beast/unit_test/suite_list.hpp
index 5feacf26d7..d8f62c5df6 100644
--- a/src/beast/extras/beast/unit_test/suite_list.hpp
+++ b/src/beast/extras/beast/unit_test/suite_list.hpp
@@ -18,23 +18,27 @@
namespace beast {
namespace unit_test {
-/** A container of test suites. */
+/// A container of test suites.
class suite_list
: public detail::const_container >
{
private:
#ifndef NDEBUG
- std::unordered_set names_;
- std::unordered_set classes_;
+ std::unordered_set names_;
+ std::unordered_set