From a59329ff8ee5cb060dd7948e6484ebe2a40e5985 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Fri, 6 May 2016 21:51:43 -0400 Subject: [PATCH] Improvements to code coverage: More tests and test cases are added to bring up the percentage of library code covered by tests. --- TODO.txt | 1 + include/beast/http/impl/message_v1.ipp | 6 - include/beast/http/impl/write.ipp | 42 +---- include/beast/websocket/detail/debug.hpp | 24 +-- include/beast/websocket/detail/frame.hpp | 36 ++-- include/beast/websocket/detail/mask.hpp | 45 ++--- test/Jamfile | 2 + test/http/basic_parser_v1.cpp | 108 ++++++++++- test/http/parse_error.cpp | 47 +++++ test/http/reason.cpp | 20 ++ test/http/write.cpp | 42 ++++- test/static_streambuf.cpp | 56 ++++++ test/static_string.cpp | 23 ++- test/websocket/CMakeLists.txt | 2 + test/websocket/detail/frame.cpp | 227 +++++++++++++++++++++++ test/websocket/detail/mask.cpp | 48 +++++ test/websocket/error.cpp | 42 +++++ 17 files changed, 649 insertions(+), 122 deletions(-) create mode 100644 test/websocket/detail/frame.cpp create mode 100644 test/websocket/detail/mask.cpp diff --git a/TODO.txt b/TODO.txt index ef032038..5de1e6c0 100644 --- a/TODO.txt +++ b/TODO.txt @@ -55,3 +55,4 @@ HTTP: * Make empty_body write-only, remove reader nested type * Add concepts WritableBody ReadableBody with type checks, check them in read and write functions +* Branch prediction hints in parser diff --git a/include/beast/http/impl/message_v1.ipp b/include/beast/http/impl/message_v1.ipp index 153b6f4d..805eddd1 100644 --- a/include/beast/http/impl/message_v1.ipp +++ b/include/beast/http/impl/message_v1.ipp @@ -228,12 +228,6 @@ prepare(message_v1& msg, msg.headers["Connection"], "upgrade")) throw std::invalid_argument( "invalid version for Connection: upgrade"); - - // rfc7230 3.3.2 - if(msg.headers.exists("Content-Length") && - msg.headers.exists("Transfer-Encoding")) - throw std::invalid_argument( - "Content-Length and Transfer-Encoding cannot be combined"); } } // http diff --git a/include/beast/http/impl/write.ipp b/include/beast/http/impl/write.ipp index b8364157..bb54c036 100644 --- a/include/beast/http/impl/write.ipp +++ b/include/beast/http/impl/write.ipp @@ -39,22 +39,11 @@ write_firstline(Streambuf& streambuf, write(streambuf, msg.method); write(streambuf, " "); write(streambuf, msg.url); - switch(msg.version) - { - case 10: - write(streambuf, " HTTP/1.0\r\n"); - break; - case 11: - write(streambuf, " HTTP/1.1\r\n"); - break; - default: - write(streambuf, " HTTP/"); - write(streambuf, msg.version / 10); - write(streambuf, "."); - write(streambuf, msg.version % 10); - write(streambuf, "\r\n"); - break; - } + write(streambuf, " HTTP/"); + write(streambuf, msg.version / 10); + write(streambuf, "."); + write(streambuf, msg.version % 10); + write(streambuf, "\r\n"); } template @@ -62,22 +51,11 @@ void write_firstline(Streambuf& streambuf, message_v1 const& msg) { - switch(msg.version) - { - case 10: - write(streambuf, "HTTP/1.0 "); - break; - case 11: - write(streambuf, "HTTP/1.1 "); - break; - default: - write(streambuf, " HTTP/"); - write(streambuf, msg.version / 10); - write(streambuf, "."); - write(streambuf, msg.version % 10); - write(streambuf, " "); - break; - } + write(streambuf, "HTTP/"); + write(streambuf, msg.version / 10); + write(streambuf, "."); + write(streambuf, msg.version % 10); + write(streambuf, " "); write(streambuf, msg.status); write(streambuf, " "); write(streambuf, msg.reason); diff --git a/include/beast/websocket/detail/debug.hpp b/include/beast/websocket/detail/debug.hpp index e86e2e59..847a6449 100644 --- a/include/beast/websocket/detail/debug.hpp +++ b/include/beast/websocket/detail/debug.hpp @@ -1,21 +1,9 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== +// +// 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_WEBSOCKET_DETAIL_DEBUG_HPP #define BEAST_WEBSOCKET_DETAIL_DEBUG_HPP diff --git a/include/beast/websocket/detail/frame.hpp b/include/beast/websocket/detail/frame.hpp index a4c780f8..f23aa63e 100644 --- a/include/beast/websocket/detail/frame.hpp +++ b/include/beast/websocket/detail/frame.hpp @@ -119,6 +119,12 @@ write(Streambuf& sb, frame_header const& fh) std::size_t n; std::uint8_t b[14]; b[0] = (fh.fin ? 0x80 : 0x00) | static_cast(fh.op); + if(fh.rsv1) + b[0] |= 0x40; + if(fh.rsv2) + b[0] |= 0x20; + if(fh.rsv3) + b[0] |= 0x10; b[1] = fh.mask ? 0x80 : 0x00; if (fh.len <= 125) { @@ -196,13 +202,6 @@ read_fh1(frame_header& fh, Streambuf& sb, code = close_code::protocol_error; return 0; } - // invalid opcode - // (only in locally generated headers) - if(! is_valid(fh.op)) - { - code = close_code::protocol_error; - return 0; - } // fragmented control message if(is_control(fh.op) && ! fh.fin) { @@ -243,13 +242,7 @@ read_fh2(frame_header& fh, Streambuf& sb, std::uint8_t b[2]; assert(buffer_size(sb.data()) >= sizeof(b)); sb.consume(buffer_copy(buffer(b), sb.data())); - #if 0 - // Causes strict-aliasing warning in gcc - fh.len = reinterpret_cast< - big_uint16_buf_t const*>(&b[0])->value(); - #else fh.len = big_uint16_to_native(&b[0]); - #endif // length not canonical if(fh.len < 126) { @@ -263,13 +256,7 @@ read_fh2(frame_header& fh, Streambuf& sb, std::uint8_t b[8]; assert(buffer_size(sb.data()) >= sizeof(b)); sb.consume(buffer_copy(buffer(b), sb.data())); - #if 0 - // Causes strict-aliasing warning in gcc - fh.len = reinterpret_cast< - big_uint64_buf_t const*>(&b[0])->value(); - #else fh.len = big_uint64_to_native(&b[0]); - #endif // length not canonical if(fh.len < 65536) { @@ -284,13 +271,12 @@ read_fh2(frame_header& fh, Streambuf& sb, std::uint8_t b[4]; assert(buffer_size(sb.data()) >= sizeof(b)); sb.consume(buffer_copy(buffer(b), sb.data())); - #if 0 - // Causes strict-aliasing warning in gcc - fh.key = reinterpret_cast< - little_uint32_buf_t const*>(&b[0])->value(); - #else fh.key = little_uint32_to_native(&b[0]); - #endif + } + else + { + // initialize this otherwise operator== breaks + fh.key = 0; } code = close_code::none; } diff --git a/include/beast/websocket/detail/mask.hpp b/include/beast/websocket/detail/mask.hpp index 14a1977b..29d49c6b 100644 --- a/include/beast/websocket/detail/mask.hpp +++ b/include/beast/websocket/detail/mask.hpp @@ -1,24 +1,12 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco +// +// 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) +// - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_WEBSOCKETDETAIL_MASKGEN_HPP -#define BEAST_WEBSOCKETDETAIL_MASKGEN_HPP +#ifndef BEAST_WEBSOCKET_DETAIL_MASK_HPP +#define BEAST_WEBSOCKET_DETAIL_MASK_HPP #include #include @@ -33,13 +21,14 @@ namespace detail { // Pseudo-random source of mask keys // -template +template class maskgen_t { - std::mt19937 g_; + Generator g_; public: - using result_type = typename std::mt19937::result_type; + using result_type = + typename Generator::result_type; maskgen_t(); @@ -50,15 +39,15 @@ public: rekey(); }; -template -maskgen_t<_>::maskgen_t() +template +maskgen_t::maskgen_t() { rekey(); } -template +template auto -maskgen_t<_>::operator()() noexcept -> +maskgen_t::operator()() noexcept -> result_type { for(;;) @@ -78,7 +67,7 @@ maskgen_t<_>::rekey() g_.seed(ss); } -using maskgen = maskgen_t<>; +using maskgen = maskgen_t; //------------------------------------------------------------------------------ diff --git a/test/Jamfile b/test/Jamfile index 7061be39..02b8e5eb 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -73,6 +73,8 @@ unit-test websocket-tests : websocket/stream.cpp websocket/teardown.cpp websocket/utf8_checker.cpp + websocket/detail/frame.cpp + websocket/detail/mask.cpp ; exe websocket-echo : diff --git a/test/http/basic_parser_v1.cpp b/test/http/basic_parser_v1.cpp index e7feff8d..cbf7194e 100644 --- a/test/http/basic_parser_v1.cpp +++ b/test/http/basic_parser_v1.cpp @@ -10,7 +10,6 @@ #include "message_fuzz.hpp" -#include #include #include #include @@ -102,6 +101,68 @@ public: } }; + template + struct cb_fail + : public basic_parser_v1> + + { + std::size_t n_; + + void fail(error_code& ec) + { + if(n_ > 0) + --n_; + if(! n_) + ec = boost::system::errc::make_error_code( + boost::system::errc::invalid_argument); + } + + private: + friend class basic_parser_v1>; + + void on_method(boost::string_ref const&, error_code& ec) + { + fail(ec); + } + void on_uri(boost::string_ref const&, error_code& ec) + { + fail(ec); + } + void on_reason(boost::string_ref const&, error_code& ec) + { + fail(ec); + } + void on_request(error_code& ec) + { + fail(ec); + } + void on_response(error_code& ec) + { + fail(ec); + } + void on_field(boost::string_ref const&, error_code& ec) + { + fail(ec); + } + void on_value(boost::string_ref const&, error_code& ec) + { + fail(ec); + } + int on_headers(error_code& ec) + { + fail(ec); + return 0; + } + void on_body(boost::string_ref const&, error_code& ec) + { + fail(ec); + } + void on_complete(error_code& ec) + { + fail(ec); + } + }; + //-------------------------------------------------------------------------- static @@ -177,6 +238,50 @@ public: } }; + void + testFail() + { + using boost::asio::buffer; + { + std::string const s = + "GET / HTTP/1.1\r\n" + "User-Agent: test\r\n" + "Content-Length: 1\r\n" + "\r\n" + "*"; + static std::size_t constexpr limit = 100; + std::size_t n = 1; + for(; n < limit; ++n) + { + error_code ec; + basic_parser_v1> p; + p.write(buffer(s), ec); + if(! ec) + break; + } + expect(n < limit); + } + { + std::string const s = + "HTTP/1.1 200 OK\r\n" + "Server: test\r\n" + "Content-Length: 1\r\n" + "\r\n" + "*"; + static std::size_t constexpr limit = 100; + std::size_t n = 1; + for(; n < limit; ++n) + { + error_code ec; + basic_parser_v1> p; + p.write(buffer(s), ec); + if(! ec) + break; + } + expect(n < limit); + } + } + void testCallbacks() { @@ -647,6 +752,7 @@ public: void run() override { + testFail(); testCallbacks(); testVersion(); testFlags(); diff --git a/test/http/parse_error.cpp b/test/http/parse_error.cpp index 5cc9b0f9..235d9abe 100644 --- a/test/http/parse_error.cpp +++ b/test/http/parse_error.cpp @@ -7,3 +7,50 @@ // Test that header file is self-contained. #include + +#include +#include + +namespace beast { +namespace http { + +class parse_error_test : public unit_test::suite +{ +public: + void check(char const* name, parse_error ev) + { + auto const ec = make_error_code(ev); + expect(std::string{ec.category().name()} == name); + expect(! ec.message().empty()); + expect(std::addressof(ec.category()) == + std::addressof(get_parse_error_category())); + expect(get_parse_error_category().equivalent(static_cast(ev), + ec.category().default_error_condition(static_cast(ev)))); + expect(get_parse_error_category().equivalent( + ec, static_cast(ev))); + } + + void run() override + { + check("http", parse_error::connection_closed); + check("http", parse_error::bad_method); + check("http", parse_error::bad_uri); + check("http", parse_error::bad_version); + check("http", parse_error::bad_crlf); + check("http", parse_error::bad_request); + check("http", parse_error::bad_status_code); + check("http", parse_error::bad_status); + check("http", parse_error::bad_field); + check("http", parse_error::bad_value); + check("http", parse_error::bad_content_length); + check("http", parse_error::illegal_content_length); + check("http", parse_error::bad_on_headers_rv); + check("http", parse_error::invalid_chunk_size); + check("http", parse_error::short_read); + } +}; + +BEAST_DEFINE_TESTSUITE(parse_error,http,beast); + +} // http +} // beast diff --git a/test/http/reason.cpp b/test/http/reason.cpp index 857d19be..9acb9385 100644 --- a/test/http/reason.cpp +++ b/test/http/reason.cpp @@ -7,3 +7,23 @@ // Test that header file is self-contained. #include + +#include + +namespace beast { +namespace http { + +class reason_test : public unit_test::suite +{ +public: + void run() override + { + for(int i = 1; i <= 999; ++i) + expect(reason_string(i) != nullptr); + } +}; + +BEAST_DEFINE_TESTSUITE(reason,http,beast); + +} // http +} // beast diff --git a/test/http/write.cpp b/test/http/write.cpp index 1634c758..053a74f7 100644 --- a/test/http/write.cpp +++ b/test/http/write.cpp @@ -56,7 +56,7 @@ public: } }; - struct test_Body + struct fail_body { using value_type = std::string; @@ -67,7 +67,41 @@ public: public: template explicit - writer(message const& msg) + writer(message const& msg) + : body_(msg.body) + { + } + + void + init(error_code& ec) + { + ec = boost::system::errc::make_error_code( + boost::system::errc::errc_t::invalid_argument); + } + + template + boost::tribool + operator()(resume_context&&, error_code&, Write&& write) + { + write(boost::asio::buffer(body_)); + return true; + } + }; + }; + + struct test_body + { + using value_type = std::string; + + class writer + { + std::size_t pos_ = 0; + value_type const& body_; + + public: + template + explicit + writer(message const& msg) : body_(msg.body) { } @@ -148,7 +182,7 @@ public: } // no content-length HTTP/1.0 { - message_v1 m{{ + message_v1 m{{ "GET", "/", 10}}; m.headers.insert("User-Agent", "test"); m.body = "*"; @@ -214,7 +248,7 @@ public: } // no content-length HTTP/1.1 { - message_v1 m{{ + message_v1 m{{ "GET", "/", 11}}; m.headers.insert("User-Agent", "test"); m.body = "*"; diff --git a/test/static_streambuf.cpp b/test/static_streambuf.cpp index ece8996a..5d60d84c 100644 --- a/test/static_streambuf.cpp +++ b/test/static_streambuf.cpp @@ -139,9 +139,65 @@ public: }}}}}} } + void testIterators() + { + static_streambuf_n<2> ba; + { + auto mb = ba.prepare(2); + std::size_t n; + n = 0; + for(auto it = mb.begin(); + it != mb.end(); it++) + ++n; + expect(n == 1); + mb = ba.prepare(2); + n = 0; + for(auto it = mb.begin(); + it != mb.end(); ++it) + ++n; + expect(n == 1); + mb = ba.prepare(2); + n = 0; + for(auto it = mb.end(); + it != mb.begin(); it--) + ++n; + expect(n == 1); + mb = ba.prepare(2); + n = 0; + for(auto it = mb.end(); + it != mb.begin(); --it) + ++n; + expect(n == 1); + } + ba.prepare(2); + ba.commit(1); + std::size_t n; + n = 0; + for(auto it = ba.data().begin(); + it != ba.data().end(); it++) + ++n; + expect(n == 1); + n = 0; + for(auto it = ba.data().begin(); + it != ba.data().end(); ++it) + ++n; + expect(n == 1); + n = 0; + for(auto it = ba.data().end(); + it != ba.data().begin(); it--) + ++n; + expect(n == 1); + n = 0; + for(auto it = ba.data().end(); + it != ba.data().begin(); --it) + ++n; + expect(n == 1); + } + void run() override { testStaticStreambuf(); + testIterators(); } }; diff --git a/test/static_string.cpp b/test/static_string.cpp index 9ea71c42..1b73c250 100644 --- a/test/static_string.cpp +++ b/test/static_string.cpp @@ -154,14 +154,6 @@ public: { pass(); } - s1 = "1"; - s2 = "2"; - expect(s1.compare(s2) < 0); - expect(s2.compare(s1) > 0); - expect(s1 < "10"); - expect(s2 > "1"); - expect("10" > s1); - expect("1" < s2); } pass(); } @@ -170,6 +162,21 @@ public: { using str1 = static_string<1>; using str2 = static_string<2>; + { + str1 s1; + str2 s2; + s1 = "1"; + s2 = "22"; + expect(s1.compare(s2) < 0); + expect(s2.compare(s1) > 0); + expect(s1 < "10"); + expect(s2 > "1"); + expect("10" > s1); + expect("1" < s2); + expect(s1 < "20"); + expect(s2 > "1"); + expect(s2 > "2"); + } { str2 s1("x"); str2 s2("x"); diff --git a/test/websocket/CMakeLists.txt b/test/websocket/CMakeLists.txt index f9fbd268..80f48f11 100644 --- a/test/websocket/CMakeLists.txt +++ b/test/websocket/CMakeLists.txt @@ -15,6 +15,8 @@ add_executable (websocket-tests stream.cpp teardown.cpp utf8_checker.cpp + detail/frame.cpp + detail/mask.cpp ) if (NOT WIN32) diff --git a/test/websocket/detail/frame.cpp b/test/websocket/detail/frame.cpp new file mode 100644 index 00000000..237316a0 --- /dev/null +++ b/test/websocket/detail/frame.cpp @@ -0,0 +1,227 @@ +// +// 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) +// + +#include +#include +#include +#include + +namespace beast { +namespace websocket { +namespace detail { + +static +bool +operator==(frame_header const& lhs, frame_header const& rhs) +{ + return + lhs.op == rhs.op && + lhs.fin == rhs.fin && + lhs.mask == rhs.mask && + lhs.rsv1 == rhs.rsv1 && + lhs.rsv2 == rhs.rsv2 && + lhs.rsv3 == rhs.rsv3 && + lhs.len == rhs.len && + lhs.key == rhs.key; +} + +class frame_test : public beast::unit_test::suite +{ +public: + void testValidOpcode() + { + expect(! is_valid(0)); + expect(! is_valid(1)); + expect(! is_valid(999)); + expect(! is_valid(1004)); + expect(! is_valid(1005)); + expect(! is_valid(1006)); + expect(! is_valid(1016)); + expect(! is_valid(2000)); + expect(! is_valid(2999)); + expect(is_valid(3000)); + expect(is_valid(4000)); + expect(is_valid(5000)); + } + + struct test_fh : frame_header + { + test_fh() + { + op = opcode::text; + fin = false; + mask = false; + rsv1 = false; + rsv2 = false; + rsv3 = false; + len = 0; + key = 0; + } + }; + + void testFrameHeader() + { + // good frame headers + { + role_type role = role_type::client; + + auto check = + [&](frame_header const& fh) + { + fh_streambuf sb; + write(sb, fh); + frame_header fh1; + close_code::value code; + auto const n = read_fh1( + fh1, sb, role, code); + if(! expect(! code)) + return; + if(! expect(sb.size() == n)) + return; + read_fh2(fh1, sb, role, code); + if(! expect(! code)) + return; + if(! expect(sb.size() == 0)) + return; + expect(fh1 == fh); + }; + + test_fh fh; + + check(fh); + + role = role_type::server; + fh.mask = true; + fh.key = 1; + check(fh); + + fh.len = 1; + check(fh); + + fh.len = 126; + check(fh); + + fh.len = 65535; + check(fh); + + fh.len = 65536; + check(fh); + + fh.len = std::numeric_limits::max(); + check(fh); + } + + // bad frame headers + { + role_type role = role_type::client; + + auto check = + [&](frame_header const& fh) + { + fh_streambuf sb; + write(sb, fh); + frame_header fh1; + close_code::value code; + auto const n = read_fh1( + fh1, sb, role, code); + if(code) + { + pass(); + return; + } + if(! expect(sb.size() == n)) + return; + read_fh2(fh1, sb, role, code); + if(! expect(code)) + return; + if(! expect(sb.size() == 0)) + return; + }; + + test_fh fh; + + fh.op = opcode::close; + fh.fin = true; + fh.len = 126; + check(fh); + fh.len = 0; + + fh.rsv1 = true; + check(fh); + fh.rsv1 = false; + + fh.op = opcode::rsv3; + check(fh); + fh.op = opcode::text; + + fh.op = opcode::ping; + fh.fin = false; + check(fh); + fh.fin = true; + + fh.mask = true; + check(fh); + + role = role_type::server; + fh.mask = false; + check(fh); + } + } + + void bad(std::initializer_list bs) + { + using boost::asio::buffer; + using boost::asio::buffer_copy; + static role_type constexpr role = + role_type::client; + std::vector v{bs}; + fh_streambuf sb; + sb.commit(buffer_copy( + sb.prepare(v.size()), buffer(v))); + frame_header fh; + close_code::value code; + auto const n = read_fh1(fh, sb, role, code); + if(code) + { + pass(); + return; + } + if(! expect(sb.size() == n)) + return; + read_fh2(fh, sb, role, code); + if(! expect(code)) + return; + if(! expect(sb.size() == 0)) + return; + } + + void testBadFrameHeaders() + { + // bad frame headers + // + // can't be created by the library + // so we produce them manually. + + bad({0, 126, 0, 125}); + bad({0, 127, 0, 0, 0, 0, 0, 0, 255, 255}); + } + + void run() override + { + testValidOpcode(); + testFrameHeader(); + testBadFrameHeaders(); + pass(); + } +}; + +BEAST_DEFINE_TESTSUITE(frame,websocket,beast); + +} // detail +} // websocket +} // beast + diff --git a/test/websocket/detail/mask.cpp b/test/websocket/detail/mask.cpp new file mode 100644 index 00000000..653bfa00 --- /dev/null +++ b/test/websocket/detail/mask.cpp @@ -0,0 +1,48 @@ +// +// 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) +// + +#include +#include + +namespace beast { +namespace websocket { +namespace detail { + +class mask_test : public beast::unit_test::suite +{ +public: + struct test_generator + { + using result_type = std::uint32_t; + + result_type n = 0; + + void + seed(std::seed_seq const&) + { + } + + std::uint32_t + operator()() + { + return n++; + } + }; + + void run() override + { + maskgen_t mg; + expect(mg() != 0); + } +}; + +BEAST_DEFINE_TESTSUITE(mask,websocket,beast); + +} // detail +} // websocket +} // beast + diff --git a/test/websocket/error.cpp b/test/websocket/error.cpp index 5800f3f2..36af8658 100644 --- a/test/websocket/error.cpp +++ b/test/websocket/error.cpp @@ -7,3 +7,45 @@ // Test that header file is self-contained. #include + +#include +#include + +namespace beast { +namespace websocket { + +class error_test : public unit_test::suite +{ +public: + void check(char const* name, error ev) + { + auto const ec = make_error_code(ev); + expect(std::string{ec.category().name()} == name); + expect(! ec.message().empty()); + expect(std::addressof(ec.category()) == + std::addressof(detail::get_error_category())); + expect(detail::get_error_category().equivalent(static_cast(ev), + ec.category().default_error_condition(static_cast(ev)))); + expect(detail::get_error_category().equivalent( + ec, static_cast(ev))); + } + + void run() override + { + check("websocket", error::closed); + check("websocket", error::failed); + check("websocket", error::handshake_failed); + check("websocket", error::keep_alive); + check("websocket", error::response_malformed); + check("websocket", error::response_failed); + check("websocket", error::response_denied); + check("websocket", error::request_malformed); + check("websocket", error::request_invalid); + check("websocket", error::request_denied); + } +}; + +BEAST_DEFINE_TESTSUITE(error,websocket,beast); + +} // http +} // beast