diff --git a/include/bitcoin/network/error.hpp b/include/bitcoin/network/error.hpp index 3f34be32c..a1893bdbf 100644 --- a/include/bitcoin/network/error.hpp +++ b/include/bitcoin/network/error.hpp @@ -41,7 +41,9 @@ namespace error { /// These are platform-specific error codes, for which we have seen variance. /// boost::system::errc::errc_t is the boost::system error condition enum. /// By comparing against conditions we obtain platform-independent error codes. +typedef boost::json::error json_error_t; typedef boost::beast::http::error http_error_t; +typedef boost::beast::websocket::error ws_error_t; typedef boost::system::errc::errc_t boost_error_t; typedef boost::asio::error::misc_errors asio_misc_error_t; typedef boost::asio::error::netdb_errors asio_netdb_error_t; @@ -229,6 +231,47 @@ enum error_t : uint8_t bad_close_size, bad_close_payload, + // boost json error + syntax, + extra_data, + incomplete, + exponent_overflow, + too_deep, + illegal_leading_surrogate, + illegal_trailing_surrogate, + expected_hex_digit, + expected_utf16_escape, + object_too_large, + array_too_large, + key_too_large, + string_too_large, + number_too_large, + input_error, + exception, + out_of_range, + test_failure, + missing_slash, + invalid_escape, + token_not_number, + value_is_scalar, + json_not_found, + token_overflow, + past_the_end, + not_number, + not_exact, + not_null, + not_bool, + not_array, + not_object, + not_string, + not_int64, + not_uint64, + not_double, + not_integer, + size_mismatch, + exhausted_variants, + unknown_name, + // rpc error message_overflow, undefined_type, @@ -244,21 +287,25 @@ enum error_t : uint8_t // No current need for error_code equivalence mapping. DECLARE_ERROR_T_CODE_CATEGORY(error); -/// Construct a boost_code object from a boost system errc_t. -/// Unfortunately boost_code does not have this std::error_code construction. -inline boost_code to_boost_code(boost_error_t ec) NOEXCEPT +inline boost_code to_system_code(boost_error_t ec) NOEXCEPT { - return boost_code{ ec, boost::system::generic_category() }; + return boost::system::errc::make_error_code(ec); } -/// Unfortunately boost_code does not have this std::error_code construction. inline boost_code to_http_code(http_error_t ec) NOEXCEPT { return boost::beast::http::make_error_code(ec); } -/// Shortcircuit common boost code mapping. -BCT_API bool asio_is_canceled(const boost_code& ec) NOEXCEPT; +inline boost_code to_ws_code(ws_error_t ec) NOEXCEPT +{ + return boost::beast::websocket::make_error_code(ec); +} + +inline boost_code to_json_code(json_error_t ec) NOEXCEPT +{ + return boost::json::make_error_code(ec); +} /// Unfortunately std::error_code and boost::system::error_code are distinct /// types, so they do not compare as would be expected across distinct @@ -269,14 +316,22 @@ BCT_API bool asio_is_canceled(const boost_code& ec) NOEXCEPT; /// codes to network::error_t codes. This cannot be done using the equivalence /// operator overloads of either, since the error_code types are distinct, /// despite being effectively identical. So we provide this explicit mapping. + +/// Shortcircuit common boost code mapping. +BCT_API bool asio_is_canceled(const boost_code& ec) NOEXCEPT; + +/// mapping of boost::asio error codes to network (or error::unknown). BCT_API code asio_to_error_code(const boost_code& ec) NOEXCEPT; /// 1:1 mapping of boost::beast:http::error to network (or error::unknown). BCT_API code http_to_error_code(const boost_code& ec) NOEXCEPT; -/// 1:1 mapping of boost::beast:websocket::error to network (or error::unknown). +/// 1:1 mapping of boost::beast::websocket::error to network (or error::unknown). BCT_API code ws_to_error_code(const boost_code& ec) NOEXCEPT; +/// 1:1 mapping of boost::json::error to network (or error::unknown). +BCT_API code json_to_error_code(const boost_code& ec) NOEXCEPT; + } // namespace error } // namespace network } // namespace libbitcoin diff --git a/include/bitcoin/network/impl/messages/json_body.ipp b/include/bitcoin/network/impl/messages/json_body.ipp index 7aa0b2f87..7d58d7016 100644 --- a/include/bitcoin/network/impl/messages/json_body.ipp +++ b/include/bitcoin/network/impl/messages/json_body.ipp @@ -35,7 +35,7 @@ void CLASS::reader::init(const http::length_type& length, boost_code& ec) NOEXCEPT { BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) - const auto value = length.get_value_or(zero); + const auto value = length.get_value_or(max_size_t); BC_POP_WARNING() using namespace system; diff --git a/src/error.cpp b/src/error.cpp index 10e7c5110..73cbfb2ba 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -204,6 +204,47 @@ DEFINE_ERROR_T_MESSAGE_MAP(error) { bad_close_size, "bad close size" }, { bad_close_payload, "bad close payload" }, + // boost json error + { syntax, "syntax error" }, + { extra_data, "extra data" }, + { incomplete, "incomplete json" }, + { exponent_overflow, "exponent too large" }, + { too_deep, "too deep" }, + { illegal_leading_surrogate, "illegal leading surrogate" }, + { illegal_trailing_surrogate, "illegal trailing surrogate" }, + { expected_hex_digit, "expected hex digit" }, + { expected_utf16_escape, "expected utf16 escape" }, + { object_too_large, "object too large" }, + { array_too_large, "array too large" }, + { key_too_large, "key too large" }, + { string_too_large, "string too large" }, + { number_too_large, "number too large" }, + { input_error, "input error" }, + { exception, "exception" }, + { out_of_range, "out of range" }, + { test_failure, "test failure" }, + { missing_slash, "missing slash" }, + { invalid_escape, "invalid escape" }, + { token_not_number, "token not number" }, + { value_is_scalar, "value is scalar" }, + { json_not_found, "json not found" }, + { token_overflow, "token overflow" }, + { past_the_end, "past the end" }, + { not_number, "not number" }, + { not_exact, "not exact" }, + { not_null, "not null" }, + { not_bool, "not bool" }, + { not_array, "not array" }, + { not_object, "not object" }, + { not_string, "not string" }, + { not_int64, "not int64" }, + { not_uint64, "not uint64" }, + { not_double, "not double" }, + { not_integer, "not integer" }, + { size_mismatch, "size mismatch" }, + { exhausted_variants, "exhausted variants" }, + { unknown_name, "unknown name" }, + // rpc error { message_overflow, "message overflow" }, { undefined_type, "undefined type" }, @@ -218,6 +259,7 @@ DEFINE_ERROR_T_MESSAGE_MAP(error) DEFINE_ERROR_T_CATEGORY(error, "network", "network code") +// boost_code overloads the `==` operator to include category. bool asio_is_canceled(const boost_code& ec) NOEXCEPT { // self termination @@ -227,7 +269,7 @@ bool asio_is_canceled(const boost_code& ec) NOEXCEPT // The success and operation_canceled codes are the only expected in normal // operation, so these are first, to optimize the case where asio_is_canceled -// is not used. +// is not used. boost_code overloads the `==` operator to include category. code asio_to_error_code(const boost_code& ec) NOEXCEPT { if (ec == boost_error_t::success) @@ -350,140 +392,153 @@ code asio_to_error_code(const boost_code& ec) NOEXCEPT return error::unknown; } +// includes json codes code http_to_error_code(const boost_code& ec) NOEXCEPT { - namespace http = boost::beast::http; + static const auto& category = boost::beast::http:: + make_error_code(http_error_t::end_of_stream).category(); if (!ec) - return {}; - - if (ec == http::error::end_of_stream) - return error::end_of_stream; - if (ec == http::error::partial_message) - return error::partial_message; - if (ec == http::error::need_more) - return error::need_more; - if (ec == http::error::unexpected_body) - return error::unexpected_body; - if (ec == http::error::need_buffer) - return error::need_buffer; - if (ec == http::error::end_of_chunk) - return error::end_of_chunk; - if (ec == http::error::buffer_overflow) - return error::buffer_overflow; - if (ec == http::error::header_limit) - return error::header_limit; - if (ec == http::error::body_limit) - return error::body_limit; - if (ec == http::error::bad_alloc) - return error::bad_alloc; - if (ec == http::error::bad_line_ending) - return error::bad_line_ending; - if (ec == http::error::bad_method) - return error::bad_method; - if (ec == http::error::bad_target) - return error::bad_target; - if (ec == http::error::bad_version) - return error::bad_version; - if (ec == http::error::bad_status) - return error::bad_status; - if (ec == http::error::bad_reason) - return error::bad_reason; - if (ec == http::error::bad_field) - return error::bad_field; - if (ec == http::error::bad_value) - return error::bad_value; - if (ec == http::error::bad_content_length) - return error::bad_content_length; - if (ec == http::error::bad_transfer_encoding) - return error::bad_transfer_encoding; - if (ec == http::error::bad_chunk) - return error::bad_chunk; - if (ec == http::error::bad_chunk_extension) - return error::bad_chunk_extension; - if (ec == http::error::bad_obs_fold) - return error::bad_obs_fold; - if (ec == http::error::multiple_content_length) - return error::multiple_content_length; - if (ec == http::error::stale_parser) - return error::stale_parser; - if (ec == http::error::short_read) - return error::short_read; - - return asio_to_error_code(ec); + return error::success; + + if (ec.category() != category) + return json_to_error_code(ec); + + switch (static_cast(ec.value())) + { + case http_error_t::end_of_stream: return error::end_of_stream; + case http_error_t::partial_message: return error::partial_message; + case http_error_t::need_more: return error::need_more; + case http_error_t::unexpected_body: return error::unexpected_body; + case http_error_t::need_buffer: return error::need_buffer; + case http_error_t::end_of_chunk: return error::end_of_chunk; + case http_error_t::buffer_overflow: return error::buffer_overflow; + case http_error_t::header_limit: return error::header_limit; + case http_error_t::body_limit: return error::body_limit; + case http_error_t::bad_alloc: return error::bad_alloc; + case http_error_t::bad_line_ending: return error::bad_line_ending; + case http_error_t::bad_method: return error::bad_method; + case http_error_t::bad_target: return error::bad_target; + case http_error_t::bad_version: return error::bad_version; + case http_error_t::bad_status: return error::bad_status; + case http_error_t::bad_reason: return error::bad_reason; + case http_error_t::bad_field: return error::bad_field; + case http_error_t::bad_value: return error::bad_value; + case http_error_t::bad_content_length: return error::bad_content_length; + case http_error_t::bad_transfer_encoding: return error::bad_transfer_encoding; + case http_error_t::bad_chunk: return error::bad_chunk; + case http_error_t::bad_chunk_extension: return error::bad_chunk_extension; + case http_error_t::bad_obs_fold: return error::bad_obs_fold; + case http_error_t::multiple_content_length: return error::multiple_content_length; + case http_error_t::stale_parser: return error::stale_parser; + case http_error_t::short_read: return error::short_read; + default: return error::unknown; + } } +// includes json codes code ws_to_error_code(const boost_code& ec) NOEXCEPT { - namespace ws = boost::beast::websocket; + static const auto& category = boost::beast::websocket:: + make_error_code(ws_error_t::closed).category(); + + if (!ec) + return error::success; + + if (ec.category() != category) + return http_to_error_code(ec); + + switch (static_cast(ec.value())) + { + case ws_error_t::closed: return error::websocket_closed; + case ws_error_t::buffer_overflow: return error::websocket_buffer_overflow; + case ws_error_t::partial_deflate_block: return error::partial_deflate_block; + case ws_error_t::message_too_big: return error::message_too_big; + case ws_error_t::bad_http_version: return error::bad_http_version; + case ws_error_t::bad_method: return error::websocket_bad_method; + case ws_error_t::no_host: return error::no_host; + case ws_error_t::no_connection: return error::no_connection; + case ws_error_t::no_connection_upgrade: return error::no_connection_upgrade; + case ws_error_t::no_upgrade: return error::no_upgrade; + case ws_error_t::no_upgrade_websocket: return error::no_upgrade_websocket; + case ws_error_t::no_sec_key: return error::no_sec_key; + case ws_error_t::bad_sec_key: return error::bad_sec_key; + case ws_error_t::no_sec_version: return error::no_sec_version; + case ws_error_t::bad_sec_version: return error::bad_sec_version; + case ws_error_t::no_sec_accept: return error::no_sec_accept; + case ws_error_t::bad_sec_accept: return error::bad_sec_accept; + case ws_error_t::upgrade_declined: return error::upgrade_declined; + case ws_error_t::bad_opcode: return error::bad_opcode; + case ws_error_t::bad_data_frame: return error::bad_data_frame; + case ws_error_t::bad_continuation: return error::bad_continuation; + case ws_error_t::bad_reserved_bits: return error::bad_reserved_bits; + case ws_error_t::bad_control_fragment: return error::bad_control_fragment; + case ws_error_t::bad_control_size: return error::bad_control_size; + case ws_error_t::bad_unmasked_frame: return error::bad_unmasked_frame; + case ws_error_t::bad_masked_frame: return error::bad_masked_frame; + case ws_error_t::bad_size: return error::bad_size; + case ws_error_t::bad_frame_payload: return error::bad_frame_payload; + case ws_error_t::bad_close_code: return error::bad_close_code; + case ws_error_t::bad_close_size: return error::bad_close_size; + case ws_error_t::bad_close_payload: return error::bad_close_payload; + default: return error::unknown; + } +} + +code json_to_error_code(const boost_code& ec) NOEXCEPT +{ + static const auto& category = boost::json:: + make_error_code(json_error_t::syntax).category(); if (!ec) - return {}; - - if (ec == ws::error::closed) - return error::websocket_closed; - if (ec == ws::error::buffer_overflow) - return error::websocket_buffer_overflow; - if (ec == ws::error::partial_deflate_block) - return error::partial_deflate_block; - if (ec == ws::error::message_too_big) - return error::message_too_big; - if (ec == ws::error::bad_http_version) - return error::bad_http_version; - if (ec == ws::error::bad_method) - return error::websocket_bad_method; - if (ec == ws::error::no_host) - return error::no_host; - if (ec == ws::error::no_connection) - return error::no_connection; - if (ec == ws::error::no_connection_upgrade) - return error::no_connection_upgrade; - if (ec == ws::error::no_upgrade) - return error::no_upgrade; - if (ec == ws::error::no_upgrade_websocket) - return error::no_upgrade_websocket; - if (ec == ws::error::no_sec_key) - return error::no_sec_key; - if (ec == ws::error::bad_sec_key) - return error::bad_sec_key; - if (ec == ws::error::no_sec_version) - return error::no_sec_version; - if (ec == ws::error::bad_sec_version) - return error::bad_sec_version; - if (ec == ws::error::no_sec_accept) - return error::no_sec_accept; - if (ec == ws::error::bad_sec_accept) - return error::bad_sec_accept; - if (ec == ws::error::upgrade_declined) - return error::upgrade_declined; - if (ec == ws::error::bad_opcode) - return error::bad_opcode; - if (ec == ws::error::bad_data_frame) - return error::bad_data_frame; - if (ec == ws::error::bad_continuation) - return error::bad_continuation; - if (ec == ws::error::bad_reserved_bits) - return error::bad_reserved_bits; - if (ec == ws::error::bad_control_fragment) - return error::bad_control_fragment; - if (ec == ws::error::bad_control_size) - return error::bad_control_size; - if (ec == ws::error::bad_unmasked_frame) - return error::bad_unmasked_frame; - if (ec == ws::error::bad_masked_frame) - return error::bad_masked_frame; - if (ec == ws::error::bad_size) - return error::bad_size; - if (ec == ws::error::bad_frame_payload) - return error::bad_frame_payload; - if (ec == ws::error::bad_close_code) - return error::bad_close_code; - if (ec == ws::error::bad_close_size) - return error::bad_close_size; - if (ec == ws::error::bad_close_payload) - return error::bad_close_payload; - - return http_to_error_code(ec); + return error::success; + + if (ec.category() != category) + return asio_to_error_code(ec); + + switch (static_cast(ec.value())) + { + case json_error_t::syntax: return error::syntax; + case json_error_t::extra_data: return error::extra_data; + case json_error_t::incomplete: return error::incomplete; + case json_error_t::exponent_overflow: return error::exponent_overflow; + case json_error_t::too_deep: return error::too_deep; + case json_error_t::illegal_leading_surrogate: return error::illegal_leading_surrogate; + case json_error_t::illegal_trailing_surrogate: return error::illegal_trailing_surrogate; + case json_error_t::expected_hex_digit: return error::expected_hex_digit; + case json_error_t::expected_utf16_escape: return error::expected_utf16_escape; + case json_error_t::object_too_large: return error::object_too_large; + case json_error_t::array_too_large: return error::array_too_large; + case json_error_t::key_too_large: return error::key_too_large; + case json_error_t::string_too_large: return error::string_too_large; + case json_error_t::number_too_large: return error::number_too_large; + case json_error_t::input_error: return error::input_error; + case json_error_t::exception: return error::exception; + case json_error_t::out_of_range: return error::out_of_range; + case json_error_t::test_failure: return error::test_failure; + case json_error_t::missing_slash: return error::missing_slash; + case json_error_t::invalid_escape: return error::invalid_escape; + case json_error_t::token_not_number: return error::token_not_number; + case json_error_t::value_is_scalar: return error::value_is_scalar; + case json_error_t::not_found: return error::not_found; + case json_error_t::token_overflow: return error::token_overflow; + case json_error_t::past_the_end: return error::past_the_end; + case json_error_t::not_number: return error::not_number; + case json_error_t::not_exact: return error::not_exact; + case json_error_t::not_null: return error::not_null; + case json_error_t::not_bool: return error::not_bool; + case json_error_t::not_array: return error::not_array; + case json_error_t::not_object: return error::not_object; + case json_error_t::not_string: return error::not_string; + case json_error_t::not_int64: return error::not_int64; + case json_error_t::not_uint64: return error::not_uint64; + case json_error_t::not_double: return error::not_double; + case json_error_t::not_integer: return error::not_integer; + case json_error_t::size_mismatch: return error::size_mismatch; + case json_error_t::exhausted_variants: return error::exhausted_variants; + case json_error_t::unknown_name: return error::unknown_name; + default: return error::unknown; + } } } // namespace error diff --git a/src/messages/http_body.cpp b/src/messages/http_body.cpp index 256a63278..d45e527c6 100644 --- a/src/messages/http_body.cpp +++ b/src/messages/http_body.cpp @@ -39,7 +39,7 @@ void body::reader::init(const length_type& length, boost_code& ec) NOEXCEPT { [&](std::monostate&) NOEXCEPT { - ec = to_boost_code(boost_error_t::io_error); + ec = to_system_code(boost_error_t::io_error); }, [&](auto& read) NOEXCEPT { @@ -49,7 +49,7 @@ void body::reader::init(const length_type& length, boost_code& ec) NOEXCEPT } catch (...) { - ec = to_boost_code(boost_error_t::io_error); + ec = to_system_code(boost_error_t::io_error); } } }, reader_); @@ -61,7 +61,7 @@ size_t body::reader::put(const buffer_type& buffer, boost_code& ec) NOEXCEPT { [&](std::monostate&) NOEXCEPT { - ec = to_boost_code(boost_error_t::io_error); + ec = to_system_code(boost_error_t::io_error); return size_t{}; }, [&](auto& read) NOEXCEPT @@ -72,7 +72,7 @@ size_t body::reader::put(const buffer_type& buffer, boost_code& ec) NOEXCEPT } catch (...) { - ec = to_boost_code(boost_error_t::io_error); + ec = to_system_code(boost_error_t::io_error); return size_t{}; } } @@ -96,7 +96,7 @@ void body::reader::finish(boost_code& ec) NOEXCEPT } catch (...) { - ec = to_boost_code(boost_error_t::io_error); + ec = to_system_code(boost_error_t::io_error); } } }, reader_); @@ -120,7 +120,7 @@ void body::writer::init(boost_code& ec) NOEXCEPT } catch (...) { - ec = to_boost_code(boost_error_t::io_error); + ec = to_system_code(boost_error_t::io_error); } } }, writer_); @@ -142,7 +142,7 @@ body::writer::out_buffer body::writer::get(boost_code& ec) NOEXCEPT } catch (...) { - ec = to_boost_code(boost_error_t::io_error); + ec = to_system_code(boost_error_t::io_error); return out_buffer{}; } } diff --git a/src/messages/rpc/body.cpp b/src/messages/rpc/body.cpp index b7c32ec28..8d3ba8af7 100644 --- a/src/messages/rpc/body.cpp +++ b/src/messages/rpc/body.cpp @@ -52,7 +52,7 @@ put(const buffer_type& buffer, boost_code& ec) NOEXCEPT if (is_null(buffer.data())) { - ec = to_boost_code(boost_error_t::bad_address); + ec = to_system_code(boost_error_t::bad_address); return {}; } @@ -129,21 +129,21 @@ finish(boost_code& ec) NOEXCEPT if (value_.message.method.empty() || !value_.message.params.has_value()) { - ec = to_boost_code(boost_error_t::bad_message); + ec = to_system_code(boost_error_t::bad_message); return; } if (value_.message.jsonrpc == version::v1) { if (!value_.message.id.has_value()) - ec = to_boost_code(boost_error_t::bad_message); + ec = to_system_code(boost_error_t::bad_message); else if (!std::holds_alternative( value_.message.params.value())) - ec = to_boost_code(boost_error_t::bad_message); + ec = to_system_code(boost_error_t::bad_message); // TODO: v1 batch is not allowed. ////else if (value_.message.is_batch()) - //// ec = to_boost_code(boost_error_t::bad_message); + //// ec = to_system_code(boost_error_t::bad_message); } } diff --git a/src/net/socket.cpp b/src/net/socket.cpp index 1cefb8df4..122c58c39 100644 --- a/src/net/socket.cpp +++ b/src/net/socket.cpp @@ -425,6 +425,7 @@ void socket::do_rpc_read(boost_code ec, size_t total, const read_rpc::ptr& in, if (ec) { + // Json parser emits http and json codes. const auto code = error::http_to_error_code(ec); if (code == error::unknown) logx("rpc-read", ec); handler(code, total); @@ -444,6 +445,7 @@ void socket::do_rpc_write(boost_code ec, size_t total, const auto buffer = ec ? write_rpc::out_buffer{} : out->writer.get(ec); if (ec) { + // Json serializer emits http and json codes. const auto code = error::http_to_error_code(ec); if (code == error::unknown) logx("rpc-write", ec); handler(code, total); diff --git a/test/error.cpp b/test/error.cpp index f3757f2cf..0388a5a25 100644 --- a/test/error.cpp +++ b/test/error.cpp @@ -1381,6 +1381,359 @@ BOOST_AUTO_TEST_CASE(error_t__code__bad_close_payload__true_expected_message) BOOST_REQUIRE_EQUAL(ec.message(), "bad close payload"); } +// boost json error + +BOOST_AUTO_TEST_CASE(error_t__code__syntax__true_expected_message) +{ + constexpr auto value = error::syntax; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "syntax error"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__extra_data__true_expected_message) +{ + constexpr auto value = error::extra_data; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "extra data"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__incomplete__true_expected_message) +{ + constexpr auto value = error::incomplete; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "incomplete json"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__exponent_overflow__true_expected_message) +{ + constexpr auto value = error::exponent_overflow; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "exponent too large"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__too_deep__true_expected_message) +{ + constexpr auto value = error::too_deep; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "too deep"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__illegal_leading_surrogate__true_expected_message) +{ + constexpr auto value = error::illegal_leading_surrogate; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "illegal leading surrogate"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__illegal_trailing_surrogate__true_expected_message) +{ + constexpr auto value = error::illegal_trailing_surrogate; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "illegal trailing surrogate"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__expected_hex_digit__true_expected_message) +{ + constexpr auto value = error::expected_hex_digit; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "expected hex digit"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__expected_utf16_escape__true_expected_message) +{ + constexpr auto value = error::expected_utf16_escape; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "expected utf16 escape"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__object_too_large__true_expected_message) +{ + constexpr auto value = error::object_too_large; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "object too large"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__array_too_large__true_expected_message) +{ + constexpr auto value = error::array_too_large; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "array too large"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__key_too_large__true_expected_message) +{ + constexpr auto value = error::key_too_large; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "key too large"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__string_too_large__true_expected_message) +{ + constexpr auto value = error::string_too_large; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "string too large"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__number_too_large__true_expected_message) +{ + constexpr auto value = error::number_too_large; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "number too large"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__input_error__true_expected_message) +{ + constexpr auto value = error::input_error; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "input error"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__exception__true_expected_message) +{ + constexpr auto value = error::exception; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "exception"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__out_of_range__true_expected_message) +{ + constexpr auto value = error::out_of_range; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "out of range"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__test_failure__true_expected_message) +{ + constexpr auto value = error::test_failure; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "test failure"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__missing_slash__true_expected_message) +{ + constexpr auto value = error::missing_slash; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "missing slash"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__invalid_escape__true_expected_message) +{ + constexpr auto value = error::invalid_escape; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "invalid escape"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__token_not_number__true_expected_message) +{ + constexpr auto value = error::token_not_number; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "token not number"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__value_is_scalar__true_expected_message) +{ + constexpr auto value = error::value_is_scalar; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "value is scalar"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__json_not_found__true_expected_message) +{ + constexpr auto value = error::json_not_found; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "json not found"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__token_overflow__true_expected_message) +{ + constexpr auto value = error::token_overflow; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "token overflow"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__past_the_end__true_expected_message) +{ + constexpr auto value = error::past_the_end; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "past the end"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__not_number__true_expected_message) +{ + constexpr auto value = error::not_number; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "not number"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__not_exact__true_expected_message) +{ + constexpr auto value = error::not_exact; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "not exact"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__not_null__true_expected_message) +{ + constexpr auto value = error::not_null; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "not null"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__not_bool__true_expected_message) +{ + constexpr auto value = error::not_bool; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "not bool"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__not_array__true_expected_message) +{ + constexpr auto value = error::not_array; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "not array"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__not_object__true_expected_message) +{ + constexpr auto value = error::not_object; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "not object"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__not_string__true_expected_message) +{ + constexpr auto value = error::not_string; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "not string"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__not_int64__true_expected_message) +{ + constexpr auto value = error::not_int64; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "not int64"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__not_uint64__true_expected_message) +{ + constexpr auto value = error::not_uint64; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "not uint64"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__not_double__true_expected_message) +{ + constexpr auto value = error::not_double; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "not double"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__not_integer__true_expected_message) +{ + constexpr auto value = error::not_integer; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "not integer"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__size_mismatch__true_expected_message) +{ + constexpr auto value = error::size_mismatch; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "size mismatch"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__exhausted_variants__true_expected_message) +{ + constexpr auto value = error::exhausted_variants; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "exhausted variants"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__unknown_name__true_expected_message) +{ + constexpr auto value = error::unknown_name; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "unknown name"); +} + // rpc error BOOST_AUTO_TEST_CASE(error_t__code__message_overflow__true_expected_message)